Настройте NSFetchedResultsController в фоновом режиме при запуске приложения Core Data.

Я настроил приложение Core Data с обычным шаблонным кодом, и RootViewController инициализирует FRC, вызвав это:

- (NSFetchedResultsController *)fetchedResultsController 
{
    if (__fetchedResultsController != nil) 
    {
        return __fetchedResultsController;
    }
    // configure the fetchRequest, sectionKey and cacheName
    __fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest: fetchRequest 
                                                                    managedObjectContext: self.managedObjectContext 
                                                                      sectionNameKeyPath: sectionKey 
                                                                               cacheName: cacheName];
    return __fetchedResultsController;
}

Весь пример кода, который я видел, делает это. Однако у меня большой набор данных и более 15 000 записей, поэтому запуск приложения на iPhone 4S занимает около 5 секунд. Это с включенным кешированием (без него это занимает 11 секунд) и с проиндексированными атрибутами.

Итак, я хочу иметь возможность показать UIActivityIndicatorView, которое приложение ожидает загрузки. Я знаю, как обычно загружать основные объекты данных в фоновом потоке, а затем объединять их обратно в основной поток, но как я могу инициализировать FRC в фоновом потоке, чтобы все объекты загружались и секционировались в фоновом режиме?

Я знаю, что могу загрузить все объекты и разделить их в фоновом потоке в пользовательский словарь и использовать его для представления данных, но я бы предпочел использовать стандартные вызовы и делегаты FRC.

Спасибо.


person Z S    schedule 06.06.2012    source источник


Ответы (2)


Я не совсем уверен, что вы имеете в виду под использованием NSFetchedResultsController в фоновом режиме, но, исходя из моего опыта, вы можете просто установить размер пакета для вашего запроса на выборку, например:

[fetchRequest setFetchBatchSize:20];

Таким образом, при запуске загружаются первые 20 элементов, при прокрутке следующие 20 и так далее. Кроме того, вы можете просто выбрать свойства для извлечения с помощью - (void)setPropertiesToFetch:(NSArray *)values.

Другой способ - иметь (фоновую) задачу, которая начинает извлекать объекты в фоновом режиме. Я думаю, что при извлечении в фоновом режиме объекты каким-то образом кэшируются (но я не совсем уверен), и поэтому вы можете быстрее получить к ним доступ из основного потока.

Надеюсь, поможет.

person Lorenzo B    schedule 06.06.2012
comment
fetchBatchSize немного помогает, но не решает мою проблему (она уже есть в моем коде). Мне нужен секционированный UITableView с индексами сбоку. Я полагаюсь на FRC для расчета этих разделов, поэтому независимо от того, какой размер пакета я ему даю, он должен прочитать все строки из базы данных, найти их разделы и поместить объекты в правильное ведро. Теперь выполнение этого в основном потоке останавливает поток на 5 секунд после запуска приложения, что, очевидно, не очень хорошо. - person Z S; 06.06.2012
comment
Для больших наборов данных (iOS 5) извлекаются все данные, если у вас установлен sectionNamekeyPath независимо от размера пакета. - person Neil; 09.06.2012
comment
@Neil Извините, но где вы нашли эту ссылку? - person Lorenzo B; 09.06.2012
comment
Это действительно очень помогло мне. 1 Голосуйте за это. - person Ansari; 18.01.2013
comment
Одним из решений для sectionNameKeyPath является денормализация данных, как предложил Бен Блейкли: cimgf.com/2013/01/03/ - person chadbag; 30.04.2014

Я думаю, что понял это... вы МОЖЕТЕ создать FRC в фоновом потоке и выполнить выборку в основном потоке:

- (NSFetchedResultsController *)fetchedResultsController 
{
    if (__fetchedResultsController != nil) 
    {
        return __fetchedResultsController;
    }

    // create something to pass back to the first time FRC is initialized without fetching
    __block NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
    aFetchedResultsController.delegate = self;
    [self.list_spinner startAnimating];

    dispatch_async(self.filterMainQueue, ^{

           NSFetchedResultsController *newFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest: fetchRequest 
                                                                                                         managedObjectContext: self.managedObjectContext 
                                                                                                           sectionNameKeyPath: sectionKey 
                                                                                                                    cacheName: cacheName];
           dispatch_async(dispatch_get_main_queue(), ^{ 
               // stop the spinner here
               [self.list_spinner stopAnimating];

               NSError *error = nil;
               if (![newFetchedResultsController performFetch:&error]) 
               {
                   NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
                   [SimpleListAppDelegate showCoreDataError: @"SimpleListViewController - FRC"];
               }
               __fetchedResultsController = nil;
               newFetchedResultsController.delegate = self;
               __fetchedResultsController = newFetchedResultsController;
               [self.tableView reloadData];
           });
         });

    return aFetchedResultsController;
}
person Z S    schedule 07.06.2012
comment
Я новичок в концепции потоков. Но я слышал, что NSOperationQueue может быть лучшей альтернативой NSThread. Проект, над которым я сейчас работаю, использует очереди операций. Это действительно отлично работает, создавая асинхронные операции. - person hp iOS Coder; 08.06.2012
comment
NSOperationQueue лучше, чем использование NSThreads, но использование GCD (из которого происходит dispatch_async) еще лучше. Я бы посоветовал вам ознакомиться с фреймворком GCD, так как Apple будет все больше и больше полагаться на него в будущем. - person Z S; 09.06.2012
comment
Большое спасибо, друг, за эту важную информацию. Но снова мой вопрос: почему Apple все больше и больше будет полагаться на платформу GCD? Какая-то конкретная причина? - person hp iOS Coder; 09.06.2012
comment
Потому что а) более эффективно, так как система не создает потоки каждый раз, она разделяет пул потоков, которым она управляет сама, и б) разработчикам проще использовать, чем использовать NSThreads напрямую (как только вы разберетесь с этим ). - person Z S; 10.06.2012
comment
В каком потоке вы создали self.managedObjectContext? Вы используете его в другом потоке, это плохая идея. - person adnako; 06.11.2013