iOS開發筆記之四十七——多執行緒場景下的KVO使用參考方案
阿新 • • 發佈:2019-01-26
如果你取檢索網路資料會發現,有人直接不建議把KVO與多執行緒混合使用,因為KVO的響應和KVO觀察的值變化是在一個執行緒上的,不同的執行緒可能會導致不可預知的後果。參考資料見這裡:
當然,場景總是千變萬化的,下面我就介紹一種多執行緒下使用KVO的場景。
具體場景如下:
(2)資料拿到後,建立一個子執行緒,執行緒去請求zip包資料,並解壓縮到本地(圖片.png檔案);
(3)通知(KVO)主執行緒,去本地目錄取圖片資源,重新整理UI;
具體程式碼實現如下
1、方案一:
(1)主執行緒viewDidLoad方法中,註冊監聽,併發送資料請求;
@weakify(self) [RACObserve(self, enablePromotionSkin)subscribeNext:^(NSNumber *enablePromotionSkin) { @strongify(self); if ([[self enablePromotionSkin] integerValue]) { //...重新整理UI } }];
(2)子執行緒中,解壓縮並通知主執行緒重新整理UI;
- (RACSignal *)fetchSkinSignalWithConfig:(NVModelBaseOSAppPromoDo *)skinConfig { return (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ //下載、解壓縮操作 //... //md5校驗 if ([[responseData md5] isEqualToString:skinConfig.md5]) { self.enablePromotionSkin = @(YES); //通知主執行緒 } }); }]; }
這樣的呼叫KVO是直接跨越執行緒,實際執行時發現,最終從主執行緒傳送請求,到圖片刷出來,會經歷5-10s的時間,zip包沒有超過500k,並且wifi網路下,這個真的好慢,沒有人能容忍。
KVO訊息從子執行緒發出,到主執行緒上響應,而nonatomic屬性的enablePromotionSkin是非執行緒安全的,這樣設計會導致不可預知的問題。
2、方案二:
RAC本身有比較強大機制可以處理這種非同步場景:
(1)主執行緒註冊時,強制指定了主執行緒處理訊息;
(2)子執行緒處理時,強制由主執行緒處理;@weakify(self) [[RACObserve(self, enablePromotionSkin) deliverOn:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSNumber *enablePromotionSkin) { @strongify(self); if ([self enablePromotionSkin] integerValue) { //...重新整理UI } }];
- (RACSignal *)fetchSkinSignalWithConfig:(NVModelBaseOSAppPromoDo *)skinConfig
{
return [RACSignal startEagerlyWithScheduler:[RACScheduler mainThreadScheduler] block:^(id<RACSubscriber> subscriber) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
//....
});
}];
}
這樣之後,圖片的下載一般會在2s左右就會刷新出來,基本達到了預期效果;
3、方案三:
如果不用RAC提供的機制,我們也可以採取直接主執行緒發訊息的方法:
dispatch_async(dispatch_get_main_queue(), ^{
self.enablePromotionSkin = YES;
});
這種方法可以達到與方案二相同的效果。