Swift使用自動引用計數(ARC(Automatic Reference Count))來管理應用程序的內存使用。這表示內存管理已經是Swift的一部分,在大多數情況下,你並不需要考慮內存的管理。當實例並不再被需要時,ARC會自動釋放這些實例所使用的內存。
內存管理:針對的是實例的內存占用的管理(放在堆里面)
實例:1:由class類型構建的實例,2:閉包對象
下面我們來寫一個實例來證明一下
class Person { var name: String init(name: String ) { self.name = name } //類被銷毀時,會調用這個方法 deinit { print("\(name) person deinit") } } // var p: Person? = Person(name: "張三")
p = nil
//"張三" person deinit
當一個事例化的對象被賦予nil的話,會調用的 deinit(),代表着這個對象被銷毀
class Person { var name: String init(name: String ) { self.name = name } //類被銷毀時,會調用這個方法 deinit { print("\(name) person deinit") } } // var p: Person? = Person(name: "張三") p = Person(name: "banzhang") //"張三persondeinit"
當一個對象引用了另一個新的對象時,舊的對象就會被銷毀
func testArc() { var p = Person(name: "chen") print(p.name) } testArc() //chen person deist
如果是一個函數的話, 受作用域的作用, 該對象會被銷毀
所以呢,通過上面的幾個實例,可以得出如果當一個對象如果沒被引用的話,就會自動被銷毀
接下來呢, 我們來說一下循環引用,
簡單來說呢, 你可以把循環引用當做兩個函數里的屬性或方法相互調用彼此,這樣的話, 很有可能會發生內存泄漏,下面我們來看一下循環引用的解決方法,在說明解決方法時,我們先來說一下兩個名詞的含義:
空懸指針:(只會出現在弱引用)當指定每一個位置時,該位置存儲的數據已經不在。
如果想解決空懸指針的辦法只有兩種:一種是把其值賦值為nil,另一種是把其指向另外的新對象(這種方法不可行)。
//在swift中,賦值為nil只有用?或!聲明的類成員才可以解決空懸指針的問題
//A (a1:B ) B(b1:A)
//? ?
//? !
//! ? (這種情況與上面一樣)
//! !
1.兩邊都是?和 ?
class Student { var name: String var t: Teacher? init(name: String) { self.name = name } deinit { print("\(name) student deinit") } } class Teacher { var name: String weak var banzhang: Student? init(name: String) { self.name = name } deinit { print("\(name) teacher deinit") } } var teacher:Teacher? = Teacher(name: "cj") var bc:Student? = Student(name: "yeweidong") teacher?.banzhang = bc bc?.t = teacher teacher = nil bc = nil //yeweidong student deinit //cj teacher deinit
2.一邊為可空類型,一邊為非可空類型(unowned)
class Student2 { var name: String var t: Teacher2? init(name: String) { self.name = name } deinit { print("\(name) student deinit") } } class Teacher2 { var name: String //unowned修飾在非可選類型上,不能用weak,weak只能用在可選類型 unowned var banzhang: Student2 init(name: String,stu: Student2) { self.name = name self.banzhang = stu } deinit { print("\(name) teacher deinit") } } var s1: Student2? = Student2(name: "ch") var teac: Teacher2? = Teacher2(name: "david", stu: s1!) s1?.t = teac teac?.banzhang = s1! s1 = nil teac = nil //ch student deist //david teacher deinit
3.兩邊為非可用類型
class Student2 { var name: String unowned var t: Teacher2 init(name: String ,t :Teacher2) { self.name = name self.t = t } deinit { print("\(name) student deinit") } } class Teacher2 { var name: String //unowned修飾在非可選類型上,不能用weak,weak只能用在可選類型 unowned var banzhang: Student2 init(name: String,stu: Student2) { self.name = name self.banzhang = stu } deinit { print("\(name) teacher deinit") } } var s1: Student2? = Student2(name: "ax", t: teac!)) var teac: Teacher2? = Teacher2(name: "david", stu: s1!) s1?.t = teac teac?.banzhang = s1! s1 = nil teac = nil
兩邊都是非可用類型的話,無法創建實例,會報錯
內存泄露: 當某個對象沒有用處時,還占着內存。
關於內存泄漏的話,我們寫一個例子循環強引用來看一下
class Student { var name: String var t: Teacher? init(name: String) { self.name = name } deinit { print("\(name) student deinit") } } class Teacher { var name: String var banzhang: Student? init(name: String) { self.name = name } deinit { print("\(name) teacher deinit") } } var teacher:Teacher? = Teacher(name: "cj") var bc:Student? = Student(name: "yeweidong") teacher?.banzhang = bc bc?.t = teacher teacher = nil bc = nil
這樣調用的話,不會調用兩個類的deinit()。當這兩個類沒有作用時,還是占着內存, 這就造成了內存泄漏
要解決這種情況的話,
1.使用弱引用
只需要將上述例子Teacher類的banzhang變量加上關鍵字weak,或者將Student類的t變量加上關鍵字weak。
class Student { var name: String var t: Teacher? init(name: String) { self.name = name } deinit { print("\(name) student deinit") } } class Teacher { var name: String weak var banzhang: Student? init(name: String) { self.name = name } deinit { print("\(name) teacher deinit") } } var teacher:Teacher? = Teacher(name: "cj") var bc:Student? = Student(name: "yeweidong") teacher?.banzhang = bc bc?.t = teacher teacher = nil bc = nil //yeweidong student deinit
//cj teacher deinit
這樣調用的話,會調用兩個類的deinit()。
好了,內存管理和循環引用就介紹到這里了