2012-12-28 1 views
14

Ho un'app che sta utilizzando MagicalRecord per la sua gestione dei dati di base e questo funziona bene. Tuttavia, ho diversi utenti che possono accedere all'app e quando un altro utente effettua l'accesso, il database dei dati di base deve essere svuotato in modo che il diverso utente possa avere i propri dati. Il database può essere svuotato completamente poiché i dati vengono anche memorizzati su un servizio web e quindi possono sempre essere sincronizzati di nuovo dopo aver effettuato nuovamente il login al primo utente.Pulire (rimuovere) un database in MagicalRecord

Finora non riesco a trovare un metodo di supporto (che funzioni) per questo scopo. Ho provato

[MagicalRecord cleanUp]; 

ogni volta che l'utente si disconnette, ma questo non fa il trucco.

+2

non so se magico ha qualcosa da gestire questo. Devi aspettare l'autore per questo. Ad ogni modo, potresti semplicemente bypassarlo rimuovendo il file db creato e inizializzando di nuovo lo stack tramite MagicalRecord. Forse potresti aprire una richiesta di pull (è necessario un account GitHub) nel progetto MagicalRecord. –

risposta

17

MagicalRecord non fornisce questa funzionalità. Il metodo cleanUp viene fornito per reinizializzare lo stack CoreData in memoria e pulire tutti i contesti, le code e altri oggetti correlati. Tuttavia, non è così difficile da fare da te dato che MagicalRecord fornisce un metodo pratico per ottenere il percorso per la tua biblioteca.

Controllare il metodo -[NSPersistentStore MR_urlForStoreName:]. Questo ti darà l'url del file per il tuo negozio. È quindi possibile eliminarlo con un'istanza NSFileManager. Fai attenzione a fare questo prima di impostare lo stack dei Core Data o ti romperà quando salvi perché avresti strappato lo store da uno stack correttamente inizializzato.

+0

se vedi il mio commento ho suggerito la stessa cosa ;-) +1 per la tua spiegazione più profonda –

+0

Il tuo suggerimento per una richiesta pull o un problema sul repository è il benvenuto :) – casademora

+0

Ho appena inserito un nuovo problema su GitHub. Saluti. –

36

Ecco come l'ho fatto. È essenziale avere questa linea: [MagicalRecord cleanup]. Senza di esso, [self setupDB] non funzionerà.

AGGIORNAMENTO: Elimina i file -wal e -shm. @thattyson ha segnalato un problema in iOS 9. Inoltre, vedere answer of @onmyway133.

- (void)setupDB 
{ 
    [MagicalRecord setupCoreDataStackWithAutoMigratingSqliteStoreNamed:[self dbStore]]; 
} 

- (NSString *)dbStore 
{ 
    NSString *bundleID = (NSString *)[[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleIdentifierKey]; 
    return [NSString stringWithFormat:@"%@.sqlite", bundleID]; 
} 

- (void)cleanAndResetupDB 
{ 
    NSString *dbStore = [self dbStore]; 

    NSError *error1 = nil; 
    NSError *error2 = nil; 
    NSError *error3 = nil; 

    NSURL *storeURL = [NSPersistentStore MR_urlForStoreName:dbStore]; 
    NSURL *walURL = [[storeURL URLByDeletingPathExtension] URLByAppendingPathExtension:@"sqlite-wal"]; 
    NSURL *shmURL = [[storeURL URLByDeletingPathExtension] URLByAppendingPathExtension:@"sqlite-shm"]; 

    [MagicalRecord cleanUp]; 

    if([[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error1] && [[NSFileManager defaultManager] removeItemAtURL:walURL error:&error2] && [[NSFileManager defaultManager] removeItemAtURL:shmURL error:&error3]){ 
     [self setupDB]; 
    } 
    else{ 
     NSLog(@"An error has occurred while deleting %@", dbStore); 
     NSLog(@"Error1 description: %@", error1.description); 
     NSLog(@"Error2 description: %@", error2.description); 
     NSLog(@"Error3 description: %@", error3.description); 
    } 
} 

Ecco la versione Swift:

func setupDB() { 
    MagicalRecord.setupCoreDataStackWithAutoMigratingSqliteStoreNamed(self.dbStore()) 
} 

func dbStore() -> String { 
    return "\(self.bundleID()).sqlite" 
} 

func bundleID() -> String { 
    return NSBundle.mainBundle().bundleIdentifier! 
} 

func cleanAndResetupDB() { 
    let dbStore = self.dbStore() 

    let url = NSPersistentStore.MR_urlForStoreName(dbStore) 
    let walURL = url.URLByDeletingPathExtension?.URLByAppendingPathExtension("sqlite-wal") 
    let shmURL = url.URLByDeletingPathExtension?.URLByAppendingPathExtension("sqlite-shm") 

    var removeError: NSError? 

    MagicalRecord.cleanUp() 

    //Swift 1 
    //let deleteSuccess = NSFileManager.defaultManager().removeItemAtURL(url, error: &removeError) 

    //Swift 2 
    let deleteSuccess: Bool 
    do { 
     try NSFileManager.defaultManager().removeItemAtURL(url) 
     try NSFileManager.defaultManager().removeItemAtURL(walURL!) 
     try NSFileManager.defaultManager().removeItemAtURL(shmURL!) 
     deleteSuccess = true 
    } catch let error as NSError { 
     removeError = error 
     deleteSuccess = false 
    } 

    if deleteSuccess { 
     self.setupDB() 
    } else { 
     println("An error has occured while deleting \(dbStore)") 
     println("Error description: \(removeError?.description)") 
    } 
} 
+3

ma che dire dei file -shm e -wal? Quelli non vengono cancellati in questo modo, giusto? – swalkner

+1

Non funziona per me. Ricevo il seguente errore: "Impossibile completare l'operazione. Nessun file o directory" – Szu

+0

A partire da iOS9 se non si eliminano i file -shm e -wal l'app si bloccherà con l'errore 'Codice errore SQLite: 522 'dopo aver provato a configurare il DB una seconda volta. – thattyson

2

Se si utilizza il simulatore iOS e cancellato il file di database, si può probabilmente notare che i dati sono ancora lì. Tuttavia, se testato su un dispositivo reale (che dovrebbe essere), il file viene eliminato e il contesto viene ripristinato come dovrebbe essere.

[MagicalRecord cleanUp]; 

// delete database file 
NSError *error; 
NSURL *fileURL = [NSPersistentStore MR_urlForStoreName:@"db.sqlite"]; 
[[NSFileManager defaultManager] removeItemAtURL:fileURL error:&error]; 
if(error) { 
    // Hanldle error 
} 

// reset setup. 
[MagicalRecord setupCoreDataStackWithAutoMigratingSqliteStoreNamed:@"db.sqlite"]; 
+0

in iOS 9 dopo averlo fatto, e quindi facendo l'arresto anomalo dell'app, il DB si perde. –

5

Quanto segue cancellare completamente i file SQLite MagicalRecord CoreData, così come i file -wal e -shm. MagicalRecord li mette tutti nella cartella Libreria; questo semplicemente rimuoverà tutti i file dalla cartella. Questo non funzionerà se si dispone di altri dati necessari a persistere nella cartella Libreria, non l'ho fatto:

- (void)resetCoreDataDB 
{ 
    [MagicalRecord cleanUp]; 
    [self deleteFilesInLibrary]; 
    [MagicalRecord setupCoreDataStackWithAutoMigratingSqliteStoreNamed:@"YourDBName.sqlite"]; 
} 

- (void)deleteFilesInLibraryDirectory 
{ 
    NSString* folderPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0]; 
    NSError *error = nil; 
    for (NSString *file in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:folderPath error:&error]) 
    { 
     [[NSFileManager defaultManager] removeItemAtPath:[folderPath stringByAppendingPathComponent:file] error:&error]; 
     if(error) 
     { 
      NSLog(@"Delete error: %@", error.description); 
     } 
    } 
} 
20

Per espandere sulla risposta di' @yoninja, questo renderà ripristinare pila CoreData esplicitamente, oltre a trattare con wal e file SHM

- (void)setupDB 
{ 
    [MagicalRecord setDefaultModelNamed:@"Model.momd"]; 
    [MagicalRecord setupCoreDataStack]; 
} 

- (void)cleanAndResetupDB 
{ 
    [MagicalRecord cleanUp]; 

    NSString *dbStore = [MagicalRecord defaultStoreName]; 

    NSURL *storeURL = [NSPersistentStore MR_urlForStoreName:dbStore]; 
    NSURL *walURL = [[storeURL URLByDeletingPathExtension] URLByAppendingPathExtension:@"sqlite-wal"]; 
    NSURL *shmURL = [[storeURL URLByDeletingPathExtension] URLByAppendingPathExtension:@"sqlite-shm"]; 

    NSError *error = nil; 
    BOOL result = YES; 

    for (NSURL *url in @[storeURL, walURL, shmURL]) { 
     if ([[NSFileManager defaultManager] fileExistsAtPath:url.path]) { 
      result = [[NSFileManager defaultManager] removeItemAtURL:url error:&error]; 
     } 
    } 

    if (result) { 
     [self setupDB]; 
    } else { 
     NSLog(@"An error has occurred while deleting %@ error %@", dbStore, error); 
    } 
} 
+0

Grazie, funziona per me – lenhhoxung

+0

Questo funziona anche per me, ma sembra che a volte i contesti privati ​​sui thread in background vengano lasciati penzolare dopo il disconnettersi. Qualche idea su come posso risolvere il problema? Apprezzo il tuo aiuto. – Myxtic

+0

Grazie !!!! mi hai salvato! –

0

Un po 'di risposta @yoninja riscritto per Swift 4:

private var dbStore : String? { 
    get { 
     if let bundleId = Bundle.main.bundleIdentifier { 
      return bundleId + ".sqlite" 
     } 
     return MagicalRecord.defaultStoreName() 
    } 
} 

func setupCoreDataStack() { 
    MagicalRecord.setupCoreDataStack(withAutoMigratingSqliteStoreNamed: self.dbStore) 
} 

func cleanUp() {   
    MagicalRecord.cleanUp() 

    var removeError: NSError? 
    let deleteSuccess: Bool 
    do { 
     guard let url = NSPersistentStore.mr_url(forStoreName: self.dbStore) else { 
      return 
     } 
     let walUrl = url.deletingPathExtension().appendingPathExtension("sqlite-wal") 
     let shmUrl = url.deletingPathExtension().appendingPathExtension("sqlite-shm") 

     try FileManager.default.removeItem(at: url) 
     try FileManager.default.removeItem(at: walUrl) 
     try FileManager.default.removeItem(at: shmUrl) 

     deleteSuccess = true 
    } catch let error as NSError { 
     removeError = error 
     deleteSuccess = false 
    } 

    if deleteSuccess { 
     self.setupCoreDataStack() 
    } else { 
     print("An error has occured while deleting \(self.dbStore)") 
     print("Error description: \(removeError.debugDescription)") 
    } 
}