W naszej opracowywanej aplikacji używamy Core Data ze sklepem baz danych sqlite do przechowywania naszych danych. Model obiektowy naszej aplikacji jest złożony. Łączna ilość danych obsługiwanych przez naszą aplikację jest zbyt duża, aby zmieścić się w pakiecie aplikacji na iOS (iPhone/iPad/iPod Touch). Ze względu na to, że nasi użytkownicy są zazwyczaj zainteresowani tylko podzbiorem danych, podzieliliśmy nasze dane w taki sposób, aby aplikacja zawierała podzbiór (aczkolwiek ~ 100 MB) obiektów danych w pakiet aplikacji. Nasi użytkownicy mają możliwość pobrania dodatkowych obiektów danych (o wielkości ~ 5 MB do 100 MB) z naszego serwera po opłaceniu dodatkowej zawartości za pośrednictwem zakupów w aplikacji iTunes. Przyrostowe pliki danych (istniejące w magazynach sqlite) używają tej samej wersji xcdatamodel, co dane dostarczane z pakietem; są zerowe zmiany w modelu obiektowym. Przyrostowe pliki danych są pobierane z naszego serwera jako skompresowane pliki sqlite z gzipem. Nie chcemy powiększać pakietu aplikacji, wysyłając przyrostową zawartość do aplikacji. Ponadto nie chcemy polegać na zapytaniach dotyczących usługi sieciowej (ze względu na złożony model danych). Testowaliśmy pobieranie przyrostowych danych sqlite z naszego serwera. Mogliśmy dodać pobrany magazyn danych do współużytkowanego persistentStoreCoordinator aplikacji. Jaki jest skuteczny sposób scalania dwóch trwałych składnic danych podstawowych systemu iOS?
{
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();
}
}
}
Istnieją jednak dwa problemy robi to w ten sposób.
- wyników pobierania danych (na przykład z NSFetchResultController) wykazują z danych z incrementalStoreURL przyłączonej do końca danych z defaultStoreURL.
- Niektóre z obiektów są duplikowane. W naszym modelu danych istnieje wiele podmiotów o danych tylko do odczytu; zostaną one zduplikowane, gdy dodamy drugi obiekt persistentStore do persistentStoreCoordinator.
Idealnie chcielibyśmy, aby Core Data scalała wykresy obiektów z dwóch trwałych sklepów w jeden (nie ma wspólnych relacji między danymi z dwóch sklepów w momencie pobierania danych). Ponadto chcielibyśmy usunąć zduplikowane obiekty. Przeszukując internet, zobaczyliśmy kilka pytań od osób próbujących zrobić to samo, co robimy - takie jak this answer i this answer. Przeczytaliśmy Marcus Zarra's blog on importing large data sets in Core Data. Jednak żadne z rozwiązań, które widzieliśmy, nie działało dla nas. Nie chcemy ręcznie odczytywać i zapisywać danych z magazynu przyrostowego do domyślnego sklepu, ponieważ uważamy, że będzie to bardzo powolne i narażone na błędy w telefonie. Czy istnieje skuteczniejszy sposób na scalenie?
Próbowaliśmy rozwiązać problem, wprowadzając ręczną migrację w następujący sposób. Jednak nie udało nam się uzyskać scalenia. Nie jesteśmy do końca przekonani co do rozwiązania sugerowanego przez odpowiedzi 1 i 2, o których mowa powyżej. Blog Marcusa Zarry omówił niektóre z problemów, które mieliśmy na początku naszego projektu, importując nasz duży zestaw danych do 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();
}
}
Wydaje się, że autor odpowiedzi 1 zakończył się czytając jego dane z bieżących oszczędności do sklepu i magazynu domyślnego. Być może, źle zrozumieliśmy rozwiązanie sugerowane przez oba artykuły 1 & 2. Rozmiar naszych danych może uniemożliwić nam ręczne odczytywanie i ponowne wstawianie naszych danych przyrostowych do domyślnego sklepu. Moje pytanie brzmi: jaki jest najskuteczniejszy sposób na uzyskanie wykresów obiektów z dwóch trwałych obiektów (które mają ten sam obiekt), aby scalić się w jeden plik persistentStore?
Automatyczne migrowanie działa całkiem dobrze, gdy dodajemy nowe atrybuty encji do wykresów obiektów lub modyfikujemy relacje. Czy istnieje proste rozwiązanie polegające na łączeniu podobnych danych w ten sam trwały sklep, który będzie wystarczająco odporny na zatrzymanie i wznowienie - w miarę jak przeprowadzana jest automatyczna migracja?
Gdzie jest Marcus Zarra, kiedy go potrzebuję? Poczyniono pewne postępy przy użyciu metody [NSPersistentStore migratePersistentStore: toURL: options: withType: error]. Potrzebuję tylko kilku dodatkowych kodów, żeby dostać się tam, gdzie powinienem być. – Sunny
Walczę z tym samym. Czy możesz napisać, co do tej pory wymyśliłeś? Zgubiłem się. – damon
Gotowe! Daj mi znać, jak ci się wydaje. – Sunny