Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Save Array of Strings to CoreData

I am trying to save an array of 6 strings to CoreData, like this:

     let imageUrls = ["image-url....", "image-url....", ..., "image-url"]

I have tried all methods stated in How to save Array to CoreData? and in Best practice? - Array/Dictionary as a Core Data Entity Attribute without success.

This is the method I am trying to do.

Inside my .xcdatamodeld, I have declared: imageUrl as a Transformable, see picture in link (couldn't attach it to the post, I'm sorry for that!): https://drive.google.com/file/d/1VJey55oD9KhOy1KDy59h8PweMMQnaK2-/view?usp=sharing

Inside my NSManagedObject class I have

    @objc(Entity)
    public class Entity: NSManagedObject {
    @NSManaged public var imageUrls: [String]?
    ....

This is how I create the entity before saving it to CoreData:

    entity.imageUrls = ["test", "test", "test"]

When I try to fetch the imageUrls, the fetched entity.imageUrls is equal to nil. I don't understand this. The expected results is the same array I saved to CoreData.

ANSWERED by Joakim Danielson

like image 501
CoderOgden Avatar asked Aug 29 '19 05:08

CoderOgden


People also ask

Can you store an array in Core Data?

There are two steps to storing an array of a custom struct or class in Core Data. The first step is to create a Core Data entity for your custom struct or class. The second step is to add a to-many relationship in the Core Data entity where you want to store the array.

How do I save in Core Data?

Right-click on your project's folder in the project navigator and then New File… In the new window, type “data” in the top right corner, select Data Model, and press Next. Give it a name, and save it. Now, let's add all the necessary code to connect Core Data with our project.

Should I use Core Data?

The next time you need to store data, you should have a better idea of your options. Core Data is unnecessary for random pieces of unrelated data, but it's a perfect fit for a large, relational data set. The defaults system is ideal for small, random pieces of unrelated data, such as settings or the user's preferences.

How do I use Core Data?

Open Xcode and create a new iOS project based on the Single View App template. Name the app HitList and make sure Use Core Data is checked. Checking the Use Core Data box will cause Xcode to generate boilerplate code for what's known as an NSPersistentContainer in AppDelegate.


5 Answers

My suggestion is to encode/decode the array to JSON and use a computed property. From the Swift perspective this is probably more efficient than a transformable attribute which bridges the array to the Objective-C runtime and uses heavier NSCoding.

@NSManaged public var imageUrls: String

var urls : [String] {
    get {
        let data = Data(imageUrls.utf8)
        return (try? JSONDecoder().decode([String].self, from: data)) ?? []
    }
    set {
        guard let data = try? JSONEncoder().encode(newValue),
            let string = String(data: data, encoding: .utf8) else { imageUrls = "" }
        imageUrls = string
    }
}

Another benefit is that a JSON string is searchable

like image 109
vadian Avatar answered Oct 20 '22 19:10

vadian


check the attachement below for declration in ".xcdatamodelId" file. After that declare below line in CoreDataProperties.swift file

@NSManaged public var thumbnail: [String]?

Now, we can initialised string array into thumnail variable.Declaration variable in xcdatamodelID file

like image 20
Pawan Kumar Avatar answered Oct 20 '22 17:10

Pawan Kumar


You will have to save it to the core data as String and split the array with a seperator. The thing is that you have to be sure that the string will no include that seperator.

For example if you used the seperator ", " on saving your array to the core data you will have to save it like

coreData.arrayToStringValue = array.joined(separator: ", ")

and when you read your data you will have to read it like:

let arrayFromStringValue:[String] = coreDataValue.split(separator: ", ")
like image 37
Vasilis D. Avatar answered Oct 20 '22 17:10

Vasilis D.


Change type of imageUrl to BinaryData, then convert your list to data and save.

let urls = NSKeyedArchiver.archivedData(withRootObject: imageUrls)
manageObject.setValue(urls, forKey: "imageUrls")
like image 32
Ruben Nahatakyan Avatar answered Oct 20 '22 18:10

Ruben Nahatakyan


Swift 5

I found vadian's answer very helpful. I Used the same idea, But in a different way. Giving my code hoping that it may help.

  • Select the Type of the attribute that you want to store the array as String

enter image description here

// save to core data

var quizManagedObject : [NSManagedObject] = []

func save(question: String, answers: [String]) {

    guard let data = try? JSONEncoder().encode(answers),
    let answersEncodedString = String(data: data, encoding: .utf8) else { return }

    guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
    let managedContext = appDelegate.persistentContainer.viewContext

    let entity = NSEntityDescription.entity(forEntityName: "Quiz", in: managedContext)!
    let quiz = NSManagedObject(entity: entity, insertInto: managedContext)

    quiz.setValue(question, forKeyPath: "question")
    quiz.setValue(answersEncodedString, forKeyPath: "answers")

    do {
        quizManagedObject.append(quiz)
        try managedContext.save()
    } catch let error as NSError {
        print("Could not save. \(error), \(error.userInfo)")
    }
}

// fetch from core data

func fetchCoreData() {

    guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
    let managedContext = appDelegate.persistentContainer.viewContext
    let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Quiz")

    do {
        quizManagedObject = try managedContext.fetch(fetchRequest)

        for i in quizManagedObject {
            if let decodedAnswerString = i.value(forKey: "answers") as? String {
                let data = Data(decodedAnswerString.utf8)
                let answerArray = try? JSONDecoder().decode([String].self, from: data)
                let question = i.value(forKey: "question") as! String

                print("Q : ", question)
                print("A : ", answerArray ?? [""])
            }
        }
    } catch let error as NSError {
        print("Could not fetch. \(error), \(error.userInfo)")
    }
}
like image 36
Naval Hasan Avatar answered Oct 20 '22 17:10

Naval Hasan