UIkit Basic 2 (UINavigationController, transition, ViewController Life Cycle, 화면간 데이터 전달, asset catalogs)

Updated:

1.UINavigationController

Content View Controller

  • 화면을 구성하는 뷰를 직접 구현하고 관련된 이벤트 처리하는 뷰 컨트롤러 입니다. 일반적으로 storyboard 생성시, 기본으로 생성되는 view controller 입니다

Container View Controller

  • 하나 이상의 Child View 를 가지고 있습니다. 여러개의 Content View controller 를 가지고 있는거라고 보면 됩니다

  • 하나 이상의 Child View Controller 를 관리하고 레이아웃과 화면 전환을 담당합니다

  • 화면 구성과 이벤트 관리는 Child View Controller 에서 합니다.

  • Container View Controller 는 대표적으로 Navigation Controller 와 TabBar Controller 가 있습니다.

  • 계층구조로 구성된 content 를 순차적으로 보여주는 container view controller 를 말합니다.

image

  • Navigation Stack 을 통해서 Navigation View Controller 를 관리 하게 됩니다
  • Navigation stack 은 기본적으로 Last in, First out 의 구조로써 Stack 에 나중에 들어오는게 먼저 나가는 구조입니다. Controller의 화면전환을 담당합니다
  • Navigation View Controller 구현할 시, 화면 상단에 항상 보여지는 bar 이며, root view controller 이외에는 모든 controller 에는 leading 부분에 back button 이 있어서 유저가 stack 구조에서 pop 해서 뒤로 가기를 할 수 있게 만들어 줍니다

  • 각 자식마다 다르게 Navigation bar 를 구성 할 수 있습니다

image

2.Transition 개념

iOS 에서 화면전화 방법으로는 크게 소스코드를 통한 전환방식, Storyboard 를 통한 2가지 방법이 있습니다

View Controller 에서 다른 View Controller 를 호출하여 전환하기

현재 View controller 에서 이동할 view controller 를 직접호출해서 화면에 표시하는 방법입니다. 직접 표시한다는 의미에서 Presentation 방식이라고 불립니다. 이 방법은 기존 화면에 새로운 화면을 덮는 방식을 말합니다

  • present method 에 이동할 controller 를 넘겨 주면, 이전할 화면에서 이동할 화면에 controller 가 표시가 됩니다. 각각의 parameter 는

    - 첫번째 parameter 에는 이동할 view controller 의 instance 를
    
    - 두번째 에는 화면을 전환 할때, 에니메이션 효과를 줄것인지 안줄건지 boolean 값을
    
    -  세번째는 completion 이라는 클로져를 전달 받고 있는데, 이것은 화면이 전환되는 시점에 맞춰 completion 클로져가 호출됩니다. 화면전환 방식은 비동기 방식으로 처리되기 때문에, 화면전환이 완료된 이후에는 뭔가 code 로 처리해야될 logic 이 있다면, 위체 completion 클로져 안에 넣어 줍니다
    
  • present 화면에서 이전화면으로 되돌아 가는 method 는 dismiss() 가 있습니다. pop 기능이기 때문에 viewController 를 인자로 받지는 않습니다.

    - 첫번째 parameter는 이전화면에 에니메이션을 할건지 말건지 boolean 값으로
    
    - 두번째는 completion 클로져를 받는데 이전화면으로 돌아 갈때는 클로져를 불러옴
    

스크린샷 2021-11-24 오전 9 15 18

계층적인 contents 구조를 관리하기 위한 controller 인 Navigation controller 를 사용하여, view controller를 전환을 직접 control 하고, app 에 네비게이션을 조절하는 역활을 할 뿐만아니라, 네비게이션 stack 에서 First in Last out 을 해서 나중에 들어오늘 것이 제일 먼저 나가는 방식을 말합니다

그래서 pushViewController 를 사용해서 Navigation Stack 에 화면을 추가하고, popViewController 를 사용해서 Navigation stack 에 서 삭제 합니다

  • pushViewController(): 첫번째 parameter는 새롭게 넘길 controller 를 넣어주고, 두번째는 animation boolean 값을 넣어 줍니다

  • popViewController(): 첫번째 parameter는 animation 값을 boolean 값으로 넣어줍니다

image

화면 전환용 객체 세그웨이(Segueway) 를 사용하여 화면 전환하기

Storyboard 를 통해 출발지와 목적지를 지정하는 Segueway 를 이용하면, 따로 code 를 작성하지 않고 Storyboard 로 화면을 전환 할 수 있습니다. 종류로는 Action , Manual Segueway 가 있습니다.

  • Action Segueway: 출발점이 button, send 인 경우를 말합니다. button touch 와 같은 trigger event 가 segueway 실행으로 바로 연결 됩니다. 그래서 code 를 추가 하지 않아도 화면 전환 기능을 구현할 수 있습니다

    - Show: 가장 일반적인 segueway 로써 navigation controller를 사용하면, 화면 전환시, view controller가 navigation stack 에 쌓이게 되고, 만약 navigation controller를 사용하지 않게 되면, view controller freezed 됩니다
    
    - Shoe Detail: split view 에서 사용하는 segueway 로, 특히 iPad 에서 사용하게 되면 split 구조의 master slave 로 작동하게 됩니다
    

image

	- Present Modally: 이전 view controller 를 덮으면서 새로운 화면이 나타나게 되는데 presentation 방식으로 화면이 전환거라고 보면 됩니다

	- Present As Popover: 주로 iPad 에서 사용되는 것으로, popup 창을 띄울때 사용합니다 (iPhone 에서는 사용되지 않음)

	- Custom: Segueway 를 사용자가 원하는 방식으로 custom 할 때 사용합니다
  • Manual Segueway: 출발점이 view controller 자체인것을 말하고, 넘길 시점에 perform method 를 호출하여 segueway 가 실행되어 화면 전환이 이뤄 집니다

화면전환 실습예제 Code

image

Kapture 2021-11-24 at 11 51 07

3.ViewController Life Cycle

보통 App 을 만들때, 복잡해질 수록 많은 화면 전환을 가지게 되는데 그래서 ViewController 들을 잘 관리를 해줘야 합니다. 그래서 ViewController Life Cycle 에 대한 이해가 필요합니다. 크게 4가지 단계로 나뉘게 되는데

아래의 method 들은 각자 필요한 단계일때 iOS 에서 자동으로 호출이 됩니다. UIViewController 를 생성할때, override 하여 lifecycle 상황에 맞게 적절한 logic 들을 method 에 추가 할 수 있습니다. 시스템이 method 을 언제 호출해야 될지를 먼저 이해 하지만, 시점에 맞춰서 UI, Data 의 변화를 잘 파악 할 수 있습니다

  • Appearing: 뷰가 화면에 나타나는 중

  • Appeared: 뷰가 화면에 나타나는게 환요된 상태

  • Disappearing: 뷰가 화면에서 사라지는 중

  • Disappeared: 뷰가 화면에서 사라진 상태

image

각 lifecycle 에 도달하기까지의 method 들을 다음과 같습니다

viewDidLoad()

  • 뷰 컨트롤러의 모든 뷰들이 메모리에 로드 됬을때 호출

  • 메모리에 처음 로드될 때 한번만 호출

  • 보통 딱 한번 호출될 행위들을 이 메소드 안에 정의 함

  • 뷰와 관련된 추가적인 초기화 작업, 네트워크 호출

viewWillAppear()

  • 뷰가 뷰 계층에 추가되고, 화면에 보이기 직전에 매 번 호출

  • 다른 뷰로 이동했다가 돌아오면 재호출

  • 뷰와 관련된 추가적인 초기화 작업

viewDidAppear()

  • 뷰 컨트롤러의 뷰가 뷰 계층에 추가된 후 호출됩니다.

  • 뷰를 나타낼 때 필요한 추가 작업

  • 애니메이션을 시작하는 작업

viewWillDisappear()

  • 뷰 컨트롤러의 뷰가 뷰 계층에서 사라지기 전에 호출됩니다.

  • 뷰가 생성된 뒤 작업한 내용을 되돌리는 작업

  • 최종적으로 데이터를 저장하는 작업

viewDidDisappear()

  • 뷰 컨트롤러의 뷰가 뷰 계층에서 사라진 뒤에 호출

  • 뷰가 사라지는 것과 관련된 추가 작업


// lifecycle 예시
class ViewController: UIViewController {

	override func viewDidLoad() {
		super.viewDidLoad()
		print("ViewController view 가 로드됨")
	}

	override func viewWillAppear(_ animated: Bool) {
		super.viewWillAppear(animated)
		print("ViewController view 가 나타날 것이다")
	}

	override func viewDidAppear(_ animated: Bool) {
		super.viewDidAppear(animated)
		print("VuewController view 가 나타났다.")
	}

	override func viewWillDisappear(_ animated: Bool) {
		super.viewWillDisappear(animated)
		print("ViewCOntroller view 가 사라질 것이다.")
	}

	override func viewDidDisappear(_ animated: Bool) {
		super.viewDidDisappear(animated)
		print("ViewController view 가 사라졌다")
	}

화면전환 이동을 버튼을 누를때 나타나는 lifecycle 되는것

Kapture 2021-11-25 at 09 40 12

4.화면간 데이터 전달하는 방법

Main ViewController 에서 다른 페이지로 데이터 넘기기

// in ViewController

	@IBAction func tabCodePresentButton(_ sender: UIButton) {

		// downcasting: 각 타입에 맞는 viewController 를 각각의 정의한 name property 에 접근할 수 있음
		guard let viewController = self.storyboard?.instantiateViewController(identifier: "CodePresentViewController") as? CodePresentViewController else { return }
		viewController.modalPresentationStyle = .fullScreen

		// name property 에 접근해서 data 를 넘겨주기
		viewController.name = "Jacob"
		self.present(viewController, animated: true, completion: nil)
	}


// in CodePresentViewController

class CodePresentViewController: UIViewController {

	// UI 에 label 추가
	@IBOutlet weak var nameLabel: UILabel!

	// 변수 선언
	var name: String?

	override func viewDidLoad() {
		super.viewDidLoad()

		// 전달 받은 데이터 처리
		if let name = name {
			self.nameLabel.text = name
			self.nameLabel.sizeToFit()
		}
	}

	@IBAction func tabBackButton(_ sender: UIButton) {
		self.presentingViewController?.dismiss(animated: true, completion: nil)
	}
}

Kapture 2021-11-25 at 10 24 01

이전 화면으로 다시 데이터 넘겨주기

다양한 방법이 있지만, 자주사용하는 방법으로 delegate pattern 을 사용해서 이전화면으로 data 를 다시 전송하기

  • delegate pattern: delegate(위임자) 를 가지고 있는 객체가 다른객체에게 자신의 task 를 위임하는 design pattern 입니다
// in  CodePresentViewController.swift

// 데이터를 전달받은 viewController 에서 SendDataDelegate protocol 을 채택하고, delegate 를 위임 받게 되면 senData() 함수가 실행이 되게 됨
protocol SendDataDelegate: AnyObject {
	func sendData(name: String)
}

class CodePresentViewController: UIViewController {

	// UI 에 label 추가
	@IBOutlet weak var nameLabel: UILabel!

	// 변수 선언
	var name: String?

	// delegate 를 사용할때는 변수 앞에 weak 를 붙여 줘야 함. 만약 안쓰게 되면 strong 이 적용되어서 강한참조가 되어 메모리 누수가 발생됨을 주의
	weak var delegate: SendDataDelegate?

	override func viewDidLoad() {
		super.viewDidLoad()

		// 전달 받은 데이터 처리
		if let name = name {
			self.nameLabel.text = name
			self.nameLabel.sizeToFit()
		}
	}

	@IBAction func tabBackButton(_ sender: UIButton) {
		// delegate pattern 으로 뒤로 갈때 data 를 보낼 수 있음
		self.delegate?.sendData(name: "Jacob2")
		self.presentingViewController?.dismiss(animated: true, completion: nil)
	}
}
 // in ViewController.swift

// 타입으로 sendDataDelegate 를 채택 해줘야 함
class ViewController: UIViewController, SendDataDelegate {
	@IBOutlet weak var nameLabel: UILabel!

	override func viewDidLoad() {
		super.viewDidLoad()
		print("ViewController view 가 로드됨")
	}

	override func viewWillAppear(_ animated: Bool) {
		super.viewWillAppear(animated)
		print("ViewController view 가 나타날 것이다")
	}

	override func viewDidAppear(_ animated: Bool) {
		super.viewDidAppear(animated)
		print("VuewController view 가 나타났다.")
	}

	override func viewWillDisappear(_ animated: Bool) {
		super.viewWillDisappear(animated)
		print("ViewCOntroller view 가 사라질 것이다.")
	}

	override func viewDidDisappear(_ animated: Bool) {
		super.viewDidDisappear(animated)
		print("ViewController view 가 사라졌다")
	}

	@IBAction func tabCodePresentButton(_ sender: UIButton) {

		// downcasting: 각 타입에 맞는 viewController 를 각각의 정의한 name property 에 접근할 수 있음
		guard let viewController = self.storyboard?.instantiateViewController(identifier: "CodePresentViewController") as? CodePresentViewController else { return }
		viewController.modalPresentationStyle = .fullScreen

		// name property 에 접근해서 data 를 넘겨주기
		viewController.name = "Jacob"

		// delegate 된 data 가져오기
		viewController.delegate  = self
		self.present(viewController, animated: true, completion: nil)
	}



	@IBAction func tabCodePushBtn(_ sender: UIButton) {
		guard let viewController = self.storyboard?.instantiateViewController(identifier: "CodePushViewController") as? CodePushViewController else { return }

		viewController.name = "Jacob"
		self.navigationController?.pushViewController(viewController, animated: true)
	}


	// delegate 된 sendData UI label 과 연결 시키기 위한 method
	func sendData(name: String) {
		self.nameLabel.text = name
		// text 사이즈에 맞게 사이즈 맞추기
		self.nameLabel.sizeToFit()
	}
}

Segueway 로 구성된 화면에서 데이터 보내기

Segueway 구현된 화면전환 방법에서 전환되는 data 를 보내기에 제일 좋은 방법은 prepare method 를 사용하는것입니다.

  • prepare method: override 하기 위한 segueway 를 실행하기 직전에 system 위에서 자동으로 호출됩니다
// in ViewController.swift

// override prepare method
	override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
		// 전환하고자 하는 viewController 의 instance 가져오기 하고 downcasting 하기
		if let viewController = segue.destination as? SeguePushViewController {
			viewController.name = "Jacob"
		}

	}
// in SeguePushViewController.swift
class SeguePushViewController: UIViewController {
	// UI 에서 label 연결
	@IBOutlet weak var nameLabel: UILabel!

	// 변수 생성
	var name: String?

	override func viewDidLoad() {
		super.viewDidLoad()
		// 전달 받은 data 를 nameLabel 에 표시하기
		if let name = name {
			self.nameLabel.text = name
			self.nameLabel.sizeToFit()
		}
	}
}

🔶 🔷 📌 🔑

Reference

On the swift - https://ontheswift.tistory.com/8

농부와 코드 - https://tono18.tistory.com/11

fastcampus - https://fastcampus.co.kr/dev_online_iosappfinal

Categories:

Updated:

Leave a comment