I have a view controller which presents a modal view when a certain button is tapped. Upon closing the modal view and re-revealing the original view underneath, I want a refresh method to be called. How do I call this refresh: method in OriginalViewController from ModalViewController?
I know this works if I do it in -viewDidAppear, but I only want it to happen when the modal view closes, not every single time.
As you can see in the View Controller Programming Guide, the recommended way is to use delegation.
How do you do it is up to you, but a standard way to so would be to define a protocol such as:
#protocol RecipeAddDelegate <NSObject>
- (void)modalViewControllerDismissed:(ModalViewController *)modalViewController;
#end
Then on your OriginalViewController you can implement that method, and act when the modal view controller has been dismissed:
- (void)modalViewControllerDismissed:(ModalViewController *)modalViewController {
[self refresh]; // or anything you want to do
}
As an additional comment, the guide I linked suggest that you should dismiss the modal not from the modal itself but from the controller that opened it. In the example, they create the delegate protocol a bit different, so it has methods for the original controller to be informed of the actions the modal controller does, and be able to decide when to close it.
Have a look at the View Controller Programming Guide, specifically, the section on dismissing a modal view.
The OriginalViewController should have a protocol method called by the ModalViewController when it's done. It should be the OriginalViewControllers responsibility to dismiss the modal view and perform any tasks it needs to on itself, such as refreshing itself.
Related
After a modal view controller is dismissed, is there any delegate method called to bring the parent view controller to the front?
I ended up using delegation from Apple's View Controller Programming Guide for iOS :
http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/ModalViewControllers/ModalViewControllers.html#//apple_ref/doc/uid/TP40007457-CH111-SW14
When it comes time to dismiss a modal view controller, the preferred approach is to let the parent view controller do the dismissing. In other words, the same view controller that presented the modal view controller should also take responsibility for dismissing it whenever possible. Although there are several techniques for notifying a parent view controller that it should dismiss its modally presented child, the preferred technique is delegation.
There was a good example in the CoreDataRecepies sample code when adding a recipe that fit what I was trying to do.
i.e., at the "same time" view[Will|Did]Disappear: is being called on the modal view controller as its view is being dismissed, the view[Will|Did]Appear: are sent to the view controller that is being revealed
the code in here should not really need to differ from the reveal code you used when it was first displayed,
if you need data passed back from the modal controller to the one that displayed it, generally the code that dismisses the modal controller lets the other one know
parentController.item = self.chosenItem;
[parentController dismissModal…
I wanted to do bottom-up or up-bottom animation for settings page. (which would normally be pushViewController)
And found out that bottom-up can be done with..
- (void)presentModalViewController:(UIViewController *)modalViewController animated:(BOOL)animated;
Some people seem to suggest that you stick to Apple's HIG (Apple surely made left-right animation as default pushViewController) and do not use modal view.
I wonder what is modal view and wonder what other animations people use for pushing/popping viewController?
Thank you.
A modal view prevents interaction with any other UI until it is dismissed.
A modal view controller is simply a UIViewController class that is presented modally. When the view controller is presented modally it covers whatever the existing view was (using an animation if specified) and the user most somehow dismiss this view before they can return to what they were doing.
To present a view controller in a modal fashion, you can use the method:
- (void)presentModalViewController:(UIViewController *)modalViewController animated:(BOOL)animated;
Whenever I want to use a modal view (i.e. a view that must be completed before continuing with anything else) I would call this method and use Apple's standard animation for presenting a view controller (notice that the instance method above does not include a parameter to specify how the view is animated - because Apple has a standard way of doing this).
I have a view in my app that displays a UITableView. This view is created in a nib file and has a custom view controller. The UIViewController subclass for this view acts as the Datasource and Delegate for the UITableView.
My UITableView displays several rows based on my data. Then, the last row displays different text: "Add another...". If the last row is selected, I present a modal view controller (to allow the user to add more data). When I dismiss the modal view controller, I again see the original view (as expected) and all appears to be well. However, when I try to interact with this view, the app crashes.
From placing several NSLog() statements through the UIViewController (for the UITableView), I have determined that the -dealloc method is being called just after the modal view is dismissed. This explains the crash when I try to do something with that view. However, I have no idea why -dealloc is being called on this view controller.
To dismiss the modal view controller, I have:
[self dismissModalViewController:YES];
As the code in an IBAction method in the modal view controller's UIViewController. This action is tied to a cancel button in the corresponding nib file.
In addition, my understanding from the View Controller Programming Guide is that it's OK to dismiss the modal controller from within itself, but it's more robust to use delegates. I was initially using a delegate, but took the delegate out to simplify debugging. I just put the delegate back in to double-check, and the same behavior occurs when using delegates. The modal controller's action method calls is implemented as:
[[self delegate] myModalViewController:self didAddObject:obj];
The delegate implementation in the parent view controller is:
[self dismissModalViewController:YES]
If anyone has seen this before or has any suggestions of what could be happening or how to debug this, I would greatly appreciate it.
If -dealloc is being called, something is releasing the view controller. Try implementing -release in your view controller:
-(void)release {
NSLog(#"view controller released");
[super release];
}
so that you can use the debugger to inspect the call stack when this unexpected release message happens.
Its dangerous to call dismissModalViewController from the modal view controller itself (message will be forwarded to parent view controller), if you have not retained it elsewhere. Normally, the parent view controller is responsible for dismissing the modal view controller it presented.
After presenting another view on my rootview, then I dismiss it, I want to refresh or reload my view, is it possible?
Send the view setNeedsDisplay message.
I define a simple protocol for modal view controllers to use to notify their parent that they're done:
#protocol ModalViewControllerDelegate <NSObject>
- (void)modalViewControllerDone:(UIViewController*)viewController;
#end
The parent then implements this protocol, and assigns itself to the modal view controller's delegate property. When the modal view controller is finished, it calls [delegate modalViewControllerDone:self]. The parent then dismisses the modal view controller and can do whatever else it wants (in your case, reload something).
I've been reading the Head First iPhone Development book and I understand how to get to a new view from a table but how exactly would I be able to get to a new view or view controller, by just simply pressing a button? Is that even possible?
I mean there are some apps where you click a button, not a table cell and it loads a new view. How exactly is that done? If someone could help out a newbie it would be greatly appreciated!
I think what you're looking for is a modal vew controller. THis presents a modal view like you described on top of everything else. If rootViewController is the view controller that is displaying your current view, and myNewViewController the view controller you want to display modally:
[rootViewController presentModalViewController:myNewViewController animated:YES];
There's plenty of examples of this kind of thing on the net, just search for presentModalViewController
Like bpapa said in the comments, it's hard to be specific without code. However, generally what you want to do is:
Build a navigation controller that contains one original view.
Create a button in your original view using the Interface Builder.
Build a callback method (usually defined with IBAction) that is run when the button is pushed.
In that callback method, create a new view and push it onto the navigation controller the same way you would using a table view cell.
Alternately, if you only want one level of hierarchy, you could use a modal view controller; instead of pushing onto the navigation controller in the last step, just present the modal view controller.
The general answer is that you have an object that manages which view controller loads when.
The most commonly used is the UINavigationController. It is a UIViewController that instead of controlling views, controls other view controllers. It works like a simple stack. You push views you want to display onto the nav's controller stack and when you want them to disappear you pop them off.
A common (though sloppy) way of using a nav is to make it a property of your app delegate. Then anywhere in your app you can references it by:
UINavigationController *nav=[[[UIApplication sharedApplication] delegate] navigationController];
The view controller for the first the user sees is held in the nav's topViewController property. If you want to load a view based on a user action in the topViewController.view, you would have something like this:
- (IBAction) loadNextView:(id) sender{ // Action called by a a UI event such as a button press.
UINavigationController *nav=[[[UIApplication sharedApplication] delegate] navigationController];
UIViewController *nextViewController=...// load from nib, connect with IBOutlet, create programmatically
[nav pushViewController:nextView animated:YES];
}
The first view disappears to be replaced by the next one. To return to the first view, you have a method in the next view controller like so:
- (IBAction) unloadSelf:(id) sender{ // Action called by a a UI event such as a button press.
UINavigationController *nav=[[[UIApplication sharedApplication] delegate] navigationController];
[nav popViewControllerAnimated:YES];
}
... and the nav returns you automatically to the previous view regardless of what that view was.
When you first start out, especially if you use Interface Builder, the structure of the app is largely hidden. Behind the scenes all view controllers and their views exist in a hierarchy of some kind that leads back up to the app delegate. You should train yourself to think in hierarchal terms even if it is not immediately obvious how that hierarchy is constructed.