代码之家  ›  专栏  ›  技术社区  ›  frankodwyer

如何安全地关闭viewWillDisappear中正在加载的UIWebView?

  •  31
  • frankodwyer  · 技术社区  · 17 年前

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

    这似乎可以处理大多数情况,因为当委托为零时,它会停止向我的视图控制器发送didFailLoadWithError。但是,如果我在视图的dealloc方法中释放web视图,有时(间歇性地)我仍然会收到一条发送到已释放实例的消息,这似乎与实际页面中运行的javascript有关,例如:

    -[UIWebView webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:]: message sent to deallocated instance 0x4469ee0
    

    /SourceCache/WebCore/WebCore-351.9.42/wak/WKWindow.c:250 WKWindowIsSuspendedWindow:  NULL window.
    

    这个特别的东西快把我逼疯了。我认为这可能与在加载web视图之前视图消失有关,即在这种情况下,我怀疑它可能会在内存上乱写,混淆视图堆栈。或者,这可能是完全无关的,是其他地方的错误(我从来没有在调试构建模式下复制过它,只有在我无法用gdb:-观看时,它才会在发布构建设置中发生)。从我的调试运行来看,我认为我没有过度发布任何东西。而且,我似乎只有在某个时候点击了具有网络视图的视图时才能触发它,而且在那之后不会立即发生。

    6 回复  |  直到 17 年前
        1
  •  53
  •   rpetrich    15 年前

    对此的一个变体应该可以解决泄漏和僵尸问题:

    - (void)loadRequest:(NSURLRequest *)request
    {
        [self retain];
        if ([webView isLoading])
            [webView stopLoading];
        [webView loadRequest:request];
        [self release];
    }
    - (void)webViewDidStartLoad:(UIWebView *)webView
    {
        [self retain];
    }
    - (void)webViewDidFinishLoad:(UIWebView *)webView
    {
        [self release];
    }
    - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
    {
        [self release];
    }
    
    - (void)viewWillDisappear
    {
        if ([webView isLoading])
            [webView stopLoading];
    }
    
    - (void)dealloc
    {
        [webView setDelegate:nil];
        [webView release];
        [super dealloc];
    }
    
        2
  •  1
  •   dieselmcfadden    17 年前

    有几种方法可以处理它,但这应该有效。您需要didFailLoadWithError消息,这是告诉您它已停止的消息。

    设置标志为离开=是; 向Webview发送stopLoading。

    webview停止:

    如果((此错误代码==NSURLError已取消)&&(是离开==是){

    [其他类性能选择器:@选择器(拍摄Webview),对象:nil,延迟:0]

    }

    在shoutWebview中释放webView:


    变化: 如果你想对此掉以轻心,你可以使用performSelect:withObject:withDelay:延迟[fillintheblank],称之为10-30秒而不进行检查,你几乎肯定会逃脱惩罚,尽管我不建议这样做。

    您可以让didFailLoadWithError设置一个标志,并在其他地方进行清理。

    您的调试与发布问题不同,您可能需要检查您的配置,以确保它完全相同。赏金是问题的可重复部分,对吧? ;-).

    --

        3
  •  1
  •   Armaggi Armaggi    17 年前

    您在文章的第二部分中描述的UINavigationController错误可能与您对内存警告的处理有关。我经历过这种现象,我能够通过在查看堆栈中的视图(n+1)时模拟内存警告,在堆栈中的n视图上再现它。

    UIWebView是一个内存消耗者,因此当它被用作视图层次结构的一部分时,收到内存警告并不奇怪。

        4
  •  0
  •   Can Berk Güder Pugalmuni    17 年前

    一个简单的 release 中的消息 dealloc 应该足够了。

    你的第二个问题听起来像是过早释放的视图,但如果不看到一些代码,我就无法说太多。

        5
  •  0
  •   TimM    17 年前

    在OS3中使用UIWebView时,我也遇到了类似的问题——这个描述是一个很好的起点,但我发现,在发布webView之前,简单地忽略web视图委托解决了我的问题。

    阅读示例代码(上面公认的答案)似乎有点矫枉过正。例如,给定作者描述变量声明的方式,[webView release]和webView=nil行执行完全相同的操作(因此您不需要两者)。我也不完全相信所有的保留和释放线,但我想你的里程会有所不同。

        6
  •  -1
  •   abuharsky    17 年前

    可能相关,我有时(再次 完全间歇性)变得丑陋 海森堡点击后退 将弹出标题,但不会弹出视图。 堆栈上视图n的标题,但 视图显示仍然是视图n+1( 结果就是你陷入了困境 视图-你可以去另一个方向, 即推送更多视图并返回 出路是退出应用程序)。在其他 对相同的推送序列进行计时 弹出相同的视图效果很好。

    当我在堆栈中使用带有视图控制器的导航控制器时,我也有同样的问题>2和当前视图控制器索引>2、如果此时发生记忆警告,也会引发同样的问题。

    只有一个解决方案,这是我在NavigationController中重写pop和push方法、视图控制器堆栈、堆叠ViewController的视图和监督视图等多次实验后发现的。

    #import <UIKit/UIKit.h>
    #import <Foundation/Foundation.h>
    
    @interface FixedNavigationController : 
    UINavigationController <UINavigationControllerDelegate>{
    
    }
    
    @end
    

    #import "FixedNavigationController.h"
    
    static BOOL bugDetected = NO;
    
    @implementation FixedNavigationController
    
    - (void)viewDidLoad{
        [self setDelegate:self];
    }
    
    - (void)didReceiveMemoryWarning{
        // FIX navigationController & memory warning bug
        if([self.viewControllers count] > 2)
            bugDetected = YES;
    }
    
    - (void)navigationController:(UINavigationController *)navigationController 
    didShowViewController:(UIViewController *)viewController 
    animated:(BOOL)animated
    {
    
        // FIX navigationController & memory warning bug
        if(bugDetected){
            bugDetected = NO;
    
            if(viewController == [self.viewControllers objectAtIndex:1]){
                [self popToRootViewControllerAnimated:NO];
                self.viewControllers = [self.viewControllers arrayByAddingObject:viewController];
            }
        }
    }
    
    @end
    

    它适用于堆栈中的3个视图控制器。