UISearchDisplayController在viewDidUnload之后导致崩溃

时间:2011-12-19 21:02:15

标签: iphone uisearchdisplaycontroller uistoryboard

我有一个项目使用StoryBoards和UISearchDisplayControllerUINavigationController的上下文中使用,它出现在根视图控制器中。当我将一个新的视图控制器推入堆栈并导致模拟内存警告(或实际上得到一个低内存警告)。上一个视图控制器成功卸载其视图。但是,当我从堆栈中弹出第二个视图控制器时,我得到一个EXC_BAD_ACCESS。我打开NSZombies并发现了这个:

  

[UISearchDisplayController retain]:发送到解除分配的实例0xb13aa30的消息

我不是(至少在我的代码中)将该消息发送到UISearchDisplayController。用编程方式说,我没有做任何事情。断点显示我甚至没有进入第一个视图控制器的viewDidLoad

但是,有些好奇:因为笑声和笑声,我决定在retain中彻底viewDidLoad SDC,只是为了看看会发生什么,不会发生崩溃。但是,我的UISearchDisplayController实例是nil

我做了一个回溯并得到了这个输出:

#0  0x01e30e1e in ___forwarding___ ()
#1  0x01e30ce2 in __forwarding_prep_0___ ()
#2  0x01dd1490 in CFRetain ()
#3  0x01eb69c0 in +[__NSArrayI __new::] ()
#4  0x01e0a00a in -[__NSPlaceholderArray initWithObjects:count:] ()
#5  0x01e34f52 in +[NSArray arrayWithObjects:count:] ()
#6  0x01e5e084 in -[NSDictionary allValues] ()
#7  0x01035272 in -[UINib instantiateWithOwner:options:] ()
#8  0x00edce2c in -[UIViewController _loadViewFromNibNamed:bundle:] ()
#9  0x00edd3a9 in -[UIViewController loadView] ()
#10 0x00edd5cb in -[UIViewController view] ()
#11 0x00edd941 in -[UIViewController contentScrollView] ()
#12 0x00eef47d in -[UINavigationController _computeAndApplyScrollContentInsetDeltaForViewController:] ()
#13 0x00eef66f in -[UINavigationController _layoutViewController:] ()
#14 0x00eef93b in -[UINavigationController _startTransition:fromViewController:toViewController:] ()
#15 0x00ef03df in -[UINavigationController _startDeferredTransitionIfNeeded] ()
#16 0x00ef16cb in _popViewControllerNormal ()
#17 0x00ef196c in -[UINavigationController _popViewControllerWithTransition:allowPoppingLast:] ()
#18 0x0b446e82 in -[UINavigationControllerAccessibility(SafeCategory) _popViewControllerWithTransition:allowPoppingLast:] ()
#19 0x00ef0b10 in -[UINavigationController popViewControllerAnimated:] ()
#20 0x00ef297d in -[UINavigationController navigationBar:shouldPopItem:] ()
#21 0x00e7dabe in -[UINavigationBar _popNavigationItemWithTransition:] ()
#22 0x00e7da49 in -[UINavigationBar popNavigationItemAnimated:] ()
#23 0x0b42208c in -[UINavigationBarAccessibility(SafeCategory) popNavigationItemAnimated:] ()
#24 0x00e80507 in -[UINavigationBar _handleMouseUpAtPoint:] ()
#25 0x00e8074c in -[UINavigationBar touchesEnded:withEvent:] ()
#26 0x00e3fa30 in -[UIWindow _sendTouchesForEvent:] ()
#27 0x00e3fc56 in -[UIWindow sendEvent:] ()
#28 0x00e26384 in -[UIApplication sendEvent:] ()
#29 0x00e19aa9 in _UIApplicationHandleEvent ()
#30 0x02d37fa9 in PurpleEventCallback ()
#31 0x01e9e1c5 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ ()
#32 0x01e03022 in __CFRunLoopDoSource1 ()
#33 0x01e0190a in __CFRunLoopRun ()
#34 0x01e00db4 in CFRunLoopRunSpecific ()
#35 0x01e00ccb in CFRunLoopRunInMode ()
#36 0x02d36879 in GSEventRunModal ()
#37 0x02d3693e in GSEventRun ()
#38 0x00e17a9b in UIApplicationMain ()
#39 0x00002b72 in main (argc=1, argv=0xbffff620)

似乎没有任何真正有趣的东西(有吗?:P)并且似乎是Apple的所有内部结构。关于如何解决这个问题的任何想法?

更新:即使我删除了我的视图控制器与搜索显示控制器的属性之间的连接,但为它创建了自己的IBOutlet,它仍然会崩溃。可能是坏虫?

更新2:当我以编程方式创建我自己的UISearchDisplayController实例(不是通过故事板)并在viewDidLoad中创建它时,一切都按照它的方式工作到。

更新3:我能够在带有故事板的新项目中始终如一地重现此问题。我使用香草笔尖做了同样的事情,一切都按照它想象的方式工作。但是,如果我使用故事板和segue设置相同的东西,它会像在我的真实项目中一样爆炸。 :(

RECAP :以下是重新创建此问题的步骤:

  1. 使用UISearchDisplayController
  2. 在故事板中创建视图控制器
  3. 在导航堆栈上推送新的视图控制器
  4. 导致内存不足警告
  5. 将控制器从堆栈中弹出
  6. KABOOM!
  7. 此时,

    viewDidLoad甚至没有在第一个视图控制器上被调用,Apple的代码在此之前就会爆炸。

7 个答案:

答案 0 :(得分:12)

这是我做的(授予,这是一个解决方法,而不是修复Apple的错误):

首先,在基座UIViewController中,我创建了一个名为searchController的属性:

@property (nonatomic, retain) IBOutlet UISearchDisplayController* searchController;

我在通过界面构建​​器中添加了UISearchBar,以便我在其UI中有一个占位符。然后,在我的viewDidLoad我手动设置控制器并连接它:

UISearchDisplayController* searchController = [[UISearchDisplayController alloc] 
                             initWithSearchBar:self.searchBar contentsController:self];
searchController.searchResultsDataSource = self;
searchController.searchResultsDelegate = self;
searchController.delegate = self;

self.searchController = searchController;
[searchController release];

在我的viewDidUnload中,我一定要清除它:

self.searchController = nil;

答案 1 :(得分:11)

到目前为止,我发现这个使用ARC的iOS 5 SDK的解决方案:

<。>在.h文件中,使用IBOutlet

声明自己的searchDisplayController属性
@property (strong, nonatomic) IBOutlet UISearchDisplayController * searchDisplayController;

然后在.m文件中,合成它:

@synthesize searchDisplayController;

在viewDidUnload中将其设置为nil。

这样搜索显示控制器将使用您创建的属性而不是使用继承的属性。

我还注意到手势识别器也会出现类似的错误(如果您从故事板创建手势识别器而不是以编程方式创建它们)。我们还需要创建STRONG手势识别器属性,并将它们与您在storyboard中创建的手势识别器对象挂钩。然后在viewDidUnload中,不要将它们设置为nil。 &lt; - 这可以防止崩溃。

答案 2 :(得分:0)

为什么不使用self.searchDisplayController?

我已经多次使用它不会造成任何问题。如果需要,您也可以自定义。

答案 3 :(得分:0)

@Wayne:我在使用Storyboard创建的SearchDisplayController遇到了同样的问题,花了一天时间尝试调试当我的代码都没有运行时似乎出现的崩溃。在我的情况下,症状是用户点击UITabBarController中的选项卡以返回到内存警告后已卸载的ViewController。卸载的视图控制器的viewDidLoad方法永远不会运行,代码至少就像tabBarController:didSelectViewController :(应该在 viewDidLoad之后运行)才能在汇编代码中崩溃之前崩溃!

非常感谢您发布此解决方法以及所有后续工作。一个小的改进是将您的UIDisplayController实例化移动到searchDisplayController属性的延迟加载的访问器方法。实际效果可以忽略不计,但看起来更好!

答案 4 :(得分:0)

需要注意的一点是,如果在searchDisplayController仍处于活动状态时离开视图,则可能会发生此类崩溃。这是我遇到的问题,在searchDisplayController中选择一个项目被设置为从堆栈中弹出视图控制器,为了解决这个问题,我必须在弹出视图之前包含以下代码...

if (self.searchDisplayController.active) {

        [self.searchDisplayController setActive:NO];

}

答案 5 :(得分:0)

Explicitly declare your outlet 

@property (nonatomic, strong) IBOutlet UISearchDisplayController *searchDisplayController;


Then in dealloc - add these lines - nil out the delegate / data source so that they do not receive any message further when the searchDisplayController deallocates itself.

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

答案 6 :(得分:-1)

ViewDidUnload调用意味着,您的应用程序中存在内存异常。

首先尝试修复你的内存问题,然后自动搜索显示视图控制器问题将得到解决。

因为代码中似乎没有任何问题,当发生内存异常时,最好通过说[self.navigationController popViewControllerAnimated:NO]

来取用用户之前的屏幕