使用 UISearchBar 作为 UITableView 的 header 视图不可避免的保留周期?

Unavoidable retain cycle using UISearchBar as UITableView's header view?

我 运行 进入这个问题是因为我正在构建一个使用 UISearchController 和它的 UISearchBar 成员的基本 UI。我的 tableView 是一个弱 IBOutlet,就像 Apple Docs 演示的那样,我将它的 tableHeaderView 属性 设置为搜索栏成员。

//Snippet from viewDidLoad
UISearchController* searchController = [self createSearchController];
UISearchBar* searchBar = searchController.searchBar;
searchBar.userInteractionEnabled = NO;

self.tableView.tableHeaderView = searchBar; //The assignment in question

[NetworkStuff makeCall:^(Response *response) {
    //handle success
    searchBar.userInteractionEnabled = YES; //local variables
    searchController.active = YES;
    ...
} failure:^(Response *response) {
    //handle failure
    ...
}];

当我从堆栈中弹出视图时,它的 dealloc 方法永远不会被调用,即使我在 viewWillDisappear: 中将 tableHeaderView 设置为 nil 也是如此。我需要注释掉的唯一一行才能看到调用的 dealloc 是初始分配。

有人知道为什么会发生这种情况吗?

编辑:

发现了一些有趣的行为。同样根据 Apple Docs,我将控制器的 definesPresentationContext 变量设置为 YES。在将 tableViewHeader 赋值保留在固定的保留周期中时注释掉这一点,即使我没有消除 tableViewHeader。但是,在viewDidLoad中设置definesPresentationContext并在viewWillDisappear中清除它re-introduces保留周期。

偶然发现这个答案: UISearchController retain issue

该解决方案似乎在 viewDidDisappear: 中明确取消了 UISearchController(请注意,我无法在 viewWillDisappear: 中使用它)。由于该代码在 swift 中,我将在此处将其转录为 Objective-C:

- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];

    if (!self.presentingViewController) {
        [self.searchController dismissViewControllerAnimated:NO completion:nil];
    }
}

正如原始答案所指出的,检查 self.presentingViewController 不存在在另一个视图控制器被推到视图顶部的情况下很有帮助,因为我们会回到这一页。很可能,我们只想在弹出包含它的视图控制器时关闭 searchController。