2010-05-13 2 views
4

Я в основном нажимаю UIView из UITableViewController, и все, что он содержит, является UIWebView. Однако, когда я удаляю UIView, чтобы вернуться в UITableView, приложение аварийно завершает работу.Popping UIView crashes app

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 
// Navigation logic may go here. Create and push another view controller. 
if (indexPath.row == websiteCell) { 
    NSString *urlPath = [NSString stringWithFormat:@"http://%@", exhibitor.website]; 
    WebViewController *webViewController = [[WebViewController alloc] initWithURLString:urlPath]; 

    // Pass the selected object to the new view controller. 
    [self.parentViewController presentModalViewController:webViewController animated:YES]; 
    [webViewController release]; 
} 

}

Если я закомментировать [релиз webViewController] приложение не врезаться, но я знаю, что это будет утечка.

Ниже приведен код для веб-браузера:

#import "WebViewController.h" 

@implementation WebViewController 

@synthesize webBrowserView; 
@synthesize urlValue; 
@synthesize toolBar; 
@synthesize spinner; 
@synthesize loadUrl; 

-(id)initWithURLString:(NSString *)urlString { 
if (self = [super init]) { 
    urlValue = urlString; 
} 

return self; 
} 


#pragma mark WebView Controls 
- (void)goBack { 
[webBrowserView goBack]; 
} 


- (void)goForward { 
[webBrowserView goForward]; 
} 


- (void)reload { 
[webBrowserView reload]; 
} 

- (void)closeBrowser { 
[self.parentViewController dismissModalViewControllerAnimated:YES]; 
} 

#pragma end 

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib. 
- (void)viewDidLoad { 
[super viewDidLoad]; 

CGRect contentRect = self.view.bounds; 
//NSLog(@"%f", contentRect.size.height); 
float webViewHeight = contentRect.size.height - 44.0f; // navBar = 44 
float toolBarHeight = contentRect.size.height - webViewHeight; 


// navigation bar 
UINavigationBar *navBar = [[[UINavigationBar alloc] initWithFrame:CGRectMake(0, 20, contentRect.size.width, 44)] autorelease]; 
navBar.delegate = self; 

UIBarButtonItem *doneButton = [[[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:nil action:@selector(closeBrowser)] autorelease]; 
UINavigationItem *item = [[[UINavigationItem alloc] initWithTitle:@"CEDIA10"] autorelease]; 
item.leftBarButtonItem = doneButton; 

[navBar pushNavigationItem:item animated:NO]; 
[self.view addSubview:navBar]; 

// web browser 
webBrowserView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 64, contentRect.size.width, webViewHeight)]; 
webBrowserView.delegate = self; 
webBrowserView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 
webBrowserView.scalesPageToFit = YES; 
[self.view addSubview:webBrowserView]; 

// buttons 
UIBarButtonItem *backButton = [[[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"arrowleft.png"] style:UIBarButtonItemStylePlain target:self action:@selector(goBack)] autorelease]; 
UIBarButtonItem *fwdButton = [[[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"arrowright.png"] style:UIBarButtonItemStylePlain target:self action:@selector(goForward)] autorelease]; 
UIBarButtonItem *refreshButton = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:@selector(reload)] autorelease]; 
UIBarButtonItem *flexSpace = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil] autorelease]; 
UIBarButtonItem *fixSpace = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil] autorelease]; 
[fixSpace setWidth: 40.0f]; 

spinner = [[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite] autorelease]; 
[spinner startAnimating]; 
UIBarButtonItem *loadingIcon = [[[UIBarButtonItem alloc] initWithCustomView:spinner] autorelease]; 

NSArray *toolBarButtons = [[NSArray alloc] initWithObjects: fixSpace, backButton, fixSpace, fwdButton, flexSpace, loadingIcon, flexSpace, refreshButton, nil]; 

// toolbar 
toolBar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, webViewHeight, contentRect.size.width, toolBarHeight)]; 
toolBar.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth; 
toolBar.items = toolBarButtons; 

[self.view addSubview:toolBar]; 

// load the request 
NSURL *requestString = [NSURL URLWithString:urlValue]; 
[webBrowserView loadRequest:[NSURLRequest requestWithURL: requestString]]; 

[toolBarButtons release]; 
} 

- (void)viewWillDisappear 
{ 
if ([webBrowserView isLoading]) { 
    [webBrowserView stopLoading]; 
    webBrowserView.delegate = nil; 
} 
} 

#pragma mark UIWebView 

- (void)webViewDidStartLoad:(UIWebView*)webView { 
[spinner startAnimating]; 
} 

- (void)webViewDidFinishLoad:(UIWebView*)webView { 
[spinner stopAnimating]; 
} 

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { 
loadUrl = [[request URL] retain]; 

if ([[loadUrl scheme] isEqualToString: @"mailto"]) { 
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"CEDIA10" message:@"Do you want to open Mail and exit AREC10?" delegate:self cancelButtonTitle:@"No" otherButtonTitles:@"Yes",nil]; 
    [alert show]; 
    [alert release]; 

    return NO; 
} 

[loadUrl release]; 

return YES; 
} 

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { 
[spinner stopAnimating]; 
if (error.code == -1009) { 
    // no internet connection 
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"CEDIA10" message:@"You need an active Internet connection." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil]; 
    [alert show]; 
    [alert release]; 
} 
} 

#pragma mark UIAlertView 

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { 
if (buttonIndex == 1) { 
    [[UIApplication sharedApplication] openURL:loadUrl]; 
    [loadUrl release]; 
} 
} 


- (void)didReceiveMemoryWarning { 
// Releases the view if it doesn't have a superview. 
[super didReceiveMemoryWarning]; 

// Release any cached data, images, etc that aren't in use. 
[webBrowserView release]; 
[urlValue release]; 
[toolBar release]; 
[spinner release]; 
[loadUrl release]; 

webBrowserView = nil; 
webBrowserView.delegate = nil; 
urlValue = nil; 
toolBar = nil; 
spinner = nil; 
loadUrl = nil; 
} 

- (void)viewDidUnload { 
// Release any retained subviews of the main view. 
// e.g. self.myOutlet = nil; 

} 


- (void)dealloc { 
[webBrowserView release]; 
[urlValue release]; 
[toolBar release]; 
[spinner release]; 
[loadUrl release]; 

webBrowserView.delegate = nil; 
urlValue = nil; 
toolBar = nil; 
spinner = nil; 
loadUrl = nil; 

[super dealloc]; 
} 


@end 

Ниже это крах журнала, что я получаю:

Date/Time:  2010-05-13 11:58:20.023 +1000 
OS Version:  iPhone OS 3.1.3 (7E18) 
Report Version: 104 

Exception Type: EXC_CRASH (SIGABRT) 
Exception Codes: 0x00000000, 0x00000000 
Crashed Thread: 0 

Thread 0 Crashed: 
0 libSystem.B.dylib    0x00090b2c __kill + 8 
1 libSystem.B.dylib    0x00090b1a kill + 4 
2 libSystem.B.dylib    0x00090b0e raise + 10 
3 libSystem.B.dylib    0x000a7e34 abort + 36 
4 libstdc++.6.dylib    0x00066390 __gnu_cxx::__verbose_terminate_handler() + 588 
5 libobjc.A.dylib     0x00008898 _objc_terminate + 160 
6 libstdc++.6.dylib    0x00063a84 __cxxabiv1::__terminate(void (*)()) + 76 
7 libstdc++.6.dylib    0x00063afc std::terminate() + 16 
8 libstdc++.6.dylib    0x00063c24 __cxa_throw + 100 
9 libobjc.A.dylib     0x00006e54 objc_exception_throw + 104 
10 CoreFoundation     0x00095bf6 -[NSObject doesNotRecognizeSelector:] + 106 
11 CoreFoundation     0x0001ab12 ___forwarding___ + 474 
12 CoreFoundation     0x00011838 _CF_forwarding_prep_0 + 40 
13 QuartzCore      0x0000f448 CALayerCopyRenderLayer + 24 
14 QuartzCore      0x0000f048 CA::Context::commit_layer(_CALayer*, unsigned int, unsigned int, void*) + 100 
15 QuartzCore      0x0000ef34 CALayerCommitIfNeeded + 336 
16 QuartzCore      0x0000eedc CALayerCommitIfNeeded + 248 
17 QuartzCore      0x00011ee8 CA::Context::commit_root(void*, void*) + 52 
18 QuartzCore      0x00011e80 x_hash_table_foreach + 64 
19 QuartzCore      0x00011e2c CA::Transaction::foreach_root(void (*)(void*, void*), void*) + 40 
20 QuartzCore      0x0000bb68 CA::Context::commit_transaction(CA::Transaction*) + 1068 
21 QuartzCore      0x0000b46c CA::Transaction::commit() + 276 
22 QuartzCore      0x000135d4 CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 84 
23 CoreFoundation     0x0000f82a __CFRunLoopDoObservers + 466 
24 CoreFoundation     0x00057340 CFRunLoopRunSpecific + 1812 
25 CoreFoundation     0x00056c18 CFRunLoopRunInMode + 44 
26 GraphicsServices    0x000041c0 GSEventRunModal + 188 
27 UIKit       0x00003c28 -[UIApplication _run] + 552 
28 UIKit       0x00002228 UIApplicationMain + 960 
29 CEDIA10       0x00002e16 main (main.m:14) 
30 CEDIA10       0x00002db8 start + 32 

Любые идеи о том, почему приложение рушится?

ответ

1

Я бы пообещал, что это веб-приложение, которое по-прежнему отправляет события своему делегату (ваш теперь обработчик просмотра dealloc'ed).

Кроме того, вы запускаете Xcode Build & Анализируйте, чтобы найти потенциальную утечку памяти/над версиями?

+0

Но я поставил делегат ноль на обоих viewWillDisappear и dealloc, но она по-прежнему кажется врезаться. Я запустил Build & Analyze, и он отлично компилируется. – Adun

2

Я только что понял, что это было. В dealloc в WebViewController, я имел это:

- (void)dealloc { 
[webBrowserView release]; 
[urlValue release]; 
[toolBar release]; 
[spinner release]; 
[loadUrl release]; 

webBrowserView.delegate = nil; 
urlValue = nil; 
toolBar = nil; 
spinner = nil; 
loadUrl = nil; 

[super dealloc]; 

}

Так, изменяя его к этому он отлично работает, и нет никаких утечек:

- (void)dealloc { 
webBrowserView.delegate = nil; 
[webBrowserView stopLoading]; 
urlValue = nil; 
toolBar = nil; 
spinner = nil; 
loadUrl = nil; 

[webBrowserView release]; 
[urlValue release]; 
[toolBar release]; 
[spinner release]; 
[loadUrl release]; 

[super dealloc]; 
} 

Так что я не ноля делегата перед выпуском, поэтому веб-просмотр должен по-прежнему отправлять вызовы делегату, который не существует.

+2

Итак, что вы говорите, я был прав;) –

+0

Да, вы правы. Хотя несколько странно, как такой порядок кода может вызвать такую ​​проблему. – Adun

1

Проблема в том, что на самом деле вы устанавливаете webBrowserViewdelegate на номер nil ПОСЛЕ того, как вы его выпустили. Устанавливая все до нуля, прежде чем освобождать его, вы создаете утечки памяти (отправка [nil release] ничего не делает).

Вместо этого он должен быть как

- (void)dealloc { 
    [webBrowserView stopLoading]; 
    webBrowserView.delegate = nil; 

    [webBrowserView release]; 
    [urlValue release]; 
    [toolBar release]; 
    [spinner release]; 
    [loadUrl release]; 

    [super dealloc]; 
}