1. 程式人生 > >Objective-C中的@property和@synthesize用法

Objective-C中的@property和@synthesize用法

有時 頭文件 關鍵字 nbsp nsa atomic 所有者 ica 風險

描述
  • @代表“Objective-C”的標誌,證明您正在使用Objective-C語言。
  • 是Objective-C語言關鍵詞。
  • @property與@synthesize配對使用。
  • 功能:讓編譯器自動編寫一個與數據成員同名的方法聲明來省去讀寫方法的聲明。
property屬性
  • 作用:提供成員變量的訪問方法的聲明、控制成員變量的訪問權限、控制多線程時成員變量的訪問環境。
  • 使用範圍:property不但可以在interface,在協議protocol和類別category中也可以使用。
synthesize 合成訪問器方法
  • 作用:實現property所聲明的方法的定義。其實說直白就像是:property聲明了一些成員變量的訪問方法,synthesize則定義了由property聲明的方法。
  • 他們之前的對應關系是:property 聲明方法 ->頭文件中申明getter和setter方法 synthesize定義方法 -> m文件中實現getter和setter方法。

如:

1、在頭文件中:

1. @property int count;  
等效於在頭文件中聲明2個方法:
1. - (int)count;  
2. -(void)setCount:(int)newCount;  
2、實現文件(.m)中


@synthesize count;  
等效於在實現文件(.m)中實現2個方法。
1. - (int)count  
2. {  
3.     return
count; 4. } 5. -(void)setCount:(int)newCount 6. { 7. count = newCount; 8. }
  • 在Xcode4.5及以後的版本中,可以省略@synthesize,編譯器會自動幫你加上get 和 set 方法的實現,並且默認會去訪問_age這個成員變量,如果找不到_age這個成員變量,會自動生成一個叫做 _age的私有成員變量。
  • 註意:iOS 中setter和getter方法不可以同時寫,在.m文件中同時實現getter和setter時候需要@synthesize age = _age.表示要手動生成setter和getter方法,同時用age的地方可以用_age,
    _age是寫在花括號裏的字段,而age是@property裏聲明的屬性,字段是私有的,而屬性可以供外界訪問,私有字段在校驗數據合法性等情況(尤其是在安全方面)有著積極作用。

例如:@interface MyClass()
@property (nonatomic, copy) NSString *age;
@end
 
@implementation MyClass
@synthesize age = _age ;
- (void)setAge:(NSString *)age
{
    …..
}
- (NSString *)age
{
   ....
}
 
@end
以上等效的函數部分由編譯器自動幫開發者填充完成,簡化了編碼輸入工作量。 格式: 聲明property的語法為:@property (參數1,參數2) 類型 名字; 其中參數主要分為三類:
  • 讀寫屬性: (readwrite/readonly)
  • setter語意:(assign/retain/copy)
  • 原子性: (atomicity/nonatomic)
各參數意義如下:
  • readwrite: 產生setter\getter方法
  • readonly: 只產生簡單的getter,沒有setter。(此時重寫getter方法時,不可以用下劃線屬性,比如_age。必須也得先聲明,比如:@synthesize age =_age,此時重寫getter方法時才可以用_age);
  • assign: 默認類型,setter方法直接賦值,而不進行retain操作
  • retain: setter方法對參數進行release舊值,再retain新值。該屬性與 strong 一致;只是可讀性更強一些。
  • copy: setter方法進行Copy操作,與retain一樣,與 strong 的區別是聲明變量是拷貝對象的持有者。
  • nonatomic: 禁止多線程,變量保護,提高性能
1.讀寫特性:readonly 、readwrite
在Objective-C中,擁有這樣兩個讀寫特性:readwrite和readonly,意思簡單明了,就是可讀可寫以及只讀。默認情況下,屬性默認是可讀可寫的。
readwrite,聲明此屬性為讀寫屬性,即可以訪問設置方法(setter),也可以訪問獲取方法(getter),與readonly互斥。
readonly,聲明此屬性為只讀屬性,只能訪問此屬性對應的獲取方法(getter),與readwrite互斥。
2.setter語意
setter語意特性主要是用來告訴Xcode,對於這個屬性,應該如何去自動實現它的setter方法。這個特性主要是針對非ARC情況的。
 在Objective-C中,擁有三個setter語意特性:assign、retain和copy,默認情況下屬性特性是assign的。
assign:簡單賦值特性,它不會對索引計數(Reference Counting)進行更改。默認類型,setter方法直接賦值,而不進行retain操作
-(void)setStr:(NSString*)value{  
   str=value;  
}
retain:setter方法釋放(release)舊的對象,然後將舊對象的值賦予輸入對象,再將輸入對象的索引計數增加1(retain)。
-(void)setStr:(NSString*)v{  
   if(v!=str){  
       [str release];  
       str=[v retain];
   }  
}
聲明在setter方法中,需要對設過來的值進行retain 加1操作。如:
1. -(void)setName:(NSString*)_name{  
2.      //首先判斷是否與舊對象一致,如果不一致進行賦值。  
3.      //因為如果是一個對象的話,進行if內的代碼會造成一個極端的情況:當此name的retain為1時,使此次的set操作讓實例name提前釋放,而達不到賦值目的。  
4.      if ( name != _name){  
5.           [name release];  
6.           name = [_name retain];  
7.      }  
8. }
copy:setter方法進行Copy操作,與retain一樣,建立一個索引計數為1的對象,釋放掉舊對象。
-(void)setStr:(NSString*)v{  
   if(v!=str){  
       [str release];  
       str=[v copy];
   }  
}
參數中比較復雜的是retain和copy,具體分析如下: getter 分析 1、
1. @property(nonatomic,retain)test* thetest;  
2. @property(nonatomic ,copy)test* thetest; 
等效代碼:
1. -(void)thetest  
2. {  
3.   return thetest;  
4. } 
2、
1. @property(retain)test* thetest;  
2. @property(copy)test* thetest; 
等效代碼:
1. -(void)thetest  
2. {  
3.     [thetest retain];  
4.     return [thetest autorelease];  
5. } 
setter分析 1、
1. @property(nonatomic,retain)test* thetest;  
2. @property(retain)test* thetest;  
等效於:
1. -(void)setThetest:(test *)newThetest {  
2.     if (thetest!= newThetest) {  
3.         [thetestrelease];  
4.         thetest= [newThetest retain];  
5.     }  
6. } 
2、
1. @property(nonatomic,copy)test* thetest;  
2. @property(copy)test* thetest; 
等效於:
1. -(void)setThetest:(test *)newThetest {  
2.     if (thetest!= newThetest) {  
3.         [thetest release];  
4.         thetest= [newThetest copy];  
5.     }  
6. }  
retain 代碼說明 如果只是@property NSString*str; 則通過@synthesize自動生成的setter代碼為:
1. -(void)setStr:(NSString*)value{  
2.     str=value;  
3. }  
如果是@property(retain)NSString*str; 則自動的setter內容為:
1. -(void)setStr:(NSString*)v{  
2.     if(v!=str){  
3.         [str release];  
4.         str=[v retain];  
5.     }  
6. } 
什麽時候使用這些語意特性呢? 只要是值類型、簡單類型的類型,比如說NSInteger、CGPoint、CGFloat,以及C數據類型int、float、double,bool等,都應該使用assign。 那麽對於含有可深復制子類的對象,比如說NSArray、NSSet、NSDictionary、NSData、NSString等等,都應該使用copy特性。 註意:對於NSMutableArray之類的可變類型,不能夠使用Copy特性,否則初始化會出現錯誤。 至於其他的NSObject對象,那麽都應該使用retain來進行操作,這也是絕大多數所使用的情況。 3.所有者特性 我們先來看看與所有權有關系的屬性,關鍵字間的對應關系。 屬性值 關鍵字 所有權 strong __strong 有 weak __weak 無 unsafe_unretained __unsafe_unretained 無 copy __strong 有 assign __unsafe_unretained 無 retain __strong 有 strong 該屬性值對應 __strong 關鍵字,即該屬性所聲明的變量將成為對象的持有者。 weak 該屬性對應 __weak 關鍵字,與 __weak 定義的變量一致,該屬性所聲明的變量將沒有對象的所有權,並且當對象被拋棄之後,對象將被自動賦值nil。 並且,delegate 和 Outlet 應該用 weak 屬性來聲明。同時 iOS 5 之前的版本是沒有 __weak 關鍵字的,所以 weak 屬性是不能使用的。這種情況我們使用 unsafe_unretained。 unsafe_unretained 等效於__unsafe_unretaind關鍵字聲明的變量;像上面說明的,iOS 5之前的系統用該屬性代替 weak 來使用。 對於ARC來說,上一節中所說的getter語意特性將被所有者特性所代替。 在Objective-C中,擁有兩個所有者特性:strong和weak。默認情況下屬性特性是strong的。 對於strong來說,它就相當於getter語意特性中的retain特性,即這個特性的屬性將會成為對象的持有者。這個特性稱之為強引用。 @property(strong) MyClass *myObject; 相當於@property(retain) MyClass *myObject; 對於weak來說,它聲明的屬性不會擁有這個對象的所有權,如果弱引用指向的對象被deallocated的話,弱引用的對象會被自動設置為nil。 @property(weak) MyOtherClass *delegate; 相當於@property(assign) MyOtherClass *delegate; 簡單講strong等同retain weak比assign多了一個功能,當對象消失後自動把指針變成nil,好處不言而喻。 強引用與弱引用的廣義區別: 強引用也就是我們通常所講的引用,其存亡直接決定了所指對象的存亡。如果不存在指向一個對象的引用,並且此對象不再顯示列表中,則此對象會被從內存中釋放。 弱引用除了不決定對象的存亡外,其他與強引用相同。即使一個對象被持有無數個弱引用,只要沒有強引用指向他,那麼其還是會被清除。 面對ARC機制中,最令人頭疼的就是“循環強引用”的問題,所謂循環強引用,就是我們申請了兩個保險櫃,然後分別將另外一個保險櫃的鑰匙鎖在了保險櫃當中。這樣就會造成什麽現象呢?我們完全就無法歸還鑰匙了,這兩個保險櫃就無法再重新使用了。那麽使用弱引用,就不會出現這個問題了。 weak常用於網絡delegate屬性 原子特性 原子特性,簡要來說,是針對多線程而設置的。Objective-C擁有兩種原子特性,分別是atomic和nonatomic。 相比之下,swift目前還不支持這些特性。如果我們要實現線程安全,似乎只能使用objc_sync_enter此類的方法,來保證屬性的處理只有一個線程在進行。或者使用屬性觀察器來完成這些操作。 如果使用多線程,有時會出現兩個線程互相等待對方導致鎖死的情況(具體可以搜下線程方面的註意事項去了解)。在沒有(nonatomic)的情況下,即默認(atomic),會防止這種線程互斥出現,但是會消耗一定的資源,而如果使用nonatomic,就不會有這種阻止死鎖的功能,但是如果我們確定不使用多線程的話,那麽使用這個特性可以極大地改善應用性能,所以如果不是多線程的程序,打上(nonatomic)即可。 有個評友說的,感覺挺到位的:nonatomic 和 atomic 之間的根本區別不是死不死鎖或者能不能阻止死鎖,而是產不產生競爭。如果用atomic,那麽編譯器生成的set方法會在整個set邏輯外層加互斥鎖,保證set動作是原子的,如果用nonatomic,那麽就不會加互斥鎖,所以多線程下同時set會有數據混亂的風險,但是atomic版本因為有互斥鎖,等鎖和釋放鎖都會有開銷,所以影響性能。總之,只要不是自己亂寫set,get,是不會有死鎖問題的,而是等鎖開銷。 總結 我們總共介紹了四種屬性特性,分別是讀寫特性、setter語意特性、所有者特性和原子特性。ARC是不支持setter語意特性的,它使用所有者特性。 iOS開發的建議 所有屬性都聲明為nonatomic 盡量避免多線程搶奪同一塊資源 盡量將加鎖、資源搶奪的業務邏輯交給服務器端處理,減小移動客戶端的壓力 參考: http://www.jianshu.com/p/bcf734db475c http://justcoding.iteye.com/blog/1444548

Objective-C中的@property和@synthesize用法