Edited at

delegateをweakで宣言する際にprotocolにclassを継承する理由

Swiftでコードを書く際、任意のクラスをdelegateとしてweakにしたい場合は、classプロトコルを採用するコードを書かなければ ‘weak’ cannot be applied to non-class type というコンパイルエラーとなる。

(言い換えると、classプロトコルに準拠したクラスはweakにできるようになりdelegateとして扱える)

例がこれ

protocol SomeProtocolOne {

func run() -> Void
}

protocol SomeProtocolTwo : class {
func run() -> Void
}

class SomeView {
weak var delegate: SomeProtocolOne? // これはコンパイルエラー ‘weak’ cannot be applied to non-class type
weak var delegate: SomeProtocolTwo? // これは大丈夫
}

この理由は何か、「そういうものと覚えておけばいい」と思っていたんだけど納得できる理由のためにおさらいしてみる。


おさらい

まず、キーワード : class は見た目通り class プロトコルを採用することを宣言している。classプロトコルを採用していると言ってもいい。

また、プロトコルの採用をクラス限定に出来ることも意味していて、"class-only protocol"と名付けられている。つまり StructEnum でこのプロトコル(SomeProtocolTwo)を採用することは出来なくなるということ。


考察

そもそもプロトコル、構造体、列挙体はweakにできないことを思い出してほしい。

クラスおよびクラスを継承したものだけはweakに出来るという前提がある。

今回の"class-only protocol"を使うことで、weakとして宣言できるようになる理由として、class プロトコルを採用するプロトコルも同じ用にweakに出来るようになっているためではないかと思う。


備考

Swiftではクラスもプロトコルも同じように継承することを宣言するが、これは他の言語で"継承"と"プロトコルの採用"を分けて考えている前提で見ると混乱する。

せめて"class-only protocol"がもっと長い記述なら説明的でいいのに、と思ったらSwift Beta4以前は長いアトリビュートが必要だったのが、Beta5から簡潔になったらしい。

// Beta5以降

protocol ProtocolNameDelegate : class {
}
// Beta4以前
@class_protocol protocol ProtocolNameDelegate {
}


しかし現在はclassを指定するのではなくAnyObjectを指定することが推奨されている

protocol ProtocolNameDelegate: AnyObject {

}

理由は下記

https://qiita.com/lovee/items/a686e11f00b31323e683#20181106-%E8%BF%BD%E8%A8%98


参考URL

http://stackoverflow.com/questions/24066304/how-can-i-make-a-weak-protocol-reference-in-pure-swift-w-o-objc