I know how delegates work, and I know how I can use them.
But how do I create them?
Disclaimer: this is the Swift
version of how to create a delegate
.
So, what are delegates? …in software development, there are general reusable solution architectures that help to solve commonly occurring problems within a given context, these “templates”, so to speak, are best known as design patterns. Delegates are a design pattern that allows one object to send messages to another object when a specific event happens. Imagine an object A calls an object B to perform an action. Once the action is complete, object A should know that B has completed the task and take necessary action, this can be achieved with the help of delegates!
For a better explanation, I am going to show you how to create a custom delegate that passes data between classes, with Swift in a simple application,start by downloading or cloning this starter project and run it!
You can see an app with two classes, ViewController A
and ViewController B
. B has two views that on tap changes the background color of the ViewController
, nothing too complicated right? well now let’s think in an easy way to also change the background color of class A when the views on class B are tapped.
The problem is that this views are part of class B and have no idea about class A, so we need to find a way to communicate between this two classes, and that’s where delegation shines. I divided the implementation into 6 steps so you can use this as a cheat sheet when you need it.
step 1: Look for the pragma mark step 1 in ClassBVC file and add this
//MARK: step 1 Add Protocol here.
protocol ClassBVCDelegate: class {
func changeBackgroundColor(_ color: UIColor?)
}
The first step is to create a protocol
, in this case, we will create the protocol in class B, inside the protocol you can create as many functions that you want based on the requirements of your implementation. In this case, we just have one simple function that accepts an optional UIColor
as an argument.
Is a good practice to name your protocols adding the word delegate
at the end of the class name, in this case, ClassBVCDelegate
.
step 2: Look for the pragma mark step 2 in ClassVBC
and add this
//MARK: step 2 Create a delegate property here.
weak var delegate: ClassBVCDelegate?
Here we just create a delegate property for the class, this property must adopt the protocol
type, and it should be optional. Also, you should add the weak keyword before the property to avoid retain cycles and potential memory leaks, if you don’t know what that means don’t worry for now, just remember to add this keyword.
step 3: Look for the pragma mark step 3 inside the handleTap method
in ClassBVC
and add this
//MARK: step 3 Add the delegate method call here.
delegate?.changeBackgroundColor(tapGesture.view?.backgroundColor)
One thing that you should know, run the app and tap on any view, you won’t see any new behavior and that’s correct but the thing that I want to point out is that the app it’s not crashing when the delegate is called, and it’s because we create it as an optional value and that’s why it won’t crash even the delegated doesn’t exist yet. Let’s now go to ClassAVC
file and make it, the delegated.
step 4: Look for the pragma mark step 4 inside the handleTap method in ClassAVC
and add this next to your class type like this.
//MARK: step 4 conform the protocol here.
class ClassAVC: UIViewController, ClassBVCDelegate {
}
Now ClassAVC adopted the ClassBVCDelegate
protocol, you can see that your compiler is giving you an error that says “Type ‘ClassAVC does not conform to protocol ‘ClassBVCDelegate’ and this only means that you didn’t use the methods of the protocol yet, imagine that when class A adopts the protocol is like signing a contract with class B and this contract says “Any class adopting me MUST use my functions!”
Quick note: If you come from an Objective-C
background you are probably thinking that you can also shut up that error making that method optional, but for my surprise, and probably yours, Swift
language does not support optional protocols
, if you want to do it you can create an extension for your protocol
or use the @objc keyword in your protocol
implementation.
Personally, If I have to create a protocol with different optional methods I would prefer to break it into different protocols
, that way I will follow the concept of giving one single responsibility to my objects, but it can vary based on the specific implementation.
here is a good article about optional methods.
step 5: Look for the pragma mark step 5 inside the prepare for segue method and add this
//MARK: step 5 create a reference of Class B and bind them through the `prepareforsegue` method.
if let nav = segue.destination as? UINavigationController, let classBVC = nav.topViewController as? ClassBVC {
classBVC.delegate = self
}
Here we are just creating an instance of ClassBVC
and assign its delegate to self, but what is self here? well, self is the ClassAVC
which has been delegated!
step 6: Finally, look for the pragma step 6 in ClassAVC
and let’s use the functions of the protocol
, start typing func changeBackgroundColor and you will see that it’s auto-completing it for you. You can add any implementation inside it, in this example, we will just change the background color, add this.
//MARK: step 6 finally use the method of the contract
func changeBackgroundColor(_ color: UIColor?) {
view.backgroundColor = color
}
Now run the app!
Delegates
are everywhere and you probably use them without even notice, if you create a tableview
in the past you used delegation, many classes of UIKIT
works around them and many other frameworks
too, they solve these main problems.
Congratulations, you just implement a custom delegate, I know that you are probably thinking, so much trouble just for this? well, delegation is a very important design pattern to understand if you want to become an iOS
developer, and always keep in mind that they have one to one relationship between objects.
You can see the original tutorial here
//1.
//Custom delegate
@protocol TB_RemovedUserCellTag <NSObject>
-(void)didRemoveCellWithTag:(NSInteger)tag;
@end
//2.
//Create a weak reference in a class where you declared the delegate
@property(weak,nonatomic)id <TB_RemovedUserCellTag> removedCellTagDelegate;
//3.
// use it in the class
[self.removedCellTagDelegate didRemoveCellWithTag:self.tag];
//4. import the header file in the class where you want to conform to the protocol
@interface MyClassUsesDelegate ()<TB_RemovedUserCellTag>
@end
//5. Implement the method in the class .m -(void)didRemoveCellWithTag:(NSInteger)tag { NSLog@("Tag %d",tag);
}
Please! check below simple step by step tutorial to understand how Delegates works in iOS.
Delegate in iOS
I have created two ViewControllers (for sending data from one to another)
To create your own delegate, first you need to create a protocol and declare the necessary methods, without implementing. And then implement this protocol into your header class where you want to implement the delegate or delegate methods.
A protocol must be declared as below:
@protocol ServiceResponceDelegate <NSObject>
- (void) serviceDidFailWithRequestType:(NSString*)error;
- (void) serviceDidFinishedSucessfully:(NSString*)success;
@end
This is the service class where some task should be done. It shows how to define delegate and how to set the delegate. In the implementation class after the task is completed the delegate's the methods are called.
@interface ServiceClass : NSObject
{
id <ServiceResponceDelegate> _delegate;
}
- (void) setDelegate:(id)delegate;
- (void) someTask;
@end
@implementation ServiceClass
- (void) setDelegate:(id)delegate
{
_delegate = delegate;
}
- (void) someTask
{
/*
perform task
*/
if (!success)
{
[_delegate serviceDidFailWithRequestType:@”task failed”];
}
else
{
[_delegate serviceDidFinishedSucessfully:@”task success”];
}
}
@end
This is the main view class from where the service class is called by setting the delegate to itself. And also the protocol is implemented in the header class.
@interface viewController: UIViewController <ServiceResponceDelegate>
{
ServiceClass* _service;
}
- (void) go;
@end
@implementation viewController
//
//some methods
//
- (void) go
{
_service = [[ServiceClass alloc] init];
[_service setDelegate:self];
[_service someTask];
}
That's it, and by implementing delegate methods in this class, control will come back once the operation/task is done.
ViewController.h
@protocol NameDelegate <NSObject>
-(void)delegateMEthod: (ArgType) arg;
@end
@property id <NameDelegate> delegate;
ViewController.m
[self.delegate delegateMEthod: argument];
MainViewController.m
ViewController viewController = [ViewController new];
viewController.delegate = self;
Method:
-(void)delegateMEthod: (ArgType) arg{
}
The approved answer is great, but if you're looking for a 1 minute answer try this:
MyClass.h file should look like this (add delegate lines with comments!)
#import <BlaClass/BlaClass.h>
@class MyClass; //define class, so protocol can see MyClass
@protocol MyClassDelegate <NSObject> //define delegate protocol
- (void) myClassDelegateMethod: (MyClass *) sender; //define delegate method to be implemented within another class
@end //end protocol
@interface MyClass : NSObject {
}
@property (nonatomic, weak) id <MyClassDelegate> delegate; //define MyClassDelegate as delegate
@end
MyClass.m file should look like this
#import "MyClass.h"
@implementation MyClass
@synthesize delegate; //synthesise MyClassDelegate delegate
- (void) myMethodToDoStuff {
[self.delegate myClassDelegateMethod:self]; //this will call the method implemented in your other class
}
@end
To use your delegate in another class (UIViewController called MyVC in this case) MyVC.h:
#import "MyClass.h"
@interface MyVC:UIViewController <MyClassDelegate> { //make it a delegate for MyClassDelegate
}
MyVC.m:
myClass.delegate = self; //set its delegate to self somewhere
Implement delegate method
- (void) myClassDelegateMethod: (MyClass *) sender {
NSLog(@"Delegates are great!");
}