[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 Swift和OC專案中自定義LogiOSSwift
- [iOS] [OC] NSNotificationCenter 進階及自定義(附原始碼)iOS原始碼
- Siri自定義Intent以及處理Intent
- 自定義事件相容處理物件事件物件
- OC:自定義日期選擇器
- 【Django】DRF自定義異常處理Django
- 自定義處理頁面請求
- 處理可能超時的非同步操作非同步
- [系列] Gin框架 - 自定義錯誤處理框架
- 自定義Toast及視窗透明處理AST
- iOS自定義的PickViewiOSView
- Promise自定義,看我如何征服你Promise
- 手寫一個自定義PromisePromise
- java自定義序列化Java
- Android自定義TitleBar 自定義標題欄 並進行事件處理Android事件
- Promise.allSettled 的 Polyfill 處理Promise
- restframework 異常處理及自定義異常RESTFramework
- Dubbo 自定義異常,你是怎麼處理的?
- Java中的註解-自定義註解處理器Java
- iOS自定義tabBariOStabBar
- 自定義Spring Security的身份驗證失敗處理Spring
- Spring Cloud Gateway-自定義異常處理SpringCloudGateway
- 用列舉來處理java自定義異常Java
- MySQL自定義變數處理行號問題MySql變數
- 多型關聯自定義的型別欄位的處理多型型別
- 非同步操作系列之Promise物件非同步Promise物件
- 談談JavaScript非同步操作PromiseJavaScript非同步Promise
- iOS 自定義 UISlider 的 trackRectiOSUIIDE
- iOS-自定義PickerViewiOSView
- .Net Core 自定義序列化格式
- springboot下新增全域性異常處理和自定義異常處理Spring Boot
- 語音訊號處理獲取 NFFT 的自定義函式音訊FFT函式
- Spring Boot 中關於自定義異常處理的套路!Spring Boot
- 對 echo 框架進行統一的自定義錯誤處理框架
- Promise.all API 的出錯處理PromiseAPI
- SpringBoot系列——自定義統一異常處理Spring Boot
- Spring Cloud Gateway自定義異常處理Exception HandlerSpringCloudGatewayException