zoukankan      html  css  js  c++  java
  • objective-C: nonatomic retain copy assgin 等属性详解

    http://my.oschina.net/u/728866/blog/90798


    property,可以提供的功能有:提供成员变量的访问方法的声明、控制成员变量的访问权限、控制多线程时成员变量的访问环境 )。

    property不但可以在interface,在协议protocol .和类别category中也可以使用.

    synthesize的理解是:实现property所声明的方法的定义。

    其实说直白就像是:property声明了一些成员变量的访问方法 ,synthesize则定义了由property声明的方法。他们之前的对应关系是

      property 声明方法 ----------》 头文件(.h)中申明的方法

     synthesize定义方法---------》Cpp文件(.m)中定义的方法

    不过这里还有有一点细微的差别,后面我会讲到。


    先讲property

    大家都知道:@property(attribute1 , attribute2, ...])是@property的他的官方表达方式,所以看到attribute1, attribute2,你就应该懂的, 他的用法不是很简单。下面就对他的属性列表进行分类介绍:

    下面对属性列表进行一下简单的介绍,后续会用代码来解释。

    1.可读性:readonly 、readwrite

    @property(readwrite,....) valueType value;

    这个属性是变量的默认属性,就是如果你(readwrite and readonly都没有使用,那么你的变量就是readwrite属性),通过加入readwrite属性你的变量就会有get方法,和set方法。

    property(readonly,...) valueType value;

    这个属性变量就是表明变量只有可读方法,也就是说,你只能使用它的get方法。

    2,assign,setter方法直接赋值,不进行任何retain操作,为了解决原类型与环循引用问题对基础数据类型 。

    3,retain,setter方法对参数进行release旧值再retain新值,所有实现都是这个顺序

    4,copy,setter方法进行Copy操作,与retain处理流程一样,先旧值release,再Copy出新的对象,retainCount为1。这是为了减少对上下文的依赖而引入的机制。

    5  相对原文进行了修改,更便于理解.

    a ) atomic的意思就是setter/getter这个函数是一个原语操作。当设置了多线程操作时,如果有两个以上线程同时调用setter的话,不会出现某一个线程执行setter全部语句之前,另一个线程开始执行setter情况,相当于函数头尾加了锁,以保证多个线程取到的东西的一致性.
    b ) nonatomic不保证setter/getter的原语行,所以多线程调用时可能取到东西并不一致,比如setter函数里面改变两个成员变量,如果你用nonatomic的话,getter可能会取到只更改了其中一个变量时候的状态,这样取到的东西会有问题。

    如果不需要多线程支持的话,当然nonatomic就够用了,另外由于不涉及锁操作,所以它执行相对快点.

    注意,如果不加此属性,则默认是两个访问方法都为原子型事务访问。锁被加到所属对象实例级.

    所以 不加nonatomic对与多线程是安全的 。


    其实他们都可以用代码表示:

    1.nonatomic 和 atomic

    @property(nonatomic ) NSObject* test1;

    @synthesize test1;

    上面两句代码,表示我们对test1的访问,是非多线程安全的。

    @property(atomic) NSObject* test1;

    @synthesize test1;

    上面两句代码,表示我们对test1的访问,是多线程安全的。其实也就是在讲该成员变量放到互斥代码中,例如,下面进行加锁。

    [_internal lock]; // lock using an object-level lock 
    id result = [[value retain] autorelease]; 
    [_internal unlock]; 
    return result;

    就如上面所说 ,这两个属性,是出于对多线程条件下 ,对test1的访问安全。如果你的程序的成员变量不存在安全问题,用nonatomic 就好,因为这样不要在访问是进行互斥,效率更高。

     

    2. readonly 、readwrite (注,后续过程我们都会加入nonatomic 属性,因为它是十分普遍的

    2.1 readonly 

    @property(nonatomic  ,readonly) NSObject* test1;

    @synthesize test1;

    上面的两句代码,objc编辑器将会为我们翻译为:

    @property(nonatomic  ,readonly) NSObject* test1; 等同

    -(NSObject*)test1;

    @synthesize test1;等同

    -(NSObject*)test1

    {

     return test1;

    }

    2.2 readwrite 

    @property(nonatomic  ,readwrite ) NSObject* test1;

    @synthesize test1;

    上面的两句代码,objc编辑器将会为我们翻译为:

    @property(nonatomic  ,readwrite ) NSObject* test1; 等同

    -(NSObject*)test1;

    -(void)settest1(NSObject* other);

    @synthesize test1;等同

    -(NSObject*)test1

    {

     return test1;

    }

    -(void)settest1(NSObject* other);

    {

     test1 = other;

    }

    这里要说明一下, readonly 、readwrite 这两个属性他们的真正价值,不是提供成员变量访问接口,而是控制

    成员变量的访问权限。所以要抓住他们真正价值。

    3. assign

    @property(nonatomic  ,assign) NSObject* test1;

    @synthesize test1;

    上面两句:objc编辑器将会翻译如下:

    @property(nonatomic  ,assign) NSObject* test1;等同

    -(void)settest1(NSObject* other);

    @synthesize test1;

    -(void)settest1(NSObject* other);等同

    {

     test1 = other;

    }

    4. retain

    @property(nonatomic  ,retain) NSObject* test1;

    @synthesize test1;

    objc编辑器翻译如:

    @property(nonatomic  ,retain) NSObject* test1;等同

    -(NSObject*)test1;

    -(void)settest1(NSObject* other);

    @synthesize test1; 

    -(NSObject*)test1

    {

     return test1;

    }

    -(void)settest1(NSObject* other)

     {  

      if (test1!= other)

        {

                       [test1release];

                       test1= [otherretain];

         }

    }

     

    5. copy

    @property(nonatomic  ,copy) NSObject* test1;

    @synthesize test1;

    objc编辑器将翻译如:

    @property(nonatomic  ,copy) NSObject* test1;

    -(NSObject*)test1;

    -(void)settest1(NSObject* other);

    @synthesize test1;

    -(NSObject*)test1

    {

     return test1;

    }

    -(void)settest1(NSObject* other);

    {

        if (test1!=other) { 
            [test1release]; 
            test1= [othercopy]; 
        } 

    }

    对于Copy属性有一点要主要,被定义有copy属性的对象必须要符合NSCopying协议,并且你还必须实现了

    -(id)copyWithZone:(NSZone*)zone该方法

     

     

    代码才是王道:都是一些简单代码用例

    //为了更具有普遍性,我选择用自定义对象testObj 

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    //testObj .h

    @interface testObj : NSObject<NSCopying>{
        
    }
    @end 
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    //testObj .m

    -(id)copyWithZone:(NSZone *)zone
    {
        testObj* pObj = [[testObj allocWithZone:zone] init];
        return pObj;
    }
    @end

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    //testApp是包含多个testObj 对象指针

    //testApp .h
    @interface testApp :
    {
        testObj*  test1;
        testObj*  _test2;
    }

    @property(nonatomic , retain) NSObject* test1;
    @property(nonatomic , copy) NSObject* test2;

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    //testApp.m

    @synthesize test1;

    @synthesize test2 = _test2;

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    @synthesize test2 = _test2; //对这里要特别主要一下,这里可以看作是一种别名机制,这点和前面类比的C++头文件和Cpp文件不同。

    例如对于setter函数,objc编辑器将会按如下方式翻译

    如果是@synthesize _test2;

    setter函数将是这种形式:

    -(void)set_test2(NSObject*); //注意中间的下划线

    写成@synthesize test = _test2;

    setter函数将是这种形式:
     -(void)settest2(NSObject*);// _test2 被 test2替换了

    可以看出这种别名机制,感觉是规范书写(其实更像是规范Objc的书写,大家可以看看官方文档中,成员变量都是前面带下滑线的(如_test2),所以才搞了这样一个别名规范代码中的书写)

    //下面是一个功能函数,

    -(void )test

    {

    test1 = [[testObj alloc]init];// test1  retainCount  =1;

    //下面有三种对test2操作方法:

      _test2 = test1; //这里是将test1的指针赋值给_test2指针,注意,并没有调用test2的setter方法 ,所以test retainCount  = 1、 test2 retainCount  = 0;

      self.test2 = test1; //这里调用test2的Copy方法,因此这是test retainCount  = 1、 test2 retainCount  = 1; 

      test2   = test1;

     //这段代码系统将会提示出错说test2没有定义。因为这里编译器认为是一条赋值表达式,将test2看作是一个成员变量,而在我们的testApp 中是没有这个成员变量的,这里要区别我们所说的别名,别名机制可以看作是在调用setter或者getter函数才会起作用,而这里只是一个简单的赋值, 也就出现未定义的错误。如果没有理解,你就记住要调用setter或者getter函数,就用"self.成员变量"这种形式就行了.

    //我们把  test2   = test1这行代码注释掉,保证程序继续执行

        [test1 release];  // 释放test1 ,test1 retainCount  = 0;
        
        [test2 release]; // 释放test2 ,test2 retainCount  = 0;

    }

    @end

  • 相关阅读:
    异常响应配置
    用户模块自定义
    数据库配置
    虚拟环境搭建
    SDK Manager failed to install 'java.exe' locking directory
    AndroidUI自动化测试工具-UIautomator
    Android自动化压力测试快速入门教程(图解)——MonkeyRunner
    adb 常用命令
    Android压力测试快速入门教程(图解)——Monkey工具
    测试用例的优先级别划分
  • 原文地址:https://www.cnblogs.com/code-style/p/3656315.html
Copyright © 2011-2022 走看看