I'm basically pushing a UIView from a UITableViewController and all it contains is a UIWebView. However when I remove the UIView to return back to the UITableView the app crashes.
- (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];
}
}
If I comment out the [webViewController release] the app doesn't crash, but I know that this would be a leak.
Below is the code for the Web Browser:
#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
Below this is the crash log that I am getting:
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
Any ideas on why the app is crashing?
I just figured out what it was. In the WebViewController's dealloc I had this:
- (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];
}
So by changing it to this it works fine and there are no leaks:
- (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];
}
So I didn't nil the delegate before the release so I webview must have still be sending calls to a delegate that doesn't exists.
I'd bet that it's the webView that is still sending events to its delegate (your now dealloc'ed view controller).
Also, have you run the Xcode Build & Analyze to find potential memory leaks / over releases?
The problem is that actually you are setting the webBrowserView
delegate
to nil
AFTER you've released it. By setting everything to nil BEFORE releasing it you create memory leaks (sending [nil release]
does nothing).
Instead it should be like
- (void)dealloc {
[webBrowserView stopLoading];
webBrowserView.delegate = nil;
[webBrowserView release];
[urlValue release];
[toolBar release];
[spinner release];
[loadUrl release];
[super dealloc];
}
User contributions licensed under CC BY-SA 3.0