Swift — Require classes implementing protocol to be subclasses of a certain class

前端 未结 8 1977
臣服心动
臣服心动 2021-01-01 08:58

I\'m creating several NSView classes, all of which support a special operation, which we\'ll call transmogrify. At first glance, this seems like t

相关标签:
8条回答
  • 2021-01-01 09:20

    For Swift 4, based on @Antoine's keen insight:

    Create a protocol then use a typealias to give a cleaner name to a type that conforms to both a class and the protocol.

    protocol Transmogrifiable {
        func transmogrify()
    }
    typealias TransmogrifiableView = NSView & Transmogrifiable
    

    You can then define a class that inherits from that type....

    class ATransmogView: TransmogrifiableView {
        func transmogrify() {
            print("I'm transmogging")
        }
    }
    

    ....or define a class that inherits from the protocol and a subclass

    // this also qualifies as a TransmogrifiableView
    
    class BTransmogView: NSTextView, Transmogrifiable {
        func transmogrify() {
            print("I'm transmogging too")
        }
    }
    

    Now you can do this.

    func getTransmogrifiableView() -> TransmogrifiableView {
        return someBool ? ATransmogView() : BTransmogView()
    }
    

    And this now compiles.

    let myView: TransmogrifiableView = getTransmogrifiableView()
    let theSuperView = myView.superView
    
    0 讨论(0)
  • 2021-01-01 09:20

    Still not the ideal solution, but here's a pattern I use on occasion:

    1. Define a protocol with the methods that you want to enforce.
    2. Define your base class, implementing whatever you want the children to get for free.
    3. In that base class (from #2), have an optional "delegate" variable of the protocol you made in #1.
    4. Define all children classes so that they inherit the base class and implement the protocol.

    This let's your base class call the protocol methods while forcing the children to implement them (eg. self.myDelegate?.myProtocolMethod).

    0 讨论(0)
  • 2021-01-01 09:21

    As per definition a protocol just declares requirements of "methods, properties an other requirements". And by "other requirements" it means a superclass is not a part of it.

    A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality.

    Right now, I don't see a clean solution. It's possible to use a where-clause to define a type which is a NSView and conforms to the TransmogrifiableView like this:

    class MyClass<T where T: NSView, T: TransmogrifiableView> {
        var aTransmogrifiableNSView: T
    }
    

    Or you could use another superclass:

    protocol TransmogrifiableViewProtocol {
        func transmogrify()
    }
    
    class TransmogrifiableView: NSView, TransmogrifiableViewProtocol {
        func transmogrify() {
            assert(false, "transmogrify() must be overwritten!")
        }
    }
    
    class AnImplementedTransmogrifiableView: TransmogrifiableView {
        func transmogrify() {
            println("Do the transmogrification...")
        }
    }
    

    In the end both solutions aren't clean and wouldn't satisfy myself. Maybe an abstract-keyword will be added to Swift someday?

    0 讨论(0)
  • 2021-01-01 09:27

    You could use something like this:

    protocol TransmogrifiableView where Self:NSView {}
    

    This requires all created instances which one conforms to TransmogrifiableView protocol to be subclassed with NSView

    0 讨论(0)
  • 2021-01-01 09:31

    Starting from Swift 4 you can now define this as followed:

    let myView: NSView & TransmogrifiableView
    

    For more information, checkout issue #156 Subclass Existentials

    0 讨论(0)
  • 2021-01-01 09:33

    I think you are after a subclass of NSView. Try this:

    protocol TransmogrifiableView {
        func transmogrify()
    }
    
    class MyNSView: NSView, TransmogrifiableView {
        // do stuff.
    }
    

    And later in the code accept objects of type MyNSView.

    Edit

    You maybe want an Extension, see this

    extension NSView: TransmogrifiableView {
        // implementation of protocol requirements goes here
    }
    
    • Note that you will not be able to get an NSView without this extra method.
    • You can separately extend subclasses of NSView to override this new method.

    Yet another option is to make a class which holds a pointer to an NSView, and implements additional methods. This will also force you to proxy all methods from NSView that you want to use.

    class NSViewWrapper: TransmogrifiableView {
        var view : NSView!
        // init with the view required.
        //  implementation of protocol requirements goes here.
        .....
       // proxy all methods from NSView.
       func getSuperView(){
           return self.view.superView
       }
    }
    

    This is quite long and not nice, but will work. I would recommend you to use this only if you really cannot work with extensions (because you need NSViews without the extra method).

    0 讨论(0)
提交回复
热议问题