4

I want to save the JSON Result from web service to Core data, following is the code for JSON parsing.

if let jsonResult = try JSONSerialization.jsonObject(with: JSONData!, options: [.mutableContainers]) as? [String: AnyObject]

If i prints jsonResult, following is the output

["Code": 00, "Desc": success, "iinData": <__NSArrayM 0x1c02531a0>
{
  name = “AAA”;
  iin = 123456;
  isOn = 0;
},
{
  name = "Allahabad Bank";
  iin = 608112;
  isOn = 0;
},
)

I can able to insert Code, Desc into Entity1, but how to insert innData into Entity2 .

Entity1 Structure Entity2 Structure

Following is the code for inserting JSON result into core data

func createEntity1From(dictionary: [String: AnyObject]) -> NSManagedObject? {
    let context = CoreDataStack.sharedInstance.persistentContainer.viewContext
    if let Entity1 = NSEntityDescription.insertNewObject(forEntityName: “ParamDownload”, into: context) as? ParamDownload {
        Entity1.Code= dictionary[“name”] as? String
        Entity1.desc = dictionary[“desc”] as? String
        return Entity1
    }
}
3
  • Use convert to data? Nskeyedarchieve? Commented Sep 28, 2018 at 13:07
  • What did you do to save the parsed JSON to CoreData? It seems you have only used JSONSerialization to decode, but did nothing to convert the data to the CoreData-format you created. Commented Sep 28, 2018 at 13:28
  • 1
    Thanks or your reply. I updated the code for inserting the data into entity1. Can you please explain me how to insert innData into Entity2. As this is one to many relationship datas. Commented Oct 8, 2018 at 8:15

3 Answers 3

9

It's quite easy to decode the JSON directly into Core Data with Decodable

  • First of all create extensions of CodingUserInfoKey and JSONDecoder to be able to pass the managed object context

    extension CodingUserInfoKey {
        static let context = CodingUserInfoKey(rawValue: "context")!
    }
    
    extension JSONDecoder {
        convenience init(context: NSManagedObjectContext) {
            self.init()
            self.userInfo[.context] = context
        }
    }
    
  • Add conformance to Decodable in both classes

    class Name: NSManagedObject, Decodable {
    
    class ParamDownload: NSManagedObject, Decodable {
    
  • In the class Name (not the extension) add

    private enum CodingKeys: String, CodingKey { case name, iin, isOn }
    
    required convenience init(from decoder: Decoder) throws {
        guard let context = decoder.userInfo[.context] as? NSManagedObjectContext else { fatalError("NSManagedObjectContext is missing") }
        let entity = NSEntityDescription.entity(forEntityName: "Name", in: context)!
        self.init(entity: entity, insertInto: context)
        let values = try decoder.container(keyedBy: CodingKeys.self)
        name = try values.decode(String.self, forKey: .name)
        iin = try values.decode(String.self.self, forKey: .iin)
        isOn = try values.decode(Bool.self.self, forKey: .isOn)
    }
    
  • In the class ParamDownload (not the extension) add

    private enum CodingKeys: String, CodingKey { case code = "Code", desc = "Desc", names = "iinData" }
    
    required convenience init(from decoder: Decoder) throws {
        guard let context = decoder.userInfo[.context] as? NSManagedObjectContext else { fatalError("NSManagedObjectContext is missing") }
        let entity = NSEntityDescription.entity(forEntityName: "ParamDownload", in: context)!
        self.init(entity: entity, insertInto: context)
        let values = try decoder.container(keyedBy: CodingKeys.self)
        code = try values.decode(String.self, forKey: .code)
        desc = try values.decode(String.self, forKey: .desc)
        names = try values.decode(Set<Name>.self, forKey: .names)
        names.forEach { $0.pd = self }
    }
    

To decode the JSON create the Decoder with the convenience initializer

let decoder = JSONDecoder(context: CoreDataStack.sharedInstance.persistentContainer.viewContext)

the init methods handle the relationships.

I recommend to declare the Core Data attributes as much non-optional as possible.
If an attribute must be remain optional replace decode with decodeIfPresent.

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for your reply. Its working fine with some changes .
@vadian The mechanics makes sense - the inits create an entity, initialise the properties, and set the relationship where appropriate. But how are you actually initialising the decoding? i.e. #what?# = decoder.deocde(#what?#.self, from: data). Is the returned data structure even needed, or just a .save() as the data is already committed to context?
@flanker The record is created in the self.init(entity: entity, insertInto: context) line and the context (passed by the JSONDecoder) needs to be saved.
@vadian Thanks. Get that bit. It was more how to do you get the json into the decoder in the first place. Just had a quick play and let _ = decoder.decode[MyType].self, from: jsonAsData); try? moc.save() did the job, but it seems inelegant and I was wondering if there was a smarter way of initialising he decoding?
Sorry I don’t get it. The first snippet is the extension to put the context in the userInfo dictionary. The JSON is decoded directly into the NSManagedObject instance in the convenience initializer. Yes, just decoding [MyType].self does the job and it’s rather elegant.
0

I save JSON by converting it in into Data and save that Data in CoreData

Following Code works for me......

func saveSpotsLocation(model: SpotsModel, packageId: String, regionName: String) {
  let newUser = NSEntityDescription.insertNewObject(forEntityName: "SpotsDetail", into: context)
  do {
    let data = NSKeyedArchiver.archivedData(withRootObject: model.dictionaryRepresentation())
    newUser.setValue(data, forKey: "data")
    newUser.setValue(packageId, forKey: "packageId")
    newUser.setValue(regionName, forKey: "regionName")
    try context.save()
  } catch {
    print("failure")
  }
}

Comments

-1

This also worked fine for me,

private func createParamDownloadEntityFrom(dictionary: [String: AnyObject]) -> NSManagedObject? {
    let context = CoreDataStack.sharedInstance.persistentContainer.viewContext

    if let paramEntity = NSEntityDescription.insertNewObject(forEntityName: “ParamDwonload”, into: context) as? ParamDownload {
        paramEntity.code = dictionary[“code”] as? String
        paramEntity.desc = dictionary[“desc”] as? String
        let innData = dictionary["iinData"] as! NSArray


        for i in 0..<(innData.count-1) {

            if let nameEntity = NSEntityDescription.insertNewObject(forEntityName: Name
                , into: context) as? Name {

                if let val = innData[i] as? [String: Any] {
                    nameEntity.bankName = val[“name"] as? String
                    nameEntity.iin = val[“iin"] as? String
                    if let isOn = Int16(val[“isOn"] as! String) {
                        nameEntity.isOnus = isOn
                    }
                    paramEntity.addToNames(nameEntity)
                }

            }
        }
        return paramEntity
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.