如何将正常核心数据更改为背景?

时间:2015-04-08 06:49:43

标签: ios multithreading core-data

我的应用中有核心数据,它在主线程中运行。但是现在我从服务器接收大量数据并保存到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

2 个答案:

答案 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:&amp;error])
  {
    // handle error
  }

  // save parent to disk asynchronously
 [self.mainContext performBlock:^{
    NSError *error;
    if (![self.mainContext save:&amp;error])
    {
      // handle error
   }
 }];
}];