在后台线程上执行Core Data保存?

时间:2013-04-10 10:46:13

标签: ios objective-c core-data structure nsmanagedobjectcontext

我有一个按钮,它将Core Data SQLite中的选定条目标记为“收藏夹”,这意味着我只是将该索引的BOOL从off更改为on。

目前,当我这样做时,我会在save上拨打managedObjectContext,这可能需要500毫秒,或许多一点,根据乐器。

我有一些代码同时执行,触发了一个漂亮的小粒子爆炸(“万岁,最喜欢的!”),但我遇到了一个问题,爆炸延迟到{{1}之后已完成。

我不知道为什么,因为触发爆炸的代码是在save调用之前。我是一个相对较新的程序员,所以也许我错过了一些东西,但是在这样的情况下不会逐行执行代码执行,因为爆炸会触发,然后保存会在它发生的时候发生?这里的委托调用也可能需要一些时间,但同样的问题也适用,为什么它会在这些代码行之后重要?

编辑:我是否正确地告诉主线程在下一行代码出现粒子之前被阻止,这意味着UI无法自行更新?

这是我的代码:

save

第一个问题:当我在方法中首先调用动画代码时,为什么会出现延迟?

第二个问题:会在背景线程上调用// Particle animation LikeExplosion *likeExplosionView = [[LikeExplosion alloc] initWithFrame: CGRectMake(0, 0, 320, 400)]; [likeExplosionView setUserInteractionEnabled: NO]; [self.view addSubview: likeExplosionView]; [self.view bringSubviewToFront: likeExplosionView]; [likeExplosionView decayOverTime: 1.1]; // Delegate call to reload tableview elsewhere [self.delegate detailViewControllerDidLikeLine]; // Update current object [_selectedLine setIsLiked: [NSNumber numberWithBool: YES]]; [_selectedLine setIsDisliked: [NSNumber numberWithBool: NO]]; // Update context NSError *error; if (![[[CDManager sharedManager] managedObjectContext] save:&error]) NSLog(@"Saving changes failed: %@, %@", error, [error userInfo]); 来解决问题,这样做是否安全/好主意?

3 个答案:

答案 0 :(得分:11)

动画,通常与UI有关的任何内容都在主线程上执行。如果您不希望持久化到磁盘(保存过程)来保持UI(主线程),则需要通过NSManagedObjectContext的{​​{1}}方法将上下文放在它自己的私有队列上。专用队列将处理与您的上下文有关的任何后台线程。这三种类型是:

initWithConcurrencyType:

您需要NSConfinementConcurrencyType NSPrivateQueueConcurrencyType NSMainQueueConcurrencyType

您可以通过使用具有不同并发类型的子/嵌套托管对象上下文来采用更复杂的体系结构路由,但如果您不熟悉Core Data,请坚持使用单个上下文,直到您牢牢掌握上下文和队列。 / p>

答案 1 :(得分:7)

1)在主runloop完成其循环之前,您的动画将不会开始运行。此周期无法完成,因为save:是一种阻止方法。

2)将保存移动到后台线程将解决问题,但您必须访问主线程中的主managedObjectContext,因此,您必须使用背景上下文:

NSManagedObjectContext* context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(mergeChanges:)
                                             name:NSManagedObjectContextDidSaveNotification
                                           object:context];
[context performBlock:^{
    //make changes
    NSError* error = nil;
    [context save:&error];
    //remember to remove observer after the save (in mergeChanges: and dealloc)
}];

您可以通过使用以下方法在下一个runloop中的主线程上安排保存来启动动画而不移动到后台:[self performSelectorOnMainThread:@selector(saveMain) withObject:nil waitUntilDone:NO];

答案 2 :(得分:3)

查看CIMGF.com上的this精彩文章! ;)

阅读完本教程后,您应该知道如何解决这个问题。