views:

438

answers:

2

I have a UITabBarConroller that I use to switch between 3 different views. This all works perfectly. On one of my tabs, I added a button at the to called "Add", I have added an outlet to this, as well as an IBAction method which looks like the following:

// Method used to load up view where we can add a new ride
- (IBAction)showAddNewRideView {    

    MyRidesViewController *controller = [[MyRidesViewController alloc] initWithNibName:@"AddNewRide" bundle:nil];
    controller.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
    [self presentModalViewController:controller animated:YES];
    [controller release];

}//end showAddNewRideView

This currently works fine, and loads up my AddNewRide nib file. But, once that view loads, I have a cancel button, which, when clicked, I want to return to the previous view. So, I figured I would just do the reverse of the above, using the following method which would load back my previous nib:

- (IBAction)cancelAddingNewRide {
    MyRidesViewController *controller = [[MyRidesViewController alloc] initWithNibName:@"MainWindow" bundle:nil];
    controller.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
    [self presentModalViewController:controller animated:YES];
    [controller release];

}//end cancelAddingNewRide

But, which trying to load the MainWindow nib, the program crashes, and I get the following error:

2010-05-05 20:24:37.211 Ride[6032:207] *** -[MyRidesViewController cancelAddingNewRide]: unrecognized selector sent to instance 0x501e450
2010-05-05 20:24:37.213 Ride[6032:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[MyRidesViewController cancelAddingNewRide]: unrecognized selector sent to instance 0x501e450'

So, I am a little lost as to why it would work one way, but not the other.

A: 

Typically when I have used presentModalViewController the presented viewController tells the calling viewController to dismiss it using dismissModalViewControllerAnimated:YES;

So in other words in the cacncelAddingNewRide you simply call the class that hass showAddnewRideView in it and have it pass itself to the method.

Its hard to explain but Ill show you an example:

cancelAddingNewRide class:

- (IBACtion)home:(id)sender {
    if (self.delegate respondsToSelctor:@selector(dismiss:)]) {
        [self.delegate dismiss:self];
    }
}

and then in the showAddNewRideView class

-(void) dismiss:(cancelAddingNewRide_class *) controller {
     [self dismissModalViewControllerAnimated:Yes];
}

Hope that makes sense and soz for typos

Edit: oh and make the controller's delegate self

controller.delegate = self;

Actually thinking about it more there is a bit more to this. You have to define the called viewController as a Delegate. Have a look at Stanford universities iPhone lectures, lecture 11 deals with this and is available from iTunesU

Rudiger
+1  A: 

First, I wanted to address part of the error: Think of your views as a stack. When you "push" a modal controller, you are adding that view to a stack. The old view is still there underneath. So you need to "pop" off the modal view to return to the old view. If you push a new view on, you now have 3 views on the stack which are all taking up memory, where you really only need one.

So, inside cancelAddingNewRide just try:

[super dismissModalViewControllerAnimated:true];

You may have other issues that are causing the crash, but this should generally get things working.

Nathan S.
This is true but is not a recommended way. The current viewController shouldn't dismiss itself, the class that called it should dismiss it
Rudiger
Apple's docs say: "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." While the modal controller isn't responsible, it doesn't say it shouldn't dismiss itself. Does Apple document this elsewhere?
Nathan S.
Yay! This definitely worked, and solved my problem. But, you see that is not a good method?
Nic Hubbard
I do believe in Apples demo examples the viewController calls its parent to dismiss it and your quote basically confirms that. I guess the only problem I can think of is if the parent wants to know that the viewController has been dismissed this way would have issues doing it, perhaps in the viewWillAppear method. Cancelling wouldn't be an issue but if you want to reload a table to update what you have just inputted on the modalViewController it would be a problem as the parent wouldn't know it its been cancelled or something added, just that its been dismissed.
Rudiger
Right -- when this happens I use the NSNotificationCenter center to post an update message back to the controlling view. That's really easy, but I'm open to other, better methods.
Nathan S.