Dismissing a UIPopoverController from within its contentViewController? - iphone

If you want to dismiss a popover -- for example, from a button within the popover's contentViewController you must --
Create a reference to the popover to be held by view controller which creates it
Create a notification from the contentViewController to let the owning view controller know that it should be dismissed, or alternately create a delegate for the same purpose
Send the notification or delegate message when the popover is ready to be dismissed
Call dismissPopover:animated when the notification or delegate method is called
Meanwhile, from a UIViewController you can access the modal view controller, the parent view controller, the navigation controller, the split view controller, the tab bar controller, the search display controller, the child view controllers, the presenting view controllers, and the presented view controllers.
Is there a better approach to do this from popover's contentViewController?

Unfortunately, you'll have to create a weak property reference to said UIPopoverController as there's no way to access it from within the content view controller.
I was surprised how UIViewControllers can access the modal view controller, the parent view controller, the navigation controller, the split view controller, the tab bar controller, the search display controller, and as of iOS 5, the child view controllers as well as presenting and presented controllers...but not the popover controller (granted popovers aren't UIViewControllers but still).
Technically, there's a private, undocumented method to retrieve the popoverController that the UIViewController is in...I have no idea why they never made it public given that it should be exactly the same as any of the above controllers.
Though even in the private, undocumented world, there's no equivalent to dismissModalViewcontrollerAnimated:. You'll still have to get that reference then dismiss it that way.

Another way to solve this is to create an abstract view controller (for all your view controllers) that adds an NSNotification observer to a method such as -(void)closePopoverIfNecessary:(NSNotification*)notification and have child classes optionally implement the method to close their popover(s) if open. Then from within the popover's controller you fire the notification to close it. You could also pass other info via the notification (userInfo) if needed.
This way there's no need for the parent references.

Related

addChildViewController and presentViewController

iOS 5 introduces the concept of custom container view controller and provides API like addChildViewController. Question: can you add a view controller as a child and still present it using presentViewController? Does doing the latter automatically make it a child view controller of the presentingViewController?
That's not how it's supposed to be used.
The parent/child relationship is for when a view controller has subviews that are managed by their own view controllers, for example a UITabBarController, where the parent view controller draws the tabs and the child view controllers draw the content of each tab.
If you present a view controller using presentViewController, it generally takes over the whole screen, or appears in a modal so that the presenting view controller is no longer in control. In that scenario there's no reason for the presenter to be the parent because it doesn't need to cooperate with the presented controller - it just gets out of the way until the presented controller is dismissed again.
Why is it that you wanted to do this? If it's just so that the view controllers have a reference to one another and can pass data, there are other ways to do this (e.g. the delegate pattern, NSNotifications, or even just a property linking the two).

What happen on current viewController when i call presentModalViewController

i'm developing an app for iphone, and i use
[self presentModalViewController:aViewControllerInitializateBefore animated:YES];
Can you tell me what happens to the current viewController when i use this?
The current view controller stays "underneath" the modal view controller and will reappear when you call
- (void)dismissModalViewControllerAnimated:(BOOL)animated
either on the modal view or the parent/presenting view controller (as the parent/presenting view controller's view is no longer visible, it's view may be unloaded when the system requires memory, and reloaded on dismiss).
From this method's documentation:
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.
If you present several modal view controllers in succession, and thus
build a stack of modal view controllers, calling this method on a view
controller lower in the stack dismisses its immediate child view
controller and all view controllers above that child on the stack.
When this happens, only the top-most view is dismissed in an animated
fashion; any intermediate view controllers are simply removed from the
stack. The top-most view is dismissed using its modal transition
style, which may differ from the styles used by other view controllers
lower in the stack.
Also note the change in iOS 5
Prior to iOS 5.0, if a view did not have a parent view controller and
was being presented modally, the view controller that was presenting
it would be returned. This is no longer the case. You can get the
presenting view controller using the presentingViewController
property.

Is there a delegate in the parent view controller that gets called after a modal view gets dismissed?

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…

UIViewController -dealloc Being Called After Dismissing Modal View Controller

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.

View controller chain

I have a Navigation Controller with a root table view which has several links. Tapping each link moves to the next view (by pushing it to the navigation controller's stack). But suppose that in that "next view", I have a UIButton that should take me further to another view (by pushing on to the same navigation controller's stack)...
View Controller-->first view-->second view-->third view..........
Now, I can easily access the Navigation Controller when I deal with the first view (and successfully push it to the Navigation Controller's stack) because it has been instantiated in the same file itself. What my real doubt is--How do you access a Navigation Controller in a far off view controller (eg, the third view or fourth view etc)? Please note that I am not using any separate delegate. All the Navigation Bar methods have been implemented in one file and connected to the Navigation Controller via an outlet.
When you push a ViewController onto a NavigationController the ViewController will automatically have it's navigationController property set. This means you can access the same NAvigationController no matter where you are in the stack.
-Update-
navigationController
In every UIViewController you can access that property.
So to in any other UIViewController that has been pushed onto the stack you should be able to just do this:
[self.navigationController pushViewController:othercontroller animated:YES];
Look at the documentation for UIViewController to see what other magic properties you have available.