Monday 24 September 2018

UITableViewCell Animation

Hello friends,
This article is use for UITableViewCell animation.
In most of the application for represent data you can use UITableView.
When UITableView represent at that time you need to animated UITableViewCell for best UI experience of application.

How to use
You need to implement UITableView method 

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
     
        ///Animation code
    
    }

Now you need to developed FadeIn animation like this

cell.alpha = 0
        UIView.animate(withDuration: 0.1, delay: (0.1 * Double(indexPath.row)),  animations: {
            cell.alpha = 1.0
        }, completion: nil)

For more animation see this video



For above animation I have created extension for UITableViewCell

extension UITableViewCell{
    
    /// Table view cell fade in animation for best way to represent
    /// tableview
    ///
    /// - Parameters:
    ///   - duration: animation duration default value 0.1
    ///   - index: cell index
    func fadeInAnimation(withDuration duration: Double = 0.1,forIndex index : Int) {
        self.alpha = 0
        UIView.animate(withDuration: duration, delay: (duration * Double(index)),  animations: {
            self.alpha = 1.0
        }, completion: nil)
    }
    
    /// Table view cell bounce animation for best way to represent
    /// tableview
    ///
    /// - Parameters:
    ///   - duration: animation duration default value 0.8
    ///   - delay: animation delay default value 0.05
    ///   - index: cell index
    func bouncingAnimation(withDuration duration: Double = 0.8,withDelay delay : Double = 0.05,forIndex index : Int) {
        self.transform = CGAffineTransform(translationX: 0, y: self.frame.height)
        UIView.animate(withDuration: duration,delay: delay * Double(index),usingSpringWithDamping: 0.8,initialSpringVelocity: 0.1,animations: {
            self.transform = CGAffineTransform(translationX: 0, y: 0)
        })
    }
    
    /// Table view cell move in animation for best way to represent
    /// tableview
    ///
    /// - Parameters:
    ///   - duration: animation duration default value 0.5
    ///   - delay: animation delay default value 0.08
    ///   - index: cell index
    func moveInAnimation(withDuration duration: Double = 0.5,withDelay delay : Double = 0.08,forIndex index : Int) {
        self.alpha = 0
        self.transform = CGAffineTransform(translationX: 0, y: self.frame.height / 2)
        UIView.animate(withDuration: duration,delay: delay * Double(index),animations: {
            self.alpha = 1
            self.transform = CGAffineTransform(translationX: 0, y: 0)
        })
    }
    
    /// Table view cell right side to in animation for best way to represent
    /// tableview
    ///
    /// - Parameters:
    ///   - duration: animation duration default value 0.5
    ///   - delay: animation delay default value 0.08
    ///   - index: cell index
    func rightInAnimation(withDuration duration: Double = 0.5,withDelay delay : Double = 0.08,forIndex index : Int) {
        self.transform = CGAffineTransform(translationX: self.bounds.width, y: 0)
        UIView.animate(withDuration: duration,delay: delay * Double(index),animations: {
            self.transform = CGAffineTransform(translationX: 0, y: 0)
        })
    }
    
    /// Table view cell left side to in animation for best way to represent
    /// tableview
    ///
    /// - Parameters:
    ///   - duration: animation duration default value 0.5
    ///   - delay: animation delay default value 0.08
    ///   - index: cell index
    func leftInAnimation(withDuration duration: Double = 0.5,withDelay delay : Double = 0.08,forIndex index : Int) {
        self.transform = CGAffineTransform(translationX: -self.bounds.width, y: 0)
        UIView.animate(withDuration: duration,delay: delay * Double(index),animations: {
            self.transform = CGAffineTransform(translationX: 0, y: 0)
        })
    }
}

And you can simply use like 

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        if (animationType == .bounce){
            cell.bouncingAnimation(forIndex: indexPath.row)
        }else if (animationType == .moveIn){
            cell.moveInAnimation(forIndex: indexPath.row)
        }else if (animationType == .leftIn){
            cell.leftInAnimation(forIndex: indexPath.row)
        }else if (animationType == .rightIn){
            cell.rightInAnimation(forIndex: indexPath.row)
        }else if (animationType == .side){
            if (indexPath.row % 2 == 0){
                cell.leftInAnimation(forIndex: indexPath.row)
            }else{
                cell.rightInAnimation(forIndex: indexPath.row)
            }
        }else{
            cell.fadeInAnimation(forIndex: indexPath.row)
        }
    }

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

Thank you.

Wednesday 19 September 2018

Optional Types

Optional represents either wrapped value or nil.
Optionals are generic enum type that works as wrapper.

Basically wrapper allow variable have 2 states:

  1. User define type
  2. nil (that represent no value)
In swift nil value must be optional.
Optional can be created by appending either "?" or "!".

example :

var name : String? = nil
var lname : String! = nil

"?" must be explicitly unwrapped where as "!" automatically unwrapped.
Conditionally unwrapped use "?" optional binding where as force unwrapped use "!" operator. If you force unwrapped variable and value is nil then program will throw exception and crash so be careful.

example :

var lname : String! = nil
print(lname!)

Output :

fatal error: unexpectedly found nil while unwrapping an Optional value

Safe unwrapping :

Using if-let statement safe unwrap

example :

func safeUnwrap(withName name : String?){
    if let userName = name{
        print(userName)
    }else{
        print("name value is nil")
    }
}

safeUnwrap(withName: "Pratik")

Output :

Pratik

safeUnwrap(withName: nil)


Output :

name value is nil

Using guard-let statement safe unwrap

example :

func safeUnwrap(withName name : String?){
    guard let userName = name else{
        print("user name not found")
        return
    }
    print(userName)
}

safeUnwrap(withName: "Pratik")

Output :

Pratik

safeUnwrap(withName: nil)


Output :

user name not found

Using Coalescing operator safe unwrap

example :

var name : String? = nil
print(name ?? "name value is nil")


Output :

name value is nil

var name : String? = nil
name = "Pratik"
print(name ?? "name value is nil")


Output :

Pratik

You can also use Optional chaining in order to call method,property or subscript.

example : 

struct Family{
    func printName() {
        print("Hello friends")
    }
}

var objFamily : Family?
objFamily?.printName()

Output :

no print 

var objFamily : Family? = Family()
objFamily?.printName()

Output :

Hello friends



unwrapped using optional type in swift
Optional types unwrapped

Monday 17 September 2018

Logger

Hello friends this article is use for developer debugging print values in LLDB debug area.
There are multiple functions available in swift

print(),debugPrint(),dump(),NSLog()

use of these functions in swift

print : print(_ items: Any..., separator: String = default, terminator: String = default)

print is use for some textual representations in debug area. 

example : 

print("hello friends")

Output : 

hello friends

debugPrint : debugPrint(_ items: Any..., separator: String = default, terminator: String = default)

debugPrint is use for shows the instance of some textual representations in debug area.

example : 

debugPrint("hello friends")

Output : 

"hello friends"

dump : dump<T>(_ value: T, name: String? = default, indent: Int = default, maxDepth: Int = default, maxItems: Int = default)

dump is use for print the contents of an object via reflection like mirroring. dump prints details hierarchy

example : 

dump(["iOS","Android"])

Output : 

2 elements
  - "iOS"
  - "Android"

NSLog : NSLog(_ format: String, _ args: CVarArg...)

NSLog is use for print the contents with timestamp. It will also print project_name along with timestamp.

example :

NSLog("hello iOS developers")

Output : 

2018-09-17 15:18:10.522 DebuggerDemo[2022:4583274]hello iOS developers

print() vs dump()

Let’s create simple “Student” class

class Student{
    let name = "Pratik"
    let lname = "Lad"
}

now print Student() class using print() & dump() 

print(Student())

Output :

__lldb_expr_81.Student

dump(Student())

Output : 

__lldb_expr_81.Student #0
  - name: "Pratik"
  - lname: "Lad"

You can see the difference of printing in debug area result. print() simple print the class name where as dump() print the whole class hierarchy. 

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.