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
}

Friday, 18 March 2016

Custom layout for Collection View

UICollectionView provides a way in which we can arrange our data in a grid . Some times we may encounter a problem where we want to design the grid in our way , for example we may want to show the layout of the collection view cell based on the content size of the data we want to display in the collection view. In this way we have to define our custom layout for the each cell based on the content size of the data.


Collection view layouts are subclasses of  the abstract UICollectionViewLayout class. They define the visual attribute of each item in your collection view.

The individual attributes are instances of  UICollectionViewLayoutAttributes and contain the properties of each item in your collection view, such as the frame or opacity of the item .

To customize the layout of the the collection view we have to understand how collection view and layout object works together. Collection view layout process is a collaboration between collection view and the layout object.
When collection view needs some information about layout, it asks your layout object to provide it by calling certain methods in a specific order:

1) prepareLayout
2) collectionViewContentSize
3) layoutAttributesForElementsInRect:

Your layout subclass must implement above mentioned methods:

1) prepareLayout(): It is called when a layout operation is to take place. Here we make calculations to define the collection view size and and the position of the items.

2) collectionViewContentSize(): In this method we return the  height and width of the entire collection view.

3) layoutAttributesForElementInRect(_:) In this method we return  the layout attributes for all the items in a given rect as  UICollectionViewLayoutAttributes .

Friday, 11 March 2016

Working with UIAlertController

UIAlertView and UIActionSheet are deprecated in iOS8. Now to show alert , we use UIAlertViewController which gives a more functionality to show alert. With this single class, we can create alert and add multiple actions to it. Each action has a completion handler called when user tap on that action button .

A UIAlertController objects displays an alert message to the user. This class replaces the UIAlertView and UIActionSheet  classes for displaying alerts. Although UIAlertController is a subclass of the UIViewController but it does not support subclassing  further .

UIAlertController is initialized with a title, message, and whether it prefers to be displayed as an alert or action sheet. Alert views are presented modally in the center of their presenting view controllers, where as action sheets are anchored to the bottom. Alerts can have both buttons and text fields, while action sheet only support buttons.


Creating an Alert Controller :

UIAlertController *alert = [UIAlertController  alertControllerWithTitle:@"My Alert"
                                                 message:@"This is an alert."
                                                 preferredStyle:UIAlertControllerStyleAlert];




title
The title of the alert. Use this string to get the user’s attention and communicate the reason for the alert.
message
Descriptive text that provides additional details about the reason for the alert.
preferredStyle
The style to use when presenting the alert controller. Use this parameter to configure the alert controller as an action sheet or as a modal alert.

When configuring an alert with the UIAlertControllerStyleAlert style , we can also  add text fields to the alert interface. The alert controller provide a block for configuring  text fields prior to display. The alert controller maintains a reference to each text field so that we can access its value later.

We can associate actions with  alert controller to give the user a way to respond. Actions are displayed as buttons in the alert . The action object provides the button text and the action to be performed when that button is tapped.

Creating an Action:

UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK"
                                               style: UIAlertActionStyleDefault
                                            handler: ^(UIAlertAction * action) {
                                           
                                          }];

[alert addAction: okAction];
[self  presentViewController:alert animated: YES  completion: nil];


Add TextFields:

-(void)addTextFieldWithConfigurationHandler:(void  (^)
  (UITextField * textField) ) configurationHandler

Calling this method adds an editable text field to the alert. We can call this method more than once to  add additional text fields. The text fields are stacked in the resulting alert.We can add a text field only if the  preferredStyle  property is set to UIAlertControllerStyleAlert.


References:

https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIAlertController_class/#//apple_ref/occ/instm/UIAlertController/addTextFieldWithConfigurationHandler:

   

Friday, 4 March 2016

Get the height of the text in textview/textfield

Some times we may have need to set the height of the textfield or textview based on the text size contained in the textfield or textview. 

Before iOS 7, we used sizeWithFont: method  to get the desired height, but now it is deprecated. So to get/set the height of the textview/textfield based on the text to be stored in it, we use:

For example: We have textView to show some text . The text length may be different. What if we have some other view there just touching  the  lower left corner of the text field. Though textView can contain different text say one line or multiple lines of text.  Then the position of that other view depends on the height of the textView.

//get the rect size of the counting text

  //set the attribute of the text, like font size and family and some other option
 NSDictionary *attributes  =@{NSFontAttributeName:[UIFont fontWithName:@"Helvetica Neue" size:14]};



CGRect rect = [[text to be stored in view] boundingRectWithSize:CGSizeMake(txtFieldWidth, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil];

Now from rect, we can extract the height and make the changes in the frame of the textfield so that textfield has the proper height to contain the text.
So we have approach like this:

 First calculate the text height to be stored in textView using above mentioned method. Then change the frame of the textView to adjust the text in it. After that also make some changes in the frame of the other view so that it places just touching the lower left corer of the textView.





Friday, 26 February 2016

Working with blocks

Block is same as the c function.The basic idea of a block is to treat a small piece of code as if it were a value. The piece of code can then be passed as a parameter in messages or assigned to a variable.

^{NSLog(@"It is a block literal); }


The use of blocks often involves nothing more than including code in block literal form as parameters for methods (designed to take blocks) that are part of the iOS API.
A block is the only object that begins its life in stack, rather than heap memory.A very effective use of a block literal is to deal with a callback. 

Creating a block variable:

int  (^sum)(int, int) = ^(int a , int b){
 return a+b;
}

This  is a simple block definition . It takes two parameters  of type int and return one int parameter.
To call this block as:

int c = sum(3,5);
NSLog(@"sum is %d",c);

When a block is created, it will capture, or close around, the values of those variables that the code has referred to and that are in the same lexical scope of the block. Essentially, a snapshot is taken of these values. These values are preserved in the memory allocated for the block and cannot later be changed. It is said that these variables are "captured by value".
To change the this behavior(to use the latest values of the variable), we can declare these variable as 
__block storage specifier.

__block int z =5;

Block as method parameter: We can also use block as method parameter to use call back. For example:
 
-(void)validateString:(NSString *)str onCompletion:(void(^)(bool isValidate))completion{
          
 if(str.length ==0){
    completion(NO); //call block
}else{
    completion(YES);
}
}

Now call this method as 

[self validateString:@"iOS" onCompletion:^(bool isValidate){
    
if(isValidate){
 //str is valid, handle it
}else{
  // str is not valid, handle it here
}       
   
}];

That's it. Though the use of block seems some complex at first time but once we get used to, it is very easy to use block in our code. With the help of block we can make our code simple, readable and easy to maintain .