Mam projekt iOS z dużą, wstępnie załadowaną bazą danych i małą bazą danych użytkowników (oba bazy danych SQLite CoreData). Poprzednie pytania sugerują stosowanie konfiguracji do kontrolowania, które jednostki są używane w danym sklepie. Mam problem z tym, żeby to zadziałało. Oto, co starałem ...CoreData z wieloma sklepami: problemy konfiguracyjne
- (NSManagedObjectModel *)managedObjectModel
{
if (_managedObjectModel != nil) return _managedObjectModel;
// set up the model for the preloaded data
NSURL *itemURL = [[NSBundle mainBundle] URLForResource:@"FlagDB" withExtension:@"momd"];
NSManagedObjectModel *itemModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:itemURL];
// set up the model for the user data
NSURL *userDataURL = [[NSBundle mainBundle] URLForResource:@"UserData" withExtension:@"momd"];
NSManagedObjectModel *userDataModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:userDataURL];
// merge the models
_managedObjectModel = [NSManagedObjectModel modelByMergingModels:[NSArray arrayWithObjects:itemModel, userDataModel, nil]];
// define configurations based on what was in each model
WRONG [_managedObjectModel setEntities:itemModel.entities forConfiguration:@"ItemData"];
WRONG [_managedObjectModel setEntities:userDataModel.entities forConfiguration:@"UserData"];
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) return _persistentStoreCoordinator;
// preloaded data is inside the bundle
NSURL *itemURL = [[[NSBundle mainBundle] bundleURL] URLByAppendingPathComponent:@"FlagDB.sqlite"];
// user data is in the application directory
NSURL *userDataURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"UserData.sqlite"];
NSManagedObjectModel *mom = self.managedObjectModel;
NSError *error = nil;
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
if (![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:@"ItemData" URL:itemURL options:nil error:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
...
ten przerywa z „Model używany do otwarcia sklepu jest niezgodna z użytej do stworzenia sklepu”. Sprawdzanie skrótów w modelu w odniesieniu do skrótów w sklepie wskazuje, że są one identyczne dla elementów znajdujących się w konfiguracji ItemData.
Gdy próbuję robić lekkie migracji, tak jak poniżej:
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
if (![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:@"ItemData" URL:itemURL options:options error:&error])
To nie z '', NSInvalidArgumentException powodu: ' '' model nie zawiera konfigurację' itemData Zakładam, że dzieje się tak dlatego, że w procesie migracji jest tworzony nowy model i nie zawiera on mojej konfiguracji.
Na podstawie kilku sugestii z innych wątków próbowałem wykonać niewielką migrację bez konfiguracji, a następnie utworzyć nowego koordynatora za pomocą konfiguracji. Ten rodzaj prac, ale dodaje tabele do wstępnie załadowanego pliku .sqlite odpowiadającego encji danych użytkownika (które nie należą do niego) i tworzy zarówno wstępnie załadowane tabele danych, jak i tabele danych użytkowników w nowo utworzonym magazynie danych użytkownika . Wynik końcowy jest taki, że pobieranie kończy się niepowodzeniem, pozornie dlatego, że szukają w niewłaściwym sklepie.
NSDictionary *migrationOptions = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
// make a temp persistent store coordinator to handle the migration
NSPersistentStoreCoordinator *tempPsc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
// migrate the stores
if (![tempPsc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:itemURL options:migrationOptions error:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
if (![tempPsc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:userDataURL options:migrationOptions error:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
// make a permanent store coordinator
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
NSDictionary *readOnlyOptions = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSReadOnlyPersistentStoreOption, nil];
if (![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:@"ItemData" URL:itemURL options:readOnlyOptions error:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
/*if (![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:@"UserData" URL:userDataURL options:nil error:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}*/
A potem ...
OSAppDelegate *delegate = [UIApplication sharedApplication].delegate;
NSManagedObjectContext *context = delegate.managedObjectContext;
// sanity check
for (NSPersistentStore *store in context.persistentStoreCoordinator.persistentStores) {
NSLog(@"store %@ -> %@", store.configurationName, store.URL);
NSMutableArray *entityNames = [[NSMutableArray alloc] init];
for (NSEntityDescription *entity in [context.persistentStoreCoordinator.managedObjectModel entitiesForConfiguration:store.configurationName]) {
[entityNames addObject:entity.name];
}
NSLog(@"entities: %@", entityNames);
}
NSFetchRequest *categoryFetchRequest = [[NSFetchRequest alloc] init];
categoryFetchRequest.entity = [NSEntityDescription entityForName:@"Category" inManagedObjectContext:context];
categoryFetchRequest.predicate = [NSPredicate predicateWithFormat:@"name == %@", categoryName];
NSError *error = nil;
Category *category = [[delegate.managedObjectContext executeFetchRequest:categoryFetchRequest error:&error] lastObject];
Działa to dobrze, wracając odpowiednio nazwany kategorię obiektu, aż odkomentowaniu dodanie drugiego sklepu. Jeśli to zrobię, wynik pobierania wróci pusta. Diagnostyczne komunikaty NSLog drukują dokładnie to, czego się spodziewam. Każdy sklep jest powiązany z poprawną konfiguracją, a każda konfiguracja ma odpowiednie elementy.
Czy ktoś może wskazać mi kod źródłowy do konfiguracji wielu sklepów lub wskazać, co robię źle? Z góry dziękuję!
SOLVED: Sedno problemu były dwie linie oznaczone źle w pierwszej listingu. Próbowałem programowo tworzyć konfiguracje, ale wydaje się to niewystarczające. Jeśli wyszukujesz ManagedObjectModel dla konfiguracji po wykonaniu tej czynności, rzeczywiście widzisz konfiguracje na liście i poprawne encje są powiązane z tymi konfiguracjami. Wydaje się jednak, że należy zrobić coś jeszcze, aby narzędzie PersistentStoreCoordinator mogło właściwie z nich korzystać. Utworzenie konfiguracji w Xcode sprawia, że działają.
FOLLOW UP: Jest dodatkowy szkopuł. Rozwiązanie polegające na uruchomieniu oddzielnego przejścia migracji przed skonfigurowaniem ostatecznego Koordynatora magazynu trwałego działa świetnie ... w symulatorze. Na rzeczywistym urządzeniu uprawnienia są bardziej rygorystyczne. Jeśli spróbujesz przeprowadzić tę migrację, nie powiedzie się, ponieważ magazyn w pakiecie aplikacji jest tylko do odczytu. Migracja wydaje się konieczna, chyba że skonsolidujesz swoje modele. Jeśli masz tylko jeden model, a sklep w pakiecie aplikacji jest z nim kompatybilny, migracja nie jest konieczna i możliwy jest dostęp przy użyciu konfiguracji zdefiniowanych w Xcode.
Inną opcją może być przeniesienie danych do katalogu Dokumenty przed przystąpieniem do migracji. Nie sprawdziłem, czy to podejście działa.
Upewnij się, że wykonujesz migrację w katalogu dokumentów użytkownika piaskownicy - który jest przeznaczony do odczytu/zapisu - a nie w samym pakiecie aplikacji. – Sunny
Nie chciałem przenosić danych do katalogu dokumentów, ponieważ nie chcę, aby te (statyczne) dane były archiwizowane i liczone względem przydziału iCloud użytkownika. Ale wygląda na to, że w iOS 5.0.1 istnieje sposób oznaczania plików, których nie można kopiować: http://developer.apple.com/library/ios/#qa/qa1719/_index.html – Aneel
Cóż, zainspirowałeś mnie i po spędzeniu kilku godzin na rozwiązaniu mojego problemu napisałem pełny artykuł na ten temat [tutaj] (http://blog.atwam.com/blog/2012/05/11/multiple-persistent-stores-and-seed-data -with-core-data /). Pomyślałem, że może pomóc innym ludziom w przyszłości. – Wam