はじめに
結論から言うと、Protocol での記述は weak
は特に気にしなくてよさそうです。
Protocol では実クラスのプロパティが weak
か strong
かには関心がありません。
Swift において、weak var
のプロパティを持つプロトコルを定義したくなった場合、
本ポストのタイトルのようなエラーが出ると思います。
例えば delegate を持つ Protocol を定義したい場合があると思います。
protocol BProtocol {
weak var delegate: AProtocol? { get set }
}
実クラスでは delegate は weak var
で宣言しないと循環参照となってしまいます。
ですが、Protocol での記述は weak
は気にしなくてよさそうです。
簡単なプログラムで検証します。
前提条件
Mac: macOS Catalina 10.15.6
Xcode: Version 12.4 (12D4e)
検証
先に言ったように、Protocol での記述は weak
は特に気にしなくてよさそうです。
以下のようなサンプルプログラムで検証します。
protocol AProtocol: AnyObject {
func doSometing()
}
final class A: NSObject, AProtocol {
var b: B?
func raiseB() -> B? {
b = B()
b?.delegate = self
return b
}
func doSometing() {}
}
protocol BProtocol {
var delegate: AProtocol? { get set }
}
final class B: BProtocol {
weak var delegate: AProtocol? // <- weak を外すと循環参照になります
func printDelegate() {
print("delegate: \(delegate)")
}
}
ここで注目したいのが class B
が持っている delegate です。
delegate プロパティはAProtocol に準拠したクラスの変数です。
BProtocol では delegate プロパティを weak 宣言していません(できません)。
が、実クラスのBでは weak 宣言しています。
最も単純なコードだと、A
のインスタンスがnil になった時点で、
Bが保持している delegate
プロパティも weak
であれば、 nil になるはるはずです。
以下のようなコードを書いたとします。
「コードX」とします。
// コードX
var a: A? = A()
let b = a?.raiseB()
print("最初のprint")
b?.printDelegate()
a = nil
print("二番目のprint")
b?.printDelegate()
a = nil を実行された時点で、b が保持している delegate プロパティも nil になるはずです。
実際にそのようになります。
最初のprint
delegate: Optional(<HogeApp.A: 0x6000010f4320>)
二番目のprint
delegate: nil
一方、実クラスのB の delegate から weak を外してみます。
BProtocol では delegate プロパティを weak 宣言していません(できません)。
final class B: BProtocol {
var delegate: AProtocol?
... 略 ...
}
これで「コードX」を実行します。
すると以下のようになります。
最初のprint
delegate: Optional(<HogeApp.A: 0x6000018b4530>)
二番目のprint
delegate: Optional(<HogeApp.A: 0x6000018b4530>)
つまり、Protocol では実クラスが weak
か strong
かには関心がない
ということになります。
当該のプロポーザル
Swift evolution に以下のプロポーザルがあります。
0186-remove-ownership-keyword-support-in-protocols.md
Protocol は weak だろうが strong だろうが宣言できるが、
実クラスではそれに従う必要はないため、混乱を招いてしまう。
そのため、そもそもProtocol ではそれらの宣言をできないようにするべきだ、と書かれています。
最後に
というわけで Protocol は所有権に関心がないということが分かりました。
以上です。
お疲れ様でした!