Codable with CoreData

Monday, 10 September 2018

Codable with CoreData

Swift define standard approach to data encoding and decoding which combines the Encodable and Decodable protocols that is called Codable.

In this block I illustrated Codable using API parse and store into CoreData.
First you need to create entity called "List" and create attribute(id,user_id,title,body) like below

CoreData
List Entity

and then create NSManageObject subclass for List entity.
Now create encode and decode method like below

import Foundation
import CoreData

@objc(List)
public class List: NSManagedObject,Codable {
    
    ///From api response key if changed
    enum apiKey: String, CodingKey {
        case id
        case user_id = "userId"
        case title
        case body
    }

    // MARK: - Decodable
    required convenience public init(from decoder: Decoder) throws {
        
        ///Fetch context for codable
        guard let codableContext = CodingUserInfoKey.init(rawValue: "context"),
            let manageObjContext = decoder.userInfo[codableContext] as? NSManagedObjectContext,
            let manageObjList = NSEntityDescription.entity(forEntityName: "List", in: manageObjContext) else {
                fatalError("failed")
        }
        
        self.init(entity: manageObjList, insertInto: manageObjContext)
        
        let container = try decoder.container(keyedBy: apiKey.self)
        self.user_id = try container.decodeIfPresent(Int64.self, forKey: .user_id) ?? 0
        self.id = try container.decodeIfPresent(Int64.self, forKey: .id) ?? 0
        self.title = try container.decodeIfPresent(String.self, forKey: .title)
        self.body = try container.decodeIfPresent(String.self, forKey: .body)
    }
    
    // MARK: - encode
    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: apiKey.self)
        try container.encode(user_id, forKey: .user_id)
        try container.encode(id, forKey: .id)
        try container.encode(title, forKey: .title)
        try container.encode(body, forKey: .body)
    }

}

Now send server request and parse response using Codable and store into CoreData.

///get data from api
    func getListData()  {
        guard let listURL = URL(string: "https://jsonplaceholder.typicode.com/posts/")else {
            return
        }
        URLSession.shared.dataTask(with: listURL){
            (data,response,error) in
            guard let jsonData = data else { return }
            DispatchQueue.main.async {
                self.parseResponse(forData: jsonData)
            }
        }.resume()
    }
    
    ///parse response using decodable and store data 
    func parseResponse(forData jsonData : Data)  {
        do {
            guard let codableContext = CodingUserInfoKey.init(rawValue: "context") else {
                fatalError("Failed context")
            }
            
            let manageObjContext = appDelegate.persistentContainer.viewContext
            let decoder = JSONDecoder()
            decoder.userInfo[codableContext] = manageObjContext
            // Parse JSON data
            _ = try decoder.decode([List].self, from: jsonData)
            ///context save
            try manageObjContext.save()
            UserDefaults.standard.set(true, forKey: "isAllreadyFetch")
            self.fetchLocalData()
        } catch let error {
            print("Error ->\(error.localizedDescription)")
            self.errorMessage(error.localizedDescription)
        }
    }

And fetch data like below 

    ///Local data fetch from core data
    func fetchLocalData()  {
        let manageObjContext = appDelegate.persistentContainer.viewContext
        let fetchRequest = NSFetchRequest<List>(entityName: "List")
        ///Sort by id
        let sortDescriptor = NSSortDescriptor(key: "id", ascending: true)
        fetchRequest.sortDescriptors = [sortDescriptor]
        do {
            self.arrayOfList = try manageObjContext.fetch(fetchRequest)
        } catch let error {
            print(error)
            self.errorMessage(error.localizedDescription)
        }
    }

The sample code for illustrated in this post is available on GitHub
Thank you.

0 Comment on "Codable with CoreData"

Post a Comment

MVVM

Swift MVVM design pattern

Design pattern is an important part for code reusability. History Since the beginning of it's development, iOS has used MVC (Mo...