Skip to main content

Using delegates in Objective-C



Why use delegation?

Well when writing Objective-C programs in Xcode we are encouraged to use the MVC(Model View Controller) structure.In MVC a model cannot send messages directly to a specific controller.This can become a problem if data in your model changes independantly and you need to update this information in your view via the controller(The model must never communicate directly with the view).This is where a delegate comes in,it allows messages to be sent from the model to a controller that is not specified in the model but is rather specified by the controller,in other words the controller specifies itself.

If you dont really understand what im talking about so far ,don't worry.I didn't understand delegates either until I needed one,but hopefully by the end of this tutorial you will understand not only how to use a delegate ,but the reason you would want to use one.

Program breakdown

For this tutorial we will write a program that has a model that will change an integer value on a timer event and we will have a view with a label and a controller that will update the value displayed on the label.We will then use delegation to tell the controller when it needs to update the label by broadcasting messages from the model.

First things first ,lets open up Xcode and create a single view based iPhone application With ARC(Automatic Reference Counting) enabled,I tried doing this without ARC before and alot of things broke and I actually wasn't able to fix it.I am also using storyboards,you can use Xibs if you know what you are doing.



Next lets add a label to the view and link it to our controller by selecting assistant editor and ctrl+dragging it into the Controller code.Make it an outlet and name it textLabel.

Assistant Editor icon:
Creating an Outlet:


This should generate the following code in ViewController.h:

@property (weaknonatomicIBOutlet UILabel *textLabel;

Now lets create our model,create a new Objective-C class That is a subclass of NSObject and name it NumberLooper or anything you deem appropraite.



Now lets start coding,in NumberLooper.h add the following code:

#import <Foundation/Foundation.h>
@interface NumberLooper : NSObject{
    NSTimer *timer;
    int currentNumber;
}
@property (nonatomic,strongNSTimer *timer;
-(void)startTimerLoop;
@end
Now lets implement the model in NumberLooper.m

#import "NumberLooper.h"
@implementation NumberLooper
@synthesize timer;
-(void)timerEvent:(NSTimer*)timer{
    /*if the number is less than 256 add 1 and else set 
     the number to 0*/
    
    if(currentNumber < 256)
        currentNumber ++;
    else
        currentNumber = 0;
    
    //Display the number in the console
    NSLog(@"%d",currentNumber);
}
-(void)startTimerLoop{
    if (!timer){
timer=[ NSTimer scheduledTimerWithTimeInterval:0.020 target:self  
selector:@selector(timerEvent:) userInfo:nil repeats:YES ];
        NSLog(@"Timer started.");
    }
    else {
        NSLog(@"Timer is already running");
    }
}
@end
This will begin a loop that will constantly change the value of currentNumber once startTimerLoop is called,however if we ran the application now we wouldnt see this output in the console because satrtTimerLoop is never called,so lets call it ,go to ViewController.h and add
#import "NumberLooper.h"
then go to ViewController.m and add the following code to - (void)viewDidLoad:

 NumberLooper *nl = [[NumberLooper allocinit];
    [nl startTimerLoop];
Now when we run the app on the simulator we can see the console output in Xcode of the number changing


As you can see the label is still not updating ,which is good because if it is then some sort of voodoo magic has occured because we haven't even written the delegate yet.I think its about time we do that.First we create a @protocol in the model in NumberLooper.h above the interface ,this lets us specify what messages are sent to the delegate:

@protocol NumberLooperDelegate <NSObject>
-(void)numberHaschangedTo:(int)number;
@end
@interface NumberLooper : NSObject{ ...
Then we set the delegate as a property in the interface,this property must always be strong.

@property (nonatomic,strongNSTimer *timer;
@property (nonatomic,strongid <NumberLooperDelegate> delegate;
-(void)startTimerLoop;
Now lets move to the implementation in NumberLooper.m and synthesize the delegate:

@synthesize delegate;
And now we send the message to the delegate in timerEvent just after we write the number to the console:

 //Display the number in the console
    NSLog(@"%d",currentNumber);
    
    //send the message to the delegate
    [self.delegate numberHaschangedTo:currentNumber];
That wraps up all the code we need to implement in the model ,now lets move to ViewController.h,here we will tell ViewController that it can be a NumberLooperDelegate by adding to the end of its subclass int the interface declaration like this:

@interface ViewController : UIViewController <NumberLooperDelegate>;
@property (weaknonatomicIBOutlet UILabel *textLabel;
@end
Now we implement the -(void)numberHasChangedTo: method that we declared in our @protocol in the @implementation of ViewController in ViewController.m:

#pragma mark - NumberLooperDelegate -
-(void)numberHaschangedTo:(int)number{
    //set the textlabel text value to the number
    textLabel.text = [NSString stringWithFormat:@"%d",number];
}
The last thing that is left for us to do is to set ViewController as NumberLooper's delegate so that it knows who to send its message to ,we do this just before we call startLoopTimer using [NumberLooper Instance Name].delegate = self:

- (void)viewDidLoad
{
    [super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
    NumberLooper *nl = [[NumberLooper allocinit];
    nl.delegate = self;
    [nl startTimerLoop];
    
}
Now when we run the application the label should update every time the value of currentNumber changes:



I hope you now have a good understanding of how to use delegates and why you would use them so that you can now go and try them out in your own apps.

If your app did not compile or didn't work properly or you have any questiions or some part of the tutorial was unclear to you and you need help,feel free to comment,i will reply to questions when I have time.

Popular posts from this blog

Running Node.js alongside IIS on Windows

Most of the time when you are looking for a way to run Node.js as a production server on Windows you will just run into IISNode , now IISNode is a great thing ,but I'm a fan of choice and most importantly , not a fan of XML web config files.

I wanted to run my node server on what ever port I wished,or maybe even a different server and just have IIS reroute the traffic from a particular URL to the node process(so a proxy), this allows you to still manage your own load balancing and possibly scale up from that point without having to bother with IIS again.

So first things first you will want to download and install the URL Rewrite and ARR modules for IIS

ARR (Application Request Routing)URL Rewrite Once thats done lets crack open IIS and open up Application Request Routing, then navigate to Server Proxy Settings and Check Enable Proxy and Apply.







Now lets create an an application on our Default Website that will link our url to the node process, here im directing it to an empty direc…

Half-Life 2 for OSX , how well does it run?

Earlier this week Valve advertised Half-Life 2 for the Mac with the best advert I have ever seen. They took the old 1984 Mac advert and re-created it using the source engine and characters from the game. As if the awesome(albeit 35 second) entertainment wasn't enough they offered the game at $3.40 for a limited period. It was not shortly afterwards that I made my first ever purchase on Steam(its kind of strange buying a game and not getting a box with it).




The game purchase actually allows you to download the OSX or Windows version of the game , depending on the platform you are logged in to .This is great , because I have a PC with some decent gaming power and my Mac Mini (which I naturally wanted to test on) and wow ,the OSX version runs pretty darn well,especially considering that my mac mini is running only an intel HD3000.



Performance
I was surprised how well the game performed on high settings , the gameplay was smooth with the default high settings , reaching frame-rates up …

Controlling an LED on an Arduino over HTTP

Prerequisites
You will need node.js and npm installed , and should have at least some knowledge when it comes to node, if you do not , I suggest you try some example code in node before diving into controlling hardware with it. You must have the Arduino IDE installed on your machineYou must know how to get an LED working on pin 13 of an Arduino
Set up the Arduino
Wire up an LED to the Arduino on pin 13 and plug it into your development machine. Now we need to get it ready to talk to johnny-five. To do this simply follow the instructions under johnny-five's readme
Set up the project 

Create a folder on your development machine for the project , in this folder create the server.js and index.html files. Copy the code from the files in this gist to the respective files.

Loading ....
We aren't done yet , we need johnny-five and the narf for this to work. In your project directory run the following command:

npm install narf johnny-five

If that succeeded we now have the johnny-five libra…