我有一个包含UIWebView的视图,它正在加载谷歌地图(因此有很多javascript等)。我遇到的问题是,如果用户在Web视图加载完之前点击导航栏上的“后退”按钮,我不清楚如何整理地告诉Web视图停止加载然后释放它,而不是获取发送到解除分配的实例的消息。我也不确定Web视图是否喜欢它的容器视图在它完成之前消失(但如果用户在加载之前点击后退按钮,我别无选择。)
在我的viewWillDisappear处理程序中我有这个
map.delegate=nil;
[self.map stopLoading];
这似乎处理大多数情况OK,因为nil'ing委托停止它将didFailLoadWithError发送到我的视图控制器。但是,如果我在视图的dealloc方法中释放Web视图,有时(间歇性地)我仍会收到发送到解除分配的实例的消息,这似乎与在实际页面中运行的javascript有关,例如:
-[UIWebView webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:]: message sent to deallocated instance 0x4469ee0
如果我只是不发布webview,那么我不会收到这些消息,但我想我正在泄漏webview。
如果我没有发送'stopLoading'消息,只是在viewWillDisappear中发布webview,那么我会看到这样的消息:
/SourceCache/WebCore/WebCore-351.9.42/wak/WKWindow.c:250 WKWindowIsSuspendedWindow: NULL window.
可能相关,我有时(再次完全间歇)得到一个丑陋的heisenbug,点击其他视图的导航栏上的后退按钮将弹出标题,但不是视图。换句话说,我在堆栈上留下了视图n的标题,但是显示的视图仍然是视图n + 1(结果是你被困在这个屏幕上并且无法返回到根视图 - 你可以去其他方向,即推送更多视图并弹回到没有正确弹出的视图,只是不到根视图。唯一的出路是退出应用程序)。在其他时候,相同视图上的推送和弹出的相同序列工作正常。
这个特别令我疯了。我认为这可能与视图在加载Web视图之前消失有关,即在这种情况下我怀疑它可能会在内存上乱写并混淆视图堆栈。或者,这可能是完全不相关的,而且是其他地方的错误(我从来没有能够在调试构建模式下重现它,只有当我无法使用gdb观看时才会发布版本设置:-)。从我的调试运行开始,我认为我不会过度发布任何内容。而且我似乎只能触发它,如果在某些时候我已经点击了具有Web视图的视图,并且在此之后不会立即发生。
答案 0 :(得分:52)
对此的变化应该解决泄漏和僵尸问题:
- (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];
}
答案 1 :(得分:1)
有几种方法可以处理它,但这应该有效。你想要didFailLoadWithError消息,它告诉你它被停止了。
设置标志isLeaving = YES; 向Webview发送stopLoading。
在didFailLoadWithError:中,检查您何时收到错误 webview停止:
if((thiserror.code == NSURLErrorCancelled)&&(isLeaving == YES)){
[otherClass performSelector:@selector(shootWebview)withObject:nil withDelay:0]
}
在shootWebview中发布webView:
变体: 如果你想成为骑士,你可以执行performSelector:withObject:withDelay:延迟[fillintheblank],在没有检查的情况下调用它10-30秒,你几乎肯定会逃脱它,尽管我不喜欢不推荐它。
你可以让didFailLoadWithError设置一个标志并在其他地方清理它。
或者我最喜欢的,也许你不需要在你离开时将它全部解除。你不会再次显示那个视图容器吗?为什么不把它重复使用呢?
您的调试与发布问题不同,您可能需要检查配置以确保它完全相同。赏金是问题的可重复部分,对吧? ; - 。)
- 哦等一下,您可能会使用WebView将整个View容器关闭。您可以对上述内容进行修改,并等待在shootWebView中释放整个容器。
答案 2 :(得分:1)
您在帖子的第二部分中描述的UINavigationController错误可能与您对内存警告的处理有关。我已经经历过这种现象,并且通过在查看堆栈中的视图(n + 1)时模拟内存警告,我已经能够在堆栈中的视图n上重现它。
UIWebView是一个内存消费者,因此当它被用作视图层次结构的一部分时,获取内存警告就不足为奇了。
答案 3 :(得分:0)
release
中的简单dealloc
消息应该足够了。
你的第二个问题听起来像是一个过早释放的视图,但如果没有看到一些代码,我就不能说太多了。
答案 4 :(得分:0)
我在OS3中使用UIWebView遇到了类似的问题 - 这个描述是一个很好的起点,但是我发现在发布webView之前简单地忽略了Web视图委托解决了我的问题。
阅读示例代码(上面接受的答案) - 似乎有点矫枉过正。例如。 [webView发布]和webView = nil行完全相同,因为作者描述了变量的声明方式(所以你不需要两者)。我也不完全相信所有的保留和释放线 - 但我想你的里程会有所不同。
答案 5 :(得分:0)
可能相关,我有时(再次 得到一个丑陋的 heisenbug点击后面 某个其他视图的导航栏上的按钮 将弹出标题,但不是视图。 换句话说,我离开了 视图n的标题在堆栈上,但是 视图显示仍然是视图n + 1( 结果是你被困在这上面 屏幕,无法回到根 观点 - 你可以走另一个方向, 即推送更多视图并弹回 没有正确弹出的视图, 只是没有到根视图。唯一的 出路是退出应用程序)。在其他 次数相同的推动和 相同视图上的弹出窗口工作正常。
我有同样的问题,当我在堆栈中使用带有视图控制器的导航控制器时> 2,当前视图控制器索引> 2,如果在这个女性中发生记忆警告,它会引发同样的问题。
有一个解决方案,我在NavigationController中覆盖pop和push方法的许多实验后发现,包含视图控制器堆栈,带有堆叠ViewControllers的视图和超级视图等。
#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个视图控制器。