言語
日本語
English

Caution

お使いのブラウザはJavaScriptが無効になっております。
当サイトでは検索などの処理にJavaScriptを使用しています。
より快適にご利用頂くため、JavaScriptを有効にしたうえで当サイトを閲覧することをお勧めいたします。

Swift辞典

  1. トップページ
  2. Swift辞典
  3. ARC / 強参照 / 循環参照

ARC / 強参照 / 循環参照

対応: Swift 1.0(2014)

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にならない状態。メモリリークが発生します。

サンプルコード

sample_arc_strong_reference.swift
class Person {
    let name: String

    init(name: String) {
        self.name = name
        print("\(name) を生成")
    }

    // 『deinit』はインスタンスがメモリから解放される直前に呼ばれるメソッドです。
    deinit {
        print("\(name) を解放")
    }
}

// 強参照の基本
var iori: Person? = Person(name: "八神庵")  // 参照カウント: 1
var another = iori                           // 参照カウント: 2

iori = nil            // 参照カウント: 1(another がまだ保持)
print("iori を 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: "草薙流古武術")
var kyo: Resident?  = Resident(name: "草薙京")

apt!.tenant   = kyo    // Apartment → Resident(強参照)
kyo!.apartment = apt   // Resident → Apartment(強参照)

apt = nil   // 解放されない(草薙京 がまだ参照している)
kyo = nil   // 解放されない(apt がまだ参照している)
print("--- 循環参照のためどちらも解放されていません ---")
swift arc_strong_reference.swift
八神庵 を生成
iori を nil に
八神庵 を解放
another を nil に
道場 草薙流古武術 を生成
草薙京 を生成
--- 循環参照のためどちらも解放されていません ---

概要

ARC は struct・enum・基本型には適用されません。クラス(参照型)のインスタンスのみが ARC の管理対象です。

循環参照が発生するとインスタンスの参照カウントが0にならず、deinit も呼ばれません。循環参照はメモリリークの原因となります。weak や unowned を使って解決してください。

weak / unowned による循環参照の解決についてはweak / unownedを参照してください。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。