Domanda

Sono stato la creazione di un elenco di app e il backup con i dati di base.

Mi piacerebbe avere un elenco predefinito di dire 10 articoli dell'aeroporto, in modo che l'utente non ha bisogno di ripartire da zero.

Esiste un modo per fare questo?

Ogni aiuto è apprezzato. Grazie in anticipo.

È stato utile?

Soluzione

Ecco il modo migliore (e non richiede la conoscenza di SQL):
Creare una rapida Core Data per iPhone (o anche Mac App) utilizzando lo stesso modello a oggetti come l'elenco app. Scrivere poche righe di codice per salvare gli oggetti predefiniti riuscito che si desidera al negozio. Quindi, eseguire tale applicazione nel simulatore. Ora, andare a ~ / Library / Application Support / iPhone Simulator / User / Applications. Trova l'applicazione tra i GUID, poi basta copiare il negozio SQLite fuori nella cartella del progetto tua lista di app.

Poi, carico che memorizzano come fanno nell'esempio CoreDataBooks.

Altri suggerimenti

Sì, c'è, infatti, l'esempio CoreDataBooks fa questo, è possibile scaricare il codice qui: codice di esempio

Quello che fai è creare l'archivio interno (database) utilizzando la normale procedura per inizializzare il vostro negozio, proprio come si farebbe con qualsiasi altro negozio, quindi è sufficiente eseguire il codice e lasciarlo eseguire il codice come descritto nell'esempio CoreDataBooks ( frammento di codice di seguito). Una volta che il negozio è stato inizializzato si vuole creare un NSManagedObjectContext e inizializzare con la memoria permanente creato, inserire tutti i soggetti necessari, e salvare il contesto.

Una volta che il contesto è stato salvato con successo, è possibile interrompere l'applicazione, poi vai a Finder e andare alla cartella: tipo ~/Library/Developer nel .sqlite di ricerca e guardare sotto / Developer, l'ordinamento per data vi darà la .sqlite più recente banca dati che dovrebbe corrispondere al momento in cui il codice è stato eseguito, quindi è possibile prendere questo negozio e aggiungerlo come una risorsa del progetto. Questo file quindi può essere letto da un coordinatore archivio permanente.

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

if (persistentStoreCoordinator) {
    return persistentStoreCoordinator;
}


NSString *storePath = [[self applicationDocumentsDirectory]      stringByAppendingPathComponent: @"CoreDataBooks.sqlite"];
 /*
  Set up the store.
 For the sake of illustration, provide a pre-populated default store.
 */
NSFileManager *fileManager = [NSFileManager defaultManager];
// If the expected store doesn't exist, copy the default store.
if (![fileManager fileExistsAtPath:storePath]) {
  NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:@"CoreDataBooks"      ofType:@"sqlite"];
 if (defaultStorePath) {
 [fileManager copyItemAtPath:defaultStorePath toPath:storePath error:NULL];
 }
}

NSURL *storeUrl = [NSURL fileURLWithPath:storePath];

 NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber   numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil]; 
  persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];

 NSError *error;
 if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {
  // Update to handle the error appropriately.
  NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
 exit(-1);  // Fail
}    

return persistentStoreCoordinator;
}

La speranza che aiuta.

-Oscar

Con questo metodo non è necessario effettuare un'applicazione separata o avere alcuna conoscenza di SQL. Hai solo bisogno di essere in grado di creare un file JSON per i dati iniziali.

Io uso un file JSON che mi parse in oggetti, poi inserirli in Core Data. Lo faccio quando l'applicazione inizializza. Ho anche fare un'entità nel mio dati di base che indica se è già inserito questi dati iniziale, dopo inserisco i dati iniziali ho impostato questa entità così la prossima volta lo script viene eseguito vede che i dati iniziali è già stato inizializzato.

Per leggere il file JSON in oggetti:

NSString *initialDataFile = [[NSBundle mainBundle] pathForResource:@"InitialData" ofType:@"json"];
NSError *readJsonError = nil;
NSArray *initialData = [NSJSONSerialization
                        JSONObjectWithData:[NSData dataWithContentsOfFile:initialDataFile]
                        options:kNilOptions
                        error:&readJsonError];

if(!initialData) {
    NSLog(@"Could not read JSON file: %@", readJsonError);
    abort();
}

Poi si può fare per oggetti entità in questo modo:

[initialData enumerateObjectsUsingBlock:^(id objData, NSUInteger idx, BOOL *stop) {

    MyEntityObject *obj = [NSEntityDescription
                          insertNewObjectForEntityForName:@"MyEntity"
                          inManagedObjectContext:dataController.managedObjectContext];

    obj.name = [objData objectForKey:@"name"];
    obj.description = [objData objectForKey:@"description"];

    // then insert 'obj' into Core Data

}];

Se si desidera una descrizione più dettagliata su come fare questo, controlla questo tutorial: http://www.raywenderlich.com/12170/core- dati dimostrativi-how-to-preloadimport-esistenti-dati-aggiornato

Per 10 elementi, si può solo fare questo all'interno applicationDidFinishLaunching: nella vostra applicazione delegato.

Definire un metodo, diciamo insertPredefinedObjects, che crea e popola le istanze del soggetto incaricato della gestione dei prodotti e per l'aeroporto, e salvare il contesto. Si può sia leggere gli attributi da un file oppure semplicemente cablare nel codice. Poi, chiamare questo metodo all'interno applicationDidFinishLaunching:.

Tenete a mente, quando si segue il codice di esempio CoreDataBooks, che si rompe probabilmente le Istruzioni per la conservazione dei dati iOS:

https://developer.apple.com/icloud/documentation/data-storage /

Ho avuto un app respinto per copiare la (sola lettura) pre-popolato database nella directory documenti - come si chiamava allora viene eseguito il backup su iCloud -. E Apple vuole solo che questo accada ai file generati dagli utenti

Le linee guida di cui sopra offrono alcune soluzioni, ma la maggior parte essi si riducono a:

  • memorizzare il DB nella directory di cache, e con grazia gestire situazioni in cui il sistema operativo elimina le cache -. Si dovrà ricostruire il DB, che probabilmente esclude fuori per la maggior parte di noi

  • impostare un 'non l'attributo cache' sul file di DB, che è un po 'arcano, in quanto deve essere fatto in modo diverso per le diverse versioni del sistema operativo.

Non credo che sia troppo difficile, ma essere consapevoli che avete un po 'in più per fare per fare quel lavoro esempio di codice a fianco di iCloud ...

Così ho sviluppato un metodo generico che carica da un dizionario (possibilmente da JSON) e popola il database. Dovrebbe essere usato solo con i dati di fiducia (da un canale sicuro), non può gestire i riferimenti circolari e migrazioni schema può essere problematico ... Ma per semplici casi di utilizzo come il mio dovrebbe andare bene

Qui si va

- (void)populateDBWithDict:(NSDictionary*)dict
               withContext:(NSManagedObjectContext*)context
{
    for (NSString* entitieName in dict) {

        for (NSDictionary* objDict in dict[entitieName]) {

            NSManagedObject* obj = [NSEntityDescription insertNewObjectForEntityForName:entitieName inManagedObjectContext:context];
            for (NSString* fieldName in objDict) {

                NSString* attName, *relatedClass, *relatedClassKey;

                if ([fieldName rangeOfString:@">"].location == NSNotFound) {
                    //Normal attribute
                    attName = fieldName; relatedClass=nil; relatedClassKey=nil;
                } else {
                    NSArray* strComponents = [fieldName componentsSeparatedByString:@">"];
                    attName = (NSString*)strComponents[0];
                    relatedClass = (NSString*)strComponents[1];
                    relatedClassKey = (NSString*)strComponents[2];
                }
                SEL selector = NSSelectorFromString([NSString stringWithFormat:@"set%@:", attName ]);
                NSMethodSignature* signature = [obj methodSignatureForSelector:selector];
                NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature];
                [invocation setTarget:obj];
                [invocation setSelector:selector];

                //Lets set the argument
                if (relatedClass) {
                    //It is a relationship
                    //Fetch the object
                    NSFetchRequest* query = [NSFetchRequest fetchRequestWithEntityName:relatedClass];
                    query.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:relatedClassKey ascending:YES]];
                    query.predicate = [NSPredicate predicateWithFormat:@"%K = %@", relatedClassKey, objDict[fieldName]];

                    NSError* error = nil;
                    NSArray* matches = [context executeFetchRequest:query error:&error];


                    if ([matches count] == 1) {
                        NSManagedObject* relatedObject = [matches lastObject];
                        [invocation setArgument:&relatedObject atIndex:2];
                    } else {
                        NSLog(@"Error! %@ = %@ (count: %d)", relatedClassKey,objDict[fieldName],[matches count]);
                    }


                } else if ([objDict[fieldName] isKindOfClass:[NSString class]]) {

                    //It is NSString
                    NSString* argument = objDict[fieldName];
                    [invocation setArgument:&argument atIndex:2];
                } else if ([objDict[fieldName] isKindOfClass:[NSNumber class]]) {

                    //It is NSNumber, get the type
                    NSNumber* argument = objDict[fieldName];
                    [invocation setArgument:&argument atIndex:2];

                }
                [invocation invoke];


            }

            NSError *error;
            if (![context save:&error]) {
                NSLog(@"%@",[error description]);
            }
        }
    }   
}

E carichi da json ...

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"initialDB" ofType:@"json"];
NSData *jsonData = [NSData dataWithContentsOfFile:filePath];

NSError* error;
NSDictionary *initialDBDict = [NSJSONSerialization JSONObjectWithData:jsonData
                                                           options:NSJSONReadingMutableContainers error:&error];

[ self populateDBWithDict:initialDBDict withContext: [self managedObjectContext]];

esempi JSON

    {
    "EntitieA": [ {"Att1": 1 }, {"Att1": 2} ],
    "EntitieB": [ {"Easy":"AS ABC", "Aref>EntitieA>Att1": 1} ]
    }

e

{
    "Country": [{"Code": 55, "Name": "Brasil","Acronym": "BR"}],
    "Region": [{"Country>Country>code": 55, "Code": 11, "Name": "Sao Paulo"},
               {"Country>Country>code": 55, "Code": 31, "Name": "Belo Horizonte"}]
}

Che ne dite di controllo se esistono eventuali oggetti e se no, crearne uno con alcuni dati?

NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"Settings"];
_managedObjectSettings = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];

if ([_managedObjectSettings count] == 0) {
    // first time, create some defaults
    NSManagedObject *newDevice = [NSEntityDescription insertNewObjectForEntityForName:@"Settings" inManagedObjectContext:managedObjectContext];

    [newDevice setValue:[NSNumber numberWithBool: YES ] forKey:@"speed"];
    [newDevice setValue:[NSNumber numberWithBool: YES ] forKey:@"sound"];
    [newDevice setValue:[NSNumber numberWithBool: NO ] forKey:@"aspect"];
    [newDevice setValue:[NSNumber numberWithBool: NO  ] forKey: @"useH264"];
    [newDevice setValue:[NSNumber numberWithBool: NO ] forKey: @"useThumbnail"];

    NSError *error = nil;
    // Save the object to persistent store
    if (![managedObjectContext save:&error]) {
        NSLog(@"Can't Save! %@ %@", error, [error localizedDescription]);
    }
}

Questa risposta è solo per le persone che sono

  • tra cui un database pre-popolato nel vostro app
  • fare un app per più piattaforme (iOS, Android, ecc.)

Avevo fatto un database SQLite precompilato per un app Android. Poi, quando stavo facendo una versione iOS del app ho pensato che sarebbe stato meglio usare Core Data. Così ho passato un periodo piuttosto lungo di apprendimento Core Data e poi riscrivere il codice per precompilare il database. Imparare a fare ogni singolo passo in entrambe le piattaforme necessarie un sacco di ricerca e di tentativi ed errori. C'era un sacco di meno sovrapposizione di quanto avrei sperato.

Alla fine ho deciso di utilizzare lo stesso database SQLite dal mio progetto Android. Poi ho usato l'involucro FMDB per accedere direttamente al database in iOS. I vantaggi:

  • Solo bisogno di rendere il database precompilato una volta.
  • Non richiede un cambiamento di paradigma. La sintassi tra Android e FMDB, mentre diverso, è ancora abbastanza simile.
  • avere molto più controllo su come vengono eseguite le query.
  • Permette ricerca a testo integrale.

Anche se non mi pento di apprendimento Core Data, se dovessi farlo più avrei potuto salvare un sacco di tempo da solo attenersi a SQLite.

Se si avvia in iOS e poi in programma di passare ad Android, sarei ancora utilizzare un wrapper SQLite come FMDB o qualche altro software per precompilare il database. Anche se è possibile tecnicamente estrarre il database SQLite che si precompilare con Core Data, lo schema (nomi di tabelle e colonne, ecc) sarà strano nome.

A proposito, se non è necessario modificare il database precompilato, quindi non copiare nella directory documenti dopo aver installato l'applicazione. Basta accedere direttamente dal fascio.

// get url reference to databaseName.sqlite in the bundle
let databaseURL: NSURL = NSBundle.mainBundle().URLForResource("databaseName", withExtension: "sqlite")!

// convert the url to a path so that FMDB can use it
let database = FMDatabase(path: databaseURL.path)

Questo fa in modo che non si dispone di due copie.

Aggiorna

Io uso SQLite.swift piuttosto che FMDB, perché si integra meglio con progetti di Swift.

Un altro metodo per la memorizzazione di default si trova in via NSUserDefaults. (sorpresa!) E la sua facile.

suggerito da alcuni, che mettere in applicationDidFinishLaunching

Nel caso specifico di 10 valori predefiniti, Airport0 attraverso 9

Impostazioni

NSUserDefaults *nud = [NSUserDefaults standardUserDefaults];
[nud setString:@"MACADDRESSORWHY" forKey:@"Airport0"];
    ...
[nud setString:@"MACADDRESSORWHY" forKey:@"Airport9"];
[nud synchronize];

o

[[NSUserDefaults standardUserDefaults] setString:@"MACADDRESSORWHY" forKey:@"Airport9"]];
     ...
[[NSUserDefaults standardUserDefaults] synchronize];

E poi, ottenendo i valori di default.

NSString *air0 = [[NSUserDefaults standardUserDefaults] stringForKey:@"Airport0"];

Questo ha funzionato per me. Questa è una modifica di questo rispondere da Andrea Toso e ispirato da questo blog . L'unico problema con la risposta è che c'è una possibilità di perdita di dati quando si spostano file SQLite con FileManager. Ho salvato circa 500 righe di dati utilizzando replacePersistentStore invece di FileManager.default.copyItem

Passaggio 1
Compilare il Nucleo dati in un'altra applicazione e ottenere il percorso file utilizzando questo codice:

let paths = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
print(documentsDirectory)

Step2
Trascinare i 3 file con estensione .sqlite nel progetto Xcode. (Assicurarsi di selezionare l'opzione Aggiungi target a).

Fase 3
Creare la funzione di controllare prima esecuzione dell'applicazione in AppDelegate.swift

func isFirstLaunch() -> Bool {
    let hasBeenLaunchedBeforeFlag = "hasBeenLaunchedBeforeFlag"
    let isFirstLaunch = !UserDefaults.standard.bool(forKey: hasBeenLaunchedBeforeFlag)
    if (isFirstLaunch) {
        UserDefaults.standard.set(true, forKey: hasBeenLaunchedBeforeFlag)
        UserDefaults.standard.synchronize()
    }
    return isFirstLaunch
}

Fase 4
Copiare questa funzione in AppDelegate.swift per ottenere URL dove database SQLite dovrebbe essere spostato:

func getDocumentsDirectory()-> URL {
    let paths = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)
    let documentsDirectory = paths[0]
    return documentsDirectory
}

Passaggio 5
Sostituire dichiarazione di persistentContainer con questo:

// MARK: - Core Data stack

lazy var persistentContainer: NSPersistentContainer = {
    let container = NSPersistentContainer(name: "ProjectName")

    let storeUrl = self.getDocumentsDirectory().appendingPathComponent("FileName.sqlite")

    if UserDefaults.isFirstLaunch() {
        let seededDataUrl = Bundle.main.url(forResource: "FileName", withExtension: "sqlite")
        try! container.persistentStoreCoordinator.replacePersistentStore(at: storeUrl, destinationOptions: nil, withPersistentStoreFrom: seededDataUrl!, sourceOptions: nil, ofType: NSSQLiteStoreType)
    }

    container.loadPersistentStores(completionHandler: { (storeDescription, error) in
        if let error = error as NSError? {
            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
    })
    return container
}()
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top