Caution
お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。
ARC / 強参照 / 循環参照
Swiftは ARC(Automatic Reference Counting)によってメモリを自動管理します。クラスのインスタンスへの参照が1つ以上ある限り、そのインスタンスはメモリに保持されます。
構文
// 強参照(デフォルト)
var a: MyClass? = MyClass() // 参照カウント: 1
var b = a // 参照カウント: 2
a = nil // 参照カウント: 1(b が保持)
b = nil // 参照カウント: 0 → 解放
// 循環参照が起きるパターン
class A {
var b: B? // A が B を強参照
}
class B {
var a: A? // B が A を強参照 → 循環参照!
}
用語一覧
| 用語 | 概要 |
|---|---|
| ARC(自動参照カウント) | クラスインスタンスへの参照数を自動で追跡し、参照数が0になったときにメモリを解放します。 |
| 強参照(strong reference) | デフォルトの参照。参照カウントを増加させます。 |
| 参照カウント | インスタンスへの参照の数。0になるとインスタンスが解放されます。 |
| 循環参照(retain cycle) | 2つのインスタンスが互いに強参照し合い、参照カウントが0にならない状態。メモリリークが発生します。 |
サンプルコード
class Person {
let name: String
init(name: String) {
self.name = name
print("\(name) が作られました")
}
deinit {
print("\(name) が解放されました")
}
}
// 強参照の基本
var alice: Person? = Person(name: "Alice") // 参照カウント: 1
var another = alice // 参照カウント: 2
alice = nil // 参照カウント: 1(another がまだ保持)
print("alice を nil に")
another = nil // 参照カウント: 0 → 解放
print("another を nil に")
// 循環参照の例(メモリリーク)
class Apartment {
let unit: String
var tenant: Resident? // 強参照
init(unit: String) {
self.unit = unit
print("アパート \(unit) が作られました")
}
deinit { print("アパート \(unit) が解放されました") }
}
class Resident {
let name: String
var apartment: Apartment? // 強参照 → 循環参照!
init(name: String) {
self.name = name
print("\(name) が作られました")
}
deinit { print("\(name) が解放されました") }
}
// 循環参照の発生
var apt: Apartment? = Apartment(unit: "101")
var bob: Resident? = Resident(name: "Bob")
apt!.tenant = bob // Apartment → Resident(強参照)
bob!.apartment = apt // Resident → Apartment(強参照)
apt = nil // 解放されない(Bob がまだ参照している)
bob = nil // 解放されない(apt がまだ参照している)
print("--- 循環参照のためどちらも解放されていません ---")
概要
ARC は struct・enum・基本型には適用されません。クラス(参照型)のインスタンスのみが ARC の管理対象です。
循環参照が発生するとインスタンスの参照カウントが0にならず、deinit も呼ばれません。循環参照はメモリリークの原因となります。weak や unowned を使って解決してください。
weak / unowned による循環参照の解決についてはweak / unownedを参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。