mBaaSで、複数オブジェクト操作APIの提供終了に伴い、for文等で複数オブジェクト操作を行った際に、処理が完了した後にメインスレッドに戻す必要性が出てきました。
http://info.biz.nifty.com/mb/2017/03/api-2.html
今回は、Operationを利用してその処理を行ってみようと思います。
Operationのサブクラスを作成する
RequestOperation.swift
class RequestOperation: Operation {
var object:NCMBObject? = nil
private var _executing: Bool = false
override var isExecuting: Bool {
get {
return _executing
}
set {
if _executing != newValue {
willChangeValue(forKey: "isExecuting")
_executing = newValue
didChangeValue(forKey: "isExecuting")
}
}
}
private var _finished: Bool = false;
override var isFinished: Bool {
get {
return _finished
}
set {
if _finished != newValue {
willChangeValue(forKey: "isFinished")
_finished = newValue
didChangeValue(forKey: "isFinished")
}
}
}
init(object:NCMBObject?) {
super.init()
self.object = object
}
override func start() {
_executing = true
// データストアへの登録を実施
object?.saveInBackground({ (error) in
if error != nil {
// 保存に失敗した場合の処理
} else {
// 保存に成功した場合の処理
}
self._executing = false
self._finished = true
})
// 並列実行モードで動かす
repeat {
RunLoop.current.run(mode: RunLoopMode.defaultRunLoopMode, before: NSDate.distantFuture)
} while isExecuting
}
}
処理を実行するクラスでの処理
プロパティ
var finishedBlock: (() -> Void)?
処理を実行するメソッド内での処理
let operationQueue = OperationQueue.init()
// OperationQueueのカウント数の監視を登録
operationQueue.addObserver(self, forKeyPath: "operationCount", options: .new, context: nil)
for _ in 1...5 {
// testクラスのNCMBObjectを作成
let object = NCMBObject.init(className: "test")
// オブジェクトに値を設定
object?.setObject("value", forKey: "key")
// リクエストの作成
let operasion = RequestOperation.init(object :object)
// 処理の開始
operationQueue.addOperation(operasion)
}
// 処理が完了した時のblock
self.finishedBlock = {() -> Void in
// メインスレッドに戻ってきた時に行う処理
}
// NSOperationQueueのカウント数に変化があると呼ばれる
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
// operationCountが0になり処理が完了した時にメインスレッドでblockを実行する
if keyPath == "operationCount" {
if change?[NSKeyValueChangeKey.newKey] as! Int == 0 {
OperationQueue.main.addOperation({
self.finishedBlock!()
})
}
}
}
waitUntilAllOperationsAreFinishedメソッドについて
waitUntilAllOperationsAreFinishedメソッドを利用して、キューに入っているオペレーションが完了するのを待つ方法があります。
しかし、NCMBのsaveInBackgroundWithBlockはNSURLConnectionに[NSOperationQueue mainQueue]を設定しているため、waitUntilAllOperationsAreFinishedを利用して完了するのを待っても処理が実行されません。
そのため、今回はKVOを利用する方法になっています。