核心数据在多次保存时冻结应用程序

时间:2013-03-29 07:49:59

标签: core-data moc

我在保存核心数据中的数据方面存在问题。我必须点击按钮在数据库中保存多个图书信息。当我点击按钮时,我调用该方法并将书籍信息保存在数据库中。对于前三次点击,可以保存书籍信息并且ui也是响应式的。当我第四次点击按钮时,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,因为代码在后台线程中,每次保存后我都会发送通知。

第四次点击按钮app冻结。我被困在这一点上。

1 个答案:

答案 0 :(得分: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");

确保或修改合并流程 )