2014-09-06 9 views
11


Ho già un'app in App Store che utilizza i dati principali per il salvataggio dei dati.
Ora, quando iOS 8 sta per uscire, voglio aggiungere un widget ad esso, quindi devo usare App Groups per condividere i dati tra i binari.
Un problema però - ho bisogno di cambiare la posizione del negozio per supportare i gruppi di app a tutti gli utenti esistenti.
ho scritto il seguente codice, cercando di spostare il negozio per il nuovo percorso:Aggiorna posizione di archiviazione dei dati principali per supportare gruppi di app

// Returns the persistent store coordinator for the application. 
// If the coordinator doesn't already exist, it is created and the application's store added to it. 
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator 
{ 
    if (_persistentStoreCoordinator != nil) { 
     return _persistentStoreCoordinator; 
    } 

    NSURL *oldStoreURL = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; 
    oldStoreURL = [oldStoreURL URLByAppendingPathComponent:@"Schooler.sqlite"]; 


    NSURL *storeURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.com.schooler.mycontainer"]; 
    storeURL = [storeURL URLByAppendingPathComponent:@"Schooler.sqlite"]; 


    if([[NSFileManager defaultManager] fileExistsAtPath:oldStoreURL.path] == YES && [[NSFileManager defaultManager] fileExistsAtPath:storeURL.path] == NO) 
    { 
     // Prior today extension - Need to move to new directory 
     NSError *error = nil; 
     if([[NSFileManager defaultManager] moveItemAtURL:oldStoreURL toURL:storeURL error:&error] == YES) 
      NSLog(@"Migrated successfully to new database location."); 
     else 
      NSLog(@"error: %@",error); 
    } 

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

    NSError *error = nil; 
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; 
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) { 
     NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
    } 

    return _persistentStoreCoordinator; 
} 

L'uscita è sempre "con successo la migrazione al nuovo percorso del database.", Anche se tutti i dati salvati sul app prima è stato cancellato, come se avesse creato un nuovo database invece di spostarlo.

Quali sono le cause del problema? Come dovrei risolverlo?
Grazie.

+0

Si prega di verificare sotto il post per una soluzione in swift. https://stackoverflow.com/questions/27253566/coredata-move-to-app-group-target/47551887#47551887 –

risposta

16

Un archivio dati NSSQLiteStoreType di base creato con le opzioni predefinite è in realtà diversi file, come descritto in Technical Q&A 1809: New default journaling mode for Core Data SQLite stores in iOS 7 and OS X Mavericks. È importante ricordare quando si tenta di spostare un negozio all'esterno di di un processo di migrazione ed è la fonte del problema: si sta spostando un file quando è necessario spostarli tutti. Tuttavia, non è consigliabile spostare i file singolarmente al di fuori dei Core Data e senza i vantaggi di un coordinatore di file. È molto meglio usare invece una migrazione.

Una migrazione preleverà i dati dall'archivio di origine e li migrerà nella posizione del nuovo negozio, essenzialmente replicando i vecchi dati nella nuova posizione. I vecchi dati continueranno a esistere sul filesystem. Nella tua applicazione, dovresti eseguire la migrazione come sei ora, ma non tentare di spostare da te i vecchi dati nella nuova posizione - è lì che le cose vanno male.

Invece di spostare i file intorno a te, puoi fare affidamento su una migrazione per spostare i dati per te. Innanzitutto, aggiungi un negozio al coordinatore del negozio permanente con l'URL dei dati di origine. Poi si eseguire una migrazione per spostare i dati al nuovo URL

NSPersistentStore *sourceStore  = nil; 
NSPersistentStore *destinationStore = nil; 
NSDictionary  *storeOptions  = @{ NSSQLitePragmasOption : @{ @"journal_mode" : 
    @"WAL" } }; 

// Add the source store 
if (![coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:oldStoreURL options:storeOptions error:&error]){ 
    // Handle the error 
} else { 
    sourceStore = [coordinator persistentStoreForURL:oldStoreURL]; 
    if (sourceStore != nil){ 
     // Perform the migration 
     destinationStore = [coordinator migratePersistentStore:sourceStore toURL:storeURL options:storeOptions withType:NSSQLiteStoreType error:&error]; 
     if (destinationStore == nil){ 
      // Handle the migration error 
     } else { 
      // You can now remove the old data at oldStoreURL 
      // Note that you should do this using the NSFileCoordinator/NSFilePresenter APIs, and you should remove the other files 
      // described in QA1809 as well. 
     } 
    } 
} 

Una volta che la migrazione è stata completata è possibile eliminare i vecchi file. L'esempio qui specifica esplicitamente le opzioni del journal SQLite, questo per garantire che se le opzioni predefinite vengano modificate in futuro il codice funzionerà ancora. Se stai usando opzioni diverse, dovresti usare quelle.

+0

Grazie mille per avermi aiutato! –

+0

Nessun problema Noam, felice di poterti aiutare. Buona fortuna con la tua estensione e app! – quellish

+1

Per eliminare i file rimanenti, è preferibile utilizzare removeItemAtURL di NSFileManager: https: //developer.apple.com/library/mac/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/ManagingFIlesandDirectories/ManagingFIlesandDirectories.html#//apple_ref/doc/uid/TP40010672 -CH6-SW11. Perché raccomandi NSFileCoordinator/NSFilePresenter? –

Problemi correlati