Showing posts with label iOS. Show all posts
Showing posts with label iOS. Show all posts

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.

Sunday, 9 September 2018

Tuples

Why Tuples ?
Swift 4 has introduced tuples to help us to return multiple values from a function instead of only one value.
Tuples is multiple values grouped into a single compound value. The values can be of any type, it need not necessarily to be of same type.
Tuples type is comma-seperated list types, enclosed in parentheses.
Tuples are created by grouping any amount of values.

Please check below examples for different uses of tuples :
---------------------------------------------------------------------------------
Displaying tuple value using variable name

1) Same Data type

let multipleValue : (value1 : String,value2 : String) = ("iOS","Android")

print(multipleValue.value1)
print(multipleValue.value2)

Output
iOS
Android
---------------------------------------------------------------------------------
Different Data type

1) Displaying tuple value using index (without variable name)

let multipleValue = ("iOS""Android"5)

print(multipleValue.0
print(multipleValue.1)
print(multipleValue.2)

Output :
iOS
Android
5

2) Displaying tuple value using variable names

let multipleValue = (name: "iOS",name1: "Android",value1: 5)

print(multipleValue.name)
print(multipleValue.name1)
print(multipleValue.value1)

Output :
iOS
Android
5
---------------------------------------------------------------------------------
Displaying tuples as optionals

var multipleValue : (name: String,name1: String?,value1: Int)
multipleValue = ("iOS",nil,5)

print(multipleValue.name)
print(multipleValue.name1)
print(multipleValue.value1)

Output
iOS
nil
5

---------------------------------------------------------------------------------
Tuples usage in function return type

1) Displaying tuple value using index (without variable name)

func test() -> (String,Int) {
    return ("iOS",11)
}

print(test().0)
print(test().1)

Output
iOS
11

2) Displaying tuple value with variable name


func test() -> (name : String,version : Int) {
    return ("iOS",11)
}
print(test().name)
print(test().version)

Output
iOS
11
---------------------------------------------------------------------------------

For more info, click on below link :-

https://www.youtube.com/watch?v=MwOv844k9-4&t=222s




Thank you.


Animation

Animation interaction is best way to deal with different type of interact with application functionality. Now a days Animation is big part of Application for success.
In this article you can create easy way to animated object in Swift Xcode.
If you want to object zoomin, zoomout, move, roted. bounce etc.,

Example of code :

import UIKit

enum Axis {
    case x
    case y
    case both
}
extension UIView{
    func zoomAnimation(withDuration duration: Double, withZoomLevel zoomLevel: CGFloat, complition : ((Bool) -> Swift.Void)?)  {
        UIView.animate(withDuration: duration, animations: {
            self.transform = CGAffineTransform(scaleX: zoomLevel, y: zoomLevel)
        }) { _ in
            UIView.animate(withDuration: duration, animations: {
                self.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
            },completion : {_ in
                complition?(true)
            })
        }
    }
    
    func rotedAnimation(withDuration duration: Double,withAngle angle : CGFloat,withRepetation isRepeat:Bool , complition : ((Bool) -> Swift.Void)?) {
        if isRepeat
        {
            UIView.animate(withDuration: duration, delay: 0.0, options: .repeat, animations: {
                self.transform = self.transform.rotated(by: angle)
            }) { _ in
                complition?(true)
            }
        }
        else
        {
            UIView.animate(withDuration: duration, animations: {
                self.transform = self.transform.rotated(by: angle)
            }, completion: {_ in
                complition?(true)
            })
        }
    }
    
    func moveAnimation(withDuration duration : Double,withAxis axis:Axis,withAnimStepCount step:CGFloat,complition : ((Bool) -> Swift.Void)?) {
        let oldFrame = self.frame
        UIView.animate(withDuration: duration, animations: {
            if axis == .both
            {
                self.frame.origin.x += step
                self.frame.origin.y += step
            }
            else if axis == .y
            {
                self.frame.origin.y += step
            }
            else
            {
                self.frame.origin.x += step
            }
        }) { _ in
            UIView.animate(withDuration: duration, animations: {
                self.frame = oldFrame
            }, completion: { _ in
                complition?(true)
            })
        }
    }
    
    func bounceAnimation(withDuration duration : Double,withAxis axis:Axis,withBounceStepCount step:Int,withAxisStepCount bounceStep : CGFloat ,complition : ((Bool) -> Swift.Void)?) {
        let oldFrame = self.frame
        UIView.animate(withDuration: duration/Double(step), animations: {
            if axis == .x
            {
                self.frame.origin.x  += bounceStep
            }
            else
            {
                self.frame.origin.y += bounceStep
            }
        }, completion: { _ in
            UIView.animate(withDuration: duration/Double(step), animations: {
                if axis == .x
                {
                    self.frame.origin.x -= (bounceStep * 2)
                }
                else
                {
                    self.frame.origin.y -= (bounceStep * 2)
                }
            },completion:{_ in
                complition?(true)
                UIView.animate(withDuration: duration/Double(step), animations: {
                    self.frame.origin.x = oldFrame.origin.x
                    self.frame.origin.y = oldFrame.origin.y
                    
                },completion:{_ in
                    complition?(true)})
            })
        })
    }
}


You can put above code in file and easy to use
-> for example zoom-in object then

obj.zoomAnimation(withDuration: 1.0, withZoomLevel: 0.5, complition: nil)

-> zoom-out

obj.zoomAnimation(withDuration: 1.0, withZoomLevel: 1.5 ,complition: {_ in
            print("zoom complition")
        })

-> Bounce 

        sender.bounceAnimation(withDuration: 1.0, withAxis: .x, withBounceStepCount: 10, withAxisStepCount: 20, complition: nil)


For more info watch this video for different animation 
Github project link is available in video description 




Another example of Add to cart animation 



If you like my video then please like and subscribe and also share with iOS community.

Thank you.





Wednesday, 5 September 2018

LLDB

In Xcode use LLDB debugger command for debug application.
For example app is running and you want to print some variable value at run time then use po command.
There are multiple commands are available in Xcode.
If you need to type help in debug area you can show list of command for lldb

(lldb) help
Debugger commands:
  apropos           -- List debugger commands related to a word or subject.
  breakpoint        -- Commands for operating on breakpoints (see 'help b' for
                       shorthand.)
  bugreport         -- Commands for creating domain-specific bug reports.
  command           -- Commands for managing custom LLDB commands.
  disassemble       -- Disassemble specified instructions in the current
                       target.  Defaults to the current function for the
                       current thread and stack frame.
  expression        -- Evaluate an expression on the current thread.  Displays
                       any returned value with LLDB's default formatting.
  frame             -- Commands for selecting and examing the current thread's
                       stack frames.
  gdb-remote        -- Connect to a process via remote GDB server.  If no host
                       is specifed, localhost is assumed.
  gui               -- Switch into the curses based GUI mode.
  help              -- Show a list of all debugger commands, or give details
                       about a specific command.
  kdp-remote        -- Connect to a process via remote KDP server.  If no UDP
                       port is specified, port 41139 is assumed.
  language          -- Commands specific to a source language.
  log               -- Commands controlling LLDB internal logging.
  memory            -- Commands for operating on memory in the current target
                       process.
  platform          -- Commands to manage and create platforms.
  plugin            -- Commands for managing LLDB plugins.
  process           -- Commands for interacting with processes on the current
                       platform.
  quit              -- Quit the LLDB debugger.
  register          -- Commands to access registers for the current thread and
                       stack frame.
  script            -- Invoke the script interpreter with provided code and
                       display any results.  Start the interactive interpreter
                       if no code is supplied.
  settings          -- Commands for managing LLDB settings.
  source            -- Commands for examining source code described by debug
                       information for the current target process.
  target            -- Commands for operating on debugger targets.
  thread            -- Commands for operating on one or more threads in the
                       current process.
  type              -- Commands for operating on the type system.
  version           -- Show the LLDB debugger version.
  watchpoint        -- Commands for operating on watchpoints.
Current command abbreviations (type 'help command alias' for more info):
  add-dsym  -- Add a debug symbol file to one of the target's current modules
               by specifying a path to a debug symbols file, or using the
               options to specify a module to download symbols for.
  attach    -- Attach to process by ID or name.
  b         -- Set a breakpoint using one of several shorthand formats.
  bt        -- Show the current thread's call stack.  Any numeric argument
               displays at most that many frames.  The argument 'all' displays
               all threads.
  c         -- Continue execution of all threads in the current process.
  call      -- Evaluate an expression on the current thread.  Displays any
               returned value with LLDB's default formatting.
  continue  -- Continue execution of all threads in the current process.
  detach    -- Detach from the current target process.
  di        -- Disassemble specified instructions in the current target. 
               Defaults to the current function for the current thread and
               stack frame.
  dis       -- Disassemble specified instructions in the current target. 
               Defaults to the current function for the current thread and
               stack frame.
  display   -- Evaluate an expression at every stop (see 'help target
               stop-hook'.)
  down      -- Select a newer stack frame.  Defaults to moving one frame, a
               numeric argument can specify an arbitrary number.
  env       -- Shorthand for viewing and setting environment variables.
  exit      -- Quit the LLDB debugger.
  f         -- Select the current stack frame by index from within the current
               thread (see 'thread backtrace'.)
  file      -- Create a target using the argument as the main executable.
  finish    -- Finish executing the current stack frame and stop after
               returning.  Defaults to current thread unless specified.
  image     -- Commands for accessing information for one or more target
               modules.
  j         -- Set the program counter to a new address.
  jump      -- Set the program counter to a new address.
  kill      -- Terminate the current target process.
  l         -- List relevant source code using one of several shorthand formats.
  list      -- List relevant source code using one of several shorthand formats.
  n         -- Source level single step, stepping over calls.  Defaults to
               current thread unless specified.
  next      -- Source level single step, stepping over calls.  Defaults to
               current thread unless specified.
  nexti     -- Instruction level single step, stepping over calls.  Defaults to
               current thread unless specified.
  ni        -- Instruction level single step, stepping over calls.  Defaults to
               current thread unless specified.
  p         -- Evaluate an expression on the current thread.  Displays any
               returned value with LLDB's default formatting.
  parray    -- Evaluate an expression on the current thread.  Displays any
               returned value with LLDB's default formatting.
  po        -- Evaluate an expression on the current thread.  Displays any
               returned value with formatting controlled by the type's author.
  poarray   -- Evaluate an expression on the current thread.  Displays any
               returned value with LLDB's default formatting.
  print     -- Evaluate an expression on the current thread.  Displays any
               returned value with LLDB's default formatting.
  q         -- Quit the LLDB debugger.
  r         -- Launch the executable in the debugger.
  rbreak    -- Sets a breakpoint or set of breakpoints in the executable.
  repl      -- Evaluate an expression on the current thread.  Displays any
               returned value with LLDB's default formatting.
  run       -- Launch the executable in the debugger.
  s         -- Source level single step, stepping into calls.  Defaults to
               current thread unless specified.
  si        -- Instruction level single step, stepping into calls.  Defaults to
               current thread unless specified.
  sif       -- Step through the current block, stopping if you step directly
               into a function whose name matches the TargetFunctionName.
  step      -- Source level single step, stepping into calls.  Defaults to
               current thread unless specified.
  stepi     -- Instruction level single step, stepping into calls.  Defaults to
               current thread unless specified.
  t         -- Change the currently selected thread.
  tbreak    -- Set a one-shot breakpoint using one of several shorthand
               formats.
  undisplay -- Stop displaying expression at every stop (specified by stop-hook
               index.)
  up        -- Select an older stack frame.  Defaults to moving one frame, a
               numeric argument can specify an arbitrary number.
  x         -- Read from the memory of the current target process.

For more information on any command, type 'help <command-name>'.

If you get info about perticuler command then type

(lldb) help po
     Evaluate an expression on the current thread.  Displays any returned value
     with formatting controlled by the type's author.  Expects 'raw' input (see
     'help raw-input'.)

Syntax: 

Command Options Usage:
  po <expr>


'po' is an abbreviation for 'expression -O  --'


LLDB is also use-full in edit debug point to evaluate condition or execute any above lldb command.



Watch my video for live demo of some lldb commands


If you like my video then please like and subscribe my channel and also share it.

Thank you.