キャプチャリストとweak self
[weak self]で循環参照を避けます。
「キャプチャリストとweak self」はCoddyKit上の無料Swift Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはSwift Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Swift Academyコースには全4レッスンが含まれています。
強参照循環のリスク
オブジェクトがselfを強くキャプチャするエスケープするクロージャーを保持すると、お互いが永遠に生存し続けます — これは強参照循環となり、メモリリークを引き起こします。
強参照による循環
クロージャーはselfを強くキャプチャし、selfはクロージャーを保持するため、どちらも解放されません:
class Owner {
var onEvent: (() -> Void)?
func setup() {
onEvent = { print(self.describe()) } // strong self -> cycle
}
func describe() -> String { "Owner" }
}
let o = Owner(); o.setup()
o.onEvent?() // "Owner" (but leaks)キャプチャリスト
クロージャーの先頭にあるキャプチャリスト、{ [weak self] in ... }は、キャプチャする各参照の保持方法を制御します。強参照ではなく、weakまたはunownedを指定できます。
weak self で循環を断つ
[weak self]はselfを、selfを生存させ続けないオプショナルとしてキャプチャします:
class Owner {
var onEvent: (() -> Void)?
func setup() {
onEvent = { [weak self] in
print(self?.describe() ?? "gone")
}
}
func describe() -> String { "Owner" }
}
let o = Owner(); o.setup()
o.onEvent?() // "Owner" (no cycle)weak によって self はオプショナルになります
[weak self]を使うと、selfはSelf?になるため、アンラップする必要があります:
class Worker {
var tag = "W"
lazy var job: () -> Void = { [weak self] in
guard let self = self else { return }
print(self.tag)
}
}
let w = Worker()
w.job() // "W"guard let self パターン
最初にselfを再束縛すると、クロージャーの残りの部分では強い非オプショナル参照を使えます:
class Service {
var name = "S"
lazy var run: () -> Void = { [weak self] in
guard let self else { return }
print(self.name)
print("still \(self.name)")
}
}
Service().run() // "S" / "still S"weak と unowned の違い
weakはオプショナルを生成し、オブジェクトがすでに存在しない可能性がある場合にも安全です。unownedは非オプショナルで高速ですが、オブジェクトの解放後にアクセスするとクラッシュします。selfがクロージャーより長く生存すると保証できる場合にだけ使ってください。
unowned を使う
クロージャーがselfより長く生存することがない場合は、unownedを選びます:
class Timer2 {
var ticks = 0
lazy var tick: () -> Void = { [unowned self] in
self.ticks += 1
}
}
let t = Timer2()
t.tick(); t.tick()
print(t.ticks) // 2特定のプロパティをキャプチャする
self全体ではなく必要なものだけをキャプチャしてください。そうすることで、循環を完全に避けられる場合があります:
class VM {
let id = 42
lazy var printer: () -> Void = { [id] in print(id) }
}
VM().printer() // 42エスケープしないクロージャーに weak は不要です
mapのような同期的でエスケープしないクロージャーは循環を引き起こさないため、そこでselfを強くキャプチャしても問題ありません:
class Calc {
let factor = 3
func scale(_ xs: [Int]) -> [Int] {
xs.map { $0 * self.factor } // safe, non-escaping
}
}
print(Calc().scale([1, 2])) // [3, 6]経験則
selfを参照する保存済みまたはエスケープするクロージャーには、[weak self]を使います。unownedを使うのは、selfが生存していると保証できる場合だけにしてください。エスケープしないクロージャーでは、キャプチャリストを省略します。
class P {
var n = "P"
var stored: (() -> Void)?
func arm() { stored = { [weak self] in print(self?.n ?? "-") } }
}
let p = P(); p.arm(); p.stored?() // "P"クイックチェック
[weak self]を使うのはなぜですか?まとめ
キャプチャリストについて学びました:
- 保存されたエスケープするクロージャー内でselfを強くキャプチャすると、強参照循環(メモリリーク)が発生します
[weak self]で循環を断てます。selfはオプショナルになるため、guard let selfを使いますunownedは非オプショナルで高速ですが、selfが存在しないとクラッシュします- エスケープしないクロージャーにキャプチャリストは不要です
次は、オートクロージャーです。
よくある質問
「キャプチャリストとweak self」レッスンは無料ですか?
はい。「キャプチャリストとweak self」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Swift Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Swift Academyコースには全4レッスンが含まれています。
「キャプチャリストとweak self」で何を学びますか?
[weak self]で循環参照を避けます。 ブラウザで直接実行するハンズオンコードでSwift Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Swift Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのSwift Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「キャプチャリストとweak self」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このSwift Academyレッスンでコードを書いて実行できますか?
はい。すべてのSwift Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- 参照による値のキャプチャ
- エスケapingクロージャ
- キャプチャリストとweak self
- オートクロージャ