2016-04-12 20 views
1

Ich versuche, eine einfache API für ein komplexes Szenario zu erreichen. Ich habe einen Typ, der Daten asynchron (Bluetooth-Gerät tatsächlich) abruft. So ist die API Ich versuche, mit am Ende ist dies:Dynamische generische Parameter, die den generischen Typ in Closure zurückgeben?

peripheral.requestData(.Temperature) { value: Double in 
    print(value) 
} 

Ich habe ein paar gute Ideen aus this amazing article, so ist dies, was ich die oben zu erreichen versucht:

class MyPeripheral { 

    class Keys { 
     static let Temperature = PeripheralKey<Double>("Temperature") 
     static let UserData = PeripheralKey<[String: String]>("UserData") 
    } 

    func requestData(service: Keys, handler: (value: ???Get ValueType from PeripheralKey???) -> Void) { 
     if let service = service as? PeripheralKey<Int> { 
      service.key //Do something 
     } else if let service = service as? PeripheralKey<[String: String]> 
      //Do something else 
     } 
    } 
} 

class PeripheralKey<ValueType>: MyPeripheral.Keys { 
    let key: String 

    init(_ key: String) { 
     self.key = key 
    } 
} 

Ich bin Probleme mit dem zurückgegebenen Schließungstyp haben. Ich möchte stark typisiert werden, basierend auf dem generischen Peripherietypschlüssel, der übergeben wurde, kann aber nicht verstehen, wie dies zu tun ist, oder vielleicht einen anderen Ansatz benötigen? Jede Hilfe oder Richtung würde sehr geschätzt werden !!

Antwort

2

Sie können einen generischen Parameter in oder verwenden, um den Werttyp Ihrer service zu erhalten. Um es zu benutzen statisch schlage ich PeripheralKey<T> statt seiner Unterklasse zu verwenden:

class MyPeripheral { 

    class Keys { 
     static let Temperature = PeripheralKey<Double>("Temperature") 
     static let UserData = PeripheralKey<[String: String]>("UserData") 
    } 

    // use a generic parameter T 
    func requestData<T>(service: PeripheralKey<T>, handler: (value: T) -> Void) { 
     // if you do similar things like in your posted link 
     // you can use ("data" has to be defined by you): 
     // data[service.key] as! T 
    } 
} 

// make class final as long as you don't subclass it 
final class PeripheralKey<ValueType>: MyPeripheral.Keys { 
    let key: String 

    init(_ key: String) { 
     self.key = key 
    } 
} 

let peripheral = MyPeripheral() 
// here you can omit the explicit Double declaration 
peripheral.requestData(.Temperature) { value in 
    print(value) 
} 

Nach Swift 3.0 wurde veröffentlicht Sie wahrscheinlich statische Eigenschaften in generische Typen setzen können, die Sie nur eine Struktur wie diese verwenden können:

struct PeripheralKey<ValueType> { 

    static let Temperature = PeripheralKey<Double>("Temperature") 
    static let UserData = PeripheralKey<[String: String]>("UserData") 

    let key: String 

    init(_ key: String) { 
     self.key = key 
    } 
} 
Verwandte Themen