UIWebView EXC_BAD_ACCESS崩溃

时间:2009-08-12 07:29:27

标签: iphone uiwebview exc-bad-access

我遇到了使用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(不是可可触摸)WebView。 我怀疑UIWebView或其委托有问题。但我无法设置断点来观察它们。请告知我如何在这种情况下获得更多信息。

6 个答案:

答案 0 :(得分:86)

您必须在离开视图之前停止加载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方法中完成此操作。

答案 1 :(得分:9)

尝试启用NSZombie并查看是否有太快发布的内容。

可能是您正在取消视图的加载,然后立即拆除视图层次结构,导致在UIWebView完成之前释放某些内容。

在这种情况下,回溯看起来很像是一个早期发布的委托。委托关系通常很弱,并且缺少GC,是悬挂引用的精彩来源,导致崩溃看起来像这样。

答案 2 :(得分:5)

查看Will Disappear是接受答案的工作选项:

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

这适用于iOS 6。

答案 3 :(得分:2)

我在滚动的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方法之前停止滚动,这似乎是个问题。

答案 4 :(得分:1)

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

答案 5 :(得分:0)

处理从webview取消注册委托,并停止加载webview,最好从ViewController的dealloc方法处理。

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

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