Monday, February 25, 2013

Delegate in iOS


Fire Xcode and Create New Project --> Select "Empty Project" in iOS Application (see on left side options). go next




In the next screen put the values like

Product Name: DelegateDemo
Org Name : RDCWorld
Company Identifier (package name) : com.rdcworld

Class Prefix : (leave blank for now)

Devices : select iPhone (if its not selected)

then check Tick mark for "Use Automatic Reference Counting" option to enable ARC.

and click on Finish button.



In this screen select location to save your project and click on create button.



So here is the default Xcode dashboard look like when you create new project.



See we have only two files
AppDelegate.h
AppDelegate.m

these are the most important and default file for every application.

so we don''t have any view controller in our project because we selected 
 "Empty application " option 

For this application We will create two View Controllers for having two screens.

in FirstViewController (we will send data to SecondViewController using delegate)
in SecondViewController (We will get the data sent by First)

So lets create ViewController.

First we will create new Group (Folder) for our Controllers 

Right click on Project Icon (Blue Icon) and click on "New Group" as shown in below picture.



double click on it and change default name to " Controllers ".

Now it time to create new ViewController

so, just right click on newly created Group "Controllers" and click on "New File" option



Select "Objective-C class" in iOS - Cocoa Touch option (on left side) and go Next 



in the next window just put

Class : "FirstViewCotroller" (its the name of our new controller)
Subclass of : UIViewController

don't forget to add Tick mark on "With XIB" for user interface

now go ahead and create..



Now you can see three new files added into our project in Group "Controllers"

FirstViewController.h
FirstViewController.m
FirstViewController.xib

Nice!! now we need to add one more controller, Go ahead same way and Create new View Controller
and Give it name as "SecondViewController".

If you have done this very well then you can see three more files added in Group "Controllers"

SecondViewController.h
SecondViewController.m
SecondViewController.xib

It's time to write some code…

Okay, we will start writing code from AppDelegate File, because we need to define which View Controller is startup screen for application. in our app its "First View Controller"

Here is the default code of "AppDelegate.h" file

now add

@class FirstViewController;

just after #import statement.
then add property for First View Controller like this

@property (strong, nonatomic) FirstViewController *firstViewController;

So Finally our "AppDelegate.h" file look like this

-----------------------------------------------------------------------------------------------------------------------------------------

//
//  AppDelegate.h
//  DelegateDemo
//
//  Created by RDC on 2/22/13.
//  Copyright (c) 2013 RDCWorld. All rights reserved.
//

#import <UIKit/UIKit.h>

@class FirstViewController;

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) FirstViewController *firstViewController;

@end

-----------------------------------------------------------------------------------------------------------------------------------------

if you did any mistake just make it like this. and go ahead open "AppDelegate.m" file

in this file, you can see many method with comments, don't worry about all these.

we will do three task.

1. add import statement for FirstViewController

#import "FirstViewController.h"

2. synthesize our FirstViewController's property. Just below to @implementation directive

@synthesize firstViewController;

3. Now in the "didFinishLaunchingWithOptions" method


delete below line

self.window.backgroundColor = [UIColor whiteColor];

and replace with this code

firstViewController = [[FirstViewController alloc] init];
    
UINavigationController *firstView = [[UINavigationController alloc] initWithRootViewController:firstViewController];
    
self.window.rootViewController = firstView;

what we doing is , creating FirstViewController's instance and added to Navigation Controller
then at last we added NavigationController as a rootViewController to our UIWindow, so it will be startup screen with FirstView.

So Finally our "AppDelegate.m" file look like this

-----------------------------------------------------------------------------------------------------------------------------------------

//
//  AppDelegate.m
//  DelegateDemo
//
//  Created by RDC on 2/22/13.
//  Copyright (c) 2013 RDCWorld. All rights reserved.
//

#import "AppDelegate.h"
#import "FirstViewController.h"

@implementation AppDelegate

@synthesize firstViewController;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    
    //create instance of FirstViewController
    firstViewController = [[FirstViewController alloc] init];
    
    //create UINavigationController instance using firstViewController
    UINavigationController *firstView = [[UINavigationController alloc] initWithRootViewController:firstViewController];
    
    //added navigation controller to window as a rootViewController
    self.window.rootViewController = firstView;
    
    [self.window makeKeyAndVisible];
    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application
{
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}

- (void)applicationWillTerminate:(UIApplication *)application
{
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}

@end


-----------------------------------------------------------------------------------------------------------------------------------------

So far so good, for now if you will execute application it will show FirstViewController as First Screen With just simple blue navigation bar (on top) and white background.

So it's time to add one TextField and Button on FirstViewController to get input data, and one Label on SecondViewController to show data.

Open FirstViewController.XIB (double click on it, it opens in Interface Builder), you will see blank White Layout.

So Add Navigation Bar on it, just click on Attribute Inspector and change the Top Bar value to "Navigation Bar"



Drag one TextField and Button on screen, select TextField and click on again Attribute Inspector and 
change placeholder value "enter your message" then select Button and give it name "Next" like this..



Now we need to create IBOutlet and IBAction for these items in FirstViewController.h file 
--But Make sure our FirstViewController.XIB file is selected--
For Creating IBOutlets select Assistant Editor in Editor Toolbar as shown in picture (you can find this on Top Right side in Xcode ).



Now you can see XIB and .h files together like this



To create TextField's IBOutlet right click on TextField.
then click on (+) button in "Referencing Outlet" option and drag cursor to its Header file (here its FirstViewController.h) like this



now small window will pop up, so put the name for TextField as "textField" and click on connect button



Now same stuff do for creating button's IBOutlet



put the button name as "nextButton" and click on connect button



Now we will create IBAction (event handler method) for button to handle its Click Event

Again right click on Next Button, click on (+) button with "Touch Up Inside" option in Send Events
and drag cursor to header file



give the method name as "buttonPressed"



Cool!! we have created two IBOutlets and One IBAction in our FirstViewController.h file


Now click on Standard Editor in Editor ToolBar



you can see this code in FirstViewController.h

@property (weak, nonatomic) IBOutlet UITextField *textField;
@property (weak, nonatomic) IBOutlet UIButton *nextButton;

- (IBAction)buttonPressed:(id)sender;


and empty button Pressed method  in FirstViewController.m file.


In FirstViewController.h file
add import statement
#import "SecondViewController.h"

Now add one string for storing input message data in header file.

@property (nonatomic, retain) NSString *mesasgeData;

and property  also for SecondViewController.

@property (nonatomic, strong) SecondViewController *secondViewController;

So far make sure our FirstViewController.h file code should be like this

-----------------------------------------------------------------------------------------------------------------------------------------
#import <UIKit/UIKit.h>

@class SecondViewController;

@interface FirstViewController : UIViewController

@property (nonatomic, retain) NSString *mesasgeData;

@property (weak, nonatomic) IBOutlet UITextField *textField;
@property (weak, nonatomic) IBOutlet UIButton *nextButton;

- (IBAction)buttonPressed:(id)sender;

@property (nonatomic, strong) SecondViewController *secondViewController;

@end
-----------------------------------------------------------------------------------------------------------------------------------------

Now come to the implementation file (FirstViewController.m)

synthesize the messageData string, textfield and view controller

@synthesize mesasgeData;
@synthesize textField;
@synthesize secondViewController;

then add the code in buttonPressed method.

- (IBAction)buttonPressed:(id)sender {
    
    //get the input data from text feild and store into string
    mesasgeData = textField.text;
    
    //go keypad back when button clicked from textfield
    [textField resignFirstResponder];
    
    //crating instance of second view controller
    secondViewController = [[SecondViewController alloc]init];
    
    //loading new view via navigation controller
    [self.navigationController pushViewController:secondViewController animated:YES];
    
    
}

So far our FirstViewController.m file code look like this (delete any other methods if you have)

-----------------------------------------------------------------------------------------------------------------------------------------
#import "FirstViewController.h"

@interface FirstViewController ()
@end

@implementation FirstViewController

@synthesize mesasgeData;
@synthesize textField;
@synthesize secondViewController;

#pragma mark - View Controller's Life Cycle methods

- (void)viewDidLoad
{
    [super viewDidLoad];    
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];    
}

#pragma mark - Button Click event handling method

- (IBAction)buttonPressed:(id)sender {
    
    //get the input data from text feild and store into string
    mesasgeData = textField.text;
    
    //go keypad back when button clicked from textfield
    [textField resignFirstResponder];
    
    //crating instance of second view controller
    secondViewController = [[SecondViewController alloc]init];
    
    //loading new view via navigation controller
    [self.navigationController pushViewController:secondViewController animated:YES];    
    
}
@end
-----------------------------------------------------------------------------------------------------------------------------------------

Good!! now if you will run the application you can enter message and go to the next screen .


Now Come to the second screen.

First is First, open SecondViewController.XIB file, 


1. click on white blank layout, select Attribute Inspector and update the Top Bar value is "Navigation Bar".

screen 20

2. We will add two labels to show message, what we got from previous screen.

  2.1 double click on First Label and give it value as "We got the message is :'
  2.2 create IBOutlet for second Label to show message.


For that Select Assistant Editor in Editor ToolBar as we did in last screen.
Right click on Label and create new Referencing outlet this way,



give the label name as "messageLabel"



if did this, then come back to Standard Editor in Editor tool bar.
so now you SecondViewController.h file look like this.
-----------------------------------------------------------------------------------------------------------------------------------------
#import <UIKit/UIKit.h>

@interface SecondViewController : UIViewController

@property (weak, nonatomic) IBOutlet UILabel *messageLabel;

@end
-----------------------------------------------------------------------------------------------------------------------------------------

That's it!! no more UI, IBOutlets,hookup and bla bla bla..

Now we will write the code to Implement the Delegate Feature in our application.

So in SecondViewController.h file 
1. First declare delegate  with its methods.

@protocol MyDelegate <NSObject>

-(NSString *) getMessageString;

@end

2. then create our delegate instance to call its methods.

@property (nonatomic, retain) id <MyDelegate> myDelegate;

Finally our SecondViewController.h file code is look like this 

-----------------------------------------------------------------------------------------------------------------------------------------
//
//  SecondViewController.h
//  DelegateDemo
//
//  Created by RDC on 2/22/13.
//  Copyright (c) 2013 RDCWorld. All rights reserved.
//

//declare our own delegate
@protocol MyDelegate <NSObject>

-(NSString *) getMessageString;

@end

#import <UIKit/UIKit.h>

@interface SecondViewController : UIViewController

@property (weak, nonatomic) IBOutlet UILabel *messageLabel;

@property (nonatomic, retain) id <MyDelegate> myDelegate;

@end
-----------------------------------------------------------------------------------------------------------------------------------------


Now come to SecondViewController.m file

1. synthesize our messageLabel and delegate variables

2. In viewDidLoad method we need to call delegate's method to get message string and put on message Label (string will be stored by FirstViewController, you will come to know later) .

messageLabel.text = [myDelegate getMessageString];

Finally our SecondViewController.m file code is look like this (if any other methods you have just delete those or you can leave, no problem)

-----------------------------------------------------------------------------------------------------------------------------------------
//
//  SecondViewController.m
//  DelegateDemo
//
//  Created by RDC on 2/22/13.
//  Copyright (c) 2013 RDCWorld. All rights reserved.
//

#import "SecondViewController.h"

@interface SecondViewController ()
@end

@implementation SecondViewController

@synthesize messageLabel;
@synthesize myDelegate;

- (void)viewDidLoad
{
    [super viewDidLoad];    
    messageLabel.text = [myDelegate getMessageString];    
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}

@end
-----------------------------------------------------------------------------------------------------------------------------------------

Now at last we need to implement our delegate in FirstViewController to store message string.

Just open the FirstViewController.h file and add delegate this way.

@interface FirstViewController : UIViewController<MyDelegate>

So Finally our FirstViewController.h file code is look like this

-----------------------------------------------------------------------------------------------------------------------------------------
//
//  FirstViewController.h
//  DelegateDemo
//
//  Created by RDC on 2/22/13.
//  Copyright (c) 2013 RDCWorld. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "SecondViewController.h"

@interface FirstViewController : UIViewController<MyDelegate>

@property (nonatomic, retain) NSString *mesasgeData;

@property (weak, nonatomic) IBOutlet UITextField *textField;
@property (weak, nonatomic) IBOutlet UIButton *nextButton;

- (IBAction)buttonPressed:(id)sender;

@property (nonatomic, strong) SecondViewController *secondViewController;

@end
-----------------------------------------------------------------------------------------------------------------------------------------

now come to implementation file (FirstViewController.m)

and implement MyDelegate's getMessageString method this way

-(NSString *) getMessageString{
    return mesasgeData;
}

and most important we need to add one more line in our buttonPressed method while we are going to load next controller.

secondViewController.myDelegate = self;


So Finally our FirstViewController.m file code is look like this

-----------------------------------------------------------------------------------------------------------------------------------------
//
//  FirstViewController.m
//  DelegateDemo
//
//  Created by RDC on 2/22/13.
//  Copyright (c) 2013 RDCWorld. All rights reserved.
//

#import "FirstViewController.h"

@interface FirstViewController ()
@end

@implementation FirstViewController

@synthesize mesasgeData;
@synthesize textField;
@synthesize secondViewController;

#pragma mark - View Controller's Life Cycle methods

- (void)viewDidLoad
{
    [super viewDidLoad];
    
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    
}

#pragma mark - Button Click event handling method

- (IBAction)buttonPressed:(id)sender {
    
    //get the input data from text feild and store into string
    mesasgeData = textField.text;
    
    //go keypad back when button clicked from textfield
    [textField resignFirstResponder];
    
    //crating instance of second view controller
    secondViewController = [[SecondViewController alloc]init];
    
    //it says SecondViewController is implementing MyDelegate
    secondViewController.myDelegate = self;
    
    //loading new view via navigation controller
    [self.navigationController pushViewController:secondViewController animated:YES];    
}

#pragma mark - MyDelegate's method implementation

-(NSString *) getMessageString{
    return mesasgeData;
}

@end

-----------------------------------------------------------------------------------------------------------------------------------------

Now save project (command+s) and we all set for execute our application!!

Here is the output screen (enter any message and press next button)



Wow!! we got the message from previous screen




Great!! we learnt one of the important feature of iOS.

You may like to download complete project source code zip file here : Delegate Demo in iOS

I would love to hear feedback :)

3 comments:

  1. Replies
    1. Ooops! I forgot to drop zip file,

      Yeah! fix that link, please check now ;)

      Delete
  2. Appreciate laying it out clearly. I got repeatedly confused when I read most people explaining "the delegate", "delegate of that class", "delegate object", "delegate method" etc. But I could now clearly see the difference between the class is sending and the one that is receiving.
    If I understood correctly,
    The class that is delegating = receiving class
    The class that is the delegate = the sending class

    ReplyDelete