Sunday, 16 September 2018

class vs struct

Class

  • class is reference type.
  • class object is created on Heap memory.
  • For class member variable can initialised directly.
  • class have constructor and destructor methods of all types.
  • class can inherit another class.
  • class are good for larger or complex object.

Struct


  • struct is value type.
  • struct object is created on Stack memory.
  • For struct member vaiable can not initialised directly.
  • struct can't be abstract.
  • stucts are good for small and isolated model object.  


Example of class

created one Student class with name and lname property with init method
class Student{
    var name : String?
    var lname : String?
    init(name : String?,lname : String?) {
        self.name = name
        self.lname = lname
    }

}
- now create one object for Student class called objStudent and print
let objStudent = Student(name: "Pratik", lname: "Lad")
dump(objStudent)

Output :
__lldb_expr_44.Student #0
  name: Optional("Pratik")
    - some: "Pratik"
  lname: Optional("Lad")
    - some: "Lad"

- now one more object create and assign older object of Student class
let obj1Student = objStudent
- now change the name of obj1Student object
obj1Student.name = "Bunty"
- now print both object 
dump(objStudent)

Output :
__lldb_expr_44.Student #0
  name: Optional("Bunty")
    - some: "Bunty"
  lname: Optional("Lad")
    - some: "Lad"

dump(obj1Student)

Output :
__lldb_expr_44.Student #0
   name: Optional("Bunty")
    - some: "Bunty"
   lname: Optional("Lad")
    - some: "Lad"
you can see the objStudent object name also change because class is reference type.

Example of struct

created one Student struct with name and lname property with init method
struct Student{
    var name : String?
    var lname : String?
    init(name : String?,lname : String?) {
        self.name = name
        self.lname = lname
    }

}
- now create one object for Student struct called objStudent and print
let objStudent = Student(name: "Pratik", lname: "Lad")
dump(objStudent)

Output :
__lldb_expr_44.Student #0
   name: Optional("Pratik")
    - some: "Pratik"
   lname: Optional("Lad")
    - some: "Lad"

- now one more object create and assign older object of Student struct
var obj1Student = objStudent
- now change the name of obj1Student object
obj1Student.name = "Bunty"
- now print both object 
dump(objStudent)

Output :
__lldb_expr_44.Student #0
   name: Optional("Pratik")
    - some: "Bunty"
   lname: Optional("Lad")
    - some: "Lad"

dump(obj1Student)

Output :
__lldb_expr_44.Student #0
   name: Optional("Bunty")
    - some: "Bunty"
   lname: Optional("Lad")
    - some: "Lad"
you can see the objStudent and obj1Student object name not change because struct is value type.

Thanks for reading this article.



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.