1. 程式人生 > >ARC中strong和weak的探究

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的話, 其便不能得到.

相關推薦

ARCstrongweak探究

曾幾何時, 自己也是對 strong/retain/weak等暈頭轉向, 今天看到了自己之前整理的關於ARC中的 strong指標和weak指標的 demo 和幾篇文章, 所以便來總結一下. 簡介 ARC是自iOS 5之後增加的新特性,完全消除了手動管理

iosstrongweak的解釋理解

來自stackoverflow解釋的挺有意思的 Imagine our object is a dog, and that the dog wants to run away (be deallocated). Strong pointers are like a leas

iOS 5strongweak關鍵字

iOS 5 中對屬性的設定新增了strong 和weak關鍵字來修飾屬性 strong 用來修飾強引用的屬性; @property (strong) SomeClass * aObject; 對應原來的 @property (retain) SomeClass * aObj

iOSassignweak的區別

一、區別 assign與weak,它們都是弱引用宣告型別,最大的區別在那呢? 如果用weak宣告的變數在棧中就會自動清空,賦值為nil。 如果用assign宣告的變數在棧中可能不會自動賦值為nil,就會造成野指標錯誤! 二、例項 他們常用在基本型別屬性,比如BO

strongweak引用的講解

由於這幾天一直在學習ViewController之間的資料傳輸方法,學著學著就有了疑問:為什麼在前向傳輸時(forward)可以使用屬性傳值,而後向傳輸(backward)時不能再使用,為了弄清楚這個問題,搜了很多文章,大部分都是在講傳輸方法的使用,沒有找到原因,但是根據蛛絲馬跡找到了strong和wea

strongweak的區別

一、簡介 ARC是自iOS 5之後增加的新特性,完全消除了手動管理記憶體的煩瑣,編譯器會自動在適當的地方插入適當的retain、release、autorelease語句。你不再需要擔心記憶體管理,因為編譯器為你處理了一切 注意:ARC 是編譯器特性,而不是 iOS

iOS中用strongweak來修飾成員變數的對比

對於純程式碼佈局,用@property宣告成員變數時,我是很自然的用strong來修飾的。然後突然有人問我用weak來修飾可不可以,我第一反應是不可以,因為用weak來修飾,初始化過後就會被釋放掉,就算我第一句寫了初始化的方法,立即執行addSubView也是沒

swift ARCstrongweak、unowned

Swift 用自動引用計數ARC(Automatic Reference Counting)方式來跟蹤和管理app的記憶體使用。這使得記憶體管理成為swift內部的機制,不需要認為考慮。ARC會自動釋放那些不再被需要的變數。 ARC如何工作 每次建立一個類的

GNU的strong symbolweak symbol

一個 glib 根據 pos ati mic 例子程序 來看 int 首先,同樣的原型的兩個函數在連個不同的c文件中都有定義,把這兩個c文件編譯、連接在一起,也沒有什麽錯誤。原因就是因為,gcc中有一個strong symbol和weak symbol的概念。默認函數定義都

重新理解strongweak(強引用,弱引用),以及strongcopy的區別

- (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

iOSMRCARC混編

1. 在targets的build phases選項下Compile Sources下選擇,不使用arc編譯的檔案,雙擊它,輸入-fno-objc-arc即可(這個類就可以使用MRC模式) 2.  MRC工程中也可以使用ARC的類。方法如下: 在targets的bui

《Objective-C高階程式設計:引用計數strongweak

轉載請註明出處 如果覺得文章對你有所幫助,請通過留言或關注微信公眾帳號wangzzstrive來支援我,謝謝! 一、前言 這本書由日本人Kazuki Sakamoto和Tomohiko Furumoto所著,主要講了ARC、Blocks、GCD三個模組。總

深入探究Javaequals()==的區別是什麼

目錄 相等判斷符"=="介紹 "=="判斷基本型別是否相等. "=="判斷引用型別資料是否相等 判斷是否相等-equals()方法

從語言設計的角度探究JavahashCode()equals()的關係

目錄 一. 基礎: hashCode()和equals()簡介 二. 漫談: 引入hashCode()與equals()之間的關係 三. 解密: 深入理解hashCode()和equals()之間的關係. 四

JSisPrototypeOf hasOwnProperty 的區別

另一個 strong 是否 指定 不同 名稱 功能 成員 eof 1、isPrototypeOf isPrototypeOf是用來判斷指定對象object1是否存在於另一個對象object2的原型鏈中,是則返回true,否則返回false。 格式如下: object1.is

MybatisjavaTypejdbcType對應關系

mat brush true real default url define red tools MyBatis 通過包含的jdbcType類型 BIT FLOAT CHAR TIMESTAMP OTHER

odoo系統name_searchname_get用法

打印 per sequence not 添加 product xpath ret 領料單 自動帶出工序和工序序號,兩個條件都能搜索,並且兩個都帶出來顯示在前端: # 輸入工序序號會自動帶出工序名// def name_search(self, cr,user,name=

Python在函數使用***接收元組列表

eight argument ron err 由於 .net 表示 方法 class 當要使函數接收元組或字典形式的參數 的時候,有一種特殊的方法,它分別使用*和**前綴 。這種方法在函數需要獲取可變數量的參數 的時候特別有用。[註意] [1] 由於在args變量前有*前綴