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

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

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

    我有一个包含UIWebView的视图,它正在加载一个google地图(所以有很多javascript等)。我遇到的问题是,如果用户在web视图完成加载之前点击导航栏上的“后退”按钮,我不清楚如何整齐地告诉web视图停止加载,然后释放它,而不将消息发送到解除分配的实例。我也不确定web视图是否喜欢它的容器视图在加载之前消失(但是如果用户在加载之前点击后退按钮,我没有选择)。

    在我看来,我有这个

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

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

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

    如果我只是不发布webview,那么我就不会收到这些消息,尽管我猜我是在泄露webview。

    如果我不发送“stopLoading”消息,只需在viewwilldiscover中释放webview,我就会看到如下消息:

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

    可能是相关的,我有时(同样是断断续续地)会遇到一个丑陋的海森堡,点击其他视图导航栏上的后退按钮会弹出标题,但不会弹出视图。换句话说,我在堆栈上留下了视图n的标题,但显示的视图仍然是视图n+1(结果是你被困在这个屏幕上,无法回到根视图-你可以转到另一个方向,即推送更多视图并弹出到没有正确弹出的视图,而不是根视图。唯一的出路是退出应用程序)。在其他时候,相同视图上的相同推送和弹出顺序可以正常工作。

    这件事真让我抓狂。我认为这可能与加载web视图之前视图消失有关,也就是说,在这种情况下,我怀疑它可能会在内存上涂鸦,并混淆视图堆栈。或者,这可能是完全不相关的,并且是其他地方的一个bug(我从来没有能够在调试构建模式下重现它,它只发生在发布构建设置中,当我不能用gdb:-)查看它时)。从我的调试运行来看,我认为我没有过度发布任何东西。我似乎只有在某个时候我点击了包含web视图的视图时才能够触发它,而这之后不会立即发生。

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

    - (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    15 年前

    有几种方法可以解决这个问题,但这应该行得通。如果你想要didFailLoadWithError消息,它会告诉你它已停止。

    设置一个标志isLeaving=YES;

    在didFailLoadWithError:中,检查在 webview将停止:

    if((thisrerror.code==nsurerrorcancelled)&(isLeaving==YES)){

    [otherClass performSelector:@selector(shootWebview)with object:nil with delay:0]

    }

    在shootWebview中释放webView:


    如果你想在这件事上表现得更从容一些,你可以选择performSelector:withObject:withDelay:withDelay,延迟[Fillingblank],在没有检查的情况下,称之为10-30秒,你几乎肯定会成功,尽管我不推荐这样做。

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

    由于调试与发行版问题不同,您可能需要检查配置以确保其完全相同。赏金是问题的可复制部分,对吗?;-)。

    --

        3
  •  1
  •   Armaggi Armaggi    15 年前

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

    UIWebView是一个内存消耗器,因此当它作为视图层次结构的一部分使用时,获取内存警告并不令人惊讶。

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

    简单的 release 留言 dealloc

    您的第二个问题听起来像是一个过早释放的视图,但我不能说太多,除非看到一些代码。

        5
  •  0
  •   TimM    15 年前

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

    阅读示例代码(上面接受的答案)-这似乎有点过头了。例如,[webView release]和webView=nil行的作用与作者描述变量的声明方式完全相同(因此您不需要两者都使用)。我也不完全相信所有的保留和释放线-但我想你的里程数会有所不同。

        6
  •  -1
  •   abuharsky    15 年前

    完全间歇)得到一个丑陋的 海森堡在哪里点击背面 将弹出标题,但不弹出视图。 换言之,我只剩下 堆栈上视图n的标题,但 显示的视图仍然是视图n+1( 结果是你被困在这上面了 视图-您可以转到另一个方向, 只是不到根视图。唯一的 解决方法是退出应用程序)。另外 乘以相同的推送和推送顺序 相同视图上的pops工作正常。

    在NavigationController中重写pop和push方法、堆栈视图控制器、堆栈视图控制器的视图和超级视图等的多次实验后,我发现了inly 1解决方案。

    #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