原文地址http://blog.csdn.net/wozaiwogu/article/details/6611051 安全
對其中對線程安所有分進行詳細補充,更便於理解. 多線程
///////////////////////////////////////////////////////////////////////////////////////////////////////// 編輯器
property,能夠提供的功能有:提供成員變量的訪問方法的聲明、控制成員變量的訪問權限、控制多線程時成員變量的訪問環境 )。 函數
property不但能夠在interface,在協議protocol .和類別category中也可使用. atom
synthesize的理解是:實現property所聲明的方法的定義。 spa
其實說直白就像是:property聲明瞭一些成員變量的訪問方法 ,synthesize則定義了由property聲明的方法。他們以前的對應關係是 .net
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) {
}
對於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 = 一、 test2 retainCount = 0;
self.test2 = test1; //這裏調用test2的Copy方法,所以這是test retainCount = 一、 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;
}