SeSAC_iOS_Day 31 | TIL

린다·2021년 11월 16일
0

SSAC_iOS_Dev

목록 보기
23/33
post-thumbnail

👩‍💻 수업

📂 CocoaPods 사용법

📂 View간 값 전달하는 방법

1. firstView에서 버튼을 통해 SecondView를 띄우는 동시에 값 전달하기

→ ViewController에 의한 값 전달

ViewController TextView에 작성한 text를 다음 버튼을 눌렀을 때 SecondViewController로 전달하여 SecondViewController의 TextView에 띄우기

class SecondViewController: UIViewController {
	var textSpace: String = ""

	@IBOutlet weak var secondTextView: UITextView!

	override func viewDidLoad() {
		super.viewDidLoad()

		secondTextView.text = textSpace
	}
}
@IBAction func buttonClicked(_ sender: UIButton) {
	guard let vc = self.storyboard.instantiateViewController(withIdentifier: "SecondViewController") as? SecondViewController else {return}
	vc.textSpace = firstTextView.text

	self.present(vc, animated: true, completion: nil)
}

2. 열려있는 SecondView를 닫는 버튼을 누를 때 화면을 닫음과 동시에 값을 전달하는 방식

→ 클로저를 이용한 값 전달

역으로 값을 전달하는 방식 → 메서드(클로저 구문을 만듦)

→ SecondViewController에서는 클로저 구문을 작성만 함(이거 실행해줘) → 자세한 실행 사항은 FirstViewController에서 작성하면 됨!!

// SecondViewController내에서 클로저 변수 선언
var buttonActionHandler: (() -> ())?
// 실행이 안되는 경우를 대비하여 초기화 구문을 작성하지 않아도 되도록 옵셔널로 선언해줌

@IBAction func buttonClicked(_ sender: UIButton) {
	buttonActionHandler()
	self.dismiss(animated: true, completion: nil)
}
// firstViewController
@IBAction func buttonClicked(_ sender: UIButton) {
	guard let vc = self.storyboard.instantiateViewController(withIdentifier: "SecondViewController") as? SecondViewController else {return}

	vc.buttonActionHandler = {
		self.firstTextView.text = vc.textView.text
	}

	vc.textSpace = firstTextView.text

	self.present(vc, animated: true, completion: nil)
}

해당 클로저가 어느 시점에서 실행되는지 디버그 창을 통해 확인해보기

// firstViewController
@IBAction func buttonClicked(_ sender: UIButton) {
	guard let vc = self.storyboard.instantiateViewController(withIdentifier: "SecondViewController") as? SecondViewController else {return}

	vc.buttonActionHandler = {
		print("buttonActionHandler")
		self.firstTextView.text = vc.textView.text
	}

	vc.textSpace = firstTextView.text

	self.present(vc, animated: true, completion: nil)
}

→ SecondViewController에서 화면 닫는 버튼 누르는 경우 핸들러가 실행되고 이때 print 되는 것을 확인할 수 있음!

vc.buttonActionHandler = { [weak self ] // 이걸 캡쳐..리스트..?라고 하나봐...이건 나중에 알려준다고 함 (순환참조)
		print("buttonActionHandler")
		self.firstTextView.text = vc.textView.text
	}

3. 화면 닫는 버튼을 눌렀는데 화면이 꺼짐과 동시에 다른 팝업 화면이 뜨는 경우

→ dismiss의 completion 활용 + presentingViewController 사용

// SecondViewController
@IBAction func buttonClicked(_ sender: UIButton) {
	buttonActionHandler()
	self.dismiss(animated: true) { // completion 타입: (() -> Void)?
		guard let vc = self.storyboard.instantiateViewController(withIdentifier: "PopUpViewController") as? PopUpViewController else {return}
		self.presentVC.present(vc, animated: true, completion: nil)
	}
}

→ popUpView가 한 번 뜨고 닫고 다시 띄우려고 하면 view hierachy 어쩌구 하면서 다시 popupView가 안뜸 ㅜㅜ

이유는 !! 여기서 self = SecondViewController 임
self.dismiss 면 이미 self 즉 SeondViewController는 사라졌음 근데 여기서 self.present하려고 하면 이미 SecondViewController는 사라진 상태이기 때문에 오류가 뜰 수 밖에 없음.

→ 화면 전환할때 property를 두 가지를 더 제공해줌 사용할 수 있도록

  1. PresentingViewController: 자신을 호출한 뷰컨트롤러가 누구인지에 대한 정보를 남겨줌(ex. SecondViewController를 호출한 mainViewController를 알려줌)
  2. presentedViewController: 자신이 직접 호출한 뷰컨트롤러를 의미함(ex. mainViewController의 입장에서는 SecondViewController 의미)

→ 현재 SecondViewController가 사라졌기 때문에 mainViewController에게 present 해달라고 요청해야하는 상황임(presentingViewController)

// SecondViewController
@IBAction func buttonClicked(_ sender: UIButton) {
	buttonActionHandler()

	guard let presentVC = self.presentingViewController else {return}	// 나를 띄워준 뷰컨트롤러가 누군지 이 변수에 담아둘게 ...

	self.dismiss(animated: true) { // completion 타입: (() -> Void)?
		guard let vc = self.storyboard.instantiateViewController(withIdentifier: "PopUpViewController") as? PopUpViewController else {return}
		presentVC.present(vc, animated: true, completion: nil)
	}
}

4. Notification

  1. 로컬 알림
  2. 서버 푸시 알림
  3. 앱 내에서도 서로 알려주는 역할 → 적절히 사용하기~
  • Post(신호 보내기) → Observer (내용도 같이 받을 수 있음)
  • 1:다 관계가 가능함. 여러 군데서 보낸걸 한군데서 받을 수 도 있고 한 군데서 보낸걸 여러군데서 받을 수도 있음 (여러 뷰컨에서 받을 수 있음) → 약간...와이파이 같은 넉김ㅎ
// firstViewController
// 버튼 눌렀을 때 신호 + 데이터 보내기~
@IBAction func notificationButtonClicked(_ sender: UIButton) {
	NotificationCenter.default.post(name: NSNotification.Name(rawValue: "firstNotification"), object: nil, userInfo: ["myText":secondTextView.text!, "value":123])
	self.dismiss(animated: true, completion: nil)
}
  • Post를 보내고 받기 위해서는 Observer가 먼저 등록돼있어야함(ex. FirstViewController에서 post하고 그 뒤에 뜨는 SecondViewController에 observer를 등록해도 viewdidload는 창이 뜰 때마다 실행되기 때문에 post를 받을 수 없음)
  • notification에 담아 보낸 userInfo를 사용하기 위해서는 selector objc 메서드에 NSNotification 타입의 매개변수를 넣어줘야함
@objc func firstNotification(notification: NSNotification) {
		print("Notification!1")
		if let text = notification.userInfo?["myText"] as? String {
			firstTextView.text = text
	}
}
  • viewDidLoad는 단 한번만 실행되기 때문에 observer가 한번만 추가돼서 신경써줘야될 부분이 없지만 만약에 viewWillAppear 같이 여러번 실행될 가능성이 있는 메서드에 observer를 추가하는 경우 여러번 추가되어 비효율적인 코드가 될 수 있음
    → 이런 경우에는 viewWillDisappear 혹은 deinit 메서드에서 observer를 삭제해주는 코드를 작성해야함
override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: "firstNotification"), object: nil)
}

deinit {
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: "firstNotification"), object: nil)
}

5. Protocol

// SeondViewController에 protocol 선언
protocol PassDataDelegate {
    func sendTextData(text: String)
}
// secondTextView에 작성된 Text를 역으로 넘겨주기!!
  • delegate 프로토콜 선언....
var delegate: PassDataDelegate?
  • 버튼 클릭됐을 때 프로토콜 실행해주는...ㅜㅜ 코드 넘 어렵
@IBAction func protocolButtonClicked(_ sender: UIButton) {
    
    if let text = secondTextView.text {
        delegate?.sendTextData(text: text)
    }
    
    dismiss(animated: true, completion: nil)
}
  • 그럼 이제 데이터 받는 viewcontroller에서 프로토콜 채택해줘야함
class ViewController: UIViewController, PassDataDelegate
  • 그리고 필수 요건인 메서드 구현해줌
func sendTextData(text: String) {
        firstTextView.text = text
}
  • 프로토콜 버튼 누를 때 vc.delegate = self 해줘야됨...
@IBAction func protocolButtonClicked(_ sender: UIButton) {
    guard let vc = self.storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as? SecondViewController else {return}
    vc.delegate = self
    self.present(vc, animated: true, completion: nil)
}

0개의 댓글