1. 程式人生 > >__weak typeof(self) weakSelf=self; __strong typeof(weakSelf) strongSelf = weakSelf;

__weak typeof(self) weakSelf=self; __strong typeof(weakSelf) strongSelf = weakSelf;

使用Block時何時需要WeakSelf和StrongSelf?

主題 iOS開發

現在我們用 Objective-C 寫程式碼時已經越來越多地用到了block,相比delegate的回撥方式,block更直觀易用。相信每個使用過block的人都遇到過block中使用self時需要weakself的情況,以下就是非常典型的一段程式碼:

__weak __typeof(self)weakSelf = self;

[self.context performBlock:^{

    __strong __typeof(weakSelf)strongSelf = weakSelf;

    [strongSelf doSomething];

}];

對於小白的我一般越到這種情況就是直接拷貝上面這個模板到需要的程式碼中去,而不知箇中原委。但作為一個合格的程式設計師,是需要完完全全明白自己寫的每一行程式碼是在做什麼的,所以現在就簡單說明一下這個 WeakSelf 和 StrongSelf 到底是什麼。首先看下面這段程式碼:

[UIView animateWithDuration:0.2 animations:^{

    self.myView.alpha = 1.0;

}];

在ARC環境下的,每個block在建立時,編譯器會對裡面用到的所有物件自動增加一個reference count,然後當block執行完畢時,再釋放這些reference。針對上面的程式碼,在animations block執行期間,self(假設這裡的self是個view controller)的引用數會被加1,執行完後再次減1。但這種情況下為什麼我們一般不會去weakify self呢?因為這個block的生命週期是明確可知的,在這個block執行期間當前的view controller一般是不會被銷燬的,所以不存在什麼風險。現在我們看下面這個例子:

NSBlockOperation *op = [[[NSBlockOperation alloc] init] autorelease];

[op addExecutionBlock:^ {

    [self doSomething];

    [self doMoreThing];

}];

在這種情況下,我們並不知道這個execution block什麼時候會執行完畢,所以很有可能發生的情況是,我在block還沒執行完畢時就想銷燬當前物件(比方說使用者關閉了當前頁面),這時就會因為block還對self有一個reference而沒有立即銷燬,這會引起很多問題,比方說你寫在 - (void)dealloc {}

中的程式碼並不能馬上得到執行。所以為了避免這種情況,我們會在block前加上 __weak __typeof(self)weakSelf = self; 的定義來使block對self獲取一個弱引用(也就是refrence count不會加1)。

那block中的StrongSelf又是做什麼的呢?還是上面的例子,當你加了WeakSelf後,block中的self隨時都會有被釋放的可能,所以會出現一種情況,在呼叫doSomething的時候self還存在,在doMoreThing的時候self就變成nil了,所以為了避免這種情況發生,我們會重新strongify self。一般情況下,我們都建議這麼做,這沒什麼風險,除非你不關心self在執行過程中變成nil,或者你確定它不會變成nil(比方說所以block都在main thread執行)。

好了,簡要的說明到此結束,想要詳細瞭解的可以自行google,這類文章很多。前面程式碼中的WeakSelf、StrongSelf轉換看起來很冗長,不利於閱讀程式碼,下面介紹一個超好用的巨集定義程式碼,它是這個開源庫的一部分: libextobjc 。把它加入到專案中後,就可以用以下如此簡潔的格式來完成轉換啦:

#import "EXTScope.h"

@weakify(self)

[self.context performBlock:^{

@strongify(self)

    [self doSomething];

}];

自己的理解:

進入Block之前加一遍__weak 讓self的引用計數不-1 。這樣的話self會隨著當前控制元件的釋放而釋放。如果不寫的話,block塊中預設會將裡面所有內容的引用計數+1.有可能當前控制元件釋放了,但是self還沒有釋放。

進入Block之後加一遍__strong 讓self的引用計數+1 ,這樣的話,self就不會再離開block的時候被釋放。