Monday 26 June 2017

Protocol in Swift

There are three main pillar of swift that provides facility to write your code in a way which will decrease the size of code and also improve make your code scalable , easy to read and maintainable.

These pillar are:
1) Value types
2) Functional programming
3) Protocol oriented programming

In swift for value types we use struct and enum. Value types copied when they are assigned, passed as argument to function. We won’t dive in deep for value type and functional programming here. In this blog I am going to discuss about protocol oriented programming. 


     protocol  TestProtocol{
        func  sayHello()
       
    }

    Like classes, we can inherit protocol also.
   
    struct Person: TestProtocol{
         
      //implement TestProtocol here
      func sayHello(){
       print(“Hi”)
        }

    }

   Protocol Extension:                                

 It’s not necessary to always implement a protocol . You can provide the default definition of a protocol in Protocol extension. You can also provide your implementation , in this case you will override the default implementation.

    extension TestProtocol{
    
  func sayHello(){
       print(“default implementation ”)
        }

    }

   If a protocol extension provide the definition of a function , then it’s not necessary to implement a protocol on the type which conforms it.

    struct Area:TestProtocol{

    }

    Area().sayHello


In protocol we declare the type and tell it what to do but not how to do. A protocol is like a coach , he tells the player what to do . Protocol is like interface in JAVA. Let’s understand protocol with an example:

Let’s say you have page in which you have two UILabel and a UIButton and main UIView of  your screen. Now  each UILabel and UIButton have a series of animation. 

So What approach will you take here:

1) You can directly write your animation code in main view controller in place where you want, this could be worst approach. What if you want other views to have same animation? So here comes the second approach.

2) In this approach , you can subclass your UILabel and UIButton to have animation and in future if you want other UILabel and UIButton to have same animation , you just replace their class. 

3) As you will say , swift provide even a better approach than subclassing , As we know UILabel and UIButton has the same parent UIView. So you can create an extension to UIView and write animation there. This is good approach, but this will open this for all views in your application. So here comes the Protocol .

In Protocol you just declare what to do and then each control which wants to have animation must have to implement this.

Protocol  Fadable{
}

extension Fadable where  Self:UIView{
   func fade{
      //do your animation here
    }
 }

So any UIComponents that conforms to Fadable protocol would have the fade() method with it. Here  where  Self:UIView used to indicate  that the protocol  should be only conformed  to UIView or view which are inherited from UIView.


class MyLable:UILabel, Fadable{
  //write your code
}


Reference:

Sunday 18 June 2017

Background color of status bar

UINavigationBar includes status bar which is of 20 points in height of UINavigationBar. Thus the actual default height of UINavigationBar is 44 point. 
When we change the background color of UINavigationBar, it includes the background color of status bar also. Thus by setting the background color of UINavigationBar with 

        UINavigationBar.appearance().barTintColor = UIColor.Red

will set the background color of navigation bar as well as status bar to red.

Thus to set the different background color of status bar other than navigation bar's tint color, you can use these line of code in your application at appropriate place:

        //change appearance of status bar
        
        UINavigationBar.appearance().clipsToBounds = true
        //get the status bar
        let statusBar: UIView? = UIApplication.shared.value(forKey: "statusBar") as? UIView
        //set background color
        statusBar?.backgroundColor = UIColor.white

Sunday 11 June 2017

UIImagePickerController in Swift

In iOS app development UIImagePickerController is used to access the picture either from the camera or photos app. It's very easy to use UIImagePickerController. But what if we want to access image picker more than once in an iOS app. Here we don't want redundant code .

In swift it's very easy to write code which can be used all over the application. Yes the rescue is the extension. We can create an extension of UIViewController which can be called from every view controller where we want to present the image picker.

In iOS 10, first of all we have to declare the usage of camera and photos app in info.plist.

Then create an extension of UIViewController to present image picker:

 func imagePickerControllerWith(delegate:(UIImagePickerControllerDelegate & UINavigationControllerDelegate)?){
        let actionSheet =  UIAlertController(title: "YakYapp", message: "", preferredStyle: .actionSheet)
        
        let camera  = UIAlertAction(title: "Camera", style: .default) { (cameraAction) in
            
            let mediaType = AVMediaTypeVideo
            
            let authorizationStatus =  AVCaptureDevice.authorizationStatus(forMediaType: mediaType)
            
            if authorizationStatus == .authorized{
                self.prsentImagePickerWith(option: "Camera",delegate: delegate)
                
            }else if authorizationStatus == .notDetermined{
                AVCaptureDevice.requestAccess(forMediaType: mediaType, completionHandler: { (newStatus) in
                    if newStatus {
                        let authorizationStatus1 =  AVCaptureDevice.authorizationStatus(forMediaType: mediaType)
                        if authorizationStatus1 == .authorized{
                            self.prsentImagePickerWith(option: "Camera",delegate: delegate)
                        }
                        
                    }else{
                        
                    }
                })
            }else{
                
                let message = "It seems access for camera is denied for Spirosure. To make it work, Go to Setting -> Privacy -> Camera and enable the access for the app"
                self.showAlertWith(message: message, title: "", handler: nil)
            }
        }
        
        let gallery  = UIAlertAction(title: "Photo Album", style: .default) { (galleryActn) in
            
            let status = PHPhotoLibrary.authorizationStatus()
            
            switch status{
                
            case .authorized:
                self.prsentImagePickerWith(option: "PhotoAlbum",delegate: delegate)
            case .notDetermined:
                PHPhotoLibrary.requestAuthorization({ (newStatus) in
                    if newStatus == PHAuthorizationStatus.authorized{
                        self.prsentImagePickerWith(option: "PhotoAlbum",delegate: delegate)
                        
                    }else{
                        
                    }
                })
            default:
                self.showAlertWith(message: "The access is not granted to use photo library. Go to Setting app to change the access for the app.", title: "", handler: nil)
                
            }
        }
        
        let cancel  = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
        
        actionSheet.addAction(camera)
        actionSheet.addAction(gallery)
        actionSheet.addAction(cancel)
        self.present(actionSheet, animated: true, completion: nil)
        
    }
    
   private func prsentImagePickerWith(option:String,delegate:(UIImagePickerControllerDelegate & UINavigationControllerDelegate)?){
        let uiimagePicker = UIImagePickerController.init()
        uiimagePicker.delegate = delegate
        
        if option == "Camera" && UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.camera){
            uiimagePicker.sourceType = .camera
        }else {
            uiimagePicker.sourceType = .photoLibrary
        }
        
        DispatchQueue.main.async {
            self.present(uiimagePicker, animated: true, completion: nil)
        }
        
    } 

Here we created an action sheet to let user select the source from which he/she will pick the image and then we check based on choice of user, whether this app has access to that source or not and if allowed then present the image picker.

To use in your view controller:

A) First set the viewcontroller  to implement the delegate for UIImagePickerControllerDelegate and UINavigationControllerDelegate

B) Then call method of extension to present an image picker from your view controller as:
        
      self.imagePickerControllerWith(delegate: self)

Sunday 4 June 2017

TextColor and backgroundColor Properties of UISearchBar

UISearchBar search text color

If we want to set the search text color in UISearchBar, we can do this either programmatically or in interface builder.

In order to change the text color in UISearchBar, we have to access the UITextField inside the UISearchBar. We can do this by using valueForKey("searchField")

var textFieldInsideSearchBar = yourSearchbar.valueForKey("searchField") as? UITextField

textFieldInsideSearchBar?.textColor = yourcolor

To set the text color of UISearchBar in interface builder,  go to in identity inspector- > User Defined Runtime Attributes -> in Key Path add searchField.textColor  and in Type write Color and in value set color.

In swift we can also create an extension for UISearchBar

public extension UISearchBar {

   public func setTextColor(color: UIColor) {
       let svs = subviews.flatMap { $0.subviews }
       guard let tf = (svs.filter { $0 is UITextField }).first as? UITextField else { return }
       tf.textColor = color
   }
}

UISearchBar background color

If you want to set the background color of UISearchBar,  you can change it in your ViewController and don't want anywhere else to effect then use

for view in searchBar.subviews {
           for subview in view.subviews {
               if subview .isKindOfClass(UITextField) {
                   let textField: UITextField = subview as! UITextField
                   textField.backgroundColor = UIColor.redColor()
               }
           }
    }

But if you want it to be change in whole app and targeting the iOS 9.0 or later then should be using appearanceWhenContainedInInstancesOfClasses like

UITextField.appearanceWhenContainedInInstancesOfClasses([UISearchBar.self]).backgroundColor = UIColor.redColor()