2016-10-05 6 views
6

ich in Swift 3 die folgende Funktion habenWas bedeutet() in Swift?

func fetchOrders(_ completionHandler: (_ orders: [Order]) -> Void) 
    { 
    ordersStore.fetchOrders { (orders:() throws -> [Order]) -> Void in 
     do { 
     let orders = try orders() 
     completionHandler(orders) 
     } catch { 
     completionHandler([]) 
     } 
    } 
    } 
  1. Was in fetchOrders ist _ completionHandler Argument bedeuten?
  2. Was bedeutet (orders:() throws -> [Order])?

PS: Ich bin neu in iOS und Swift

+2

Lesen Sie im Kapitel „Funktionen“ in dem Buch Swift Referenz könnte hilfreich sein ... –

Antwort

7

Es gibt ziemlich viel hier, so dass wir es brechen ein Stück zu einer Zeit:

func fetchOrders(_ completionHandler: (_ orders: [Order]) -> Void) 
  • Dies ist eine Funktion fetchOrders genannt.
  • Es hat einen Parameter (completionHandler) und gibt nichts zurück.
  • Die erste _ zeigt an, dass es keinen "externen Namen" des ersten Parameters gibt. Das heißt, Sie müssen es nicht beschriften (in der Tat können Sie nicht). (Aus subtilen Gründen, die hier nicht wirklich wichtig sind, glaube ich, dass der Autor einen Fehler gemacht hat, _ dort, und das hätte ich nicht getan.)
  • Der completionHandler ist der "interne Name", wie der Parameter im Inneren heißt die Funktion.
  • Der Typ completionHandler ist (_ orders: [Order]) -> Void. Wir werden das jetzt durchbrechen.
    • Dieser Wert ist ein Verschluss, der eine [Order] (array of Order) und gibt Void nimmt. Informell bedeutet dies "gibt nichts zurück", bedeutet aber wörtlich, dass es das leere Tupel () zurückgibt.
    • Die _ orders: Syntax ist in der Praxis ein Kommentar. Im Prinzip ist der _ ein externer Name (aber das ist der einzige zulässige externe Name für eine Schließung), und orders ist ein interner Name, aber in Wirklichkeit haben Closures-Parameter keine Namen in irgendeiner sinnvollen Weise, so dass dies rein informativ ist.
    • Ich glaube, dies ist eine schlechte Verwendung des Kommentarsystems Schließung Parameter.Seit orders erzählt uns nichts mehr als [Order], hätte ich es weggelassen, und machte den Typ nur ([Order]) -> Void.

Jetzt werden wir in der nächsten Zeile drehen:

ordersStore.fetchOrders { (orders:() throws -> [Order]) -> Void in 
  • Dies ruft die fetchOrders Methode auf ordersStore. Wir können anhand dieses Codes erkennen, dass fetchOrders einen Verschlussparameter annimmt. Dies wird in Swift als "Trailing Closure" -Syntax bezeichnet, weshalb ich die _ für unsere Schließung nicht verwendet hätte. Bei einer abschließenden Closure-Syntax wird der externe Name des Parameters nicht benötigt.
  • Der Autor hat hier Typinformationen angegeben, die wahrscheinlich nicht notwendig waren, aber wir können es trotzdem erkunden. Dies hätte wahrscheinlich nur als { orders in geschrieben werden können, aber dann wäre der Leser wahrscheinlich von diesem etwas ungewöhnlichen Code überrascht gewesen.
  • Wir wurden eine Schließung namens orders übergeben, die nichts nimmt und [Order] zurückgibt oder einen Fehler auslöst. Grundsätzlich ist dies eine Möglichkeit zu sagen, dass fetchOrders möglicherweise fehlschlagen.
  • Der Autor arbeitet um eine Peinlichkeit in Swifts throws System, das keine natürliche Möglichkeit hat, eine asynchrone Aktion auszudrücken, die fehlschlagen könnte. Dies ist eine Möglichkeit, es zu beheben; Sie übergeben eine werfen (d. h. eine möglicherweise scheitern) Funktion. Ich bevorzuge diesen Ansatz nicht, ich bevorzuge eine Result enum für diesen Fall, weil ich denke, dass es besser skaliert und mögliche unbeabsichtigte Nebenwirkungen vermeidet, aber das ist ein strittiger Punkt (und die Swift-Community hat nicht wirklich entschieden, wie sie damit umgehen soll häufiges Problem).

Das alles führt uns zu:

do { 
    let orders = try orders() 
    completionHandler(orders) 
    } catch { 
    completionHandler([]) 
    } 
  • Hier wird der orders Schließung ausgewertet wird. (Dies ist sehr wichtig; wenn orders Nebenwirkungen hat, tritt dies auf, wenn sie auftreten, die sich möglicherweise in einer anderen Warteschlange als beabsichtigt befinden. Das ist ein Grund, warum ich dieses Muster nicht favorisiere.) Wenn der Abschluss erfolgreich ist, geben wir sein Ergebnis zurück sonst geben wir [] in der catch unten zurück.
    • In diesem insbesondere Fall der throws Ansatz ist etwas albern, weil es still in [] abgeflacht ist, ohne auch nur eine Log-Nachricht. Wenn wir uns nicht um die Fehler kümmern, dann sollte der Fehler [] mit throws und throws zurückgegeben werden. Es ist jedoch möglich, dass andere Anrufer die Fehler überprüfen.
    • In beiden Fällen nennen wir die completionHandler Schließung mit unserem Ergebnis, verketten diese zurück zu unserem ursprünglichen Anrufer.

    Dieser do/catch-Block mehr haben könnte einfach geschrieben als:

    let completedOrders = try? orders() ?? [] 
    completionHandler(completedOrders) 
    

    Dies macht deutlicher, dass wir Fehler sind zu ignorieren, indem sie es in eine optionale Dreh und vermeidet Code-Duplizierung des Anrufs zu completionHandler.

    (Ich füge nur die zusätzlichen let den Code ein wenig leichter lesbar machen verbindlich;. Es ist nicht erforderlich)

+0

Dies hätte nicht besser erklärt werden können. –

+0

Kann jemand erklären, wie oder warum dieses Muster den Abschluss-Handler in eine andere Warteschlange bringen kann? – Jay

+1

@Jay In einer anderen Warteschlange als was? (In GCD gibt es keine "aktuelle Warteschlange". Dies ist ein häufiges Missverständnis, wie Warteschlangen funktionieren.) Wenn die Methode mit einem Hintergrundthread arbeitet (ein Thread ist keine Warteschlange), führt sie wahrscheinlich den Beendigungshandler auf diesem aus Thread, wenn es abgeschlossen ist. Das Dispatching zu einer Warteschlange erfordert zusätzliche Komplexität; Sie müssen entweder eine Warteschlange übergeben oder eine bestimmte Warteschlange (z. B. die Hauptwarteschlange) versprechen. Ersteres ist in Cocoa etwas verbreitet. Letzteres ist in Frameworks von Drittanbietern häufiger, ist aber oft unerwünscht. –

2

Das completionHandler Argument bedeutet, dass der erwartete Parameter (benannt completionHandler) muss eine Funktion sein, die eine Liste von Order Objekte nimmt und liefert keinen Wert.

2

completionHandler ist der Name der Variablen. In diesem speziellen Beispiel ist diese Variable ein callback. Sie wissen, dass es sich um eine Callback-Funktion handelt, weil (orders: [Order]) -> Void der Datentyp ist; In diesem speziellen Fall ist der Datentyp eine Funktion, die ein Array von Order Objekten in einer Variablen _orders empfängt und keinen Rückgabewert hat (der Void Teil).

TL; DR:

  1. es ist der Variablenname, Typ:
  2. Funktion, die als Rückruf ein Array von Order als Parameter und wirkt empfängt.
Verwandte Themen