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の循環参照とその解決、クロージャーの循環参照とその解決がわかるサンプルコード