UIViewController如何作为父容器管理子容器

UIViewController新增了作为容器添加子容器的方法

/*
  苹果官方注释
  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].
*/

- (void)willMoveToParentViewController:(nullable UIViewController *)parent NS_AVAILABLE_IOS(5_0);
- (void)didMoveToParentViewController:(nullable UIViewController *)parent NS_AVAILABLE_IOS(5_0);
  • 当在子视图控制器与父视图控制器与互相进行过渡的时候,子视图控制器可以调用这两个公开的方法。

  • 如果重写了这两个方法,在重写的方法里面一定要调用父视图控制器的方法。

  • 当子视图控制器从他们的父视图控制器中移除的时候,后面的parent参数都要填nil;否则,则要填新的父视图控制器。

  • 当某个子视图控制器将从父视图控制器中删除时,parent参数为nil。
    即:[将被删除的子试图控制器 willMoveToParentViewController:nil];

  • 当某个子试图控制器将加入到父视图控制器时,parent参数为父视图控制器。
    即:[将被加入的子视图控制器 didMoveToParentViewController:父视图控制器];

  • 当调用 addChildViewController:这个方法添加子视图控制器的时候,会自动调用[child willMoveToParentViewController:self]方法;
    然而,这时候并不会去调用 didMoveToParentViewController:方法;

  • 因此

  1. 一个容器的子视图控制器过渡到另一个子类控制器完成之后,会调用 didMoveToParentViewController: 方法
  2. 没有过渡到另一个子类控制器, 当调用 addChildViewController:方法后会马上调用didMoveToParentViewController:方法
  • 相似的 用removeFromParentViewController:这个方法, 在移除子容器之前不会调用[self willMoveToParentViewController:nil] 方法
这也是父视图控制器的职责
  • 父视图控制器应当定义一个方法用于过渡到一个新的子视图控制器, 方法里面要先调用addChildViewController:方法
    然后执行过渡,执行完之后会将子视图控制器加到他的父视图控制器之中,然后最后会调用didMoveToParentViewController:方法

  • 相似的,父视图控制器需要定义一个相反的方式--来移除子容器的方法,方法需要首先调用 [child willMoveToParentViewController:nil]方法


以上是本人对这两个方法的官方注释的翻译, 下面结合这些注释谈谈这两个方法的使用

  • 在iOS 5.0之前,只能在UIViewController的View中通过addSubView的方法来添加子view,而有一些View是不需要一直出现的,但是在ViewDidLoad之后,则会一起加载到内存中,影响性能的同时不方便管理。
  • 在在iOS 5.0及以后,iOS为UIViewController类添加了新的属性和方法:
@property(nonatomic,readonly) NSArray *childViewControllers

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

这样,就能够将一个页面中的UIViewController控制起来,而不是混乱的共用一个UIViewController,最重要的是,编程习惯的革命:降低了功能的耦合度!

[父视图控制器 addChildViewController:子视图控制器];

在此,图控制器A添加了另一个图控制器B,那么A充当父视图控制器,B充当子视图控制器。父视图控制器充当了视图控制器容器的角色。

addChildViewController方法:

- (void)addChildViewController:(UIViewController *)childController

向视图控制器容器中添加子视图控制器


childController:子视图控制器

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

removeFromParentViewController 方法

  • (void)removeFromParentViewController
    从父视图控制器中删除。

transitionFromViewController 方法

- (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 方法

- (void)willMoveToParentViewController:(UIViewController *)parent

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

parent:父视图控制器,如果没有父视图控制器,将为nil

注意点:

  1. 当我们向我们的视图控制器容器中调用removeFromParentViewController方法时,必须要先调用该方法,且parent参数为nil
[将要删除的视图控制器 willMoveToParentViewController:nil];
  • 当我们调用addChildViewController方法时,在添加子视图控制器之前将自动调用该方法。所以,就不需要我们显示调用了。
  1. 当从一个视图控制容器中添加或者移除viewController后,该方法被调用。
    parent:父视图控制器,如果没有父视图控制器,将为nil
//didMoveToParentViewController 方法
 - (void)didMoveToParentViewController:(UIViewController *)parent
  • 当我们向我们的视图控制器容器(就是父视图控制器,它调用addChildViewController方法加入子视图控制器,它就成为了视图控制器的容器)中添加(或者删除)子视图控制器后,必须调用该方法,告诉iOS,已经完成添加(或删除)子控制器的操作。
  • removeFromParentViewController 方法会自动调用了该方法,所以,删除子控制器后,不需要在显示的调用该方法了。

其实,这几个方法中的API说明,看的还懂。

最后,

关于willMoveToParentViewController方法和didMoveToParentViewController方法的使用

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

  2. 当调用willMoveToParentViewController方法或didMoveToParentViewController方法时,要注意他们的参数使用:

  • 当某个子视图控制器将从父视图控制器中删除时,parent参数为nil
[将被删除的子试图控制器 willMoveToParentViewController:nil];
  • 当某个子试图控制器将加入到父视图控制器时,parent参数为父视图控制器。
[将被加入的子视图控制器 didMoveToParentViewController:父视图控制器];
  1. 无需调用[子视图控制器 willMoveToParentViewController:父视图控制器]方法。因为我们调用[父视图控制器 addChildViewController:子视图控制器]时,已经默认调用了。
    只需要在transitionFromViewController方法后,调用
[子视图控制器didMoveToParentViewController:父视图控制器]
  1. 无需调用[子视图控制器 didMoveToParentViewController:父视图控制器]方法。因为我们调用
    [子视图控制器 removeFromParentViewController]时,已经默认调用了。
    只需要在transitionFromViewController方法之前调用:
[子视图控制器 willMoveToParentViewController:nil]
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341

推荐阅读更多精彩内容