溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

objective-C: retain copy assgin nonatomic 等屬性詳解

發(fā)布時間:2020-06-12 14:07:31 來源:網(wǎng)絡(luò) 閱讀:273 作者:xiesiyuana 欄目:開發(fā)技術(shù)

在我們開發(fā)iOS程序時,常常會遇到:
property 和synthesize,以前很懶沒有仔細去理解,只是看了看別人寫的書,覺得挺容易的(在這里我不得不說,現(xiàn)在很多本土出的土?xí)?,尤其是早期?009年,寫的是真亂,誤人子弟),所以今天有時間,自己試驗了一番,希望和大家討論。

property,他可以提供的功能有:提供成員變量的訪問方法的聲明、控制成員變量的訪問權(quán)限、控制多線程時成員變量的訪問環(huán)境 )。

property不但可以在interface,在協(xié)議protocol .和類別category中也可以使用.

synthesize的理解是:實現(xiàn)property所聲明的方法的定義。

其實說直白就像是:property聲明了一些成員變量的訪問方法 ,synthesize則定義了由property聲明的方法。他們之前的對應(yīng)關(guān)系是

  property 聲明方法 ———-》 頭文件中申明的方法

 synthesize定義方法———》Cpp文件中定義的方法

不過這里還有有一點細微的差別,后面我會講到。


先講property

大家都知道:@property(attribute1 , attribute2, …])是@property的他的官方表達方式,所以看到attribute1, attribute2,你就應(yīng)該懂的, 他的用法不是很簡單。下面就對他的屬性列表進行分類介紹:

下面對屬性列表進行一下簡單的介紹,后續(xù)會用代碼來解釋。

1.可讀性:readonly 、readwrite

@property(readwrite,….) valueType value;

這個屬性是變量的默認屬性,就是如果你(readwrite and readonly都沒有使用,那么你的變量就是readwrite屬性),通過加入readwrite屬性你的變量就會有g(shù)et方法,和set方法。

property(readonly,…) valueType value;

這個屬性變量就是表明變量只有可讀方法,也就是說,你只能使用它的get方法。

2,assign,setter方法直接賦值,不進行任何retain操作,為了解決原類型與環(huán)循引用問題

3,retain,setter方法對參數(shù)進行release舊值再retain新值,所有實現(xiàn)都是這個順序


4,copy,setter方法進行Copy操作,與retain處理流程一樣,先舊值release,再Copy出新的對象,retainCount為1。這是為了減少對上下文的依賴而引入的機制。


5,nonatomic,非原子性訪問,不加同步,多線程并發(fā)訪問會提高性能。注意,如果不加此屬性,則默認是兩個訪問方法都為原子型事務(wù)訪問。鎖被加到所屬對象實例級.

所以 不加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 (注,后續(xù)過程我們都會加入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 這兩個屬性他們的真正價值,不是提供成員變量訪問接口,而是控制

成員變量的訪問權(quán)限。所以要抓住他們真正價值。

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協(xié)議,并且你還必須實現(xiàn)了

-(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函數(shù),objc編輯器將會按如下方式翻譯

如果是@synthesize _test2;

setter函數(shù)將是這種形式:

-(void)set_test2(NSObject*); //注意中間的下劃線

寫成@synthesize test = _test2;

setter函數(shù)將是這種形式:
 -(void)settest2(NSObject*);// _test2 被 test2替換了

可以看出這種別名機制,感覺是規(guī)范書寫(其實更像是規(guī)范Objc的書寫,大家可以看看官方文檔中,成員變量都是前面帶下滑線的(如_test2),所以才搞了這樣一個別名規(guī)范代碼中的書寫)


//下面是一個功能函數(shù),

-(void )test

{

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

//下面有三種對test2操作方法:

  _test2 = test1;  //這里是將test1的指針賦值給_test2指針,注意,并沒有調(diào)用test2的setter方法 ,所以test retainCount  = 1、 test2 retainCount  = 0;

  self.test2 = test1;  //這里調(diào)用test2的Copy方法,因此這是test retainCount  = 1、 test2 retainCount  = 1; 

  test2   = test1;

 //這段代碼系統(tǒng)將會提示出錯說test2沒有定義。因為這里編譯器認為是一條賦值表達式,將test2看作是一個成員變量,而在我們的testApp 中是沒有這個成員變量的,這里要區(qū)別我們所說的別名,別名機制可以看作是在調(diào)用setter或者getter函數(shù)才會起作用,而這里只是一個簡單的賦值,也就出現(xiàn)未定義的錯誤。如果沒有理解,你就記住要調(diào)用setter或者getter函數(shù),就用”self.成員變量”這種形式就行了.


//我們把  test2   = test1這行代碼注釋掉,保證程序繼續(xù)執(zhí)行

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

}

@end


更多Objective-C 查看 :http://www.seanyxie.com/objective-c-retain-copy-assgin-nonatomic-%E7%AD%89%E5%B1%9E%E6%80%A7%E8%AF%A6%E8%A7%A3/

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI