Zombie UIWebView在从javascript调用alert()之后被解除分配

时间:2013-04-09 11:02:07

标签: ios objective-c uiwebview nszombie

我正在使用UIWebView,它会在单击按钮时弹出警报(来自javascript)。还有另一个按钮(在本机端),它关闭控制器,因此deallocs也是UIWebView。

问题是,如果我触摸UIWebView中的按钮,并在填充警报之前触摸关闭按钮,我的控制器和UIWebView将被取消分配,但警报仍保留在屏幕上。然后,如果我单击警报上的任何按钮,应用程序崩溃并发出以下错误:

[UIWebView modalView:didDismissWithButtonIndex:]: message sent to deallocated instance

这个方法是从私有方法调用的

[UIModalView(Private) _popoutAnimationDidStop:finished:]

我正在使用ARC,而我的dealloc是这样的:

- (void)dealloc {
    [_myWebView stopLoading];
    _myWebView.delegate = nil;
    _myWebView = nil;
}

但是这并没有解决我的问题,因为我认为UIModalView有一个我的webview作为委托的引用,我无法将其设置为nil,因为它是私有的。

我该如何解决?

此致

3 个答案:

答案 0 :(得分:1)

在解除分配UIWebView之前,找到一种将UIAlertView上的委托设置为nil的方法。

答案 1 :(得分:1)

这是处理警报视图时的Apple错误。 Open a bug report.

与此同时,这里有一些解决方法:

在UIAlertView上创建一个类别:

@interface UIAlertView (QuickDismiss) @end

@implementation UIAlertView (QuickDismiss)


- (void)__quickDismiss
{
     [self dismissWithClickedButtonIndex:self.cancelButtonIndex animated:NO];
}

@end

现在,在视图控制器的dealloc方法中,调用:

[[UIApplication sharedApplication] sendAction:@selector(__quickDismiss) to:nil from:nil forEvent:nil];

这将关闭当前打开的所有警报视图,包括您的Web视图显示的视图。

如果这不起作用,您可以始终迭代所有UIApplication.sharedApplication.windows个对象的所有子视图,检查[view.class.description hasPrefix:@"UIAlertView"]是否为真,并将其解除。这是一种比前一种方法更不优雅的方法,应该是最后的选择。

祝你好运。

答案 2 :(得分:0)

最后,我找到了一个很有效的解决方案。我使用方法swizzle来挂钩UIAlertView Delegate函数 - (void)didPresentAlertView:(UIAlertView *)alertView

- (void)didPresentAlertView:(UIAlertView *)alertView
{
    if ([self.delegate respondsToSelector:@selector(didPresentAlertView:)]) {
        [self.delegate didPresentAlertView:alertView];
    }
    if ([self.delegate isKindOfClass: [UIWebView class]]) {
        uiWebView = self.delegate;
    }
}

我只是在此函数中保留UIWebView实例,以便在UIAlertView实例发布之前不会释放作为UIAlertView代理的UIWebView实例。