Ich habe in meinem Swift-Projekt eine Dienstprogrammklasse erstellt, die alle REST-Anforderungen und -Antworten verarbeitet. Ich habe eine einfache REST-API erstellt, damit ich meinen Code testen kann. Ich habe eine Klassenmethode erstellt, die ein NSArray zurückgeben muss. Da der API-Aufruf jedoch asynchron ist, muss ich von der Methode innerhalb des asynchronen Aufrufs zurückkehren. Das Problem ist, dass die asynchrone Rückgabe ungültig ist. Wenn ich dies in Node tun würde, würde ich JS-Versprechen verwenden, aber ich kann keine Lösung finden, die in Swift funktioniert.
import Foundation
class Bookshop {
class func getGenres() -> NSArray {
println("Hello inside getGenres")
let urlPath = "http://creative.coventry.ac.uk/~bookshop/v1.1/index.php/genre/list"
println(urlPath)
let url: NSURL = NSURL(string: urlPath)
let session = NSURLSession.sharedSession()
var resultsArray:NSArray!
let task = session.dataTaskWithURL(url, completionHandler: {data, response, error -> Void in
println("Task completed")
if(error) {
println(error.localizedDescription)
}
var err: NSError?
var options:NSJSONReadingOptions = NSJSONReadingOptions.MutableContainers
var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: options, error: &err) as NSDictionary
if(err != nil) {
println("JSON Error \(err!.localizedDescription)")
}
//NSLog("jsonResults %@", jsonResult)
let results: NSArray = jsonResult["genres"] as NSArray
NSLog("jsonResults %@", results)
resultsArray = results
return resultsArray // error [anyObject] is not a subType of 'Void'
})
task.resume()
//return "Hello World!"
// I want to return the NSArray...
}
}
ios
rest
asynchronous
swift
Mark Tyers
quelle
quelle
Antworten:
Sie können einen Rückruf weiterleiten und einen Rückruf innerhalb eines asynchronen Anrufs anrufen
etwas wie:
und rufen Sie dann diese Methode auf:
quelle
override func viewDidLoad() { super.viewDidLoad() var genres = Bookshop.getGenres() // Missing argument for parameter #1 in call //var genres:NSArray //Bookshop.getGenres(genres) NSLog("View Controller: %@", genres) }
Swiftz bietet bereits Future an, den Grundbaustein eines Versprechens. Eine Zukunft ist ein Versprechen, das nicht scheitern kann (alle Begriffe hier basieren auf der Scala-Interpretation, bei der ein Versprechen eine Monade ist ).
https://github.com/maxpow4h/swiftz/blob/master/swiftz/Future.swift
Hoffentlich wird es irgendwann zu einem vollständigen Versprechen im Scala-Stil (ich kann es irgendwann selbst schreiben; ich bin sicher, andere PRs wären willkommen; es ist nicht so schwierig, wenn Future bereits vorhanden ist).
In Ihrem speziellen Fall würde ich wahrscheinlich eine erstellen
Result<[Book]>
(basierend auf Alexandros Salazars Version vonResult
). Dann wäre Ihre Methodensignatur:Anmerkungen
get
in Swift voranzustellen. Es wird bestimmte Arten der Interoperabilität mit ObjC unterbrechen.Book
Objekt zu analysieren, bevor Sie Ihre Ergebnisse als zurückgebenFuture
. Es gibt verschiedene Möglichkeiten, wie dieses System ausfallen kann, und es ist viel bequemer, wenn Sie nach all diesen Dingen suchen, bevor Sie sie in ein System einpackenFuture
. Anreise nach[Book]
ist viel besser für den Rest Ihres Swift Code als Gabe um einNSArray
.quelle
Future
. Aber schauen Sie sich github.com/mxcl/PromiseKit an, es funktioniert großartig mit Swiftz!get
Präfix gibt die Referenzrückgabe in ObjC an (z. B. in-[UIColor getRed:green:blue:alpha:]
). Als ich dies schrieb, war ich besorgt, dass die Importeure diese Tatsache nutzen würden (um beispielsweise ein Tupel automatisch zurückzugeben). Es hat sich herausgestellt, dass sie nicht haben. Als ich dies schrieb, hatte ich wahrscheinlich auch vergessen, dass KVC "get" -Präfixe für Accessoren unterstützt (das habe ich mehrmals gelernt und vergessen). So vereinbart; Ich bin nicht auf Fälle gestoßen, in denen die Führungget
Dinge kaputt macht. Es ist nur irreführend für diejenigen, die die Bedeutung von ObjC "bekommen" kennen.Das Grundmuster besteht darin, den Abschluss der Vervollständigungshandler zu verwenden.
Im kommenden Swift 5 würden Sie beispielsweise Folgendes verwenden
Result
:Und du würdest es so nennen:
Beachten Sie, dass ich oben den Completion-Handler zurück in die Hauptwarteschlange sende, um Modell- und UI-Updates zu vereinfachen. Einige Entwickler nehmen eine Ausnahme von dieser Vorgehensweise und verwenden entweder die verwendete Warteschlange
URLSession
oder ihre eigene Warteschlange (der Aufrufer muss die Ergebnisse manuell selbst synchronisieren).Aber das ist hier nicht wesentlich. Das Hauptproblem ist die Verwendung des Completion-Handlers, um den Codeblock anzugeben, der ausgeführt werden soll, wenn die asynchrone Anforderung ausgeführt wird.
Das ältere Swift 4-Muster lautet:
Und du würdest es so nennen:
Beachten Sie, dass ich oben die Verwendung von eingestellt habe
NSArray
(wir verwenden diese überbrückten Objective-C-Typen nicht mehr). Ich gehe davon aus, dass wir einenGenre
Typ hatten und ihn vermutlichJSONDecoder
eherJSONSerialization
zum Dekodieren als zum Dekodieren verwendet haben. Diese Frage enthielt jedoch nicht genügend Informationen über den zugrunde liegenden JSON, um hier auf die Details einzugehen. Daher habe ich darauf verzichtet, die Verwendung von Verschlüssen als Abschlusshandler zu verwenden, um eine Trübung des Kernproblems zu vermeiden.quelle
Result
in Swift 4 und niedriger verwenden, müssen die Aufzählung jedoch selbst deklarieren. Ich benutze diese Art von Muster seit Jahren.Swift 4.0
Für asynchrone Request-Response können Sie den Completion-Handler verwenden. Siehe unten Ich habe die Lösung mit dem Vervollständigungshandle-Paradigma modifiziert.
Sie können diese Funktion wie folgt aufrufen:
quelle
Swift 3-Version von @Alexey Globchastyys Antwort:
quelle
Ich hoffe, Sie bleiben noch nicht dabei, aber die kurze Antwort lautet, dass Sie dies in Swift nicht tun können.
Ein alternativer Ansatz wäre, einen Rückruf zurückzugeben, der die benötigten Daten bereitstellt, sobald sie bereit sind.
quelle
callback
mitclosure
s, wie Sie hervorheben , oderdelegation
wie die älteren Kakao-APIsEs gibt drei Möglichkeiten, Rückruffunktionen zu erstellen: 1. Abschlusshandler 2. Benachrichtigung 3. Delegierte
Completion Handler Innerhalb des Blocksatzes wird ausgeführt und zurückgegeben, wenn die Quelle verfügbar ist. Der Handler wartet, bis eine Antwort eingeht, damit die Benutzeroberfläche anschließend aktualisiert werden kann.
Benachrichtigung Eine Reihe von Informationen wird über die gesamte App ausgelöst. Listner kann diese Informationen abrufen und nutzen. Asynchrone Methode, um Informationen durch das Projekt zu erhalten.
Delegaten Eine Reihe von Methoden wird ausgelöst, wenn der Delegat aufgerufen wird. Die Quelle muss über die Methoden selbst bereitgestellt werden
quelle
quelle
Es gibt hauptsächlich drei Möglichkeiten, um schnell einen Rückruf zu erzielen
Closures / Completion Handler
Delegierte
Benachrichtigungen
Beobachter können auch verwendet werden, um benachrichtigt zu werden, sobald die asynchrone Aufgabe abgeschlossen ist.
quelle
Es gibt einige sehr allgemeine Anforderungen, die jeder gute API-Manager erfüllen soll: Er implementiert einen protokollorientierten API-Client.
APIClient Initial Interface
Jetzt überprüfen Sie bitte die vollständige API-Struktur
quelle
Dies ist ein kleiner Anwendungsfall, der hilfreich sein könnte:
Beim Aufruf der Funktion: -
quelle