ARC中strong和weak的探究
曾幾何時, 自己也是對 strong/retain/weak等暈頭轉向, 今天看到了自己之前整理的關於ARC中的 strong指標和weak指標的 demo 和幾篇文章, 所以便來總結一下.
簡介
ARC是自iOS 5之後增加的新特性,完全消除了手動管理記憶體的煩瑣,編譯器會自動在適當的地方插入適當的retain、release、autorelease語句。你不再需要擔心記憶體管理,因為編譯器為你處理了一切
注意:ARC 是編譯器特性,而不是 iOS 執行時特性(除了weak指標系統),它也不是類似於其它語言中的垃圾收集器。因此 ARC 和手動記憶體管理效能是一樣的,有時還能更加快速,因為編譯器還可以執行某些優化
原理
ARC 的規則非常簡單:只要還有一個變數指向物件,物件就會保持在記憶體中。當指標指向新值,或者指標不再存在時,相關聯的物件就會自動釋放。這條規則對於成員變數、synthesize屬性、區域性變數都是適用的
strong指標和weak指標區別
strong 指標可以理解為物件的擁有者, weak 指標可以指向某個物件,但不屬於物件的擁有者.
如上圖面的關係圖, 總結為以下幾點:
1.strong指標和weak指標都指向同一個物件,但weak 指標不是擁有者
2.如果strong 指標指向另一個物件,則原先的物件就沒有擁有者,就會被釋放,此時 weak 指標會自動變成nil,稱為空指標. 所以, weak型的指標變數自動變為nil是非常方便的,這樣阻止了weak指標繼續指向已釋放物件,避免了野指標的產生,不然會導致非常難於尋找的Bug,空指標消除了類似的問題
3.weak指標主要用於“父-子”關係,父親擁有一個兒子的strong指標,因此父親是兒子的所有者;但為了阻止所有權迴圈,兒子需要使用weak指標指向父親。典型例子是delegate模式,你的ViewController通過strong指標(self.view)擁有一個UITableView, UITableView的dataSource和delegate都是weak指標,指向你的ViewController
程式碼實踐
為了使理解更清晰, 整理了一個小的 demo, 下面再來看一下. 先簡單說下思路, ARC 自動管理物件的釋放, 所以就涉及到一個自動釋放池的概念, 這裡就不贅述了. 在自動釋放池內, 建立三組或強或弱的對比屬性,建立時賦值, 列印. 然後在自動釋放池外,即通過螢幕按鈕點選事件實現, 再重新列印之前的所有屬性, 再次對比, 驗證以上說法.
第一次測試
#import "ViewController.h"
@interface ViewController ()
//第一組
@property (nonatomic, strong) NSString *groupOne_strong;
@property (nonatomic, weak) NSString *groupOne_weak;
//第二組
@property (nonatomic, strong) NSString *groupTwo_strong1;
@property (nonatomic, strong) NSString *groupTwo_strong2;
//第三組
@property (nonatomic, strong) NSString *groupThree_strong;
@property (nonatomic, weak) NSString *groupThree_weak;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
@autoreleasepool {
//正常的強引/弱引用對比
[self strongAndWeakCompare];
//強引用賦值給強引用,將第一個強引用置為 nil
[self strongGiveToStrong];
//強引用賦值給弱引用,將強引用置為 nil
[self strongGiveToWeak];
}
}
//正常的強引/弱引用對比
- (void)strongAndWeakCompare
{
self.groupOne_strong = [NSString stringWithFormat:@"強弱對比"];
self.groupOne_weak = [NSString stringWithFormat:@"strongAndWeakCompare"];
NSLog(@"第1組強弱對比:srong=%@-<%p>,weak=%@-<%p>",_groupOne_strong,_groupOne_strong,_groupOne_weak,_groupOne_weak);
}
//強引用賦值給強引用,將第一個強引用置為 nil
- (void)strongGiveToStrong
{
self.groupTwo_strong1 = [NSString stringWithFormat:@"強賦強"];
self.groupTwo_strong2 = _groupTwo_strong1;
_groupTwo_strong1 = nil;
NSLog(@"第2組強賦強:srong1=%@-<%p>,strong2=%@-<%p>",_groupTwo_strong1,_groupTwo_strong1,_groupTwo_strong2,_groupTwo_strong2);
}
//強引用賦值給弱引用,將強引用置為 nil
- (void)strongGiveToWeak
{
self.groupThree_strong = [NSString stringWithFormat:@"強賦弱"];
self.groupThree_weak = _groupThree_strong;
_groupThree_strong = nil;
NSLog(@"第3組強賦弱:srong=%@-<%p>,weak=%@-<%p>",_groupThree_strong,_groupThree_strong,_groupThree_weak,_groupThree_weak);
}
//待迴圈池中的物件銷燬後,進行列印驗證
- (IBAction)click:(id)sender
{
NSLog(@"第1組強弱對比:srong=%@-<%p>,weak=%@-<%p>",_groupOne_strong,_groupOne_strong,_groupOne_weak,_groupOne_weak);
NSLog(@"第2組強賦強:srong1=%@-<%p>,strong2=%@-<%p>",_groupTwo_strong1,_groupTwo_strong1,_groupTwo_strong2,_groupTwo_strong2);
NSLog(@"第3組強賦弱:srong=%@-<%p>,weak=%@-<%p>",_groupThree_strong,_groupThree_strong,_groupThree_weak,_groupThree_weak);
}
PS:在自動釋放池內還未釋放時(這裡也可以不寫@autoreleasepool,ARC 會自動新增). 在這裡這個自動釋放池只是表明了一個物件的釋放時機, MRC 中物件的釋放時機更加靈活,但 weak 不可以在 MRC 情況下使用.
第一次列印結果
先看列印結果, 自動釋放池內列印結果:
第1組強弱對比:srong=強弱對比-<0x7fe70945d320>, weak=strongAndWeakCompare-<0x7fe709456960>
第2組強賦強:srong1=(null)-<0x0>,strong2=強賦強-<0x7fe70945c460>
第3組強賦弱:srong=(null)-<0x0>,weak=強賦弱-<0x7fe709459750>
點選螢幕按鈕, 自動釋放池外列印結果:
第1組: 強弱對比:srong=強弱對比-<0x7fe70945d320>,weak=(null)-<0x0>
第2組: 強賦強:srong1=(null)-<0x0>,strong2=強賦強-<0x7fe70945c460>
第3組: 強賦弱:srong=(null)-<0x0>,weak=(null)-<0x0>
根據列印結果發現, 正如一開始我們所說的一樣. 但是在第3組中 strong指標在置為 nil 後立即列印weak 指標, 其不為 nil, 這就是因為自動釋放池中還沒有銷燬, 所以此時不會為 nil.
第二次測試
但我在整理的時候, 發現了一個問題, 一個 strong和 weak 的對比, 不會像剛剛這樣, 難道是種特殊情況嗎, 來看一下.
屬性中新增第四組:
//第四組
@property (nonatomic, strong)NSString *groupFour_strong;
@property (nonatomic, weak)NSString *groupFour_weak;
自動釋放池內執行以下程式碼:
//強引用於常量區, 將強引用置為 nil
- (void)constantStrongGiveToWeak
{
self.groupFour_strong = @"常量區賦值";
// self.groupFour_strong = [NSString stringWithFormat:@"a"];
self.groupFour_weak = _groupFour_strong;
_groupFour_strong = nil;
NSLog(@"第4組常量區賦值:srong=%@-<%p>,weak=%@-<%p>",_groupFour_strong,_groupFour_strong,_groupFour_weak,_groupFour_weak);
}
自動釋放池外點選事件中新增程式碼:
//待迴圈池中的物件銷燬後,進行列印驗證
- (IBAction)click:(id)sender
{
NSLog(@"第4組常量區賦值:srong=%@-<%p>,weak=%@-<%p>",_groupFour_strong,_groupFour_strong,_groupFour_weak,_groupFour_weak);
}
第二次測試列印結果
來看一下列印結果 (自動釋放池內/外):
第4組常量區賦值:srong=(null)-<0x0>,weak=常量區賦值-<0x107a55160>
第4組常量區賦值:srong=(null)-<0x0>,weak=常量區賦值-<0x107a55160>
這時, 會發現, 自動釋放池外列印結果 weak 指標竟然不為 nil. 因為第一次測試中字串的都是棧區建立的,所以也是在棧區來測試的, 若是直接賦值字元創,如 self.groupOne_strong = @”強弱對比”, 這樣開闢的空間在常量區,所以即使將其置為 nil, 其也不會釋放.
第三次測試(拓展)
新增屬性, 宣告特性為 weak 型別的 UIView
//宣告關鍵字為 weak 的 View 作為成員變數
@property (nonatomic, weak) UIView *red_weak_view;
自動釋放池內執行以下程式碼:
//建立 weak View
- (void)createWeakView
{
UIView *temp_view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
temp_view.backgroundColor = [UIColor redColor];
[self.view addSubview:temp_view];
self.red_weak_view = temp_view;
}
自動釋放池外點選事件中新增程式碼:
//待迴圈池中的物件銷燬後,進行列印驗證
- (IBAction)click:(id)sender
{
NSLog(@"redview=%@",_red_weak_view);
}
第三次測試列印結果
自動釋放池外列印結果:
redview=< UIView: 0x7fe63a4aeaf0; frame = (0 0; 100 100); layer = < CALayer: 0x7fe63a4a2650 > >
像上面這樣直接建立的 view, 系統自動定義為 strong 型別的, 只是其作用域小. 當其addSubview後, 其引用計數 +1, 並不會釋放, 所以屬性中的weak view可以全域性使用.
我曾見過有人這樣使用, 但我並不明白其中的優勢所在, 若大神懂得,望不吝賜教. 所以我在開發中會直接宣告一個 strong 的屬性, 如果忘記addSubview的話, 其便不能得到.
相關推薦
ARC中strong和weak的探究
曾幾何時, 自己也是對 strong/retain/weak等暈頭轉向, 今天看到了自己之前整理的關於ARC中的 strong指標和weak指標的 demo 和幾篇文章, 所以便來總結一下. 簡介 ARC是自iOS 5之後增加的新特性,完全消除了手動管理
ios中strong和weak的解釋理解
來自stackoverflow解釋的挺有意思的 Imagine our object is a dog, and that the dog wants to run away (be deallocated). Strong pointers are like a leas
iOS 5中的strong和weak關鍵字
iOS 5 中對屬性的設定新增了strong 和weak關鍵字來修飾屬性 strong 用來修飾強引用的屬性; @property (strong) SomeClass * aObject; 對應原來的 @property (retain) SomeClass * aObj
iOS中assign和weak的區別
一、區別 assign與weak,它們都是弱引用宣告型別,最大的區別在那呢? 如果用weak宣告的變數在棧中就會自動清空,賦值為nil。 如果用assign宣告的變數在棧中可能不會自動賦值為nil,就會造成野指標錯誤! 二、例項 他們常用在基本型別屬性,比如BO
strong和weak引用的講解
由於這幾天一直在學習ViewController之間的資料傳輸方法,學著學著就有了疑問:為什麼在前向傳輸時(forward)可以使用屬性傳值,而後向傳輸(backward)時不能再使用,為了弄清楚這個問題,搜了很多文章,大部分都是在講傳輸方法的使用,沒有找到原因,但是根據蛛絲馬跡找到了strong和wea
strong和weak的區別
一、簡介 ARC是自iOS 5之後增加的新特性,完全消除了手動管理記憶體的煩瑣,編譯器會自動在適當的地方插入適當的retain、release、autorelease語句。你不再需要擔心記憶體管理,因為編譯器為你處理了一切 注意:ARC 是編譯器特性,而不是 iOS
iOS中用strong和weak來修飾成員變數的對比
對於純程式碼佈局,用@property宣告成員變數時,我是很自然的用strong來修飾的。然後突然有人問我用weak來修飾可不可以,我第一反應是不可以,因為用weak來修飾,初始化過後就會被釋放掉,就算我第一句寫了初始化的方法,立即執行addSubView也是沒
swift ARC中的strong、weak、unowned
Swift 用自動引用計數ARC(Automatic Reference Counting)方式來跟蹤和管理app的記憶體使用。這使得記憶體管理成為swift內部的機制,不需要認為考慮。ARC會自動釋放那些不再被需要的變數。 ARC如何工作 每次建立一個類的
GNU的strong symbol和weak symbol
一個 glib 根據 pos ati mic 例子程序 來看 int 首先,同樣的原型的兩個函數在連個不同的c文件中都有定義,把這兩個c文件編譯、連接在一起,也沒有什麽錯誤。原因就是因為,gcc中有一個strong symbol和weak symbol的概念。默認函數定義都
重新理解strong與weak(強引用,弱引用),以及strong和copy的區別
- (void)test: { NSMutableString *mStr = [NSMutableStringstringWithFormat:@"hello"]; self.sStr = mStr; self.cStr = mStr; NSLog
strong and weak 強引用和弱引用的區別
(weak和strong)不同的是 當一個物件不再有strong型別的指標指向它的時候 它會被釋放 ,即使還有weak型指標指向它。 一旦最後一個strong型指標離去 ,這個物件將被釋放,所有剩餘的weak型指標都將被清除。 可能有個例子形容是妥當的。 想象我們的物件是一條狗,狗想要跑掉(被釋放)。 s
iOS 屬性中strong,weak,assign,retain,copy等特性
導語: 在初學iOS的時候,不明白property中屬性有什麼作用,比如strong, weak, assign, retain, copy等特性。 一、 Objective-C程式設計師的基本記憶體管理模型有三種 自動垃圾收集(現在Apple不建議使用垃圾收集,建議使用A
iOS中MRC和ARC混編
1. 在targets的build phases選項下Compile Sources下選擇,不使用arc編譯的檔案,雙擊它,輸入-fno-objc-arc即可(這個類就可以使用MRC模式) 2. MRC工程中也可以使用ARC的類。方法如下: 在targets的bui
《Objective-C高階程式設計:引用計數和strong ,weak
轉載請註明出處 如果覺得文章對你有所幫助,請通過留言或關注微信公眾帳號wangzzstrive來支援我,謝謝! 一、前言 這本書由日本人Kazuki Sakamoto和Tomohiko Furumoto所著,主要講了ARC、Blocks、GCD三個模組。總
深入探究Java中equals()和==的區別是什麼
目錄 相等判斷符"=="介紹 "=="判斷基本型別是否相等. "=="判斷引用型別資料是否相等 判斷是否相等-equals()方法
從語言設計的角度探究Java中hashCode()和equals()的關係
目錄 一. 基礎: hashCode()和equals()簡介 二. 漫談: 引入hashCode()與equals()之間的關係 三. 解密: 深入理解hashCode()和equals()之間的關係. 四
JS中isPrototypeOf 和hasOwnProperty 的區別
另一個 strong 是否 指定 不同 名稱 功能 成員 eof 1、isPrototypeOf isPrototypeOf是用來判斷指定對象object1是否存在於另一個對象object2的原型鏈中,是則返回true,否則返回false。 格式如下: object1.is
Mybatis中javaType和jdbcType對應關系
mat brush true real default url define red tools MyBatis 通過包含的jdbcType類型 BIT FLOAT CHAR TIMESTAMP OTHER
odoo系統中name_search和name_get用法
打印 per sequence not 添加 product xpath ret 領料單 自動帶出工序和工序序號,兩個條件都能搜索,並且兩個都帶出來顯示在前端: # 輸入工序序號會自動帶出工序名// def name_search(self, cr,user,name=
Python在函數中使用*和**接收元組和列表
eight argument ron err 由於 .net 表示 方法 class 當要使函數接收元組或字典形式的參數 的時候,有一種特殊的方法,它分別使用*和**前綴 。這種方法在函數需要獲取可變數量的參數 的時候特別有用。[註意] [1] 由於在args變量前有*前綴