Latest web development tutorials

スウィフト自動参照カウント(ARC)

スウィフト使用自動参照カウント(ARC)アプリケーションのメモリを追跡し、管理するために、このメカニズム

ARCは、もはやメモリを解放自動的に、使用されているクラスのインスタンスになりますので、通常の状況下で、我々は、手動でメモリを解放する必要はありません。

しかし、我々はまだいくつかの例では、メモリ管理コードを実装する必要があります。

ARC機能

  • initは()の各メソッドのクラスの新しいインスタンスを作成するとすると、ARCは、情報のインスタンスを格納するためのメモリのチャンクを割り当てます。

  • メモリに含まれる情報の種類は、インスタンスと、このインスタンスの値、関連するすべての属性になります。

  • インスタンスがもはや使用されている場合、ARCは、インスタンスによって占められるメモリを解放せず、解放されたメモリは、他の目的に使用することができましょう。

  • インスタンスが破棄されないことを確実にするために、ARCは、追跡し、各インスタンスは、属性、定数と変数の数によって参照されている計算になります。

  • プロパティ、定数または変数に割り当てられた例としては、彼らがいる限り、基準がまだ強いよう、インスタンスが破棄されるように許可されていない、強い参照をこのインスタンスを作成します。

ARCの例

class Person {
    let name: String
    init(name: String) {
        self.name = name
        print("\(name) 开始初始化")
    }
    deinit {
        print("\(name) 被析构")
    }
}

// 值会被自动初始化为nil,目前还不会引用到Person类的实例
var reference1: Person?
var reference2: Person?
var reference3: Person?

// 创建Person类的新实例
reference1 = Person(name: "w3big")


//赋值给其他两个变量,该实例又会多出两个强引用
reference2 = reference1
reference3 = reference1

//断开第一个强引用
reference1 = nil
//断开第二个强引用
reference2 = nil
//断开第三个强引用,并调用析构函数
reference3 = nil

上記プログラム実行出力は、次のとおりです。

w3big 开始初始化
w3big 被析构

クラス参照との間の強力な循環の例

上記の例では、ARCは、インスタンスの新しく作成した人の参照番号を追跡し、Personインスタンスが不要になったとき、それは破壊されません。

しかし、我々は、このようなコードを書くかもしれないクラス0強い参照が存在することはありません。 これはお互いに強い参照を保持し、そして相手が破壊されないようにする2つのクラスのインスタンスで発生します。 これは、いわゆる強い循環参照です。

次の例では、不注意に強い参照を生成するループを示しています。 例は、2つのクラス定義:Personとアパート、マンションをモデル化するために使用し、その住民は以下の通りでした。

class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
    deinit { print("\(name) 被析构") }
}

class Apartment {
    let number: Int
    init(number: Int) { self.number = number }
    var tenant: Person?
    deinit { print("Apartment #\(number) 被析构") }
}

// 两个变量都被初始化为nil
var w3big: Person?
var number73: Apartment?

// 赋值
w3big = Person(name: "w3big")
number73 = Apartment(number: 73)

// 意感叹号是用来展开和访问可选变量 w3big 和 number73 中的实例
// 循环强引用被创建
w3big!.apartment = number73
number73!.tenant = w3big

// 断开 w3big 和 number73 变量所持有的强引用时,引用计数并不会降为 0,实例也不会被 ARC 销毁
// 注意,当你把这两个变量设为nil时,没有任何一个析构函数被调用。
// 强引用循环阻止了Person和Apartment类实例的销毁,并在你的应用程序中造成了内存泄漏
w3big = nil
number73 = nil

強力な溶液の例は、参照との間を循環します

スウィフトは強い参照の質問に遭遇したときに、class属性を使用してループを解決するための2つの方法を提供します:

  • 弱参照
  • プライマリの参照はありません

弱い参照なし主な参照が強参照を保持することなく、別のインスタンスへの参照のインスタンス内の循環参照を可能にします。 このような場合には、強い参照サイクルを発生させることなく、相互に参照することができます。

ライフサイクルにnilインスタンスは弱参照を使用していますになります。 これとは対照的に、後の初期値は、nilのインスタンスに非プライマリ参照の使用を割り当てられません。

弱参照の例

class Module {
    let name: String
    init(name: String) { self.name = name }
    var sub: SubModule?
    deinit { print("\(name) 主模块") }
}

class SubModule {
    let number: Int
    
    init(number: Int) { self.number = number }
    
    weak var topic: Module?
    
    deinit { print("子模块 topic 数为 \(number)") }
}

var toc: Module?
var list: SubModule?
toc = Module(name: "ARC")
list = SubModule(number: 4)
toc!.sub = list
list!.topic = toc

toc = nil
list = nil

上記プログラム実行出力は、次のとおりです。

ARC 主模块
子模块 topic 数为 4

いいえ主な参考例はありません

class Student {
    let name: String
    var section: Marks?
    
    init(name: String) {
        self.name = name
    }
    
    deinit { print("\(name)") }
}
class Marks {
    let marks: Int
    unowned let stname: Student
    
    init(marks: Int, stname: Student) {
        self.marks = marks
        self.stname = stname
    }
    
    deinit { print("学生的分数为 \(marks)") }
}

var module: Student?
module = Student(name: "ARC")
module!.section = Marks(marks: 98, stname: module!)
module = nil

上記プログラム実行出力は、次のとおりです。

ARC
学生的分数为 98

強参照によって引き起こされるループの閉鎖

あなたは、プロパティのクラスインスタンスの閉鎖、およびクロージャ本体と例の使用を割り当てるとき、強い基準サイクルにも発生します。 クロージャ本体は、self.somePropertyとしての特性インスタンス、またはコールのインスタンスメソッドは、そのようなself.someMethodの閉鎖にアクセスすることができます。 どちらの例は、強い参照のサイクルで、その結果、自己を「キャプチャ」閉鎖につながっています。

どのようにクロージャが自己ループの強い参照への参照を生成する場合の例を、以下のことを示します後。 例は、単一のHTML要素の単純なモデルで表現し、HTML要素と呼ばれるクラスを定義しています。

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")
    }
    
}

// 创建实例并打印信息
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
print(paragraph!.asHTML())

HTML要素のクラスは強い参照間のデフォルト値asHTMLサイクルクラスのインスタンスとクロージャを生成しました。

強いasHTMLプロパティのインスタンスがクロージャへの参照を保持します。 しかし、閉鎖を意味し、自己(引用さself.nameとself.text)、したがって、閉鎖キャプチャ自己の生体内での使用でそのクロージャの閉鎖は、順番に、強い参照のHTMLElementのインスタンスを保持しています。 だから2つのオブジェクトが円形強い参照を生成します。

強い決意引用によって引き起こされるループ閉鎖:あなたはこのようにキャッチリストクロージャの定義の一部として同時にクロージャを定義する場合は、ループの閉鎖やクラスのインスタンスへの強い参照間で解決することができます。


ownerlessに弱い参照と参照

クロージャのインスタンスと取り込まれ、常にお互いを参照し、破壊し、同時に常にある場合、クロージャの定義の中に捕捉されない主な基準はありません。

キャプチャ参照が時々ゼロであるかもしれない場合は逆に、閉鎖は弱参照の定義の中に捕捉されます。

あなたは参照がnilに設定されませんキャプチャする場合は、代わりに弱参照のない主な基準となるべきではありません。

例を前述のHTMLElement、主な基準は、円形の強い参照を解決するための全く正しい方法ではありません。 円形の強い参照を避けるために、このような書き込みHTML要素のクラス:

class HTMLElement {
    
    let name: String
    let text: String?
    
    lazy var asHTML: () -> String = {
        [unowned self] in
        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) 被析构")
    }
    
}

//创建并打印HTMLElement实例
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
print(paragraph!.asHTML())

// HTMLElement实例将会被销毁,并能看到它的析构函数打印出的消息
paragraph = nil

上記プログラム実行出力は、次のとおりです。

<p>hello, world</p>
p 被析构