iOS AddChildViewController遇到的问题

Posted wwwwwwwwwwwwdi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS AddChildViewController遇到的问题相关的知识,希望对你有一定的参考价值。

今天在项目中检查循环引用问题的时候遇到了此问题,查询了别的页面,发现打印log并不一样。所以查阅了资料,这里记录一下。

很多时候,我们都会遇到,在一个viewController中,添加别的controller,已达到特殊的转场效果,或者为了用户能在一个页面看到并和多个页面的内容交互的效果。
因此,苹果给我们提供了这个概念,和实现方法:addChildViewController

这里有一个使用场景,

  1. 页面初始化的时候,在viewDidLoad中添加了子控制器,此时先加载缓存数据(也就是页面会先展示)
  2. 然后展示的同时,重新调用接口,拉取数据。
  3. 得到数据之后,重新刷新页面

相信大部分人也都是这么实现的。

因此,demo中是这么写的:

A(ViewController)页面中有一个按钮,跳转到B(TestViewController)页面, 然后B页面中有两个按钮,第一个按钮用来第一次添加childViewController->C页面(SecViewController), 第二个页面,用来模拟网络请求得到结果之后,重新刷新布局的操作。

这里有一个上述操作打印的log图

可以看到中间很醒目的dealloc!此处就造成了我的疑惑
然后来看下containerViewController中是怎么实现的:

//TestViewController.m
- (void)configureWithData:(NSArray *)array
if (!array.count) return;


NSLog(@"~~~~~~~~~~~~~~~~~~~~%@ ---- %@ 前",NSStringFromClass([self class]), NSStringFromSelector(_cmd));
[self.childViewControllers makeObjectsPerformSelector:@selector(removeFromParentViewController)];
NSLog(@"~~~~~~~~~~~~~~~~~~~~%@ ---- %@ 后",NSStringFromClass([self class]), NSStringFromSelector(_cmd));


[array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) 
SecViewController *listVC = [[SecViewController alloc] init];
listVC.view.frame = self.view.bounds;
listVC.parentContainerViewController = self;
[self addChildViewController:listVC];
//        [listVC didMoveToParentViewController:self];
];

此方法在重新布局UI的时候调用。

可以看到;其中有一句

[self.childViewControllers makeObjectsPerformSelector:@selector(removeFromParentViewController)];

此处记录一下:
苹果官方文档中是这么描述的:

### Removing a Child View Controller

To remove a child view controller from your content, remove the parent-child relationship between the view controllers by doing the following:

1.  Call the child’s `[willMoveToParentViewController:](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621381-willmovetoparentviewcontroller)` method with the value `nil`.

2.  Remove any constraints that you configured with the child’s root view.

3.  Remove the child’s root view from your container’s view hierarchy.

4.  Call the child’s `[removeFromParentViewController](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621425-removefromparentviewcontroller)` method to finalize the end of the parent-child relationship.

Removing a child view controller permanently severs the relationship between parent and child. Remove a child view controller only when you no longer need to refer to it. For example, a navigation controller does not remove its current child view controllers when a new one is pushed onto the navigation stack. It removes them only when they are popped off the stack.

大致意思就是:
如果想要移除一个子控制器,需要自控制器调用willMoveToParentViewController, 移除子控制器view在父视图中的位置约束,从父容器的层级中移除子控制器,然后调用子控制器的removeFromParentViewController
此种操作,就会造成子控制器不再被引用,然后执行了dealloc方法
所以,此处就会造成, 在进入一个页面的时候(默认是只在dealloc处打印了,没有在viewDidLoad处打印),先看到了子控制器的dealloc

Demo

以上是关于iOS AddChildViewController遇到的问题的主要内容,如果未能解决你的问题,请参考以下文章

IO模型--阻塞IO,非阻塞IO,IO多路复用,异步IO

IO复用阻塞IO非阻塞IO同步IO异步IO

四种IO模型‘阻塞IO/非阻塞IO/信号驱动IO/异步IO‘

5种IO模型阻塞IO和非阻塞IO同步IO和异步IO

网络IO模型:同步IO和异步IO,阻塞IO和非阻塞IO

同步IO异步IO阻塞IO非阻塞IO之间的联系与区别