Es gibt zwei Probleme:
Die downloadWeatherData
versucht, Daten zurückzugeben, die asynchron zurückgegeben wird. Es sollte nichts zurückgeben, sondern nur die Daten in der Schließung zurückgeben.
Die downloadWeatherDetails
hat eine verwirrende Kombination von Verschlussparametern, übergibt sie direkt an downloadWeatherData
, aber auch (a) versucht, ihre eigene Schließung zu dieser Methode zu liefern; und (b) Aktualisieren einer Eigenschaft auch.
Es sollte wahrscheinlich nur ein Modellobjekt erstellen, und das wiederum über einen Abschluss zurückgeben. Es sollte auch keine Eigenschaft aktualisieren.
Also, lasst uns zurücktreten. Um die Wörterbuch Ergebnisse zurück übergeben, aktualisieren Sie die typealias
Schließung entsprechend:
typealias DownloadComplete = ([String: Any]?) -> Void
Als Nebenwirkung, verwende ich die [KeyType: ValueType]
Syntax, die prägnanter ist als Dictionary<KeyType, ValueType>
, aber Sie können, dass andere Syntax verwenden, wenn Sie wirklich wollen. Beachten Sie auch, dass ich diesen Parameter des Abschlusses optional mache (damit Sie zwischen einem erfolgreichen Anruf und einem Fehler unterscheiden können).
Und dann downloadWeatherData
ist einfach:
/// Return the dictionary returned by web service.
///
/// - Parameters:
/// - url: URL of the web service.
/// - completed: The closure that's called when the asynchronous call finishes. If there was an error, the dictionary will be `nil`.
class func downloadWeatherData(url: String, completed: @escaping DownloadComplete) {
Alamofire.request(urlString).responseJSON { response in
completed(response.result.value as? [String: Any])
}
}
Die Absicht Ihrer anderen Methode, downloadWeatherDetails
, ist weniger klar. Sie scheinen zu versuchen, sowohl eine Eigenschaft zu aktualisieren als auch eine Schließung aufzurufen. Nur um die Dinge sauber zu halten, würde ich vorschlagen, dass Sie das eine oder andere tun, aber nicht beides.
Zum Beispiel habe ich einige Modellobjekt vorstellen konnte:
:
struct WeatherReport {
let city: String
let low: Float
let high: Float
}
Und downloadWeatherDetails
könnte einige wichtige Informationen extrahiert, vielleicht Gebäude, das Modellobjekt (ich habe die Methode, entsprechend umbenannt)
/// Build `WeatherReport` object and pass it back in the closure.
///
/// - Parameter completed: The closure that will be called when the method finishes.
func downloadWeatherReport(completed: @escaping (WeatherReport?) -> Void) {
SharedFunctions.downloadWeatherData(url: currentWeatherUrl) { dictionary in
guard let city = dictionary?["name"] as? String, let low = dictionary?["low"] as? Float, let high = dictionary?["high"] as? Float else {
completed(nil)
return
}
completed(WeatherReport(city: city, low: low, high: high))
}
}
Nun, ich weiß nicht, ob dieses Modellobjekt alles erfasst, was Sie wollen. Ebenso weiß ich nicht, was die Schlüssel zu deinem Wörterbuch sind. Aber es veranschaulicht die Idee: Extrahieren Sie die Informationen, die Sie benötigen, um ein Modellobjekt zu erstellen, und übergeben Sie das über den Abschluss (keine return
-Anweisung).
Wie auch immer, mit meinem theoretischen Beispiel fort, kann ich so etwas wie dies dann tun, die die Benutzeroberfläche aktualisiert, vielleicht in viewDidLoad
oder dem Wasserhahn auf eine Taste aufgerufen:
downloadWeatherReport { weatherReport in
guard let weatherReport = weatherReport else {
// handle error here
return
}
// update some model property
self.weatherReport = weatherReport
// and update the UI, too
let formatter = NumberFormatter()
self.cityLabel.text = weatherReport.city
self.lowLabel.text = formatter.string(from: NSNumber(value: weatherReport.low))
self.highLabel.text = formatter.string(from: NSNumber(value: weatherReport.high))
}
Aber nicht verloren gehen in den Details meines Beispiels, sondern konzentrieren Sie sich auf die Nachricht von zu Hause, dass im Umgang mit asynchronen Methoden nicht versuchen, sofort Daten zurückzugeben oder Eigenschaften zu aktualisieren, sondern Daten über Schließungen zurückgeben. Und der ultimative Anrufer kümmert sich um die Aktualisierung des Modells und der Benutzeroberfläche.