Ios 从显示的视图控制器访问extensionContext

Ios 从显示的视图控制器访问extensionContext,ios,ios8,ios-app-extension,Ios,Ios8,Ios App Extension,我已尝试为共享扩展创建自定义视图控制器 当我在main interface.storyboard上设置的初始视图控制器上显示另一个视图控制器时,会出现令人困惑的情况。此视图控制器嵌入在导航控制器中(它是导航控制器的根视图控制器) 我检查了presentingViewController (lldb) po [self presentingViewController] <_UIViewServiceViewControllerOperator: 0x7a978000> (lldb

我已尝试为共享扩展创建自定义视图控制器

当我在
main interface.storyboard
上设置的初始视图控制器上显示另一个视图控制器时,会出现令人困惑的情况。此视图控制器嵌入在导航控制器中(它是导航控制器的根视图控制器)

我检查了presentingViewController

(lldb) po [self presentingViewController]

<_UIViewServiceViewControllerOperator: 0x7a978000>

(lldb) po [[self presentingViewController] extensionContext]

nil
(lldb)po[自存可视控制器]
(lldb)po[[self-presentingViewController]扩展上下文]
无
因此,此时扩展上下文为零。我可以通过将
扩展上下文
从presentingViewController传递到presentedViewController来访问它


但是,我发现这种行为有点奇怪。应用程序扩展是否设计为只能从视图控制器层次结构的一个级别访问?

视图控制器显示的视图控制器在使用父级扩展时应该没有问题。查看文档:

视图控制器可以检查此属性,查看它是否参与扩展请求。如果未为当前视图控制器设置扩展上下文,则系统将向上遍历视图控制器层次结构,以查找具有非nil extensionContext值的父视图控制器。

因此,如果您可以确定根视图控制器确实有一个
extensionContext
,则此视图控制器提供的任何视图控制器都应该可以访问它,只需通过它自己的
extensionContext
属性即可


注意:如果这不是您正在观察的行为,这可能是SDK的一个错误,我建议您提交一个雷达。

如果您要在扩展情节提要中使用多个视图控制器,您必须将对原始视图控制器的
extensionContext
的引用传递给最终负责完成扩展请求的视图控制器。在初始视图控制器中:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    let destination = segue.destinationViewController as! FinalViewController
    destination.originalExtensionContext = self.extensionContext
}
@IBAction func dismissController(sender: UIButton!) {
    dismissViewControllerAnimated(true) { () -> Void in
        self.originalExtensionContext.completeRequestReturningItems(self.originalExtensionContext.inputItems, completionHandler: nil)
}
let context = NSExtensionContext.shared
在最终视图控制器中:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    let destination = segue.destinationViewController as! FinalViewController
    destination.originalExtensionContext = self.extensionContext
}
@IBAction func dismissController(sender: UIButton!) {
    dismissViewControllerAnimated(true) { () -> Void in
        self.originalExtensionContext.completeRequestReturningItems(self.originalExtensionContext.inputItems, completionHandler: nil)
}
let context = NSExtensionContext.shared

请注意,您必须为原始扩展上下文创建一个唯一命名的属性,因为
extensionContext
已经作为属性名称存在于超类
UIViewController
上。您不能将现有的
extensionContext
传递给UIViewController的属性
extensionContext
,因为它是一个只读属性。

虽然它不是干净代码和体系结构的最佳方法,但它非常方便:

在存在
extensionContext
的根扩展控制器中:

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

extension NSExtensionContext {
    fileprivate(set) static var shared: NSExtensionContext!
}
在任何其他视图控制器中:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    let destination = segue.destinationViewController as! FinalViewController
    destination.originalExtensionContext = self.extensionContext
}
@IBAction func dismissController(sender: UIButton!) {
    dismissViewControllerAnimated(true) { () -> Void in
        self.originalExtensionContext.completeRequestReturningItems(self.originalExtensionContext.inputItems, completionHandler: nil)
}
let context = NSExtensionContext.shared

如果视图控制器有一个具有extensionContext的父控制器,则该控制器的行为正确,但当它是一个presentedViewController时,它的行为不同,它不包括在父子关系中。@JesserMand是正确的。任何以模式呈现的视图都不会包含它呈现的视图控制器extensionContext。是的,我认为这是传递扩展上下文最明显的方式。我在询问SDK中extensionContext属性的行为。据我所知(我已经多次使用此模式),如果您传递对
extensionContext
的引用,则没有异常行为。您只需要确保最后一件事是调用
completeRequestReturningItems:
,因为这将取消分配扩展上下文,之后在扩展中调用的任何内容都不会起任何作用。