今天在項目中檢查循環引用問題的時候遇到了此問題,查詢了別的頁面,發現打印log並不一樣。所以查閱了資料,這裏記錄一下。
很多時候,我們都會遇到,在一個viewController中,添加別的controller,已達到特殊的轉場效果,或者爲了用戶能在一個頁面看到並和多個頁面的內容交互的效果。
因此,蘋果給我們提供了這個概念,和實現方法:addChildViewController
這裏有一個使用場景,
- 頁面初始化的時候,在viewDidLoad中添加了子控制器,此時先加載緩存數據(也就是頁面會先展示)
- 然後展示的同時,重新調用接口,拉取數據。
- 得到數據之後,重新刷新頁面
相信大部分人也都是這麼實現的。
因此,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