Skip to content

Instantly share code, notes, and snippets.

@naru-jpn
Last active January 31, 2017 12:01
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save naru-jpn/fa4c39ce2eda8a803358dad75d04058d to your computer and use it in GitHub Desktop.
Save naru-jpn/fa4c39ce2eda8a803358dad75d04058d to your computer and use it in GitHub Desktop.
Check behavior of unowned / weak references
//: 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