Unsere App erfordert eine leichtgewichtige Kerndaten-Migration, da wir unseren Entitäten einige Attribute hinzugefügt haben.Core Data Light Weight Migration ohne beim Start getötet zu werden
Nach der Freigabe des Updates zu unseren Beta-Testern auf TestFlight hatten wir Berichte von einigen von ihnen, dass die App beim Start abstürzte. Nachdem wir die Absturzprotokolle bekommen hatten, stellten wir fest, dass der Sprungbrett-Wachhund die App kaputt machte, weil die Migration zu lange dauerte.
Nach der Online-Suche nach Ressourcen scheint es möglich zu sein, die Migration außerhalb von application:didFinishLaunchingWithOptions:
zu verschieben, indem zunächst überprüft wird, ob eine Migration erforderlich ist, der Core Data-Stack nicht berührt wird und die Migration in einem anderen View-Controller ausgeführt wird . Hier ist das, was ich zu tun versucht:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if ([[ZSSCoreDataManager sharedService] migrationRequired]) {
UpgradeDatabaseViewController *upgrade = [self.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:@"UpgradeDatabaseViewController"];
self.window.rootViewController = upgrade;
}
return YES;
}
Migration Test:
- (BOOL)migrationRequired {
NSManagedObjectModel *mom = [NSManagedObjectModel mergedModelFromBundles:nil];
NSPersistentStoreCoordinator *persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
NSError *error = nil;
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"CoreDataMergeTest.sqlite"];
// Determine if a migration is needed
NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType URL:storeURL options:nil error:&error];
NSManagedObjectModel *destinationModel = [persistentStoreCoordinator managedObjectModel];
BOOL pscCompatibile = [destinationModel isConfiguration:nil compatibleWithStoreMetadata:sourceMetadata];
return !pscCompatibile;
}
UpgradeDatabaseViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"Starting migration");
// Start migration by accessing th epersistent container
[[ZSSCoreDataManager sharedService] persistentContainer];
NSLog(@"Ended migration");
UIWindow *window = [UIApplication sharedApplication].keyWindow;
UINavigationController *nav = [self.storyboard instantiateViewControllerWithIdentifier:@"MainNav"];
window.rootViewController = nav;
}
Persistent Container:
- (NSPersistentContainer *)persistentContainer {
@synchronized (self) {
if (_persistentContainer != nil) {
return _persistentContainer;
}
_persistentContainer = [[NSPersistentContainer alloc] initWithName:@"Model"];
// Store description
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"CoreDataMergeTest.sqlite"];
NSPersistentStoreDescription *description = [NSPersistentStoreDescription persistentStoreDescriptionWithURL:storeURL];
description.shouldInferMappingModelAutomatically = YES;
description.shouldMigrateStoreAutomatically = YES;
description.type = NSSQLiteStoreType;
_persistentContainer.persistentStoreDescriptions = @[description];
[_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error){
if (error != nil) {
NSLog(@"Unresolved error %@, %@", error, error.userInfo);
//abort();
}
}];
_persistentContainer.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
_persistentContainer.viewContext.undoManager = nil; // We don't need undo so set it to nil.
_persistentContainer.viewContext.shouldDeleteInaccessibleFaults = YES;
_persistentContainer.viewContext.automaticallyMergesChangesFromParent = YES;
}
return _persistentContainer;
}
Leider noch diese doesn schein die iss zu lösen Da das Sprungbrett die App immer noch auslöst (wenn das Gerät nicht angeschlossen ist und der Debugger läuft).
Gibt es hier etwas, was ich falsch gemacht habe? Erfolgt die Lightweight-Migration in application:didFinishLaunchingWithOptions:
unabhängig davon, ob wir unsere Datenbank nicht initiieren?
Ist es sogar möglich, das zu tun, was ich bei der Verwendung der Lightweight-Migration tun möchte?
Ich habe meine Frage aktualisiert, um zu zeigen, wie mein 'NSPersistentContainer' erstellt wird. Das ist alles, was ich benutze, um meinen "Core Data" Stack zu initialisieren, da unsere App iOS 10 ist. Wollen Sie damit sagen, dass ich mein 'NSPersistentContainer' Objekt in einer Hintergrundwarteschlange erstellen könnte? –
Ich kann den Absturz, den meine Benutzer haben, reproduzieren. Ein Benutzer hat mir ihre .sqlite Datei zur Verfügung gestellt. Ich habe den Absturz nie gesehen, seit mein Gerät mit dem Debugger verbunden war und der Watchdog-Prozess nicht läuft. –
@NicHubbard Meine Antwort enthält bereits Details darüber, wie und wann Sie Ihren persistenten Container einrichten sollten. Gibt es etwas Bestimmtes, das nicht klar ist? –