Note
:これには他にも同様の質問がありますが、いずれも著者はOperation
のライフサイクルを制御しているようです。別の質問を参照する前に読んでください。AlamofireリクエストはNSOperation内の完了ブロックを実行していません
Core Dataでデータをダウンロード、解析、キャッシュするためにSwift 3.0で[NS] Operationを作成しました。
最初は、作業中にmain()
メソッドを使用して作業を実行し、うまくいきました。今度は、このステップで取得した各デバイスに関する情報を取得するために、いくつかのタスクを実行する必要があります。このために、他の情報を取得しようとする前に、デバイスが実際にコアデータに入っていることを確認する必要があります。そのため、依存する要求を開始する前に、すべてのデバイスが安全であり、キャッシュ内で健全であることがいつタスクが完了したかを確認する必要があります。
Alamofireがリクエストを実行し、サーバーがデータを送信することを確認したにもかかわらず、コメント[THIS WONT EXECUTE!
]でマークされた完了ブロックは決して実行されません。これにより、オペレーションは、前記完了ブロック内にfinished
としてマークされているので、待ち行列がストールする。これは所望の動作である。
ここで何が起こっているのか誰にも分かりますか?
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
}
}
}
}
有用であり得る情報の一部は、私はすべての操作をキューに入れる方法で、私はすべてが行われた後に完了ハンドラを実行するqueue.waitUntilAllOperationsAreFinished()
を使用することです。
@Robにお返事いただきありがとうございます。私はあなたが示唆したことをしたし、変化はなかった。私は 'main thread'を阻止しようとしていますが、何が原因か分かりません。あなたが見るコードはOperation全体です。それ以上はありません。 – reydelleon
OK @Rob、あなたは正しい方向を指していると思うが、やるべきことはまだまだある。タスクをキューイングするメソッドで 'queue.waitUntilAllOperationsAreFinished()'を使用しています。私がコメントした場合、キューは停止しませんが、実際には完了ハンドラを呼び出す前にすべての操作が完了するのを待つ必要があります。その周りに道がありますか? – reydelleon
答えが私の最後の正しい方向に送られました。私はちょうどあなたのポインタを考慮に入れて問題を分析した後に見つけた、元の問題を解決する質問へのリンクを追加するためにそれを編集しました。 – reydelleon