2010-02-03 5 views
4

Мне интересно, есть ли какие-либо рекомендации по улучшению реагирования на пользовательский интерфейс при выполнении Core Data, который сохраняет (не извлекает) большие коллекции управляемых объектов.Сохранение основных данных и производительность пользовательского интерфейса

Приложение, над которым я работаю, требует загрузки довольно больших объемов данных с установленными интервалами из веб-службы до завершения. На каждом интервале загружается пакет данных, отформатируется на управляемые объекты и сохраняется в Core Data. Поскольку этот процесс может занять до 5 минут, пока не будет полностью завершен, просто добавив экран загрузки, пока все не закончится, это не вариант, он занимает слишком много времени. Я также заинтересован в том, чтобы делать частые записи в Core Data, а не одну большую запись в конце, чтобы поддерживать низкий уровень памяти. В идеале, я бы хотел, чтобы пользователь мог продолжать использовать остальную часть приложения в обычном режиме, одновременно загружая и записывая эти большие наборы данных в Core Data.

К сожалению, похоже, что, когда я пытаюсь сохранить свои вставки, которые я помещал в контекст управляемого объекта для каждой партии, эта операция сохранения блокирует взаимодействие пользователя с остальной частью приложения (swiping tables, касание кнопок и т. д.) до завершения. За те короткие промежутки времени, когда происходит сохранение основных данных, приложение очень не отвечает.

Естественно, я попытался сделать эти сокращения меньшими, уменьшив размер отдельных партий, которые загружаются за интервал, но помимо неудобства сделать весь процесс займет больше времени, все равно будут случаи, когда пользовательский салфетки не было захвачено, потому что в это конкретное время происходило сохранение основных данных. Уменьшение размера просто делает его менее вероятным, что пропущенные салфетки или пропущенные прикосновения произойдут, но они все еще, кажется, случаются достаточно часто, чтобы быть неудобными.

Для самих вставок я попытался использовать две различные реализации: insertNewObjectForEntityForName: inManagedObjectContext, а также setValuesForKeysWithDictionary. Обе демонстрируют проблему, описанную выше.

Я пробовал прототипирование гораздо более простого теста, чтобы увидеть производительность как в симуляторе, так и на устройстве, здесь представлены важные элементы. Этот пример фактически не загружает что-либо из Интернета, а просто записывает целую кучу материала в основные данные с установленными интервалами из TableViewController. Я хотел бы знать, есть ли у кого-нибудь предложения по улучшению реагирования.

- (void)viewDidAppear:(BOOL)animated 
{ 
    [super viewDidAppear:animated]; 
    timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(doTimerWork:) userInfo:nil repeats:YES]; 
} 

-(void) doTimerWork:(id)sender 
{ 
    for (int i = 0; i < 1000; i++) 
    { 
     Misc * m = (Misc*)[NSEntityDescription insertNewObjectForEntityForName:@"Misc" inManagedObjectContext:managedObjectContext];   
     m.someDate = [NSDate date]; 
     m.someString = @"ASDASDASD"; 
     m.someOtherString = @"BLAH BLAH BLAH"; 
     m.someNumber = [NSNumber numberWithInt:5]; 
     m.someOtherNumber = [NSNumber numberWithInt:99]; 
     m.someOtherDate = [NSDate date];  
    } 

    NSError *error; 
    if (![managedObjectContext save:&error]) { 
     NSLog(@"Experienced an error while saving to CoreData"); 
    } 
} 

ответ

3

Это звучит, как вам нужно, чтобы бросить ваши данные интенсивный материал с Core Data на отдельный поток, который, к счастью, довольно легко в какао. Вы можете просто сделать:

[obj performSelectorInBackground: @selector(method:) withObject: arg]; 

А затем разработать вещи так, что когда-то, что интенсивная работа данных закончена, звоните:

[otherObject performSelectorOnMainThread: @selector(dataStuffIsDone:) withObject: arg waitUntilDone: NO]; 

В этот момент вы можете обновить UI.

Главное, чтобы помнить, чтобы всегда держать свою логику пользовательского интерфейса на главном потоке, как для правильного проектирования, и потому, что очень странные вещи могут произойти, если вы сделаете что-нибудь с UIKit из другого потока, так как он ISN» t, предназначенные для обеспечения безопасности потоков.

+0

Спасибо за отзыв, я немного колебался, чтобы посмотреть на многопоточные решения для этого, но я смог резко повысить производительность, перемещая создание управляемого объекта и сохраняя фоновый поток, как описано здесь. – beno

+2

'NSManagedObjectContext' не является потокобезопасным, и любые объекты, созданные на нем, не являются потокобезопасными. Явно небезопасно перемещать _exactly_ то, что вы делаете передним потоком, на задний план, когда речь идет о Core Data. См. Ссылку в сообщении gerry3 для получения информации о соответствующих решениях. – Tommy

6

Обычно вы загружаете свои данные в фоновый поток и вставляете/обновляете управляемые объекты в свой контекст управляемого объекта.
В основной теме вы должны зарегистрировать и принять NSManagedObjectContextWillSaveNotification и использовать mergeChangesFromContextDidSaveNotification: для обновления основного контекста управляемого объекта.

Это вы делаете?

Также читайте Multi Threading with Core-Data.

Смежные вопросы