iOS
中是否存在野指針的狀況?野指針指向一個已刪除的對象或未申請訪問受限內存區域的指針。特別要指出的是野指針不是空指針。ios
Block
一提到 Block
你們確定都知道要說的是循環引用。在 ARC
中,若是兩個對象相互持有對方,就會形成循環引用,致使內存沒法釋放。在 Block
中,最經常使用的場景則是,self
持有 block
, block
中又持有了 self
。例以下方一段代碼:緩存
@property (nonatmaic, copy) Block dataChanged;
- (void)setUpModel{
XYModel *model = [XYModel new];
model.dataChanged = ^(NSString *title) {
self.titleLabel.text = title;
};
self.model = model;
}
複製代碼
上面的這段代碼就會形成循環引用。那咱們怎麼破除呢?一般的作法都是使用 weakSelf
來處理,即:bash
- (void)setUpModel {
XYModel *model = [XYModel new];
__weak typeof(self) weakSelf = self;
model.dataChanged = ^(NSString *title) {
weakSelf.titleLabel.text = title;
};
self.model = model;
}
複製代碼
或許你還看到另一種不是很同樣的版本:less
- (void)setUpModel {
XYModel *model = [XYModel new];
__weak typeof(self) weakSelf = self;
model.dataChanged = ^(NSString *title) {
__strong typeof(self) strongSelf = weakSelf;
strongSelf.titleLabel.text = title;
};
self.model = model;
}
複製代碼
對比一下,多了一個 strongSelf
。那爲何又要多加一個 strongSelf
呢?async
考慮一下下面的代碼,oop
__weak __typeof__(self) weakSelf = self;
dispatch_group_async(_operationsGroup, _operationsQueue, ^{
[weakSelf doSomething];
[weakSelf doSomethingElse];
});
複製代碼
在 doSomething
時, weakSelf
不會被釋放,可是在 doSomethingElse
時,weakSelf
有可能被釋放。ui
這個時候就遇到了野指針問題,回答了一開始的題目。spa
在這裏就須要用到 strongSelf
,使用 __strong
確保在 Block
內, strongSelf
不會被釋放。線程
在使用 Block
時,如遇到循環引用問題,可使用 __weak
來破除循環引用。指針
若是在 Block
內須要屢次訪問 __weak
變量,則須要使用 __strong
來保持變量不會被釋放。
SDWebImage
中爲何要解碼圖片要說明這麼問題咱們須要先了解一下在 iOS
中,圖片顯示的流程。
歸納來講,從磁盤中加載一張圖片,並將它顯示到屏幕上,中間的主要工做流以下:
假設咱們使用
imageWithContentsOfFile:
方法從磁盤中加載一張圖片,這個時候的圖片並無解壓縮;而後將生成的
UIImage
賦值給UIImageView
;接着一個隱式的
CATransaction
捕獲到了UIImageView
圖層樹的變化;在主線程的下一個
run loop
到來時,Core Animation
提交了這個隱式的transaction
,這個過程可能會對圖片進行copy
操做,而受圖片是否字節對齊等因素的影響,這個copy
操做可能會涉及如下部分或所有步驟:
- 分配內存緩衝區用於管理文件
IO
和解壓縮操做;- 將文件數據從磁盤讀到內存中;
- 將壓縮的圖片數據解碼成未壓縮的位圖形式,這是一個很是耗時的
CPU
操做;- 最後
Core Animation
使用未壓縮的位圖數據渲染UIImageView
的圖層。在上面的步驟中,咱們提到了圖片的解壓縮是一個很是耗時的
CPU
操做,而且它默認是在主線程中執行的。那麼當須要加載的圖片比較多時,就會對咱們應用的響應性形成嚴重的影響,尤爲是在快速滑動的列表上,這個問題會表現得更加突出。
這裏順便提一下 imageNamed:
和 imageWithContentsOfFile:
的區別,這兩個 API
都須要解碼,而且工做流程都是一致的。不過imageNamed:
會作緩存處理,在下一次用到相同的資源時,就會從緩存裏面讀取。而 imageWithContentsOfFile:
則不會。因此網上大多文章都會告訴你,屢次使用的小圖片使用 imageNamed:
加載,一次性使用的大圖片使用 imageWithContentsOfFile:
加載。
對於上面引用的流程中最後提到,當有大量圖片滑動時就會形成主線程的卡頓,緣由就是解碼圖片在主線程中操做的。那有什麼辦法避免呢? 我在查詢關於這個問題的相關資料時,發現有些博客給出了2種方案:
咱們不使用
imageNamed:
加載圖片,使用其餘的方法,好比imageWithContentsOfFile:
咱們本身解碼圖片,能夠把這個解碼過程放到子線程
其實第一種方式無法避免卡頓。這就引出了爲何 SDWebImage
中須要本身解碼圖片。
在咱們使用
UIImage
的時候,建立的圖片一般不會直接加載到內存,而是在渲染的時候再進行解壓並加載到內存。這就會致使UIImage
在渲染的時候效率上不是那麼高效。爲了提升效率經過decodedImageWithImage
方法把圖片提早解壓加載到內存,這樣這張新圖片就再也不須要重複解壓了,提升了渲染效率。這是一種空間換時間的作法。
你也能夠關注個人公衆號,獲取更多文章。