Como salvar Array em CoreData?

91

Preciso salvar meu array em Core Data.

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

Os valores dentro dessa matriz e o número de valores são variáveis.

1. O que declaro dentro da minha classe 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. O que declaro dentro do meu .xcdatamodel?

insira a descrição da imagem aqui

3. Como faço para salvar isso na minha entidade? (Eu 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
fonte
Não há "deveria", o design do banco de dados é com você, por exemplo, no que me diz respeito, você também pode usar datas ou formato de texto se essa for a maneira mais eficiente de armazenar esses dados em seu aplicativo.
A-Live
Então dentro do meu NSManagedObject: @NSManaged var values: [Double]isso é bom? Você pode me dizer que tipo devo usar .xcdatamodelpara salvar isso?
Bartłomiej Semańczyk
Posso não ter deixado claro o suficiente, a maneira como você pergunta é sobre a preferência pessoal, não há nenhum problema real para resolver. Se você está procurando alguma maneira de usar relações um para muitos, adicione as informações sobre o que você tentou e onde teve um problema. Se você entende cada uma das soluções mencionadas por você e está procurando a mais eficiente - liste seus critérios de eficiência e descreva os casos de uso. Se por alguma razão você está tendo problemas para entender diferentes tipos de relações ou não quer usar relações de forma alguma - diga isso diretamente.
A-Live
Eu atualizei a pergunta
Bartłomiej Semańczyk
Essa é uma pergunta decente, adicionei uma tag MagicalRecord para você, infelizmente não tenho experiência nessa área e espero que alguém que tenha possa ajudá-lo melhor a partir deste ponto.
A-Live

Respostas:

177

Ok, fiz algumas pesquisas e testes. Usando o tipo Transformable , a solução é simples:

1. O que declaro dentro da minha classe NSManagedObject?

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

2. O que declaro dentro do meu .xcdatamodel?

Transformable tipo de dados.

3. Como faço para salvar isso na minha entidade?

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

“Você pode armazenar um NSArray ou um NSDictionary como um atributo transformável. Isso usará o NSCoding para serializar a matriz ou dicionário para um atributo NSData (e desserializar apropriadamente ao acessar) ”- Fonte

Ou se você deseja declará-lo como dados binários , leia este artigo simples :

Bartłomiej Semańczyk
fonte
Bom trabalho, a resposta parece valer uma marca de verificação verde para fins de conclusão.
A-Live
2
Também funciona com [NSString]uma série de strings
Daisy R.
É possível adicionar predicado durante a busca de dados principais?
Satyam
3
No meu caso, estou tentando usar um array de Strings e não funciona
allemattio
como você faria isso em 3 maneiras rápidas?
Martian2049
94

Swift 3 Como não temos mais os arquivos de implementação a partir do Swift 3, o que temos que fazer é ir até o arquivo xcdatamodeld, selecionar a entidade e o atributo desejado (neste exemplo é chamado de valores). Defina-o como transformável e sua classe personalizada como [Double]. Agora use-o como um array normal.

Configurando a classe personalizada para array de Double

Hola Soy Edu Feliz Navidad
fonte
É possível definir a classe personalizada como [[String: Any]]? Uma série de dicionários
BergP
Teoricamente, deveria ser aceitável, mas nunca tentei.
Hola Soy Edu Feliz Navidad
2
Você sempre pode definir codegen como Manual / Nenhum e escrever sua própria classe de modelo de dados principais.
Schemetrical
14

Converter Array em 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)")
}

Selecione Dados Binários

Converter NSData em Array

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 exemplo: https://github.com/kkvinokk/Event-Tracker

Vinoth Anandan
fonte
1
Usar NSData de fato faz mais sentido e mais simples.
GeneCode
2
Se você quiser adicionar um predicado a esse atributo, pode não funcionar.
Satyam
5

Se for simples e armazenar um array como uma string

Experimente isto:

// 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 outros tipos de dados, 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
fonte
Sua solução economizou muito tempo
Kishore Kumar
Não sei por que, mas nenhuma dessas soluções está funcionando para mim. Tentei sua solução de armazenar os dados da matriz de string em Core Data e recuperá-los e, em seguida, decodificá-los em uma matriz de string, mas ainda não está funcionando. Algum conselho?
Tyler Cheek
3

Faça o tipo de atributo de entidade como "Dados binários"

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

Recupere a matriz original como:

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

Isso é tudo.

Avijit Nagare
fonte
1

O seguinte código funciona para mim para armazenar array de JSON em 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
fonte