¿Cómo guardar Array en CoreData?

93

Necesito guardar mi matriz en Core Data.

let array = [8, 17.7, 18, 21, 0, 0, 34]

Los valores dentro de esa matriz y el número de valores son variables.

1. ¿Qué declaro dentro de mi clase NSManagedObject?

class PBOStatistics: NSManagedObject, Equatable {
    @NSManaged var date: NSDate
    @NSManaged var average: NSNumber
    @NSManaged var historicAverage: NSNumber
    @NSManaged var total: NSNumber
    @NSManaged var historicTotal: NSNumber
    @NSManaged var ordersCount: NSNumber
    @NSManaged var historicOrdersCount: NSNumber
    @NSManaged var values: [Double]  //is it ok?

    @NSManaged var location: PBOLocation

}

2. ¿Qué declaro dentro de mi .xcdatamodel?

ingrese la descripción de la imagen aquí

3. ¿Cómo guardo esto en mi Entidad? (Yo uso MagicalRecord)

let statistics = (PBOStatistics.MR_createInContext(context) as! PBOStatistics)
statistics.values = [8, 17.7, 18, 21, 0, 0, 34] //is it enough?
Bartłomiej Semańczyk
fuente
No hay "debería", el diseño de la base de datos depende de usted, por ejemplo, en lo que a mí respecta, también puede usar fechas o formato de texto si esta es la forma más eficiente de almacenar estos datos en su aplicación.
A-Live
Así que dentro de mi NSManagedObject: ¿ @NSManaged var values: [Double]está bien? ¿Puede decirme qué tipo debo usar .xcdatamodelpara guardar esto?
Bartłomiej Semańczyk
Puede que no lo haya dejado lo suficientemente claro, la forma en que lo preguntas se trata de preferencias personales, no hay ningún problema real que resolver. Si está buscando alguna forma de utilizar relaciones de uno a muchos, agregue la información de lo que ha intentado y dónde ha tenido un problema. Si comprende cada una de las soluciones mencionadas por usted y está buscando la más eficiente, enumere sus criterios de eficiencia y describa los casos de uso. Si por alguna razón tiene problemas para comprender diferentes tipos de relaciones o no quiere usar relaciones en absoluto, dígalo directamente.
A-Live
Actualicé
Ahora que es una pregunta decente, he agregado una etiqueta MagicalRecord para usted, desafortunadamente no tengo experiencia en esta área y espero que alguien que sí pueda ayudarlo mejor desde este punto.
A-Live

Respuestas:

179

Ok, hice algunas investigaciones y pruebas. Usando el tipo Transformable , la solución es simple:

1. ¿Qué declaro dentro de mi clase NSManagedObject?

@NSManaged var values: [NSNumber]  //[Double] also works

2. ¿Qué declaro dentro de mi .xcdatamodel?

Transformable tipo de datos.

3. ¿Cómo guardo esto en mi Entidad?

statistics!.values = [23, 45, 567.8, 123, 0, 0] //just this

“Puede almacenar un NSArray o un NSDictionary como un atributo transformable. Esto usará NSCoding para serializar la matriz o diccionario a un atributo NSData (y deserializarlo apropiadamente al acceder) ”- Fuente

O si desea declararlo como datos binarios , lea este simple artículo :

Bartłomiej Semańczyk
fuente
Buen trabajo, la respuesta parece valer una marca de verificación verde por el bien de la finalización.
A-Live
3
También funciona con [NSString]una variedad de cadenas
Daisy R.
¿Es posible agregar predicados mientras se obtienen datos básicos?
Satyam
5
En mi caso, estoy tratando de usar una matriz de cadenas y no funciona
allemattio
¿Cómo harías esto en Swift 3?
Martian2049
97

Swift 3 Como ya no tenemos los archivos de implementación a partir de Swift 3, lo que tenemos que hacer es ir al archivo xcdatamodeld, seleccionar la entidad y el atributo deseado (en este ejemplo se llama valores). Configúrelo como transformable y su clase personalizada en [Double]. Ahora utilícelo como una matriz normal.

Configurando la clase personalizada a una matriz de Double

Hola Soy Edu Feliz Navidad
fuente
¿Es posible definir una clase personalizada como [[String: Any]]? Una variedad de diccionarios
BergP
Teóricamente debería ser aceptable, sin embargo, nunca lo he intentado.
Hola Soy Edu Feliz Navidad
2
Siempre puede establecer codegen en Manual / Ninguno y escribir su propia clase de modelo Core Data.
Schemetrical
14

Convertir matriz en NSData

let appDelegate =
    UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let entity =  NSEntityDescription.entityForName("Device",
                                                inManagedObjectContext:managedContext)
let device = NSManagedObject(entity: entity!,
                             insertIntoManagedObjectContext: managedContext)
let data = NSKeyedArchiver.archivedDataWithRootObject(Array)

device.setValue(data, forKey: "dataOfArray")
do {
    try managedContext.save()
    devices.append(device)
} catch let error as NSError  {
    print("Could not save \(error), \(error.userInfo)")
}

Seleccionar datos binarios

Convertir NSData a matriz

let appDelegate =
    UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "Device")

do {
    let results =
        try managedContext.executeFetchRequest(fetchRequest)

    if results.count != 0 {

        for result in results {

                let data = result.valueForKey("dataOfArray") as! NSData
                let unarchiveObject = NSKeyedUnarchiver.unarchiveObjectWithData(data)
                let arrayObject = unarchiveObject as AnyObject! as! [[String: String]]
                Array = arrayObject
        }

    }

} catch let error as NSError {
    print("Could not fetch \(error), \(error.userInfo)")
}

Por ejemplo: https://github.com/kkvinokk/Event-Tracker

Vinoth Anandan
fuente
1
De hecho, usar NSData tiene más sentido y es más simple.
GeneCode
2
Si desea agregar un predicado a ese atributo, es posible que no funcione.
Satyam
6

Si lo mantiene simple y almacena una matriz como una cadena

Prueba esto:

// Array of Strings
let array: [String] = ["red", "green", "blue"]
let arrayAsString: String = array.description
let stringAsData = arrayAsString.data(using: String.Encoding.utf16)
let arrayBack: [String] = try! JSONDecoder().decode([String].self, from: stringAsData!)

Para otros tipos de datos respectivamente:

// Set of Doubles
let set: Set<Double> = [1, 2.0, 3]
let setAsString: String = set.description
let setStringAsData = setAsString.data(using: String.Encoding.utf16)
let setBack: Set<Double> = try! JSONDecoder().decode(Set<Double>.self, from: setStringAsData!)
Alexey Chekanov
fuente
Su solución me ahorró mucho tiempo
Kishore Kumar
No estoy seguro de por qué, pero ninguna de estas soluciones me funciona. Probé su solución de almacenar los datos de la matriz de cadenas en Core Data y recuperarlos, luego decodificarlos en una matriz de cadenas, pero todavía no funciona. ¿Algún consejo?
Tyler Cheek
3

Hacer que el tipo de atributo de entidad sea "Datos binarios"

NSData *arrayData = [NSKeyedArchiver archivedDataWithRootObject:TheArray];
myEntity.arrayProperty = arrayData;
[self saveContext]; //Self if we are in the model class

Recuperar matriz original como:

NSMutableArray *array = [NSKeyedUnarchiver unarchiveObjectWithData:anEntity.arrayProperty];

Eso es todo.

Avijit Nagare
fuente
1

El siguiente código me funciona para almacenar una matriz de JSON en CoreData

func saveLocation(model: [HomeModel],id: String){

    let newUser = NSEntityDescription.insertNewObject(forEntityName: "HomeLocationModel", into: context)

    do{
        var dictArray = [[String: Any]]()
        for i in 0..<model.count{
            let dict = model[i].dictionaryRepresentation()
            dictArray.append(dict)
        }
        let data = NSKeyedArchiver.archivedData(withRootObject: dictArray)
        newUser.setValue(data, forKey: "locations")
        newUser.setValue(id, forKey: "id")
        try context.save()
    }catch {
       print("failure")
    }

}
Rahul Gusain
fuente