Objective-c – Iphone: Unable to load modal view from UITabBarController

cocoa-touchiphoneiphone-sdk-3.0objective c

I want to be able to present a modal view with an instance of a UIViewController. I have no problem doing this when presenting it from a standard UIViewController (the root view). I have set up a delegate to make the presenting root view close the modal view. This is according to Apple best practice.

When I try to make the same root view present the modal view when the root view is loaded from a UITabBarController I get serious problems. The first three times I have no problem loading the view, but the fourth time the debugger shows that the the root view is deallocated when trying to call the delegate method ("message sent to deallocated instance"). My guess is that the root view has been autoreleased while the modal view was shown. How am I able to avoid this?

The example I have set up uses the template for the the UITabBarController, presenting the modal view from the first view:

FirstViewController.h (root view controller):

#import <UIKit/UIKit.h>

@protocol ModalDelegate;
@interface FirstViewController : UIViewController <ModalDelegate>{
}

-(IBAction)startPressed:(id)sender;
@end

FirstViewController.m:

#import "FirstViewController.h"
#import "ModalViewController.h"


@implementation FirstViewController

-(IBAction)startPressed:(id)sender
{
 ModalViewController *modal=[[ModalViewController alloc] init];
 modal.delegate=self;
 [self presentModalViewController:modal animated:TRUE];
 [modal release];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

- (void)dealloc {
    [super dealloc];
}

#pragma mark Modal Delegate
-(void)modal:(ModalViewController *)controller
{
 [self dismissModalViewControllerAnimated:YES];
}

@end

ModalViewController.h:

#import <UIKit/UIKit.h>

@protocol ModalDelegate;


@interface ModalViewController : UIViewController {
 id<ModalDelegate> delegate;

}

@property (assign) id<ModalDelegate> delegate;

- (IBAction)OKPressed:(id)sender;

@end

@protocol ModalDelegate <NSObject>

@optional
-(void)modal:(ModalViewController *)controller;

@end

ModalViewController.m:

#import "ModalViewController.h"

@implementation ModalViewController
@synthesize delegate;
- (IBAction)OKPressed:(id)sender
{
 if ([self.delegate respondsToSelector:@selector(modal:)]) //Check to see if method responds to selector
 {
  [self.delegate modal:self];
 }
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

- (void)dealloc {
 [delegate release];
    [super dealloc];
}

@end

Best Answer

You should not release the delegate in the ModalViewController's implementation of dealloc since you (correctly) did not retain it.

Also, you can dismiss the modal view controller from itself rather than setting up a delegate. I find this simpler. Here is the iPhone Dev Center discussion of dismissModalViewControllerAnimated:

The parent view controller is responsible for dismissing the modal view controller it presented using the presentModalViewController:animated: method. If you call this method on the modal view controller itself, however, the modal view controller automatically forwards the message to its parent view controller.

Related Topic