[Swift]ARCとは?


こんにちはジェジェロです😊
今日は、iOS開発者として一度は聞いたことのあるARCのテーマについてお話ししたいと思います.

ARCとは?


https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html
上の内容を翻訳してください.
SWIFTは自動参照カウント管理とトレースメモリを使用します.
ほとんどの場合、メモリ管理はSWIFTで「正常に動作している」ことを意味し、ユーザーがメモリ管理を考慮する必要はありません.
うん...ドキュメントの内容を翻訳すると、SWIFTはユーザーの設定を必要とせずにARCを使用してメモリを管理していることがわかりました.
では、ARCはどのようにメモリを管理しますか?

ARCのメモリの管理方法


アプリケーションがメモリを管理するためにインスタンスを必要としない場合、ARCはクラスインスタンスで使用されるメモリを自動的に解放します.
ではARCはどのようにしてインスタンスを必要としないことを知っていますか?
ARCは、各クラスインスタンスを現在参照している属性、定数、および変数の数(参照数)を追跡する.ARCは、インスタンスに少なくとも1つのアクティビティ参照がある限り、インスタンスの割り当てをキャンセルしません.このため、属性、定数、または変数にクラスインスタンスを割り当てるたびに、属性、定数、または変数に強い参照が作成されます.参照は、インスタンスの安定性を維持し、強い参照が存在する限り、割り当て解除は許可されないため、Strong参照と呼ばれます.
異なる点は、使用するインスタンスが強力な参照を作成し、ARCがインスタンスを割り当て解除することを阻止することです.

Strong Reference Cycles Between Class Instances


ARCで問題が発生する可能性があります.
前述したように、使用するインスタンスは、ARCがインスタンスを割り当て解除することを阻止する強力な参照を作成します.
場合によっては、インスタンスは使用されませんが、参照は変更されないため、閉じることができません.
図とコードを見て説明します.
class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
    deinit { print("\(name) is being deinitialized") }
}

class Apartment {
    let unit: String
    init(unit: String) { self.unit = unit }
    var tenant: Person?
    deinit { print("Apartment \(unit) is being deinitialized") }
}

var john: Person?
var unit4A: Apartment?

john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")

現在のコードを図に示します.
各インスタンスは、現在のjohnおよびunit 4 A変数に割り当てられるため、強力な参照が作成されます.
john!.apartment = unit4A
unit4A!.tenant = john
インスタンスプロセスとして互いに割り当てられます.
Propertyにインスタンスを割り当てて、強力な参照を作成します.

johnは、unit 4 Aインスタンスの割り当てを解除しようとします.
john! = nil
unit4A! = nil

jajon、unit 4 A、クラスインスタンスの参照が切断されているため、Denitの呼び出しと割り当て解除が必要ですが、propertyとして相互参照されているため、解除できません.
Weakを使用してこの問題を解決します.
Weakは参照ですが、弱い参照です.
WeakはARCの割り当て解除を阻止できない.
これはWeakがreferencecountを増加させないことを意味します.
class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
    deinit { print("\(name) is being deinitialized") }
}

class Apartment {
    let unit: String
    init(unit: String) { self.unit = unit }
    weak var tenant: Person?
    deinit { print("Apartment \(unit) is being deinitialized") }
}

Person instanceの強い参照はjohnという変数が1つしかないため、johnとinstanceの参照をキャンセルすると、インスタンスは正常に割り当て解除されます.
john! = nil

Weak


弱点を使うときは注意が必要です.
「弱」と宣言された変数は、参照中にインスタンスの割り当てを解除できます.
reference Countは増加しないため、他の場所では強い参照が失われ、reference Countが0の場合、ARCはインスタンスの割り当てをキャンセルします.
割り当てを解除すると、ARCは弱いと宣言された変数にnilを自動的に割り当てます.したがって、オプション変数として宣言する必要があります.

Unowned


弱い項目のように、非プライベートインスタンスも強い参照を維持しません.
弱い参照と相違参照が負でない参照のインスタンスには、常に値が存在する必要があります.
すなわち、ARCリファレンスの割り当てをキャンセルしたインスタンスはnilを割り当てません.
インスタンスが割り当て解除され、インスタンスにアクセスしようとすると、エラーが発生します.
したがって、wned参照以外のインスタンスをメモリから最初に解放する必要がない場合に使用されます.
+)unnownedはnilを指定していないのでNon-Optional Typeと宣言し、letも可能です.
SWIFT 5.0からオプショナルタイプも選べるそうです.
うん.なぜnilが割り当てられていないのか知りたいのですが、Optional Typeを可能にしたので、これを再調査しなければなりません.

Strong Reference Cycles for Closures


クラスインスタンスのプロパティにインスタンスを割り当て、インスタンスからインスタンスをキャプチャすると、強いリファレンスサイクルが発生する可能性があります.

どうして起こるの?


エンクロージャは参照タイプです.したがって、クラスのPropertyエンクロージャを宣言すると、そのエンクロージャが強く参照されます.モジュールからインスタンスにアクセスすると、インスタンスがキャプチャされます.Strong Referenceとして取得されるため、モジュールとインスタンスの間に強いループ参照が生成されます.
class HTMLElement {

    let name: String
    let text: String?

    lazy var asHTML: () -> String = {
        if let text = self.text {
            return "<\(self.name)>\(text)</\(self.name)>"
        } else {
            return "<\(self.name) />"
        }
    }

    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }

    deinit {
        print("\(name) is being deinitialized")
    }

}

強いループ参照を解決するには、[キャプチャ](Capture)リストでインスタンスを[弱](Less)または[ゼロ以外](None)に明示的にキャプチャします.

    lazy var asHTML: () -> String = {
        [unowned self] in
        if let text = self.text {
            return "<\(self.name)>\(text)</\(self.name)>"
        } else {
            return "<\(self.name) />"
        }
    }

の最後の部分


次の記事では、ARCについてさらに詳しく説明します.
ありがとうございます.😊
いつでもご健康のご指導をお待ちしております