2017-10-20 204 views
2

我們的應用需要核心數據輕量級遷移,因爲我們已向實體添加了一些屬性。核心數據輕量級遷移不會在發佈時遇難

在TestFlight上發佈更新給我們的beta測試者後,我們從其中一些人那裏報告說應用程序在啓動時崩潰了。得到崩潰日誌後,我們意識到跳板看門狗正在殺死該應用程序,因爲遷移時間過長。

在網上淘資源後,似乎可以通過首先檢查是否需要遷移,不接觸核心數據堆棧並選擇在另一個視圖控制器中執行遷移來卸載application:didFinishLaunchingWithOptions:之外的遷移。這裏是我想要做的事:

- (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; 

} 

遷移測試:

- (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; 

} 

持續容器:

- (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; 

} 

可悲的是,這仍然沒有按似乎沒有解決問題因爲跳板仍然會殺死應用程序(當設備未插入並且調試器正在運行時)。

這裏有什麼我做錯了嗎?不管我們是否不啓動我們的數據庫,輕量級遷移是否發生在application:didFinishLaunchingWithOptions:中?

在使用輕量級遷移時,甚至可以做我想做的事情嗎?

回答

1

加載持久性存儲時發生遷移。使用NSPersistentContainer時,只要您致電loadPersistentStores()就會發生。在你的代碼中,它看起來像是在ZSSCoreDataManagerpersistentContainer方法中。

你做這個這不是什麼方法,就是隊列你調用它的問題。如果您長時間阻止主隊列,看門狗會殺死您的應用程序。當你這樣做時,你的應用程序已停止響應。看門狗無法分辨出爲什麼會發生這種情況,它所強制執行的規則是將其視爲一個掛起的過程並將其殺死。這通常是一個好主意,因爲它只發生在你的應用一直坐在那裏忽略用戶輸入很長一段時間。如果您在viewDidLoad中處理遷移,那麼您處於主隊列中,這就是您的應用被殺的原因。

我不確定這是否可以用NSPersistentContainer修復。該課程旨在處理最常見的情況,但你似乎超出了這個範疇。在過去我所做的是使用NSPersistentStoreCoordinator加載持久存儲在後臺隊列上,然後創建任何我需要的託管對象上下文。您可能首先使用NSPersistentStoreCoordinator來處理遷移,然後在完成時加載NSPersistentContainer

解決這個問題將部分取決於您是否可以重現崩潰。如果你現在無法做到這一點,那可能是第一步 - 到達與用戶相同的崩潰位置,這樣你就可以知道崩潰的時間是否已修復。

+0

我已更新我的問題以顯示如何創建我的'NSPersistentContainer'。這就是我用來初始化我的Core Data堆棧,因爲我們的應用程序是iOS 10.您是否說我可以在後臺隊列上創建我的'NSPersistentContainer'對象? –

+0

我能夠重現我的用戶擁有的崩潰。用戶向我提供了他們的.sqlite文件。自從我的設備連接到調試器並且看門狗進程沒有運行以來,我從未看到過崩潰。 –

+0

@NicHubbard我的答案已經涵蓋了如何以及何時應該設置持久容器的細節。有沒有關於它的具體內容尚不清楚? –