Импорт больших наборов данных на использовании iPhone CoreData

Я сталкиваюсь с очень раздражающей проблемой. Мое приложение для iPhone загружается, это - данные из сетевого сервера. Данные отправляются как plist и при парсинге это должно быть сохранено к использованию дб SQLite CoreData.

Проблема - то, что в некоторых случаях те наборы данных являются слишком большими (5000 + записи), и импорт берет слишком долго. Больше на этом, когда iPhone пытается приостановить экран, Сторожевой таймер уничтожает приложение, потому что это все еще обрабатывает импорт и не отвечает до 5 секунд, таким образом, импорт никогда не заканчивается.

Я использовал все рекомендуемые методы в соответствии со статьей "Efficiently Importing Data" http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Conceptual/CoreData/Articles/cdImporting.html и другие документы относительно этого, но это все еще ужасно медленно.

Решение, которое я ищу, состоит в том, чтобы позволить приложению приостановить, но впустить импорт, выполненный позади (лучше один) или предотвратить попытки приостановить приложение вообще. Или любая лучшая идея одобрена также.

Любые подсказки относительно того, как преодолеть эти проблемы, высоко ценятся!Спасибо

5
задан gerry3 27 January 2010 в 07:15
поделиться

7 ответов

Во-первых, если вы можете упаковать данные с приложением, которое было бы идеальным.

Тем не менее, предполагая, что вы не можете сделать это, то я бы сделал, затем следую:

  1. После того, как данные загружаются, разбите его в несколько файлов до .
  2. Импорт на фоновой резьбе, один файл за раз.
  3. После того, как файл был импортирован и сохранен, удалите файл импорта.
  4. О запуске, ищите эти файлы, ожидающие обработки и забрать, где вы остановились.

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

4
ответ дан 13 December 2019 в 19:27
поделиться

Вместо того, чтобы выталкивать файлы Plist на телефон, вы можете отправить готовые к использованию файлов SQLite. Это имеет много преимуществ:

  1. Нет необходимости импортировать на телефон
  2. более компактным

Если вы всегда заменяете весь контент, просто перезапишите постоянный магазин в устройстве. В противном случае вы можете поддерживать массив как Plist со всеми SQLites, которые вы загрузили, а затем используете это, чтобы добавить все магазины в PersiStentStoreCoordinator.

Нижняя строка: используйте несколько предложенных файлов SQLite и добавьте их в персистентно -ordinator.

Вы можете использовать симулятор iPhone, чтобы создать эти хранилища COREDATA-SQLITE или использовать автономное приложение Mac. Вам нужно будет написать обоим тем самим собой.

4
ответ дан 13 December 2019 в 19:27
поделиться

Есть ли, что вы можете упаковать данные заранее - сказать во время развития? И когда вы толкаете приложение в магазин, некоторые данные уже есть? Это сокращает количество данных, которые вы должны потянуть, тем самым помогая решить эту проблему?

Если данные - это чувствительность к времени, или не готова, или по любой причине вы не можете сделать это, не могли бы вы сжать Данные с использованием сжатия ZLIB перед отправкой его по сети?

или проблема, которую телефон умирает 5k + вставки?

0
ответ дан 13 December 2019 в 19:27
поделиться

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

Это в основном ViewControllers ViewBoadLoad

- (void)viewDidLoad 
{
    [super viewDidLoad];

    NSError *error = nil;
    if (![[self fetchedResultsController] performFetch:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }

    // Only insert those not imported, here I know it should be 2006 entries
    if ([self tableView:nil numberOfRowsInSection:0] != 2006) {

        // Put up an alert with a progress bar, need to implement
        [self createProgressionAlertWithMessage:@"Initilizing database"];  

        // Spawn the insert thread making the app still "live" so it 
        // won't be killed by the OS
        [NSThread detachNewThreadSelector:@selector(loadInitialDatabase:) 
                                 toTarget:self 
                      withObject:[NSNumber numberWithInt:[self tableView:nil 
                                                numberOfRowsInSection:0]]];
    }
}

Нить вставки была сделана подобная это

- (void)loadInitialDatabase:(NSNumber*)number
{
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    int done = [number intValue]+1; // How many done so far

    // I load from a textfile (csv) but imagine you should be able to 
    // understand the process and make it work for your data
    NSString *file = [NSString stringWithContentsOfFile:[[NSBundle mainBundle]
                                                pathForResource:@"filename"
                                                         ofType:@"txt"] 
                                               encoding:NSUTF8StringEncoding
                                                  error:nil];

    NSArray *lines = [file componentsSeparatedByString:@"\n"];

    float num = [lines count];
    float i = 0;
    int perc = 0;

    for (NSString *line in lines) {
        i += 1.0;

        if ((int)(i/(num*0.01)) != perc) {
            // This part updates the alert with a progress bar
            // setProgressValue: needs to be implemented 
            [self performSelectorOnMainThread:@selector(setProgressValue:) 
                                   withObject:[NSNumber numberWithFloat:i/num] 
                                waitUntilDone:YES]; 
            perc = (int)(i/(num*0.01));
        }

        if (done < i) // keep track of how much done previously
            [self insertFromLine:line]; // Add to data storage...

    }

    progressView = nil;
    [progressAlert dismissWithClickedButtonIndex:0 animated:YES]; 
    [pool release];
}

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

2
ответ дан 13 December 2019 в 19:27
поделиться

Я представляю, что вы не показываете все 5K записей клиенту? Я бы порекомендовал выполнять все необходимые вами агрегацию на сервере, а затем отправлять только необходимые данные на телефон. Даже если это включает в себя генерацию нескольких различных видов данных, он все еще будет закаряями быстрее, чем отправка (а затем обработка) всех этих строк на iPhone.

Вы также обрабатываете данные в отдельном (без событии / UI) потоке?

0
ответ дан 13 December 2019 в 19:27
поделиться

Есть ли шанс настроить серверную часть для предоставления веб-службы RESTful для обработки ваших данных? У меня была аналогичная проблема, и я смог предоставить свою информацию через веб-сервис RESTful. На iphone есть библиотеки, которые упрощают чтение из подобного веб-сервиса. Я решил запросить JSON у службы и использовал библиотеку SBJSON на iphone, чтобы быстро получить полученные результаты и преобразовать их в словари для удобства использования. Я использовал библиотеку ASIHTTP для создания веб-запросов и постановки в очередь последующих запросов, а также для их работы в фоновом режиме.

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

0
ответ дан 13 December 2019 в 19:27
поделиться

Давайте согласимся с тем, что Restful (ленивая загрузка) не подходит ... Я так понимаю, вы хотите повторить. Если проблема с загрузкой относится к типу «все меньше и меньше строк загружается все больше и больше времени», то в псевдокоде ...

[self sQLdropIndex(OffendingIndexName)]
[self breathInOverIP];
[self breathOutToSQLLite];
[self sQLAddIndex(OffendingIndexName)]

Это должно вам многое рассказать.

0
ответ дан 13 December 2019 в 19:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: