Note
: Während es andere, ähnliche Fragen zu diesem in SO gibt, scheinen in keinem von ihnen die Autoren den Lebenszyklus der Operation
von selbst zu steuern. Bitte lesen Sie sich durch, bevor Sie sich auf eine andere Frage beziehen.Alamofire Anfrage läuft nicht Abschlussblock innerhalb NSOperation
Ich habe eine [NS] Operation in Swift 3.0 erstellt, um einige Daten in Core Data herunterzuladen, zu parsen und zwischenzuspeichern.
Zuerst habe ich die main()
Methode in der Operation verwendet, um die Aufgabe auszuführen, und es hat gut funktioniert. Jetzt muss ich mehrere separate Aufgaben ausführen, um Informationen über jedes einzelne Gerät zu erhalten, das ich in diesem Schritt erhalten habe. Dafür muss ich sicherstellen, dass die Geräte tatsächlich in Core Data sind, bevor ich versuche, die anderen Informationen zu erhalten. Aus diesem Grund möchte ich sicherstellen, dass ich mich entscheide, wann die Aufgabe abgeschlossen ist - und wann ALLE Geräte sicher im Cache sind - bevor die abhängigen Anfragen ausgelöst werden.
Das Problem ist, dass, obwohl ich überprüft habe, dass Alamofire die Anfrage ausführt und der Server die Daten sendet, der Completion-Block mit dem Kommentar [THIS WONT EXECUTE!
] nie ausgeführt wird. Dies führt dazu, dass die Warteschlange zum Stillstand kommt, da die Operation innerhalb des besagten Vervollständigungsblocks als finished
markiert ist, was das gewünschte Verhalten ist.
Hat jemand irgendwelche Ideen, was hier vor sich geht?
class FetchDevices: Operation {
var container: NSPersistentContainer!
var alamofireManager: Alamofire.SessionManager!
var host: String!
var port: Int!
private var _executing = false
private var _finished = false
override internal(set) var isExecuting: Bool {
get {
return _executing
}
set {
willChangeValue(forKey: "isExecuting")
_executing = newValue
didChangeValue(forKey: "isExecuting")
}
}
override internal(set) var isFinished: Bool {
get {
return _finished
}
set {
willChangeValue(forKey: "isFinished")
_finished = newValue
didChangeValue(forKey: "isFinished")
}
}
override var isAsynchronous: Bool {
return true
}
init(usingContainer container: NSPersistentContainer, usingHost host: String, usingPort port: Int) {
super.init()
self.container = container
self.host = host
self.port = port
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForResource = 10 // in seconds
self.alamofireManager = Alamofire.SessionManager(configuration: configuration)
}
override func start() {
if self.isCancelled {
self.isFinished = true
return
}
self.isExecuting = true
alamofireManager!.request("http://apiurlfor.devices")
.validate()
.responseJSON { response in
// THIS WONT EXECUTE!
if self.isCancelled {
self.isExecuting = false
self.isFinished = true
return
}
switch response.result {
case .success(let value):
let jsonData = JSON(value)
self.container.performBackgroundTask { context in
for (_, rawDevice):(String, JSON) in jsonData {
let _ = Device(fromJSON: rawDevice, usingContext: context)
}
do {
try context.save()
} catch {
let saveError = error as NSError
print("\(saveError), \(saveError.userInfo)")
}
self.isExecuting = false
self.isFinished = true
}
case .failure(let error):
print("May Day! May Day! \(error)")
self.isExecuting = false
self.isFinished = true
}
}
}
}
Eine Information, die nützlich sein kann, ist, dass bei dem Verfahren, wo ich alle Operationen Warteschlange, I queue.waitUntilAllOperationsAreFinished()
verwenden, um einen Abschluss-Handler auszuführen, nachdem alles getan ist.
Vielen Dank, dass Sie sich die Zeit genommen haben, @Rob zu beantworten. Ich habe getan, was Sie vorgeschlagen haben, und es gab keine Veränderung. Ich werde mir die Sache mit dem "Blockieren des Hauptthreads" ansehen, aber ich sehe nicht, was das verursachen kann. Der Code, den Sie sehen, ist die ganze Operation. Es gibt nicht mehr dazu. – reydelleon
OK @Rob, ich denke du hast in die richtige Richtung gewiesen, aber es gibt noch mehr zu tun. Ich benutze 'queue.waitUntilAllOperationsAreFinished()' in der Methode, die für das Einreihen der Aufgaben verantwortlich ist. Wenn ich das kommentiere, wird die Warteschlange nicht stehen bleiben, aber ich muss tatsächlich warten, bis alle Operationen beendet sind, bevor ich einen Beendigungshandler anrufe. Gibt es einen Weg dahin? – reydelleon
Ihre Antwort hat mich am Ende in die richtige Richtung geschickt. Ich habe es gerade bearbeitet, um einen Link zu einer Frage hinzuzufügen, die das ursprüngliche Problem anspricht, das ich erst gefunden habe, nachdem ich das Problem unter Berücksichtigung der Zeiger analysiert hatte. – reydelleon