iOS中代理屬性為什么要用Weak修飾?
一.寫在前面
代理設計模式,在iOS開發過程中,是一個非常常見的設計模式,可以說用的范圍非常廣泛,而對初學者來講,常常對代理的屬性修飾用weak存在疑惑,因此下面就解釋一下其中非常簡單的道理.
二.必要的知識補充.
- 眾所周知,OC是一門面向對象的語言,因此,對象這個詞,在iOS中是個非常重要的詞匯了(扯淡).開發中,創建一個對象是再常見不過的事兒了,每個對象的創建都需要在內存中分配一定的空間,簡單的說,因為內存是有限的,所以一些沒有必要存在的對象,我們需要及時的去將它釋放,還原更多的內存空間(如果不進行釋放就會造成"內存泄露").
- 因此,在iOS中引入了引用計數(retainCount)這個詞匯,規定:只要引用計數為零,對象就會被釋放,注意是規定,規定就不要問為什么了.
- 這里主要介紹strong和weak兩個修飾詞(不能偏離重點),如果想了解其他的修飾詞(retain,copy,getter,setter...),可以Google一下,簡單點來講strong屬性會使引用計數+1,而weak修飾的對象不會使引用計數改變.
- OK了,有了上面的只是準備,應該可以理解下面的要解釋的東西了.
三.案例說明
- 案例介紹
```
案例中的類介紹: 案例共用到三個類,Baby類(嬰兒類),LLBabyServant類(保姆類),ViewControllr類(控制器類),其中說明問題的關鍵是之前兩個類.
假設,嬰兒類要想做一些事情(像換衣服了,方便了之類的...)就必須具有代理的屬性,因此指定了一個協議<LLBabyDelegate>,合情合理.而保姆需要成為嬰兒的代理,必須遵循協議,廢話不多說,上代碼!
```
- 首先介紹Baby類-----.h文件
```
// 制定協議
@protocol LLBabyDelegate <NSObject>
//這里可以編寫代理方法(該案例中用不到所以就不寫了)
@end
@interface Baby : NSObject
/**
* baby的代理屬性(這里用的是weak修飾,正確的做法)
*/
@property(nonatomic, weak) id<LLBabyDelegate>delegate;
@end
```
說明:跟上面描述的一樣嬰兒擁有一個代理的屬性.并且用修飾詞Weak修飾的.
接著粘Baby類-----.m文件
```
@implementation Baby
- (void)dealloc
{
NSLog(@"Baby被銷毀了");
}
@end
```
說明:該方法的作用是當該類的對象被銷毀時會調用-dealloc方法(在這個案例中用來觀察對象是否被銷毀了)
-
再有介紹BabyServant類-----.m文件
//BabyServant類也就是保姆必須遵循代理協議 @interface BabyServant()<LLBabyDelegate> //并有一個需要照顧的Baby @property(nonatomic, strong) Baby *baby; @end @implementation LLBabyServant //初始化方法 - (instancetype)init { self = [super init]; if (self) { // 初始化'嬰兒'對象 self.baby = [[Baby alloc]init]; // 設置'自己(LLBabyServant)'為(Baby)類的代理 self.baby.delegate = self; } return self; }
-
我們介紹最后一個類 ViewController類
@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; LLBabyServant *servant = [[LLBabyServant alloc]init]; } @end
說明: 在ViewController的方法ViewDidLoad中創建保姆對象,并且該對象作用的范圍是這個方法內部.這個方法執行完成,servant對象就會被銷毀了.
上面的代碼執行完成之后,運行結果如下:
2016-02-18 15:06:41.151 代理weak案例[1805:173874] LLBabyServant 被銷毀了
2016-02-18 15:06:41.152 代理weak案例[1805:173874] Baby類被銷毀了
這就說明LLBabyServant對象和Baby對象在沒有用處之后都會被銷毀,但是如果用代理用strong修飾,而不是用weak修飾,則不會打印上面的結果!
四.分析
1. 用weak分析圖如下:
-
整體來看如下圖
-
分開來看如下圖:
如果weak的話,在程序運行的時候不會造成循環引用,對象都會被順利的銷毀,所以會調用嬰兒類和保姆類的delloc方法
2. 用strong分析如下
-
整體來看如下圖
-
分開來看如下圖
如果strong的話,在程序運行的時候會造成循環引用(意思就是reatainCount不為0,只要有實線引用,計數器就+1),對象都不會的銷毀,所以會調用嬰兒類和保姆類不會調用delloc方法,從而造成了內存泄露的問題
這就是為什么代理屬性要用weak修飾的原因了!如果有哪里不嚴謹或者錯誤的地方,希望能夠多多交流.