在核心数据中同时保存上下文在 iOS7 中不起作用
Posted
技术标签:
【中文标题】在核心数据中同时保存上下文在 iOS7 中不起作用【英文标题】:Saving context concurrently in Core Data not working in iOS7 【发布时间】:2015-05-03 10:55:25 【问题描述】:我从几个异步调用的 Web 服务中获取了一些数据。当我收到他们的回复时,我需要使用收到的信息在 Core Data 中创建和保存相应的实体。由于服务回调是异步的,当我收到另一个服务时,我可能已经保存了其中一个服务的响应,所以我写了几个这样的方法:
- (void)createEntity
@autoreleasepool
dispatch_queue_t queue = dispatch_queue_create(kSaveQueue, NULL);
dispatch_async(queue, ^
// Context for background operations
NSManagedObjectContext *tmpContext = [[NSManagedObjectContext alloc] init];
NSPersistentStoreCoordinator *mainThreadContextPSC = [self.context persistentStoreCoordinator];
[tmpContext setPersistentStoreCoordinator:mainThreadContextPSC];
@try
// Parse service response and create entity
// Save context
[tmpContext save:nil];
dispatch_async(dispatch_get_main_queue(), ^
// Notify end of operation
);
@catch (NSException *ex)
NSLog(@"exception: %@", [ex description]);
);
实际上,我有两种这样的方法,一种用于假设EntityA,另一种用于EntityB,当我收到相应的服务响应(serviceA,serviceB)时会调用每个方法。在我的测试中,我看到 tmpContext
始终保存在 ios 8 中,但在 iOS 7 中,它只是第一个被保存的,而第二个实体没有保存在 Core Data
中。
为什么这在 iOS 8 中有效,但在 iOS 7 中无效?
提前致谢
【问题讨论】:
【参考方案1】:您使用alloc init
创建上下文然后分配持久存储协调器的方法已被弃用。
相反,使用工厂方法initWithConcurrencyType:
并将NSPrivateQueueConcurrencyType
传递给后台线程。通过调用setParentContext:
与父上下文关联。
您还可以利用上下文的performBlock
和performBlockAndWait
API 来执行后台操作,而不是下拉到 GCD。
【讨论】:
【参考方案2】:以上来自 Mundi 的回答是正确且很好的解释。我可以给你我用来创建线程上下文以及保存和停止上下文的代码
+ (NSManagedObjectContext*)startThreadContext
AppDelegate *theDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *moc = theDelegate.managedObjectContext;
NSThread *thread = [NSThread currentThread];
if ([thread isMainThread])
return moc;
// get thread dictionary
NSMutableDictionary *threadDictionary = [[NSThread currentThread] threadDictionary];
if ( [threadDictionary objectForKey:@"managedObjectContext"] == nil )
// create a context for this thread
NSManagedObjectContext *newMoc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[newMoc setPersistentStoreCoordinator:[theDelegate persistentStoreCoordinator]];
// Register for context save changes notification
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(mergeChanges:)
name:NSManagedObjectContextDidSaveNotification
object:newMoc];
[newMoc setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
[newMoc processPendingChanges]; // flush operations for which you want undos
[[newMoc undoManager] disableUndoRegistration];
newMoc.undoManager = nil;
// cache the context for this thread
[threadDictionary setObject:newMoc forKey:@"managedObjectContext"];
return [threadDictionary objectForKey:@"managedObjectContext"];
+ (void)saveAndStopThreadContext:(NSManagedObjectContext *)context
// save managed object
NSError* error = nil;
BOOL success = [context save:&error];
if ( !success )
ERRLOG(@"[stopThreadContext] failed to save managedObjectContext (err:%@)", error );
[[NSNotificationCenter defaultCenter] removeObserver:self
name:NSManagedObjectContextDidSaveNotification
object:context];
NSThread *thread = [NSThread currentThread];
if (![thread isMainThread])
NSMutableDictionary *threadDictionary = [[NSThread currentThread] threadDictionary];
[threadDictionary removeObjectForKey:@"managedObjectContext"];
你可以这样使用它
// get managed object context
NSManagedObjectContext* moc = [CoreDataHelper startThreadContext];
// perform update
[moc performBlock:^
/*
Do something...
*/
// save and stop thread context
[CoreDataHelper saveAndStopThreadContext:moc];
];
【讨论】:
以上是关于在核心数据中同时保存上下文在 iOS7 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章
UISearchBar 的自定义 InputView 在 iOS7 中不起作用