Thursday, 19 January 2017

Operation on Collection in Swift

In iOS app development we need to perform some task on collection (Array,dictionary..) in swift. For example to get the sum of the element in an array we could go for for-in loop . Do code like this:

let arr =  [1,3, 4,6,9]

var sum = 0
for i in arr{
sum += i
}

We can achieve such kind of task very easily with a line of code.

Working with Map, filter, reduce and flatMap:

To get the sum of all element we can write

let sum =  arr.reduce(0,+)

Map:

We use map to  loop over the collection and apply a same  on each element in collection. For example to get the square of of each element in an array we could go for for in loop and to square of each element in an array.

With map, we can do this task this way:
let arr = [1,2,4,5,6,7,8,9]

let squares =  arr.map{$0 * $0}

The map function has a single argument which is a closure. Map function calls this closure as it loop over the collection. This closure takes an element from the collection as an argument and returns result. The map function return the result in an array.

We can  write above line of code as:

let squares2 =  arr.map{element in   element * element}

The keyword  in separates  the argument from the body of the closure .

The map operation can be performed on each collection type it is not limited to just an array. We can use this with dictionary, set also. But the result of the operation is always an array.

Filter: We use filter where we want to filter the collection  of data with a condition. Filter function loop over the collection  and returns only those element from the collection which satisfy  a given condition in include.

let arrData  = [1,23,45,,4,6,8,3]

For example : To get only those element from above array which is even, we write:

let arrEven = arrData.filter{ $0 %2 == 0}

Reduce: reduce method used to combine all elements in a collection to create a single value . The reduce() method takes two arguments, an initial value and a closure

let  fullStatement  = arr.reduce("==") {text, name in "\(text),\(name)"}

FlatMap: Used to flatten to  collection of   collections.

let complexArray  = [[2,3,5],[34,56], [34,56,78]]

let flat =  complexArray.flatMap {$0 }

The above line of code will combine all sub array  from complexArray into  a single array.

With flatMap and  chaining of the above methods we can solve complex queries on collection .

For example: get all even elements from complexArray

let   evenNums  = complexArray.flatMap{ 
                  subArray in subArray.filter{ $0 %2 == 0}
             }

In short form we can write above line as:
let evenInShortForm =  complexArray.flatMap { $0.filter{ $0 %2 == 0  }}

References:http://useyourloaf.com

Thursday, 12 January 2017

Sort Array in swift


To sort an array we can use sort() which all arrays have in default. We can use sort() and sorted() to sort an array.

To sort an simple array like this, we can use sort() as:

var arr =  [ "orange","Apple" "Grapes","banana"]

arr.sort()


To sort an array of custom object like custom struct or class we  use sort() using a trailing closure that sort an array on field we specify.

For example: We have an array of custom object Opportunity which have a string field date . So to sort this array on date field, here we will first convert string date to Date object . Let's have a look on below code:To sort arrOpportunities on a string field say title,

arrOpportunities.sort{

$0.title.compare($1.title) == NSComparisonResult.OrderedAscending
}

 If we have title say:
["hello","ok","arm","Basket"]  then using  above code will results in

["Basket","arm","hello","ok"]

To get results in ignoring the case we can use localizedCompare() like this:

arrOpportunities.sort{

$0.title.localizedCompare($1.title) == NSComparisonResult.OrderedAscending
}

will result in
["arm","Basket","hello","ok"]

If we want to return an array after doing sort we can use sorted() like this

var arr_sorted =  arrOpportunities.sorted{

$0.title.localizedCompare($1.title) == NSComparisonResult.OrderedAscending
}

Tuesday, 27 December 2016

Integrate third party library in an iOS project:


In iOS app development we need many other libraries to be included in our app to accomplish set of task. There are number of ways by which we can include these library  in our project .

1) Using Cocoapods 

Cocoa pod is dependency manager . It is very simple to add library this way . Go to project directory and follow these steps:

a) Run pod init  command
    The above command will initialize the pod in project directory and creates a pod file. 
b) Now open the pod file and add  required library in this file . And save the file .
c) Run pod install command .
    This will install the library in project directory  and creates a xcworkspace  file in project directory .

     From now open the xcworkspace instead of Xcode project . 

2) Manually:

Using this way , we just drag and drop the required files/folder of required library to our project.

3) using git sub module:


Using this way we add a third party project using git command . This command will add third party library as a submodule in our project.

a) Go to your project directory , initialize git if git is not initialized in project directory .
      
     git init 
   
 b) git submodule add  project-url

    The above command will add third party library at given url as a sub module in our project .


Thursday, 8 December 2016

Manage navigation controller

In iOS app development UINavigationController play a vital role . As we all know UINavigationController keeps the stack of view controller when we use in our app for transition among view controllers .

We face many problems related to UINavigationController like change appearance of the navigation bar, add UIBarButton items to navigation bar , combine the status bar with navigation bar and some others. All these tasks seem very easy at first look but it depends on our requirements .

In my recent app I want to use the navigation bar with two buttons (left and right bar button item)in all view controller and also want the color of status bar and navigation bar should be same . 

1) To change the appearance of the UINaviagtionBar, we can code in our AppDelegate this will reflect in all view controllers: 

    var navBarAppearance = UINavigationBar.appearance()

    navBarAppearance.tintColor = UIColor.white

    navBarAppearance.barTintColor  = UIColor.init(red: 73/255.0, green: 180/255.0, blue: 255/255.0, alpha: 1)

 a) Here tintColor attribute will change the background color of the navigation bar .
 b) Bar tint color will change the color of button titles and  button images.

The above two properties won't change the color of the title of the navigation bar. To change the color of the title use this line of code:
   
   navBarAppearance.titleTextAttributes = [NSForegroundColorAttributeName:UIColor.white]


 2) Change the status bar color:

  UIApplication.shared.statusBarStyle = .lightContent

This will not change the color of the status bar. To reflect the change we need to make one more change in our info.plist file:
set UIViewControllerBasedAppearance to false

3) Add bar button items to all view controller: This was my requirement to have two buttons in navigation bar in all view controllers: I can not achieve this like appearance. Because bar buttons are added to navigation item property of the view controller. Each view controller have its own navigation item . 
So to add bar  buttons to all view controller:

a) Add in viewDidLoad() of each view controller
b) Make a Utility class and add a class function to it and call this from each view controller's viewDidLoad() or any other methods of view life cycle as per your need .
c) Make an separate subclass of UIViewController and add two bar buttons here in this class and change the super class of your view controller from UIViewController to one you created previous .

I will  choose the last approach. Add this code in your subclass:
     let leftBtn = UIBarButtonItem(image: UIImage(named:"back_btn_icon"), style: .plain, target: self, action: #selector(backBtnTapped))
   self.navigationItem.leftBarButtonItem = leftBtn

    let rightBtn = UIBarButtonItem(image: UIImage(named:"setting_icon"), style: .plain, target: self, action: #selector(settingBtnTapped))

    self.navigationItem.rightBarButtonItem = rightBtn

What if one of your view controller need only one bar button. It's easy we can hide the unwanted button:
 To hide the left button add this line your view controller:

self.navigationItem.leftBarButtonItems?.remove(at: 0)



Reference: Stackoverflow and https://coderwall.com



Friday, 2 December 2016

Set attributed text in interface builder

 1) Increase font size as size of UILabel increases:

There may be a requirement to increase the font size as the size of UILabel increases.To see this in action, Open Xcode and switch to xib/storyboard file and follow these steps:

Take a UILabel and  set height of the UILabel to the proportional to the height of screen . and set other required constraint on UILabel.
Then set some properties of UILabel to have font size proportional to the size of UILabel.

a) Set AutoShrink to minimum font size
b) set number of lines to 0
c) set the font size bigger as the maximum size of UILabel .


2) Set Attributed text in interface builder for a UILabel:

We can set attributed text programatically by setting different attributes like font, color, size on a attributed string(instance of NSAttributedString) . But there is an easy way , we can create an attributed text without typing even a single line of code.

We can create an attributed text in interface builder. To set attributed text for a UILabel :

a) Change text type  plain to attributed  in the attributes inspector window.
b) Then type the string as your requirements.
c) Then select  word you want to change the appearance  of and change it's size, font family, color etc. 

Thursday, 10 November 2016

Change in privacy setting in iOS10

There is one major change in iOS 10 when using some framework. With iOS 10 , now we have to ask for accessing user's private data like camera, photos, contacts ,microphone etc . Now with release of iOS 10, we must declare the usage of any private data in info.plist, otherwise our application will crash when accessing these data .

The list of framework that counts as sensitive data is:







We must declare the usage description of these in info.plist as:




















These are the key for which we have to provide the usage description in info.plist .

References
useyourloaf.com
https://developer.apple.com/library/prerelease/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html

Friday, 4 November 2016

Custom UI Elements with IBDesignable

In Xcode 6 two new interface builder declaration attributes were added: IBDesignable and IBInspectable.

IBDesignable updates the view in real time. We prefix out class with @IBDesignable keyword to inform interface builder that the class' instance will try to design  themselves when added to the storyboard:

@IBDesignable class MyCustomView: UIView{

}

Then we prefix any properties of the class with @IBInspectable to ensure that interface builder can read and write the value of these properties directly in the inspector view.

With these two new keyword we can create custom UI controls as per our need and use them directly in interface builder and can change their properties in inspector view as we do with other built in UI controls . To create a custom UI elements we have to perform following steps:

1) Create a View .Xib file and design the required view .

2) Then setup auto layout constraints.

3) Create a .swift file to write code .

4) Set .xib file's  File's Owner custom class to  the class we created in last step .

5) In .swift file implement initializers: init(coder:) and init(frame:) .

6) Load the UIView from  the .xib file using NSBundle and  UINIb classes .

7) Add the  view as a subview and  property  for the class .

8) Add auto resizing masks for the view to match the size of the Custom View itself .

9) Make the  view's frame to have the same size as in design time  by assigning CustomView's bounds .

Here is the sample class code :

import UIKit

@IBDesignable class MyCustomView: UIView {

let nibName = "MyCustomView"
var view: UIView!

@IBInspectable var date: String = "3/19/1990" {
            
             didSet{
                          
                       }
}


override init(frame: CGRect) {
     super.init(frame)
    setupXib()
}

required init?(coder aDecoder: NSCoder){
     super.init(coder: aDecoder)
     setupXib()
}

func setupXib() -> Void {

view  =  loadFromNib()
view.frame =  bounds
view.autoresizingMask =  [UIViewAutoresizing.FlexibleWidth, UIViewAutoresizing.FlexibleHeight]
addSubview(view)

}

func loadFromNib() -> UIView {

 let bundle =  NSBundle(forClass: self.dynamicType)

 let nib = UINib(nibName: nibName, bundle: bundle)

 let view =  nib.instantiateWithOwner(self, options:nil)[0] as! UIView

 return view
}

}


Resources:
http://supereasyapps.com/blog/2014/12/15/create-an-ibdesignable-uiview-subclass-with-code-from-an-xib-file-in-xcode-6
https://www.weheartswift.com/make-awesome-ui-components-ios-8-using-swift-xcode-6/