UISearchDisplayController autorelease 如何在不同的视图控制器中导致崩溃?

Posted

技术标签:

【中文标题】UISearchDisplayController autorelease 如何在不同的视图控制器中导致崩溃?【英文标题】:How can UISearchDisplayController autorelease cause crash in a different view controller? 【发布时间】:2010-05-03 14:04:25 【问题描述】:

我有两个视图控制器 A 和 B。我从 A 导航到视图控制器 B,如下所示:

// in View Controller A 
// navigateToB method

-(void) navigateToB 

BViewController *bViewController = 
[[BViewController alloc] initWithNibName: @"BView" bundle:nil];

bViewController.bProperty1 = SOME_STRING_CONSTANT;
bViewController.title = @"A TITLE OF A VC's CHOOSING"; 
[self.navigationController pushViewController: bViewController animated:YES];
[bViewController release]; //<----- releasing 0x406c1e0


在 BViewController 中,属性 bPropery1 定义如下(注意,B 还包含 UITableView 和其他属性):

@property (nonatomic, copy) NSString *bProperty1;

在 A 和 B 之间来回导航时,一切似乎都运行良好。直到我将 UISearchDisplayController 添加到 BViewController 中包含的表视图中。现在,当我从 B 导航到 A 时,应用程序崩溃了。

堆栈跟踪显示了崩溃时自动释放的搜索显示控制器的外观:

#0 0x009663a7 in ___forwarding___
#1 0x009426c2 in __forwarding_prep_0___
#2 0x018c8539 in -[UISearchDisplayController _destroyManagedTableView]
#3 0x018c8ea4 in -[UISearchDisplayController dealloc]
#4 0x00285ce5 in NSPopAutoreleasePool

NSZombies 节目:

-[BViewController respondsToSelector:]: message sent to deallocated instance 0x406c1e0

并且关于这个的 malloc 历史指向已经在上面 A 的 navigateToB 方法中释放的 bViewController:

    Call [2] [arg=132]: thread_a065e720 |start  ... <snip> 
..._sendActionsForEvents:withEvent:] | -[UIControl sendAction:to:forEvent:] | -
[UIApplication sendAction:to:from:forEvent:] | -[**AViewController navigateToB**] | 
+[NSObject alloc] | +[NSObject allocWithZone:] | _internal_class_createInstance | 
_internal_class_createInstanceFromZone | calloc | malloc_zone_calloc 

有人可以就这里发生的事情给我任何想法吗?在 navigateToB 方法中,一旦 bViewController 被释放(在 pushViewController 之后),bViewController 应该就是它了。其他人甚至都不知道它,因为它位于 navigateToB 方法块的本地并且已被释放。

当从 B 导航回 A 时,不会在 viewDidLoad、viewWillAppear 等中调用任何会重新进入 navigateToB 的内容。

看起来搜索显示控制器以某种方式引用了我的 AViewController 中的某些内容,因此由于它是自动释放的,因此它正在将这个“某些东西”拿下来,但我不明白这是怎么可能的,尤其是当我使用副本时在 A 和 B 之间传递数据。

我要为此而烦恼。我确定这是我在某个地方的错误,所以我求助于 Stack Overflow 的传奇人物,寻求任何关于如何解决这个问题的智慧或建议。

非常感谢。

【问题讨论】:

【参考方案1】:

通过将这些行添加到作为 UISearchDisplayController 委托的 UITableViewController 的 dealloc 方法中,我解决了类似的问题:

self.searchDisplayController.delegate = nil;
self.searchDisplayController.searchResultsDelegate = nil;
self.searchDisplayController.searchResultsDataSource = nil;

我对解决这个问题的建议有点困惑,应该在 dealloc 中释放搜索显示控制器 - 你需要做的是删除搜索显示控制器对你的表视图控制器的指针,因为你的表视图控制器现在消失了,以后发布搜索显示控制器时不应调用它。就像您想在 dealloc 中取消的任何其他委托引用一样。

【讨论】:

这对我有用。我以为我不需要这样做,因为我使用的是 ARC,但我将这些行添加到带有搜索显示控制器的视图控制器的 dealloc 方法中,我的工作就像一个魅力!我想知道这是否是一个错误...... @cgossain 这些属性在 UISearchDisplayController 中是“非原子的,赋值”,因此,无效的引用会破坏事情。恕我直言,我们需要向 Apple 提交 RFE 以使它们“非原子、弱”。【参考方案2】:

当您将视图控制器推送到导航控制器时,导航控制器会保留视图控制器。当视图控制器弹出时,导航控制器会释放它。

UISearchDisplayController 似乎正在尝试查看您的视图控制器是否响应选择器,并且由于它是从 _destroyManagedTableView 调用的,我猜选择器是 searchDisplayController:willUnloadSearchResultsTableView: (您的视图控制器是搜索显示控制器的委托,对吗? )。

@robert - 这个例子一定是错误的,因为 pushViewController 确实保留了它的参数。页面上的所有其他示例要么在初始化后立即自动释放,要么在推送后释放。

【讨论】:

谢谢布赖恩。 BViewController 是搜索显示控制器的委托,尽管 malloc 历史记录在跟踪中显示 AViewController(我猜这是因为它显示了 BViewController 的来源?)。听起来 UISearchDisplayController 正在尝试向其已发布的委托发送消息?我是否需要在 BViewController 的 dealloc 中以某种方式释放/取消 UISearchDisplayController? 是的,搜索显示控制器应该在 BViewController 的 dealloc 中释放(以及在 BViewController 的 init 中创建的任何其他内容,或由 nib 加载并分配给 IBOutlet)。 谢谢,似乎工作正常,你太棒了!我将继续测试和监控(当然也将答案奖励给你 :))但我现在看到了正在发生的事情。顺便说一句,我之前评论“我需要以某种方式”发布 UISearchDisplayController 的原因是我从未为搜索显示控制器创建 IBOutlet。最初,在 IB 中,当我拖放新的 UISearchDisplayController 控件时,它似乎自动与文件所有者链接。现在我意识到,拥有一个显式 IBOutlet 可以让我释放搜索显示控制器及其委托视图控制器 (BViewController)。 有一个明确的出口是缺少的一件事,谢谢。这不是很明显:您在 IB 中看到它,但它与 view 内置插座非常不同!【参考方案3】:

我有同样的问题。 searchDisplayController 在使用它的 View 控制器的 dealloc 中没有被设为 nil。相反,委托管理了 searchDisplayController 的释放,这是在 tableView 被释放之后完成的。 现在在视图控制器的 dealloc 中手动输入此代码后,它现在可以正常工作了。

self.searchDisplayController.delegate = nil; self.searchDisplayController.searchResultsDelegate = nil; self.searchDisplayController.searchResultsDataSource = nil;

感谢您的帮助。

【讨论】:

以上是关于UISearchDisplayController autorelease 如何在不同的视图控制器中导致崩溃?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 UISearchDisplayController 有时有效,有时无效?

iOS UISearchDisplayController学习笔记

在 UISearchDisplayController 上遇到僵尸问题

修复 UITableView 顶部的 UISearchdisplaycontroller 搜索栏

iphone隐藏UISearchDisplayController结果?

在 UISearchDisplayController 中设置 UISearchBar 的边框颜色