在后台线程上保存coredata会导致陷入死锁并崩溃

时间:2015-05-21 08:55:24

标签: ios objective-c multithreading core-data

我在背景方法(父子)中保存coredata,但是在主线程上完成提取。所以我在fetch方法中遇到了死锁,有时app崩溃了。我在做什么有什么不对吗?如何在不影响主线程的情况下改进保存和获取?我已经阅读了很多文档,但没有一个文档向我解释如何在项目中使用它们。如果这是一个错误的问题,请指导我正确的解决方案,并让我知道我的错误。

-(ThreadInfo *)retrieveSolicitationInfoForThreadID:(NSString*)inThreadID;
{
NSString *loginUser=[[NSUserDefaults standardUserDefaults]    valueForKey:@"currentUser"];

AppDelegate *sharedDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [sharedDelegate managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setReturnsObjectsAsFaults:NO];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"ThreadInfo"
                                      inManagedObjectContext:context];
[fetchRequest setEntity:entity];
 NSPredicate *userPredicate = [NSPredicate predicateWithFormat:@"userEmail ==   %@",loginUser];
 NSPredicate *threadPredicate = [NSPredicate predicateWithFormat:@"threadID == %@",inThreadID];

NSPredicate *compoundPredicate = [NSCompoundPredicate andPredicateWithSubpredicates: @[userPredicate, threadPredicate]];

[fetchRequest setPredicate:compoundPredicate];

 NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:nil];
if(fetchedObjects.count!=0)
{
    ThreadInfo *threadInfo=[fetchedObjects objectAtIndex:0];
    return threadInfo;
}
 return nil;
}  

保存

-(void)updateThreadEntityWithSyncDetails:(NSMutableDictionary *)inDictionary
  {

 NSString *loginUser=[[NSUserDefaults standardUserDefaults] valueForKey:@"currentUser"];

 AppDelegate *sharedDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [sharedDelegate managedObjectContext];

  //    NSManagedObjectContext *writerContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
  //   [writerContext setPersistentStoreCoordinator:[sharedDelegate persistentStoreCoordinator]];

 // create main thread MOC
   context = [[NSManagedObjectContext alloc]        initWithConcurrencyType:NSMainQueueConcurrencyType];
     context.parentContext = writerContext;

    NSManagedObjectContext *contextforThread = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];

   contextforThread.parentContext = context;

  [contextforThread performBlock:^{




NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setReturnsObjectsAsFaults:NO];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"ThreadInfo"
                                          inManagedObjectContext:contextforThread];
[fetchRequest setEntity:entity];
NSPredicate *userPredicate = [NSPredicate predicateWithFormat:@"userEmail == %@",loginUser];
NSPredicate *threadPredicate = [NSPredicate predicateWithFormat:@"threadID == %@",[inDictionary valueForKey:@"thread"]];
NSPredicate *compoundPredicate = [NSCompoundPredicate andPredicateWithSubpredicates: @[userPredicate, threadPredicate]];
[fetchRequest setPredicate:compoundPredicate];

NSArray *fetchedObjects = [contextforThread executeFetchRequest:fetchRequest error:nil];
for (ThreadInfo *threadInfo in fetchedObjects)
{
    if([[inDictionary allKeys] containsObject:@"userEmail"])
    {
        if([inDictionary valueForKey:@"userEmail"]!=[NSNull null])
        {
            threadInfo.userEmail=[inDictionary valueForKey:@"userEmail"];
        }
    }
    if([[inDictionary allKeys] containsObject:@"badgeValue"])
    {
        if([inDictionary valueForKey:@"badgeValue"]!=[NSNull null])
        {
            threadInfo.badgeValue=[inDictionary valueForKey:@"badgeValue"];
        }
    }


    if([[inDictionary allKeys] containsObject:@"choice4Percentage"])
    {
        if([inDictionary valueForKey:@"choice4Percentage"]!=[NSNull null])
        {
            threadInfo.choice4Percentage=[inDictionary valueForKey:@"choice4Percentage"];
        }
    }
    if([[inDictionary allKeys] containsObject:@"choice5Percentage"])
    {
        if([inDictionary valueForKey:@"choice5Percentage"]!=[NSNull null])
        {
            threadInfo.choice5Percentage=[inDictionary valueForKey:@"choice5Percentage"];
        }
    }

 }

    NSError *error;
    if(![context save:&error]) {
        NSLog(@"Child error : %@",error);

    }

    [context performBlock:^{
        NSError *error;
        if(![context save:&error]) {
            NSLog(@"%@",error);
        }
               }];
    }];


 }    

2 个答案:

答案 0 :(得分:3)

问题在于你的提取。您正在提取两个字符串,而我猜测的是您商店中的大量实体。您的抓取效果是您问题的100%。

A)如果可以避免,你不应该进行字符串比较 B)你不应该进行两次字符串比较

您的数据模型需要重构。对具有大量实体的表进行两次字符串比较无论如何都会表现不佳。

更新

您的数据结构不好。我不知道有多少方法可以这么说。理想情况下,您需要整数或其他数字结构作为唯一标识符。

由于您没有告诉我/我们您正在处理多少实体,我只能猜测您有大量实体。如何预期男人的结果?一?还是很多?这是一个你正在反对的独特约束吗?如果没有,为什么没有来自您的服务器的唯一约束?如果它是一个独特的约束,为什么你没有像我建议的那样限制提取大小?

您没有向我提供任何信息,但希望我能够神奇地解决您的问题。

您可以尝试将其缩减为一个字符串,但是您要求 您的数据的行为方式。测试一下。你有乐器,你有数据。改变一切并比较结果。

字符串很贵。他们一直都是,而且永远都是。

更新

由于它是一个独特的约束,你可以自己做一个大忙,稍微改变你的代码:

- (ThreadInfo *)retrieveSolicitationInfoForThreadID:(NSString*)inThreadID;
{
    NSString *loginUser = [[NSUserDefaults standardUserDefaults] valueForKey:@"currentUser"];

    AppDelegate *sharedDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    NSManagedObjectContext *context = [sharedDelegate managedObjectContext];
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"ThreadInfo"];
    [fetchRequest setReturnsObjectsAsFaults:NO];

    //Since there is every only one tell SQL to stop looking after one
    [fetchRequest setFetchBatchSize:1]; 

    /* Change these to your single constraint
    NSPredicate *userPredicate = [NSPredicate predicateWithFormat:@"userEmail ==   %@",loginUser];
    NSPredicate *threadPredicate = [NSPredicate predicateWithFormat:@"threadID == %@",inThreadID];
    NSPredicate *compoundPredicate = [NSCompoundPredicate andPredicateWithSubpredicates: @[userPredicate, threadPredicate]];
    [fetchRequest setPredicate:compoundPredicate];
    */

    NSError *error = nil;
    NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
    if (fetchedObjects == nil) {
        NSLog(@"Error fetching: %@\n%@", [error localizedDescription], [error userInfo]);
        abort();
    }
    return [fetchedObjects lastObject];
}

设置获取限制将导致存储停止查看第一个匹配,这将减少获取时间。将其移动到单个字符串也会缩短获取时间。

将来,在这种情况下避免使用字符串。执行整数主键的速度非常快,完全可以避免这种性能问题。

答案 1 :(得分:-1)

面对coreData和multiplyThreads等问题,您应该在相应的方法中添加以下代码:

[[NSNotificationCenter defaultCenter] addObserver: cdm.managedObjectContext selector: @selector(mergeChangesFromContextDidSaveNotification:) name:NSManagedObjectContextDidSaveNotification object: nil];

然后coreData在一个线程上更改,它将立即在另一个使用coreData的线程中更新它。

希望答案能帮到你!