Last active
August 29, 2015 14:14
-
-
Save roothybrid7/f55c162814bcde6865df to your computer and use it in GitHub Desktop.
実行中のNSOperationに考慮しつつ、NSOperationQueueのキャンセルを実行する ref: http://qiita.com/roothybrid7/items/83db3809775295ea6df3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// DataParseOperationQueue.h | |
#import <Foundation/Foundation.h> | |
@interface DataParseOperationQueue : NSOperationQueue | |
// XXX: 全ての実行中の`NSOperation`が終わるまで待ち、完了したらcompletionHandler blocksを実行する | |
- (void)cancelAllOperationsWithCompletionHandler:(void(^)(void))completionHandler; | |
@end | |
// DataParseOperationQueue.m | |
#import "DataParseOperationQueue.h" | |
static NSString *const SynchronizedQueueLabelPrefix = @"com.rh7.synchronized.DataParseOperationQueue"; | |
@interface ParseOperationQueue () | |
// XXX: 同時アクセスを防止するためのシリアルキュー(@synchronizedでも可) | |
@property (nonatomic) dispatch_queue_t synchronizedQueue; | |
@end | |
@implementation ParseOperationQueue | |
- (instancetype)init { | |
self = [super init]; | |
if (self) { | |
const char *synchronized_queue_label = [[SynchronizedQueueLabelPrefix stringByAppendingPathExtension:[[NSUUID UUID] UUIDString]] UTF8String]; | |
_synchronizedQueue = dispatch_queue_create(synchronized_queue_label, DISPATCH_QUEUE_SERIAL); | |
} | |
return self; | |
} | |
- (void)cancelAllOperationsWithCompletionHandler:(void(^)(void))completionHandler { | |
dispatch_sync(self.synchronizedQueue, ^{ | |
// XXX: 実行待ちの`NSOperation`を実行されないように停止する | |
self.suspended = YES; | |
// XXX: 実行待ちの`NSOperation`は全てキャンセルする | |
NSArray *pendingOperations = [self.operations filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"%K == %@", @"isExecuting", @NO]]; | |
[pendingOperations enumerateObjectsUsingBlock:^(NSOperation *op, NSUInteger idx, BOOL *stop) { | |
[op cancel]; | |
}]; | |
// XXX: 実行中の`NSOperation`が全て完了してから、`completionHandler`を一番最後に実行するため、同時実行並列数を1にする | |
NSUInteger currentMaxConcurrentCount = self.maxConcurrentOperationCount; | |
self.maxConcurrentOperationCount = 1; | |
// XXX: 再開 | |
self.suspended = NO; | |
// XXX: このOperationは必ず最後に実行される | |
NSBlockOperation *waitForCompletion = [NSBlockOperation blockOperationWithBlock:^{ | |
if (completionHandler) { | |
completionHandler(); // 呼び出し元から渡されたblocksを実行 | |
} | |
// XXX: 設定を元に戻す | |
self.maxConcurrentOperationCount = currentMaxConcurrentCount; | |
}]; | |
[self addOperation:waitForCompletion]; | |
}); | |
} | |
@end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "DataParseOperationQueue.h" | |
@interface AccountManger () | |
@property (nonatomic, readonly) DataParseOperationQueue *operationQueue; | |
@end | |
@implementation AccountManager | |
- (void)cancelAllOperationsWithCompletionHandler:(void(^)(void))completionHandler { | |
dispatch_sync(self.synchronizedQueue, ^{ | |
DataParseOperationQueue *operationQueue = self.operationQueue; | |
self.operationQueue = nil; // XXX: 新しい処理を追加されないように、 一旦他から参照させないようにする | |
// XXX: Pendingのままにして、実行していないオペレーションをすべてキャンセルする | |
[operationQueue cancelAllOperationsWithCompletionHandler:^{ | |
// XXX: 元に戻す | |
self.operationQueue = operationQueue; | |
if (completionHandler) { | |
completionHandler(); | |
} | |
}]; | |
}); | |
} | |
@end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
- (PMKPromise *)waitAllOperations { | |
PMKPromise *accountManagerCancelAllOperations = [PMKPromise new:^(PMKPromiseFulfiller fulfill, PMKPromiseRejecter reject) { | |
[[AccountManager defaultManager] cancelAllOperationsWithCompletionHandler:^{ fulfill(nil); }]; | |
}]; | |
PMKPromise *apiResourceManagerCancelAllOperations = [PMKPromise new:^(PMKPromiseFulfiller fulfill, PMKPromiseRejecter reject) { | |
[[APIResourceManager defaultManager] cancelAllOperationsWithCompletionHandler:^{ fulfill(nil); }]; | |
}]; | |
return [PMKPromise when:@[accountManagerCancelAllOperations, organizationCancelAllOperations]]; | |
} | |
- (void)logout { | |
[APISessionManager sharedManager] resetSession]; | |
[self waitAllOperations].finally(^{ | |
// XXX: すべてのOperationQueueのキャンセルが完了したら、ログアウト処理を実行する。 | |
[self closeSessionWithNotification]; | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment