-
自動(dòng)引用計(jì)數(shù):
OC中,每個(gè)對(duì)象alloc,new,copy的時(shí)候,都會(huì)引起它相應(yīng)的引用計(jì)數(shù)加1,當(dāng)引用計(jì)數(shù)為0時(shí),該對(duì)象會(huì)被釋放.
在Swift中,也與OC類似.不過Swift中,引用指數(shù)只為引用類型提供,值類型不存在引用計(jì)數(shù)
- #####引用與釋放:
下列例子可以看出,我們生成了一個(gè)retainCount1的實(shí)例對(duì)象,并將其賦給2,3.當(dāng)我們把retainCount1置空時(shí),并沒有調(diào)起deinit方法.
因?yàn)閞etainCount1已經(jīng)被2,3引用,所以我們不釋放它們,該實(shí)例不會(huì)被釋放.當(dāng)我們把2,3也置空時(shí),deinit方法被調(diào)起,證明對(duì)象已被釋放
class RetainCount { init() { print("init") } deinit { print("deinit") } } var retainCount1,retainCount2,retainCount3:RetainCount? retainCount1 = RetainCount() retainCount2 = retainCount1 retainCount3 = retainCount1 retainCount1 = nil retainCount2 = nil retainCount3 = nil
- #####需要注意,Swift中的引用,都是強(qiáng)引用(Strong Reference)
- #####循環(huán)強(qiáng)引用:
當(dāng)兩個(gè)類互相引用時(shí),如果沒有正確的釋放,則兩個(gè)互相引用的對(duì)象,將永遠(yuǎn)不會(huì)被釋放.
下列例子中,就算我們把name與person都釋放了,也不會(huì)調(diào)起deinit方法.
我們生成了person,name實(shí)例,同時(shí),各自的屬性中,又各自強(qiáng)制指向了這兩個(gè)實(shí)例,當(dāng)我們釋放了其中一個(gè)指向時(shí),實(shí)際上還有一個(gè)指向存在,這樣ARC永遠(yuǎn)無法銷毀這兩個(gè)實(shí)例對(duì)象
class Name { var name = "[Unname]" var person:Person? deinit { print("name is deinit") } } class Person { var name:Name? deinit { print("person is deinit") } } var person:Person? = Person() var name:Name? = Name() name!.person = person person!.name = name name = nil person = nil
將上述代碼后兩句替換成這兩句,再試試效果,是不是被釋放了呢?
盡管我們先置空的是name,運(yùn)行順序中先被釋放的卻是person.
首先,我們釋放了name實(shí)例的person對(duì)象(name.person),此時(shí)指向Person()實(shí)例的只有一個(gè)person對(duì)象.
然后我們釋放了name實(shí)例,此時(shí)Name()實(shí)例也存在一個(gè)指向,在person.name中,隨后我們釋放了person,person再也沒有持有對(duì)象,ARC銷毀了它,同時(shí)也銷毀了person.name,此時(shí)Name()也沒有被引用的對(duì)象,因此也被銷毀
name?.person = nil name = nil person = nil
- ###避免循環(huán)強(qiáng)引用
- #####弱引用(weak):
在定義類屬性時(shí),在屬性前添加weak關(guān)鍵字,表明該屬性是弱引用類型,此時(shí)該屬性被引用時(shí),并不會(huì)強(qiáng)制持有,當(dāng)被引用的對(duì)象釋放時(shí),弱引用的屬性也會(huì)變成nil,從而解決循環(huán)引用
class Name { var name = "[Unname]" var person:Person? deinit { print("name is deinit") } } class Person { weak var name:Name? deinit { print("person is deinit") } } var person:Person? = Person() var name:Name? = Name() name!.person = person person!.name = name name = nil person = nil
- #####無主類型引用(unowned):
與weak類似,被該關(guān)鍵字修飾的屬性不會(huì)強(qiáng)制引用被引用對(duì)象,但不同的是,無主類型必須有值,且不能為nil
class Name { var name = "[Unname]" var person:Person? deinit { print("name is deinit") } } class Person { unowned var name:Name = Name() deinit { print("person is deinit") } } var name:Name = Name() var person:Person? = Person() person!.name = name person = nil
- ###由閉包引起的循環(huán)引用:
在類中,值捕獲閉包可以捕獲它上下文中想要捕獲的對(duì)象,包括類的實(shí)例屬性,即使類被釋放,他依然可以捕獲該值,如果該閉包引用了類中的實(shí)例屬性,那么即使類實(shí)例被設(shè)為nil,它依舊不會(huì)執(zhí)行deinit方法
class ClouserRetain { var text:String = "str" lazy var str:()->String = { var text = self.text return text } deinit { print("deinit") } } var cl:ClouserRetain? = ClouserRetain() var fun = cl?.str cl = nil fun!()
- #####使用值捕獲列表來避免循環(huán)引用:
捕獲列表定義了閉包體內(nèi)捕獲一個(gè)或者多個(gè)引用類型的規(guī)則.在閉包前傳入?yún)?shù)添加[],里面添加我們要捕獲的引用參數(shù),參數(shù)之間用","隔開,并將其設(shè)置為unowned或者weak,weak會(huì)將對(duì)象變?yōu)榭蛇x對(duì)象
class ClouserRetain { var text:String = "str" lazy var str:(_ a:String)->String = {[unowned self](_ a:String) in self.text = self.text + a return self.text } lazy var str1:(_ b:String)->String = {[weak self](_ b:String) in self?.text = (self?.text)! + b return self!.text } deinit { print("deinit") } } var cl:ClouserRetain? = ClouserRetain() var fun = cl?.str1 cl = nil
-
"weak"和"unowned":
無主類型要求被修飾的對(duì)象永遠(yuǎn)不為空,而weak則表明被修飾的對(duì)象可為空,上述方法雖然兩種都寫了,但其實(shí),無論何時(shí),我們都不能把self置空,所以不推薦使用第二種方法來避免循環(huán)引用