https://www.facebook.com/events/444214209099406/
Swiftの循環参照とその解決、クロージャーの循環参照とその解決がわかるサンプルコード
//: Playground - noun: a place where people can play | |
import UIKit | |
/* | |
参照カウンタの仕組み | |
インスタンスが生成されると1になる。 | |
参照が増えるごとに+1。参照減ると-1。 | |
参照が0になるとインスタンスが破棄される。 | |
*/ | |
class Person { | |
let name : String | |
init(name : String){ | |
self.name = name | |
print("\(self.name)さんがやってきました") | |
} | |
deinit{ | |
print("\(self.name)さんはいなくなりました") | |
} | |
} | |
//佐藤さんが3人いる | |
var sato,sato2,sato3 : Person? | |
sato = Person(name: "佐藤")//参照カウント1 | |
sato2 = sato//参照カウント2 | |
sato3 = sato//参照カウント3 | |
sato = nil//参照カウント2 | |
sato2 = nil//参照カウント1 | |
sato3 = nil//参照カウント0 ->Personインスタンス破棄 | |
/* | |
循環参照。メモリリークを起こす | |
nilになる可能性があるプロパティにはweakを指定する | |
*/ | |
/*ユーザークラス*/ | |
class User { | |
let name : String | |
weak var haveDevice : AppleDevice?//弱参照を指定する | |
init(name : String){ | |
self.name = name | |
} | |
deinit{ | |
print("\(name)さんはいなくなりました") | |
} | |
} | |
/*アップルデバイスクラス*/ | |
class AppleDevice { | |
let name : String | |
var user : User? | |
init(name : String){ | |
self.name = name | |
} | |
deinit{ | |
print("\(self.user!.name)さんの持ち物ではなくなりました") | |
} | |
} | |
var tanaka : User? | |
var iPhone6s : AppleDevice? | |
tanaka = User(name: "田中") | |
iPhone6s = AppleDevice(name: "iPhone6s") | |
tanaka?.haveDevice = iPhone6s//プロパティに代入。 | |
iPhone6s?.user = tanaka | |
tanaka = nil | |
iPhone6s = nil//weakがないとiPhone6sが破棄されない | |
/* | |
カスタマーと銀行口座の関係でアンオウンド参照を見てみる | |
アンオウンド参照は一旦プロパティが設定されたらnilになることはないような場合に使用する | |
プロパティのクラスに強く結びついていて、プロパティが先に破棄されることがないような場合 | |
*/ | |
/*カスタマークラス*/ | |
class Customer { | |
let name : String | |
var bankAccount : BankAccount? | |
init(name : String){ | |
self.name = name | |
} | |
deinit{ | |
print("\(self.name)はいなくなりました") | |
} | |
} | |
/*銀行口座クラス*/ | |
class BankAccount { | |
let number : Int | |
unowned let customer : Customer | |
init(number : Int, customer: Customer){ | |
self.number = number | |
self.customer = customer | |
} | |
deinit{ | |
print("銀行口座:\(self.number)は解約されました") | |
} | |
} | |
var takashi : Customer? | |
takashi = Customer(name: "タカシ") | |
takashi!.bankAccount = BankAccount(number: 12345678, customer: takashi!)//口座を開設する | |
takashi = nil//unownedを指定していないと口座が解約されない | |
/* | |
クロージャーの循環参照 | |
クラスのプロパティにクロージャを割り当て、その中でselfを参照するような場合に循環参照が起こる可能性がある | |
*/ | |
class HTMLElement { | |
let name : String | |
let text : String? | |
//プロパティにクロージャーを設定 | |
lazy var asHTML : Void ->String = { | |
[unowned self] in | |
if let text = self.text { | |
return "<\(self.name)>\(text)</\(self.name)>" | |
}else{ | |
return"<\(self.name) />" | |
} | |
} | |
init(name :String, text: String? = nil){ | |
self.name = name | |
self.text = text | |
} | |
deinit{ | |
print("\(name)を削除しました") | |
} | |
} | |
//HTMLElementを使ってみる | |
var heading : HTMLElement? = HTMLElement(name: "h1", text: "hello, world!") | |
print(heading!.asHTML()) | |
heading = nil | |
https://www.facebook.com/events/444214209099406/
Swiftの循環参照とその解決、クロージャーの循環参照とその解決がわかるサンプルコード