我正在创建几个NSView
类,所有这些类都支持特殊操作,我们称之为transmogrify
。乍一看,这似乎是协议的理想之地:
protocol TransmogrifiableView {
func transmogrify()
}
但是,此协议不强制执行每个TransmogrifiableView
也是NSView
。这意味着我在NSView
上调用的任何TransmogrifiableView
方法都不会输入check:
let myView: TransmogrifiableView = getTransmogrifiableView()
let theSuperView = myView.superView // error: TransmogrifiableView does not have a property called 'superview'
我不知道如何要求实现我的协议的所有类也是NSView
的子类。我试过这个:
protocol TransmogrifiableView: NSView {
func transmogrify()
}
但Swift抱怨协议不能从类继承。使用
将协议转换为仅类协议没有帮助protocol TransmogrifiableView: class, NSView {
func transmogrify()
}
我不能使TransmogrifiableView
成为超类而不是协议,因为我的一些TransmogrifiableView
类必须是其他非可变形视图的子类。
我应该如何要求所有TransmogrifiableView
也是NSView
?我真的不想用“as
”转换来加密我的代码,这些转换形式不好而且分散注意力。
答案 0 :(得分:17)
通过使用关联类型来强制执行子类,有一种解决方法:
protocol TransmogrifiableView {
associatedtype View: NSView = Self
func transmogrify()
}
class MyView: NSView, TransmogrifiableView { ... } // compiles
class MyOtherClass: TransmogrifiableView { ... } // doesn't compile
答案 1 :(得分:17)
从Swift 4开始,您现在可以将其定义如下:
let myView: NSView & TransmogrifiableView
有关详情,请查看问题#156 Subclass Existentials
答案 2 :(得分:9)
您可以使用以下内容:
protocol TransmogrifiableView where Self:NSView {}
这要求所有创建的实例符合TransmogrifiableView协议,并使用NSView进行子类化
答案 3 :(得分:5)
我认为你是在NSView
的子类之后。试试这个:
protocol TransmogrifiableView {
func transmogrify()
}
class MyNSView: NSView, TransmogrifiableView {
// do stuff.
}
稍后在代码中接受MyNSView
类型的对象。
您可能需要Extension
,请参阅this
extension NSView: TransmogrifiableView {
// implementation of protocol requirements goes here
}
另一个选择是创建一个包含指向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
}
}
这很长很不好,但会奏效。我建议你只在你真的无法使用扩展时使用它(因为你需要NSView而不需要额外的方法)。
答案 4 :(得分:3)
根据定义,协议只声明"方法的属性,属性其他要求"。并且通过"其他要求"这意味着超类不属于它。
协议定义了适合特定任务或功能的方法,属性和其他要求的蓝图。
现在,我没有看到一个干净的解决方案。可以使用where
- 子句来定义NSView
的类型并符合TransmogrifiableView
这样的类型:
class MyClass<T where T: NSView, T: TransmogrifiableView> {
var aTransmogrifiableNSView: T
}
或者你可以使用另一个超类:
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...")
}
}
最后,这两种解决方案都不干净,不能让自己满意。也许有一天abstract
- 关键字会被添加到Swift中?
答案 5 :(得分:3)
对于Swift 4,基于@Antoine敏锐的洞察力:
创建协议,然后使用typealias为符合类和协议的类型提供更清晰的名称。
protocol Transmogrifiable {
func transmogrify()
}
typealias TransmogrifiableView = NSView & Transmogrifiable
然后,您可以定义一个继承自该类型的类....
class ATransmogView: TransmogrifiableView {
func transmogrify() {
print("I'm transmogging")
}
}
....或者定义一个继承自协议和子类的类
// this also qualifies as a TransmogrifiableView
class BTransmogView: NSTextView, Transmogrifiable {
func transmogrify() {
print("I'm transmogging too")
}
}
现在你可以做到这一点。
func getTransmogrifiableView() -> TransmogrifiableView {
return someBool ? ATransmogView() : BTransmogView()
}
这现在编译。
let myView: TransmogrifiableView = getTransmogrifiableView()
let theSuperView = myView.superView
答案 6 :(得分:0)
仍然不是理想的解决方案,但这是我偶尔使用的模式:
这让你的基类调用协议方法,同时强制孩子们实现它们(例如,self.myDelegate?.myProtocolMethod)。
答案 7 :(得分:0)
在此处检查此解决方案... Swift - class method which must be overridden by subclass
此解决方案允许从类继承,也可以进行协议的编译时检查。 :)