【每天总结一个ios开发心得】对于Retain和Assign属性的理解

来源:互联网 发布:淘宝怎么天天特价 编辑:程序博客网 时间:2024/06/04 17:41

http://bbs.9ria.com/thread-203030-1-1.html

比如我要定义一下字符串var:

  1. NSString *var;
复制代码

声明Property时,

  1. @property(nonamtic,assign)NSString *var;
复制代码

将属性声明为Assign,当使用@Synthsize生成Getter和Setter方法后,我们就可以用“.”操作符来为var赋值,

将属性声明为Assign时,Setter方法的实现是这样的:

  1. -(void)setter: (NSString*)str
  2. {
  3.    var=str;
  4. }
  5. var=[[NSString alloc]initWithString: @"aaa"];
复制代码


当我们这样用时,没有调用Setter方法,只是将var指向目标地址,这时

NSLog(@“%d”,[var retainCount]);的值会是1。

如果我们这样写:self.var=[[NSString alloc]initWithString:"aaa"];

这时会调用setter方法,但是NSLog(@“%d”,[var retainCount]);的值仍然是1。

如果我们在设置属性时这样来设置:

  1. @property(nonamtic,retain)NSString *var;
复制代码

这时,自动生成的Setter方法是这样的:

  1. -(void)Setter:(NSString*)str

  2.   [str retain];
  3.   [var release];
  4.   var=str;
复制代码

这样就一目了然了,也就是被设置为retain属性的方法,在生成Setter方法时,先将要赋的值的引用计数加1,然后将var指向的对象release。再后才是将str赋值给var。这时下面的代码的输出结果会是2,因为,在Setter中[[NSString alloc]initWithString:"aaa"]所指的内存区域的retain被加了1,然后var又指向这个区域,所以var的retainCount自然就为2了:
  1. self.var=[[NSString alloc]initWithString: @"aaa"];
  2. NSLog(@“%d”,[var retainCount]);
复制代码


这样做是为了防止内存被过渡释放,比如,[[NSString alloc]initWithString:"aaa"]这个内存区域不光有var指向,还有另外一个变量var2也指向这个区域,如果我们不设置成retain属性,在执行var=[[NSString alloc]initWithString:"aaa"];后,var和var1都指向一个共同的内存区域,但这个内存区域的retainCount为1。如果在另一个地方执行了[var2 release];这样[[NSString alloc]initWithString:"aaa"]所指的内存区域的retainCount为0,所以这个内存区域就被释放了,var也就成了野指针,这时再引用var将会出现内存错误。


但是,需要特别注意的是,即使我们设置var的属性为retain,如果我们在为var赋值时,使用的是如下形式:

  1. var=[[NSString alloc]initWithString: @"aaa"];
复制代码


而不是:

  1. self.var=[[NSString alloc]initWithString: @"aaa"];
复制代码


这样retain属性是不起作用的,前面不加self.,相当于我们定义的属性还是assign。retainCount不会加1的。

我个人对这个的理解是,如果不显示的使用"."操作符,Setter方法是不调用的,仅仅是指针的传递。

今天又有了点新的想法,补充一下:


"."操作符在OBJC中是方法的调用,比如:self.str和[self str]是一样的。如果我在.h文件中声明了一个方法:

  1. -(void)method;
复制代码

那么,我调用这个方法可以用两种方式:[self method]或self.method。



这样说的话,我们为什么可以用诸如self.str这样的形式来表示一个变量呢,原因就在于OBJC中变量属性的机制。



我们前面说过,定义一个变量str,加个assign或retain之类的属性后,再用@synthesize就可以生成相应的setter和getter方法了。这样,对于一个变量,就有了相应的赋值方法,于是,对于self.str这样的写法,实际上就是调用了str对应的setter或getter方法。换句话说,也是把setter或getter消息发送给和str。str这时就是一个方法名,而不仅仅是变量名了。



所以如果我们没有对一个变量声明属性,也没有@synthesize来生成setter和getter方法,那么我们就不能用self.str这种形式,而只能用str=@"aaa",或者str1=str这样的形式来使用变量。



于是也就有了我们前面的结论:用self.str这种形式,相当于调用setter或getter方法。也就会执行retain的操作。不用这种形式,就没用调用setter或getter方法,retain的操作也就无从谈起。

0 0