はい、これは可能です。主な利点は、GCD への依存を取り除き、コードの大部分を主要な同時実行テクノロジにとらわれないようにできることです。
これをView Controllerクラスに追加するのではなく、非同期作業ユニットのディスパッチを管理し、それらのコールバックを調整する責任を持つ新しいクラスを開始するのが合理的だと思います。このようなオブジェクトは、後でカスタム ディスパッチ キューまたは を維持しNSOperationQueue
たり、将来のテクノロジが登場したりする可能性があります。私は、基礎となるスレッド技術に依存しないブロックをディスパッチするための API も提供するデフォルトのインスタンスを持つものを想像しています。GCD を使用した例は次のとおりです。
typedef void(^AsynchronousWorkManagerBlock)();
@interface AsynchronousWorkManager : NSObject
+ (AsynchronousWorkManager *)defaultManager;
- (void)executeInBackground:(AsynchronousWorkManagerBlock)backgroundBlock
withMainThreadCallback:(AsynchronousWorkManagerBlock)callbackBlock;
@end
@implementation AsynchronousWorkManager
+ (AsynchronousWorkManager *)defaultManager
{
static dispatch_once_t onceToken;
static AsynchronousWorkManager *DefaultManager = nil;
dispatch_once(&onceToken, ^{
DefaultManager = [[self alloc] init];
});
return DefaultManager;
}
- (void)executeInBackground:(AsynchronousWorkManagerBlock)backgroundBlock
withMainThreadCallback:(AsynchronousWorkManagerBlock)callbackBlock
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
backgroundBlock();
dispatch_async(dispatch_get_main_queue(), callbackBlock);
});
}
@end
クライアントコードは次のように呼び出すことができます:
[[AsynchronousWorkManager defaultManager] executeInBackground:^{
NSLog(@"This code is happening in the background");
}
withMainThreadCallback:^{
NSLog(@"This code is happening on the main thread");
}];
[[AsynchronousWorkManager defaultManager] executeInBackground:^{
sleep(3);
}
withMainThreadCallback:^{
NSLog(@"Done Sleeping");
}];
後でNSOperationQueue
GCD の代わりに使用することに切り替えた場合、次の実装例のように、API を変更せずに簡単に変更できます。
@interface AsynchronousWorkManager ()
@property (nonatomic, strong) NSOperationQueue *operationQueue;
@end
@implementation AsynchronousWorkManager
+ (AsynchronousWorkManager *)defaultManager
{
static dispatch_once_t onceToken;
static AsynchronousWorkManager *DefaultManager = nil;
dispatch_once(&onceToken, ^{
DefaultManager = [[self alloc] init];
});
return DefaultManager;
}
- (id)init
{
if (self = [super init]) {
_operationQueue = [[NSOperationQueue alloc] init];
}
return self;
}
- (void)executeInBackground:(AsynchronousWorkManagerBlock)backgroundBlock
withMainThreadCallback:(AsynchronousWorkManagerBlock)callbackBlock
{
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:backgroundBlock];
blockOperation.completionBlock = ^{ [[NSOperationQueue mainQueue] addOperationWithBlock:callbackBlock]; };
[self.operationQueue addOperation:blockOperation];
}
@end
これがどれほど必要かは完全にはわかりませんが、多くのコードがなくても達成できるので、オーバーエンジニアリングの練習だけではなく、おそらく価値があると判断します. あなたのアプリケーションがさまざまなプライオリティ キューやより特化した GCD 機能を広範囲に使用している場合、根本的な実装の柔軟性を真に得ずに漏れやすい抽象化を導入する可能性があるため、これに移行することには慎重です。