Swift -- 要求 classes 实现协议是某个 class 的子classes
Swift -- Require classes implementing protocol to be subclasses of a certain class
我正在创建几个 NSView
类,所有这些类都支持一个特殊的操作,我们称之为 transmogrify
。乍一看,这似乎是协议的完美位置:
protocol TransmogrifiableView {
func transmogrify()
}
但是,此协议不会强制每个 TransmogrifiableView
也是 NSView
。这意味着我在 TransmogrifiableView
上调用的任何 NSView
方法都不会类型检查:
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
”转换,这是一种糟糕的形式并且会分散注意力。
我认为您是在 NSView
的子 class 之后。试试这个:
protocol TransmogrifiableView {
func transmogrify()
}
class MyNSView: NSView, TransmogrifiableView {
// do stuff.
}
稍后在代码中接受类型为 MyNSView
的对象。
编辑
您可能想要 Extension
,请参阅 this
extension NSView: TransmogrifiableView {
// implementation of protocol requirements goes here
}
- 请注意,如果没有这个额外的方法,您将无法获得 NSView。
- 您可以单独扩展 NSView 的子classes 来覆盖这个新方法。
另一种选择是制作一个 class ,它包含一个指向 NSView 的指针,并实现其他方法。这也将强制您代理 all 您想要使用的 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
}
}
这篇文章很长而且不太好,但是可以用。我建议你只有在你真的不能使用扩展时才使用它(因为你需要 NSViews 而没有额外的方法)。
根据定义,协议仅声明 "methods, properties an other requirements" 的要求。 "other requirements" 表示超类不是它的一部分。
A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality.
目前,我没有看到一个干净的解决方案。可以使用 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?
仍然不是理想的解决方案,但这是我偶尔使用的模式:
- 使用您要强制执行的方法定义协议。
- 定义您的基础 class,实施您希望 children 免费获得的任何内容。
- 在该基础 class(来自 #2)中,有一个可选的 "delegate" 您在 #1 中创建的协议变量。
- 定义所有 children classes 以便它们继承基础 class 并实现协议。
这让您的基础 class 调用协议方法,同时强制 children 实现它们(例如 self.myDelegate?.myProtocolMethod)。
更新。在最新的Swift版本中你可以写
protocol TransmogrifiableView: NSView {
func transmogrify()
}
,这将强制符合者类型为 NSView
或其子类。这意味着编译器将“看到”NSView
.
的所有成员
原回答
通过使用关联类型强制执行子类有一个解决方法:
protocol TransmogrifiableView {
associatedtype View: NSView = Self
func transmogrify()
}
class MyView: NSView, TransmogrifiableView { ... } // compiles
class MyOtherClass: TransmogrifiableView { ... } // doesn't compile
从 Swift 4 开始,您现在可以定义如下:
let myView: NSView & TransmogrifiableView
更多信息,结帐问题#156 Subclass Existentials
你可以使用这样的东西:
protocol TransmogrifiableView where Self:NSView {}
这要求所有创建的符合 TransmogrifiableView 协议的实例都被 NSView 子类化
对于Swift 4,基于@Antoine 敏锐的洞察力:
创建协议,然后使用类型别名为同时符合 class 和协议的类型提供更清晰的名称。
protocol Transmogrifiable {
func transmogrify()
}
typealias TransmogrifiableView = NSView & Transmogrifiable
然后您可以定义从该类型继承的 class....
class ATransmogView: TransmogrifiableView {
func transmogrify() {
print("I'm transmogging")
}
}
.....或者定义一个继承自协议的class和一个subclass
// 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
在此处检查此解决方案... Swift - class 方法必须被 subclass 覆盖
此解决方案允许从 class 继承并进行协议的编译时检查。 :)
我正在创建几个 NSView
类,所有这些类都支持一个特殊的操作,我们称之为 transmogrify
。乍一看,这似乎是协议的完美位置:
protocol TransmogrifiableView {
func transmogrify()
}
但是,此协议不会强制每个 TransmogrifiableView
也是 NSView
。这意味着我在 TransmogrifiableView
上调用的任何 NSView
方法都不会类型检查:
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
”转换,这是一种糟糕的形式并且会分散注意力。
我认为您是在 NSView
的子 class 之后。试试这个:
protocol TransmogrifiableView {
func transmogrify()
}
class MyNSView: NSView, TransmogrifiableView {
// do stuff.
}
稍后在代码中接受类型为 MyNSView
的对象。
编辑
您可能想要 Extension
,请参阅 this
extension NSView: TransmogrifiableView {
// implementation of protocol requirements goes here
}
- 请注意,如果没有这个额外的方法,您将无法获得 NSView。
- 您可以单独扩展 NSView 的子classes 来覆盖这个新方法。
另一种选择是制作一个 class ,它包含一个指向 NSView 的指针,并实现其他方法。这也将强制您代理 all 您想要使用的 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
}
}
这篇文章很长而且不太好,但是可以用。我建议你只有在你真的不能使用扩展时才使用它(因为你需要 NSViews 而没有额外的方法)。
根据定义,协议仅声明 "methods, properties an other requirements" 的要求。 "other requirements" 表示超类不是它的一部分。
A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality.
目前,我没有看到一个干净的解决方案。可以使用 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?
仍然不是理想的解决方案,但这是我偶尔使用的模式:
- 使用您要强制执行的方法定义协议。
- 定义您的基础 class,实施您希望 children 免费获得的任何内容。
- 在该基础 class(来自 #2)中,有一个可选的 "delegate" 您在 #1 中创建的协议变量。
- 定义所有 children classes 以便它们继承基础 class 并实现协议。
这让您的基础 class 调用协议方法,同时强制 children 实现它们(例如 self.myDelegate?.myProtocolMethod)。
更新。在最新的Swift版本中你可以写
protocol TransmogrifiableView: NSView {
func transmogrify()
}
,这将强制符合者类型为 NSView
或其子类。这意味着编译器将“看到”NSView
.
原回答
通过使用关联类型强制执行子类有一个解决方法:
protocol TransmogrifiableView {
associatedtype View: NSView = Self
func transmogrify()
}
class MyView: NSView, TransmogrifiableView { ... } // compiles
class MyOtherClass: TransmogrifiableView { ... } // doesn't compile
从 Swift 4 开始,您现在可以定义如下:
let myView: NSView & TransmogrifiableView
更多信息,结帐问题#156 Subclass Existentials
你可以使用这样的东西:
protocol TransmogrifiableView where Self:NSView {}
这要求所有创建的符合 TransmogrifiableView 协议的实例都被 NSView 子类化
对于Swift 4,基于@Antoine 敏锐的洞察力:
创建协议,然后使用类型别名为同时符合 class 和协议的类型提供更清晰的名称。
protocol Transmogrifiable {
func transmogrify()
}
typealias TransmogrifiableView = NSView & Transmogrifiable
然后您可以定义从该类型继承的 class....
class ATransmogView: TransmogrifiableView {
func transmogrify() {
print("I'm transmogging")
}
}
.....或者定义一个继承自协议的class和一个subclass
// 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
在此处检查此解决方案... Swift - class 方法必须被 subclass 覆盖
此解决方案允许从 class 继承并进行协议的编译时检查。 :)