您的位置:首页 >> APPLE >> 和屌丝一起学SWIFT-自动引用计数(ARC)
和屌丝一起学SWIFT-自动引用计数(ARC)
[ 孤狼 | 2016-04-28 11:13:03 | APPLE ]

声  明

       本教程仅用于初学SWIFT同学使用,内容由本人(孤狼)学习过程中笔记编写,本教程使用SWIFT版本为2.0。本教程内容可以自由转载,但必须同时附带本声明,或注明出处。PAEA.CN版权所有。


欢迎回到和屌丝一起学SWIFT系列教程,上节我们说了析构过程,大家有没有和构造过程连起来做实验呢.这节我们来一起学习一个在开发中很重要的知识,自动引用计数(ARC),可别小看这个知识点,他可是保证你程序不崩溃的前提.

 

 

 

自动引用计数(ARC)


SWIFT中会使用自动引用计数(ARC)来跟踪管理应用内存,当检测到一个类的实例不会再被使用的时候,就会自动去释放这个实例所占用的内存.一般情况这个过程是自动的,不需要人为参与,不过,总有不起作用的时候.所以学习他还是很有意义的.

 

 

[工作机制]

每当你实例化操作的时候,ARC就会自动为你分配一个内存空间用来存放信息.如果检测到你不会在使用这个实例的时候,就会自动的回收这部分内存空间,避免内存被占用.不过如果你的实例空间被回收,那么你将无法使用这个实例,一旦使用,直接崩溃,丝毫不顾及你的颜面.当然,为了保证这种让你扫面子的事情发生,ARC会一直监测实例使用动态,哪怕只有一个引用,ARC都不会去动你的实例.为了保证这个监测一直存在,不论你把实例赋值给常量,变量等都会采用强引用的方式.换句话说,引用在,实例在.

 

为了能看到实例是否被销毁,我们在析构器中输出一句话.

class A{
    init(){
        print("实例创建了");
    }
    deinit{
        print("实例销毁");
    }
}
//为了能够销毁实例,我们依然使用一个可选类型来创建实例
var a1:A?;
var a2:A?;
var a3:A?;
//开始创建实例
a1=A();     //输出"实例创建了"
//接下来,我们把这个实例引用出去,因为都是一个实例,所以这里不会再次调用A的构造器.
a2=a1;
a3=a2;
//接着我们开始销毁
a2=nil;     //我们销毁了a2的引用,不过没有任何反应,因为实例的强引用还有a1和a3
//我们继续销毁a1
a1=nil;     //这个时候,我们的强引用还剩a3,不过只要用一个引用都不会销毁哦.
//我们全部销毁看看.
a3=nil;     //输出"实例销毁"

 

上面的测试我们可以看到,强引用只要存在就不会销毁实例.如果都不使用了,那么就会自动释放空间销毁实例.

 

 

[循环强引用]

如果我们只是很简单的用过就销毁,那么ARC就能帮我们直接处理后事.但是一旦代码量大了,就不能保证是否会出现循环强引用的情况,这种情况下ARC是不能自动销毁的,因为你无法把引用降到0.

class B{
    var bb:C?;
    init(){
        print("B创建了");
    }
    deinit{
        print("B销毁了");
    }
}
class C{
    var cc:B?;
    init(){
        print("C创建了");
    }
    deinit{
        print("C销毁了");
    }
}
var b:B?=B();     //输出"B创建了"
var c:C?=C();     //输出"C创建了"
//接着,我们因为业务需要他们之间互相引用.
b?.bb=c;
c?.cc=b;
//用完之后我们销毁b和c
b=nil;          //无输出
c=nil;          //无输出

 

这时,我们看到,虽然我们销毁了bc,但是因为实例之间的相互强引用,导致无法被ARC释放,永远占用着我们宝贵的内存,一旦这种操作多来几次,game over.所以,我们在实际使用中,应该尽量避免这种循环强引用的情况发生.上面我们看到,如果我们用了循环强引用,那么内存无法被正确回收,但是如果业务需要又不得不那么做,怎么处理呢?这时我们就需要弱引用和无主引用来帮忙了.

 

[弱引用]

弱引用不会对实例保持强引用,所以不违背ARC回收规则,用来确保回收的正常进行.我们使用关键字 weak 来声明弱引用.在实例使用过程中,如果一下引用可能会没有值,那么我们可以使用弱引用.

class B{
    weak var bb:C?;
    init(){
        print("B创建了");
    }
    deinit{
        print("B销毁了");
    }
}
class C{
    weak var cc:B?;     //这里我们使用弱引用.
    init(){
        print("C创建了");
    }
    deinit{
        print("C销毁了");
    }
}
var b:B?=B();     //输出"B创建了"
var c:C?=C();     //输出"C创建了"
//接着,我们因为业务需要他们之间互相引用.
b?.bb=c;
c?.cc=b;
//用完之后我们销毁b和c
b=nil;          
//检测到c对b的引用只是弱引用,b不存在强引用了,所以可以销毁b,输出"B销毁了",
//同时检测到弱引用cc的存在,所以cc被变为nil
c=nil;          
//检测到b已经被销毁,bb引用已经不存在,所以不存在强引用,可以销毁c,输出"C销毁了"

 

TIP:弱引用情况下,如果一个引用被销毁,那么ARC会赋值nil来表示不存在,所以引用必须是变量类型.同时我们也要注意弱引用的使用,因为是弱引用,一旦对象没有强引用则会被释放,可能会出现意想不到的提前释放问题.

 

 

[无主引用]

无主引用和弱引用类似,但是无主引用是一直有值的,我们使用关键字 unowned 来声明一个无主引用.因为无主引用是一直有值的,所以要用非可选类型来定义.

class B{
    var bb:C?;
    init(){
        print("B创建了");
    }
    deinit{
        print("B销毁了");
    }
}
class C{
    unowned var cc:B;     //这里我们使用无主引用.
    init(x:B){
        print("C创建了");
        cc=x;
    }
    deinit{
        print("C销毁了");
    }
}
var b:B?=B();       //输出"B创建了"
b?.bb=C(x:b!);      //输出"C创建了" 同时cc无主引用到b
//用完之后我们销毁b
b=nil;              //输出"B销毁了,C销毁了"
//b没有强引用,开始销毁.销毁后,因为c失去了强引用而自动销毁.

 

本节代码下载

转载请注明出处:http://gl.paea.cn/apple/content/2016/04/28/97.html