我的应用中有核心数据,它在主线程中运行。但是现在我从服务器接收大量数据并保存到coredata,现在我的速度变慢了。我已经在堆栈中搜索了解决方案,发现我需要使用背景核心数据保存。它会解决我的问题吗?
如果是的话,我很困惑如何将现有方法更改为后台核心数据?
这是我现在使用的代码,用于保存到Core数据中。
-(void)insertToUserEntityWithData:(NSMutableDictionary *)inDictionary
{
AppDelegate *sharedDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [sharedDelegate managedObjectContext];
UserInfo *userInfo = [NSEntityDescription
insertNewObjectForEntityForName:@"UserInfo"
inManagedObjectContext:context];
if([[inDictionary allKeys] containsObject:@"userEmail"])
{
if([inDictionary valueForKey:@"userEmail"]!=[NSNull null])
{
userInfo.userEmail=[inDictionary valueForKey:@"userEmail"];
}
}
if([[inDictionary allKeys] containsObject:@"password"])
{
if([inDictionary valueForKey:@"password"]!=[NSNull null])
{
userInfo.password=[inDictionary valueForKey:@"password"];
}
}
if([[inDictionary allKeys] containsObject:@"isCurrentUser"])
{
if([inDictionary valueForKey:@"isCurrentUser"]!=[NSNull null])
{
userInfo.isCurrentUser=[NSNumber numberWithBool:[[inDictionary valueForKey:@"isCurrentUser"] boolValue]];
}
}
if([[inDictionary allKeys] containsObject:@"login_time"])
{
if([inDictionary valueForKey:@"login_time"]!=[NSNull null])
{
userInfo.loginTimestamp=[NSString stringWithFormat:@"%@",[inDictionary valueForKey:@"login_time"]];
}
}
if([inDictionary valueForKey:@"sid"]!=[NSNull null])
{
userInfo.sessionID=[inDictionary valueForKey:@"sid"];
}
NSError *error;
if (![context save:&error]) {
NSLog(@"Could not insert to userInfo: %@", [error localizedDescription]);
}
}
更新的代码已崩溃
015-04-08 12:59:32.935 Inxed[3401:158275] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Parent NSManagedObjectContext must use either NSPrivateQueueConcurrencyType or NSMainQueueConcurrencyType.'
*** First throw call stack:
(
0 CoreFoundation 0x035fb946 __exceptionPreprocess + 182
1 libobjc.A.dylib 0x03284a97 objc_exception_throw + 44
2 CoreData 0x013b224d -[NSManagedObjectContext setParentContext:] + 269
3 Inxed 0x002463de __55-[IXDataBaseManager updateThreadEntityWithSyncDetails:]_block_invoke + 318
4 libdispatch.dylib 0x03fa030a _dispatch_call_block_and_release + 15
5 libdispatch.dylib 0x03fc0e2f _dispatch_client_callout + 14
6 libdispatch.dylib 0x03fa6afc _dispatch_queue_drain + 1475
7 libdispatch.dylib 0x03fa63c3 _dispatch_queue_invoke + 212
8 libdispatch.dylib 0x03fa9067 _dispatch_root_queue_drain + 466
9 libdispatch.dylib 0x03faa84a _dispatch_worker_thread3 + 115
10 libsystem_pthread.dylib 0x0431c296 _pthread_wqthread + 724
11 libsystem_pthread.dylib 0x04319eea start_wqthread + 30
)
libc++abi.dylib: terminating with uncaught exception of type NSException
managedObjectContext
- (NSManagedObjectContext *)managedObjectContext
{
managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return _managedObjectContext;
}
retrieveCurrentUserDetailsForUser
-(UserInfo *)retrieveCurrentUserDetailsForUser:(NSString*)inUserEmail
{
AppDelegate *sharedDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [sharedDelegate managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setReturnsObjectsAsFaults:NO];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"UserInfo"
inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSPredicate *userPredicate = [NSPredicate predicateWithFormat:@"userEmail == %@",inUserEmail];
[fetchRequest setPredicate:userPredicate];
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:nil];
if(fetchedObjects.count!=0)
{
UserInfo *userInfo=[fetchedObjects objectAtIndex:0];
return userInfo;
}
return nil;
}
CRASH LOG
2015-04-08 14:17:29.789 Inxed[3519:170514] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+entityForName: nil is not a legal NSPersistentStoreCoordinator for searching for entity name 'UserInfo''
*** First throw call stack:
(
0 CoreFoundation 0x03673946 __exceptionPreprocess + 182
1 libobjc.A.dylib 0x032fca97 objc_exception_throw + 44
2 CoreData 0x013d8ba9 +[NSEntityDescription entityForName:inManagedObjectContext:] + 281
3 Inxed 0x002cf47c -[IXDataBaseManager retrieveCurrentUserDetailsForUser:] + 316
4 Inxed 0x001a9268 -[AppDelegate application:didFinishLaunchingWithOptions:] + 2552
5 UIKit 0x01ccd97c -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 291
6 UIKit 0x01cce687 -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 2869
7 UIKit 0x01cd1c0d -[UIApplication _runWithMainScene:transitionContext:completion:] + 1639
8 UIKit 0x01cea7d0 __84-[UIApplication _handleApplicationActivationWithScene:transitionContext:completion:]_block_invoke + 59
9 UIKit 0x01cd081f -[UIApplication workspaceDidEndTransaction:] + 155
10 FrontBoardServices 0x056ed9de __37-[FBSWorkspace clientEndTransaction:]_block_invoke_2 + 71
11 FrontBoardServices 0x056ed46f __40-[FBSWorkspace _performDelegateCallOut:]_block_invoke + 54
12 FrontBoardServices 0x056ff425 __31-[FBSSerialQueue performAsync:]_block_invoke + 26
13 CoreFoundation 0x035971c0 __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 16
14 CoreFoundation 0x0358cad3 __CFRunLoopDoBlocks + 195
15 CoreFoundation 0x0358c92b __CFRunLoopRun + 2715
16 CoreFoundation 0x0358bbcb CFRunLoopRunSpecific + 443
17 CoreFoundation 0x0358b9fb CFRunLoopRunInMode + 123
18 UIKit 0x01cd01e4 -[UIApplication _run] + 571
19 UIKit 0x01cd38b6 UIApplicationMain + 1526
20 Inxed 0x002160ad main + 141
21 libdyld.dylib 0x04064ac9 start + 1
22 ??? 0x00000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
答案 0 :(得分:0)
创建后台队列,通过为该块创建上下文
,在该队列上调度插入代码不要在后台线程上使用mainContext
请参阅修改后的代码。
-(void)insertToUserEntityWithData:(NSMutableDictionary *)inDictionary
{
dispatch_queue_t backgroundQueue = dispatch_queue_create("backgroundQueueName", NULL);
dispatch_async(backgroundQueue, ^{
AppDelegate *sharedDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [sharedDelegate managedObjectContext];
NSManagedObjectContext *contextforThread = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
contextforThread.parentContext = context;
UserInfo *userInfo = [NSEntityDescription
insertNewObjectForEntityForName:@"UserInfo"
inManagedObjectContext:contextforThread];
if([[inDictionary allKeys] containsObject:@"userEmail"])
{
if([inDictionary valueForKey:@"userEmail"]!=[NSNull null])
{
userInfo.userEmail=[inDictionary valueForKey:@"userEmail"];
}
}
if([[inDictionary allKeys] containsObject:@"password"])
{
if([inDictionary valueForKey:@"password"]!=[NSNull null])
{
userInfo.password=[inDictionary valueForKey:@"password"];
}
}
if([[inDictionary allKeys] containsObject:@"isCurrentUser"])
{
if([inDictionary valueForKey:@"isCurrentUser"]!=[NSNull null])
{
userInfo.isCurrentUser=[NSNumber numberWithBool:[[inDictionary valueForKey:@"isCurrentUser"] boolValue]];
}
}
if([[inDictionary allKeys] containsObject:@"login_time"])
{
if([inDictionary valueForKey:@"login_time"]!=[NSNull null])
{
userInfo.loginTimestamp=[NSString stringWithFormat:@"%@",[inDictionary valueForKey:@"login_time"]];
}
}
if([inDictionary valueForKey:@"sid"]!=[NSNull null])
{
userInfo.sessionID=[inDictionary valueForKey:@"sid"];
}
if (![contextforThread save:&error]) {
NSLog(@"Could not insert to userInfo: %@", [error localizedDescription]);
}
dispatch_async(dispatch_get_main_queue(), ^{
NSError *error;
if (![context save:&error]) {
NSLog(@"Could not insert to userInfo: %@", [error localizedDescription]);
}
else
{
//Post a notification or call method for tableview reload here
}
});
});
}
修改强>
在AppDelegate.m中找到您的方法 managedObjectContext
并进行以下更改
managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
编辑2
请参阅我的核心数据方法。相应地做出改变。
请参阅:您的NSManagedObjectContext只能在您的 - (NSManagedObjectContext *)managedObjectContext方法中创建
- (NSManagedObjectContext *) managedObjectContext {
if (managedObjectContext != nil) {
return managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[managedObjectContext setPersistentStoreCoordinator: coordinator];
}
//[managedObjectContext setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy];
return managedObjectContext;
}
- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel != nil) {
return managedObjectModel;
}
managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
return managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator != nil) {
NSLog(@"old persistent returned!!!");
return persistentStoreCoordinator;
}
NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory]
stringByAppendingPathComponent: @"<Project Name>.sqlite"]];
NSError *error = nil;
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc]
initWithManagedObjectModel:[self managedObjectModel]];
if(![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil URL:storeUrl options:nil error:&error]) {
/*Error for store creation should be handled in here*/
}
NSLog(@"new persistent created!!!");
return persistentStoreCoordinator;
}
- (NSString *)applicationDocumentsDirectory {
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
}
答案 1 :(得分:0)
从背景线程创建私有上下文,并将其父上下文设置为主上下文。
NSManagedObjectContext* childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
childContext.parentContext = self.mainContext;
在后台线程中使用此子上下文插入/更新/删除您的托管对象,然后将子项与主上下文一起保存,如下所示
[childContext performBlock:^{
// do something that takes some time asynchronously using the temp context
// push to parent
NSError *error;
if (![childContext save:&error])
{
// handle error
}
// save parent to disk asynchronously
[self.mainContext performBlock:^{
NSError *error;
if (![self.mainContext save:&error])
{
// handle error
}
}];
}];