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,因为代码在后台线程中,每次保存后我都会发送通知。

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

4

1 回答 1

0

*假设:

+storeBookInfo:inContext:总是在 BG 线程中调用

使用 ARC

*请注意:

selfin+storeBookInfo:inContext:是类本身,removeObserver:它将删除所有观察信息(您可能会错过某些时间的合并,请考虑removeObserver:name:object:改用,而不是立即使 tempCtx 无效)

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

如果+mergeChanges:将在主线程上调用您的应用程序将卡住(考虑添加:

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

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

于 2013-03-30T18:18:38.830 回答