Ryan Stone
Ryan Stone

Reputation: 3

Objective-C on iPhone - tab bar crash

I'm relatively new to Objective-C and coding. I've tried doing a little dev on my own but have now become stuck on what is probably a rookie error. I've created a tab bar controller with 5 views, one such view is a UIWebView. I've got the Webview working and it loads, but when I select a different tab, the app crashes. Please find my code below and any help would be appreciated!

#import <UIKit/UIKit.h>


@interface LiveViewController : UIViewController {

IBOutlet UIWebView *liveView;

}

@property (nonatomic, retain) UIWebView *liveView;

@end



    #import "LiveViewController.h"

@implementation LiveViewController

@synthesize liveView; 



// The designated initializer.  Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
/*
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization.
    }
    return self;
}
*/

/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/


// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [self.liveView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.britishseapower.co.uk/live/"]]];
[super viewDidLoad];
}

- (void)webViewDidStartLoad:(UIWebView *)liveView
{
    // starting the load, show the activity indicator in the status bar
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
}

- (void)webViewDidFinishLoad:(UIWebView *)liveView
{
    // finished loading, hide the activity indicator in the status bar
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}

- (void)liveView:(UIWebView *)liveView didFailLoadWithError:(NSError *)error
{
    // load error, hide the activity indicator in the status bar
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;

    // report the error inside the webview
    NSString* errorString = [NSString stringWithFormat:
                             @"<html><center><font size=+5 color='red'>An error occurred:<br>%@</font></center></html>",
                             error.localizedDescription];
    [self.liveView loadHTMLString:errorString baseURL:nil];
}

- (void)viewWillDisappear:(BOOL)animated
{
    if ( [self.liveView loading] ) {
        [self.liveView stopLoading];
    }
    self.liveView.delegate = nil;    // disconnect the delegate as the webview is hidden
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}


- (void)dealloc {
    [liveView release];
    [UIWebView release];
    [LiveViewController release];
    [super dealloc];
}


@end

Many thanks,

Ryan

Upvotes: 0

Views: 566

Answers (4)

emp
emp

Reputation: 3498

Crashes like this are almost always related to releasing an object that has already been released and deallocated.
Let XCode help you find the error. In XCode 4:
- In the toolbar, select the scheme list, and select 'Edit Scheme'
- Select the 'Run Your.app' in the list on the left. - Under 'Environment Variables', add the following name/value pairs in the appropriate columns:
CFZombieLevel 3
NSZombieEnabled YES

Now when debug your app, you will get a message telling when -release is called on an object that already has a -retainCount of zero. Now you have a good clue to start your investigation.

Note that these flags prevent objects from being deallocated, so it is best to turn them on as needed to prevent out of memory errors.

Upvotes: 0

MHC
MHC

Reputation: 6405

One of the most common reasons why an app may crash is to refer to or send a message to an object that has been already released from the memory. And this type of bug can be easily located using NSZombieEnabled and looking into the console message. So if you haven't already tried that, that's the first thing you must do.

The problem could be in LiveViewController but could be in the other view controllers as well. I wouldn't believe the problem is 100% in LiveViewController because the view controller wouldn't try releasing its view when the view is not shown unless it gets a memory warning. And you run the app using the simulator, it's unlikely it will have a memory warning unless you simulate one.

You would probably know that a view controller never create a view unless the view is used by an object. One of the other view controllers may have a silly bug in its view loading process which causes a crash. Or, you might have released another view controller by mistake. Make 100% sure that the other view controllers have no problem showing their views on their own, when you keep changing between their views (without showing LiveViewController).

So what I would do is to try NSZombieEnabled and check if it accesses a released object, and if it does, what the object is. Also, I will make a double check that the problem is related to LiveViewController. If it doesn't help I would log a message when LiveViewController and its liveView is deallocated (for liveView you need to subclass it). Because delegate property almost always does not retain an object, if the LiveViewController object is released (which shouldn't happen) and liveView still has a reference to it in the delegate property it will make a crash.

Upvotes: 1

Mark Adams
Mark Adams

Reputation: 30846

Not sure if this is related but I noticed that you aren't setting yourself as the delegate anywhere in code which means that it must be connected in Interface Builder. Now when the view disappears, you are breaking that connection, but if the view were to re-appear and wasn't previously unloaded that connection will remain broken.

Upvotes: 1

grandouassou
grandouassou

Reputation: 2530

[UIWebView release]; [LiveViewController release];

This is what make your app crash. It's not valid to send a release message to a class itself. What you've done with [liveView release]; is enough (with the call to [super dealloc];.)

You should also set the delegate to nil in the dealloc method as in the viewWillDisappear method self.liveView.delegate = nil;. This way you're sure to avoid any further message sent to the LiveViewController from the UIWebView.

You should read a bit more of documentation on Objective-C to better understand how it works.

Upvotes: 2

Related Questions