Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accessing extensionContext from a presented view controller

I've tried creating a custom view controller for a share extension.

A confusing situation happens when I present another view controller on top of the initial view controller that was set on the MainInterface.storyboard. This presented view controller is embedded in a navigation controller (it's the root view controller of it).

I did a check on the presentingViewController

(lldb) po [self presentingViewController]

<_UIViewServiceViewControllerOperator: 0x7a978000>

(lldb) po [[self presentingViewController] extensionContext]

nil

So, the extension context is nil at this point. I could access the extensionContext by passing it around from the presentingViewController to the presentedViewController.

But, I found this behavior is a bit strange. Is the app extension designed to only be accessed from one level of view controller hierarchy?

like image 712
Jesse Armand Avatar asked Aug 28 '14 09:08

Jesse Armand


3 Answers

If you're going to use more than a single view controller in your extension storyboard, you'll have to pass a reference to the extensionContext of the original view controller to the view controller that will ultimately be responsible for completing the extension's request. In the initial view controller:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    let destination = segue.destinationViewController as! FinalViewController
    destination.originalExtensionContext = self.extensionContext
}

And in your final view controller:

@IBAction func dismissController(sender: UIButton!) {
    dismissViewControllerAnimated(true) { () -> Void in
        self.originalExtensionContext.completeRequestReturningItems(self.originalExtensionContext.inputItems, completionHandler: nil)
}

Note that you have to create a uniquely named property for the original extension context, since extensionContext already exists as a property name on the superclass UIViewController. You can't pass the existing extensionContext to the UIViewController's property extensionContext as it is a read-only attribute.

like image 77
Michael Frain Avatar answered Oct 13 '22 22:10

Michael Frain


The view controller being presented by a view controller should have no problem using the parent's extension. Taking a look at the documentation:

The view controller can check this property to see if it participates in an extension request. If no extension context is set for the current view controller, the system walks up the view controller hierarchy to find a parent view controller that has a non nil extensionContext value.

Therefore, if you can be certain of the fact that your root view controller does indeed have an extensionContext, any view controller presented by this view controller should have access to it, simply through it's own extensionContext property.

Note: If this is not the behaviour you a re observing, this may be a bug with the SDK, and I would recommend filing a radar.

like image 1
Infinity James Avatar answered Oct 13 '22 21:10

Infinity James


While it's not the best approach for clean code and architecture, it's quite handy:

In root extension controller where extensionContext exists:

final class ShareRootViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        NSExtensionContext.shared = self.extensionContext
    }
}

extension NSExtensionContext {
    fileprivate(set) static var shared: NSExtensionContext!
}

In any other view controller:

let context = NSExtensionContext.shared
like image 1
Alexander Kulabukhov Avatar answered Oct 13 '22 21:10

Alexander Kulabukhov