iOS:Webview代理引起的EXC_BAD_ACCESS错误

6

我有一个情况,正在尝试解决这些Crashlytics问题,并且我有这个崩溃日志。

Thread : Crashed: com.apple.main-thread
0  libobjc.A.dylib                0x34217f46 objc_msgSend + 5
1  UIKit                          0x29a2d5a3 -[UIWebView webView:decidePolicyForNavigationAction:request:frame:decisionListener:] + 182
2  CoreFoundation                 0x2630cad4 __invoking___ + 68
3  CoreFoundation                 0x26239645 -[NSInvocation invoke] + 300
4  CoreFoundation                 0x2623d0c7 -[NSInvocation invokeWithTarget:] + 50
5  WebKitLegacy                   0x326d9261 -[_WebSafeForwarder forwardInvocation:] + 224
6  CoreFoundation                 0x2630b62f ___forwarding___ + 354
7  CoreFoundation                 0x2623d008 _CF_forwarding_prep_0 + 24
8  CoreFoundation                 0x2630cad4 __invoking___ + 68
9  CoreFoundation                 0x26239645 -[NSInvocation invoke] + 300
10 WebCore                        0x31c02729 HandleDelegateSource(void*) + 100
11 CoreFoundation                 0x262cefbf __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 14
12 CoreFoundation                 0x262ce461 __CFRunLoopDoSources0 + 364
13 CoreFoundation                 0x262cca35 __CFRunLoopRun + 772
14 CoreFoundation                 0x2621a3b1 CFRunLoopRunSpecific + 476
15 CoreFoundation                 0x2621a1c3 CFRunLoopRunInMode + 106
16 GraphicsServices               0x2d801201 GSEventRunModal + 136
17 UIKit                          0x2988443d UIApplicationMain + 1440
18 abc                          0x0030dcd7 main (main.m:14)

我可以理解这是Webview委托的一些回调,出现了错误访问,为了纠正这个问题,我通过处理委托来解决。

[self.webview stopLoading];
self.webview.delegate =nil;

在所有的类中,我仍然可以看到这个崩溃。你能告诉我可能出了什么问题并提出一些纠正方法吗?

你好@AnkitSachan,你在哪一行遇到了这个问题?你是否在类中使用断点调试了所有的代码? - Paras Joshi
1
Ankit,请详细解释一下你的问题。许多Web视图是什么意思? - Dipen Chudasama
大家好:正如我在问题中所述,我正在寻找处理这种情况的方法或方法论,即我只有这些崩溃日志,没有其他信息,而且Web视图广泛分布在代码库中,我不确定哪个是导致问题的原因。 - Ankit Sachan
看起来很奇怪,堆栈跟踪包含 decidePolicyForNavigationAction。这属于 WebPolicyDelegate,在 iOS 上不受支持。它只适用于 OSX。有没有可能链接了一个使用OSX头文件构建的库?这将解释崩溃,因为 NSInvolcation 可能调用不存在的内容。所以我的直觉是它与您链接的某些第三方代码有关。 - Rory McKinnel
@AnkitSachan,你解决了这个问题吗?我们的应用程序也遇到了同样的问题。 - anoop4real
显示剩余3条评论
6个回答

19

可能的情况如下:

  • 用户被呈现一个带有UIWebView的屏幕
  • UIViewControllerself设置为Web页面的delegate。网页开始下载
  • 用户退出屏幕
  • UIViewController被解除分配,UIWebView完成加载并向其delegate发送我已经完成加载消息

或者

当WebView对象不再存在时,调用了其他委托方法,即挂起指针效应。

1. 离开视图之前,始终确保停止加载webView删除委托

释放已设置委托的UIWebView实例之前,必须首先将其delegate属性设置为空。这可以在dealloc方法中完成

这是参考

// If ARC is used
- (void)dealloc {
    [_webView setDelegate:nil];
    [_webView stopLoading];
}

// If ARC is not used
- (void)dealloc {
    [webView setDelegate:nil];
    [webView stopLoading];
    [webView release];
    [super dealloc];
}

// ARC - Before iOS6 as its deprecated from it.
- (void)viewWillUnload {
    [webView setDelegate:nil];
    [webView stopLoading];
}

2.确保在viewWillDisappear中不要stopLoadingsetDelegatenil

如果ViewController是另一个ViewController的子控制器,则可以使用动画触发从父ViewController的视图中删除ViewController的视图。同时,您可以将ViewController从其父级中删除并 nil 出其引用。 此时ViewController将为 nil ,并且 viewWillDisappear 永远不会被调用,这意味着WebView代理永远不会被清除

请使用dealloc确保始终清除WebView

3.确保没有动画将webviewsubviewsContentOffset设置为CGPointZero

在某些版本的iPad上,当webview滚动时,如果在关闭父视图控制器之前未将ContentOffset设置为 CGPointZero ,则会出现此类问题

因此,在关闭它之前,最好在父视图控制器中调用以下代码:

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

希望这能帮到你。如有问题请随时提出。

4.一般来说,不应该在UIScrollView对象中嵌入UIWebView对象。如果这样做,由于两个对象的触摸事件可能会混淆和错误地处理,可能会导致意外的行为。

这里是参考文献


1
一般来说,如果你遇到了像EXC_BAD_ACCESS这样的内存管理问题,启用Xcode中的NSZombies是一个很好的方式,检查所有内容并尝试使用静态分析工具。使用这些工具可以让你在用户发现之前尽早捕获错误。 - Durai Amuthan.H
非常感谢!我一直在尝试弄清楚为什么我的委托方法从未被调用,现在终于知道原因了。我在一个方法中创建了连接类的实例(该实例初始化流和委托(self)),但没有存储对它的引用。因此,垃圾收集器似乎会在连接打开后立即删除该实例,这就是为什么委托从未被调用的原因。 - Simon Hessner
1
欢迎。在iOS中没有GC,ARC来完成这项工作。检查是否符合委托并确保已将委托实例设置为self。 - Durai Amuthan.H

1
尝试在 ViewController 销毁之前禁用 UIWebView 的滚动行为。
for (id subview in webView.subviews){
    if ([[subview class] isSubclassOfClass: [UIScrollView class]]){
        [subview setContentOffset:CGPointZero animated:NO];
    }
}

p.s. Dipen Chudasama的方法是正确的,根据苹果的文档,你应该在释放webview之前将delegate属性设置为nil,假设你已经在dealloc函数中正确释放了webview,但不是在viewWillDisappear


-1

UIWebViewdelegate使用assign而不是weak。因此,当webView的控制器被释放时,您需要将delegate设置为null

示例:

- (void)dealloc
{
     self.webview.delegate =nil;
}

我已经阅读了完整的问题。您说您“通过处理委托来处理...”,但没有说明您也在dealloc中将Web视图置为空。 - bhr
尊敬的@tubtub先生,即使我没有在dealloc和代码的其他地方处理它,这应该也没问题,对吧?虽然确切地说,是的,我已经在dealloc中处理了它。 - Ankit Sachan
将此代码放入dealloc的原因是为了处理在Web视图委托被调用之前,您的视图控制器被释放的情况。您能否提供一个包含webView的ViewController的小示例类?这应该会更有帮助。 - bhr
正如我所说,这些是Crashlytics的错误,并且我的代码库中有许多Webview。这些崩溃日志没有明显指向任何特定的Webview,因为它是一个通用回调。 - Ankit Sachan
是的!我假设您在涉及 Web 视图的任何地方都使用相同的模式。由于这似乎是一个非常重要的问题,需要代码来更好地帮助您。 - bhr

-1

使用相反的方法,先将委托设为nil,然后停止加载Web视图可能会有帮助。

就像这样。

[_webView setDelegate:nil];
[_webView stopLoading];

根据苹果文档:在释放已设置委托的UIWebView实例之前,必须首先将其委托属性设置为nil。

-1
使用 [listener use] 代替,告诉你的 UIWebView 处理点击的 URL。
-(void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id )listener
{
    [listener use]
}

开发者应用程序崩溃是因为访问错误(即Web视图和委托未正确处理),而不是由于委托方法实现,这些方法无论如何都是可选的。 - Ankit Sachan

-1
你是否在 Web 视图的子类中添加了一个 Web 视图?通常这就是问题所在,如果是这样,将超类更改为 UIView 将解决该问题。

嗨Chihan,感谢更新,但情况并非如此。我有一个拥有这个Web视图的视图控制器。 - Ankit Sachan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接