Как эффективно объединить два хранилища iOS Core Data Persistent Store?

В нашем разрабатываемом приложении мы используем Core Data с резервным хранилищем sqlite для хранения наших данных. Объектная модель нашего приложения сложна. Кроме того, общий объем данных, обслуживаемых нашим приложением, слишком велик, чтобы поместиться в пакет приложений для iOS (iPhone/iPad/iPod Touch). Из-за того, что наших пользователей, как правило, интересует только подмножество данных, мы разделили наши данные таким образом, что приложение поставляется с подмножеством (хотя и ~100 МБ) объектов данных в комплект приложений. Наши пользователи имеют возможность загружать дополнительные объекты данных (размером от ~ 5 МБ до 100 МБ) с нашего сервера после оплаты дополнительного содержимого через покупки в приложении iTunes. Файлы инкрементных данных (существующие в резервных хранилищах sqlite) используют ту же версию xcdatamodel, что и данные, поставляемые с пакетом; нет никаких изменений в объектной модели. Файлы инкрементных данных загружаются с нашего сервера в виде gzip-файлов sqlite. Мы не хотим раздувать наш пакет приложений, отправляя добавочное содержимое вместе с приложением. Кроме того, мы не хотим полагаться на запросы через веб-службу (из-за сложной модели данных). Мы протестировали загрузку добавочных данных sqlite с нашего сервера. Нам удалось добавить загруженное хранилище данных в общий файл persistenceStoreCoordinator приложения.

{
       NSError *error = nil;
       NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                                [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, 
                                [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

       if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:defaultStoreURL options:options error:&error])
       {            
           NSLog(@"Failed with error:  %@", [error localizedDescription]);
           abort();
       }    

       // Check for the existence of incrementalStore
       // Add incrementalStore
       if (incrementalStoreExists) {
           if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:incrementalStoreURL options:options error:&error])
           {            
               NSLog(@"Add of incrementalStore failed with error:  %@", [error localizedDescription]);
               abort();
           }    
       }
 }

Однако при таком способе возникают две проблемы.

  1. Результаты выборки данных (например, с помощью NSFetchResultController) отображаются с данные из incrementalStoreURL, добавленные в конец данные из defaultStoreURL.
  2. Некоторые объекты дублируются. Существует много субъектов с данные только для чтения в нашей модели данных; они дублируются, когда мы добавляем второй персистентсторе в персистентсторекоординатор.

В идеале мы хотели бы, чтобы Core Data объединил графы объектов из двух постоянных хранилищ в одно (между данными из двух хранилищ нет общих отношений во время загрузки данных). Кроме того, мы хотели бы удалить повторяющиеся объекты. Поискав в Интернете, мы нашли пару вопросов от людей, пытающихся сделать то же самое, что и мы, например этот ответи этот ответ. Мы читали блог Маркуса Зарры об импорте больших наборов данных в Core Data. Однако ни одно из решений, которые мы видели, не сработало для нас. Мы не хотим вручную считывать и сохранять данные из добавочного хранилища в хранилище по умолчанию, так как считаем, что это будет очень медленно и подвержено ошибкам на телефоне. Есть ли более эффективный способ слияния?

Мы попытались решить проблему, внедрив ручную миграцию следующим образом. Однако нам не удалось успешно осуществить слияние. Нам не совсем понятно решение, предложенное ответами 1 и 2, упомянутыми выше. В блоге Маркуса Зарры были рассмотрены некоторые проблемы, с которыми мы столкнулись в начале нашего проекта по импорту большого набора данных в iOS.

{
       NSError *error = nil;
       NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                                [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, 
                                [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];        

       NSMigrationManager *migrator = [[NSMigrationManager alloc] initWithSourceModel:__managedObjectModel destinationModel:__managedObjectModel];
       if (![migrator migrateStoreFromURL:stateStoreURL
                                type:NSSQLiteStoreType 
                             options:options 
                    withMappingModel:nil
                    toDestinationURL:destinationStoreURL 
                     destinationType:NSSQLiteStoreType 
                  destinationOptions:nil 
                               error:&error])
       {
           NSLog(@"%@", [error userInfo]);
           abort();
       }
}

Похоже, что автор ответа 1 в итоге прочитал свои данные из добавочного хранилища и сохранил их в хранилище по умолчанию. Возможно, мы неправильно поняли решение, предложенное в статьях 1 и 2. Размер наших данных может помешать нам вручную прочитать и повторно вставить наши добавочные данные в хранилище по умолчанию. Мой вопрос: каков наиболее эффективный способ получить графы объектов из двух постоянных магазинов (с одной и той же объектной моделью) для слияния в один постоянный магазин?

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

10
задан Community 23 May 2017 в 12:26
поделиться