Tutorial Swift Automatic Referensi Counting (ARC) Terbaik Pada tahun 2024, Dalam tutorial ini Anda dapat mempelajari Contoh sirkulasi yang kuat antara referensi kelas,penutupan lingkaran disebabkan oleh referensi yang kuat,referensi lemah dan referensi tanpa pemilik,
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.
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.
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 被析构
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 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
Swift menyediakan dua cara untuk memecahkan lingkaran Anda menggunakan atribut class ketika ditemui pertanyaan referensi yang kuat:
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.
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
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
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.
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.
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.
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 被析构