assign,retain,strong,weak,还有copy,这些都是一个property在声明中可以指定的属性,且都与内存管理有关。相信很多刚刚接触OC的朋友,对这些属性的引用有时还是会存在一些困惑。今天在这里主要讲讲我对这些属性的理解。
首先,我们先来谈谈对property的理解。我们通常所说的property不是一个对象,它的表现形式主要有两种:
1:代表一个简单数据类型,
2:代表一个表现对象的指针(注意:这里说的是指针,而不是对象).
assign:这是property的一个默认属性。用于 ‘基本数据类型’、‘枚举’、‘结构体’ 等非OC对象类型,比如int,float,bool等。如果这个属性被应用于一个指向对象的指针,那么当这个指针指向对象时,对象的引用计数是没有发生变化的,也就是说这个用assign修饰的property不能持有这个对象(感觉是不是和weak弱引用挺像的,不过weak引用会自动归置为nil),当对象在某个地方被释放了,这时的property可能就会成为一个悬垂指针,我们访问它指向的内存地址时,可能就会出现一些意想不到的状况。
retain:用来修饰对象的指针在MRC时使用(和strong类似)。
strong:OC对象类型(NSArray、NSDate、NSNumber、模型类),一个对象只要有强指针引用着,就不会被销毁 ,也就是我们经常说的强引用。指向对象的指针会被重新拷贝一遍,原对象的内存地址没有发生变化,引用计数+1,通俗点的理解就是指针拷贝(引用场景:类似于一条被牵着的狗,你用strong修饰一下,就相当于给这只狗又加了一条绳子,但是狗还是那条狗)。
copy:一般用在NSString*类型、block类型上。指向的对象会被重新拷贝一遍(即会重新分配一个内存地址),并给这个新建的对象引用计数设置为1,通俗点的理解就是对象拷贝(引用场景:类似于重新创造了一只狗,并给这只狗套上了一条绳)。
weak:弱引用(一般应用: UI控件,代理).类似于assign。对象销毁之后会自动置为nil,防止野指针。指向对象时,对象的引用计数不改变,即property不能持有这个对象。(引申:默认情况下,一个指针都会用__strong属性,表明这是一个强引用。那么只要引用存在,对象就不会被销毁。但是如果所有的strong类型的指针都消失以后,对象就会被释放掉,即使该对象还有__weak类型的指针指向它。同时清除掉所有剩余的weak指针。)
这里有一个很有趣的例子(也是网上看来的)分享给大家来加深一下理解:
strong类型的指针就是像是拴住的狗,只要你用绳子拴住狗,那么狗就不会跑掉。如果有5个人都牵着这一条狗(5条绳子牵一只狗),类比为5个strong类型指针指向一个对象。除非5个绳子都脱落,否则狗是不会跑掉的,类比,5个strong指针都=nil,则该对象释放。
weak型指针就像是一个小孩子指着狗喊道:“看,有一只狗在那里”,只要狗一直被拴着,那么小孩子就能看到狗 (weak指针)会一直指向它,只要狗的绳子脱落,那么狗就会跑掉,不管有多少的小孩在看着它。
以上说了那么多,主要是对各种属性的理解。那么接下来会和大家说一些我们经常所需考虑的问题;
1:strong和copy的使用
上面也说了strong和copy的区别分别是指针拷贝和对象拷贝。所以我们在使用这两种属性时要考虑到是否需要对象的值变问题。比如我们经常所使用的Model,可能它会同时被多个对象进行引用。如果我们用strong来修饰的Model,那么就可能会造成当我们在A对象改变model成员变量值时,B对象的model成员变量值也会发生改变。所以这个时候选择copy修饰就不会出现这种问题了(需要实现copyWithZone方法)。
2.strong和weak的使用
所有的引用计数系统,都存在循环应用的问题。例如下面的引用关系对象:a创建并引用到了对象b.对象b创建并引用到了对象c.对象c创建并引用到了对象b.这时候b和c的引用计数分别是2和1。当a不再使用b,调用release释放对b的所有权,因为c还引用了b,所以b的引用计数为1,b不会被释放。b不释放,c的引用计数就是1,c也不会被释放。从此,b和c永远留在内存中,造成内存浪费。这种情况,必须打断循环引用,通过其他规则来维护引用关系。这个时候当c引用b时就可以使用weak来避免循环问题。
总的来说,OC的内存管理机制就是要保证引用计数平衡,当对象释放时使引用计数为0,大于零则会造成内存泄漏。
http://ios.jobbole.com/87649/