atomic和nonatomic用来决定编译器生成的getter和setter是否为原子操作。
atomic
设置成员变量的@property属性时,默认为atomic,提供多线程安全。
在多线程环境下,原子操作是必要的,否则有可能引起错误的结果。加了atomic,setter函数会变成下面这样:{lock}
if (property != newValue) {
[property release];
property = [newValue retain];
}
{unlock}
nonatomic
禁止多线程,变量保护,提高性能。atomic是Objc使用的一种线程保护技术,基本上来讲,是防止在写未完成的时候被另外一个线程读取,造成数据错误。而这种机制是耗费系统资源的,所以在iPhone这种小型设备上,如果没有使用多线程间的通讯编程,那么nonatomic是一个非常好的选择。
指出访问器不是原子操作,而默认地,访问器是原子操作。这也就是说,在多线程环境下,解析的访问器提供一个对属性的安全访问,从获取器得到的返回值或者通过设置器设置的值可以一次完成,即便是别的线程也正在对其进行访问。如果你不指定 nonatomic ,在自己管理内存的环境中,解析的访问器保留并自动释放返回的值,如果指定了 nonatomic ,那么访问器只是简单地返回这个值。
assign
对基础数据类型 (NSInteger,CGFloat)和C数据类型(int, float, double, char)等等。
此标记说明 设置器直接进行赋值,这也是默认值。在使用垃圾收集的应用程序中,如果你要一个属性使用assign,且这个类符合NSCopying协 议,你就要明确指出这个标记,而不是简单地使用默认值,否则的话,你将得到一个编译警告。这再次向编译器说明你确实需要赋值,即使它是 可拷贝的。
retain
对其他NSObject和其子类对参数进行release旧值,再retain新值
指定retain会在赋值时唤醒传入值的retain消息。此属性只能用于Objective-C对象类型,而不能用于Core Foundation对象。(原因很明显,retain会增加对象的引用计数,而基本数据类型或者Core Foundation对象都没有引用计数——译者注)。
注意: 把对象添加到数组中时,引用计数将增加对象的引用次数+1。
copy
对NSString 它指出,在赋值时使用传入值的一份拷贝。拷贝工作由copy方法执行,此属性只对那些实行了NSCopying协议的对象类型有效。更深入的讨论,请参考“复制”部分。——————主要用于NSString类型
copy与retain:
Copy其实是建立了一个相同的对象,而retain不是:
1.比如一个NSString 对象,地址为0×1111 ,内容为@”STR”,Copy 到另外一个NSString 之后,地址为0×2222 ,内容相同。
2.新的对象retain为1 ,旧有对象没有变化retain 到另外一个NSString 之后,地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1。
总结:retain 是指针拷贝,copy 是内容拷贝。
工厂方法:
在UIKit提供的类中经常会看到static方法创建出的对象,如:NSNumber *numObj = [NSNumber numberWithInt: 1];
从设计模式的角度上讲这个static方法创建了,一个对象,这中利用公共方法创建对象的模式叫做工厂方法。
这种工厂方法返回的对象都是不需要调用者release的,因为虽然他们现在的引用计数为1,但是他会自动释放。(因为他们在返回对象的时候都对其调用了autorelease)
四、声明一个property,利用assign, retain或者copy
利用property可以快速创建一个属性
利用property创建一个属性之后,根据设置(assign, retain或者copy)系统生成的Setter和Getter是不同的。(以NSString为例)
在调用self.name进行赋值时会调用setter(setName:)在进行取值时会调用getter(getName)
公用部分:
@property (nonatomic, XXXX) NSString *name;
// .m文件
@synthesize name = _name;
_name = newName;
}
- (NSString *) getName {
return _name;
}
_name = [newName retain]; // 将新的对象引用计数加一
}
- (NSString *) getName {
return _name;
}
3.如果XXXX是copy,系统会自动生成setter和getter如下:
if (_name != newName) {
[_name release]; // 旧的对象引用计数减一
_name = [newName copy]; // 将新的对象引用计数加一 ,
}
}
- (NSString *) getName {
return _name;
}
如果是用retain和copy声明的属性,有一些场景需要直接对_name执行释放(如需要立即释放内存的dealloc,关掉网络请求等),这时要直接调用[_name release]将内存释放,并且将_name变量设置为nil。
[_name release], _name = nil;
}
// 或者
self.name = nil;
// 错误的方式
if(_name != nil) {
[_name release]; // _name引用计数为0,_name 所指被释放
}
self.name = nil; // 这里肯定崩溃, 因为在前面,_name已经被release了。
// 但由于_name没有赋值为nil,变成了野指针。
// 前面说过,self.name执行的setter会先将
// 旧的_name执行release,这时造成崩溃。
摘自http://www.189works.com/article-69133-1.html
自上,在释放时,用[self.aa release] 是错误的,置空时也不要用self.aa = nil 以防aa本来就release过了,self.调用时通过set方法再此release而早上崩溃
所有self就是 释放就的retain新的,所以慎用
(以上自解)