令人沮丧的UIWebView委托崩溃问题
我创build了一个运行完美的ARC应用程序。 它有一个UINavigationController,我用来通过视图,一切运行良好。
我将应用程序转换为iPad,并决定将其中一个视图显示为popup窗口。 (我不喜欢UIPopoverController,所以我创build了我自己的基本popup窗口)。 它被添加到视图如下
MyViewController *hotelinf = [[MyViewController alloc] initWithNibName:@"MyViewController_iPad" bundle:nil]; [self.view addSubview:hotelinf.view];
该视图被添加为子视图罚款。 我添加的视图包含一个UIWebView,它具有通常的委托方法,但是当视图试图访问其中一个委托时,它就会崩溃。
*** -[MyViewController respondsToSelector:]: message sent to deallocated instance 0x7917b90
具体来说,它在这条线上崩溃..
[self.webView loadHTMLString:stringResponse baseURL:nil];
我已经显示视图(和UINavigationControllers)作为子视图多次没有任何问题,虽然他们都没有包括一个UIWebView委托。 我猜我必须设置我的UIViewController istance的委托,但我不知道如何。 还值得注意的是,如果我在现有的UINavigationController中推送视图,它会调用并加载HTML罚款,这肯定意味着它与视图本身的代码无关。
任何帮助将不胜感激! 这里是代码(除了上面显示的控制器)..
。H
@interface MyViewController : UIViewController <UIWebViewDelegate, UIActionSheetDelegate> { //Unrelated IBOutlets } @property (nonatomic, strong) UIWebView *webView; @end
.M
@implementation MyViewController @synthesize webView; - (void)viewDidLoad { [super viewDidLoad]; self.webView = [[UIWebView alloc]initWithFrame:CGRectMake(317,283,393,354)]; self.webView.delegate = self; [self.view addSubview:self.webView]; [NSThread detachNewThreadSelector:@selector(getHTMLString) toTarget:self withObject:nil]; } -(void)getHTMLString { @autoreleasepool { //Download a valid HTML String [self performSelectorOnMainThread:@selector(loadHTML) withObject:nil waitUntilDone:NO]; } } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; self.webView = nil; } -(void)loadHTML { self.webView.opaque = NO; self.webView.backgroundColor = [UIColor clearColor]; if ([stringResponse isEqualToString:@""]) { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Could not connect to XXXXX.com. Please verify you are connected to a working 3G/WIFI Network." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; } else { //it crashes here only when loaded as a subview - the first access to the delegate [self.webView loadHTMLString:stringResponse baseURL:nil]; } } - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { } - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; } - (void)webViewDidFinishLoad:(UIWebView *)webView { [self stopIndicator]; } - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { if (error.code == NSURLErrorCancelled) return; // this is Error -999 [self stopIndicator]; // report the error inside the webview NSString* errorString = [NSString stringWithFormat: @"<html><center><font size=+10 color='black' face='Helvetica'>An error occurred:<br>%@</font></center></html>", error.localizedDescription]; [self.webView loadHTMLString:errorString baseURL:nil]; UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Cannot load URL." message:@"You have a connection failure. Please verify you are connected to a WIFI or 3G enabled Network." delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil]; [alert show]; } @end
这个问题与UIWebView
无关,而与您的控制器类无关。 确实,
MyViewController *hotelinf = [[MyViewController alloc] initWithNibName:@"MyViewController_iPad" bundle:nil]; [self.view addSubview:hotelinf.view];
您正在分配控制器并将其分配给一个局部variables; 然后将控制器的视图作为子视图添加到当前视图。 这样做,该视图被保留,但控制器对象本身会发生什么? 你释放吗? 或者它泄漏(因为它被分配给一个局部variables)?
这可能解释了为什么当稍后调用respondsToSelector
方法时,控制器已被释放…
解决这个问题的一个方法是在你的主控制器类中创build一个新的属性或者一个ivar,并且在那里存储MyViewController
。 不要忘记在dealloc中释放它。
我还build议另一件事。 在:
- (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; self.webView = nil; }
在释放视图之前将webView委托设置为零:
- (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; self.webView.delegate = nil; self.webView = nil; }
我也可能会回顾你在viewDidDisappear
释放webView的原因。 另一方面你在viewDidLoad
分配它。 这种不对称是危险的,因为每当主视图消失(出于任何原因),webView将被删除,当视图再次出现时,它不再存在。
最好添加所有委托方法。 你还没有添加前两个。 当发送消息webViewDidStartLoad
时,很可能您的代码崩溃了
– webView:shouldStartLoadWithRequest:navigationType: – webViewDidStartLoad: – webViewDidFinishLoad: – webView:didFailLoadWithError: