您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“Swift變量怎么使用”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Swift變量怎么使用”吧!
通常情況下我們不需要去手動釋放內(nèi)存,因?yàn)?ARC 會在類的實(shí)例不再被使用時(shí),自動釋放其占用的內(nèi)存。
但在有些時(shí)候我們還是需要在代碼中實(shí)現(xiàn)內(nèi)存管理。
ARC 功能
1.當(dāng)每次使用 init() 方法創(chuàng)建一個(gè)類的新的實(shí)例的時(shí)候,ARC 會分配一大塊內(nèi)存用來儲存實(shí)例的信息。
2.內(nèi)存中會包含實(shí)例的類型信息,以及這個(gè)實(shí)例所有相關(guān)屬性的值。
3.當(dāng)實(shí)例不再被使用時(shí),ARC 釋放實(shí)例所占用的內(nèi)存,并讓釋放的內(nèi)存能挪作他用。
4.為了確保使用中的實(shí)例不會被銷毀,ARC 會跟蹤和計(jì)算每一個(gè)實(shí)例正在被多少屬性,常量和變量所引用。
5.實(shí)例賦值給屬性、常量或變量,它們都會創(chuàng)建此實(shí)例的強(qiáng)引用,只要強(qiáng)引用還在,實(shí)例是不允許被銷毀的。
ARC 實(shí)例
class Person { let name: String init(name: String) { self.name = name print("\(name) 開始初始化") } deinit { print("\(name) 被析構(gòu)") } } // 值會被自動初始化為nil,目前還不會引用到Person類的實(shí)例 var reference1: Person? var reference2: Person? var reference3: Person? // 創(chuàng)建Person類的新實(shí)例 reference1 = Person(name: "Runoob") //賦值給其他兩個(gè)變量,該實(shí)例又會多出兩個(gè)強(qiáng)引用 reference2 = reference1 reference3 = reference1 //斷開第一個(gè)強(qiáng)引用 reference1 = nil //斷開第二個(gè)強(qiáng)引用 reference2 = nil //斷開第三個(gè)強(qiáng)引用,并調(diào)用析構(gòu)函數(shù) reference3 = nil
以上程序執(zhí)行輸出結(jié)果為:
Runoob 開始初始化 Runoob 被析構(gòu)
類實(shí)例之間的循環(huán)強(qiáng)引用
在上面的例子中,ARC 會跟蹤你所新創(chuàng)建的 Person 實(shí)例的引用數(shù)量,并且會在 Person 實(shí)例不再被需要時(shí)銷毀它。
然而,我們可能會寫出這樣的代碼,一個(gè)類永遠(yuǎn)不會有0個(gè)強(qiáng)引用。這種情況發(fā)生在兩個(gè)類實(shí)例互相保持對方的強(qiáng)引用,并讓對方不被銷毀。這就是所謂的循環(huán)強(qiáng)引用。
實(shí)例
下面展示了一個(gè)不經(jīng)意產(chǎn)生循環(huán)強(qiáng)引用的例子。例子定義了兩個(gè)類:Person和Apartment,用來建模公寓和它其中的居民:
class Person { let name: String init(name: String) { self.name = name } var apartment: Apartment? deinit { print("\(name) 被析構(gòu)") } } class Apartment { let number: Int init(number: Int) { self.number = number } var tenant: Person? deinit { print("Apartment #\(number) 被析構(gòu)") } } // 兩個(gè)變量都被初始化為nil var runoob: Person? var number73: Apartment? // 賦值 runoob = Person(name: "Runoob") number73 = Apartment(number: 73) // 意感嘆號是用來展開和訪問可選變量 runoob 和 number73 中的實(shí)例 // 循環(huán)強(qiáng)引用被創(chuàng)建 runoob!.apartment = number73 number73!.tenant = runoob // 斷開 runoob 和 number73 變量所持有的強(qiáng)引用時(shí),引用計(jì)數(shù)并不會降為 0,實(shí)例也不會被 ARC 銷毀 // 注意,當(dāng)你把這兩個(gè)變量設(shè)為nil時(shí),沒有任何一個(gè)析構(gòu)函數(shù)被調(diào)用。 // 強(qiáng)引用循環(huán)阻止了Person和Apartment類實(shí)例的銷毀,并在你的應(yīng)用程序中造成了內(nèi)存泄漏 runoob = nil number73 = nil
解決實(shí)例之間的循環(huán)強(qiáng)引用
Swift 提供了兩種辦法用來解決你在使用類的屬性時(shí)所遇到的循環(huán)強(qiáng)引用問題:
1.弱引用
2.無主引用
弱引用和無主引用允許循環(huán)引用中的一個(gè)實(shí)例引用另外一個(gè)實(shí)例而不保持強(qiáng)引用。這樣實(shí)例能夠互相引用而不產(chǎn)生循環(huán)強(qiáng)引用。
對于生命周期中會變?yōu)閚il的實(shí)例使用弱引用。相反的,對于初始化賦值后再也不會被賦值為nil的實(shí)例,使用無主引用。
弱引用實(shí)例
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 數(shù)為 \(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
以上程序執(zhí)行輸出結(jié)果為:
ARC 主模塊 子模塊 topic 數(shù)為 4
無主引用實(shí)例
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("學(xué)生的分?jǐn)?shù)為 \(marks)") } } var module: Student? module = Student(name: "ARC") module!.section = Marks(marks: 98, stname: module!) module = nil
以上程序執(zhí)行輸出結(jié)果為:
ARC 學(xué)生的分?jǐn)?shù)為 98
閉包引起的循環(huán)強(qiáng)引用
循環(huán)強(qiáng)引用還會發(fā)生在當(dāng)你將一個(gè)閉包賦值給類實(shí)例的某個(gè)屬性,并且這個(gè)閉包體中又使用了實(shí)例。這個(gè)閉包體中可能訪問了實(shí)例的某個(gè)屬性,例如self.someProperty,或者閉包中調(diào)用了實(shí)例的某個(gè)方法,例如self.someMethod。這兩種情況都導(dǎo)致了閉包 "捕獲" self,從而產(chǎn)生了循環(huán)強(qiáng)引用。
實(shí)例
下面的例子為你展示了當(dāng)一個(gè)閉包引用了self后是如何產(chǎn)生一個(gè)循環(huán)強(qiáng)引用的。例子中定義了一個(gè)叫HTMLElement的類,用一種簡單的模型表示 HTML 中的一個(gè)單獨(dú)的元素:
class HTMLElement { let name: String let text: String? lazy var asHTML: () -> String = { if let text = self.text { return "<\(self.name)>\(text)" } else { return "<\(self.name) />" } } init(name: String, text: String? = nil) { self.name = name self.text = text } deinit { print("\(name) is being deinitialized") } } // 創(chuàng)建實(shí)例并打印信息 var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world") print(paragraph!.asHTML())
HTMLElement 類產(chǎn)生了類實(shí)例和 asHTML 默認(rèn)值的閉包之間的循環(huán)強(qiáng)引用。
實(shí)例的 asHTML 屬性持有閉包的強(qiáng)引用。但是,閉包在其閉包體內(nèi)使用了self(引用了self.name和self.text),因此閉包捕獲了self,這意味著閉包又反過來持有了HTMLElement實(shí)例的強(qiáng)引用。這樣兩個(gè)對象就產(chǎn)生了循環(huán)強(qiáng)引用。
解決閉包引起的循環(huán)強(qiáng)引用:在定義閉包時(shí)同時(shí)定義捕獲列表作為閉包的一部分,通過這種方式可以解決閉包和類實(shí)例之間的循環(huán)強(qiáng)引用。
弱引用和無主引用
當(dāng)閉包和捕獲的實(shí)例總是互相引用時(shí)并且總是同時(shí)銷毀時(shí),將閉包內(nèi)的捕獲定義為無主引用。
相反的,當(dāng)捕獲引用有時(shí)可能會是nil時(shí),將閉包內(nèi)的捕獲定義為弱引用。
如果捕獲的引用絕對不會置為nil,應(yīng)該用無主引用,而不是弱引用。
實(shí)例
前面的HTMLElement例子中,無主引用是正確的解決循環(huán)強(qiáng)引用的方法。這樣編寫HTMLElement類來避免循環(huán)強(qiáng)引用:
class HTMLElement { let name: String let text: String? lazy var asHTML: () -> String = { [unowned self] in if let text = self.text { return "<\(self.name)>\(text)" } else { return "<\(self.name) />" } } init(name: String, text: String? = nil) { self.name = name self.text = text } deinit { print("\(name) 被析構(gòu)") } } //創(chuàng)建并打印HTMLElement實(shí)例 var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world") print(paragraph!.asHTML()) // HTMLElement實(shí)例將會被銷毀,并能看到它的析構(gòu)函數(shù)打印出的消息 paragraph = nil
以上程序執(zhí)行輸出結(jié)果為:
hello, world p 被析構(gòu)
到此,相信大家對“Swift變量怎么使用”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。