May 20, 2021, TIL (Today I Learned) - Container View Controller

Inwoo Hwang·2021년 8월 26일
0
post-thumbnail

학습내용


Container View Controller란?

Create a composite Interface by combining content from one or more view controllers with other custom views.

  • 특정 ViewController가 다른 ViewController를 Contain하게 해 주는 컨트롤러

    • Navigation Controller

      Screen Shot 2021-05-25 at 4.22.36 PM

      • Container View Controller를 활용하여 Navigation Controller의 Stack을 쌓을 수 있다.
    • TabBar Controller

      Screen Shot 2021-05-25 at 4.21.57 PM

      • 여러 개의 ViewController가 TabBar Controller에 연결 될 수 있고 이는 Container View Controller을 활용하기에 가능하다.
    • PageViewController

Containver View Controller vs Content View Controller

Content View Controller는 앱의 데이터를 화면에 디스플레이 하는거에 비해 Container View Controller는 다른 View Controller를 보여주고 다른 View Controller의 view를 디스플레이 해 주고 다른 View Controller간의 전환을 관리합니다.

컨텐츠를 화면에 구현하는 것과 컨텐츠 자체를 분리 시켜주기 때문에 Container View Controller는 Content View Controller보다 더 캡슐화된 모델을 설계할 수 있습니다.

Screen Shot 2021-05-25 at 8.17.11 PM

Add a Child View Controller Programmatically to Your Content

  1. addChild(_:) 메서드를 통해 container view controller와 해당 컨트롤러와 관리할 자식 view controller들 간의 containment 관계를 구축합니다.
  2. 자식 view와 container의 view의 연동
  3. didMove(toParent:) 메서드를 활용하여 자식 view controller에게 연동작업이 끝났음을 알려준다.

생성한 ViewController를 NavigationController에 embed 시킵니다.

우측상단 Editor → embed in → NavigationController

class OpenMarketViewController: UIViewController { 
	let openMarketCollectionViewController = OpenMarketCollectionViewController()
  
  let openMarketTableViewController = OpenMarketViewController()
}
  • ChildViewController로 ViewController의 인스턴스 구현
class OpenMarketViewController: UIViewController { 
	let openMarketCollectionViewController: UIViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "OpenMarketCollectionViewController")
  
  let openMarketTableViewController: UIViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "OpenMarketTableViewController")
}

Storyboard를 통해 UIViewController를 구현할 경우 위와 같이 .instantiateViewController를 통해 인스턴스를 구현하여야 합니다.

private func setUpView() {
  addChild(openMarketCollectionViewController)
  addChild(openMarketTableViewController)
  
  self.view.addSubview(openMarketCollectionViewController.view)
  self.view.addSubview(openMarketTableViewController.view)
  
  openMarketTableViewController.didMove(toParent: self)
  openMarketCollectionViewController.didMove(toParent: self)
  
  openMarketTableViewController.view.frame = self.view.bounds
  openMarketCollectionViewController.view.frame = self.view.bounds
  // 첫 화면에서 컬렉션뷰컨트롤러의 뷰를 hidden시켜 안보이도록 설정
  openMarketCollectionViewController.view.isHidden = true
}

*frame과 bound의 차이가 궁금하시다면 아래 링크 참조 해 주세요

iOS ) Frame과 Bounds의 차이 (1/2)

iOS ) Frame과 Bounds의 차이 (2/2)

Segmented Control을 활용하여 유저가 segment를 텝할 때 마다 특정 컨트롤러의 뷰를 볼 수 있도록 조건 구현

@IBAction func didTapSegment(segment: UISegmentedControl) {
  openMarketTableViewController.view.isHidden = true
  openMarketCollectionViewController.view.isHidden = true
  if segment.selectedSegmentIndex == 0 {
    self.openMarketTableViewController.view.isHidden = false
  } else {
    self.openMarketCollectionViewController.view.isHidden = false
  }
override func viewDidLoad() {
        super.viewDidLoad()
        setUpView()
    }

문제 / 해결방법

세그멘트를 텝할 때 아래와 같은 오류 발생

unrecognized selector sent to instance

해결방법:

@IBAction의 특정 파라메터 값을 refactor해서 수정하는 것이 아니라 바로 수정을 했기 때문에 세그먼트를 클릭해도 메서드가 정상적으로 실행이되지 않았던 것이다.

@IBAction func didTapSegment 메서드를 지운 뒤 다시 구현한 다음 다시 Storyboard 상 구현된 segmentcontrol과 연결 시켜주면서 문제 해결

[참고]:

Swift Tutorial: Container View Controllers for Beginners

[Creating a Custom Container View Controller | Apple](

profile
james, the enthusiastic developer

0개의 댓글