<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    qileilove

    blog已經轉移至github,大家請訪問 http://qaseven.github.io/

    IOS開發之property詳解

    之前很多網友對我翻譯的教程中的Property的使用感到有些迷惑不解,搞不清楚什么時候要release,什么時候要self.xxx = nil;同時對于Objective-c的內存管理以及cocos2d的內存管理規則不夠清楚。本文主要講解objc里面@property,它是什么,它有什么用,atomic,nonatomic,readonly,readwrite,assign,retain,copy,getter,setter這些關鍵字有什么用,什么時候使用它們。至于Objc的內存管理和cocos2d的內存管理部分,接下來,我會翻譯Ray的3篇教程,那里面再和大家詳細討論。今天我們的主要任務是搞定@property。
      學過c/c++的朋友都知道,我們定義struct/class的時候,如果把訪問限定符(public,protected,private)設置為public的話,那么我們是可以直接用.號來訪問它內部的數據成員的。比如
      //in Test.h
      class Test
      {
      public:
      int i;
      float f;
      };
      我在main函數里面是可以通過下面的方式來使用這個類的:(注意,如果在main函數里面使用此類,除了要包含頭文件以外,最重要的是記得把main.m改成main.mm,否則會報一些奇怪的錯誤。所以,任何時候我們使用c++,如果報奇怪的錯誤,那就要提醒自己是不是把相應的源文件改成.mm后綴了。其它引用此類的文件有時候也要改成.mm文件)
      //in main.mm
      Test test;
      test.i =1;
      test.f =2.4f;
      NSLog(@"Test.i = %d, Test.f = %f",test.i,  test.f);
      但是,在objc里面,我們能不能這樣做呢?請看下面的代碼:(新建一個objc類,命名為BaseClass)
      //in BaseClass.h
      @interface BaseClass : NSObject{
      @public
      NSString *_name;
      }
      接下來,我們在main.mm里面:
      BaseClass *base= [[BaseClass alloc] init];
      base.name =@"set base name";
      NSLog(@"base class's name = %@", base.name);
      不用等你編譯,xcode4馬上提示錯誤,請看截圖:
      請大家注意看出錯提示“Property 'nam' not found on object of type BaseClass*",意思是,BaseClass這類沒有一個名為name的屬性。即使我們在頭文件中聲明了@public,我們仍然無法在使用BaseClass的時候用.號來直接訪問其數據成員。而@public,@protected和@private只會影響繼承它的類的訪問權限,如果你使用@private聲明數據成員,那么在子類中是無法直接使用父類的私有成員的,這和c++,java是一樣的。
      既然有錯誤,那么我們就來想法解決啦,編譯器說沒有@property,那好,我們就定義property,請看代碼:
      //in BaseClass.h
      @interface BaseClass : NSObject{
      @public
      NSString *_name;
      }
      @property(nonatomic,copy) NSString *name;
      //in BaseClass.m
      @synthesize name = _name;
      現在,編譯并運行,ok,很好。那你可能會問了@prperty是不是就是讓”."號合法了呀?只要定義了@property就可以使用.號來訪問類的數據成員了?先讓我們來看下面的例子:
    @interface BaseClass : NSObject{
    @public
    NSString *_name;
    }
    //@property(nonatomic,copy) NSString *name;
    -(NSString*) name;
    -(void) setName:(NSString*)newName;
    我把@property的定義注釋掉了,另外定義了兩個函數,name和setName,下面請看實現文件:
    //@synthesize name = _name;
    -(NSString*) name{
    return _name;
    }
    -(void) setName:(NSString *)name{
    if (_name != name) {
    [_name release];
    _name = [name copy];
    }
    }
    現在,你再編譯運行,一樣工作的很好。why?因為我剛剛做的工作和先前聲明@property所做的工作完全一樣。@prperty只不過是給編譯器看的一種指令,它可以編譯之后為你生成相應的getter和setter方法。而且,注意看到面property(nonatomic,copy)括號里面這copy參數了嗎?它所做的事就是
      _name = [name copy];
      如果你指定retain,或者assign,那么相應的代碼分別是:
      //property(retain)NSString* name;
      _name = [name retain];
      //property(assign)NSString* name;
      _name = name;
      其它講到這里,大家也可以看出來,@property并不只是可以生成getter和setter方法,它還可以做內存管理。不過這里我暫不討論。現在,@property大概做了件什么事,想必大家已經知道了。但是,我們程序員都有一個坎,就是自己沒有完全吃透的東西,心里用起來不踏實,特別是我自己。所以,接下來,我們要詳細深挖@property的每一個細節。
      首先,我們看atomic 與nonatomic的區別與用法,講之前,我們先看下面這段代碼:
      @property(nonatomic, retain) UITextField *userName;    //1
      @property(nonatomic, retain,readwrite) UITextField *userName;  //2
      @property(atomic, retain) UITextField *userName;  //3
      @property(retain) UITextField *userName;  //4
      @property(atomic,assign) int i;         // 5
      @property(atomic) int i;         //6
      @property int i;               //7
      請讀者先停下來想一想,它們有什么區別呢?
      上面的代碼1和2是等價的,3和4是等價的,5,6,7是等價的。也就是說atomic是默認行為,assign是默認行為,readwrite是默認行為。但是,如果你寫上@property(nontomic)NSString *name;那么將會報一個警告,如下圖:
      因為是非gc的對象,所以默認的assign修飾符是不行的。那么什么時候用assign、什么時候用retain和copy呢?推薦做法是NSString用copy,delegate用assign(且一定要用assign,不要問為什么,只管去用就是了,以后你會明白的),非objc數據類型,比如int,float等基本數據類型用assign(默認就是assign),而其它objc類型,比如NSArray,NSDate用retain。
      在繼續之前,我還想補充幾個問題,就是如果我們自己定義某些變量的setter方法,但是想讓編譯器為我們生成getter方法,這樣子可以嗎?答案是當然可以。如果你自己在.m文件里面實現了setter/getter方法的話,那以翻譯器就不會為你再生成相應的getter/setter了。請看下面代碼:
    //代碼一:
    @interface BaseClass : NSObject{
    @public
    NSString *_name;
    }
    @property(nonatomic,copy,readonly) NSString *name;  //這里使用的是readonly,所有會聲明geter方法
    -(void) setName:(NSString*)newName;
    //代碼二:
    @interface BaseClass : NSObject{
    @public
    NSString *_name;
    }
    @property(nonatomic,copy,readonly) NSString *name;   //這里雖然聲明了readonly,但是不會生成getter方法,因為你下面自己定義了getter方法。
    -(NSString*) name;   //getter方法是不是只能是name呢?不一定,你打開Foundation.framework,找到UIView.h,看看里面的property就明白了)
    -(void) setName:(NSString*)newName;
    //代碼三:
    @interface BaseClass : NSObject{
    @public
    NSString *_name;
    }
    @property(nonatomic,copy,readwrite) NSString *name;  //這里編譯器會我們生成了getter和setter
    //代碼四:
    @interface BaseClass : NSObject{
    @public
    NSString *_name;
    }
    @property(nonatomic,copy) NSString *name;  //因為readwrite是默認行為,所以同代碼三
      上面四段代碼是等價的,接下來,請看下面四段代碼:
    //代碼一:
    @synthesize name = _name;  //這句話,編譯器發現你沒有定義任何getter和setter,所以會同時會你生成getter和setter
    //代碼二:
    @synthesize name = _name;  //因為你定義了name,也就是getter方法,所以編譯器只會為生成setter方法,也就是setName方法。
    -(NSString*) name{
    NSLog(@"name");
    return _name;
    }
    //代碼三:
    @synthesize name = _name;   //這里因為你定義了setter方法,所以編譯器只會為你生成getter方法
    -(void) setName:(NSString *)name{
    NSLog(@"setName");
    if (_name != name) {
    [_name release];
    _name = [name copy];
    }
    }
    //代碼四:
    @synthesize name = _name;  //這里你自己定義了getter和setter,這句話沒用了,你可以注釋掉。
    -(NSString*) name{
    NSLog(@"name");
    return _name;
    }
    -(void) setName:(NSString *)name{
    NSLog(@"setName");
    if (_name != name) {
    [_name release];
    _name = [name copy];
    }
    }
      上面這四段代碼也是等價的。看到這里,大家對Property的作用相信會有更加進一步的理解了吧。但是,你必須小心,你如果使用了Property,而且你自己又重寫了setter/getter的話,你需要清楚的明白,你究竟干了些什么事。別寫出下面的代碼,雖然是合法的,但是會誤導別人:
    //BaseClass.h
    @interface BaseClass : NSObject{
    @public
    NSArray *_names;
    }
    @property(nonatomic,assgin,readonly) NSArray *names;  //注意這里是assign
    -(void) setNames:(NSArray*)names;
    //BaseClass.m
    @implementation BaseClass
    @synthesize names = _names;
    -(NSArray*) names{
    NSLog(@"names");
    return _names;
    }
    -(void) setNames:(NSArray*)names{
    NSLog(@"setNames");
    if (_name != name) {
    [_name release];
    _name = [name retain];  //你retain,但是你不覆蓋這個方法,那么編譯器會生成setNames方法,里面肯定是用的assign
    }
    }
      當別人使用@property來做內存管理的時候就會有問題了。總結一下,如果你自己實現了getter和setter的話,atomic/nonatomic/retain/assign/copy這些只是給編譯的建議,編譯會首先會到你的代碼里面去找,如果你定義了相應的getter和setter的話,那么好,用你的。如果沒有,編譯器就會根據atomic/nonatomic/retain/assign/copy這其中你指定的某幾個規則去生成相應的getter和setter。
      好了,說了這么多,回到我們的正題吧。atomic和nonatomic的作用與區別:
      如果你用@synthesize去讓編譯器生成代碼,那么atomic和nonatomic生成的代碼是不一樣的。如果使用atomic,如其名,它會保證每次getter和setter的操作都會正確的執行完畢,而不用擔心其它線程在你get的時候set,可以說保證了某種程度上的線程安全。但是,我上網查了資料,僅僅靠atomic來保證線程安全是很天真的。要寫出線程安全的代碼,還需要有同步和互斥機制。
      而nonatomic就沒有類似的“線程安全”(我這里加引號是指某種程度的線程安全)保證了。因此,很明顯,nonatomic比atomic速度要快。這也是為什么,我們基本上所有用property的地方,都用的是nonatomic了。
      還有一點,可能有讀者經常看到,在我的教程的dealloc函數里面有這樣的代碼:self.xxx = nil;看到這里,現在你們明白這樣寫有什么用了吧?它等價于[xxx release];  xxx = [nil retain];(---如果你的property(nonatomic,retian)xxx,那么就會這樣,如果不是,就對號入座吧)。
      因為nil可以給它發送任何消息,而不會出錯。為什么release掉了還要賦值為nil呢?大家用c的時候,都有這樣的編碼習慣吧。
      int* arr = new int[10];    然后不用的時候,delete arr; arr = NULL;  在objc里面可以用一句話self.arr = nil;搞定。

    posted on 2014-11-24 10:03 順其自然EVO 閱讀(204) 評論(0)  編輯  收藏 所屬分類: 測試學習專欄

    <2014年11月>
    2627282930311
    2345678
    9101112131415
    16171819202122
    23242526272829
    30123456

    導航

    統計

    常用鏈接

    留言簿(55)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 毛片在线播放免费观看| 在线亚洲高清揄拍自拍一品区| 国产成人精品久久亚洲高清不卡| 久久综合AV免费观看| 亚洲免费电影网站| 无码人妻一区二区三区免费手机| 亚洲永久中文字幕在线| 国产亚洲av片在线观看16女人| 麻豆一区二区三区蜜桃免费| 日韩在线永久免费播放| 亚洲天天做日日做天天看| 午夜不卡久久精品无码免费| 久久久久亚洲av无码专区导航 | 在线观看日本免费a∨视频| 亚洲经典在线观看| 日韩免费a级毛片无码a∨| 亚洲欧美日韩中文无线码 | 5555在线播放免费播放| 久久精品国产精品亚洲毛片| 亚洲三级在线免费观看| 亚洲乱妇熟女爽到高潮的片| 免费国产a国产片高清| 99热亚洲色精品国产88| 免费的一级片网站| 九九久久精品国产免费看小说 | 亚洲区精品久久一区二区三区| 久久久久国色AV免费看图片| 自拍偷自拍亚洲精品播放| 亚洲av无码国产精品色在线看不卡| 亚洲av日韩av综合| 国产一区二区三区免费在线观看| 国产成人精品免费大全| 国产乱子伦精品免费女 | 无码国产精品一区二区免费式芒果| 久久亚洲国产成人精品性色| 97人伦色伦成人免费视频| 一级视频在线免费观看| 亚洲黄色网址在线观看| 免费国产a国产片高清| 久艹视频在线免费观看| 亚洲AV无码国产剧情|