iOS UIviewController控制器管理

在iOS 5.0以前,我们一般是这样使用UIViewController的:一个UIViewController的View可能有很多小的子view。这些子view很多时候被盖在最后,我们在最外层ViewController的viewDidLoad方法中,用addSubview增加了大量的子view。这些子view大多数不会一直处于界面上,只是在某些情况下才会出现。
在iOS 5.0及以后,iOS为UIViewController类添加了新的属性和方法:

1
2
3
4
5
6
7
@property(nonatomic,readonly) NSArray *childViewControllers

- (void)addChildViewController:(UIViewController *)childController
- (void)removeFromParentViewController
- (void)transitionFromViewController::::::
- (void)willMoveToParentViewController:(UIViewController *)parent
- (void)didMoveToParentViewController:(UIViewController *)parent

这样,就能够将一个页面中的UIViewController控制起来,而不是混乱的共用一个UIViewController.

下面就分别来说说这几个方法:

addChildViewController

向视图控制器容器中添加子视图控制器,当要添加的子视图控制器已经包含在视图控制器容器中,那么,相当于先从父视图控制器中删除,然后重新添加到父视图控制器中。

removeFromParentViewController

从父视图控制器中删除

transitionFromViewController

1
2
3
4
5
6
- (void)transitionFromViewController:(UIViewController *)fromViewController
toViewController:(UIViewController *)toViewController
duration:(NSTimeInterval)duration
options:(UIViewAnimationOptions)options
animations:(void (^)(void))animations
completion:(void (^)(BOOL finished))completion;

交换两个子视图控制器的位置(由于添加的顺序不同,所以子试图控制器在父视图控制器中存在层次关系)
各个参数的作用:
fromViewController:当前显示的子试图控制器,将被替换为非显示状态
toViewController:将要显示的子视图控制器
duration:交换动画持续的时间,单位秒
options:动画的方式
animations:动画Block
completion:完成后执行的Block

willMoveToParentViewController

官方文档:(部分段落的引用会出现空隙,不过不影响阅读)

Your view controller can override this method when it needs to know that it has been added to a container.
If you are implementing your own container view controller, it must call the willMoveToParentViewController: method of the child view controller before calling the removeFromParentViewController method, passing in a parent value of nil.
When your custom container calls the addChildViewController: method, it automatically calls the willMoveToParentViewController: method of the view controller to be added as a child before adding it.

当一个视图控制器从视图控制器容器中被添加或者被删除之前,该方法被调用

  1. 当我们向我们的视图控制器容器中调用removeFromParentViewController方法时,必须要先调用该方法,且parent参数为nil:
    [将要删除的视图控制器 willMoveToParentViewController:nil];
  2. 当我们调用addChildViewController方法时,在添加子视图控制器之前将自动调用该方法。所以,就不需要我们显示调用了。

didMoveToParentViewController

官方文档:

Your view controller can override this method when it wants to react to being added to a container.
If you are implementing your own container view controller, it must call the didMoveToParentViewController: method of the child view controller after the transition to the new controller is complete or, if there is no transition, immediately after calling the addChildViewController: method.
The removeFromParentViewController method automatically calls the didMoveToParentViewController: method of the child view controller after it removes the child.

当从一个视图控制容器中添加或者移除viewController后,该方法被调用。
当我们向我们的视图控制器容器(就是父视图控制器,它调用addChildViewController方法加入子视图控制器,它就成为了视图控制器的容器)中添加(或者删除)子视图控制器后,必须调用该方法,告诉iOS,已经完成添加(或删除)子控制器的操作。
removeFromParentViewController 方法会自动调用了该方法,所以,删除子控制器后,不需要在显示的调用该方法了

willMoveToParentViewController和didMoveToParentViewController的调用

对于这两个方法的调用,苹果有注释:

These two methods are public for container subclasses to call when transitioning between child controllers. If they are overridden, the overrides should ensure to call the super. The parent argument in both of these methods is nil when a child is being removed from its parent; otherwise it is equal to the new parent view controller. addChildViewController: will call [child willMoveToParentViewController:self] before adding the child. However, it will not call didMoveToParentViewController:. It is expected that a container view controller subclass will make this call after a transition to the new child has completed or, in the case of no transition, immediately after the call to addChildViewController:.
Similarly removeFromParentViewController: does not call [self willMoveToParentViewController:nil] before removing the child. This is also the responsibilty of the container subclass. Container subclasses will typically define a method that transitions to a new child by first calling addChildViewController:, then executing a transition which will add the new child’s view into the view hierarchy of its parent, and finally will call didMoveToParentViewController:. Similarly, subclasses will typically define a method that removes a child in the reverse manner by first calling [child willMoveToParentViewController:nil].

  • 这两个方法用在子试图控制器交换的时候调用!即调用transitionFromViewController 方法时会调用这两个方法。

  • 当调用willMoveToParentViewController方法或didMoveToParentViewController方法时,要注意他们的参数使用:
    当某个子视图控制器将从父视图控制器中删除时,parent参数为nil。
    即:[将被删除的子试图控制器 willMoveToParentViewController:nil];
    当某个子试图控制器将加入到父视图控制器时,parent参数为父视图控制器。
    即:[将被加入的子视图控制器 didMoveToParentViewController:父视图控制器];

  • 当调用[父视图控制器 addChildViewController:子视图控制器]时,默认调用[子视图控制器 willMoveToParentViewController:父视图控制器]。只需要在transitionFromViewController方法后,调用[子视图控制器 didMoveToParentViewController:父视图控制器];

  • 当调用[子视图控制器 removeFromParentViewController]时,默认调用[子视图控制器 didMoveToParentViewController:父视图控制器]。只需要在transitionFromViewController方法之前调用:[子视图控制器 willMoveToParentViewController:nil].