当把属性的语义特性分别声明为assign,retain,copy时, 自动生成setter, getter方法内部实现
假定有一个车类Car.h中定义三个属性
@property (nonatomic, retain) NSString * brand; //品牌
@property (nonatomic, copy) NSString * colour; //颜色
@property (nonatomic, assign) CGFloat price; //价格
以下是把属性的语义特性分别声明为assign,retain,copy时, 自动生成setter, getter方法内部实现:
//当把属性的语义特性声明为retain时,自动生成setter方法内部实现
- (void)setBrand:(NSString *)brand
{
if (_brand != brand) {//如果旧值不等于新值
[_brand release];//旧值先release
_brand = [brand retain];//新值retain赋值给旧值
}
}
//当把属性的语义特性声明为retain时,自动生成getter方法内部实现
- (NSString *)brand
{
return [[_brand retain] autorelease];
}
//当把属性的语义特性声明为copy时,自动生成setter方法内部实现
- (void)setColor:(NSString *)color
{
if (_color != color) {
[_color release];
_color = [color copy];
}
}
//当把属性的语义特性声明为copy时,自动生成getter方法内部实现
- (NSString *)color
{
return [[_color retain] autorelease];
}
//当把属性的语义特性声明为assign时,自动生成setter方法内部实现
- (void)setPrice:(CGFloat)price
{
_price = price;
}
//当把属性的语义特性声明为assign时,自动生成getter方法内部实现
- (CGFloat)price
{
return _price;
}
比如我要定义一下字符串var:
声明Property时,
将属性声明为Assign,当使用@Synthsize生成Getter和Setter方法后,我们就可以用“.”操作符来为var赋值,
将属性声明为Assign时,Setter方法的实现是这样的:
当我们这样用时,没有调用Setter方法,只是将var指向目标地址,这时
NSLog(@“%d”,[var retainCount]);的值会是1。
如果我们这样写:self.var=[[NSString alloc]initWithString:"aaa"];
这时会调用setter方法,但是NSLog(@“%d”,[var retainCount]);的值仍然是1。
如果我们在设置属性时这样来设置:
这时,自动生成的Setter方法是这样的:
这样做是为了防止内存被过渡释放,比如,[[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赋值时,使用的是如下形式:
而不是:
这样retain属性是不起作用的,前面不加self.,相当于我们定义的属性还是assign。retainCount不会加1的。
我个人对这个的理解是,如果不显示的使用"."操作符,Setter方法是不调用的,仅仅是指针的传递。
今天又有了点新的想法,补充一下:
"."操作符在OBJC中是方法的调用,比如:self.str和[self str]是一样的。如果我在.h文件中声明了一个方法:
那么,我调用这个方法可以用两种方式:[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的操作也就无从谈起。
如果你用self._myObject = aMyObject; 或者 myObject = aMyObject; 你会得到一个错误, 为什么呢, 这里就是和Obj-c的存取方法有关了. 说白了很简单 , 大家都知道, @property (nonatomic, retain) MyObject *myObject; 是为一个属性设置存取方法, 只是平时我们用的方法名和属性名是一样的,现在你把它写成不同的名字, 就会很清楚了. _myObject是属性本身, myObject是存取方法名.
顺便说一下, 如果你想在其它类访问对象属性, 而不是通过存取方法, 你可以用myClass -> myObject来访问, 这样是直接访问对象本身, 不过你先要把myObject设成@public. 但这个是官方不提倡的