troystribling / BlueCap

iOS Bluetooth LE framework
MIT License
715 stars 115 forks source link

Advice migrating code, using new examples #49

Closed Laptopmini closed 7 years ago

Laptopmini commented 7 years ago

Previous Code: Swift 2, BlueCap 0.1.0 New Code: Swift 3, BlueCap 0.2 Example Referenced: https://github.com/troystribling/BlueCap/blob/master/Examples/CentralManager/CentralManager/ViewController.swift#L132

I am currently in the middle of a migration to Swift 3, and at the same time I am updating some of my old code, and I was wondering if I could get some advice.

In my previous code, when calling .connect() on the Peripheral, I would use the .onSuccess syntax to handle the code to be executed after its completion.

However, looking at your (new) examples, it seems you've adopted a preferred syntax of using .flatmap() to handle a chain of closures.

I really like this syntax, the only problem I've encountered with it is when calling .terminate() or .reconnect() on the Peripheral. Here is the code I will be referencing:

.flatMap { [unowned self] (peripheral, connectionEvent) -> Future<Peripheral> in
            switch connectionEvent {
            case .connect:
                return peripheral.discoverServices([self.deviceUUID_CB])
            case .timeout:
                print(err_msg + "Connection Timeout, reconnecting.")
                self.statusMessage(nil)
                peripheral.reconnect()
            case .disconnect:
                print(err_msg + "Got disconnected, reconnecting.")
                self.statusMessage(nil)
                peripheral.reconnect()
            case .forceDisconnect:
                print(err_msg + "Forced Disconnect, terminating.")
                self.statusMessage(nil)
            case .giveUp:
                print(err_msg + "Giving up, terminating.")
                self.statusMessage(nil)
                peripheral.terminate()
            }
        }

The following is obviously creating an error as not all the switch's cases either return or throw.

Now I should obviously throw when it gets to .giveUp. But is there a way to have this closure loop when using .reconnect() and not interrupt the closure chain by throwing or having it proceed with a return statement?

troystribling commented 7 years ago

In this example I https://github.com/troystribling/BlueCap/blob/master/Examples/CentralManager/CentralManager/ViewController.swift#L114-L217 throw for everything that does not return and do reconnect() where needed in onFailure.

With the current implementation I do not have a way to loop in a combinator. You would need something like a new retry method.

I need to think about it. You could also take a shot at it if you are interested.

Laptopmini commented 7 years ago

Thanks that solution works great!

troystribling commented 7 years ago

I was thinking of changing the connect command to do the reconnects and throw errors for timeout or disconnect after give-up thresholds are crossed. The current implementation came from assumptions that are no longer valid. It would not be a big change and I think more sensible.

Implementing a generic looping function in SimpleFutures would be much more work since I would have to track parent-child relations between Futures.

Laptopmini commented 7 years ago

Yes, that would be great seeing we have to specify the number of timeoutRetries and disconnectRetries already, so it could just deduct when and how many times to call .reconnect().

When .forcedDisconnect or .giveUp is reach it could just throw an error, and its up to the user to handle it with all/any other errors or define a scenario to handle them specifically.

troystribling commented 7 years ago

This change was just released in version 0.3.0.