淺談swift中的內存管理


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()。

好了,內存管理和循環引用就介紹到這里了

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM