How to detect a SubView has closed? - iphone

I have View A, when the user clicks a button I pop up View B. When the user dismisses View B, and we return to View A I would like to refresh a label on View A, but is there an event that I can use to detect that we have returned to View B? I know that ViewDidLoad doesn't fire again.

I'm confused about the views in your question, but you might look into the NSNotificationCenter.
In this case, you would post an NSNotification event when the user dismisses View B.
Views A and B can register with the notification center to listen for this dismissal notification, calling a selector (method) when this notification is heard.
In this method, you might update a label's state or do anything else that involves updating the application state.
Likewise, you might post a notification when View B is popped-up, and have other classes register for that notification type.
More information about NSNotificationCenter is located on Apple's documentation site.

It sounds like you may be referring to UIViewControllers, rather than UIViews, correct? In that case, you can use -viewWillDisappear: (BOOL) animated and -viewDidDisappear: (BOOL) animated to determine when your viewController is-about-to-be/was-just-dismissed. These should be implemented on View B in your example. If you want to find out when View A is visible again, you can use -viewWillAppear: and -viewDidAppear.

Related

Where should I save a user's work when using a table with detail view pattern?

I've implemented workflow that uses a table view and a detail view with a navigation bar. I have been using the viewWillDisappear: message on the detail view to save the user's work, which I like because it makes sense intuitively, but it also gives the chance to set a cancel flag if the user wants to discard their work.
However, when I add the ability to take a picture to the workflow, it means that the viewWillDisappear: now is called both when the user goes back to the table and when going to the camera view. Is there a technique or method I can implement to make it so that the user's work is saved when going back to the table, but half finished work isn't saved when going into subviews?
You can check if a the detail view is being popped in the viewWillDisappear: method. The solution would be something similar to the answer to this question:
viewWillDisappear: Determine whether view controller is being popped or is showing a sub-view controller

Tracking when the page-curl modal closes(is dismissed)

I have a page-curl modal working. But I need to be able to track when the user hits the page curl to close the page so I can see some vars. Is there an event I can listen for or some delegate where I will get a call to tell me of this event?
Many Thanks
-Code
You'll see a lot of advice around here advocating the use of performSelector:withObject:afterDelay: with a small delay to take action after the dismissal of modal views, but I think there may be a better approach.
Generate the notification yourself. If you control the view that's being presented modally, use the viewDidDisappear: method in its controller to generate an "I was dismissed" notification which you then subscribe to in your main view controller (or somewhere else). viewDidDisappear: is called after the page uncurl animation completes upon dismissal of the modal view.
In the worst case, where the view may be presented modally or otherwise, you can keep state on the presenting view controller to ensure that the notification actually corresponds to a modal view dismissal.
For completeness' sake, viewWillDisappear: is generated when the page decurl transition starts.

viewWillAppear not getting called for detailView of UISplitViewController

I am experimenting with the splitViewController, introduced for iPads and am stuck at a point. I have a button on my detail view of the splitViewController, clicking on which a modal view opens. Now I want to change the positoning of UI controls on the detail view when the modal view gets dissmissed.
A pretty obvious way of doing this would be to catch the view transition in the ViewWillAppear method of the detailView. But it's not being called in this case. I remember facing the same problem in tabBarController where [tabBarController viewWillAppear:animated] was needed to be set before viewWillAppear of views in each tab item got called. I tried doing this with the splitViewController as well, but this doesn't seem to to work.
Any Ideas??
If the positioning is required due to an action that occurred in the modal view, you should use an explicit delegate callback. That will allow you to clearly specify the control flow and resulting behaviour of your app.
You should then define a protocol that has specific methods that carry pertinent information about the action taken. When the action occurs in the modal, perform the protocol method on the delegate, and it can react to that event (for you it seems to be a re-layout of button positioning).
To get an idea of the methods that are abstract enough to handle generic modal behaviour, look at UIAlertViewDelegate protocol. Here the delegate will get an alertViewCancel: message when the user decides to take no action, or alertView:didDismissWithButtonIndex: when they selected one of the options presented to them.
That is a good start for how to define the protocol.
If you need a many view controllers to react to the action taken in the modal, say a Sign In modal, then a better mechanism is notifications.

Actionscript style events in Objective-C?

I'm a newbie doing Objective-C, coming from Flex/Actionscript development.
I have an iPhone app with an UIApplicationDelegate conforming delegate called MyAppDelegate - it has a UIWindow.
Instead of adding buttons, labels and whatnot directly to the window, I guess I'm supposed to make a child class of UIViewController for every screen I wanna make. When that screen should be displayed, I add the respective controller's view to the window as a subview. When another screen should be displayed, I should pop off any other view from the window and add the new view. Hope I got everything correct so far...
My intent is to make each view controller only know about its own things, so let's say I wanna call view A from view B, in ActionScript I'd add a button in A firing off an event which would be caught in view A's owning object (could be the application), which could take proper action (remove view A, instantiate view B and display it).
How do I do this in Objective-C?
A UIControl, such as UIButton, can have any number of event listeners registered with:
- (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents;
The target would be the view controller you want to receive the method, and the action is the method you want called. For a button, events is usually just UIControlEventTouchUpInside. If the target is nil, the event will pass up the responder chain until a responder implements the action. If you pass #selector(buttonClicked:) then the target should have this method:
-(IBAction) buttonClicked:(id)sender;
The sender will be the button that was clicked. IBAction is equivalent to a void return type. You can bind the action in Interface Builder if you prefer that to doing it programmatically.
When another screen should be
displayed, I should pop off any other
view from the window and add the new
view.
This is basically correct, but usually you use a meta view controller like UINavigationController to manage view controllers. Even if you do not use the UI that a meta controller might present, it is convenient to have view switching managed for you.
If you're coming from Actionscript you may be interested in looking at the PureMVC framwork for objective C. Using PureMVC you'll create a combination of Mediators, Commands, and Models for application interaction.
With PureMVC you register notification with the facade, and you define listeners in your mediators to respond to these. This is pretty close to the event model you're used to in Actionscript. (At my last job we added some categories to the UIResponder to remove some of the cruft in doing this). If you're creating a considerably sized application, then I would recommend you give it a look; it certainly helped us keep everything manageable.
If you don't want to pull in a third party library then you should define your view manipulation code in your MyAppDelegate and use the [UIApplication sharedApplication] class method to access the globally shared instance.

UINavigationController intercepting – popViewControllerAnimated:

So the the problem is that when someone touches the back button on the UINavigationControler, I would like to run some code to update the datasource.
The problem is that i cant seem to find the right delegate to do it. only these are available on the nav controller delegate, and i want the 'didfinishshowing' type method.
– navigationController:willShowViewController:animated: optional method
– navigationController:didShowViewController:animated: optional method
The next best place i thought was the nav bar but when i try that.
Terminating app due to uncaught
exception
'NSInternalInconsistencyException',
reason: 'Cannot manually set the
delegate on a UINavigationBar managed
by a controller
This makes sense retrospectively, as you don't want some hacker messing around with the internals of the nav controller and stopping it from working.
This must is a common problem, and i have missed something simple.
Just so we're clear: view A is the starting point. User taps something and you slide right to view B. User taps the back button and you're going from B back to A and you want to do something as a result of the 'back' action.
There are three ways to do it (and on neither do you have to go near the navigationController -- these apply to the underlying viewControllers themselves):
As dmercredi suggests override viewWillAppear on view controller A so when you're heading back to it, it refreshes itself. Problem is that viewWillAppear is also called when A is called the very first time. So you'll have to set some sort of flag to distinguish between the first viewWillAppear and any subsequent ones when returning from B.
Override viewWillDisappear on view controller B and do your refreshing there. This will only get called when B is about to go away. If there's something on B that goes one level deeper or brings up a modal dialog on top, viewWillDisappear is going to get called so again you'll have to distinguish between the coming and the going.
Decouple the various views and use the delegate pattern. View controller A sets itself as a delegate of B and when B updates something it invokes the delegate method, so A is notified of the change and can update whatever it needs to. You can invoke the delegate method any time the user makes a change inside B or override viewWillDisappear and just do it one time on the way out.
Add your refresh code to the viewWillAppear:(BOOL)animated method on the view controller that is about to be displayed. In your case, that is the view controller that's already on the navigation stack.