如何使用 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] 之前完成的最干净的方法是什么=].
我已经搜索了一段时间,查看了 semaphores
、DispatchGroup
和其他几个解决方案,但对如何解决这个问题没有很好的想法。
对于(粗略的)示例:
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;
我目前正在为 React-Native 开发 HomeKit 的桥梁,我必须将 HomeKit 值读取到 return 以用于我的 Javascript 代码。
要读取特征的最新值,我们必须使用 readValueWithCompletionHandler,其中值在完成之前尚未就绪。所以我必须阅读这些特征中的 6 个并将每个特征分配给我的 NSMutableDictionary
对象到 return 以供 React-Native 处理。
与其将每个读取嵌套在前一个 completionHandler
中,然后将 return accObject
嵌套在最后一个中,等待所有 completionHandlers
在 [=15] 之前完成的最干净的方法是什么=].
我已经搜索了一段时间,查看了 semaphores
、DispatchGroup
和其他几个解决方案,但对如何解决这个问题没有很好的想法。
对于(粗略的)示例:
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;