【问题标题】:Swift 'open' keyword & overridable method/properties in extension?Swift'open'关键字和扩展中的可覆盖方法/属性?
【发布时间】:2016-08-25 09:50:44
【问题描述】:

在 Swift 3.0 (What is the 'open' keyword in Swift?) 中引入了 open 关键字。

注意:仅限于 NSObject 派生类或 @objc 属性化方法/属性的扩展。

在扩展模块/框架中声明和使用public (class) 方法/属性的代码损坏了,因为public 在定义模块之外不再意味着“可覆盖”。

例子:

public extension UIManagedDocument {

    public class func primaryDocumentName() -> String {
        return "Document"
    }

    public class func primaryStoreURL() -> URL {
        let documentsURL = FileManager.default.userDocumentsURL
        return URL(fileURLWithPath: self.primaryDocumentName(), isDirectory: false, relativeTo: documentsURL)
    }

    public class func primaryModelName() -> String? {
        return "Model"
    }

}
  • 原始提案 (SE-0117) 专注于子类化,没有提及扩展。
  • 目前扩展不支持open关键字(你不能写open extension NSObjectopen func Method()

问题:是否有解决方法可以覆盖模块/框架的扩展提供的方法/属性?

【问题讨论】:

  • 这真的与新的开放与公共访问模式有关吗?除非我弄错了,否则无论如何你都不能覆盖在扩展中声明的方法,无论是在 Swift 2 还是在 Swift 3 中)。
  • 您对 pure swift 类是正确的,但可以在 NSObject 派生类以及 @objc 属性方法/属性上使用。 (Can you override between extensions in Swift or not?)
  • 我明白了,谢谢。 (也许您可以将该信息添加到问题中)。
  • 感谢您提醒我自己的答案 :)

标签: ios swift syntax swift-extensions


【解决方案1】:

除非我弄错了,否则您可以将扩展方法声明为 open 在你的框架中,如果你只是省略 public 关键字 在扩展声明中:

extension UIManagedDocument {

    open class func primaryDocumentName() -> String {
        return "Document"
    }
    // ...
}

然后(对于NSObject 子类或@objc 成员)您可以覆盖该方法 在主应用程序(或任何模块)中的自定义子类中:

class MyManagedDocument: UIManagedDocument {

    override class func primaryDocumentName() -> String {
        return "MyDocument"
    }
    // ...
}

【讨论】:

  • 我不能省略public这个词,因为扩展是在另一个模块(共享框架)中声明的,而具体的子类是在依赖目标(应用程序/扩展)中实现的。
  • @Nocross:实际上我只是测试了它,它对我有用。 extension UIManagedDocument {} 在框架中,class MyManagedDocument: UIManagedDocument {} 在主应用程序中。
  • 你说得对,它有效。但困扰我的是,这种方式我们依赖于快速的“推理”逻辑,这至少是不稳定的,并且可能是针对不同 IDE 的特定实现
  • @Nocross:我认为这与 IDE 无关。请注意,您还删除了解决方案中的 public 关键字。
  • 细微差别有点不同。我省略了它,因为协议一致性扩展也符合协议的访问修饰符。
【解决方案2】:
  • '面向协议' - 使用所需的方法/属性声明 protocol,然后重构您的扩展以符合 protocol
  • 'Traditional' - 使用所需的方法/属性实现中间(抽象)子类。

协议示例:

protocol PrimaryDocument {
    static func primaryDocumentName() -> String

    static func primaryStoreURL() -> URL

    static func primaryModelName() -> String?
}

extension UIManagedDocument : PrimaryDocument {

    open class func primaryDocumentName() -> String {
        return "Document"
    }

    open class func primaryStoreURL() -> URL {
        let documentsURL = FileManager.default.userDocumentsURL
        return URL(fileURLWithPath: self.primaryDocumentName(), isDirectory: false, relativeTo: documentsURL)
    }

    open class func primaryModelName() -> String? {
        return "Model"
    }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-03
    • 1970-01-01
    • 2016-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多