iOS5中加入了新知識,就是ARC,因為習慣了自己管理記憶體。但是學習還是很有必要的。
在iOS開發過程中,屬性的定義往往與retain, assign, copy有關,我想大家都很熟悉了,在此我也不介紹,網上有很多相關文章。
現在我們看看iOS5中新的關鍵字strong, weak, unsafe_unretained. 可以與以前的關鍵字對應學習strong與retain類似,weak與unsafe_unretained功能差不多(有點差別,等下會介紹,這兩個新 關鍵字與assign類似)。在iOS5中用這些新的關鍵字,就可以不用手動管理記憶體了,從java等其它語言轉過來的程式員非常受用。
strong關鍵字與retain關似,用了它,引用計數自動+1,用執行個體更能說明一切
- @property (nonatomic, strong) NSString *string1;
- @property (nonatomic, strong) NSString *string2;
有這樣兩個屬性,
- @synthesize string1;
- @synthesize string2;
猜一下下面代碼将輸出什麼結果?
- self.string1 = @"String 1";
- self.string2 = self.string1;
- self.string1 = nil;
- NSLog(@"String 2 = %@", self.string2);
結果是:String 2 = String 1
由于string2是strong定義的屬性,是以引用計數+1,使得它們所指向的值都是@"String 1", 如果你對retain熟悉的話,這了解并不難。
接着我們來看weak關鍵字:
如果這樣聲明兩個屬性:
- @property (nonatomic, strong) NSString *string1;
- @property (nonatomic, weak) NSString *string2;
并定義
- @synthesize string1;
- @synthesize string2;
再來猜一下,下面輸出是什麼?
- self.string1 = @"String 1";
- self.string2 = self.string1;
- self.string1 = nil;
- 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的呢,下面看執行個體。
如果這樣聲明兩個屬性:
并定義
- @property (nonatomic, strong) NSString *string1;
- @property (nonatomic, unsafe_unretained) NSString *string2;
再來猜一下,下面的代碼會有什麼結果?
- self.string1 = @"String 1";
- self.string2 = self.string1;
- self.string1 = nil;
- NSLog(@"String 2 = %@", self.string2);
請注意,在此我并沒有叫你猜會有什麼輸出,因為根本不會有輸出,你的程式會crash掉。
原因是什麼,其實就是野指針造成的,是以野指針是可怕的。為何會造成野指針呢?同于用unsafe_unretained聲明的指針,由于 self.string1=nil已将記憶體釋放掉了,但是string2并不知道已被釋放了,是以是野指針。然後通路野指針的記憶體就造成crash. 是以盡量少用unsafe_unretained關鍵字。
strong,weak, unsafe_unretained往往都是用來聲明屬性的,如果想聲明臨時變量就得用__strong, __weak, __unsafe_unretained, __autoreleasing, 其用法與上面介紹的類似。
還是看看執行個體吧。
- __strong NSString *yourString = @"Your String";
- __weak NSString *myString = yourString;
- yourString = nil;
- __unsafe_unretained NSString *theirString = myString;
- //現在所有的指針都為nil
再看一個:
- __strong NSString *yourString = @"Your String";
- __weak NSString *myString = yourString;
- __unsafe_unretained NSString *theirString = myString;
- yourString = nil;
- //現在yourString與myString的指針都為nil,而theirString不為nil,但是是野指針。
__autoreleasing的用法介紹:
在c/c++,objective-c記憶體管理中有一條是:誰配置設定誰釋放。 __autoreleasing則可以使對像延遲釋放。比如你想傳一個未初始 化地對像引用到一個方法當中,在此方法中實始化此對像,那麼這種情況将是__autoreleasing表演的時候。看個示例:
- - (void) generateErrorInVariable:(__autoreleasing NSError **)paramError{
- NSArray *objects = [[NSArray alloc] initWithObjects:@"A simple error", nil];
- NSArray *keys = [[NSArray alloc] initWithObjects:NSLocalizedDescriptionKey, nil];
- NSDictionary *errorDictionary = [[NSDictionary alloc] initWithObjects:objects forKeys:keys];
- *paramError = [[NSError alloc] initWithDomain:@"MyApp" code:1 userInfo:errorDictionary];
- }
- -(void)test
- {
- NSError *error = nil;
- [self generateErrorInVariable:&error];
- NSLog(@"Error = %@", error);
- }
這樣即便在函數内部申請的空間,在函數外部也可以使用,同樣也适合誰配置設定誰釋放的原則。
同樣下面的代碼也是類似原因, 隻不過在沒有開啟ARC的情況下适用:
- -(NSString *)stringTest
- {
- NSString *retStr = [NSString stringWithString:@"test"];
- return [[retStr retain] autorelease];
- }
開啟ARC後,應改為:
- -(NSString *)stringTest
- {
- __autoreleasing NSString *retStr = [NSString alloc] initWithString:@"test"];
- return retStr;
- }
Setter Semantics
These attributes specify the semantics of a set accessor. They are mutually exclusive.
- Specifies that there is a strong (owning) relationship to the destination object.
-
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
instead.)assign
-
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
method. This attribute is valid only for object types, which must implement thecopy
protocol.NSCopying
-
Specifies that the setter uses simple assignment. This attribute is the default.
You use this attribute for scalar types such as
andNSInteger
.CGRect
- 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
keyword to specify that a Core Foundation property should be treated like an Objective-C object for memory management:__attribute__
@property(retain) __attribute__((NSObject)) CFDictionaryRef myDictionary;
strong
weak
copy
assign
retain
http://www.33lc.com/article/661.html
//-----------------------
http://blog.csdn.net/q199109106q/article/details/8565017
參考文獻: iOS ARC 完全指南
提示:本文中所說的"執行個體變量"即是"成員變量","局部變量"即是"本地變量"
一、簡介
ARC是自iOS 5之後增加的新特性,完全消除了手動管理記憶體的煩瑣,編譯器會自動在适當的地方插入适當的retain、release、autorelease語句。你不再需要擔心記憶體管理,因為編譯器為你處理了一切
注意:ARC 是編譯器特性,而不是 iOS 運作時特性(除了weak指針系統),它也不是類似于其它語言中的垃圾收集器。是以 ARC 和手動記憶體管理性能是一樣的,有時還能更加快速,因為編譯器還可以執行某些優化
二、原理
ARC 的規則非常簡單:隻要還有一個變量指向對象,對象就會保持在記憶體中。當指針指向新值,或者指針不再存在時,相關聯的對象就會自動釋放。這條規則對于執行個體變量、synthesize屬性、局部變量都是适用的
三、strong指針
控制器中有個文本輸入框框屬性
[java] view plain copy
- @property (nonatomic, assign) IBOutlet UITextField *nameField;
1.如果使用者在文本框中輸入mj這個字元串
那麼就可以說,nameField的text屬性是NSString對象的指針,也就是擁有者,該對象儲存了文本輸入框的内容
2.如果執行了如下代碼
[java] view plain copy
- NSString *name = self.nameField.text;
一個對象可以有多個擁有者,在上面代碼中,name變量同樣也是這個NSString對象的擁有者,也就是有兩個指針指向同一個對象
3.随後使用者改變了輸入框的内容,比如
此時nameFeild的text屬性就指向了新的NSString對象。但原來的NSString對象仍然還有一個所有者(name變量),是以會繼續保留在記憶體中
4.當name變量獲得新值,或者不再存在時(如局部變量方法傳回時、執行個體變量對象釋放時),原先的NSString對象就不再擁有任何所有者,retain計數降為0,這時對象會被釋放
如,給name變量賦予一個新值
[java] view plain copy
- name = @"Jake";
我們稱name和nameField.text指針為"Strong指針",因為它們能夠保持對象的生命。預設所有執行個體變量和局部變量都是Strong指針
四、weak指針
weak型的指針變量仍然可以指向一個對象,但不屬于對象的擁有者
1.執行下面的代碼
[java] view plain copy
- __weak NSString *name = self.nameField.text;
name變量和nameField.text屬性都指向同一個NSString對象,但name不是擁有者
2.如果文本框的内容發生變化,則原先的NSString對象就沒有擁有者,會被釋放,此時name變量會自動變成nil,稱為空指針
weak型的指針變量自動變為nil是非常友善的,這樣阻止了weak指針繼續指向已釋放對象,避免了野指針的産生,不然會導緻非常難于尋找的Bug,空指針消除了類似的問題
3.weak指針主要用于“父-子”關系,父親擁有一個兒子的strong指針,是以父親是兒子的所有者;但為了阻止所有權循環,兒子需要使用weak指針指向父親。典型例子是delegate模式,你的ViewController通過strong指針(self.view)擁有一個UITableView, UITableView的dataSource和delegate都是weak指針,指向你的ViewController
五、strong和weak指針的使用注意
1.下面代碼是有問題的:
[java] view plain copy
- __weak NSString *str = [[NSString alloc] initWithFormat:@"1234"];
- NSLog(@"%@", str); // 列印出來是"(null)"
str是個weak指針,是以NSString對象沒有擁有者,在建立之後就會被立即釋放。Xcode還會給出警告("Warning: Assigning retained object to weak variable; object will be released after assignment")
2.一般的指針變量預設就是strong類型的,是以一般我們對于strong變量不加__strong修飾,以下兩行代碼是等價的:
[java] view plain copy
- NSString *name = self.nameField.text;
- __strong NSString *name = self.nameField.text;
3.屬性可以是strong或weak,寫法如下
[java] view plain copy
- @property (nonatomic, strong) NSString *name;
- @property (nonatomic, weak) id delegate;
4. 以下代碼在ARC之前是可能會行不通的,因為在手動記憶體管理中,從NSArray中移除一個對象時,這個對象會發送一條release消息,可能會被立即釋放。随後NSLog()列印該對象就會導緻應用崩潰
[java] view plain copy
- id obj = [array objectAtIndex:0];
- [array removeObjectAtIndex:0];
- NSLog(@"%@", obj);
在ARC中這段代碼是完全合法的,因為obj變量是一個strong指針,它成為了對象的擁有者,從NSArray中移除該對象也不會導緻對象被釋放
六、ARC小結
1.有了ARC,我們的代碼可以清晰很多,你不再需要考慮什麼時候retain或release對象。唯一需要考慮的是對象之間的關聯,也就是哪個對象擁有哪個對象?
2.ARC也有一些限制:
1> 首先ARC隻能工作于Objective-C對象,如果應用使用了Core Foundation或malloc()/free(),此時還是需要你來手動管理記憶體
2> 此外ARC還有其它一些更為嚴格的語言規則,以確定ARC能夠正常地工作
3.雖然ARC管理了retain和release,但并不表示你完全不需要關心記憶體管理的問題。因為strong指針會保持對象的生命,某些情況下你仍然需要手動設定這些指針為nil,否則可能導緻應用記憶體不足。無論何時你建立一個新對象時,都需要考慮誰擁有該對象,以及這個對象需要存活多久
4.ARC還能很好地結合C++使用,這對遊戲開發是非常有幫助的。對于iOS 4,ARC有一點點限制(不支援weak指針),但也沒太大關系
七、ARC使用注意總結
1.不能直接調用dealloc方法,不能調用retain,release,autorelease,retainCount方法,包括@selector(retain)的方式也不行 2.可以用dealloc方法來管理一些資源,但不能用來釋放執行個體變量,也不能在dealloc方法裡面去掉[super dealloc]方法,在ARC下父類的dealloc同樣由編譯器來自動完成 3.Core Foundation類型的對象仍然可以用CFRetain,CFRelease這些方法 4.不能再使用NSAllocateObject和NSDeallocateObject對象 5.不能在C結構體中使用對象指針,如果有類似功能可以建立一個Objective-C類來管理這些對象 6.在id和void*之間沒有簡便的轉換方法,同樣在Objective-C和Core Foundation類型之間的轉換都需要使用編譯器制定的轉換函數 7.不能再使用NSAutoreleasePool對象,ARC提供了@autoreleasepool塊來代替它,這樣更有效率 8.不能使用記憶體存儲區(不能再使用NSZone) 9.不能以new為開頭給一個屬性命名 10.聲明IBOutlet時一般應當使用weak,除了對StoryBoard這樣nib中間的頂層對象要用strong 11.weak相當于老版本的assign,strong相當于retain