2013-03-29 58 views
0

我在保存核心数据中的数据时遇到了问题。我必须通过单击按钮将多个图书信息保存在数据库中。当我点击按钮时,我调用该方法并将书籍信息保存在数据库中。对于前三次点击而言,保存图书信息是很好的,而且用户界面也具有响应能力。当我第四次点击按钮时,ui会在保存结束时冻结。核心数据冻结了多个应用程序的保存

代码如下。

+(void) storeBookInfo:(NSDictionary *) bookInfo inContext:(NSManagedObjectContext *) ctx { 

    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate]; 

    NSManagedObjectContext *tempCtx = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
    [tempCtx setPersistentStoreCoordinator:appDelegate.persistentStoreCoordinator]; 
    [tempCtx setUndoManager:nil]; 

    NSNotificationCenter *notify = [NSNotificationCenter defaultCenter]; 
    [notify addObserver:self 
       selector:@selector(mergeChanges:) 
        name:NSManagedObjectContextDidSaveNotification 
       object:tempCtx]; 

    NSFetchRequest *req = [[NSFetchRequest alloc] init]; 
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Book" inManagedObjectContext:tempCtx]; 
    [req setEntity:entity]; 

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"bid==%@", [bookInfo objectForKey:@"bid"]]; 
    [req setPredicate:predicate]; 

    [req setFetchLimit:1]; 
    [req setReturnsObjectsAsFaults:NO]; 
    NSArray *bookObjects = [tempCtx executeFetchRequest:req error:nil]; 
    if([bookObjects count] > 0){ 
     NSError *err; 
     Book *wi = [bookObjects objectAtIndex:0]; 
     wi.purchaseInfo = [NSNumber numberWithInt:[[bookInfo objectForKey:@"purchaseInfo"] intValue]]; 
     if (![tempCtx save:&err]) { 
      NSLog(@"Problem saving book info.."); 
      NSLog(@"err: %@", [err userInfo]); 
      [[NSNotificationCenter defaultCenter] removeObserver:self]; 
      [tempCtx undo]; 
      tempCtx = nil; 

     } else { 
      NSLog(@"Book saved. in if part"); 
      tempCtx = nil; 
      [[NSNotificationCenter defaultCenter] removeObserver:self]; 
     } 
    } 
    else { 

     Book *book = [NSEntityDescription insertNewObjectForEntityForName:@"Book" inManagedObjectContext:tempCtx]; 
     book.bid  = [bookInfo objectForKey:@"bid"]; 
     book.title = [bookInfo objectForKey:@"title"]; 
     book.thumbnailImgId = [bookInfo objectForKey:@"imageUrl"]; 
     book.downloadState = [NSNumber numberWithInt:0]; 
     book.pid = [bookInfo objectForKey:@"pid"]; 
     book.purchaseInfo = [NSNumber numberWithInt:[[bookInfo objectForKey:@"purchaseInfo"] intValue]]; 
     book.discription = [bookInfo objectForKey:@"desc"]; 
     NSError *err; 
     if (![tempCtx save:&err]) { 
      NSLog(@"Problem saving book ifo.."); 
      NSLog(@"err: %@", [err userInfo]); 
      [[NSNotificationCenter defaultCenter] removeObserver:self]; 
      [tempCtx undo]; 
      tempCtx = nil; 

     } else { 

      NSLog(@"Book saved."); 
      tempCtx = nil; 
      [[NSNotificationCenter defaultCenter] removeObserver:self]; 
     } 
    } 

} 

+ (void)mergeChanges:(NSNotification*)notification 
{ 
    AppDelegate *theDelegate = [[UIApplication sharedApplication] delegate]; 
    [[theDelegate managedObjectContext]   performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:) withObject:notification waitUntilDone:YES]; 

} 

我创建一个临时MOC因为代码是在后台线程,每次保存后,我发送通知。

对于第四次点击按钮应用程序获取冻结。我被困在这一点上。

回答

0

*假设:

+storeBookInfo:inContext:总是叫BG线程

使用ARC

*请注意:

self+storeBookInfo:inContext:是类本身,removeObserver:它会删除所有观察信息(您可能会错过某个时间点的合并,请考虑使用removeObserver:name:object:代替,并且不要取消tempCtx的权利远)

您正在使用:NSPrivateQueueConcurrencyType但不使用它的performBlock:performBlockAndWait:方法(考虑使用NSConfinementConcurrencyType

如果+mergeChanges:永远不会得到所谓的主线程应用程序会卡死 (考虑增加:

NSAssert(![NSThread isMainThread],@"The application will get stuck"); 

确认或修改您的合并流程 )