[iOS][OC] 自定義 Promise 處理序列的非同步操作
背景
iOS
應用中很多操作是非同步的,比如:
- 網路請求的回撥
-
UIAlertController
等待使用者點選事件的回撥 - 定位的回撥
等等,當這些操作需要逐個序列去執行時,由於不同條件下的回撥結果以及不同操作的回撥順序,如果連續巢狀會導致業務嚴重耦合,多個操作回撥加上可能的錯誤處理就會形成常說的“回撥地獄”(舉例如下面的虛擬碼),造成邏輯可讀性差,且影響以後的維護。
/// 回撥地獄
- (void)callbackHell {
[TestManager doSomethingWithCompletion:^{
NSLog(@"No 1 done");
[TestManager doSomethingWithCompletion:^{
NSLog(@"No 2 done");
[TestManager doSomethingWithCompletion:^{
NSLog(@"No 3 done");
}];
}];
}];
}
針對序列情況下的非同步回撥的處理,可以將非同步回撥進行一次封裝處理,這種對一個操作執行的預期,通常稱為 Promise
。
將每一個非同步的回撥進行封裝後放入到 PromiseManager 處理,效果舉例如下:
/// 使用 Promise
- (void)testPromise {
GSPromise *a = [GSPromise promiseWithHandler:^(dispatch_block_t then){
[TestManager doSomethingWithCompletion:^{
NSLog(@"done a"); then();
}];
}];
GSPromise *b = [GSPromise promiseWithHandler:^(dispatch_block_t then){
[TestManager doSomethingWithCompletion:^{
NSLog(@"done b"); then();
}];
}];
GSPromise *c = [GSPromise promiseWithHandler:^(dispatch_block_t then){
[TestManager doSomethingWithCompletion:^{
NSLog(@"done c"); then();
}];
}];
GSPromiseManager *manager = [GSPromiseManager manangerWithPromises:@[a, b]];
[manager addPromise:c];
}
解決方案
序列操作的順序是,一個操作結束後執行下一個操作,因此可將“執行下一個操作”這一事件,封裝入一個 block 中 (稱為 then
),並要求上一個操作執行完成後呼叫。
此外,將操作需要執行的方法也封裝入一個 block 中 (稱為 handler
),要求每一個操作都具備 handler
這一屬性,因此將該屬性宣告為協議 GSPromisable(如下),要求操作去遵循。
/**
what a promise will execute
@param then should call this block after promise done
*/
typedef void(^GSPromiseHandler)(dispatch_block_t then);
@protocol GSPromisable <NSObject>
/**
the handler which a promise should retain
*/
@property (nonatomic, copy) GSPromiseHandler handler;
@end
其中,遵循 GSPromisable
協議的物件即 promise
, 都新增到 PromiseManager
所管理的容器陣列中,每個 promise 的handler
屬性,將由外部的 PromiseManager
在合適的時機呼叫。為實現 PromiseManager
對序列的管理,manager
在執行執行操作的 handler
時將上文的 then
操作傳遞到 handler
中,如此 handler
在完成自身操作後呼叫 then
,實現下一步操作的繼續,實現如下:
/// try to handle next operation
- (void)try2Start {
if (self.isWorking) return;
id <GSPromisable> first = container.firstObject;
if (!first) return;
self.working = YES;
dispatch_block_t then = ^{
self.working = NO;
@synchronized (self) {
if (!container.firstObject) return;
[container removeObjectAtIndex:0];
}
[self try2Start];
};
first.handler(then);
}
值得一提的是,這種設計思路類似於前文的《[iOS] [OC] 關於block回撥、高階函式“回撥再呼叫”及專案實踐》
原始碼及demo
延伸
關於非同步的操作處理有許多優秀的開源框架可以學習,推薦:
感謝同事 Zoe ,其對工作水平的不懈追求,促使更好方案的實現和改進。
加我微信溝通。
相關文章
- iOS OC-自定義TabBar TabBarViewControlleriOStabBarViewController
- [iOS] [OC] NSNotificationCenter 進階及自定義(附原始碼)iOS原始碼
- Siri自定義Intent以及處理Intent
- 自定義事件相容處理物件事件物件
- OC:自定義日期選擇器
- 【Django】DRF自定義異常處理Django
- 處理可能超時的非同步操作非同步
- [系列] Gin框架 - 自定義錯誤處理框架
- iOS 自定義 UISlider 的 trackRectiOSUIIDE
- 手寫一個自定義PromisePromise
- Promise自定義,看我如何征服你Promise
- Dubbo 自定義異常,你是怎麼處理的?
- 自定義Spring Security的身份驗證失敗處理Spring
- restframework 異常處理及自定義異常RESTFramework
- Spring Cloud Gateway-自定義異常處理SpringCloudGateway
- SpringBoot系列——自定義統一異常處理Spring Boot
- java自定義序列化Java
- Promise.allSettled 的 Polyfill 處理Promise
- springboot下新增全域性異常處理和自定義異常處理Spring Boot
- Spring Boot 中關於自定義異常處理的套路!Spring Boot
- 深入研究自定義Apache Nifi處理器 - itnextApacheNifi
- Spring Cloud Gateway自定義異常處理Exception HandlerSpringCloudGatewayException
- 多型關聯自定義的型別欄位的處理多型型別
- 非同步操作系列之Promise物件非同步Promise物件
- 原始碼分析springboot自定義jackson序列化,預設null值個性化處理返回值原始碼Spring BootNull
- 語音訊號處理獲取 NFFT 的自定義函式音訊FFT函式
- C#自定義異常 統一異常處理C#
- Netty中自定義事件處理程式和監聽器Netty事件
- Ai影像分割模型PaddleSeg——自定義資料集處理AI模型
- Spring Cloud Stream消費失敗後的處理策略(二):自定義錯誤處理邏輯SpringCloud
- Promise.all API 的出錯處理PromiseAPI
- springbootredis自定義序列化方式(fastJson)Spring BootRedisASTJSON
- 時間序列資料的處理
- iOS 新增自定義的字型 Fonts provided by applicationiOSIDEAPP
- 【iOS】關於 UICollectionView 的自定義佈局iOSUIView
- springboot自定義ObjectMapper序列化、配置序列化對LocalDateTime的支援Spring BootObjectAPPLDA
- Dotnetty學習筆記——自定義初始化處理器Netty筆記
- SpringBoot專案實戰(7):自定義異常處理介面Spring Boot