Objective-C中Firebase API的Promise化改造及同步调用方案问询
改造Firebase Objective-C嵌套Block为Promise风格并适配NSOperationQueue
嘿,我来帮你搞定这个问题!咱们分两步走:先把嵌套的Firebase回调转换成类似Node.js Promise的扁平化写法,再适配NSOperationQueue的依赖调度逻辑。
第一步:封装Firebase查询为Promise风格
iOS 13+系统提供了原生的NSPromise,我们可以给FIRDatabaseQuery写个分类,把observeSingleEventOfType:withBlock:封装成返回Promise的方法,彻底摆脱嵌套回调的困扰。
1. 写FIRDatabaseQuery的Promise分类
创建FIRDatabaseQuery+Promise.h头文件:
#import <FirebaseDatabase/FirebaseDatabase.h> #import <Foundation/Foundation.h> NS_ASSUME_NONNULL_BEGIN @interface FIRDatabaseQuery (Promise) - (NSPromise<FIRDataSnapshot *> *)onceValue; @end NS_ASSUME_NONNULL_END
然后是实现文件FIRDatabaseQuery+Promise.m:
#import "FIRDatabaseQuery+Promise.h" @implementation FIRDatabaseQuery (Promise) - (NSPromise<FIRDataSnapshot *> *)onceValue { return [NSPromise promiseWithResolver:^(void (^resolve)(FIRDataSnapshot *), void (^reject)(NSError *)) { [self observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) { resolve(snapshot); } withCancelBlock:^(NSError * _Nonnull error) { reject(error); }]; }]; } @end
2. 用Promise替代嵌套Block
原来的嵌套代码现在可以改写成扁平化的Promise调用,和你给出的Node.js示例风格完全对齐:
// 替换成你实际的查询实例 FIRDatabaseQuery *query1 = [[[FIRDatabase database] reference] queryOrderedByKey]; FIRDatabaseQuery *query2 = [[[FIRDatabase database] reference] queryOrderedByChild:@"timestamp"]; // 创建两个Promise NSPromise<FIRDataSnapshot *> *promise1 = [query1 onceValue]; NSPromise<FIRDataSnapshot *> *promise2 = [query2 onceValue]; // 等待所有Promise完成,统一处理结果 [[NSPromise all:@[promise1, promise2]] then:^(NSArray<FIRDataSnapshot *> *snapshots) { FIRDataSnapshot *snapshot1 = snapshots[0]; FIRDataSnapshot *snapshot2 = snapshots[1]; // 在这里处理两个查询的结果 } catch:^(NSError *error) { // 处理任意一个Promise失败的情况 }];
第二步:适配NSOperationQueue实现同步调度
要让这些Firebase调用适配NSOperationQueue的依赖管理,我们可以把Promise的执行包装成NSBlockOperation,通过添加依赖来严格控制执行顺序,和你给出的NSOperation示例逻辑匹配。
方案:用NSBlockOperation包装Promise同步等待
// 创建自定义后台队列(避免阻塞主线程) NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init]; operationQueue.maxConcurrentOperationCount = 1; // 可选,按需设置并发数 // 第一个操作:执行第一个查询 NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ NSError *error; FIRDataSnapshot *snapshot1 = [promise1 awaitWithError:&error]; if (error) { // 处理op1的错误 return; } // 在这里处理snapshot1的业务逻辑 }]; // 第二个操作:执行第二个查询,依赖op1完成 NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{ NSError *error; FIRDataSnapshot *snapshot2 = [promise2 awaitWithError:&error]; if (error) { // 处理op2的错误 return; } // 在这里处理snapshot2的业务逻辑 }]; [op2 addDependency:op1]; // 汇总操作:依赖op2完成后执行 NSBlockOperation *opAll = [NSBlockOperation blockOperationWithBlock:^{ // 执行汇总两个查询结果的逻辑 }]; [opAll addDependency:op2]; // 将所有操作加入队列 [operationQueue addOperations:@[op1, op2, opAll] waitUntilFinished:NO];
关键点说明
awaitWithError:是NSPromise的同步等待方法,在NSOperation的block里调用是安全的——因为这些block运行在自定义队列的后台线程,不会阻塞主线程。- 通过
addDependency:可以严格控制操作的执行顺序,完全适配NSOperationQueue的调度逻辑。 - 如果你的项目需要兼容iOS 13以下版本,可以用第三方Promise库(比如PromiseKit)替代原生
NSPromise,封装思路是完全一致的。
内容的提问来源于stack exchange,提问作者Isaak Osipovich Dunayevsky
相关产品推荐
相关产品推荐

