如何使用 completionHandlers 等待多个函数?

How do I await multiple functions with completionHandlers?

我目前正在为 React-Native 开发 HomeKit 的桥梁,我必须将 HomeKit 值读取到 return 以用于我的 Javascript 代码。

要读取特征的最新值,我们必须使用 readValueWithCompletionHandler,其中值在完成之前尚未就绪。所以我必须阅读这些特征中的 6 个并将每个特征分配给我的 NSMutableDictionary 对象到 return 以供 React-Native 处理。

与其将每个读取嵌套在前一个 completionHandler 中,然后将 return accObject 嵌套在最后一个中,等待所有 completionHandlers 在 [=15] 之前完成的最干净的方法是什么=].

我已经搜索了一段时间,查看了 semaphoresDispatchGroup 和其他几个解决方案,但对如何解决这个问题没有很好的想法。

对于(粗略的)示例:

NSMutableDictionary *accObject = [[NSMutableDictionary alloc] initWithCapacity: 6];

[charac1 readValueWithCompletionHandler:^(NSError *error) {
        if (error) {
          RCTLog(@"ERROR READING HOMEKIT VALUE: %@", error);
        }
        RCTLog(@"READ SETPOINT VALUE: %@", charac1.value);
        accObject[@"charac1"] = charac1.value;
      }];
...

[charac6 readValueWithCompletionHandler:^(NSError *error) {
        if (error) {
          RCTLog(@"ERROR READING HOMEKIT VALUE: %@", error);
        }
        RCTLog(@"READ SETPOINT VALUE: %@", charac6.value);
        accObject[@"charac6"] = charac6.value;
      }];

 return accObject;

我想我已经找到了基于 this article 的解决方案。

NSMutableDictionary *accObject = [[NSMutableDictionary alloc] initWithCapacity: 6];
dispatch_group_t group = dispatch_group_create();

dispatch_group_enter(group);
[charac1 readValueWithCompletionHandler:^(NSError *error) {
        if (error) {
          RCTLog(@"ERROR READING HOMEKIT VALUE: %@", error);
        }
        RCTLog(@"READ SETPOINT VALUE: %@", charac1.value);
        accObject[@"charac1"] = charac1.value;
        dispatch_group_leave(group);
      }];
...

dispatch_group_notify(serviceGroup,dispatch_get_main_queue(),^{
        // Now call the final completion block
        return accObject;
    });

你可以在这里使用调度组,使用它你不能 return 一个值但可以调用一个完成块。这个完成块可以作为你的函数的参数。

 NSMutableDictionary *accObject = [[NSMutableDictionary alloc] initWithCapacity: 6];
    dispatch_group_t group = dispatch_group_create();

[charac1 readValueWithCompletionHandler:^(NSError *error) {
        dispatch_group_enter(group);
        if (error) {
          RCTLog(@"ERROR READING HOMEKIT VALUE: %@", error);
        }
        RCTLog(@"READ SETPOINT VALUE: %@", charac1.value);
        accObject[@"charac1"] = charac1.value;
        dispatch_group_leave(group);
      }];
...

dispatch_group_notify(serviceGroup,dispatch_get_main_queue(),^{
        // Now here instead of returning a value, you can call a completion handler.
    });

在这种情况下,我建议使用dispatch_group_t等待读取值并使用完成块来处理返回值。

- (void)readValuesWithCompletionHandler:(void(^)(NSDictionary* values))completion {
  NSMutableDictionary *accObject = [[NSMutableDictionary alloc] initWithCapacity: 6];

  // Initialize |charac1|, |charac2|, ...

  dispatch_group_t group = dispatch_group_create();

  dispatch_group_enter(group);
  [charac1 readValueWithCompletionHandler:^(NSError *error) {
    if (error) {
      RCTLog(@"ERROR READING HOMEKIT VALUE: %@", error);
    }
    RCTLog(@"READ SETPOINT VALUE: %@", charac1.value);
    accObject[@"charac1"] = charac1.value;
    dispatch_group_leave(group);
  }];

  // ... Do same thing with another values

  dispatch_group_enter(group);
  [charac6 readValueWithCompletionHandler:^(NSError *error) {
    if (error) {
      RCTLog(@"ERROR READING HOMEKIT VALUE: %@", error);
    }
    RCTLog(@"READ SETPOINT VALUE: %@", charac6.value);
    accObject[@"charac6"] = charac6.value;
    dispatch_group_leave(group);
  }];

  dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    if (completion) {
      completion(accObject);
    }
  });
}

用法:

[self readValuesWithCompletionHandler:^(NSDictionary *values) {
  // Do whatever you want with |values| after reading
}];

您可以使用 dispatch_semaphore_wait() 等待 dispatch_semaphore_t 你可以使用这个过程为我工作。

     dispatch_semaphore_t sem = dispatch_semaphore_create(0);


    dispatch_async(dispatch_get_main_queue(), ^{
            NSMutableDictionary *accObject = [[NSMutableDictionary alloc] initWithCapacity: 6];

[charac1 readValueWithCompletionHandler:^(NSError *error) {
        if (error) {
          RCTLog(@"ERROR READING HOMEKIT VALUE: %@", error);
        }
        RCTLog(@"READ SETPOINT VALUE: %@", charac1.value);
        accObject[@"charac1"] = charac1.value;
      }];
...

[charac6 readValueWithCompletionHandler:^(NSError *error) {
        if (error) {
          RCTLog(@"ERROR READING HOMEKIT VALUE: %@", error);
        }
        RCTLog(@"READ SETPOINT VALUE: %@", charac6.value);
        accObject[@"charac6"] = charac6.value;
      }];


            dispatch_semaphore_signal(sem);
        });

         dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
 return accObject;