mBaaSで、複数オブジェクト操作APIの提供終了に伴い、for文等で複数オブジェクト操作を行った際に、処理が完了した後にメインスレッドに戻す必要性が出てきました。
http://info.biz.nifty.com/mb/2017/03/api-2.html
今回は、NSOperationを利用してその処理を行ってみようと思います。
NSOperationのサブクラスを作成する
RequestOperation.h
#import <Foundation/Foundation.h>
#import <NCMB/NCMB.h>
@interface RequestOperation : NSOperation
@property (nonatomic) NCMBObject *object;
@property (nonatomic) BOOL isExecuting, isFinished;
- (id)initWithObject:(NCMBObject *)object;
@end
RequestOperation.m
#import "RequestOperation.h"
@implementation RequestOperation
- (id)initWithObject:(NCMBObject *)object {
self = [super init];
if (self) {
_object = object;
}
_isExecuting = NO;
_isFinished = NO;
return self;
}
- (void) start {
self.isExecuting = YES;
// データストアへの登録を実施
[self.object saveInBackgroundWithBlock:^(NSError *error) {
if (error){
// 保存に失敗した場合の処理
} else {
// 保存に成功した場合の処理
}
self.isExecuting = NO;
self.isFinished = YES;
}];
// 並列実行モードで動かす
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:[NSDate distantFuture]];
} while (self.isExecuting);
}
@end
処理を実行するクラスでの処理
プロパティ
@property (nonatomic) void (^finishedBlock) ();
処理を実行するメソッド内での処理
NSOperationQueue* operationQueue = [[NSOperationQueue alloc] init];
// NSOperationQueueのカウント数の監視を登録
[operationQueue addObserver:self
forKeyPath:@"operationCount"
options:NSKeyValueObservingOptionNew
context:nil];
for (int i = 0; i < 5; i++) {
// testクラスのNCMBObjectを作成
NCMBObject *object = [NCMBObject objectWithClassName:@"test"];
// オブジェクトに値を設定
[object setObject:@"value" forKey:@"key"];
// リクエストの作成
RequestOperation *operation = [[RequestOperation alloc] initWithObject:object];
// 処理の開始
[operationQueue addOperation:operation];
}
// 処理が完了した時のblock
self.finishedBlock = ^(){
// メインスレッドに戻ってきた時に行う処理
};
// NSOperationQueueのカウント数に変化があると呼ばれる
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
// operationCountが0になり処理が完了した時にメインスレッドでblockを実行する
if ([keyPath isEqualToString:@"operationCount"]) {
if ([[change objectForKey:@"new"] intValue] == 0) {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.finishedBlock();
}];
}
}
}
waitUntilAllOperationsAreFinishedメソッドについて
waitUntilAllOperationsAreFinishedメソッドを利用して、キューに入っているオペレーションが完了するのを待つ方法があります。
しかし、NCMBのsaveInBackgroundWithBlockはNSURLConnectionに[NSOperationQueue mainQueue]を設定しているため、waitUntilAllOperationsAreFinishedを利用して完了するのを待っても処理が実行されません。
そのため、今回はKVOを利用する方法になっています。