天天看點

property中的strong 、weak、copy 、assign 、retain 、unsafe_unretained 與autoreleasing差別和作用詳解...

iOS5中加入了新知識,就是ARC,其實我并不是很喜歡它,因為習慣了自己管理記憶體。但是學習還是很有必要的。

在iOS開發過程中,屬性的定義往往與retain, assign, copy有關,我想大家都很熟悉了,在此我也不介紹,網上有很多相關文章。

現在我們看看iOS5中新的關鍵字strong, weak, unsafe_unretained. 可以與以前的關鍵字對應學習strong與retain類似,weak與unsafe_unretained功能差不多(有點差別,等下會介紹,這兩個新 關鍵字與assign類似)。在iOS5中用這些新的關鍵字,就可以不用手動管理記憶體了,從java等其它語言轉過來的程式員非常受用。

strong關鍵字與retain關似,用了它,引用計數自動+1,用執行個體更能說明一切

  1. @property (nonatomic, strong) NSString *string1;   
  2. @property (nonatomic, strong) NSString *string2;  

有這樣兩個屬性,

  1. @synthesize string1;   
  2. @synthesize string2;  

猜一下下面代碼将輸出什麼結果?

  1. self.string1 = @"String 1";   
  2. self.string2 = self.string1;   
  3. self.string1 = nil;  
  4. NSLog(@"String 2 = %@", self.string2);  

結果是:String 2 = String 1

由于string2是strong定義的屬性,是以引用計數+1,使得它們所指向的值都是@"String 1", 如果你對retain熟悉的話,這了解并不難。

接着我們來看weak關鍵字:

如果這樣聲明兩個屬性:

  1. @property (nonatomic, strong) NSString *string1;   
  2. @property (nonatomic, weak) NSString *string2;  

并定義

  1. @synthesize string1;   
  2. @synthesize string2;  

再來猜一下,下面輸出是什麼?

  1. self.string1 = @"String 1";   
  2. self.string2 = self.string1;   
  3. self.string1 = nil;  
  4. NSLog(@"String 2 = %@", self.string2);  

結果是:String 2 = null

分析一下,由于self.string1與self.string2指向同一位址,且string2沒有retain記憶體位址,而 self.string1=nil釋放了記憶體,是以string1為nil。聲明為weak的指針,指針指向的位址一旦被釋放,這些指針都将被指派為 nil。這樣的好處能有效的防止野指針。在c/c++開發過程中,為何大牛都說指針的空間釋放了後,都要将指針賦為NULL. 在這兒用weak關鍵字幫我們做了這一步。

接着我們來看unsafe_unretained

從名字可以看出,unretained且unsafe,由于是unretained是以與weak有點類似,但是它是unsafe的,什麼是unsafe的呢,下面看執行個體。

如果這樣聲明兩個屬性:

并定義

  1. @property (nonatomic, strong) NSString *string1;   
  2. @property (nonatomic, unsafe_unretained) NSString *string2;  

再來猜一下,下面的代碼會有什麼結果?

  1. self.string1 = @"String 1";   
  2. self.string2 = self.string1;   
  3. self.string1 = nil;  
  4. NSLog(@"String 2 = %@", self.string2);  

請注意,在此我并沒有叫你猜會有什麼輸出,因為根本不會有輸出,你的程式會crash掉。

原因是什麼,其實就是野指針造成的,是以野指針是可怕的。為何會造成野指針呢?同于用unsafe_unretained聲明的指針,由于 self.string1=nil已将記憶體釋放掉了,但是string2并不知道已被釋放了,是以是野指針。然後通路野指針的記憶體就造成crash.  是以盡量少用unsafe_unretained關鍵字。

strong,weak, unsafe_unretained往往都是用來聲明屬性的,如果想聲明臨時變量就得用__strong,  __weak, __unsafe_unretained,  __autoreleasing, 其用法與上面介紹的類似。

還是看看執行個體吧。

  1. __strong NSString *yourString = @"Your String";   
  2. __weak  NSString *myString = yourString;   
  3. yourString = nil;   
  4. __unsafe_unretained NSString *theirString = myString;  
  5. //現在所有的指針都為nil  

再看一個:

  1. __strong NSString *yourString = @"Your String";   
  2. __weak  NSString *myString = yourString;   
  3. __unsafe_unretained NSString *theirString = myString;  
  4. yourString = nil;   
  5. //現在yourString與myString的指針都為nil,而theirString不為nil,但是是野指針。  

__autoreleasing的用法介紹:

在c/c++,objective-c記憶體管理中有一條是:誰配置設定誰釋放。 __autoreleasing則可以使對像延遲釋放。比如你想傳一個未初始 化地對像引用到一個方法當中,在此方法中實始化此對像,那麼這種情況将是__autoreleasing表演的時候。看個示例:

  1. - (void) generateErrorInVariable:(__autoreleasing NSError **)paramError{   
  2.     NSArray *objects = [[NSArray alloc] initWithObjects:@"A simple error", nil];  
  3.     NSArray *keys = [[NSArray alloc] initWithObjects:NSLocalizedDescriptionKey, nil];  
  4.     NSDictionary *errorDictionary = [[NSDictionary alloc] initWithObjects:objects forKeys:keys];  
  5.     *paramError = [[NSError alloc] initWithDomain:@"MyApp" code:1 userInfo:errorDictionary];  
  6. }  
  7. -(void)test  
  8. {  
  9.     NSError *error = nil;   
  10.     [self generateErrorInVariable:&error];  
  11.     NSLog(@"Error = %@", error);  
  12. }  

這樣即便在函數内部申請的空間,在函數外部也可以使用,同樣也适合誰配置設定誰釋放的原則。

同樣下面的代碼也是類似原因, 隻不過在沒有開啟ARC的情況下适用:

  1. -(NSString *)stringTest  
  2. {  
  3.     NSString *retStr = [NSString stringWithString:@"test"];  
  4.     return [[retStr retain] autorelease];  
  5. }  

開啟ARC後,應改為:

  1. -(NSString *)stringTest  
  2. {  
  3.     __autoreleasing NSString *retStr = [NSString alloc] initWithString:@"test"];  
  4.     return retStr;  
  5. }  

Setter Semantics

These attributes specify the semantics of a set accessor. They are mutually exclusive.

strong

Specifies that there is a strong (owning) relationship to the destination object.

weak

Specifies that there is a weak (non-owning) relationship to the destination object.

If the destination object is deallocated, the property value is automatically set to 

nil

.

(Weak properties are not supported on OS X v10.6 and iOS 4; use 

assign

instead.)

copy

Specifies that a copy of the object should be used for assignment.

The previous value is sent a 

release

 message.

The copy is made by invoking the 

copy

 method. This attribute is valid only for object types, which must implement the 

NSCopying

 protocol.

assign

Specifies that the setter uses simple assignment. This attribute is the default.

You use this attribute for scalar types such as 

NSInteger

 and 

CGRect

.

retain

Specifies that 

retain

 should be invoked on the object upon assignment.

The previous value is sent a 

release

 message.

In OS X v10.6 and later, you can use the 

__attribute__

 keyword to specify that a Core Foundation property should be treated like an Objective-C object for memory management:
@property(retain) __attribute__((NSObject)) CFDictionaryRef myDictionary;      

 http://www.33lc.com/article/661.html