【问题标题】:UIScrollView EXC_BAD_ACCESS crash in iOS SDKiOS SDK 中的 UIScrollView EXC_BAD_ACCESS 崩溃
【发布时间】:2011-04-10 20:25:03
【问题描述】:

我有一个 iPhone SDK 应用程序,该应用程序具有多个视图,这些视图会随着用户创建内容而出现和消失。在设备上使用该应用程序一段时间后,我遇到以下崩溃:

Program received signal:  “EXC_BAD_ACCESS”.
(gdb) backtrace
#0  0x33369ebc in objc_msgSend ()
#1  0x320e5248 in -[UIScrollView(UIScrollViewInternal) _scrollViewAnimationEnded] ()
#2  0x338b4a14 in -[NSObject performSelector:withObject:] ()
#3  0x320e5098 in -[UIAnimator stopAnimation:] ()
#4  0x320e4b7c in -[UIAnimator(Static) _advance:] ()
#5  0x320e4a34 in LCDHeartbeatCallback ()
#6  0x34350e60 in HeartbeatVBLCallback ()
#7  0x332e91c0 in IOMobileFramebufferNotifyFunc ()
#8  0x316532f8 in ?? ()
#9  0x33866b50 in __CFMachPortPerform ()
#10 0x338ae52a in CFRunLoopRunSpecific ()
#11 0x338adc1e in CFRunLoopRunInMode ()
#12 0x3434e1c8 in GSEventRunModal ()
#13 0x32002c30 in -[UIApplication _run] ()
#14 0x32001230 in UIApplicationMain ()
#15 0x00002ff8 in main (argc=1, argv=0x2ffff550) at /Developer/svn/MyCompany/iPhone/MyApplication/Other Sources/main.m:14

从跟踪中可以看出,其中唯一提到我的代码的是对 main 的调用。

我已经从 Xcode 运行 Build and Analyze,并且还设置它从终端运行我的项目上的 clang 分析器,这两者都找不到代码中的任何问题。我正在使用 iOS SDK 的最新版本(我还没有下载 4.1,但我使用的是 4.1 之前发布的版本)。

另外,我已经用模拟器在 Instruments 中运行了该应用程序,并且该应用程序没有内存泄漏。

我将尝试使用 NSZombieEnabled 变量,看看是否有任何发现,但问题是我需要在应用程序崩溃之前使用 30 到 40 分钟左右,我怀疑 @987654323 @ 甚至可能无法帮助我找到问题。

我所看到的崩溃似乎是模态视图在父视图控制器中调用委托时发生的。父视图控制器然后在关闭模态视图控制器之前进行一些处理。崩溃中有一些对动画和滚动视图的引用,但我不确定我可以做些什么来导致这些出现问题。有人对要寻找的东西有什么建议吗?

编辑:我已将NSZombieEnabled 标志放入应用程序,在设备上,它会在控制台中显示此消息:

2010-09-11 17:10:33.970 MyApplication[9321:207] *** 
-[MyViewController respondsToSelector:]: message 
sent to deallocated instance 0x7489480

据我所知,我将应用程序中使用的委托在我所有类的 dealloc 中设置为 nil,所以我不知道下一步该往哪里看。

我尝试对此使用malloc_history pid address 命令,但它说找不到进程,我尝试了9321、9321:207 和207。另外,如果我尝试使用MallocStackLogging变量,程序不会在设备上运行,我得到一堆malloc:无法在控制台中创建堆栈日志目录消息和程序崩溃。

哦,顺便说一句,我不能使用僵尸检查仪器,因为它似乎不适用于设备,而且我不能在模拟器中发生同样的崩溃。

【问题讨论】:

    标签: iphone uiscrollview exc-bad-access


    【解决方案1】:

    我的猜测是滚动视图的委托被设置为一个已被释放的对象。尝试在您的 dealloc 方法中将子对象的所有委托设置为 nil。

    【讨论】:

      【解决方案2】:

      堆栈帧#1 上的UIScrollView 可能想要通知其代理动画结束,但此时代理已消失。设置NSZombieEnabled 可能会证实这一点。

      没有保留委托,因此这是 Cocoa 和 Cocoa Touch 中的常见错误。在您的代码中查找UIScrollViewUITableView 上的代表,并尝试找出可能提前发布的代表。

      【讨论】:

      • +1。明确地说,委托属性应始终设置为 assign 而不是 retain
      • 规则总是有例外。请参阅NSURLConnection 了解保留代表的正当理由。
      • 我确实有一个驻留在 UIViewController 上的 UITableView,当应用程序崩溃时,我相信它已准备好返回此视图控制器。但是,这个 UITableView 的委托是在 Interface Builder 中设置的,并且在代码中的任何地方都没有更改。
      • 这个委托可能是问题所在。要进行验证,请使用NSZombiesEnabled。您必须注意委托的寿命比 UITableView 长(或表视图上的属性设置为 nil)。当然,IB 不应该受到责备,因为它不处理生命周期。您必须在应用程序逻辑中执行此操作。
      【解决方案3】:

      我自己刚刚解决了这个问题。

      我有一个问题:

      • 滚动视图委托已连接到 UIViewController
      • 滚动视图开始动画化
      • 委托离开并调用了 dealloc。

      问题是滚动视图委托消息在新释放的对象上触发,并且崩溃日志有点令人困惑,因为它们指向无意义的对象引用。

      解决方法是将滚动视图委托设置为 nil 作为我的视图控制器 dealloc 方法的第一行。

      希望这对其他人有帮助!

      【讨论】:

      • 你可能不知道这个答案给我省了多少麻烦,谢谢 :D
      • 感谢您的回答!节省了我很多时间
      • 我之前遵循了chips的回答,但这对我来说更有意义,并帮助我保持代码干净。谢谢。 +1
      【解决方案4】:

      为了完整起见,我为那些可能遇到相同问题但实施方式略有不同以及重现问题的确切步骤的人添加了此堆栈跟踪 (iOS 6)。

      Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
      Exception Codes: KERN_INVALID_ADDRESS at 0x71f05631
      Crashed Thread:  0
      
      Thread 0 name:  Dispatch queue: com.apple.main-thread
      Thread 0 Crashed:
      0   libobjc.A.dylib                 0x3919b5d0 objc_msgSend + 1
      1   UIKit                           0x33421830 -[UIScrollView(UIScrollViewInternal) _delegateScrollViewAnimationEnded] + 48
      2   UIKit                           0x334217ba -[UIScrollView(UIScrollViewInternal) _scrollViewAnimationEnded:finished:] + 130
      3   UIKit                           0x334216a4 -[UIAnimator stopAnimation:] + 460
      

      这发生在 iOS 6 上,并在我实现 UIScrollViewDelegate 方法:

      " -(void)scrollViewDidEndDecelerating:(UITableView *)tableView" 
      and made a call to:
      "[tableView scrollToRowAtIndexPath: indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];".  
      

      问题发生在动画开始时,我按下“返回”按钮,我的视图控制器在动画完成之前弹出。

      在再现时,您必须确保在动画开始之后但在完成之前按下“返回”按钮。我试了几次。我试图通过以编程方式弹出视图控制器来重新创建问题,但无法重现它。我不得不使用“返回”按钮。我只是在 dealloc 中调用 [myTableView release]。解决方案如此处所述,将这两个属性都设置为 nil:

      self.myTableView.delegate = nil;
      self.myTableView = nil;
      

      【讨论】:

        【解决方案5】:

        如果您将刷新控制器作为子视图插入到表视图中,则可能会发生这种情况(我的提示,永远不要这样做)......

        【讨论】:

        • 你有证据吗?进行了更改,但我不确定它是否会修复崩溃。
        • 根据我自己的经验(和完全相同的问题),因为旧 API 的某些部分使用了分配(而不是新的弱,因此挂断了死指针) - 这肯定是如果您将 UIRefreshController 作为子视图插入(千万不要这样做!UIRefreshController 不打算作为子视图插入)
        • 我遇到了同样的错误,并怀疑问题是插入 UIRefreshController 作为 UITableView 对象的子视图。根据 Apple 文档,UIRefreshControl 只能与 UITableViewController 一起使用,但我处理的是旧版 UIViewController。进一步调试后,我发现问题在于应用程序丢失了一个引用,该引用是在 UIViewController 中我的 UITableViewDelegate 方法之一创建的对象。我需要做的就是在 UIViewController 中创建一个属性并将其设置为该对象。
        【解决方案6】:

        首先,委托应该是weak/assign类型。但是在这种情况下,有一个非常常见的事件 滚动动画驱动的微妙障碍。如果您使用动画内容偏移更改 您的 ScrollViews 您强烈需要在 dealloc 方法中将其 delegate 设置为 nil

        否则你会得到以下结果

        [YourViewController respondsToSelector:]: message sent to deallocated instance
        

        非常常见的例子:

        1. _tableView is ivar of YourViewController
        2. _tableView.delegate = self;
        3. - (void)scrollViewDidScroll:(UIScrollView *)scrollView is implemented at YourViewController
        4. at some point you call [_tableView scrollToRowAtIndexPath:indexPath 
           atScrollPosition:UITableViewScrollPositionBottom animated:YES];
           or [_tableView setContentOffset:CGPoint animated:YES]
           and try to close YourViewController
        

        CoreAnimation 保留 _tableView,但 YourViewController 被释放!

        【讨论】:

        • 我有一个类似的问题,我想......它在 scrollView didScroll 委托方法中。但它现在是一个 ARC 项目,那怎么会发生呢?
        【解决方案7】:

        以上所有内容都没有解决我的问题,所以我再次深入挖掘了我的代码。 我认识到当我执行键盘和 UICollectionView 动画(是的,这是一个聊天)并关闭当前控制器时会出现崩溃。

        应用程序崩溃,因为我尝试在动画完成块中滚动:)

        剪掉它,现在一切正常!

        愉快的编码和调试:)

        【讨论】:

          【解决方案8】:

          遇到我设置的同样问题后:

          self.collectionView.delegate = nil;
          

          - (void)viewDidLoad 中(在实际将 ViewController 设置为 collectionView 委托之前) 和-(void)viewWillDisappear:(BOOL)animated

          现在一切正常。

          感谢您的帮助。

          【讨论】:

            【解决方案9】:

            当调用 scrollToRowAtIndexPath 且 indexPath 不存在时,我已经看到了这种行为

            【讨论】:

              猜你喜欢
              • 2013-03-24
              • 2021-04-23
              • 1970-01-01
              • 2018-11-30
              • 1970-01-01
              • 2018-03-03
              • 1970-01-01
              • 2013-09-14
              • 1970-01-01
              相关资源
              最近更新 更多