Rightpoint / RZBluetooth

Core Bluetooth helper library
Other
136 stars 47 forks source link

Add a way to cancel all pending commands for a peripheral #78

Closed fabiorodella closed 5 years ago

fabiorodella commented 6 years ago

In our app, once the user "pairs" to a peripheral, we use a connectionDelegate to re-issue a characteristic write as soon as it disconnects, which works great. Later, in the UI the user can also manually forget a peripheral, and at this point I was calling RZBPeripheral.cancelConnection.

However, I noticed that if I had that pending write command for that peripheral, the library would pro-actively retry the connection command, which would leave a dangling connection request for a device that the app has no interest in anymore, and that was causing some issues. I searched for a way to cancel all outstanding commands for a peripheral but didn't find anything, so I ended up hacking that feature into RZBPeripheral with an extension:

@implementation RZBPeripheral (Cancellation)

- (RZBCommandDispatch *)hs_dispatch {
    SEL selector = NSSelectorFromString(@"dispatch");
    IMP imp = [self methodForSelector:selector];
    RZBCommandDispatch* (*func)(id, SEL) = (void *)imp;
    return func(self, selector);
}

- (void)hs_cancelAllCommands {
    NSArray *commands = [self.hs_dispatch commandsOfClass:nil
                                 matchingUUIDPath:RZBUUIDP(self.identifier)
                                       isExecuted:YES];

    NSError *error = [NSError errorWithDomain:[NSString stringWithFormat:@"%@-hs", RZBluetoothErrorDomain]
                                         code:1
                                     userInfo:@{NSLocalizedDescriptionKey: @"The operation has been manually cancelled by the user"}];

    for (RZBCommand *command in commands) {
        [self.hs_dispatch completeCommand:command withObject:nil error:error];
    }
}

@end

I feel like this is a useful feature to add to the library, do you agree? If so, what do you think of this solution? If you think this approach is fine I can submit a PR with this change.

KingOfBrian commented 5 years ago

Thanks a lot @fabiorodella -- sorry for no reply. This is definitely a better behavior. By default, we'll now cancel all pending commands when cancelling the peripheral connection. This, and the change to the connectionDelegate to inform the user that the connection was cancelled rather than disconnected should make things a bit easier. This is in #95, and I'm hoping to land a pre-2.0 release soon.

Thanks!