2

我有一个按钮,它将 Core Data SQLite 中的选定条目标记为“收藏夹”,这意味着我只是BOOL将该索引的一个从关闭翻转到打开。

目前,当我这样做时,我会调用,save根据managedObjectContextInstruments 的说法,这可能需要 500 毫秒,甚至更多。

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

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

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

这是我的代码:

// 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]);

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

第二个问题:save调用放在后台线程上会解决问题吗?这样做是否安全/好主意?

4

3 回答 3

11

动画,通常与 UI 有关的任何事情都在主线程上执行。如果您不希望磁盘持久性(保存过程)阻止您的 UI(主线程),您需要通过NSManagedObjectContext'initWithConcurrencyType:方法将上下文放在它自己的私有队列中。私有队列将为您处理与上下文有关的任何后台线程。这三种类型是:

NSConfinementConcurrencyType
NSPrivateQueueConcurrencyType
NSMainQueueConcurrencyType      

你会想要NSPrivateQueueConcurrencyType.

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

于 2013-04-10T10:59:16.720 回答
8

1)在主运行循环完成其循环之前,您的动画不会开始运行。这个循环不会像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)
}];

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

于 2013-04-10T11:06:21.320 回答
3

在 CIMGF.com 上查看这篇精彩的文章!;)

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

于 2013-04-10T11:04:30.673 回答