プロジェクトでコアデータを使用するために、UIManagedDocument
のサブクラスを使用しています。ポイントは、サブクラスがシングルトンインスタンスを返すことです。これにより、画面で単純にインスタンスを呼び出すことができ、管理オブジェクトコンテキストはすべてのインスタンスで同じままです。
UIManagedDocument
を使用する前に、ファイルパスが既に存在する場合は開くか、まだ存在しない場合は作成して、準備する必要があります。両方のシナリオを容易にするために、サブクラスにprepareWithCompletionHandler:
という便利なメソッドを作成しました。
@implementation SPRManagedDocument
// Singleton class method here. Then...
- (void)prepareWithCompletionHandler:(void (^)(BOOL))completionHandler
{
__block BOOL successful;
// _exists simply checks if the document exists at the given file path.
if (self.exists) {
[self openWithCompletionHandler:^(BOOL success) {
successful = success;
if (success) {
if (self.documentState != UIDocumentStateNormal) {
successful = NO;
}
}
completionHandler(successful);
}];
} else {
[self saveToURL:self.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
successful = success;
if (success) {
if (self.documentState != UIDocumentStateNormal) {
successful = NO;
}
}
completionHandler(successful);
}];
}
}
@end
私がやろうとしているのは、アプリデリゲートのdidFinishLaunchingWithOptions
でこの準備メソッドを呼び出し、最後にYES
またはNO
のいずれかを返す前に完了ブロックが実行されるのを待つことです。私の現在のアプローチはうまくいきません。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
__block BOOL successful;
SPRManagedDocument *document = [SPRManagedDocument sharedDocument];
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[document prepareWithCompletionHandler:^(BOOL success) {
successful = success;
}];
});
dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
});
return successful;
}
prepareWithCompletionHandler
を返す前に、successful
の完了ハンドラーが呼び出されるまで待つにはどうすればよいですか?私は本当に混乱しています。
didFinishLaunching
を検討しているわけでもないので、launchOptions
の戻りステータスが完了ハンドラの成功に依存している理由はわかりません。ここで、同期呼び出し(または、より正確には、非同期メソッドを同期メソッドに変換するためにセマフォを使用)を行うのを嫌います。ウォッチドッグプロセス。
セマフォは、非同期プロセスを同期化するための一般的な手法の1つです。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
__block BOOL successful;
SPRManagedDocument *document = [SPRManagedDocument sharedDocument];
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[document prepareWithCompletionHandler:^(BOOL success) {
successful = success;
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
return successful;
}
しかし、prepareWithCompletionHandler
が実行していることをさらにレビューすると、明らかに、独自の完了ブロックをメインキューにディスパッチするメソッドを呼び出しているため、この同期を試みるとデッドロックが発生します。
そのため、非同期パターンを使用します。 didFinishLaunchingWithOptions
でこれを開始したい場合、通知を投稿させることができます:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
__block BOOL successful;
SPRManagedDocument *document = [SPRManagedDocument sharedDocument];
[document prepareWithCompletionHandler:^(BOOL success) {
successful = success;
[[NSNotificationCenter defaultCenter] postNotificationName:kDocumentPrepared object:nil];
}];
return successful;
}
そして、View Controller addObserverForName
にこの通知を監視させることができます。
または、このコードをアプリデリゲートからそのView Controllerに移動して、通知の必要をなくすことができます。
ディスパッチグループを使用する場合は、少し異なります。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
__block BOOL successful;
SPRManagedDocument *document = [SPRManagedDocument sharedDocument];
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[document prepareWithCompletionHandler:^(BOOL success) {
successful = success;
dispatch_group_leave(group);
}];
}];
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
return successful;
}
dispatch_group_wait
またはセマフォですが、実際の解決策は、おそらく長い非同期要求が完了するまでdidFinishLaunching
を返すことをブロックする理由を再考することです。操作が完了するまで実際に他に何もできない場合、初期化が行われている間画面を待機してからすぐにdidFinishLaunchingから戻ってください。