I am implementing a custom URL scheme which will add entities to my data model. The details for the entity are contained in the URL. The basic idea is that an email link (or a link from another app) will open my app and add the new entity.
The problem is, I can never be sure which state my app will be in when responding. Any number of view controllers might be in view. If the list of entities is in view, I need to insert a new row for that entity. If other views are on screen, I need to react differently. Some views might also be modal.
I would be satisfied with a simple pattern when this happens – abort whatever the user is currently doing, and pop to the root view controller. From here I will probably push to a controller where I will show the new entity being added.
I experimented with always dismissing any modal displayed and popping to the root, with the benefit of not needing to know what exactly is being displayed:
[(UINavigationController *)self.window.rootViewController dismissViewControllerAnimated:NO completion:nil];
[(UINavigationController *)self.window.rootViewController popToRootViewControllerAnimated:NO];
This works reasonably well, but there at least two cases where it is insufficient:
- If some object was created when the modal was presented (the modal is then used to modify the new object), and it is the delegate’s responsibility to delete the object if the user cancels, the entity will remain alive.
- If a
UIActionSheetis being displayed, all bets are off. I can’t dismiss this without knowing the controller that displayed it, having access to that controller, and sending it a message to dismiss the action sheet. Without doing so, the root view controller is popped to but the action sheet stays on screen. Subsequent taps on the action sheet of course cause a crash, since the controller that displayed it is gone.
How might I handle this robustly? Should I be trying to find out specifically which view controller is currently presented, and handling each scenario in turn? Or is there a more scalable solution that won’t need updating each time I add controllers or change my application’s flow?
It sounds like you are trying to do several things:
EntityListViewController, which may or may not be on the ViewController stack.EntityListViewController.EntityViewController, or if there is currently anEntityViewControllerin the view controller stack, you want to reload with the new entity’s data.It sounds like you have item 1 ready to go, since you didn’t explicitly ask about handling the url click and inserting the new model object.
For the rest, a flexible and MVC-ish pattern would be to use NSNotificationCenter.
The code that inserts the new model object would “post” a notification:
Then your various UI elements (e.g., UIAlertView and UIViewController subclasses) would listen for this notification and take some useful action (like closing themselves, or in the case of
EntityListViewControllerorEntityViewController, reloading themselves).For example, a
UIViewControllersubclass might do this:To keep your life simple (and not worry too much about all the different UI states), I would consider doing this when the notification occurs:
EntityListViewControllerredraw itself (does not matter if there something on top of it).If you take this approach, then there is minimal impact on whatever the user is/was doing, but when they do navigate back to the
EntityListViewControllerit has all the new entities already displayed.Clearly, if the click on the custom URL could possibly delete an existing entity, then it would be more important to pop off any viewcontrollers related to that entity. But this is also something you could do using the same pattern — have the model or controller post the notification, and then have the various UI elements listen for it and take appropriate action.