swift學習筆記之自動引用計數

2021-07-12 04:53:33 字數 3818 閱讀 4419

/**

* swift使用自動引用計數(arc)來管理應用程式的記憶體使用。這表示記憶體管理已經是swift的一部分,在大多數情況下,你並不需要考慮記憶體的管理。當例項並不再被需要時,arc會自動釋放這些例項所使用的記憶體。

另外需要注意的:

引用計數僅僅作用於類例項上。結構和列舉是值型別,而非引用型別,所以不能被引用儲存和傳遞。

swift的arc工作過程

每當建立乙個類的例項,arc分配乙個記憶體塊來儲存這個例項的資訊,包含了型別資訊和例項的屬性值資訊。

另外當例項不再被使用時,arc會釋放例項所占用的記憶體,這些記憶體可以再次被使用。

但是,如果arc釋放了正在被使用的例項,就不能再訪問例項屬性,或者呼叫例項的方法了。直接訪問這個例項可能造成應用程式的崩潰。就像空例項或游離例項一樣。

為了保證需要例項時例項是存在的,arc對每個類例項,都追蹤有多少屬性、常量、變數指向這些例項。當有活動引用指向它時,arc是不會釋放這個例項的。

為實現這點,當你將類例項賦值給屬性、常量或變數時,指向例項的乙個強引用(strong reference)將會被構造出來。被稱為強引用是因為它穩定地持有這個例項,當這個強引用存在時,例項就不能夠被自動釋放,因此可以安全地使用。

*/class

student

func getname() -> string

func listening()

deinit

}class

teacher

func getname() -> string

func classing()

deinit

}func testarc()

testarc()

/*** 從上面的例子來看,確實swift給我們自動管理了記憶體,很多時侯開發者都不需要考慮太多的記憶體管理。但真的是這樣嗎?真的安全嗎?作為開發者要如何用好arc?

儘管arc減少了很多記憶體管理工作,但arc並不是絕對安全的。下面來看一下迴圈強引用導至的記憶體洩漏。

*/func testmemoryleak()

/**例項之間的相互引用,在日常開發中是很常見的一種,哪麼如何避免這種迴圈強引用導致的記憶體洩漏呢?

可以通過在類之間定義為弱引用(weak)或無宿主引用的(unowned)變數可以解決強引用迴圈這個問題

*/testmemoryleak()

/*** 弱引用方式:

弱引用並不保持對所指物件的強烈持有,因此並不阻止arc對引用例項的**。這個特性保證了引用不成為強引用迴圈的一部分。指明引用為弱引用是在生命屬性或變數時在其前面加上關鍵字weak。

注意弱引用必須宣告為變數,指明它們的值在執行期可以改變。弱引用不能被宣告為常量。

因為弱引用可以不含有值,所以必須宣告弱引用為可選型別。因為可選型別使得swift中的不含有值成為可能。

加上weak var student : student?

或weak var teacher : teacher?

經測試得出結論:

當a類中包函有b類的弱引用的例項,同時,b類中存在a的強引用例項時,如果a釋放,也不會影響b的析放,但a的記憶體**要等b的例項釋放後才可以**。(情況一的結果)

當a類中包函有b類的強引用的例項時,如果a釋放,則不會影響b的析放。(情況二的結果)

*//**

* 無宿主引用方式:

和弱引用一樣,無宿主引用也並不持有例項的強引用。但和弱引用不同的是,無宿主引用通常都有乙個值。因此,無宿主引用並不定義成可選型別。指明為無宿主引用是在屬性或變數宣告的時候在之前加上關鍵字unowned。

因為無宿主引用為非可選型別,所以每當使用無宿主引用時不必使用?。無宿主引用通常可以直接訪問。但是當無宿主引用所指例項被釋放時,arc並不能將引用值設定為nil,因為非可選型別不能設定為nil。

注意在無宿主引用指向例項被釋放後,如果你想訪問這個無宿主引用,將會觸發乙個執行期錯誤(僅當能夠確認乙個引用一直指向乙個例項時才使用無宿主引用)。在swift中這種情況也會造成應用程式的崩潰,會有一些不可預知的行為發生。因此使用時需要特別小心。

*/class

teacher1

func getname() -> string

func classing()

deinit

}class

student1

func getname() -> string

func listening()

deinit

}func testnotowner()

/*** 所以使用無宿主引用時,就需要特別小心,小心別人釋放時,順帶釋放了強引用物件,所以要想別人釋放時不影響到原例項,可以使用弱引用這樣就算nil,也不會影響。

*/testnotowner()

/*** 上面介紹了,當某個類中的例項物件如果在整個生命週期中,有某個時間可能會被設為nil的例項,使用弱引用,如果整個生命週期中某一例項,一旦構造,過程中不可能再設為nil的例項變數,通常使用無宿主引用。但時有些時侯,在兩個類中的相互引用屬性都一直有值,並且都不可以被設定為nil。這種情況下,通常設定乙個類的例項為無宿主屬性,而另乙個類中的例項變數設為的隱式裝箱可選屬性(即!號屬性)

如下面的例子,每位父親都有孩子(沒孩子能叫父親麼?),每個孩子都有乙個親生父親

*///class children

////

// deinit

//

//}//class father

////

// deinit

//

//}//

////var fa = father(name: "王五",childname: "王八")

//print("\(fa.fathername) 有個小孩叫 \(fa.children.name)")

////另外,還有一種情況,當自身的閉包對自身(self) 的強引用,也會導致記憶體洩漏。

class

cpufactory

//宣告乙個閉包

lazy

var someclosure: (int, string) -> string =

//宣告乙個閉包,同樣閉包中引用self

lazy

var machining: () -> string =

else

}//宣告乙個閉包,但閉包中將自身作為引數傳進去(可以避去記憶體洩漏)

lazy

var machining2 : (cpufactory) -> string =

else

}deinit

}//在這個例子中有三個閉包,分別是帶參,和不帶參,對於帶參的 不能省略[unowned self] (paramers) in操作。否則會編譯不過,另外,書中沒有提到的,只有宣告為@lazy的閉包中才可以使用[unowned self] 否則在普通閉包中使用也會報錯。還有一點書中講到當自身閉包中使用self.時會產生強引用,導至記憶體洩漏,因此加上[unowned self ] in 這句可以破壞這種強引用,從而使記憶體得到釋放,但經本人親自驗證,就算加上了也沒有釋放。

func testclosure1()

testclosure1()

//顯然cpu = nil也不會釋放記憶體。

func testclosure2()

testclosure2()

//可見使用自身作為引數傳參時,可以釋放記憶體。

func testclosure3()

testclosure3()

//實第三和第一種是一樣的,都是引用了self.但第一種可以把[unowned self ]in 句注釋和不注釋的情況下進行測試,可以發現結果是一樣的,並沒有釋放記憶體。

///

Swift學習之自動引用計數

class person deinit var reference1 person?var reference2 person?var reference3 person?reference1 person name iyaqi 此時會列印 person iyaqi is being initial...

swift學習筆記 七 自動引用計數

與object c一樣,swift使用自動引用計數來跟蹤並管理應用使用的記憶體。當例項不再被使用時,及retaincount 0時,會自動釋放是理所占用的記憶體空間。注 引用計數僅適用於類的例項,因為struct和enumeration屬於值型別,也就不牽涉引用,所以其儲存和管理方式並不是引用計數。...

swift自動引用計數

在少數情況下,arc為了能幫助你管理記憶體,需要更多的關於你的 之間關係的資訊 引用計數僅僅應用於類的例項,結構體和列舉型別是值型別,不是引用型別,也不是通過引用的方式儲存和傳遞 為了使之成為可能,無論你將例項賦值給屬性,常量或者是變數,屬性,常量或者變數,都會對此例項建立強引用。之所以稱之為強引用...