我创建了一个运行完美的ARC应用程序。它有一个UINavigationController,我用它来浏览视图,一切运行正常。
我正在将应用程序转换为iPad,我决定将其中一个视图显示为popover。 (我不喜欢UIPopoverController所以我创建了自己的基本弹出窗口)。它被添加到视图中如下..
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
答案 0 :(得分:15)
该问题与UIWebView
无关,而与您的控制器类无关。事实上,
MyViewController *hotelinf = [[MyViewController alloc]
initWithNibName:@"MyViewController_iPad" bundle:nil];
[self.view addSubview:hotelinf.view];
您正在分配控制器并将其分配给局部变量;然后将控制器的视图作为子视图添加到当前视图中。这样做,该视图被保留,但控制器对象本身会发生什么?你发布了吗?或者它泄漏(因为它被分配给局部变量)?
这可能解释了为什么稍后调用respondsToSelector
方法时,控制器已被解除分配...
解决此问题的方法是在主控制器类中创建新属性或ivar,并在其中存储MyViewController
。不要忘记以dealloc发布它。
我还会建议另一件事。在:
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
self.webView = nil;
}
在发布视图之前将webView委托设置为nil:
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
self.webView.delegate = nil;
self.webView = nil;
}
我还可以查看您在viewDidDisappear
中发布webView的原因。另一方面,您在viewDidLoad
中分配它。这种不对称是危险的,因为每当主视图消失(出于任何原因)时,webView将被删除,当视图重新出现时,它就不再存在了。
答案 1 :(得分:-3)
更好地添加所有委托方法。你没有添加前两个。最有可能的是,当发送消息webViewDidStartLoad
时,您的代码会崩溃
– webView:shouldStartLoadWithRequest:navigationType:
– webViewDidStartLoad:
– webViewDidFinishLoad:
– webView:didFailLoadWithError: