iOS/πŸ€– App

[iOS] Container View Controller λž€?

woozzang 2021. 7. 26. 18:09

1μ°¨ μˆ˜μ •: 21.09.30

 

μ•ˆλ…•ν•˜μ„Έμš” 🐢

이번 μ‹œκ°„μ—λŠ” ViewController 의 μ’…λ₯˜ 쀑 ν•˜λ‚˜μΈ

Container View Controller 에 λŒ€ν•΄μ„œ κ³΅λΆ€ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

 

그럼 μ‹œμž‘ν• κ²Œμš”πŸ”₯


 

μš°μ„  View Controller λ₯Ό μ—­ν• λ‘œ κ΅¬λΆ„ν•˜μžλ©΄ 크게 두 κ°€μ§€ μ’…λ₯˜κ°€ μžˆμŠ΅λ‹ˆλ‹€!

 

μ²«λ²ˆμ§ΈλŠ” Content View Controller λ‘œμ„œ,

기본적으둜 λ·° μ»¨νŠΈλ‘€λŸ¬μ—κ²Œ κΈ°λŒ€ν•˜λŠ” μ—­ν• ( μ•± λ‚΄ 데이터λ₯Ό 화면에 λ³΄μ—¬μ£ΌλŠ” λ“±) 을 μˆ˜ν–‰ν•˜λŠ” λ·° μ»¨νŠΈλ‘€λŸ¬μž…λ‹ˆλ‹€.

일반적으둜 UIViewController λ₯Ό 직접 μ„œλΈŒν΄λž˜μ‹±ν•˜μ—¬ μ»€μŠ€ν…€ν•΄μ„œ μ‚¬μš©ν•˜λŠ” κ²½μš°μž…λ‹ˆλ‹€.

class MyHomeViewController: UiViewController { ... }

 

 

λ‘λ²ˆμ§ΈλŠ” 이번 μ‹œκ°„μ— λ‹€λ£° Container View Controller λ‘œμ„œ,

μ—¬λŸ¬ μš”μ†Œλ₯Ό μ‘°ν•©ν•œ μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬μ„±ν•˜κ³  ( composite interface )

 

보톡 직접 무언가λ₯Ό λ³΄μ—¬μ£ΌλŠ” 역할은 μ—†μœΌλ©°,

λ·° 컨트둀러 간에 λΆ€λͺ¨-μžμ‹ 관계λ₯Ό ν˜•μ„±ν•˜μ—¬ μžμ‹ λ§Œμ˜ λ°©μ‹μœΌλ‘œ μžμ‹μ„ κ΄€λ¦¬ν•˜λŠ” 역할을 λ§‘λŠ” λ·° 컨트둀러 μž…λ‹ˆλ‹€.

κ°„λ‹¨ν•˜κ²Œ 생각해보면, Container View Controller 듀이 Content View Controller 듀을 κ΄€λ¦¬ν•œλ‹€κ³  μƒκ°ν•˜λ©΄ λ˜κ² λ„€μš”!

 

그런데 이미 UIKit μ—μ„œ 기본적으둜 μ œκ³΅ν•˜λŠ” System Container View Controller 듀이 μžˆμŠ΅λ‹ˆλ‹€.

UITabBarController, UINavigationController, UIPageViewController 등이 κ·Έκ²ƒλ“€μž…λ‹ˆλ‹€.

 

container view controller 라고 λͺ…μ‹œμ μœΌλ‘œ μ ν˜€ μžˆλ‹€.

 

이 λ•Œ Contianer View Controller λ“€μ˜ νŠΉμ§•μ΄ μžˆμŠ΅λ‹ˆλ‹€.

μžμ‹ View Controller λ“€μ˜ μ°Έμ‘°λ₯Ό κ°€μ§€κ³  κ΄€λ¦¬ν•œλ‹€λŠ” κ²ƒμΈλ°μš”.

보톡 μ•„λž˜μ™€ 같은 λ°©μ‹μœΌλ‘œ μžμ‹ λ·°μ»¨νŠΈλ‘€λŸ¬μ— μ ‘κ·Όν•  수 있고, μžμ‹ 관계λ₯Ό μƒˆλ‘œ μ„€μ •ν•΄ μ€„μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.

 

 

그런데 μ™œ ꡳ이 이런 λΆ€λͺ¨-μžμ‹ 관계λ₯Ό λ§Œλ“€μ–΄μ„œ κ΄€λ¦¬ν•΄μ£ΌλŠ”μ§€μ— λŒ€ν•œ 의문이 μƒκΉλ‹ˆλ‹€.

μ»¨ν…Œμ΄λ„ˆλŠ” μ™œ ν•„μš”ν•œ κ±ΈκΉŒμš”?


 

 

Container View Controller λŠ” μ™œ ν•„μš”ν• κΉŒ?

 

🟒  Navigation 둜직 (λΌμš°νŒ…) 을 λΆ„λ¦¬ν•˜μ—¬ 단일 μ±…μž„μ›μΉ™μ„ μ§€ν‚€λ €λŠ” μ‹œλ„μ΄λ‹€.

" promote better encapsulation by separating out your content

from how you display that content onscreen"

 

MVC νŒ¨ν„΄μ„ 곡뢀할 λ•Œ

λ„ˆλ¬΄λ„ˆλ¬΄ 많이 듀어봀을 Massive View Cotroller 에 λŒ€ν•΄ 아싀거라고 μƒκ°ν•©λ‹ˆλ‹€.

 

κ°„λ‹¨ν•˜κ²Œ λ·° μ»¨νŠΈλ‘€λŸ¬κ°€ λ„ˆλ¬΄ λ§Žμ€ μ—­ν• (μ±…μž„)을 ν•˜κ³  μžˆλ‹€λŠ” 것인데, λ‹€μŒκ³Ό 같은 μ½”λ“œλ₯Ό ν•œλ²ˆ λ³Όκ²Œμš”.

 

  func showChildVC() {
    // λ·° 컨트둀러λ₯Ό 직접 μƒμ„±ν•œλ‹€
    let childVC = ChildViewController()
	
    // 직접 μ˜μ‘΄μ„± μ£Όμž…λ„ ν•΄μ€€λ‹€
    childVC.someDedendency = SomeDependency()
	
    // 직접 화면에 ν‘œμ‹œλ„ ν•΄μ€€λ‹€
    present(childVC, animated: true, completion: nil)
  }

 

μœ„ μ½”λ“œλŠ” 아무 λ¬Έμ œκ°€ μ—†λ‹€κ³  생각할 수 μžˆμ§€λ§Œ, 이 λ©”μ„œλ“œ μ•ˆμ—μ„œλ„ λ·° μ»¨νŠΈλ‘€λŸ¬λŠ” λ§Žμ€ μ±…μž„μ„ κ°€μ§€κ³  μžˆμŠ΅λ‹ˆλ‹€.

 

1. λ·° 컨트둀러λ₯Ό 직접 μƒμ„±ν•˜μ—¬ 생λͺ…주기에 κ΄€λ €ν•˜κ³ 

2. μ˜μ‘΄μ„±μ„ μ£Όμž…ν•΄μ£Όκ³ 

3. 화면에 λ„μ›Œμ£ΌλŠ” μ—­ν• κΉŒμ§€

 

μ±…μž„μ΄ 많으면 μœ μ§€λ³΄μˆ˜μ™€ ν…ŒμŠ€νŠΈκ°€ νž˜λ“€μ–΄μ§‘λ‹ˆλ‹€.

 

λ”°λΌμ„œ 화면에 ν‘œμ‹œν•΄μ£ΌλŠ” μ±…μž„μ„ λ‹€λ₯Έ 객체둜 뢄리해 λ‚Έ 것이 μ»¨ν…Œμ΄λ„ˆ λ·° μ»¨νŠΈλ‘€λŸ¬μž…λ‹ˆλ‹€.

 

 

μ‹œμŠ€ν…œ μ»¨ν…Œμ΄λ„ˆ λ·° 컨트둀러 쀑 ν•˜λ‚˜μΈ

 

Navigation Controller λ₯Ό 예둜 λ“€λ©΄

 

μ»¨ν…Œμ΄λ„ˆ λ·° μ»¨νŠΈλ‘€λŸ¬κ°€ μžμ‹ λ·° μ»¨νŠΈλ‘€λŸ¬μ— λŒ€ν•œ ν™”λ©΄ μ „ν™˜μ„ μ–΄λ–€ λ°©μ‹μœΌλ‘œ ν•˜λŠ”μ§€ λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€.

 

   @IBAction func pushSecond(_ sender: Any) {
   
    /* μ—¬κΈ°λŠ” secondVC λ₯Ό μƒμ„±ν•˜λŠ” μ½”λ“œκ°€ λ“€μ–΄κ°‘λ‹ˆλ‹€ */
    
    // 직접 λ‹€μŒ 화면을 ν‘œμ‹œν•˜μ§€ μ•Šκ³ , navigationController 에 μ˜μ‘΄ν•œλ‹€
    navigationController?.pushViewController(secondVC, animated: true)
   }

 

present(_:animated:completion:) κ³Ό 같은 ν™”λ©΄ 처리 λ©”μ„œλ“œλ₯Ό 직접 ν˜ΈμΆœν•˜μ§€ μ•Šκ³ ,

navigationController μ—κ²Œ 화면에 ν‘œμ‹œν•  VCλ₯Ό μ „λ‹¬ν•˜μ—¬ νŠΈλžœμ§€μ…˜κ³Ό ν™”λ©΄ ν‘œμ‹œλ₯Ό λ§‘κΈ°κ³  (μ˜μ‘΄ν•˜κ³ ) μžˆμŠ΅λ‹ˆλ‹€.

 

pushViewController(_:animated:) 보닀도 μ €λŠ” show(_:sender:) λ₯Ό μ’‹μ•„ν•˜λŠ”λ°μš”...

μ’€ 더 μΆ”μƒν™”λœ λ©”μ„œλ“œλΌκ³  λ³΄μ‹œλ©΄ 되고, μžμ„Έν•œ λ™μž‘μ€ λ¬Έμ„œλ₯Ό μ°Ύμ•„λ³΄μ‹œλ©΄ 쒋을 것 κ°™μŠ΅λ‹ˆλ‹€.

 

μ•„λ¬΄νŠΌ μ €λŠ” μ €λŸ° 방식이 μ™„λ²½ν•˜λ‹€κ³  μƒκ°ν•˜μ§€λŠ” μ•ŠμŠ΅λ‹ˆλ‹€.

μ—¬μ „νžˆ λ·° 컨트둀러λ₯Ό 직접 μƒμ„±ν•˜κ³ , μ˜μ‘΄μ„± μ£Όμž…λ„ ν•΄μ£ΌλŠ” μ½”λ“œκ°€ ν•„μš”ν•˜λ‹ˆκΉŒμš”.

 

🟣 λ·° 자체의 ꡬ역을 λΆ„λ¦¬ν•˜μ—¬ μœ μ§€λ³΄μˆ˜κ°€ μš©μ΄ν•΄μ§„λ‹€.

 

μ»¨ν…Œμ΄λ„ˆ 뷰컨의 루트 λ·°λ₯Ό  λͺ‡ 개의 κ΅¬μ—­μœΌλ‘œ λ‚˜λˆ„μ–΄

κ΅¬μ—­λ³„λ‘œ νŠΉμ„±μ— 맞게 각각의 λ·° 컨트둀러λ₯Ό 두고 λ”°λ‘œ κ΄€λ¦¬ν•˜λ©΄

μ±…μž„λ„ λΆ„λ¦¬λ˜κ³  μœ μ§€λ³΄μˆ˜λ„ μ’€ 더 μ‰¬μ›Œ 질 κ²ƒμž…λ‹ˆλ‹€.

 

μœ„μ˜ μ΄λ―Έμ§€λŠ” UIKit 이 μ œκ³΅ν•˜λŠ” UISplitViewController λ‘œμ„œ

루트 λ·°λ₯Ό μ™Όμͺ½κ³Ό 였λ₯Έμͺ½ λ‘κ°œμ˜ κ΅¬μ—­μœΌλ‘œ λ‚˜λˆ„μ–΄ κ΅¬μ—­λ³„λ‘œ

λ‹€λ₯Έ μ±…μž„μ„ κ°€μ§€λŠ” μžμ‹ λ·°μ»¨νŠΈλ‘€λŸ¬λ“€μ„ κ΄€λ¦¬ν•©λ‹ˆλ‹€.

 

μ•„μ΄νŒ¨λ“œμ—μ„œ μ‰½κ²Œ λ³Ό μˆ˜μžˆλŠ” UI ꡬ성인데, 보톡 μ™Όμͺ½μ— Table VC, 였λ₯Έμͺ½μ— Content VC κ°€ λ“€μ–΄κ°€λŠ” 것 자주 보셨죠?

 

 


 

 

UIContainerViewController κ°€ κ³΅μ‹λ¬Έμ„œμ— μ—†μ–΄μš” πŸ€”

 

μ• ν”Œ κ³΅μ‹λ¬Έμ„œμ—μ„œ 찾아보면 μ•„μ‹œκ² μ§€λ§Œ, UIContainerViewController 와 같은 ν΄λž˜μŠ€λŠ” μ—†μŠ΅λ‹ˆλ‹€.

 

Container View Controller λŠ” ν•˜λ‚˜μ˜ κ°œλ…μ΄λ©°, 기쑴에 μ‘΄μž¬ν•˜λŠ” ν΄λž˜μŠ€λ“€μ„ μ΄μš©ν•΄μ„œ μ»€μŠ€ν…€ κ΅¬ν˜„ν•΄μ•Ό ν•©λ‹ˆλ‹€.

 

UIViewController λ₯Ό μ„œλΈŒν΄λž˜μ‹±ν•˜μ—¬ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

 

" A custom UIViewController subclass can also act as a container view controller. "

 

λ§Œμ•½ μ»€μŠ€ν…€ ν•˜μ§€ μ•Šκ³  μ‰½κ²Œ μ‚¬μš©ν•˜κ³  μ‹Άλ‹€λ©΄,

UINavigationController, UITabBarControler 와 같이 System Container View Controller λ₯Ό μ‚¬μš©ν•΄μ•Όν•©λ‹ˆλ‹€.

 

이 ν΄λž˜μŠ€λ“€μ€ 클래슀만의 λ°©μ‹λŒ€λ‘œ ν•˜μœ„ λ·° μ»¨νŠΈλ‘€λŸ¬λ“€μ„ κ΄€λ¦¬ν•©λ‹ˆλ‹€.

 

각 μ»¨ν…Œμ΄λ„ˆ VC λ“€μ˜ νŠΉμ„±λ“€μ„ μ΄ν•΄ν•˜κ³  μš©λ„μ— 맞게 μ‚¬μš©ν•˜λ©΄ λ©λ‹ˆλ‹€.

λŒ€ν‘œμ μΈ μ‹œμŠ€ν…œ μ»¨ν…Œμ΄λ„ˆ 뷰컨트둀러인 λ„€λΉ„κ²Œμ΄μ…˜ 컨트둀러의 μ˜ˆμ‹œ ( κΈ°λ³Έμ‹œκ³„ μ•± )

 

 

μ»€μŠ€ν…€ μ»¨ν…Œμ΄λ„ˆ λ·° 컨트둀러의 μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬μ„±ν•˜λŠ” 것은 μ»€μŠ€ν…€ν•˜λŠ” μ‚¬λžŒμ˜ λͺ«μž…λ‹ˆλ‹€.

 

예λ₯Ό λ“€μ–΄ μžμ‹ λ·° 컨트둀러의 화면을 κ·ΈλŒ€λ‘œ 보여쀄 μˆ˜λ„ 있고,

μ›ν•˜λŠ” λ ˆμ΄μ•„μ›ƒμ„ μ„€μ •ν•΄μ„œ λ³΄μ—¬μ€„μˆ˜λ„ 있고 ( 예λ₯Ό λ“€μ–΄ ν™”λ©΄ 반반)

ν˜Ήμ€ 미리 κ΅¬ν˜„λœ container view λ₯Ό μ‚¬μš©ν•΄λ³Ό μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.


 

Container View λŠ” 또 λ­”κ°€μš”

 

"  A container view is a proxy view that stands in for the content of a child view controller. "

 

μ»¨ν…Œμ΄λ„ˆ λ·°λŠ” μΈν„°νŽ˜μ΄μŠ€ λΉŒλ”μ—μ„œλ§Œ μΆ”κ°€ν•  수 μžˆλŠ” μΌμ’…μ˜ ν”„λ‘μ‹œ λ·°μž…λ‹ˆλ‹€.

μ»¨ν…Œμ΄λ„ˆ λ·°λŠ” 였브젝트 λΌμ΄λΈŒλŸ¬λ¦¬μ—μ„œλ§Œ μ°Ύμ•„μ„œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

 

μ•„λž˜ 사진을 λ³΄μ‹œλ©΄

μ™Όμͺ½μ˜ 씬에 μΆ”κ°€ν•œ Container View λŠ”  

κΈ°μ‘΄ VC 와 μƒˆλ‘œμš΄ 였λ₯Έμͺ½μ˜ VC 둜 이어진 Embed Segue 둜의 연결을 ν†΅ν•˜μ—¬ μ»¨ν…μΈ λ₯Ό ν‘œμ‹œν•©λ‹ˆλ‹€.

κ·Έλž˜μ„œ λ§Œμ•½ μ™Όμͺ½ VC μ°Έμ‘° μ–»μœΌλ €λ©΄ prepare(forSegue:~) μ—μ„œ 전달해야함

 

즉 μ™Όμͺ½μ˜ Container View μ˜μ—­μ— 였λ₯Έμͺ½μ˜ VC 의 λ·° 계측을 λ³΄μ—¬μ£ΌλŠ” 것이죠!

 

λ·° μ»¨νŠΈλ‘€λŸ¬μ™€ μ—°κ²°λœ Embed Segue 을 보싀 수 μžˆμŠ΅λ‹ˆλ‹€

 

μ–˜λŠ” κ³΅μ‹λ¬Έμ„œλ„ μ—†μŒ;;;;;;;;;;

Container View λŠ” κ³΅μ‹λ¬Έμ„œκ°€ μ—†λ‹€

 


 

Custom Container View Controller κ΅¬ν˜„

 

기본적인 μ»¨ν…Œμ΄λ„ˆ λ·° 컨트둀러의 λ™μž‘μ„ μˆ˜ν–‰ν•˜λŠ” μ½”λ“œλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

μ£Όμ„μœΌλ‘œ μ„€λͺ…을 μ²¨λΆ€ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

// ν˜„μž¬μ˜ λ·° μ»¨νŠΈλ‘€λŸ¬μ— μžμ‹ λ·° 컨트둀러λ₯Ό μΆ”κ°€ν•˜λŠ” μ½”λ“œ
let storyboard = UIStoryboard(name: "Main", bundle: .main)
if let viewController = storyboard.instantiateViewController(identifier: "imageViewController")
                                    as? ImageViewController {

   // 핡심 λ©”μ†Œλ“œλ‘œμ„œ, λ·° μ»¨νŠΈλ‘€λŸ¬μ— λΆ€λͺ¨-μžμ‹ 관계λ₯Ό ν˜•μ„±ν•œλ‹€
   addChild(viewController)
   
   // μžμ‹ λ·° 컨트둀러의 루트 λ·°λ₯Ό ν˜„μž¬ 뷰의 λ·° 계측에 μΆ”κ°€ν•˜λŠ” μ½”λ“œ
   view.addSubview(viewController.view)
            
   // μ œμ•½ 생성
   onscreenConstraints = configureConstraintsForContainedView(containedView: viewController.view,
                             stage: .onscreen)
   NSLayoutConstraint.activate(onscreenConstraints)
     
   // ν™”λ©΄ μ „ν™˜μ΄ μ™„λ£Œλ˜μ—ˆλ‹€λ©΄ μžμ‹ λ·° 컨트둀러의 λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•˜μ—¬ μ•Œλ €μ€€λ‹€.
   viewController.didMove(toParent: self)
}

이 뢀뢄에 λŒ€ν•œ μžμ„Έν•œ λ‚΄μš©μ€ μ•„λž˜ μ²¨λΆ€λœ 링크λ₯Ό 확인해보면 λ©λ‹ˆλ‹€


 

 

 

끝!


참고자료: https://developer.apple.com/documentation/uikit/view_controllers/creating_a_custom_container_view_controller/