Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift 'open' keyword & overridable method/properties in extension?

With introduction of open keyword in Swift 3.0 (What is the 'open' keyword in Swift?).

Note: Limited to extensions on NSObject derived classes or @objc attributed method/properties.

Code which declared and used public (class) methods/properties in extension across modules/frameworks broke, as public is no longer means 'overridable' outside of defining module.

Example:

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"
    }

}
  • Original proposal (SE-0117) is focused on subclassing and doesn't mention extensions.
  • Currently extensions do not support open keyword (you can't write open extension NSObject as well as open func Method())

Question: Is there workaround to be able override extension provided methods/properties across modules/frameworks?

like image 644
Nocross Avatar asked Aug 25 '16 09:08

Nocross


People also ask

What is open keyword in Swift?

Open is an access level, was introduced to impose limitations on class inheritance on Swift. This means that the open access level can only be applied to classes and class members.

What is the difference between open and public keyword in Swift?

Open — This is where you can access all data members and member functions within the same module(target) and outside of it. You can subclass or override outside the module(target). Public — This is the same as open, the only difference is you can't subclass or override outside the module(target).

What is the difference between open and public and Fileprivate and private?

Open - same as public, only difference is you can subclass or override outside the module. Fileprivate - As the name say's, data members and member functions are accessible within the same file. Private - This is where you can have access within the scope of function body or class.


2 Answers

Unless I am mistaken, you can declare the extension methods as open in your framework if you just omit the public keyword in the extension declaration:

extension UIManagedDocument {

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

And then (for NSObject subclasses or @objc members) you can override the method in your custom subclass in the main application (or in any module):

class MyManagedDocument: UIManagedDocument {

    override class func primaryDocumentName() -> String {
        return "MyDocument"
    }
    // ...
}
like image 182
Martin R Avatar answered Sep 29 '22 14:09

Martin R


  • 'Protocol-oriented' - declare protocol with desired methods/properties then refactor your extension for protocol compliance.
  • 'Traditional' - implement intermediate (abstract) subclass with desired methods/properties.

Protocol example:

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"
    }

}
like image 45
Nocross Avatar answered Sep 29 '22 14:09

Nocross