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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章