【问题标题】:UISearchDisplayController causes crash after viewDidUnloadUISearchDisplayController 在 vi​​ewDidUnload 后导致崩溃
【发布时间】:2011-12-19 21:02:15
【问题描述】:

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

[UISearchDisplayController 保留]:消息发送到已释放的实例 0xb13aa30

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

但有些奇怪:为了笑声和咯咯笑声,我决定在我的viewDidLoad 中直接retain 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),而且似乎都是苹果公司的内部产品。关于如何解决这个问题的任何想法?

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

更新 2:当我以编程方式创建自己的 UISearchDisplayController 实例(不是通过情节提要)并在 viewDidLoad 中创建它时,一切正常。 p>

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

回顾:以下是重现此问题的步骤:

  1. 在情节提要中使用UISearchDisplayController 创建一个视图控制器
  2. 在导航堆栈上推送一个新的视图控制器
  3. 导致内存不足警告
  4. 从堆栈中弹出控制器
  5. KABOOM!

viewDidLoad 此时甚至没有在第一个视图控制器上被调用,Apple 的代码在那之前就崩溃了。

【问题讨论】:

  • 你的 viewDidUnload 方法是什么样的?
  • @aopsfan 只是将我的IBOutlets 清零并调用我的超级实现viewDidUnload
  • 如果您删除该代码会发生什么?
  • 我意识到这可能是泄漏,但只是为了检查......
  • 您是否将 IBOutlet 设置为弱 (ARC) 或分配(无 ARC)?

标签: iphone uisearchdisplaycontroller uistoryboard


【解决方案1】:

这是我所做的(当然,这是一种解决方法,而不是解决 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;

【讨论】:

  • 您可能不需要将整个searchController 设为nil,只需将其delegate 设置为nil。
  • @Mark Adams - 因为我是 retaining 属性中的 searchController,所以我是 niling 它。可以在 viewDidLoad 中轻松重新创建的对象应在 viewDidUnload 中清零。
  • 很公平。我说的是你的具体崩溃。
  • 我不明白您如何将新创建的searchController 实例分配给只读属性self.searchDisplayController
  • 我实际上阅读了韦恩刘的答案,它对我来说非常有效。你的可能在 MRR 环境中有意义,但我已经转向 ARC。
【解决方案2】:

到目前为止,我使用 ARC 为 iOS 5 SDK 找到了这个可行的解决方案:

在 .h 文件中,使用 IBOutlet 声明您自己的 searchDisplayController 属性

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

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

@synthesize searchDisplayController;

不要在 viewDidUnload 中将其设置为 nil。

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

我还注意到手势识别器也会出现类似的错误(如果您从情节提要创建手势识别器,而不是通过编程方式创建它们)。我们还需要创建 STRONG 手势识别器属性并将它们与您在情节提要中创建的手势识别器对象挂钩。然后在 viewDidUnload 中,不要将它们设置为 nil。

【讨论】:

  • 太棒了,这个对我有用。这为我节省了几个小时(尽管我已经花了一些时间来达到这一点;))
【解决方案3】:

你为什么不只使用 self.searchDisplayController?

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

【讨论】:

    【解决方案4】:

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

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

    【讨论】:

      【解决方案5】:

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

      if (self.searchDisplayController.active) {
      
              [self.searchDisplayController setActive:NO];
      
      }
      

      【讨论】:

        【解决方案6】:
        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;
        

        【讨论】:

          【解决方案7】:

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

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

          因为代码似乎没有任何问题,当发生内存异常时,最好通过说[self.navigationController popViewControllerAnimated:NO]来获取用户上一个屏幕

          【讨论】:

          • 在某人的设备上不可避免地会出现内存不足的情况,这不是我作为开发人员自己的过错。这个问题的重点是避免Apple的错误导致的崩溃。在这种情况下调用 [self.navigationController popViewControllerAnimated:NO] 将毫无用处,因为这是重现问题的步骤之一。
          猜你喜欢
          • 2011-12-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-04-03
          • 2014-02-09
          • 2018-01-23
          • 2020-12-02
          • 2013-11-11
          相关资源
          最近更新 更多