renren: www.renren.com/leonardozhang
1.在oc中,对象也具有生命周期。其也有产生、生存(接受消息和执行操作)、交友(借助方法的组合和参数)、死去等属性。
2.Cocoa采用引用计数(reference counting)技术,来判断该对象是否达到生命周期终结。当某段代码需要访问一个对象时,该对象的reference counting 加一,当这段代码访问结束之后,rc 减1,当rc为0的时候,表示该对象不再有代码访问,可以被销毁,其占用的内存将被系统回收以便重用。
3.当使用alloc、new、copy方法创建对象时,其reference counting将被设置为1。使用retain,可以是reference counting加1,使用release 可以减少对象的保留计数器值。
4.当reference counting为0时,oc自动向对象发送一条dealloc消息。当然,你可以在类中重写该方法,以释放全部的资源。但是记住,一定不要调用dealloc函数。可以通过系统提供的一些方法,间接调用。查看reference counting,可以通过retainCount消息。
如现实世界一样,对象也有所属关系,如果一个对象具有指向其他对象的实例变量,则该对象拥有这些对象。同样,如果在一个函数中创建了一个对象,则称该函数拥有他创建的这个对象。
经常对遇到类似以下的情况:
main()
{
...
[car setEngin:engin];
...
}
那么engin是属于main函数,还是car对象呢?如果是属于main函数,则main函数需要决定engin什么时候释放,但显然engin还在car对象中,这样main函数就不知道什么时候去释放该对象,显然engin不属于main()函数,或者更确切的说是engin不仅仅属于main()函数。
如果engin属于car对象,情况和刚刚所述类似,所以engin不仅仅属于他们中的任意一个。
其实在setEngin时,engin的reference counting已经+1,这样由main()函数负责释放一次,由engin函数负责释放一次。(此处需要验证,参考例子1,之后会设计一个程序来验证如上所述。)
首先给出设置器的三种写法:
普通青年
- (void) setEngin:(Engin *)newEngine
{
[engin release];
engin = [newEngin retain];
}
文艺青年
- (void)setEngin:(Engin *) newEngin
{
[newEngin retain];
[engin release];
engin = [newEngin retain];
}
2B青年
-(void) setEngin:(Engin *) newEngin
{
engin = [newEngin retain];
}
首先解释2B青年,确实2到不想解释。
Engin *engin1 = [Engin new]; //count:1
[car setEngin: engin1]; //count:2
[engin1 release]; //count:1
如上面的注释,计数器最终没有清零,应为2B青年对newEngin retain但是没有release。造成内存泄露!!!
下面看看普通青年:
普通青年虽然首先对newEngin release了,但是如果有如下情况,普通青年比2B青年更2:
Engin *engin2 = [Engin new];
[car2 setEngin:[car1 engin]];
这次car2把car1的engin release了,这是计数器已经成0,即car1的engin已经被释放。然后又调用car1的engin赋值,这次直接造成崩溃。
最后看看文艺青年是怎么文艺的:
首先文艺青年先将newEngin 计数器加一,然后去释放engin,这样不管engin和newEngin是不是一个对象,都没有关系,因为先+1了,保证肯定大于等于2,然后去releae engin,在赋值。