Upload
naruki-chigira
View
600
Download
2
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
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] を使わない場合
非同期処理待機時 非同期処理終了時関数実行時
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] を使わない場合