Latest web development tutorials

Swift Automatic Referensi Counting (ARC)

Swift Gunakan Automatic Referensi Menghitung (ARC) mekanisme ini untuk melacak dan mengelola memori aplikasi

Dalam keadaan normal, kita tidak perlu secara manual melepaskan memori, karena ARC akan sebuah instance dari kelas tersebut tidak lagi digunakan, secara otomatis membebaskan memori.

Tapi kita masih perlu untuk menerapkan kode manajemen memori dalam beberapa kasus.

fungsi ARC

  • Ketika init () Membuat contoh baru dari kelas masing-masing metode saat, ARC akan mengalokasikan sepotong memori untuk menyimpan misalnya informasi.

  • Jenis informasi yang terkandung dalam memori akan contoh, serta nilai hal ini semua atribut yang relevan.

  • Ketika misalnya tidak lagi digunakan, ARC melepaskan memori diduduki oleh contoh, dan membiarkan memori dibebaskan dapat digunakan untuk tujuan lain.

  • Untuk memastikan bahwa contoh tidak akan hancur, ARC akan melacak dan menghitung setiap contoh sedang direferensikan dengan jumlah atribut, konstanta dan variabel.

  • Contoh ditugaskan untuk properti, konstan atau variabel, mereka akan membuat referensi yang kuat hal ini, asalkan referensi masih kuat, misalnya tidak boleh dihancurkan.

contoh 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

Output di atas eksekusi program adalah:

w3big 开始初始化
w3big 被析构

Contoh sirkulasi yang kuat antara referensi kelas

Dalam contoh di atas, ARC akan melacak baru dibuat nomor referensi Orang Anda contoh, dan itu akan hancur ketika contoh Orang tidak lagi diperlukan.

Namun, kita mungkin menulis kode seperti ini, tidak akan pernah ada kelas 0 referensi yang kuat. Hal ini terjadi dalam dua contoh kelas untuk mempertahankan referensi yang kuat satu sama lain, dan membiarkan pihak lain tidak akan hancur. Ini adalah apa yang disebut referensi melingkar kuat.

contoh

Contoh berikut menunjukkan lingkaran secara tidak sengaja menghasilkan referensi yang kuat. Contoh mendefinisikan dua kelas: Orang dan Apartment, digunakan untuk model apartemen dan penduduknya adalah:

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

Contoh solusi yang kuat beredar antara referensi

Swift menyediakan dua cara untuk memecahkan lingkaran Anda menggunakan atribut class ketika ditemui pertanyaan referensi yang kuat:

  • referensi lemah
  • Tidak ada referensi utama

referensi lemah dan tidak ada referensi utama memungkinkan referensi melingkar dalam sebuah contoh dari referensi ke contoh lain tanpa mempertahankan referensi yang kuat. contoh tersebut dapat merujuk satu sama lain tanpa menghasilkan siklus referensi yang kuat.

Untuk siklus hidup menjadi contoh nihil menggunakan referensi lemah. Sebaliknya, setelah nilai inisialisasi tidak akan ditugaskan untuk contoh nihil, penggunaan referensi non-primer.

Contoh referensi lemah

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

Output di atas eksekusi program adalah:

ARC 主模块
子模块 topic 数为 4

Tidak ada contoh acuan utama

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

Output di atas eksekusi program adalah:

ARC
学生的分数为 98

penutupan lingkaran disebabkan oleh referensi yang kuat

siklus referensi yang kuat juga terjadi ketika Anda menetapkan kelas misalnya penutupan properti, dan tubuh penutupan dan penggunaan contoh. Tubuh penutupan dapat mengakses contoh properti, seperti self.someProperty, atau penutupan sebuah metode instan panggilan, self.someMethod tersebut. Kedua kasus telah menyebabkan penutupan "menangkap" diri, sehingga siklus referensi yang kuat.

contoh

Bagaimana setelah mengikuti contoh menunjukkan Anda ketika penutupan adalah untuk menghasilkan referensi ke referensi yang kuat lingkaran diri. Contoh mendefinisikan kelas yang disebut HtmlElement, dinyatakan dalam model sederhana dari elemen 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())

kelas HtmlElement menghasilkan contoh kelas siklus dan penutupan asHTML nilai default antara referensi yang kuat.

Kuat asHTML contoh properti memegang referensi untuk penutupan. Namun, penutupan penutupan digunakan vivo diri (dikutip self.name dan self.text), dan karena itu penutupan capture diri, yang berarti penutupan, pada gilirannya, memegang referensi yang kuat HtmlElement misalnya. Sehingga dua benda menghasilkan referensi yang kuat melingkar.

penutupan lingkaran disebabkan oleh Kutip tekad yang kuat: Ketika anda mendefinisikan penutupan pada saat yang sama sebagai bagian dari definisi daftar tangkapan penutupan dengan cara ini dapat diselesaikan antara penutupan lingkaran dan referensi yang kuat ke instance kelas.


referensi lemah dan referensi tanpa pemilik

Ketika sebuah contoh dari penutupan dan ditangkap selalu mengacu pada satu sama lain dan selalu pada saat yang sama hancur, ditangkap dalam definisi penutupan ada referensi utama.

Sebaliknya, ketika penangkapan referensi kadang-kadang mungkin nihil, penutupan akan ditangkap dalam definisi referensi lemah.

Jika Anda menangkap referensi tidak akan nil, itu harus ada acuan utama bukan referensi lemah.

contoh

HtmlElement brondong contoh, acuan utama ada cara yang tepat untuk mengatasi referensi yang kuat melingkar. kelas menulis HtmlElement tersebut untuk menghindari referensi yang kuat melingkar:

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

Output di atas eksekusi program adalah:

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