你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> 舉例講授Objective-C中@property屬性的用法

舉例講授Objective-C中@property屬性的用法

編輯:IOS開發綜合

學過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);
   
  不消等你編譯,xcode立時提醒毛病,請看截圖:

201632591128870.jpg (700×100)

請年夜家留意看失足提醒“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;那末將會報一個正告,以下圖:

201632591159602.jpg (700×50)

 由於長短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。

我們來整頓一下@property中的屬性症結字:
1.原子性 nonatomic/atomic

在默許的情形下,由編譯器分解的辦法會經由過程鎖定機制確保其原子性(atomicity)。假如具有nonatomic特質,則不應用同步鎖。

2.讀/寫權限  readwrite/readonly

3.內存治理語義

assign “設置辦法” 只會針對“純量類型”(scalar type, CGFloat或NSInteger等)的簡略賦值操作

strong “具有關系” 為這類屬性設置新值時,設置辦法先保存新值,並釋放舊值,然後再將新值設置上去

weak “非具有關系” 為這類屬性設置新值時,設置辦法既不保存新值,也不釋放舊值。此特質同assign相似,但是屬性所指的對象遭到摧毀時,屬性也會被清空(nil out)

unsafe_unretained 此特質的語義和assign雷同,然則它實用於“對象類型”(object type),該特質表達一種“非具有關系”(“不保存”,unretained),當目的對象遭到摧毀時,屬性值不會主動清空(“不平安”,unsafe),這一點與weak有差別

copy 此特質所表達的所屬關系與strong相似。但是設置辦法其實不保存新值,而是將其“拷貝”(copy)

4.辦法名

getter=<name>

@property (nonatomic, getter=isOn) BOOL on;

setter=<name> 不太經常使用


總結
  好了,說了這麼多,回到我們的正題吧。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;弄定。

【舉例講授Objective-C中@property屬性的用法】的相關資料介紹到這裡,希望對您有所幫助! 提示:不會對讀者因本文所帶來的任何損失負責。如果您支持就請把本站添加至收藏夾哦!

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved