アプリでコアデータを使用し、次の 3 つのコンテキストを使用します。
__masterManagedObjectContext ->は、NSPersistentStoreCoordinator を持ち、データをディスクに保存するコンテキストです。
_mainManagedObjectContext ->は、どこでもアプリによって使用されるコンテキストです
dispatchContext ->バックグラウンド メソッドで使用されるコンテキスト。Web サービスへのアクセスとすべてのコアデータの挿入/更新があります。
私のソリューションを実現するためにいくつかのコードを入れます:
アプリの初期化コード:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions //a app começa aqui
{
NSPersistentStoreCoordinator *coordinator = [self newPersistentStoreCoordinator];
__masterManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[__masterManagedObjectContext setPersistentStoreCoordinator:coordinator];
_mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_mainManagedObjectContext setUndoManager:nil];
[_mainManagedObjectContext setParentContext:__masterManagedObjectContext];
return YES;
}
ストアコーディネーターの新規作成方法
- (NSPersistentStoreCoordinator *)newPersistentStoreCoordinator
{
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"example.sqlite"];
NSError *error = nil;
NSPersistentStoreCoordinator *pC = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self newManagedObjectModel]];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
if (![pC addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return pC;
}
- (NSManagedObjectModel *)newManagedObjectModel
{
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"example" withExtension:@"momd"];
NSManagedObjectModel *newManagedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return newManagedObjectModel;
}
コンテキスト指定によるスレッド呼び出し (必須コード):
@try
{
dispatchContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
[dispatchContext setUndoManager:nil];
[dispatchContext setParentContext:__masterManagedObjectContext];
NSNotificationCenter *notify = [NSNotificationCenter defaultCenter];
[notify addObserver:self selector:@selector(mergeChanges:) name:NSManagedObjectContextDidSaveNotification object:dispatchContext];
if(dispatchContext != nil)
{
[NSThread detachNewThreadSelector:@selector(parseDataWithObjects) toTarget:self withObject:nil];
}
else
{
NSLog(@"context IS NIL");
}
}
バックグラウンド メソッド:
- (void)parseDataWithObjects
{
[dispatchContext lock];
...
webservice data parse, and core data inserting/updating (+/- 5MB)
...
[dispatchContext save:&error];
[dispatchContext unlock];
[__masterManagedObjectContext save:nil];
}
このメソッドは、coredata データにアクセスするためにすべての UI で呼び出されます。
- (NSManagedObjectContext *)managedObjectContext
{
return _mainManagedObjectContext;
}
呼び出し例:
NSManagedObjectContext *context = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
...fetching, update, ...
今、私の本当に問題:
マスター コンテキストを保存する必要がある場合 ( [__masterManagedObjectContext save:nil];
、バックグラウンドで)、メイン コンテキスト ( ) にアクセスしようとすると_mainManagedObjectContext
、アプリがフリーズします (おそらくロック?)。
保存処理には時間がかかります (大量のデータ (約 6 MB) のため)。保存中にアプリが遅くなり、このプロセスの実行中に一部のデータにアクセスすると、アプリが永久にフリーズします (強制終了する必要があります)。
別の問題は、コンテキストをマージすることです。他のviewControllerでメインコンテキストを使用し、そのコンテキストを保存すると、アプリを閉じるまですべてが正常に機能すると想像してください。アプリを再度開くと、何も保存されませんでした。
私は何を間違っていますか?今まで、この文脈は私を混乱させていました。誰かが私を助けることができますか?本当に感謝しております :)
- - - - - 編集:
Florian Kugler の回答に続いて、現在は 2 つのコンテキストしかなく、それぞれが同じコーディネーターを持っています。
アプリが初期化されると、次のメソッドを呼び出します。
-(void) createContexts
{
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"example" withExtension:@"momd"];
NSManagedObjectModel *newManagedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"example.sqlite"];
NSError *error = nil;
pC = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:newManagedObjectModel];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
if (![pC addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
mainManagedObjectContext.persistentStoreCoordinator = pC;
}
- (void)mergeChanges:(NSNotification*)notification {
[mainManagedObjectContext performBlock:^{
[mainManagedObjectContext mergeChangesFromContextDidSaveNotification:notification];
}];
}
- (void)saveMasterContext
{
[mainManagedObjectContext performBlock:^{
[mainManagedObjectContext save:nil];
}];
}
データのインポートを (バックグラウンドで) 開始するには、次のコードを使用します。
NSNotificationCenter *notify = [NSNotificationCenter defaultCenter];
[notify addObserver:self selector:@selector(mergeChanges:) name:NSManagedObjectContextDidSaveNotification object:backgroundContext];
[NSThread detachNewThreadSelector:@selector(parseDataWithObjects) toTarget:self withObject:nil];
私の背景方法:
- (void)parseDataWithObjects
{
[self resetTime];
backgroundContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
backgroundContext.persistentStoreCoordinator = pC;
...
[backgroundContext save:&error];
}
再開しています...
- 1st - メインコンテキストを作成します
- 2 番目 - 保存後に変更をマージするために、バックグラウンド コンテキスト通知を定義します。
- 3番目 - バックグラウンド メソッドを呼び出します
- 4rd - バックグラウンド コンテキストを保存します
そして、パフォーマンスは本当に優れています。しかし、アプリが少しフリーズします。「mergeChanges」にあると思います。私は何か間違ったことをしていますか?