リモートサーバーからデータを取得してCoreDataSQLiteデータベースに保存するアプリを構築しています。メインスレッドがデータを消費している間に、バックグラウンドスレッドからデータをフェッチしています。これが私が使用している主なアプローチです。
- すべてのバックグラウンドスレッドには独自のがあり
NSManagedObjectContext
ます。 - は
persistentStoreCoordinator
コンテキスト間で共有されます。 - バックグラウンドスレッドでフェッチするたびに、挿入されたオブジェクトを保存し、ローカルコンテキストをリセットします。
- 通知を使用して、メインスレッドコンテキストとマージします。
私が経験している問題:
- ランダムに
NSZombie
、バックグラウンドスレッドのsave:操作でメッセージなしでクラッシュが発生します(クラッシュブレークポイントが設定されます)。 - 大量の重複データが生成されています。Webサービスのデータは確かに問題ないので、サーバー側では問題ありません。
ここにコードがあります。
AppDelegate
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Update data from remote server
WebserviceDataModel *webservice = [[WebserviceDataModel alloc] init];
webservice.managedObjectContext = self.managedObjectContext;
[webservice startImport];
}
WebserviceDataModelでデータをフェッチして保存するバックグラウンドスレッド
- (void)startImport
{
dispatch_queue_t downloadQueue = dispatch_queue_create("startImport in WebserviceDataModel", NULL);
dispatch_async(downloadQueue, ^{
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init];
moc.persistentStoreCoordinator = self.managedObjectContext.persistentStoreCoordinator;
// get the remote data
NSDictionary *lojas = [Loja allLojasFromRemoteServer];
for (NSDictionary *lojaInfo in lojas) {
Loja *loja __attribute__((unused)) = [Loja lojaWithRemoteData:lojaInfo inManagedObjectContext:moc];
}
if ([moc hasChanges]) {
[moc save:nil];
[moc reset];
}
[moc release];
});
dispatch_release(downloadQueue);
}
オブジェクト作成用のNSManagedObjectメソッド:+ (Loja *)lojaWithRemoteData:inManagedContext:
+ (Loja *)lojaWithRemoteData:(NSDictionary *)remoteData inManagedObjectContext:(NSManagedObjectContext *)context
{
Loja *loja = nil;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:@"Loja" inManagedObjectContext:context];
request.predicate = [NSPredicate predicateWithFormat:@"lojaId = %d", [[remoteData objectForKey:@"lojaId"] intValue]];
NSError *error = nil;
loja = [[context executeFetchRequest:request error:&error] lastObject];
[request release];
if (!error && !loja) {
// create the record
loja = [NSEntityDescription insertNewObjectForEntityForName:@"Loja" inManagedObjectContext:context];
loja.lojaId = [remoteData objectForKey:@"lojaId"];
loja.email = [remoteData objectForKey:@"email"];
loja.facebook = [remoteData objectForKey:@"facebook"];
// ... and others...
}
return loja;
}
WebserviceDataModelのNSManagedObjectContextDidSaveNotificationへのサブスクリプション
- (id)init
{
self = [super init];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextChanged:) name:NSManagedObjectContextDidSaveNotification object:nil];
}
return self;
}
contextChanged:WebserviceDataModelのメソッド
- (void)contextChanged:(NSNotification*)notification
{
if ([notification object] == self.managedObjectContext) return;
if (![NSThread isMainThread]) {
[self performSelectorOnMainThread:@selector(contextChanged:) withObject:notification waitUntilDone:YES];
return;
}
[[self managedObjectContext] mergeChangesFromContextDidSaveNotification:notification];
}