Search code examples
objective-creact-nativeasynchronousgrand-central-dispatchhomekit

How do I await multiple functions with completionHandlers?


I'm currently working on a bridge for HomeKit for React-Native and I have to read HomeKit values to return for my Javascript code.

To read the latest value of a characteristic we must use readValueWithCompletionHandler where the value isn't ready until it's complete. So I must read 6 of these characteristics and assign each one to my NSMutableDictionary object to return for React-Native to handle.

Rather than nesting each read inside the previous completionHandler with return accObject inside the final one, what's the cleanest approach to waiting for all completionHandlers to have been complete before return.

I've been searching for a while, looking at semaphores, DispatchGroup & a couple other solutions without a great idea about how to solve this problem.

For (rough) example:

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;

Solution

  • you can use dispatch_semaphore_wait() with wait dispatch_semaphore_t you can use this process this work for me.

         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;