Выполнение сохранения основных данных в фоновом потоке?

У меня есть кнопка, которая помечает выбранную запись в Core Data SQLite как "Избранное", что означает, что я просто переворачиваю BOOL для этого индекса от выключенного до включенного.

В настоящее время, когда я делаю это, я звоню save на managedObjectContext По данным Инструментов, это может занять 500 мс, а может быть, и немного больше.

У меня есть некоторый код, который выполняется в то же самое время, который запускает изящный маленький взрыв частицы ("Ура, любимый!"), Но я сталкиваюсь с проблемой, где этот взрыв задерживается до окончания save завершено.

Я не уверен, почему, так как код для запуска взрыва до 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]);

Первый вопрос: почему происходит задержка, когда я сначала вызываю код анимации в методе?

Второй вопрос: поставил бы save вызов в фоновом потоке решит проблему, и это безопасно / хорошая идея сделать это?

3 ответа

Решение

Анимации и вообще все, что связано с пользовательским интерфейсом, выполняется в основном потоке. Если вы не хотите, чтобы постоянство на диск (процесс сохранения) удерживало ваш пользовательский интерфейс (основной поток), вам нужно поместить контекст в собственную приватную очередь через NSManagedObjectContext"s initWithConcurrencyType: метод. Частная очередь будет обрабатывать любые фоновые потоки, связанные с контекстом для вас. Три типа:

NSConfinementConcurrencyType
NSPrivateQueueConcurrencyType
NSMainQueueConcurrencyType      

Вы бы хотели NSPrivateQueueConcurrencyType,

Вы можете выбрать более сложный архитектурный маршрут, используя контексты дочерних / вложенных управляемых объектов с разными типами параллелизма, но если вы новичок в Core Data, придерживайтесь одного контекста, пока не получите четкое представление о контекстах и ​​очередях.

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

Проверьте эту замечательную статью на CIMGF.com!;)

После прочтения учебника вы должны знать, как решить эту проблему.

Другие вопросы по тегам