【问题标题】:Popping UIView crashes app弹出 UIView 使应用程序崩溃
【发布时间】:2011-02-18 22:15:33
【问题描述】:

我基本上是从 UITableViewController 推送 UIView,它所包含的只是一个 UIWebView。但是,当我删除 UIView 以返回 UITableView 时,应用程序崩溃了。

- (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 release] 应用程序不会崩溃,但我知道这将是一个泄漏。

下面是网页浏览器的代码:

#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

关于应用程序为什么会崩溃的任何想法?

【问题讨论】:

    标签: iphone iphone-sdk-3.0 uiviewcontroller


    【解决方案1】:

    我刚刚弄清楚它是什么。在 WebViewController 的 dealloc 中,我有这个:

    - (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];
    }
    

    所以我在发布之前没有将代理设为 nil,所以我的 webview 肯定仍在向不存在的代理发送调用。

    【讨论】:

    • 是的,你是对的。尽管这样的代码顺序如何导致这样的问题有点奇怪。
    【解决方案2】:

    我敢打赌,仍然是 webView 仍在向其委托(您现在已解除分配的视图控制器)发送事件。

    另外,您是否运行过 Xcode Build & Analyze 来发现潜在的内存泄漏/过度释放?

    【讨论】:

    • 但是我在 viewWillDisappear 和 dealloc 都将委托设置为 nil 但它似乎仍然崩溃。我已经运行了 Build & Analyze,它编译得很好。
    【解决方案3】:

    问题在于,实际上您在发布后将webBrowserView delegate 设置为nil。通过在释放之前将所有内容设置为 nil,您会造成内存泄漏(发送 [nil release] 不会执行任何操作)。

    应该是这样的

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-08
      • 1970-01-01
      • 2013-12-05
      • 1970-01-01
      相关资源
      最近更新 更多