您的位置:首页 > 移动开发 > IOS开发

iOS笔记:属性方法的选择

2014-09-02 14:09 183 查看
object-c有三种property accessors:assign,retain,copy,这里分别说明三种属性方法的实现和区别。

assign:就是简单的赋值。

这种方法对于传入的参数,没有做任何处理,无法保证传入的数据不会被release,所以一般的类对象,比如NSString,通常不会选择这种类型的方法。

但是非类数据,delegate,子view保存父view的句柄等等通常选择的是这个方法. int,bool之类的数据不必多说。这里说明下delegate为什么通常选择assign作为属性方法。假设有一个table
controller上面有一个table,毫无疑问的,controller会retain住这个table,并在dealloc中release这个table,如果table的delegate是这个controller,并且也retain了它。那么controller就只有在cell被dealloc时才会被release,这就导致了循环引用。

子view保存父view也是同样的道理,只能使用assign。

assign的具体实现看下面:

- (SomeVariable)someValue

{

return someValue;

}

- (void)setSomeValue:(SomeVariable)aSomeVariableValue

{

someValue = aSomeVariableValue;

}

retain方法:赋值的基础上,retain传入的数据

先看一种具体的实现(编译器自动生成的未必如此,但是原理是一样的):

- (void)setSomeInstance:(SomeClass*)aSomeInstanceValue

{

if(someInstance == aSomeInstanceValue)

{

return;

}

SomeClass*oldValue = someInstance;

someInstance = [aSomeInstanceValueretain];

[oldValuerelease];

}

- (SomeClass*)someInstance

{

return[[someInstanceretain]autorelease];

}

这里需要注意的是首先set方法中首先比较了数据是否相同。

copy方法:拷贝生成了一份的数据

之所以需要copy方法,先看下面的例子,

NSMutableString*mutableString = [NSMutableStringstringWithString:@"initial value"];

[someObject setStringValue:mutableString];

[mutableString setString:@"different value"];

someObject完全无法得知传入的数据发生了变化,最典型的例子就是NSDictionary,

比如,NSDicionary的key,通常是一个NSString,如果这个NSString是NSMutableString,那么这个key就可能发生变化,NSDicionay就可能无法找到这个key对应的value,造成memory
leak,所以NSDictioary的key的属性方法,使用的就是copy。

Assign

对基础数据类型(NSInteger,CGFloat)和C数据类型(int, float, double, char, 等等)

此标记说明设置器直接进行赋值,这也是默认值。在使用垃圾收集的应用程序中,如果你要一个属性使用assign,且这个类符合NSCopying协议,你就要明确指出这个标记,而不是简单地使用默认值,否则的话,你将得到一个编译警告。这再次向编译器说明你确实需要赋值,即使它是可拷贝的。

retain

对其他NSObject和其子类    对参数进行release旧值,再retain新值

指定retain会在赋值时唤醒传入值的retain消息。此属性只能用于Objective-C对象类型,而不能用于Core Foundation对象。(原因很明显,retain会增加对象的引用计数,而基本数据类型或者Core
Foundation对象都没有引用计数——译者注)。

copy

对NSString 它指出,在赋值时使用传入值的一份拷贝。拷贝工作由copy方法执行,此属性只对那些实行了NSCopying协议的对象类型有效。更深入的讨论,请参考“复制”部分。

注释:

Copy其实是建立了一个相同的对象,而retain不是:比如一个NSString 对象,地址为0×1111 ,内容为@”STR”,Copy到另外一个NSString 之后,地址为0×2222 ,内容相同,新的对象retain为1 ,旧有对象没有变化,retain 到另外一个NSString 之后,地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1,也就是说,retain是指针拷贝,copy 是内容拷贝。

@property (nonatomic, assign) NSString *title;

什么是assign,copy,retain之间的区别?

assign:简单赋值,不更改索引计数(Reference Counting)。

copy:建立一个索引计数为1的对象,然后释放旧对象

retain:释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1

retain的实际语法为:

- (void)setName:(NSString *)newName {

if (name != newName) {

[name release];

name = [newName retain];

// name’s retain count has been bumped up by 1

}

}

说了那么麻烦,其实接下来的话最重要:

如果你不懂怎么使用他们,那么就这样 ->

使用assign: 对基础数据类型(NSInteger,CGFloat)和C数据类型(int,
float, double, char, 等等)

使用copy:对NSString

使用retain:对其他NSObject和其子类

nonatomic关键字:

atomic是Objc使用的一种线程保护技术,基本上来讲,是防止在写未完成的时候被另外一个线程读取,造成数据错误。而这种机制是耗费系统资源的,所以在iPhone这种小型设备上,如果没有使用多线程间的通讯编程,那么nonatomic是一个非常好的选择。

使用@property配合@synthesize可以让编译器自动实现getter/setter方法,使用的时候也很方便,可以直接使用对象.属性的方法调用;

如果我们想要对象.方法的方式来调用一个方法并获取到方法的返回值,那就需要使用@property配合@dynamic了。

其实使用@dynamic关键字是告诉编译器由我们自己来实现访问方法。如果使用的是@synthesize,那么这个工作编译器就会帮你实现了。

readonly

此标记说明属性是只读的,默认的标记是读写,如果你指定了只读,在@implementation中只需要一个读取器。或者如果你使用@synthesize关键字,也是有读取器方法被解析。而且如果你试图使用点操作符为属性赋值,你将得到一个编译错误。

readwrite

此标记说明属性会被当成读写的,这也是默认属性。设置器和读取器都需要在@implementation中实现。如果使用@synthesize关键字,读取器和设置器都会被解析。

assign

对基础数据类型(NSInteger,CGFloat)和C数据类型(int, float, double, char, 等等)

此标记说明设置器直接进行赋值,这也是默认值。在使用垃圾收集的应用程序中,如果你要一个属性使用assign,且这个类符合NSCopying协议,你就要明确指出这个标记,而不是简单地使用默认值,否则的话,你将得到一个编译警告。这再次向编译器说明你确实需要赋值,即使它是可拷贝的。

retain

对其他NSObject和其子类    对参数进行release旧值,再retain新值

指定retain会在赋值时唤醒传入值的retain消息。此属性只能用于Objective-C对象类型,而不能用于Core Foundation对象。(原因很明显,retain会增加对象的引用计数,而基本数据类型或者Core
Foundation对象都没有引用计数——译者注)。

copy

对NSString 它指出,在赋值时使用传入值的一份拷贝。拷贝工作由copy方法执行,此属性只对那些实行了NSCopying协议的对象类型有效。更深入的讨论,请参考“复制”部分。

注释:

Copy其实是建立了一个相同的对象,而retain不是:

比如一个NSString 对象,地址为0×1111 ,内容为@”STR”

Copy 到另外一个NSString 之后,地址为0×2222 ,内容相同,新的对象retain为1

retain 到另外一个NSString 之后,地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1

也就是说,retain 是指针拷贝,copy 是内容拷贝。

禁止多线程,变量保护,提高性能

atomic是Objc使用的一种线程保护技术,基本上来讲,是防止在写未完成的时候被另外一个线程读取,造成数据错误。而这种机制是耗费系统资源的,所以在iPhone这种小型设备上,如果没有使用多线程间的通讯编程,那么nonatomic是一个非常好的选择。

指出访问器不是原子操作,而默认地,访问器是原子操作。这也就是说,在多线程环境下,解析的访问器提供一个对属性的安全访问,从获取器得到的返回值或者通过设置器设置的值可以一次完成,即便是别的线程也正在对其进行访问。如果你不指定 nonatomic ,在自己管理内存的环境中,解析的访问器保留并自动释放返回的值,如果指定了 nonatomic ,那么访问器只是简单地返回这个值

个人总结,求验证:

atomic 原子性,线程安全,默认,会影响效率。

nonatomic 非原子性,线程不安全的,推荐使用,效率较高。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: