Handoff and restoring view controller hierarchy

Good evening,


I have been trying to implement handoff from my watchkit 1 extension to my iPhone app. The NSUserActivity creation works fine, the icon gets displayed on the iPhone's lock screen and my application delegate gets called with the proper activity/data.


What I'm struggling with is to restore the required view controller hierarchy to resume the activity on the iPhone. I was expecting this to be as straightforward as UIKit state restoration, which I have recently implemented, but I keep hitting a wall.


My app supports two activities for handoff right now: Activity A and Activity B.

My view controller hierarchy is as follows:


Root (UISplitViewController)

  • 1. primary (UINavigationController)

    "index" UITableViewController

    • "subindex" UITableViewController
      • "details" UITableViewController (see below)
  • 2. secondary (UINavigationController)

    "details" UITableViewController

    • "complete details" UIViewController


Here is my continueUserActivity function:

    func application(application: UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: (([AnyObject]!) -> Void)) -> Bool {
        let storyboard = UIStoryboard(name: "MainStoryboard", bundle: nil)
        let viewController = storyboard.instantiateInitialViewController() as! UISplitViewController
        if let rootController = viewController.viewControllers.first?.topViewController {
            rootController.restoreUserActivityState(userActivity)
            // also tried restorationHandler([rootController]) with same outcome
        }
        self.window!.rootViewController = viewController
        return true
    }


Then, in my rootController ("index" UITableViewController in the bulleted list above) I do the following:


    override func restoreUserActivityState(activity: NSUserActivity) {
        performSegueWithIdentifier("SomeExistingSegue", sender: activity)
        super.restoreUserActivityState(activity)
    }

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
        switch segue.identifier! {
        case "SomeExistingSegue":
            let subindexViewController = segue.destinationViewController as! SubindexViewController
            var subindexGroup: SubindexGroup?
            if sender is NSUserActivity {
                // retrieve data from CoreData
                // subindexGroup = ...
            } else {
                subindexGroup = _fetched!.objectAtIndexPath(tableView.indexPathForSelectedRow()!) as? SubindexGroup
            }
            subindexViewController.subindexGroup = subindexGroup
            if sender is NSUserActivity {
                subindexViewController.restoreUserActivityState(sender as! NSUserActivity)
            }
       // ...
        default:
            break
        }
    }


The idea behind this was to go through the same segue sequence as a user, therefore rebuilding the hierarchy properly.


I am getting weird results, however, with the controllers not consistently being added to the stack. I believe I'm on the right track but I have a feeling I'm not doing everything in the proper sequence.


Any suggestions?


Thanks!

Answered by bbousquet in 19522022

Well it looks like I wasn't too far off. Wrapping the performSegueWithIdentifier calls in dyspatch_async on the main thread seemingly resolved the issue.

Accepted Answer

Well it looks like I wasn't too far off. Wrapping the performSegueWithIdentifier calls in dyspatch_async on the main thread seemingly resolved the issue.

So continueUserActivity() you force a certain ViewController to instantiate and use that to create a user flow?


The segue I'm trying to perfrom in there can be reached from multple places so I was wondering if you just force it from one place and that it. what if the app's last state was somewhere else? does that matter?

Also you know how you did subindexViewController.subindexGroup = subindexGroup

What if what I'm trying to pass to my subViewController is let uniqueIdentifier = userActivity.userInfo?[CSSearchableItemActivityIdentifier] as? String

where userActivity is of type NSUserActivity

Handoff and restoring view controller hierarchy
 
 
Q