我正在构建一个应用程序,它从远程服务器提取数据并将它们存储在CoreData SQLite数据库中。我在主线程消耗它时从后台线程获取数据。以下是我正在使用的主要方法。
NSManagedObjectContext
。persistentStoreCoordinator
在上下文之间共享。我遇到的问题:
NSZombie
和Crash Breakpoints设置)崩溃。这是代码。
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;
}
WebserviceDataModel上的contextChanged:方法
- (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];
}
答案 0 :(得分:1)
好吧,我已经弄明白了。它现在就像一个魅力。多线程上下文的实现是正确的。问题出在applicationDidBecomeActive:
我的应用程序使用CoreLocation Fence获取功能列表。当应用程序首次启动时,CoreLocation框架会向用户显示一条警告消息,指出应用程序使用de user位置...该警报再次调用applicationDidBecomeActive:
,创建两个并发的更新波。刚刚将我的WebserviceDataModel移动到一个属性并实现了一个标志,以了解它是否正在运行。多数民众赞成
只是为了进行最后的改进,将合并策略更改为NSMergeByPropertyStoreTrumpMergePolicy
,所以现在服务器端数据(在内存中)胜过本地存储。
答案 1 :(得分:0)
没有细节,很难理解发生了什么。
说,首先,尝试设置断点并遵循应用程序流程。也许你可以找到应用程序崩溃的地方。
然后,您确定lojaId
是标量值吗?创建新实体时,您编写了以下内容:
loja.lojaId = [remoteData objectForKey:@"lojaId"];
也许这可能是错误,所以我会尝试以下谓词:
[NSPredicate predicateWithFormat:@"lojaId == %@", [remoteData objectForKey:@"lojaId"]];
最后,当您执行保存尝试记录NSError
对象时。也许你可以找到崩溃的原因。
if ([moc hasChanges]) {
NSError* error = nil;
[moc save:&error];
if(error) {
NSLog(@"Error during save: %@\n%@", [error localizedDescription], [error userInfo]);
abort(); // only for debug purposes
}
[moc reset];
}
希望它有所帮助。