學過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立時提醒毛病,請看截圖:
請年夜家留意看失足提醒“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。
我們來整頓一下@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屬性的用法】的相關資料介紹到這裡,希望對您有所幫助! 提示:不會對讀者因本文所帶來的任何損失負責。如果您支持就請把本站添加至收藏夾哦!