7

I'm struggling to get my CoreData objects into JSON so that I can use it to send to a web server.

This is how I currently fetch my objects from CoreData:

func fetchRecord() -> [Record] {

    do {
        records = try context.fetch(Record.fetchRequest())

    } catch {
        print("Error fetching data from CoreData")
    }
    return records
}

I am able to display this on to my tableView this way:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "recordCell", for: indexPath) as! RecordCell

    cell.nameLbl.text = records[indexPath.row].name
    cell.quantityLbl.text = "Quantity: \(String(records[indexPath.row].quantity))"
    cell.dateLbl.text = dateString(date: records[indexPath.row].date)

    return cell
}

I have attempted to loop inside my request like this:

for rec in records {
    print(rec)
}

that gives out this:

enter image description here

I have read a lot about ways to achieve this but none of them seem to really be of beneficial to me. Most of the examples out there shows how to get JSON to CoreData and not the other way. Does anyone know any good tutorials or documentation that can help me achieve this?

Chace
  • 561
  • 10
  • 28

4 Answers4

14

In Swift 4+ you can take advantage of the Encodable protocol and add the functionality directly to your Core Data object.

Assuming your NSManagedObject subclass extension looks like

extension Record {
    
    @NSManaged public var date: Date
    @NSManaged public var name: String
    @NSManaged public var quantity: Int32
    @NSManaged public var synched: Bool
    @NSManaged public var uuid: String

   ...

Adopt Encodable

extension Record : Encodable {

and add

private enum CodingKeys: String, CodingKey { case date, name, quantity, synched, uuid }

public func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    try container.encode(date, forKey: .date)
    try container.encode(name, forKey: .name)
    try container.encode(quantity, forKey: .quantity)
    try container.encode(synched, forKey: .synched)
    try container.encode(uuid, forKey: .uuid)
}

Then you can easily encode the records to JSON

do {
    records = try context.fetch(Record.fetchRequest())
    let jsonData = try JSONEncoder().encode(records)
} catch {
    print("Error fetching data from CoreData", error)
}
vadian
  • 274,689
  • 30
  • 353
  • 361
13

Here the code as an extension. Based on KavyaKavita's answer.

extension NSManagedObject {
  func toJSON() -> String? {
    let keys = Array(self.entity.attributesByName.keys)
    let dict = self.dictionaryWithValues(forKeys: keys)
    do {
        let jsonData = try JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted)
        let reqJSONStr = String(data: jsonData, encoding: .utf8)
        return reqJSONStr
    }
    catch{}
    return nil
  }
}

Usage:

let jsonString = YourCoreDataObject.toJSON()
print(jsonString)
Mike_NotGuilty
  • 2,253
  • 5
  • 32
  • 64
6

You can convert your NSManageObject subclass object into dictionary by using following code

let record = recArray[index]
        let keys = Array(record.entity.attributesByName.keys)
        let dict = record.dictionaryWithValues(forKeys: keys)

After that you can use jsonserialization to convert that dictionary into json object

do{
        let jsonData = try JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted)
        let reqJSONStr = String(data: jsonData, encoding: .utf8)
        print(reqJSONStr!)
    }catch{

    }

Hope this will help.

KavyaKavita
  • 1,581
  • 9
  • 16
  • Sorry, please see the updated title. Is there a way you could covert this into Swift? – Chace Sep 15 '17 at 11:00
  • Would you be able to explain where I'd use this code please? – Chace Sep 15 '17 at 11:06
  • please check swift version, as per your specification you want to send this Record object to webservice, for that you want to convert recort object into json. So just add this where you want to convert your coredata object inti json. – KavyaKavita Sep 15 '17 at 11:13
  • I am struggling to implement your example. Where are you getting the recArray? Could you please show me how it would work using my method. I assume the conversion takes place in the `fetchRecord()` function, but I'm just getting errors from this. – Chace Sep 15 '17 at 13:36
  • @Chace I'm sure you figured this out already, but in your OP you are fetching an array/list of records. That is what recArray is referring to in the above answer. – SouthernYankee65 Feb 08 '21 at 05:03
1

If you want you can get the results in dictionary format from core data using below :

let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName:"Record")
fetchRequest.resultType = .dictionaryResultType
do {
    records = try context.fetch(fetchRequest)
} catch {
    print("Error fetching data from CoreData")
}
Vini App
  • 7,339
  • 2
  • 26
  • 43
  • I'm getting an error saying _Cannot assign value of type '[Any]' to type '[Record]'_ and when I change it to: `records = try context.fetch(fetchRequest) as! [Record] `I'm getting this error _Could not cast value of type 'NSKnownKeysDictionary1' (0x10639caf8) to Core_Data_App.Record' (0x1055a9360)._ – Chace Sep 18 '17 at 08:22