1. 程式人生 > >iOS 代理為啥要用weak修飾? (刨根問底一)

iOS 代理為啥要用weak修飾? (刨根問底一)

在開發中我們經常使用代理,或自己寫個代理,而代理屬性都用weak(assign)修飾,看過有些開發者用strong(retain),但並沒發現有何不妥,也不清楚weak(assign)與strong(retain)修飾有何區別

功能實現就行了,考慮這麼多幹嘛~~~我只能哈哈哈

  • weak:指明該物件並不負責保持delegate這個物件,delegate這個物件的銷燬由外部控制
@property (nonatomic, weak) id<HSDogDelegate>delegate;
  • strong該物件強引用delegate,外界不能銷燬delegate物件,會導致迴圈引用(Retain Cycles)
@property (nonatomic, strong) id<HSDogDelegate>delegate;

可能你還不太理解,沒關係,下面先舉例,看結果,再分析!

舉例

  • HSDog類

HSDog.h:

@protocol HSDogDelegate <NSObject>
@end

@interface HSDog : NSObject

@property (nonatomic, weak) id<HSDogDelegate>delegate;

@end

HSPerson.m:

#import "HSDog.h"
@implementation HSDog - (void)dealloc { NSLog(@"HSDog----銷燬"); } @end
  • HSPerson類

HSPerson.h:

@interface HSPerson : NSObject

@end

HSPerson.m:

#import "HSPerson.h"
#import "HSDog.h"

@interface HSPerson()<HSDogDelegate>
/** 強引用dog*/
@property (nonatomic, strong) HSDog *dog;
@end
@implementation HSPerson - (instancetype)init { self = [super init]; if (self) { // 例項化dog self.dog = [[HSDog alloc] init]; // dog的delegate引用self,self的retainCount,取決於delegate修飾,weak:retainCount不變,strong:retainCount + 1 self.dog.delegate = self; } return self; } - (void)dealloc { NSLog(@"HSPerson----銷燬"); } @end
  • 在ViewController實現
#import "ViewController.h"
#import "HSPerson.h"

@interface ViewController ()
@end

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    // 例項化person, self對person弱引用,person的retainCount不變
    HSPerson *person = [[HSPerson alloc] init];

}
@end

結果

  • weak修飾代理
@property (nonatomic, weak) id<HSDogDelegate>delegate;

執行->列印

HSPerson----銷燬
HSDog----銷燬
  • strong修飾代理
@property (nonatomic, strong) id<HSDogDelegate>delegate;

執行->列印
....並未列印,說明HSPerson、HSDog物件沒呼叫dealloc方法,兩個物件未銷燬
這也是我們經常說的記憶體洩露,該釋放的記憶體並未釋放!

分析

  • 使用strong

person對dog強引用

@property (nonatomic, strong) HSDog *dog; person

self.dog.delegate又對person強引用,使person的retainCount + 1

@property (nonatomic, strong) id<HSDogDelegate>delegate;

當viewController不對person引用後,dog.delegate對person還強引用著,person的retainCount為1,所以person不會釋放,dog固然也不會釋放,這就是造成迴圈引用的導致記憶體洩露的原因!

  • 使用weak

person對dog強引用

@property (nonatomic, strong) HSDog *dog; person

self.dog.delegate只對person弱引用,並未使person的retainCount + 1

@property (nonatomic, weak) id<HSDogDelegate>delegate;

所以當viewController不對person引用後,person的retainCount為0,即person會被釋放,那麼dog也被釋放