Skip to main content
1 of 2
Skwiggs
  • 166
  • 5

You could write the following protocols:

protocol Request {
    associatedtype Provider
    var provider: Provider { get }

    func execute() 
}

protocol BLERequest: Request {
    typealias Provider = BLEProvider

    var code: UInt { get }
    var characteristic: CBCharacteristic { get }
    var service: CBService { get }
}

protocol HTTPRequest: Request {
    typealias Provider = NetworkProvider

    var data: Data { get }
    var accessToken: String { get }
    var method: HTTPMethod { get }
    var params: [String:Any]? { get }
}

Then comes the magic; you can write generic extensions on your Request protocol, for each specific Request type.

extension Request where Self: BLERequest {
    func execute() {
        // provider is available since it is a get-able requirement, 
        // and we know it is a BLEProvider instance
        // same goes for all the other get-able vars
        provider.writeValue(data: code, characteristic: characteristic, service: service)
    }
}

extension Request where Self: HTTPRequest {
    func execute() {
        // Again, same thing, we have all vars we need
        provider.performRequest(data: data, token: accessToken, method: method, params: params)
    }
}

Then, when you are implementing a new Request, all you need to do is implement the requirements for your chosen protocol, and everything else will be handled for you :)

Example:

enum MyBLERequest: BLERequest {
    case getStatus
    case download

    // MARK: BLE Request conformance
    var provider: Provider {
        return BLEProvider(... whatever init is needed)
    }

    var code: UInt {
        switch self {
        case .getStatus: return 0x01
        case .download: return 0x02
        // Any further new case will require you to implement the code here, so you have compile-time safety :)
        }
    }

    var characteristic: CBCharacteristic {
        return CBCharacteristic(.. init)
    }

    var service: CBService {
        return CBService(... more init)
    }
}

Then you can simply do MyBLERequest.getStatus.execute(), and it's all done through the protocol extension code.

And since Swift Enums allow associated values, you can always pass in additional parameters, whenever needed (you could have another case case getAuthToken(byUserID: String), which are then available to you in your implementation)

Skwiggs
  • 166
  • 5