IOS学习笔记之属性方法的选择

object-c有三种property accessorsassignretaincopy,这里分别说明三种属性方法的实现和区别。

assign:就是简单的赋值。

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

但是非类数据,delegate,子view保存父view的句柄等等通常选择的是这个方法. intbool之类的数据不必多说。这里说明下delegate为什么通常选择assign作为属性方法。假设有一个table controller上面有一个table,毫无疑问的,controllerretain住这个table,并在deallocrelease这个table,如果tabledelegate是这个controller,并且也retain了它。那么controller就只有在celldealloc时才会被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

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

 

Assign

对基础数据类型(NSIntegerCGFloat)和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,旧有对象没有变化,retain 到另外一个NSString 之后,地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain+1,也就是说,retain 是指针拷贝,copy 是内容拷贝。

 

 

@property (nonatomic, assign) NSString *title; 
什么是assigncopyretain之间的区别? 

assign
:简单赋值,不更改索引计数(Reference Counting)。 
copy
:建立一个索引计数为1的对象,然后释放旧对象 
retain
:释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为
retain
的实际语法为: 

- (void)setName:(NSString *)newName { 
    if (name != newName) { 
       [name release]; 
       name = [newName retain]; 
       // name’s retain count has been bumped up by 1 
    } 

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

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

使用assign: 对基础数据类型(NSIntegerCGFloat)和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

        对基础数据类型(NSIntegerCGFloat)和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
retain 
到另外一个NSString 之后,地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain+1
也就是说,retain 是指针拷贝,copy 是内容拷贝。

      禁止多线程,变量保护,提高性能
       atomicObjc使用的一种线程保护技术,基本上来讲,是防止在写未完成的时候被另外一个线程读取,造成数据错误。而这种机制是耗费系统资源的,所以在iPhone这种小型设备上,如果没有使用多线程间的通讯编程,那么nonatomic是一个非常好的选择。
指出访问器不是原子操作,而默认地,访问器是原子操作。这也就是说,在多线程环境下,解析的访问器提供一个对属性的安全访问,从获取器得到的返回值或者通过设置器设置的值可以一次完成,即便是别的线程也正在对其进行访问。如果你不指定 nonatomic ,在自己管理内存的环境中,解析的访问器保留并自动释放返回的值,如果指定了 nonatomic ,那么访问器只是简单地返回这个值

 

个人总结,求验证:

atomic 原子性,线程安全,默认,会影响效率。
nonatomic 非原子性,线程不安全的,推荐使用,效率较高。

猜测atomic 内部实现如下:

@property(retain) UITextField *userName自动生成的代码


- (UITextField*) userName{
          UITextField *retval = nil; 
          @synchronized(self){
                  retval = [[userName retain] autorelease];
          }    
          return retval;


- (void) setUserName:(UITextField*)userName_{ 
           @synchronized(self){ 

                    if(userName == userName_)

                           return;
                    [userName release]; 
                    userName = [userName_ retain]; 
            } 
}

 

posted @ 2013-01-12 18:11  妙笔  阅读(501)  评论(0编辑  收藏  举报