Swift - 要求实现协议的类是某个类的子类

exi*_*all 37 inheritance protocols interface typechecking swift

我正在创建几个NSView类,所有类都支持特殊操作,我们将调用它们transmogrify.乍一看,这似乎是协议的完美之处:

protocol TransmogrifiableView {
    func transmogrify()
}
Run Code Online (Sandbox Code Playgroud)

然而,该协议并没有执行,每一个TransmogrifiableView是一个NSView为好.这意味着NSView我在a上调用的任何方法TransmogrifiableView都不会键入check:

let myView: TransmogrifiableView = getTransmogrifiableView()
let theSuperView = myView.superView // error: TransmogrifiableView does not have a property called 'superview'
Run Code Online (Sandbox Code Playgroud)

我不知道如何要求实现我的协议的所有类也是子类NSView.我试过这个:

protocol TransmogrifiableView: NSView {
    func transmogrify()
}
Run Code Online (Sandbox Code Playgroud)

但是Swift抱怨协议不能从类继承.将协议转换为仅使用类的协议没有帮助

protocol TransmogrifiableView: class, NSView {
    func transmogrify()
}
Run Code Online (Sandbox Code Playgroud)

我不能创建TransmogrifiableView超类而不是协议,因为我的一些TransmogrifiableView类必须是其他非transmogrifiable视图的子类.

我应该如何要求所有TransmogrifiableView的也可以NSView的?我真的不想用as"转换"来改变我的代码,这种转换形式不好而且分散注意力.

Cri*_*tik 17

通过使用关联类型来强制执行子类,有一种解决方法:

protocol TransmogrifiableView {
    associatedtype View: NSView = Self
    func transmogrify()
}

class MyView: NSView, TransmogrifiableView { ... } // compiles
class MyOtherClass: TransmogrifiableView { ... } // doesn't compile
Run Code Online (Sandbox Code Playgroud)


Ant*_*ine 17

从Swift 4开始,您现在可以将其定义如下:

let myView: NSView & TransmogrifiableView
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请查看问题#156 Subclass Existentials


Gra*_*lix 10

你可以使用这样的东西:

protocol TransmogrifiableView where Self:NSView {}
Run Code Online (Sandbox Code Playgroud)

这要求所有创建的实例符合TransmogrifiableView协议,并使用NSView进行子类化


Ram*_*hil 5

我认为您是的子类NSView。尝试这个:

protocol TransmogrifiableView {
    func transmogrify()
}

class MyNSView: NSView, TransmogrifiableView {
    // do stuff.
}
Run Code Online (Sandbox Code Playgroud)

然后在代码中接受type的对象MyNSView

编辑

您可能想要一个Extension,看到这个

extension NSView: TransmogrifiableView {
    // implementation of protocol requirements goes here
}
Run Code Online (Sandbox Code Playgroud)
  • 请注意,如果没有这种额外的方法,您将无法获得NSView。
  • 您可以单独扩展NSView的子类以覆盖此新方法。

另一个选择是创建一个类,该类持有指向NSView的指针,并实现其他方法。这也将迫使您代理要使用的NSView中的所有方法。

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
   }
}
Run Code Online (Sandbox Code Playgroud)

这很长而且不好,但是可以使用。我建议您仅在您确实无法使用扩展功能时才使用它(因为您需要使用NSViews而不需要额外的方法)。