addChildViewController는 실제로 무엇을합니까?


102

난 그냥 아이폰 OS 개발에 처음으로 내 발을 담그고있어, 내가해야 할 일을했을 한 첫 번째 것들 중 하나가 구현이다 사용자 정의 컨테이너 뷰 컨트롤러 - 호출 할 수 있습니다 SideBarViewController-이 스왑을 몇 가지 가능한 아이 뷰 컨트롤러의 어느 그것을 밖으로 표준 탭 막대 컨트롤러 와 거의 똑같습니다 . (대부분의 탭 바 컨트롤러 이지만 탭 바 대신 숨길 수있는 사이드 메뉴가 있습니다.)

Apple 문서의 지침에 따라 addChildViewController컨테이너에 자식 ViewController를 추가 할 때마다 호출 합니다. 현재 자식 뷰 컨트롤러를 교체하는 코드는 SideBarViewController다음과 같습니다.

- (void)showViewController:(UIViewController *)newViewController {
    UIViewController* oldViewController = [self.childViewControllers 
                                           objectAtIndex:0];
    
    [oldViewController removeFromParentViewController];
    [oldViewController.view removeFromSuperview];
    
    newViewController.view.frame = CGRectMake(
        0, 0, self.view.frame.size.width, self.view.frame.size.height
    );
    [self addChildViewController: newViewController];
    [self.view addSubview: newViewController.view];
}

그런 다음 나는 addChildViewController여기서 무엇을하는지 알아 내기 시작했고 , 나는 전혀 모른다는 것을 깨달았습니다. 새로운 ViewController것을 .childViewControllers배열에 붙이는 것 외에는 아무것도 영향을 미치지 않는 것 같습니다. 자식 컨트롤러의 관점에서 스토리 보드에 설정 한 자식 컨트롤러에 대한 액션과 아웃렛은를 호출하지 않더라도 여전히 잘 작동 addChildViewController하며 다른 것에 영향을 미칠 수 있다고 상상할 수 없습니다.

실제로 호출하지 않도록 코드를 다시 작성 addChildViewController하고 대신 다음과 같이 보이면 ...

- (void)showViewController:(UIViewController *)newViewController {

    // Get the current child from a member variable of `SideBarViewController`
    UIViewController* oldViewController = currentChildViewController;

    [oldViewController.view removeFromSuperview];

    newViewController.view.frame = CGRectMake(
        0, 0, self.view.frame.size.width, self.view.frame.size.height
    );
    [self.view addSubview: newViewController.view];

    currentChildViewController = newViewController;
}

... 내 앱은 여전히 ​​완벽하게 작동합니다.

애플 문서는 무엇을하는지 addChildViewController, 왜 우리가 그것을 불러야하는지 에 대해 많이 밝히지 않습니다 . UIViewController클래스 참조 의 섹션에서 메서드가 수행하는 작업 또는 사용해야하는 이유에 대한 관련 설명의 전체 범위는 현재 다음과 같습니다.

지정된 뷰 컨트롤러를 자식으로 추가합니다. ...이 메서드는 사용자 지정 컨테이너 뷰 컨트롤러 구현에 의해서만 호출됩니다. 이 메서드를 재정의하는 경우 구현에서 super를 호출해야합니다.

같은 페이지의 앞부분에도이 단락이 있습니다.

컨테이너 뷰 컨트롤러는 자식의 루트 뷰를 뷰 계층 구조에 추가하기 전에 자식 뷰 컨트롤러를 자신과 연결해야합니다. 이를 통해 iOS는 이벤트를 자식보기 컨트롤러와 해당 컨트롤러가 관리하는보기로 적절하게 라우팅 할 수 있습니다. 마찬가지로 뷰 계층 구조에서 자식의 루트 뷰를 제거한 후에는 해당 자식 뷰 컨트롤러를 자체에서 연결 해제해야합니다. 이러한 연결을 만들거나 끊기 위해 컨테이너는 기본 클래스에 정의 된 특정 메서드를 호출합니다. 이러한 메서드는 컨테이너 클래스의 클라이언트가 호출하기위한 것이 아닙니다. 예상되는 격리 동작을 제공하기 위해 컨테이너의 구현에서만 사용됩니다.

다음은 호출해야하는 필수 메서드입니다.

addChildViewController :
removeFromParentViewController
willMoveToParentViewController :
didMoveToParentViewController :

그러나 그것이 말하는 '사건'또는 '예상 격리 행동'이 무엇인지, 또는 이러한 메서드를 호출하는 이유 (또는 언제)가 '필수적'인지에 대한 단서를 제공하지 않습니다.

Apple 문서의 "Custom Container View Controllers"섹션에있는 사용자 지정 컨테이너보기 컨트롤러의 예제는 모두이 메서드를 호출하므로 자식 ViewController를 배열에 팝하는 것 이상의 중요한 목적을 수행한다고 가정하지만 알아낼 수는 없습니다. 그 목적이 무엇인지. 이 메서드의 기능은 무엇이며 왜 호출해야합니까?


3
Apple의 2011 WWDC 동영상 페이지에는 이 주제에 대한 훌륭한 세션 ( "UIViewController Containment 구현")이 있습니다.
Alladinian

답변:


94

저도이 질문에 대해 궁금합니다. 나는 WWDC 2011 비디오 의 Session 102를 보았고 Mr. View Controller, Bruce D. Nilo 는 이렇게 말했습니다.

viewWillAppear:, viewDidAppear:등은와 관련이 없습니다 addChildViewController:. 그 모든 addChildViewController:않는 "이 뷰 컨트롤러가 하나의 자식입니다"하고보기 모양과 아무 상관이 말을하는 것입니다. 호출 될 때 뷰가 창 계층 구조 안팎으로 이동할 때와 연관됩니다.

따라서에 대한 호출 addChildViewController:은 거의 작동하지 않는 것 같습니다 . 통화의 부작용이 중요한 부분입니다. 그들은 parentViewControllerchildViewControllers관계 에서 비롯됩니다 . 내가 아는 몇 가지 부작용은 다음과 같습니다.

  • 자식 뷰 컨트롤러에 모양 메서드 전달
  • 전달 회전 방법
  • (아마도) 메모리 경고 전달
  • 특히 transitionFromViewController:toViewController:…두 VC가 동일한 부모를 가져야하는 경우 일관되지 않은 VC 계층 구조 방지
  • 사용자 지정 컨테이너보기 컨트롤러가 상태 보존 및 복원에 참여하도록 허용
  • 응답자 체인에 참여
  • 위 매춘 navigationController, tabBarController등의 특성을

이 세션 (102)하지 (101)의
SeanChense

응답자 체인의 경우 +1입니다. 당신이 아이의 UIViewController가 소유 한 서브 뷰에 터치 이벤트를 수신 할 경우 addChildViewController가 필요합니다
charlieb

108

나는 예가 천 단어의 가치가 있다고 생각합니다.

저는 라이브러리 앱에서 작업하고 있었고 사용자가 메모를 추가하려고 할 때 나타나는 멋진 메모장보기를 표시하고 싶었습니다.

여기에 이미지 설명 입력

몇 가지 솔루션을 시도한 후 메모장을 표시하는 사용자 지정 솔루션을 발명했습니다. 따라서 메모장을 표시하고 싶을 때의 새 인스턴스를 만들고 NotepadViewController기본보기에 하위보기로 루트보기를 추가합니다. 여태까지는 그런대로 잘됐다.

그런 다음 메모장 이미지가 가로 모드에서 키보드 아래에 부분적으로 숨겨져 있음을 알았습니다.

여기에 이미지 설명 입력

그래서 메모장 이미지를 변경하고 위로 옮기고 싶었습니다. 이를 위해 willAnimateRotationToInterfaceOrientation:duration:메서드에 적절한 코드를 작성 했지만 앱을 실행했을 때 아무 일도 일어나지 않았습니다! 그리고 디버깅 후의 UIViewController회전 메서드가 실제로에서 호출 되지 않음을 알았 습니다 NotepadViewController. 메인 뷰 컨트롤러의 메서드 만 호출됩니다.

이를 해결하기 위해 NotepadViewController메인 뷰 컨트롤러에서 호출 될 때 모든 메서드를 수동으로 호출해야했습니다 . 이는 곧 상황을 복잡하게 만들고 앱의 관련없는 구성 요소간에 추가 종속성을 생성합니다.

이는 자식 뷰 컨트롤러 개념이 도입되기 전의 과거였습니다. 하지만 이제는 addChildViewController메인 뷰 컨트롤러 만 있으면 모든 것이 더 이상 수동 작업없이 예상대로 작동합니다.

편집 : 하위보기 컨트롤러로 전달되는 이벤트에는 두 가지 범주가 있습니다.

1- 외관 방법 :

- viewWillAppear:
- viewDidAppear:
- viewWillDisappear:
- viewDidDisappear:

2- 회전 방법 :

- willRotateToInterfaceOrientation:duration:
- willAnimateRotationToInterfaceOrientation:duration:
- didRotateFromInterfaceOrientation:

shouldAutomaticallyForwardRotationMethods및 을 재정 의하여 자동으로 전달할 이벤트 범주를 제어 할 수도 있습니다 shouldAutomaticallyForwardAppearanceMethods.


설명서에서 빠른 테스트를 수행 한 후 addChildViewController부모 컨트롤러 에만 전달되는 다른 이벤트가 없다고 생각 합니다.
Hejazi 2014-06-27

자동으로 원하는 전달 viewWillLayoutSubviews
MobileMon

10

-[UIViewController addChildViewController:]viewController (부모)가 참조를 유지하고자하는 viewController의 배열에 전달 된 view controller 만 추가합니다. 실제로 해당 viewController의 뷰를 다른 뷰 (예 : parentViewController의 뷰)의 하위 뷰로 추가하여 화면에 직접 추가해야합니다. Interface Builder에는 Storyboard에서 childrenViewController를 사용하는 편리한 개체도 있습니다.

이전에는 뷰를 사용한 다른 viewController에 대한 참조를 유지하려면 @properties에서 해당 뷰를 수동으로 참조해야했습니다. childViewControllers결과적 parentViewController으로 유사한 내장 속성을 갖는 것은 이러한 상호 작용을 관리하고 iPad 앱에서 찾을 수있는 UISplitViewController와 같은 구성된 viewController를 빌드하는 편리한 방법입니다.

또한 childrenViewControllers는 부모가받는 모든 시스템 이벤트 (-viewWillAppear, -viewWillDisappear 등)도 자동으로받습니다. 이전에는 "childrenViewControllers"에서이 메서드를 수동으로 호출 했어야했습니다.

그게 다야.


그게 전부라고 생각하는 근거는 무엇입니까? 또한 자녀가받은 '시스템 이벤트'목록을 제공 할 수 있습니까? 에 대한 Google 검색은 iOS "system events"많은 것을 던지지 않습니다. Apple이 사용하는 용어가 아닌 것 같습니다.
Mark Amery 2013-06-19

기본적으로 View Controller B의 뷰를 View Controller A의 하위 뷰로 추가 할 수있는 편리한 방법이지만 View Controller B가 해당 뷰를 관리하도록합니다. 이것이 제대로 작동하려면 View Controller B가 시스템 이벤트를 받고 있는지 확인해야합니다 (UIViewControllerDelegate 콜백 읽기). 'addChildViewController'는 수동으로 모든 것을 전달하는 수고를 덜기 위해 이것을 연결합니다.
Sam Clewlow
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.