code

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

codestyles 2020. 8. 23. 09:14
반응형

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


난 그냥 아이폰 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를 배열에 팝하는 것 이상의 중요한 목적을 수행한다고 가정하지만 알아낼 수는 없습니다. 그 목적이 무엇인지. 이 메서드의 기능은 무엇이며 왜 호출해야합니까?


I was wondering about this question too. I watched Session 102 of the WWDC 2011 videos and Mr. View Controller, Bruce D. Nilo, said this:

viewWillAppear:, viewDidAppear:, etc have nothing to do with addChildViewController:. All that addChildViewController: does is to say "This view controller is a child of that one" and it has nothing to do with view appearance. When they get called is associated with when views move in and out of the window hierarchy.

So it seems that the call to addChildViewController: does very little. The side effects of the call are the important part. They come from the parentViewController and childViewControllers relationships. Here are some of the side effects that I know:

  • Forwarding appearance methods to child view controllers
  • Forwarding rotation methods
  • (Possibly) forwarding memory warnings
  • Avoiding inconsistent VC hierarchies, especially in transitionFromViewController:toViewController:… where both VCs need to have the same parent
  • Allowing custom container view controllers to take part in State Preservation and Restoration
  • Taking part in the responder chain
  • Hooking up the navigationController, tabBarController, etc properties

I think an example is worth a thousand words.

I was working on a library app and wanted to show a nice notepad view that appears when the user wants to add a note.

enter image description here

After trying some solutions, I ended up inventing my own custom solution to show the notepad. So when I want to show the notepad, I create a new instance of NotepadViewController and add its root view as a subview to the main view. So far so good.

Then I noticed that the notepad image is partially hidden under the keyboard in landscape mode.

enter image description here

So I wanted to change the notepad image and shift it up. And to do so, I wrote the proper code in willAnimateRotationToInterfaceOrientation:duration: method, but when I ran the app nothing happened! And after debugging I noticed that none of UIViewController's rotation methods is actually called in NotepadViewController. Only those methods in the main view controller are being called.

To solve this, I needed to call all the methods from NotepadViewController manually when they're called in the main view controller. This will soon make things complicated and create an extra dependency between unrelated components in the app.

That was in the past, before the concept of child view controllers is introduced. But now, you only need to addChildViewController to the main view controller and everything will just work as expected without any more manual work.

Edit: There are two categories of events that are forwarded to child view controllers:

1- Appearance Methods:

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

2- Rotation Methods:

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

You can also control what event categories you want to be forwarded automatically by overriding shouldAutomaticallyForwardRotationMethods and shouldAutomaticallyForwardAppearanceMethods.


-[UIViewController addChildViewController:] only adds the passed in view controller in an array of viewControllers that a viewController (the parent) wants to keep reference of. You should actually add those viewController's views on screen yourself by adding them as a subviews of another view (e.g. the parentViewController's view). There's also a convenience object in Interface Builder to use childrenViewControllers in Storyboards.

Previously, to keep reference of other viewControllers of which you used the views of, you had to keep manual reference of them in @properties. Having a build-in property like childViewControllers and consequently parentViewController is a convenient way to manage such interactions and build composed viewControllers like the UISplitViewController that you find on iPad apps.

Moreover, childrenViewControllers also automatically receive all the system events that the parent receives: -viewWillAppear, -viewWillDisappear, etc. Previously you should have called this methods manually on your "childrenViewControllers".

That's it.

참고URL : https://stackoverflow.com/questions/17192005/what-does-addchildviewcontroller-actually-do

반응형