いくつかのNSView
クラスを作成していますが、それらはすべてtransmogrify
と呼ばれる特別な操作をサポートしています。一見、これはプロトコルに最適な場所のようです。
protocol TransmogrifiableView {
func transmogrify()
}
ただし、このプロトコルはnotではなく、すべてのTransmogrifiableView
がNSView
であることを強制します。これは、NSView
で呼び出すTransmogrifiableView
メソッドはタイプチェックを行わないことを意味します。
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
のサブクラスの後にいると思います。これを試して:
protocol TransmogrifiableView {
func transmogrify()
}
class MyNSView: NSView, TransmogrifiableView {
// do stuff.
}
そして後のコードでは、MyNSView
型のオブジェクトを受け入れます。
おそらくExtension
が必要です。 this を参照してください
extension NSView: TransmogrifiableView {
// implementation of protocol requirements goes here
}
さらに別のオプションは、NSViewへのポインターを保持し、追加のメソッドを実装するクラスを作成することです。また、これにより、使用するNSViewのメソッドをプロキシallメソッドに強制します。
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が必要なため)。
Swift 4から開始すると、次のように定義できます。
let myView: NSView & TransmogrifiableView
詳細については、チェックアウトの問題 #156 Subclass Existentials
関連付けられた型を使用してサブクラスを強制することにより、回避策があります。
protocol TransmogrifiableView {
associatedtype View: NSView = Self
func transmogrify()
}
class MyView: NSView, TransmogrifiableView { ... } // compiles
class MyOtherClass: TransmogrifiableView { ... } // doesn't compile
次のようなものを使用できます。
protocol TransmogrifiableView where Self:NSView {}
これには、TransmogrifiableViewプロトコルに準拠するすべての作成済みインスタンスをNSViewでサブクラス化する必要があります
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
定義により、プロトコルは「メソッド、プロパティ、およびその他の要件」の要件を宣言するだけです。 「その他の要件」とは、スーパークラスがその一部ではないことを意味します。
プロトコルは、特定のタスクまたは機能に適したメソッド、プロパティ、およびその他の要件の青写真を定義します。
今のところ、きれいな解決策は見当たりません。 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
- keywordがSwiftいつか?
ここでこの解決策を確認してください... Swift-サブクラスでオーバーライドする必要があるクラスメソッド
このソリューションにより、クラスを継承し、プロトコルのコンパイル時チェックを行うことができます。 :)
それでも理想的な解決策ではありませんが、私が時々使用するパターンは次のとおりです。
これにより、ベースクラスがプロトコルメソッドを呼び出して、子に強制的に実装させます(例:self.myDelegate?.myProtocolMethod)。