Pregunta

He estado creando una aplicación de lista y el respaldo con los datos principales.

Me gustaría tener una lista predeterminada de, digamos, 10 artículos del aeropuerto, por lo que el usuario no tiene que empezar de cero.

¿Hay alguna manera de hacer esto?

Cualquier ayuda es apreciada. Gracias de antemano.

¿Fue útil?

Solución

Esta es la mejor manera (y no requiere conocimientos de SQL):
Crear una aplicación para el iPhone rápida de Datos Básicos (o incluso Mac aplicación) utilizando el mismo modelo de objetos como su aplicación Lista. Escribir unas pocas líneas de código para guardar los objetos predeterminados logrado que desee a la tienda. A continuación, ejecute esa aplicación en el simulador. Ahora, vaya a ~ / Library / Application Support / simulador de iPhone / usuario / Aplicaciones. Encuentra su aplicación entre los GUID, a continuación, sólo copiar la tienda SQLite a cabo en la carpeta de proyectos de su aplicación lista.

A continuación, la carga que almacenan como lo hacen en el ejemplo CoreDataBooks.

Otros consejos

Sí hay, de hecho, el ejemplo CoreDataBooks hace esto, se puede descargar el código aquí: código de ejemplo

Lo que se hace es crear el almacén interno (base de datos) utilizando el procedimiento normal para inicializar su tienda al igual que lo haría con cualquier otra tienda, entonces usted sólo tiene que ejecutar su código y dejar que se ejecute el código como se describe en el ejemplo CoreDataBooks ( fragmento de código a continuación). Una vez que la tienda ha sido inicializado tendrá que crear un NSManagedObjectContext e inicializar con el almacén persistente creado, inserte todas las entidades que necesita, y guardar el contexto.

Una vez que el contexto ha sido guardado con éxito, puede detener su aplicación, a continuación, vaya a Finder y vaya a la carpeta: Tipo ~/Library/Developer en el .sqlite de búsqueda y busque en / desarrollador, ordenar por fecha le dará la más reciente .sqlite base de datos que debe coincidir con el momento en que el código se ejecuta, a continuación, puede tomar esta tienda y añadirlo como un recurso de su proyecto. Este archivo puede ser leído por un coordinador almacén persistente.

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

Espero que ayude.

-Oscar

Con este método no es necesario hacer una aplicación separada o tener ningún conocimiento de SQL. Sólo tiene que ser capaz de hacer un archivo JSON para los datos iniciales.

Yo uso un archivo JSON que analizo en objetos, y luego insertarlos en la base de datos. Lo hago cuando la aplicación inicializa. También hago una entidad en mis datos central que indica si los datos iniciales ya está insertada, después de insertar los datos iniciales puse esta entidad por lo que la próxima vez que se ejecute el script se ve que los datos iniciales ya se ha inicializado.

Para leer el archivo JSON en objetos:

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

A continuación, puede hacer que los objetos de entidad para que de esta manera:

[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

}];

Si desea una descripción más detallada sobre cómo hacer esto, echa un vistazo a este tutorial: http://www.raywenderlich.com/12170/core- datos-tutorial-cómo-a-preloadimport-existentes-data-actualiza

En 10 artículos, sólo puede hacerlo dentro de applicationDidFinishLaunching: en delegado de la aplicación.

Definir un método, digamos insertPredefinedObjects, que crea y llena las instancias de la entidad encargada de la gestión de sus artículos aeropuerto, y guardar su contexto. Es posible que sea leído los atributos de un archivo o simplemente cablear en el código. A continuación, llamar a este método dentro applicationDidFinishLaunching:.

Tenga en cuenta, cuando se sigue el código de ejemplo CoreDataBooks, que probablemente rompe las Directrices de almacenamiento de datos iOS:

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

He tenido una aplicación rechazada por copiar el (sólo lectura) rellena previamente base de datos para el directorio de documentos - ya que a continuación se copia de seguridad en iCloud -. Y Apple sólo quiere que esto suceda a los archivos generados por el usuario

Las pautas anteriores ofrecer algunas soluciones, pero que en su mayoría se reducen a:

  • almacenar la base de datos en el directorio de cachés, y con gracia manejar situaciones en las que el sistema operativo purga las cachés -., Tendrá que reconstruir la base de datos, lo que probablemente lo descarta para la mayoría de nosotros

  • establece un 'no hacer caché de atributos' en el archivo de base de datos, que es un poco arcano, ya que hay que hacer de manera diferente para diferentes versiones del sistema operativo.

No creo que sea demasiado complicado, pero ten en cuenta que usted tiene un poco más para hacer para hacer que el código de ejemplo de trabajo junto con icloud ...

Así que han desarrollado un método genérico que se carga de un diccionario (posiblemente de JSON) y rellena la base de datos. Debe usarse sólo con datos de confianza (de un canal seguro), no puede manejar las referencias circulares y las migraciones de esquema puede ser problemático ... Sin embargo, para los casos de uso sencillos como la mía que debería estar bien

Aquí 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]);
            }
        }
    }   
}

y cargas de 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]];

ejemplos JSON

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

y

{
    "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"}]
}

¿Qué hay de verificación si existen objetos y si no es así, crear una con unos datos?

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]);
    }
}

Esta respuesta es sólo para personas que están

  • que incluye una base de datos pre-poblada en su aplicación
  • hacer una aplicación para múltiples plataformas (iOS, Android, etc.)

Me había hecho una base de datos SQLite rellenada previamente para una aplicación para Android. A continuación, cuando estaba haciendo una versión de IOS de la aplicación que pensé que sería mejor utilizar datos básicos. Así que pasé mucho tiempo de aprendizaje de Datos Básicos y luego volver a escribir el código para rellenar previamente la base de datos. Aprender a hacer cada paso en ambas plataformas se requieren una gran cantidad de investigación y ensayo y error. Hubo mucho menor superposición de lo que hubiera esperado.

Al final me decidí a utilizar la misma base de datos SQLite desde mi proyecto Android. Luego utiliza el envoltorio FMDB para acceder directamente a la base de datos en IOS. Los beneficios:

  • Sólo es necesario realizar la base de datos una vez rellenada previamente.
  • No requiere un cambio de paradigma. La sintaxis entre Android y FMDB, aunque diferentes, sigue siendo bastante similar.
  • tienen mucho más control sobre cómo se llevan a cabo consultas.
  • Permite la búsqueda de texto completo.

A pesar de que no me arrepiento de aprendizaje de Datos Básicos, si tuviera que hacerlo otra que podría haber ahorrado un montón de tiempo con sólo pegar a SQLite.

Si usted está comenzando en IOS y luego planificar para pasar a Android, todavía me gustaría utilizar un envoltorio SQLite como FMDB o algún otro software para rellenar previamente la base de datos. Aunque se puede extraer técnicamente la base de datos SQLite que rellenar previamente con datos básicos, el esquema (nombres de tablas y columnas, etc.) será extraño nombre.

Por cierto, si usted no necesita modificar su base de datos Rellenado, entonces no copiarlo en el directorio de documentos después de instalar la aplicación. Sólo acceder a ella directamente desde el paquete.

// 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)

Esto lo hace de manera que usted no tiene dos copias.

Actualizar

SQLite.swift en lugar de FMDB, ya que integra mejor con proyectos Swift.

Otro método para el almacenamiento de valores predeterminados se encuentra a modo de NSUserDefaults. (¡sorpresa!) Y su fácil.

sugerido por algunos, puesto que en el applicationDidFinishLaunching

En el caso dado de 10 valores predeterminados, Aeropuerto0 thru 9

Configuración

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

Y a continuación, obtener los valores por defecto.

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

Esto funcionó para mí. Esta es una modificación de este responder por Andrea Toso e inspirado por esta el blog . El único problema con la respuesta es que existe la posibilidad de pérdida de datos al mover archivos sqlite con el FileManager. Me salvó alrededor de 500 filas de datos mediante el uso de replacePersistentStore en lugar de FileManager.default.copyItem

Paso 1
Poblar sus Datos Core en otra aplicación y obtener la ruta de los archivos de los que utiliza este código:

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

Paso 2
Arrastre los 3 archivos con extensión .sqlite en su proyecto de Xcode. (Asegúrese de seleccionar la opción Añadir a objetivos).

Paso 3
Crear función para comprobar la primera carrera de aplicación en 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
}

Paso 4
Copiar esta función en AppDelegate.swift para obtener url donde la base de datos SQLite debe ser movido:

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

Paso 5:
Reemplazar declaración de persistentContainer con éste:

// 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
}()
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top