浅谈swift中的内存管理

痞子三分冷 提交于 2020-01-28 13:31:06

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

好了,内存管理和循环引用就介绍到这里了

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!