Як зберегти масив у CoreData?


93

Мені потрібно зберегти свій масив у Core Data.

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

Значення всередині цього масиву та кількість значень є змінними.

1. Що я оголошую в своєму класі 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. Що я заявляю у своїй .xcdatamodel?

введіть тут опис зображення

3. Як я можу зберегти це у своїй організації? (Я використовую MagicalRecord)

let statistics = (PBOStatistics.MR_createInContext(context) as! PBOStatistics)
statistics.values = [8, 17.7, 18, 21, 0, 0, 34] //is it enough?

Немає "слід", дизайн БД залежить від вас, наприклад, на мій погляд, ви також можете використовувати дати або текстовий формат, якщо це виявляється найбільш ефективним способом зберігання цих даних у вашому додатку.
A-Live

Тож усередині мого NSManagedObject: @NSManaged var values: [Double]це добре? Чи можете ви сказати, який тип слід використовувати .xcdatamodelдля збереження цього?
Бартломей Семанчик

Можливо, я недостатньо чітко пояснив, як ви запитуєте, це стосується особистих уподобань, і справжньої проблеми не вирішити. Якщо ви шукаєте будь-який спосіб використання відносин "один-до-багатьох", додайте інформацію про те, що ви спробували і де у вас виникла проблема. Якщо ви розумієте кожне із згаданих вами рішень і шукаєте найбільш ефективне - перелічіть свої критерії ефективності та опишіть варіанти використання. Якщо з якихось причин у вас виникають проблеми з розумінням різних видів відносин або ви взагалі не хочете використовувати стосунки - скажіть це прямо.
A-Live

Я оновив питання
Bartłomiej Semańczyk

Тепер це гідне запитання, я додав для вас тег MagicalRecord, на жаль, я не маю досвіду в цій галузі, і, сподіваюся, хтось, хто є, зможе допомогти вам краще з цього моменту.
A-Live

Відповіді:


179

Гаразд, я зробив кілька досліджень та тестувань. Використовуючи трансформований тип, рішення є простим:

1. Що я оголошую в своєму класі NSManagedObject?

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

2. Що я заявляю у своїй .xcdatamodel?

Transformable тип даних.

3. Як я можу зберегти це у своїй організації?

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

“Ви можете зберегти NSArray або NSD Dictionary як перетворюваний атрибут. Це використовуватиме NSCoding для серіалізації масиву або словника до атрибута NSData (і відповідно десеріалізації його при доступі) ”- Джерело

Або якщо ви хочете оголосити це як двійкові дані, прочитайте цю просту статтю :


Хороша робота, відповідь, здається, варта зеленої позначки для завершення.
A-Live

3
Також працює з [NSString]масивом рядків
Daisy R.

Чи можна додати предикат під час отримання з основних даних?
Сатьям,

5
У моєму випадку я намагаюся використовувати масив рядків, але це не працює
allemattio

як би ви зробили це швидко 3 способами?
Martian2049

97

Swift 3 Оскільки станом на Swift 3 у нас більше немає файлів реалізації, нам потрібно перейти до файлу xcdatamodeld, вибрати сутність та бажаний атрибут (у цьому прикладі це називається значеннями). Встановіть його як перетворюваний, а його спеціальний клас - [Double]. Тепер використовуйте його як звичайний масив.

Встановлення користувацького класу для масиву Double


Чи можна визначити власний клас як [[String: Any]]?
Безліч

Теоретично це повинно бути прийнятним, однак я ніколи не пробував.
Hola Soy Edu Feliz Navidad

2
Ви завжди можете встановити codegen на Manual / None та написати свій власний клас моделі Core Data.
Схематичний

14

Перетворити масив на 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)")
}

Виберіть Двійкові дані

Перетворити NSData на 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)")
}

Наприклад: https://github.com/kkvinokk/Event-Tracker


1
Використання NSData справді має більше сенсу та простіше.
GeneCode

2
Якщо ви хочете додати предикат до цього атрибуту, це може не спрацювати.
Сатьям,

6

Якщо це просто і зберегти масив як рядок

Спробуйте це:

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

Для інших типів даних відповідно:

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

Ваше рішення врятувало мій багато часу
Кішор Кумар,

Я не впевнений, чому, але жодне з цих рішень не працює для мене. Я спробував ваше рішення зберегти дані масиву рядків у Core Data та отримати їх, а потім декодувати до масиву рядків, але він все ще не працює. Будь-яка порада?
Tyler Cheek

3

Зробити тип атрибута сутності як "двійкові дані"

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

Отримати оригінальний масив як:

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

Це все.


1

Наступний код працює для мене для зберігання масиву JSON в 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")
    }

}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.