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/

Friday 7 October 2016

Push notification in iOS10

With the introduction of iOS10 and xcode8 there are some changes in the way push notification works.
In iOS10 we may get  an errors from didFailToRegisterForRemoteNotificationsWithError . If you get following error in iOS10 but not in iOS9 then you will need to enable push entitlements locally.




1) In targets, under capabilities enable push notification to add push notification entitlements .


2) Add UserNotifications.framework into your app. Import UserNotification.framework in your AppDelegate.

#import <UserNotifications/UserNotifications.h>

@interface AppDelegate ()<UNUserNotificationCenterDelegate>

@end


3) Now to register push notification in iOS10 , add following code in didFinishLaunchingWithOptions method,

if (SYSTEM_VERSION_GRATERTHAN_OR_EQUALTO(@"10.0")) {       UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
        center.delegate = self;
        [center requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error){
            if( !error ){
                [[UIApplication sharedApplication] registerForRemoteNotifications];
            }
        }];
    
    }

4) Now implement delegate methods of UNUserNotificationCenterDelegate:

-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{
    
    //Called when a notification is delivered to a foreground app.
    
    NSLog(@"Userinfo %@",notification.request.content.userInfo);
    
    completionHandler(UNNotificationPresentationOptionAlert);
}

-(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler{
    
    //Called to let your app know which action was selected by the user for a given notification.
    
    NSLog(@"Userinfo %@",response.notification.request.content.userInfo);
    
}



Reference: http://stackoverflow.com/questions/39490605/push-notification-issue-with-ios-10

Thursday 29 September 2016

Custom view controller transition and animation

iOS7 introduced a way by which we can customise the transition from one view controller to other. For example say if we  navigate from one view controller to another  , we push a view controller on another and to return back to initial view controller we pop the view controller.
With iOS7 now we can change the animation according to out requirement. We can reverse the direction of navigation controller. Even we can change the direction of the presenting view controller .
For creating custom transitioning we have to perform following steps:

1) Create a class that implements the UIViewControllerAnimatedTransitioning protocol . In this class we code to customise the animation . In this class we implements the two delegate method of the above protocol , which is as:

-(NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext{
    return 1.5;

}

-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{}

2) In view controller class (a view controller from which we navigate or transition to another  view controller), implements the following:

       If we are presenting a view controller modally, then view controller have to implement UIViewControllerTransitioningDelegate . UIviewController has a property named transitionDelegate set it to self in order to return the custom animation for transitioning .
In delegate method (animationControllerForPresentedController) return the instance of the class which implements the  UIViewControllerAnimatedTransitioning .

      If we are navigating from one view controller to another , the view controller have to implement UINavigationControllerDelegate . The set the view controller as delegate of the navigation controller . And implement the required methods .
For customising the push and pop operation , we can create the two classes one for push animation and another for pop operation which implements the UIViewControllerAnimatedTransitioning . 
And then  from the delegate method of the navigation controller we can check the type of operation (push or pop)and return the  designated custom animator instance .

- (nullable id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC{
}

With this way we can create the custom animation as we want. The core part of this process is to code the custom animation . And return the instance of the  custom animation objects.

Thursday 22 September 2016

Show download progress of the content

In iOS when we download any content , there may be a need to show the progress of the download. It's easy in iOS. We can download the data with NSURLConnection. 

First of all create a UIProgressBar in your view and initially make it hidden. Lets say we have a progress bar outlet named  progressBar .


1) Create NSURLConnection object

NSURL *url = [NSURL URLWithString:@"Your_url"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url         cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:80];

   NSMutableData *dataReceived = [[NSMutableData alloc] initWithLength:0];
    NSURLConnection * connection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self     startImmediately:YES];


2) Now implement the delegate methods of the NSURLConnection

 In this method we receive the response of the download, from which we get the expected content length.Also we make the progress bar unhidden here.

- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
     self.progressBar.hidden = NO;
    [dataReceived setLength:0];
    long long  expectedDataBytes = [response expectedContentLength];
}


In didReceiveData:(NSData*)data method we get the downloaded data chunks, here we append the data to dataReceived object . And also set the progress bar by download progress .

- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [dataReceived appendData:data];
    float downloadProgress = (float)[dataReceived length] / (float) expectedDataBytes;
     [self.progressBar setProgress: downloadProgress];
    
}

When downloading is complete the connectionDidFinishLoading:(NSURLConnection*)connection method is called. Here we can save the downloaded content to the document directory.

- (void) connectionDidFinishLoading:(NSURLConnection *)connection {
   
}
    
Here I make the expectedDataBytes and dataReceived object local .You have to declare them to interface section of the file to use them in all methods.

Reference:

Thursday 15 September 2016

Custom AVPlayer

In iOS application development some time we may have situation where we want to show our own controls on AVPlayer. Suppose user want to show the playback slider on the bottom of the screen and two buttons on the left and right side of the screen  to control the speed of the video .



To implement this  we can create a view with required buttons and slider and assign action to designated view controller. The steps are as follows:

1) Create a view controller and then design the xib as per the need and create necessary outlets and action of the objects .

2) Then in implementation file create an instance of AVPlayerItem .

NSURL *url  =[NSURL URLWithString:@"http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"];
    //create player item

AVPlayerItem *playerItem = [AVPlayerItem playerItemWithURL:url];

3)  Initialize AVPLayer with the AVPlayerItem instance

   AVPlayer *player = [AVPlayer playerWithPlayerItem:playerItem];

4)  Create an AVPLayerLayer instance

   AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:player];

5) Now insert the playerLayer to the view's layer hierarchy

    [self.view.layer insertSublayer:playerLayer atIndex:0];

That's all our design is done. 

Now our job is to run the slider, speed the video when user tap on button and  play and pause the video .To implement these all feature we can register observer .

6) To check the status of the playing item we can register for key path observing like this :

[playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];

Then implement the method

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{
}

This method is core method of KVO(Key-value-observing) and is called every time when any changes occur in the property of the registered object .In this method we can check for different key path and take action accordingly like this :

if ([keyPath isEqualToString:@"status"]) {
 }

7)To track the buffering of the video register for key path playbackLikelyToKeepUp

[playerItem addObserver:self forKeyPath:@"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionNew context:nil];

8) We can register an observer to listen for when the video is ended :

[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(playerDidEndVideo) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];

Thursday 8 September 2016

Slide down a UIView on a button action


In iOS app, we may have a requirement like, when a user tap on a button , a UIView slide down with animation . To implement this we can create a button and UIView on the top of button and make it hidden . Then in action method of the button change the frame of the UIView with animation  according to our requirement . To make it hide again with animation like slide top, reverse the operation .

Here is an example in which we will make a UIView slide down when a user tap on the button.

1) Create a UIButton

2) Then create a UIView on the top of UIButton  and make it hidden . Lets say we named it myView

3) Then in action method of UIButton , check if button is hidden or not and act accordingly:

if([myView isHidden]){

 First unhide the button

myView.hidden = NO;
 
Get the frame of the btn

CGRect frame  = myView.frame

Now change the y origin of the  frame

frame.origin.y += 30;

Now set animation to change the frame of the myView

[UIView animateWithDuration:0.7 delay:0.0
options:UIViewAnimationOptionCurveLinear animations:^{

      myView.frame  = frame

} completion:nil];


That's all . Now if we want to slide top the myView again ,when user tap on the button then change the frame of the myView to its original size .

Friday 29 July 2016

Integrate google map in an iOS app

In iOS development we have situation where we need to add  a map in our app. Google provides the iOS SDK to integrate map in an iOS app.

We can add SDK  either manually or using COCOAPODS. Here we are adding through pod .

Before adding google map SDK make sure we have COCOAPOD install in out system. If we have po d in our system  then follow these steps  to make a pod file :

1) Go to project directory and run the command
     
                pod init

This will make a pod file in your project directory.

2) Now open the Podfile

            nano Podfile

Add the following lines to add google map in our project:

    source 'https://github.com/CocoaPods/Specs.git'

target 'Indi Beats' do
pod 'GoogleMaps'
  pod 'GooglePlaces'
end

Now save and exit the pod file and run the pod install command to add the google map. This will make a file with an extension of  .xcworkspace . Now open this file to open the project in xocode .

Now go to developer site of google and follow these steps to enable the Google maps SDK for iOS on the  Google API console .

1) Go to Google API Console .

2) Creare or select a project .

3) Click Continue to enable the Google Maps SDK for iOS.

4) On the Credentials page, get an iOS key and enter your app's bundle identifier when prompted .

5) Click Create .

This will create  an API key for Google Maps .

Add API key in iOS application:

Add API key  in your AppDelegate.m file

1) Add the import statement:
      
      @import GoogleMaps;

2) In application:didFinishWithLaunchingOptions: method, add the following line:

      [GMSServices provideAPIKey:@"your api key"];


Add a map :

In your view controller add the following  import statement:

#import <GoogleMaps/GoogleMaps.h> 

-(void)addMap{

//1  Create camera position
      GMSCameraPosition *cameraPos =  [GMSCameraPosition cameraWithLatitude:-33.86 longitude:151.20 zoom:10];

//2 Create map view
     GMSMapView *mapView = [GMSMapView  mapWithFrame:CGRectZero camera:cameraPos];

     self.view = mapView ;

//3 We can also create a marker

     GMSMarker *marker =  [GMSMarker alloc]init];
    
     //set position of the marker
      marker.position = CLLocationCoordinate2DMake(-33.86,151.20);
      
      marker.map =  mapView ;
}

That's it. This is how we add a map in an iOS app,

Friday 20 May 2016

Category in Objective C


A category provides an easy way for you to modularize the definition of a class into groups or categories of related methods. It also gives you an easy way to extend an existing class definition without even having access to the original source code for the class and without having to create a subclass. 

For example: we have a class Fraction, which look like as:

#import <Foundation/Foundation.h> // Define the Fraction class

@interface Fraction : NSObject
 @property int numerator, denominator;

-(void) setTo: (int) n over: (int) d; 
-(Fraction *) add: (Fraction *) f; -(void) reduce;
-(double) convertToNum;
-(void) print; 

@end

If we want to crate a mathOps category that will include the method to perform math operation:

Steps are as follows:

We can create category in separate category file or in to the original file as  class in.

1) import the class for which you want to create a category.

#import Fraction.h

Even though this is an interface section definition, it is an extension to an existing one.Therefore, you must import the original interface section so that the compiler knows about the 
Fraction class (unless you incorporate the new category directly into the original Fraction.h header file, which is an option). 

2) add interface 
@interface Fraction(category_name)

// add methods here

-(Fraction *) add: (Fraction *) f;
-(Fraction *) mul: (Fraction *) f; 
-(Fraction *) sub: (Fraction *) f; 
-(Fraction *) div: (Fraction *) f; 

@end 

The category name is enclosed in parentheses after the class name. Notice that you don’t list the Fraction’s parent class here; the compiler already knows it from Fraction.h.Also, you don’t tell it about the instance variables .

3) 
You can put the definitions for all your methods into a single implementation section. That is, you could define all the methods from the interface section in Fraction.h plus all the methods from the MathOps category in one implementations section.

Alternatively, you could define your category’s methods in a separate implementation section. In such a case, the implementation section for these methods must also identify the category to which the methods belong. As with the interface section, you do this by enclosing the category name inside parentheses after the class name, like this: 

@implementation Fraction(category_name)

// code for category methods
@end

Remember that extending a class by adding new methods with a category affects not just that class, but all its subclasses as well. 

Class Extensions:
There is a special case of creating a category without a name, that is no name is specified between the ( and ).This special syntax defines what is known as a class extension.When you define an unnamed category like this, you can extend the class by defining additional instance variables.This is not allowed for named categories. Methods declared in an unnamed category are implemented in the main implementation section for the class and not in a separate implementation section.

Let’s assume we have a class called GraphicObject. Further assume we type the following lines into
our implementation file GraphicObject.m:

#import "GraphicObject.h"
// Class extension
@interface GraphicObject ()
 @property int uniqueID;
-(void) doStuffWithUniqueID: (int) theID;

 @end

@implementation GraphicObject 
@synthesize uniqueID;

(void) doStuffWithUniqueID: (int) myID
{
self.uniqueID = myID;
... }
...
// Other GraphicObject methods ...
@end

Unnamed categories are useful because their methods are private. So if you need to write a class that has data and methods that can only be used within the class itself, an unnamed category might just fit the bill. 






Saturday 16 April 2016

Add multiple buttons to a UITableView cell on swipe

When we want to add some action to a table view cell when swipe , Apple provides the methods to deal with it. But by default Apple gives only one button when we swipe to left, a delete button . But what if we want more buttons like a mail app in iOS 8.

In iOS8 Apple provides this functionality in form of edit actions and UITableViewRowAction.

To use UITableViewRowAction we have to implement a delegate method of UITableView:

-(NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath{
    //return an array of UITableViewRowAction instances
}
In this method we create the UITableViewRowAction instance like this:

UITableViewRowAction *delete = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"Delete" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
       
        //call method to perform action when user tap on delete button   
    }];

The above code will create a delete instance and provide handler block which will be executed when user tap on the targeted  UITableViewRowAction instance.

Like this we can create multiple instances of the UITableViewRowAction  and finally return an array of UITableViewRowAction instances.

How that's simple it is to add multiple button to a table view cell on swipe.But to enable user to perform action on these multiple buttons we have to enable users to allow editing on the table view cell. To do this, implement these two table view delegate methods:

To allow editing on cell, implement:

-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath{
    return YES;
}

It is necessary to override this second method, even though we can leave it blank. If method is not present the action won't show up on swipe.

-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
    
    //to do when commiting editing
}