Caution
お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。
weak / unowned
Swiftの『weak』(弱参照)と『unowned』(非所有参照)は、循環参照を防ぐための仕組みです。参照カウントを増やさないため、インスタンスが解放されても参照を保持しません。
構文
// weak: Optional型。インスタンス解放後は自動的に nil になる
weak var 参照: クラス名?
// unowned: 非Optional型。インスタンス解放後もアクセスするとクラッシュ
unowned var 参照: クラス名
// クロージャのキャプチャリスト
{ [weak self] in
self?.method()
}
{ [unowned self] in
self.method()
}
構文一覧
| 構文 | 概要 |
|---|---|
| weak var | 弱参照。参照先が解放されると自動的に nil になります(Optional 型)。 |
| unowned var/let | 非所有参照。参照先が必ず自分より長生きする場合に使います(非 Optional 型)。 |
| [weak self] | クロージャ内で self を弱参照でキャプチャします。 |
| [unowned self] | クロージャ内で self を非所有参照でキャプチャします。 |
サンプルコード
class Apartment {
let unit: String
weak var tenant: Resident? // weak で循環参照を解決
init(unit: String) { self.unit = unit }
deinit { print("アパート \(unit) が解放されました") }
}
class Resident {
let name: String
var apartment: Apartment? // 強参照(一方だけ weak にする)
init(name: String) { self.name = name }
deinit { print("\(name) が解放されました") }
}
// weak で循環参照を解決
var apt: Apartment? = Apartment(unit: "101")
var bob: Resident? = Resident(name: "Bob")
apt!.tenant = bob
bob!.apartment = apt
apt = nil // Apartment は解放される(Bob の weak 参照は nil に)
bob = nil // Resident も解放される
print("--- 両方解放されました ---")
// unowned: 常に参照先が存在する場合に使用
class CreditCard {
let number: String
unowned let owner: Customer // Customer は必ず存在する
init(number: String, owner: Customer) {
self.number = number
self.owner = owner
}
deinit { print("カード \(number) が解放されました") }
}
class Customer {
let name: String
var card: CreditCard?
init(name: String) { self.name = name }
deinit { print("\(name) が解放されました") }
}
var alice: Customer? = Customer(name: "Alice")
alice!.card = CreditCard(number: "1234-5678", owner: alice!)
alice = nil // Customer と CreditCard の両方が解放される
// クロージャでの [weak self]
class ViewController {
var name = "画面A"
func doAsyncWork() {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
guard let self = self else { return } // nil チェック
print("\(self.name) の処理完了")
}
}
}
概要
循環参照が発生する場合、どちらかの参照を『weak』または『unowned』にします。参照先のライフサイクルが不明な場合は安全な『weak』を、参照先が必ず自分より長生きする場合は『unowned』を使います。
クロージャが self を強参照でキャプチャすると循環参照が起きる場合があります。非同期処理のクロージャ内では『[weak self]』を使い、『guard let self = self else { return }』でアンラップするのが一般的です。unowned 参照に解放済みのインスタンスへアクセスすると実行時クラッシュします。参照先のライフサイクルが確実でない場合は weak を使ってください。
ARC の仕組みについてはARC / 強参照 / 循環参照を参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。