下のようなコードですが、weak cannot be applied to non-class type 'MyProtocol'
というエラーになります。
protocol MyProtocol {}
// weak cannot be applied to non-class type 'XXX'
class MyClass {
weak var delegate: MyProtocol?
}
エラーの解決策
protocolに:classを付与すれば直ります。
protocol MyProtocol: class {}
class MyClass {
weak var delegate: MyProtocol?
}
: classとは何か
:classを付けるとこのProtocolはclassにのみ適用できるようになります。
:classが付いている場合、enumやstructにはこのプロトコルを使えないです。
// : classなし
protocol MyProtocol {}
class MyClass: MyProtocol {}
struct MyStruct: MyProtocol {}
enum MyEnum: MyProtocol {}
// : classあり
protocol MyProtocol: class {}
class MyClass: MyProtocol {}
struct MyStruct: MyProtocol {} // エラー
enum MyEnum: MyProtocol {} // エラー
: class
はあるのですが、: struct
や: enum
はありません。
protocol MyProtocol: struct {} // エラー
protocol MyProtocol: enum {} // エラー
なぜ: classを付けないとエラーになるのか
それはstructやenumはweakを付ける事ができないからです。
struct MyStruct {}
enum MyEnum { case A }
class MyClass {
weak var myStruct = MyStruct() // エラーになる
weak var myEnum = MyEnum.A // エラーになる
}
なぜstructやenumでweakが使えないのか
おそらくですが、structやenumには参照カウントがないからだと思われます。
クラスを初期化して変数に入れた場合、変数にはオブジェクトのメモリアドレスが入っています。
参照カウントとは、変数がそのオブジェクトを参照した際にインクリメントされて参照がなくなったらデクリメントされるものです。
つまりそのオブジェクトが何個の変数から参照されているかを表すものです。
weakとはオブジェクトを参照しても参照カウントが増えないようにする機能です。
それに対してstructやenumは変数にメモリアドレスでなく値が入っています。
その為参照されると概念がなく、参照カウントもありません。
そういった事もあってstruct/enumでは参照カウントを制御するweakを使えないのだと思われます。
この辺少し自身がないので変な所あればツッコミ頂けると嬉しいです m m
まとめ
-
protocol MyPritocol: class
はクラスのみに適用できるようにする記法 - クラスに絞り込めばweak修飾子を使える
- structやenumは参照カウントがないのでweakが使えない