Last active
January 31, 2017 12:01
-
-
Save naru-jpn/fa4c39ce2eda8a803358dad75d04058d to your computer and use it in GitHub Desktop.
Check behavior of unowned / weak references
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//: Playground - noun: a place where people can play | |
import Foundation | |
import XCPlayground | |
class Executor { | |
// MARK: Execute stored procedure | |
let procedure: () -> () | |
init(procedure: @escaping () -> ()) { | |
self.procedure = procedure | |
} | |
func execute() { | |
self.procedure() | |
} | |
// MARK: Static execution | |
static func execute(procedure: () -> ()) { | |
procedure() | |
} | |
} | |
class Object { | |
var child: Object? = nil | |
weak var weakChild: Object? = nil | |
var closure: (() -> ())? = nil | |
weak var currentExecutor: Executor? = nil | |
} | |
// インスタンスが生きているかどうかの確認用変数 | |
// weak 変数は、参照先の変数が解放されていたら自動的に nil が代入される | |
weak var weakObject: Object? = nil | |
// 1. 変数はスコープを抜けたら解放される | |
if true { | |
let object: Object = Object() | |
weakObject = object | |
print("\(weakObject)") // ある | |
} | |
print("\(weakObject)") // 解放済み | |
// 2. 参照によるメモリリーク | |
if true { | |
let object: Object = Object() | |
object.child = object | |
weakObject = object | |
print("\(weakObject)") // ある | |
} | |
print("\(weakObject)") // メモリリークしてる | |
weakObject?.child = nil | |
print("\(weakObject)") // 解放済み | |
// 3. 2 で weak を使ってメモリリークしないようにしたケース | |
if true { | |
let object: Object = Object() | |
object.weakChild = object | |
weakObject = object | |
print("\(weakObject)") // ある | |
} | |
print("\(weakObject)") // 解放済み | |
// 4. クロージャからの参照によるメモリリーク | |
if true { | |
let object: Object = Object() | |
object.closure = { | |
print("\(object)") | |
} | |
weakObject = object | |
print("\(weakObject)") // ある | |
} | |
print("\(weakObject)") // メモリリークしてる | |
weakObject?.closure = nil | |
print("\(weakObject)") // 解放済み | |
// 5. 4 で [weak ---] を使ってメモリリークしないようにしたケース | |
if true { | |
let object: Object = Object() | |
object.closure = { [weak object] in | |
print("\(object)") | |
} | |
weakObject = object | |
print("\(weakObject)") // ある | |
} | |
print("\(weakObject)") // 解放済み | |
// 6. Executor のクロージャ内で [weak self] を使う場合 | |
extension Object { | |
func printWeakSelf() { | |
let executor: Executor = Executor(procedure: { [weak self] in | |
debugPrint("\(self)") | |
}) | |
executor.execute() | |
} | |
} | |
if true { | |
let object: Object = Object() | |
object.printWeakSelf() | |
weakObject = object | |
print("\(weakObject)") // ある | |
} | |
print("\(weakObject)") // 解放済み | |
// 7. Executor のクロージャ内で [weak self] を使わない場合 | |
extension Object { | |
func printSelf() { | |
let executor: Executor = Executor(procedure: { | |
print("\(self)") | |
}) | |
executor.execute() | |
} | |
} | |
if true { | |
let object: Object = Object() | |
object.printSelf() | |
weakObject = object | |
print("\(weakObject)") // ある | |
} | |
print("\(weakObject)") // メモリリークしない | |
// 8. 非同期処理で [weak self] を使う場合 | |
extension Object { | |
func printAsynchronousWeakSelf() { | |
let executor: Executor = Executor(procedure: { | |
DispatchQueue.global().asyncAfter(deadline: .now() + 1.0, execute: { [weak self] in | |
print("") | |
print("\(self)") | |
}) | |
}) | |
executor.execute() | |
self.currentExecutor = executor | |
} | |
} | |
if true { | |
let object: Object = Object() | |
object.printAsynchronousWeakSelf() | |
weakObject = object | |
print("\(weakObject)") // ある | |
} | |
print("\(weakObject)") // 解放済み | |
print("\(weakObject?.currentExecutor)") // 解放済み | |
sleep(UInt32(3.0)) | |
print("\(weakObject)") // 解放済み | |
// 9. 非同期処理で [weak self] を使わない場合 | |
extension Object { | |
func printAsynchronousSelf() { | |
let executor: Executor = Executor(procedure: { | |
DispatchQueue.global().asyncAfter(deadline: .now() + 1.0, execute: { | |
print("") | |
print("\(self)") | |
}) | |
}) | |
executor.execute() | |
self.currentExecutor = executor | |
} | |
} | |
if true { | |
let object: Object = Object() | |
object.printAsynchronousSelf() | |
weakObject = object | |
print("\(weakObject)") // ある | |
} | |
print("\(weakObject)") // まだある | |
print("\(weakObject?.currentExecutor)") // 解放済み | |
sleep(UInt32(3.0)) | |
print("\(weakObject)") // 解放済み | |
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment