__weak和__strong的使用

1. 使用場景

??一般我們在使用block的時候, 都會特意去注意一個問題--循環(huán)引用的問題, 根據(jù)OC的引用計數(shù)機制, 當對象的引用計數(shù)為0的時候, 系統(tǒng)會釋放這個對象. 循環(huán)引用會導致我們的對象不能正常釋放, 類似資源爭奪的現(xiàn)象, 釋放A的條件是B的釋放, 而釋放B的條件是釋放A.

1.1 聲明一個是TestViewController里面定義一個block--callBack

@interface TestViewController : UIViewController
@property (nonatomic, copy) void(^callBack)(NSString* name);
@end

1.2在viewDidLoad里面實現(xiàn)并調(diào)用block

- (void)viewDidLoad {
    [super viewDidLoad];
    [self setCallBack:^(NSString *name) {
        NSLog(@"%@ %@", self, name);
    }];
    self.callBack(@"come on");
}
- (void)dealloc
{
    NSLog(@"%@ dealloc ", self);
}

這個代碼里面是一個最基礎的循環(huán)引用問題(測試貼圖), 一般我們解決此類問題需要有一個弱引用也就是我們所要講述的__weak,代碼如下

- (void)viewDidLoad {
    [super viewDidLoad];
    __weak typeof(self) weakSelf = self;
    [self setCallBack:^(NSString *name) {
        NSLog(@"%@ %@", weakSelf, name);
    }];
    self.callBack(@"come on");
}

這樣的話, TestViewController就可以正常的dealloc了.

2. 注意事項

這樣寫會存在一定的隱患, 因為__weak類型在這里是個局部變量, 而且weak屬性有個特點就是自動置為nil, 所以有可能在我們?nèi)ナ褂脀eakSelf的時候, weakSelf已經(jīng)是空值了.

- (void)viewDidLoad {
    [super viewDidLoad];
    __weak typeof(self) weakSelf = self;
    [self setCallBack:^(NSString *name) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [NSThread sleepForTimeInterval:5];
            NSLog(@"%@ %@", weakSelf, name);
        });
    }];
    self.callBack(@"come on");
}

輸出結(jié)果是

2017-12-23 11:50:00.450854+0800 循環(huán)引用問題[5620:207264] <TestViewController: 0x7fc43ae025b0> dealloc
2017-12-23 11:50:02.952027+0800 循環(huán)引用問題[5620:207367] (null) come on

會先delloc, 然后才會走block里面的代碼. 可以看到此時的weakSelf已經(jīng)是null了, 如果我們做如下修改

- (void)viewDidLoad {
    [super viewDidLoad];
    __weak typeof(self) weakSelf = self;
    [self setCallBack:^(NSString *name) {
        __strong typeof(weakSelf) strongSelf = weakSelf;
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [NSThread sleepForTimeInterval:5];
            NSLog(@"%@ %@", strongSelf, name);
        });
    }];
    self.callBack(@"come on");
}

輸出結(jié)果如下

2017-12-23 11:57:05.182026+0800 循環(huán)引用問題[5709:215351] <TestViewController: 0x7ff217725e50> come on
2017-12-23 11:57:05.182414+0800 循環(huán)引用問題[5709:214769] <TestViewController: 0x7ff217725e50> dealloc

__strong可以使block對self進行強制持有, 使他的retainCount+1, 使self不能dealloc, 而strongSelf是個局部變量, 當block結(jié)束的時候就會自動釋放掉, 所以此時的self的self的retainCount-1, 然后可以釋放掉self.

- (void)viewDidLoad {
    [super viewDidLoad];
    __weak typeof(self) weakSelf = self;
    [self setCallBack:^(NSString *name) {
        NSLog(@"strong之前:%lu", CFGetRetainCount((__bridge CFTypeRef)(((NSObject *)weakSelf))));
        __strong typeof(weakSelf) strongSelf = weakSelf;
        NSLog(@"strong之后:%lu", CFGetRetainCount((__bridge CFTypeRef)(((NSObject *)weakSelf))));
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [NSThread sleepForTimeInterval:5];
            NSLog(@"%@ %@", strongSelf, name);
        });
    }];
    self.callBack(@"come on");
}

輸出結(jié)果是

2017-12-23 12:01:57.725400+0800 循環(huán)引用問題[5782:221024] strong之前:10
2017-12-23 12:01:57.725636+0800 循環(huán)引用問題[5782:221024] strong之后:11
2017-12-23 12:02:02.729803+0800 循環(huán)引用問題[5782:221561] <TestViewController: 0x7f8bc6f04230> come on
2017-12-23 12:02:02.730176+0800 循環(huán)引用問題[5782:221024] <TestViewController: 0x7f8bc6f04230> dealloc

可以看到strong之后的retainCount+1了.

源碼地址
https://github.com/autmaple/RetainCycleProblem

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容