2016-09-14 4 views
2

Ich versuche, eine einzelne Lösung für jeden Callback in der Anwendung zu implementieren. Daher möchte ich, dass jeder Callback die gleiche Klasse oder zumindest eine Familie von Klassen verwendet.Swift Generics mit Standardwert

  • Jeder Rückruf kann erfolgreich sein oder nicht.
  • Wenn es erfolgreich ist, kann es ein Ergebnis der Operation enthalten.
  • Wenn nicht, kann es Informationen darüber enthalten, was fehlgeschlagen ist.

Die gemeinsame Nutzung Rückrufe sieht wie folgt aus:

func foo(callback: ((success: Bool, result: Result?, error: Error?) -> Void)?) { } 

Oder:

func foo(success: ((result: Result) -> Void)?, failure: ((error: Error) -> Void)?) { } 

ich nicht einer von ihnen mögen. Ich möchte für jeden Rückruf eine elegante Lösung haben. Ich habe etwas ähnliches in Alamofire Bibliothek gefunden.

enum CallbackResult<T, V> { 
     case success(value: T?) 
     case failure(error: V?) 

     var isSuccess: Bool { 

      switch self { 
      case .success: return true 
      case .failure: return false 
      } 
     } 
    } 

    func foo(callback: ((result: CallbackResult<Any, AnyObject>) -> Void)?) { 
     callback?(result: .success(value: nil)) 
    } 

Diese Lösung ist nett. Aber wie in meinem Beispiel müssen wir nicht immer irgendeinen Wert oder Fehler als Parameter übergeben. Wie auch immer, der Compiler muss immer wissen, von welchem ​​Typ generische Parameter sein sollten. Also selbst wenn ich nicht messe, welcher Typ Wert ist, sollte ich immer mindestens Any oder AnyObject angeben. Es ist zu kompliziert.

Ich habe versucht, es mit Klasse-Lösung zu ändern:

class CallbackResult<T, V> { 

     let isSuccess: Bool 

     let value: T? 

     let error: V? 

     fileprivate init(success: Bool, value: T? = nil, error: V? = nil) { 

      self.isSuccess = success 
      self.value  = value 
      self.error  = error 
     } 

     static func success(value: T? = nil) -> CallbackResult { 
      return CallbackResult(success: true, value: value) 
     } 

     static func failure(error: V? = nil) -> CallbackResult { 
      return CallbackResult(success: false, error: error) 
     } 
    } 

    func foo(callback: ((result: CallbackResult<Any, AnyObject>) -> Void)?) { 
     callback?(result: CallbackResult.success(value: nil)) 
    } 

es die gleiche Funktionalität. Aber auch so hat es mein Problem nicht gelöst. Sie können nicht einfach so schreiben:

CallbackResult<_, Error> 

Es wird nicht funktionieren.

Vielleicht jemand Lösung meines Problems kennen? Irgendeine Möglichkeit, den Standardwert zu setzen^um nicht jedes Mal Any zu schreiben? Oder für den Moment gibt es nur hässliche Art, diesen Ansatz zu verwenden?

Antwort

1

Swift 3 added generic type aliases. Dadurch können Sie vermeiden, jedes Mal alle Typen einzugeben.

Beispiel:

typealias AnyResult<E> = CallbackResult<Any, E> 
typealias AnyCallback<E> = (AnyResult<E>) ->() 

func foo(callback: AnyCallback<String>?) { 
    callback?(.failure(error: "Ouch!")) 
} 

foo() { result in 
    if result.isSuccess { 
     // ... 
    } 
} 
+0

Es teilweise funktioniert. Wenn ich dies benutze: typealias AnyCallback = (AnyResult ) ->(), bekomme ich einen Fehler 'Segmentierung' Fehler: 11 –