You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React-Native(iOS)中如何利用代理方法返回结果触发回调?

解决方案:绑定异步代理结果与RN回调/Promise

你的核心问题在于:调用SDK方法后立刻执行回调,但代理方法是异步返回结果的,导致回调拿到的是旧值或未赋值的初始值;另外RCTEventEmitter的不稳定源于未正确匹配请求与事件触发。以下是两种可靠的实现方式:

一、回调绑定方案(解决结果滞后问题)

实现思路

  • 不再调用SDK后立即执行回调,而是将回调暂存,等待代理方法触发时再执行对应的回调
  • 为播放/停止操作分别维护独立的回调变量,避免操作混淆
  • 代理方法执行完回调后立即置空,防止重复触发

代码实现

1. 模块属性声明与初始化

@interface YourRCTModule () <CameraSirenDelegate>
@property (nonatomic, strong) CameraControl *cameraControl;
// 暂存播放/停止操作的回调
@property (nonatomic, copy) RCTResponseSenderBlock pendingPlayCallback;
@property (nonatomic, copy) RCTResponseSenderBlock pendingStopCallback;
@end

@implementation YourRCTModule

- (instancetype)init {
    self = [super init];
    if (self) {
        self.cameraControl = [[CameraControl alloc] init];
        // 仅初始化时设置一次代理,无需每次调用方法重复设置
        self.cameraControl.cameraSiren.delegate = self;
    }
    return self;
}

2. 修改RN导出方法

RCT_EXPORT_METHOD(openSirenAlarm: (RCTResponseSenderBlock) callback)
{
    // 检查是否有未完成的播放请求,避免重复操作
    if (self.pendingPlayCallback) {
        callback(@[@(1), @"警报正在启动中"]);
        return;
    }
    // 暂存回调,等待代理结果返回
    self.pendingPlayCallback = callback;
    [self.cameraControl.cameraSiren playCameraSiren];
}

RCT_EXPORT_METHOD(closeSirenAlarm: (RCTResponseSenderBlock) callback)
{
    if (self.pendingStopCallback) {
        callback(@[@(1), @"警报正在停止中"]);
        return;
    }
    self.pendingStopCallback = callback;
    [self.cameraControl.cameraSiren stopCameraSiren];
}

3. 代理方法中执行回调

#pragma mark CameraSirenDelegate
- (void)cameraSiren:(CameraSiren *)cameraSiren stopResult:(ENUM_APP_RESULT)result
{
    NSLog(@"stop result: %u", result);
    NSInteger errorCode = (result == RESULT_SUCCESS) ? 0 : 1;
    NSInteger responseVal = (result == RESULT_SUCCESS) ? 1 : 0;
    
    // 执行暂存的停止回调并置空
    if (self.pendingStopCallback) {
        self.pendingStopCallback(@[@(errorCode), @(responseVal)]);
        self.pendingStopCallback = nil;
    }
}

- (void)cameraSiren:(CameraSiren *)cameraSiren playResult:(ENUM_APP_RESULT)result
{
    NSLog(@"start result: %u", result);
    NSInteger errorCode = (result == RESULT_SUCCESS) ? 0 : 1;
    NSInteger responseVal = (result == RESULT_SUCCESS) ? 1 : 0;
    
    // 执行暂存的播放回调并置空
    if (self.pendingPlayCallback) {
        self.pendingPlayCallback(@[@(errorCode), @(responseVal)]);
        self.pendingPlayCallback = nil;
    }
}

二、Promise方案(更优雅的异步处理)

如果JS端更倾向于async/await语法,可以将导出方法改为Promise类型,实现逻辑与回调绑定一致,但代码更简洁:

代码实现

// 替换原有的RCT_EXPORT_METHOD为RCT_REMAP_METHOD
RCT_REMAP_METHOD(openSirenAlarm,
                 resolver:(RCTPromiseResolveBlock)resolve
                 rejecter:(RCTPromiseRejectBlock)reject)
{
    if (self.pendingPlayCallback) {
        reject(@"ALREADY_STARTING", @"警报正在启动中", nil);
        return;
    }
    // 将Promise的resolve/reject封装为回调暂存
    self.pendingPlayCallback = ^(NSArray *results) {
        NSNumber *errorNum = results[0];
        NSNumber *responseNum = results[1];
        if ([errorNum integerValue] == 0) {
            resolve(responseNum);
        } else {
            reject(@"START_FAILED", @"启动警报失败", nil);
        }
    };
    [self.cameraControl.cameraSiren playCameraSiren];
}

RCT_REMAP_METHOD(closeSirenAlarm,
                 resolver:(RCTPromiseResolveBlock)resolve
                 rejecter:(RCTPromiseRejectBlock)reject)
{
    if (self.pendingStopCallback) {
        reject(@"ALREADY_STOPPING", @"警报正在停止中", nil);
        return;
    }
    self.pendingStopCallback = ^(NSArray *results) {
        NSNumber *errorNum = results[0];
        NSNumber *responseNum = results[1];
        if ([errorNum integerValue] == 0) {
            resolve(responseNum);
        } else {
            reject(@"STOP_FAILED", @"停止警报失败", nil);
        }
    };
    [self.cameraControl.cameraSiren stopCameraSiren];
}

JS端调用示例

try {
  const response = await openSirenAlarm();
  console.log('警报启动成功:', response);
} catch (error) {
  console.error('警报启动失败:', error);
}

关于RCTEventEmitter的问题

如果仍想使用事件发射器,需确保:

  • 仅在代理方法触发时单次emit事件,并在事件数据中携带操作类型(播放/停止)
  • 正确实现startObserving和stopObserving方法,管理订阅生命周期
  • 避免重复设置代理或多次注册事件监听

但对于这种单次请求-响应的场景,回调/Promise方案更直接,能精准匹配每个操作的结果,避免事件触发混乱的问题。

内容的提问来源于stack exchange,提问作者Rej Fredericks

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 23:19:01