Unowned Reference: その概要、構文、モバイルアプリケーションでの使用

著者: IT Sectr 公開日: 2026-03-30 読了時間: 9 分

Unowned Reference(非所有参照)は、Swiftにおける非所有の参照であり、オブジェクトのretain countを増加させず、weakとは異なり、オブジェクトの解放後にnilに設定されません。Apple Swift Language Guide, 2026によると、unownedは、オブジェクトがそれを参照するオブジェクトと少なくとも同じ期間生きることが保証されている場合に使用されます。Weak Referenceとは異なり、unownedはアンラップを必要としません。これは非オプショナル型であり、コードをよりクリーンにしますが、ライフタイムの保証に関する責任を開発者に負わせます。

重要なポイント

  • Unowned Reference — 自動ゼロイングなしの非所有参照。非オプショナル、retain countを増加させない
  • 保証 — オブジェクトが参照するオブジェクトより先に解放されないことが保証されている場合に使用
  • Weakとの違い — unownedはnilにゼロイングされない(クラッシュリスク)、weakはゼロイングされる(安全)
  • シナリオ — ライフタイム保証のある親子関係、unowned selfを使用したクロージャ、シングルトン、Service Locator
  • リスク — 解放されたunownedオブジェクトへのアクセスは実行時クラッシュ(EXC_BAD_ACCESS)を引き起こす

Unowned Referenceとは?

Unowned Referenceは、ARCにおけるオブジェクトへの非所有参照であり、そのretain countを増加させません。weakとは異なり、unowned参照はオブジェクトの解放後にゼロイングされません。解放済みのメモリを指し続けます。このような参照にアクセスすると、EXC_BAD_ACCESSによる実行時クラッシュが発生します。

“非所有”という用語は、その意味合いを反映しています。オブジェクトは存在しますが、そのライフタイムに責任を持つ者は誰もいません。開発者は明示的に宣言します:「このオブジェクトは私が参照している限り生き続けることを保証します。」コンパイラはこの保証を検証しません。これは開発者レベルの契約です。

Swift.org Documentation, 2026によると、unowned参照はライフタイムが保証されたシナリオでweakよりも優先されます。その理由は、オプショナル型を必要とせず(よりクリーンなコード)、アンラップを必要とせず(force-unwrapやguard letが少ない)、ゼロイング用のweakテーブルを維持するオーバーヘッドがないためです。ただし、契約に違反するとクラッシュします。

Swiftでのunowned構文

Swiftでは、unowned参照はletまたはvarの前にキーワードunownedを付けて宣言します。weakとは異なり、unownedはletとvarの両方を使用でき、オプショナル型を必要としません。この特性により、unownedはドメインロジックによってnilになり得ない参照に便利です。

swift
class Country {
    let name: String
    var capital: City!           // 初期化後に設定されます
    init(name: String) { self.name = name }
}

class City {
    let name: String
    unowned let country: Country   // ✅ unowned let — ライフタイム保証

    init(name: String, country: Country) {
        self.name = name
        self.country = country
    }
}

// 使用法
let france = Country(name: "France")
let paris = City(name: "Paris", country: france)
france.capital = paris
// ✅ Country → City (strong), City → Country (unowned) — retain cycleなし

この例では、City unowned let country — 都市は国なしでは存在できません。国が消滅すれば、都市(と参照)は意味を失います。意味論的には、これはunownedに理想的なケースです。ライフタイム保証が存在し、オプショナルは不要で、retain cycleは発生しません。

unowned var

unowned varは許可されていますが、あまり一般的ではありません。参照を置き換える可能性がある場合(例えば、子を別の親に再バインドする場合)に使用されます。再割り当て時に、古いオブジェクトの解放は外部所有者の責任です。

Unowned Optional

Swift 5.0+では、unownedオプショナル(unowned let x: Type?)のサポートが導入されました。これは妥協案です。unownedは、参照がnilでなければオブジェクトが生きていることを保証します。解放時の動作は通常のunownedと同様にクラッシュです。

Unowned vs Weak:いつどちらを使うか

unownedとweakの選択は、Swiftアーキテクチャを設計する際の頻繁な判断の一つです。各ケースの基準と推奨事項を検討しましょう。

基準WeakUnowned
オプショナルあり (Type?)なし (Type)
解放時のゼロイング自動でnilになし(ダングリングポインタのリスク)
型(let/var)varのみletまたはvar
パフォーマンスweakテーブルのオーバーヘッド最小限(単純なポインタ)
安全性安全(nilチェックあり)EXC_BAD_ACCESSのリスク
ライフタイム保証不要明示的な保証が必要

実用的なルール

weakを使用するのは、オブジェクトのライフタイムについて少しでも疑問がある場合です。weakは安全で明確であり、証明を必要としません。unownedを使用するのは、オブジェクトがより早く解放される可能性のあるすべてのシナリオを除外できる場合のみです。典型的なケース:親なしでは存在しない子、同期的に実行されるクロージャ、自身のイニシャライザ内でのオブジェクトへのアクセス。

Airbnb Swift Style Guide, 2025によると、大規模なコードベースではデフォルトでweakを使用し、unownedはライフタイム保証を説明する明示的なコメントと共にのみ使用することが推奨されています。これにより、リファクタリング時の不明瞭なクラッシュのリスクが軽減されます。

クロージャでのUnowned self

クロージャは、親子関係に次いでunownedの2番目に頻繁な使用ケースです。キャプチャリスト[unowned self]は、selfがクロージャより長く生きることが保証されている場合に使用されます。正しいシナリオと誤ったシナリオを検討しましょう。

unowned selfが安全な場合

同期クロージャ — sorted、filter、map。これらは現在のスレッドで即座に実行され、selfは確実に生きています。unownedを使用したキャプチャリストはここでは許容され、よりクリーンなコードになります。

swift
class DataProcessor {
    var items: [Int] = [3, 1, 4, 1, 5]

    func processSorted() {
        // ✅ unowned self — sortedは同期的に実行され、selfは確実に生存
        let sorted = items.sorted { [unowned self] a, b in
            return self.customCompare(a, b)
        }
    }

    func customCompare(_ a: Int, _ b: Int) -> Bool { return a < b }
}

unowned selfが危険な場合

非同期クロージャ — 遅延、ネットワークリクエスト、アニメーションを伴うもの。クロージャのスケジューリングと実行の間にselfが解放される可能性があります。この場合、unowned selfはクラッシュにつながります。[weak self]を使用してください。

swift
class NetworkLoader {
    func loadData() {
        // ❌ 危険: 非同期クロージャでのunowned self
        URLSession.shared.dataTask(with: url) { [unowned self] data, _, _ in
            self.handleResponse(data)  // selfが解放されるとクラッシュ
        }.resume()
    }

    func handleResponse(_ data: Data?) { }

    // ✅ 正解: weak self + guard
    func loadDataSafe() {
        URLSession.shared.dataTask(with: url) { [weak self] data, _, _ in
            guard let self else { return }
            self.handleResponse(data)
        }.resume()
    }
}

ルールを覚えておいてください:unowned self — 即座に実行される同期クロージャのみ。非同期クロージャの場合は、常にweak self + guard letを使用してください。例外:クロージャが完了するまでオブジェクトへの参照を明示的に保持する場合(例えば、別の変数に強参照を保持する)。

Unownedのリスクと回避方法

Unownedは強力だが危険なツールです。unownedがクラッシュにつながる可能性のある実際のシナリオと、リスクを最小化する方法を検討しましょう。

リファクタリングと保証の変更

unownedの主なリスクは、ライフタイム保証を無効にするビジネスロジックの変更です。開発者がコードをリファクタリングし、所有権を変更したり、遅延解放を導入したり、キャッシュを追加したりすると、unowned参照が時限爆弾と化します。コンパイラは警告しません — ユーザーのデバイスでクラッシュが発生するだけです。

推奨:unownedは、ライフタイム保証が明白で文書化されている場合にのみ使用してください。各unownedにコメントを追加してください:なぜこの参照が安全なのか、どのような条件下で違反する可能性があるのか。

UIKit階層でのUnowned

UIKitはunownedにとって高リスク領域です。ViewControllerは、ナビゲーション(pop、dismiss)、メモリ解放、画面回転の際にいつでも解放される可能性があります。unowned selfを使用してViewControllerをクロージャに渡した場合、バックグラウンドから戻る時やアニメーション完了時にselfがnilになっている可能性があります。

ベストプラクティス

unownedを使用する際のリスクを軽減するには、次のルールに従ってください:

  • デフォルトでweakを優先する — weakは安全、unownedは最適化であり標準ではない
  • 保証を文書化する — 各unownedについて、正当性を説明するコメントを書く
  • ViewControllerでunownedを避ける — UIKitのライフサイクルはunowned保証には予測不可能
  • unownedは同期クロージャのみに使用する — sorted、filter、mapは安全な候補
  • コードレビューで確認する — 各unownedにはコード作成者からの正当性が必要
  • 少しでも疑わしい場合はweakに移行する — 可読性の低下(1つのguard let)は本番環境でのクラッシュより軽微
swift
// 例: 明示的な正当性の根拠とともに文書化されたunowned参照
class InvoiceLineItem {
    let productName: String
    let price: Decimal

    // unowned Invoice — InvoiceLineItemはInvoiceなしでは存在できません。
    // InvoiceはItemを作成し、削除時にそれを除去します。
    // 保証: InvoiceはItemと少なくとも同じ期間生存します。
    unowned let invoice: Invoice

    init(productName: String, price: Decimal, invoice: Invoice) {
        self.productName = productName
        self.price = price
        self.invoice = invoice
    }
}

// これは強力な保証です: InvoiceはdeinitですべてのItemを除去します。
// 保証違反 = 修正が必要なビジネスロジックのバグ。

保証の文書化はプロフェッショナルスタンダードです。大規模プロジェクト(Airbnb、Uber)では、コードレビューで各unownedの正当性が求められます。保証が明確でない場合はweakを使用してください。unownedへのコメントは、将来の開発者がなぜここでweakが使用されなかったのか、どのような条件で保証が破られる可能性があるのかを理解するのに役立ちます。

よくある質問

オブジェクト解放後にunowned参照にアクセスするとどうなりますか?

実行時クラッシュ(EXC_BAD_ACCESS)。Swiftはアクセス時にunowned参照の有効性をチェックしません — 単なる「生の」ポインタです。オブジェクトが解放されるとメモリは上書きされ、アクセスすると致命的に終了します。これはキャッチ不可能な例外です(try-catch不可)。

unownedはプロトコルで使用できますか?

はい、プロトコルがAnyObjectを継承している場合。Unownedはすべての参照型(クラス、AnyObjectプロトコル、Objective-Cオブジェクト)で動作します。値型(struct、enum)はARCに関与しないため、unownedをサポートしません。

いつunownedはweakより安全ですか?

ライフタイム保証が絶対的で明白な場合 — unownedは設計の観点からより安全です。アンラップが不要で、nilになり得ず、エラーを隠しません。オブジェクトが親なしで存在できない場合、unownedはそれを明示的な契約にしますが、weakは保証を曖昧にします。

unownedとweakの間にパフォーマンスの違いはありますか?

はい:unownedの方が高速です。ゼロイングのために実行時にweakテーブルにアクセスする必要がないためです。ほとんどのアプリケーションでは違いはわかりませんが、何百万ものアクセスがある高負荷シナリオでは、unownedは読み取りで10〜20%高速になる可能性があります。

リファクタリングはunownedの保証にどのように影響しますか?

リファクタリングはunownedの主な危険です。オブジェクトのライフタイムの変更(キャッシュ、非同期操作、再利用)は保証を破る可能性があります。コンパイラは警告しません。解決策:アーキテクチャを変更する際はweakに移行するか、警告コメントを追加してください。

まとめ

  • Unowned Reference — ゼロイングなしの非所有参照。非オプショナル、retain countを増加させない
  • 保証 — オブジェクトがそれを参照するコードと少なくとも同じ期間生きるという明示的な証明が必要
  • 構文unowned letまたはunowned var。非オプショナルおよびオプショナル(Swift 5.0+)可能
  • Unowned vs Weak — unownedはより高速でクリーンだが、weakの方が安全。weakがデフォルトの選択
  • クロージャ — unowned selfは同期クロージャのみ。非同期には[weak self]が必要
  • 文書化 — 各unownedには保証を正当化するコメントが必要
  • 推奨 — 疑問がある場合はweakを選択。unownedは明示的で文書化された契約用

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください