Create Custom Delegate and Protocol iOS | Swift & Objective-C

One of the most powerful tools an iOS developer has is the ability to create protocols and implement delegates that let your classes notify when an event occurs. I use them all the time in my projects and wanted to show how easy it is to implement your iOS Project. I will demonstrate them in both Objective-C and Swift so you can see a side by side comparison. In this example we will be implementing timer that fires a timerFinished method to let the UIViewController know the timer finished and start the timer over.

If you want to follow allow you can download the projects from GitHub here:

Objective-C  Project
Swift Project

Protocols

A protocol is a list of methods that specify an interface that your delegate will implement. There are two kinds of delegates we can use: Option and Required. They are pretty self explanatory but the difference is Required will throw an error letting you know your class is not conforming to the protocol. Also protocol methods are required by default so if you want it optional don’t forget that optional keyword. If you are using swift you will also need to add the @objc prefix if you want an optional method.

Swift
//
//  MyTimer.swift
//  SwiftProtocol
//
//  Created by Barrett Breshears on 10/11/14.
//  Copyright (c) 2014 Sledge Dev. All rights reserved.
//

import UIKit

// set up the MyTimerDelegate protocol with a single option timer finished function
@objc protocol MyTimerDelegate{
    optional func timerFinished()
}


class MyTimer: UIViewController {
    
    // this is where we declare our protocol
    var delegate:MyTimerDelegate?
    
    // set up timer variables and labels
    var timer:NSTimer! = NSTimer()
    var labelTimer:NSTimer! = NSTimer()
    var timerLabel:UILabel! = UILabel()
    var timerCount = 0
    var duration = 0
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Do any additional setup after loading the view.
        timerLabel = UILabel(frame: self.view.frame)
        timerLabel.textAlignment = NSTextAlignment.Center
        self.view.addSubview(timerLabel)
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func startTimer(timerDuration:Double){
        self.duration = Int(timerDuration)
        timerLabel.text = String(format: "%d", duration)
        
        timer = NSTimer.scheduledTimerWithTimeInterval(timerDuration, target: self, selector: Selector("timerFired:"), userInfo: nil, repeats: false)
        
        labelTimer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: Selector("updateLabel:"), userInfo: nil, repeats: true)
        
        
    }
    
    func timerFired(timer:NSTimer){
        if(timer.valid){
            timer.invalidate()
        }
        if(labelTimer.valid){
            labelTimer.invalidate()
        }
        // ************************************** \\
        // ************************************** \\
        // This is the important part right here
        // we want to call our protocol method
        // so the class implementing this delegate will know
        // when the timer has finished
        // ************************************** \\
        // ************************************** \\
        delegate?.timerFinished!()
        
    }
    
    func updateLabel(timer:NSTimer){
        duration = duration - 1
        timerLabel.text = String(format: "%d", duration)
    }
    
    
    /*
    // MARK: - Navigation
    
    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
    // Get the new view controller using segue.destinationViewController.
    // Pass the selected object to the new view controller.
    }
    */
    
}

This is a pretty simple example but here is what is going on. The UIViewController has a start timer method that sets up the two timers: one that will fire when the overall time is complete and one that fires every second to update the timer label. When the total duration timer is finished the timerFired method is called, and thats where we run the delegate’s timerFinished method. Now lets do the same thing but with Objective-C.

Objective-C
//
//  MyTimer.h
//  ObjectIveCProtocol
//
//  Created by Barrett Breshears on 10/11/14.
//  Copyright (c) 2014 Sledge Dev. All rights reserved.
//

#import 

// set up the MyTimerDelegate protocol with a single option timer finished function
@protocol MyTimerDelegate 

@optional
-(void)timerFinished;

@end

@interface MyTimer : UIViewController
// this is where we declare our protocol
@property (nonatomic, strong) id delegate;
// set up timer variables and labels
@property (nonatomic, strong) NSTimer *timer;
@property (nonatomic, strong) NSTimer *labelTimer;
@property (nonatomic, strong) UILabel *timerLabel;
@property (nonatomic, assign) int timerCount;
@property (nonatomic, assign) int duration;

- (void)startTimer:(float)duration;

@end

//
//  MyTimer.m
//  ObjectIveCProtocol
//
//  Created by Barrett Breshears on 10/11/14.
//  Copyright (c) 2014 Sledge Dev. All rights reserved.
//

#import "MyTimer.h"



@interface MyTimer ()

@end

@implementation MyTimer

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    _timer = [[NSTimer alloc] init];
    _labelTimer = [[NSTimer alloc] init];
    _timerCount = 0;
    _duration = 0;
    
    
     _timerLabel = [[UILabel alloc] initWithFrame:self.view.frame];
    [self.view addSubview:_timerLabel];
    [_timerLabel setTextAlignment:NSTextAlignmentCenter];
    
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void)startTimer:(float)duration{
    _duration = (int)duration;
    _timerLabel.text = [NSString stringWithFormat:@"%d", _duration];
    
    _timer = [NSTimer scheduledTimerWithTimeInterval:duration
                                              target:self
                                            selector:@selector(timerFired:)
                                            userInfo:nil
                                             repeats:NO];
    
    _labelTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
                                                   target:self
                                                 selector:@selector(updateLabel:)
                                                 userInfo:nil
                                                  repeats:YES];
    
    
}

- (void)timerFired:(NSTimer *)timer {
    if ([_timer isValid]) {
        [_timer invalidate];
    }
    _timer = nil;
    if ([_labelTimer isValid]) {
        [_labelTimer invalidate];
    }
    _labelTimer = nil;
    // ************************************** \\
    // ************************************** \\
    // This is the important part right here
    // we want to call our protocol method here
    // so the class implementing this delegate will know
    // when the timer has finished
    // ************************************** \\
    // ************************************** \\
    [_delegate timerFinished];
}

- (void)updateLabel:(NSTimer *)timer{
    _duration = _duration - 1;
    _timerLabel.text = [NSString stringWithFormat:@"%d", _duration];
}

@end

So same thing just different syntax. The UIViewController has a start timer method that sets up the two timers: one that will fire when the overall time is complete and one that fires every second to update the timer label. When the total duration timer is finished the timerFired method is called, and thats where we run the delegate’s timerFinished method.

Delegates

Now that we have our protocols all set up all we have to do is implement them. We are going to do this by creating a delegate. A delegate is a variable that complies to a protocol, which a class typically uses to notify of events, in this case the timer finishing. To do this we add our protocol to our class declaration, to let our class know it must comply with the delegate. Then we add our delegate method to our class.

Swift
//
//  ViewController.swift
//  Swift-Protocol
//
//  Created by Barrett Breshears on 10/11/14.
//  Copyright (c) 2014 Sledge Dev. All rights reserved.
//

import UIKit

// add our MyTimerDelegate to our class
class ViewController: UIViewController, MyTimerDelegate {
    
    var timer:MyTimer = MyTimer()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        timer.view.frame = self.view.frame
        // ************************ \\
        // This is where we let the delegate know 
        // we are listening for the timerFinished method
        // ************************ \\
        timer.delegate = self
        self.view.addSubview(timer.view)
        timer.startTimer(10.0)
        
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // ************************ \\
    // This is where our delegate method is fired
    // ************************ \\
    func timerFinished(){
        timer.startTimer(10.0)
        println("Hey my delegate is working")
    }

}

So the important thing here is we set the timer.delegate to self so the ViewController’s method timerFinished() class is called.

Objective-C
//
//  ViewController.h
//  ObjectIveCProtocol
//
//  Created by Barrett Breshears on 10/10/14.
//  Copyright (c) 2014 Sledge Dev. All rights reserved.
//

#import 
#import "MyTimer.h"

// add our MyTimerDelegate to our class
@interface ViewController : UIViewController 

@property (nonatomic, strong) MyTimer *timer;

@end
//
//  ViewController.m
//  ObjectIveCProtocol
//
//  Created by Barrett Breshears on 10/10/14.
//  Copyright (c) 2014 Sledge Dev. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    _timer = [[MyTimer alloc] init];
    _timer.view.frame = self.view.frame;
    _timer.delegate = self;
    [self.view addSubview:_timer.view];
    [_timer startTimer:10.0];
    
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

-(void)timerFinished{
    [_timer startTimer:10.0];
    NSLog(@"Hey my delegate is working!");
}

@end

When we run the code we see the timer label is added and set to a 10 second timer. It counts down, and when it reaches 0 it notifies the viewcontroller, restarts the timer and prints the “Hey my delegate is working in the console”.

If you have any questions about the code or found this tutorial helpful let me know in the comments below! I appreciate feedback. Also don’t forget to follow me on twitter. I am always looking for iOS developers to tweet with.