強参照と弱参照、循環参照の回避

Swiftのメモリ管理は**ARC(Automatic Reference Counting)によって自動的に行われますが、開発者が強参照(strong reference)弱参照(weak reference)**の仕組みを理解して適切に使わないと、**循環参照(retain cycle)**という問題が発生します。以下に詳しく説明します。


1. 強参照(strong reference)

Swiftでは、あるインスタンスを他の変数や定数、プロパティに代入したとき、デフォルトで強参照が行われます。これは、その参照が存在する限り、対象のインスタンスのメモリが解放されないことを意味します。

swift
class Person { var name: String init(name: String) { self.name = name } } var person1 = Person(name: "Alice") // person1はPersonインスタンスを強参照

この例では、person1が存在する限り、Personインスタンスはメモリ上に保持されます。


2. 弱参照(weak reference)

弱参照(weakとは、参照先のインスタンスの所有権を持たず参照カウントを増やさない参照のことです。主に循環参照を防ぐために使用されます。

swift
class Person { var name: String weak var friend: Person? // 弱参照 init(name: String) { self.name = name } }
  • 弱参照には必ずvarOptional型が使われます。なぜなら、参照先のインスタンスが解放されると自動的にnilになるからです。


3. 循環参照(retain cycle)

2つ以上のインスタンスが互いに強参照し合うと、ARCではどちらの参照カウントも0にならず、メモリが解放されないという状態になります。これを循環参照と呼びます。

例(循環参照が発生するケース)

swift
class Person { var name: String var pet: Pet? // 強参照 init(name: String) { self.name = name } deinit { print("\(name) is deinitialized") } } class Pet { var owner: Person? // 強参照 init() {} deinit { print("Pet is deinitialized") } } var person: Person? = Person(name: "Bob") var pet: Pet? = Pet() person?.pet = pet pet?.owner = person person = nil pet = nil

この場合、PersonPetは互いに強参照し合っているため、deinitが呼ばれず、メモリが解放されません。


4. 循環参照の回避方法

解決策:一方をweakまたはunowned参照にする

weak参照で回避

swift
class Pet { weak var owner: Person? // ここを弱参照に変更 }

これで、Personが解放されると、Pet.ownerは自動的にnilになります。循環参照は発生しません。

unowned参照

  • unownedも弱参照ですが、**参照先がnilになることを許容しない(非オプショナル)**場面で使われます。

  • ただし、先に参照先が解放されているとクラッシュするため、使用には注意が必要です。

swift
class Pet { unowned var owner: Person // 非オプショナルで解放されない前提 }

まとめ

種類 所有権 参照カウント nilになるか 使用例
strong あり 増える ならない 通常のプロパティや変数
weak なし 増えない なる(Optional) 循環参照の回避、delegateなど
unowned なし 増えない ならない(非Optional) ライフサイクルが同じ前提の関係

Swiftでクラスを使う場合は、循環参照が起こりうる構造を事前に見抜き、適切にweakやunownedを使うことが重要です。

生成日:2025/05/04