Reputation: 79
In iPhone every UIContrrol has predefined delegate methods but how we will create our own custom delegate methods
Upvotes: 3
Views: 16007
Reputation: 618
To Create Custom Delegate and Protocol iOS | Swift & Objective-C
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 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)
}
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.
If you want to follow allow you can download the projects from GitHub here:
https://github.com/barrettbreshears/objective-c-protocol
or,
https://github.com/barrettbreshears/swift-protocol
Upvotes: 1
Reputation: 2802
In your header file, before @interface
, insert
@protocol YourDelegate <NSObject>
@optional
- (void) anOptionalDelegateFunction;
@required
- (void) aRequiredDelegateFunction;
@end
and under @interface
@property (nonatomic, assign) id<YourDelegate> delegate;
// Remember to synthesize in implementation file
Now you can call in your .m file
[delegate aRequiredDelegateFunction];
and in the delegate
<YourDelegate>
as usual in the .h fileself
Upvotes: 19
Reputation: 25143
In your class create an id object delegate. Create a getter and setter so other classes can set themselves as delegates. In your class add this:
@interface MyClass (Private)
-(void)myDelegateMethod;
@end
Then in what ever function you want to call back to the class that is the delegate do something like this:
if ( [delegate respondsToSelector:@selector(myDelegateMethod)] ) {
[delegate myDelegateMethod];
}
Upvotes: -6