【问题标题】:UIWebView EXC_BAD_ACCESS crashUIWebView EXC_BAD_ACCESS 崩溃
【发布时间】:2010-11-18 21:08:36
【问题描述】:

我遇到使用 UIWebView 的应用程序崩溃。通常是在页面没有完全加载并且 UIWebView 被发送 stopLoading 选择器的时候。或者当 UIWebView 完全加载页面时。我有EXC_BAD_ACCESS。堆栈如下所示:

#0  0x95bb7688 in objc_msgSend
#1  0x30a671db in -[UIWebView webView:decidePolicyForNavigationAction:request:frame:decisionListener:]
#2  0x3024a10d in __invoking___
#3  0x30249ff8 in -[NSInvocation invoke]
#4  0x358ab160 in HandleDelegateSource
#5  0x302452c1 in CFRunLoopRunSpecific
#6  0x30244628 in CFRunLoopRunInMode
#7  0x32044c31 in GSEventRunModal
#8  0x32044cf6 in GSEventRun
#9  0x309021ee in UIApplicationMain
#10 0x0000239c in main at main.m:13

对我来说最奇怪的是webView:decidePolicyForNavigationAction:request:frame:decisionListener:选择器发送到UIWebView,因为UIWebView文档中没有这样的选择器!仅适用于 Cocoa(不是 cocoa touch)WebView。 我怀疑 UIWebView 或其委托有问题。但我无法设置断点来观看它们。请告知我在这种情况下如何获得更多信息。

【问题讨论】:

  • 那么 [UIWebView webView:decidePolicyForNavigationAction:request:frame:decisionListener:] 呢??

标签: iphone uiwebview exc-bad-access


【解决方案1】:

尝试开启 NSZombie 看看是否有什么东西发布得太早了。

可能是您取消了视图的加载,然后立即拆除了您的视图层次结构,导致在 UIWebView 搞砸之前释放了一些东西。

在这种情况下,回溯看起来很明显就像是一个提前释放的委托。委托关系通常很弱,并且由于缺少 GC,因此是一个奇妙的悬空引用来源,导致看起来像这样的崩溃。

【讨论】:

    【解决方案2】:

    您必须在离开视图之前停止加载 webView 并移除委托:

    // ARC (correct solution)
    - (void)dealloc {
        [_webView setDelegate:nil];
        [_webView stopLoading];
    }
    
    // non ARC
    - (void)dealloc {
        [webView setDelegate:nil];
        [webView stopLoading];
        [webView release];
        [super dealloc];
    }
    
    // ARC (older solution)
    - (void)viewWillUnload {
        [webView setDelegate:nil];
        [webView stopLoading];
    }
    

    Apple 文档的内容是: 重要提示在释放您已为其设置委托的 UIWebView 实例之前,您必须首先将其委托属性设置为 nil。例如,这可以在您的 dealloc 方法中完成。

    【讨论】:

    • 在 ios 6 中使用带有 ARC 的 dealloc 方法(不调用 super 或任何内存释放代码) - viewWillUnload 在 ios 6 中已弃用。
    • 这在 iOS 6 中不起作用,正如@MortenHolmgaard 指出的那样。请参阅下面的答案。
    • 我不明白为什么 dealloc 是非 arc 版本。在 ARC 中,您不能手动调用 dealloc,但它会被系统自动调用并执行 dealloc 中的代码。
    • 使用dealloc应该是arc和non-arc的标准方法。在 arc 版本中,省略 [webView release];和[超级释放];。使用上述解决方案,如果您呈现全屏模式 -viewWillDisappear: 将被调用,并且当 -viewWillAppear: 被调用时您将不得不重新连接您的 webview。
    • 使用 [_webView setDelegate:nil];拯救我的一天!我有一个 viecontrolle 调用另一个使用 webview 的 viecontrolle,并且出现了崩溃。现在它工作了!
    【解决方案3】:

    我也看到了这个确切的错误,它是由我指定给 UIWebView 的委托没有被保留(在我的例子中是 UIViewController)引起的。

    【讨论】:

      【解决方案4】:

      我在滚动的 UIWebView 上遇到了 EXC_BAD_ACCESS 崩溃,但仅在 iPad 上,并且仅当用户在关闭包含它的视图控制器时离开 UIWebView 滚动时。

      将委托设置为 nil 并不能解决我的问题,但我在其他问题下找到了解决方案。我将此代码添加到关闭按钮调用的方法中:

      for (id subview in webView.subviews){
              if ([[subview class] isSubclassOfClass: [UIScrollView class]]){
                  [subview setContentOffset:CGPointZero animated:NO];
              }
          }
      

      这会在调用 dealloc 方法之前停止滚动,这似乎是问题所在。

      【讨论】:

        【解决方案5】:

        View Will Disappear 是已接受答案的一个可行选项:

        // ARC
        - (void)viewWillDisappear:(BOOL)animated{
            [self.webView setDelegate:nil];
            [self.webView stopLoading];
        }
        

        这完美适用于 iOS 6。

        【讨论】:

          【解决方案6】:

          最好从 ViewController 的 dealloc 方法中处理从 webview 中注销代理并停止加载 webview。

          作为 viewWillDisappear 可能失败的示例:如果 ViewController 是另一个 ViewController 的子级,您可以使用动画触发从父级 ViewController 的视图中移除 ViewController 的视图。同时,您可以从其父级中移除 ViewController 并取消其引用。此时 ViewController 将为 nil,并且永远不会调用 viewWillDisappear,这意味着永远不会清理 WebView 委托。

          使用 dealloc 并确保始终清理您的 WebView。

          【讨论】:

            猜你喜欢
            • 2011-06-29
            • 2012-12-03
            • 1970-01-01
            • 2013-03-24
            • 2013-01-07
            • 1970-01-01
            • 1970-01-01
            • 2012-06-16
            相关资源
            最近更新 更多