35
Naruki Chigira - Timers inc. GitHub: naru-jpn, Twitter: @naruchigi Unowned / Weak References with Closure

Unowned / Weak References with Closure

Embed Size (px)

Citation preview

Naruki Chig i ra - T imers inc .

Gi tHub: naru- jpn, Twit ter : @naruchig i

Unowned / Weak References wi th Closure

変数の生存期間、気にしてますか?

クロージャ内で保持される変数、追えますか?

DispatchQueue.main.async { [weak self] in // ... }

クロージャ内で『 とりあえず [weak self] 』してませんか?

Playground で挙動を細かく見てみよう

https://gist.github.com/naru-jpn/fa4c39ce2eda8a803358dad75d04058d

class Executor { // MARK: Exeute stored procedure let procedure: () -> () init(procedure: @escaping () -> ()) { self.procedure = procedure } func execute() { self.procedure() } // MARK: Static execution static func execute(procedure: () -> ()) { procedure() } }

クロージャを実行するクラス Executor

class Object { var child: Object? weak var weakChild: Object? var closure: (() -> ())? weak var currentExecutor: Executor? }

観測用クラス Object

weak var weakObject: Object? = nil

// スコープ内外での挙動を見るために if 文でネストさせる // object が解放されていれば weakObject の中身は nil になる

if true { let object: Object = Object() weakObject = object print(“\(weakObject)") // nil or not nil? }

print(“\(weakObject)") // nil or not nil?

変数が解放されているかどうかの確認

object object

if true { let object: Object = Object() weakObject = object // 1 } // 2

1. 変数はスコープを抜けたら解放される

object

child

object

child

if true {

let object: Object = Object() object.child = object weakObject = object // 1 } // 2

weakObject?.child = nil

2. 参照によるメモリリーク

object

child

object

child

if true { let object: Object = Object() object.weakChild = object weakObject = object // 1 } // 2

weakObject?.child = nil

3. weak を使ってメモリリークしないようにしたケース

循環参照は当然避けましょう

object

closure

object

closure

if true { let object: Object = Object() object.closure = { print("\(object)") } weakObject = object // 1 } // 2

weakObject?.closure = nil

4. クロージャからの参照によるメモリリーク

object

closure

object

closure

if true { let object: Object = Object() object.closure = { [weak object] in print("\(object)") } weakObject = object // 1 } // 2

5. [weak ---] を使ってメモリリークしないようにしたケース

クロージャの循環参照にも注意

object

closure

object object

closure

object

スコープ内 関数実行時 関数終了時 スコープ外

Executor Executor

extension Object { func printWeakSelf() { let executor: Executor = Executor(procedure: { [weak self] in debugPrint("\(self)") }) executor.execute() } }

6. Executor のクロージャ内で [weak self] を使う場合

object

closure

object object

closure

object

スコープ内 関数実行時 関数終了時 スコープ外

Executor Executor

if true { let object: Object = Object() object.printWeakSelf() weakObject = object }

6. Executor のクロージャ内で [weak self] を使う場合

object

closure

object object

closure

object

Executor Executor

スコープ内 関数実行時 関数終了時 スコープ外

extension Object { func printSelf() { let executor: Executor = Executor(procedure: { print("\(self)") }) executor.execute() } }

7. Executor のクロージャ内で [weak self] を使わない場合

object

closure

object object

closure

object

Executor Executor

スコープ内 関数実行時 関数終了時 スコープ外

if true { let object: Object = Object() object.printSelf() weakObject = object }

7. Executor のクロージャ内で [weak self] を使わない場合

クロージャ内で self を参照してもリークしない場合もある

非同期処理待機時 非同期処理終了時関数実行時

object

closure closure

Executor

object

closure

Executor

extension Object { func printAsynchronousWeakSelf() { let executor: Executor = Executor(procedure: { let time: DispatchTime = .now() + 1.0 DispatchQueue.global().asyncAfter(deadline: time, execute: { [weak self] in print("\(self)") }) }) executor.execute() self.currentExecutor = executor } }

8. 非同期処理で [weak self] を使う場合

非同期処理待機時 非同期処理終了時関数実行時

object

closure closure

Executor

object

closure

Executor

if true { let object: Object = Object() object.printAsynchronousSelf() weakObject = object }

sleep(UInt32(3.0))

8. 非同期処理で [weak self] を使う場合

非同期処理待機時 非同期処理終了時関数実行時

object

closure

object

closure

Executor

object

closure

Executor

extension Object { func printAsynchronousSelf() { let executor: Executor = Executor(procedure: { DispatchQueue.global().asyncAfter(deadline: .now() + 1.0, execute: { print("\(self)") }) }) executor.execute() self.currentExecutor = executor } }

9. 非同期処理で [weak self] を使わない場合

非同期処理待機時 非同期処理終了時関数実行時

object

closure

object

closure

Executor

object

closure

Executor

if true { let object: Object = Object() object.printAsynchronousSelf() weakObject = object }

sleep(UInt32(3.0))

9. 非同期処理で [weak self] を使わない場合

非同期処理ではコールバック時に

object が生存しているかどうかが変わってくる

ただし、リークしないことに変わりはない

目的に応じて使い分けられるようになりたいですね🤗

いつか [weak self] を見たときに思いを馳せてみてください

Motivat ion / Concept

https: / /developers .google .com/protocol-buffers/

Template

message