我有一个按钮,它将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]);
来解决问题,这样做是否安全/好主意?
答案 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精彩文章! ;)
阅读完本教程后,您应该知道如何解决这个问题。