You've already started watching Forum Tip #12
Tip 12
-
0:00
Hi. My named is Amit,@paradoxed on Twitter.
-
0:03
So today we're gonna talk about delegation.
-
0:06
Delegation is a very common design pattern used all over when programming an iOS app.
-
0:11
If you've done any of our courses like the Blog Reader project or the Ribbit
-
0:16
app, you've noticed that within the table
-
0:18
View Controller, you have the table view delegate.
-
0:22
And then if you've used a scroll view or a text field,
-
0:25
you've probably used a delegate to go along with that.
-
0:28
So we've used delegate all over the places but we've
-
0:30
never specifically addressed what is the delegate, a design pattern.
-
0:35
Now a delegate or a protocol is basically something that defines
-
0:40
a bunch of methods that can be implemented by any class.
-
0:44
It's the most common design pattern and it means, to delegate control.
-
0:50
So you
-
0:50
are basically giving over control and having
-
0:53
that class implement the functionality of that method.
-
0:57
So let's take a look at how you can
-
0:59
define a protocol, and then implement that in a class.
-
1:04
Alright, I've created a sample app over
-
1:06
here, and, basically it's a single view application.
-
1:11
Let me run the app.
-
1:13
And what you'll see is that there's a button here.
-
1:16
Which says, press me, and then a text is displayed on the text label.
-
1:22
So the way this app is designed is that if I go to the main story board you won't see
-
1:27
anything because it's just a simple view, so there is
-
1:31
our view controller and it has the main view in it.
-
1:35
And let me go to the ViewController.m and you'll see that
-
1:41
it has a property called THCustomView and
-
1:46
all I do is add this custom view as a sub view to my
-
1:51
main view. Now this custom view, let's head on over
-
1:55
to customview.h, as you can see the interface, all it has
-
2:01
is a method called set text where you can set the text of the
-
2:06
label in the custom view.
-
2:10
Now, the, this is assuming that you have created this custom view
-
2:14
that you want to reuse it in multiple places throughout your application.
-
2:19
And you do not want to give direct access to the button or the label.
-
2:23
You just want the person using the custom view to set the
-
2:27
text and then you want to control the look and feel and
-
2:31
the color and all the other attributes of the controls that are housed
-
2:37
within this custom view. Now of course, as a contrived example,
-
2:42
I'm just trying to drive home the point that if you create a complex view
-
2:47
that can be reused throughout your application or you're creating a third
-
2:52
party component so that other people can use it or opensource
-
2:57
this component.
-
2:58
And you don't want to give completely control over all the controls within that
-
3:03
custom view, then what happens is that when a button is pressed.
-
3:10
Now, it's assuming that you, you can, of course, expose the button press method
-
3:17
and set target actions to other view controllers, but the way this custom
-
3:22
control is designed is that you have a button press method with that, within the
-
3:27
custom view, so it's setting itself a text when the button is pressed.
-
3:34
Now, inside the THView controller.m, I actually
-
3:40
want to receive that button pressed event.
-
3:44
I want to know when that button was pressed within the custom
-
3:48
view, so that I can go ahead and call that set text method.
-
3:52
I can simply set the text, but that doesn't help me because
-
3:55
I want to set the text only if the button has been pressed.
-
4:00
Now how do, how does the custom view
-
4:02
instruct the THviewController that the button was pressed.
-
4:07
Right now there's no way of doing that unless we expose the button
-
4:13
as a public property. Right now it's a private property.
-
4:16
Both of these are private properties.
-
4:20
But let's say you've created a, a custom
-
4:22
view and you don't wanna expose these things
-
4:25
as, public properties because you don't want them
-
4:28
to manipulate the look and feel of your control.
-
4:32
So, in the init frame, basically, we are setting the frame for the
-
4:35
button and adding it as a sub-view and the same thing we're doing
-
4:38
for the label.
-
4:41
Now the only way we can do this is if we create a delegate object that
-
4:47
delegates the responsibility of the button-press method to its delegate.
-
4:53
So the only way we can do that is if we create a delegate object within our
-
4:58
custom view that would delegate the responsibility of the button
-
5:04
press method to its delegate. So how do we go
-
5:07
about doing that? Well let's take a look, so, the first
-
5:11
thing I would need in my interface is a delegate object.
-
5:16
So we'll say at property nonatomic, and this would be weak, this is the
-
5:22
perfect example of using a weak property you will see that in a little
-
5:29
bit why it's a weak property and not very strong.
-
5:33
So, I have defined this delegate which is of type id.
-
5:39
We, we don't specify exactly what this is, because we
-
5:42
don't know what kind of delegate it's going to be.
-
5:46
It could be a view controller, it could be another view, it
-
5:49
could be a table view controller, it could be a scroll view.
-
5:53
Anything could be a
-
5:54
delegate of this custom view.
-
5:56
We don't know what could be the delegate, that's why it's an id, which means that
-
6:01
the type of this object is going to be determined at run time.
-
6:08
So, the next thing we need to do is define a protocol.
-
6:11
Now a protocol as its, as the name states, is, is
-
6:15
a set of methods that can be implemented by a delegate.
-
6:21
So the delegate needs some sort of structure, the
-
6:25
delegate just can't be like, well I am going
-
6:27
to do x, y and z, no, the delegate
-
6:30
needs some set up instructions that it can implement.
-
6:34
So we need to define what those instructions look like.
-
6:37
So you need to declare the instructions, which is a
-
6:40
protocol, and then that protocol is implemented by your delegate.
-
6:47
So we will declare our protocol right here in our THCustomView.
-
6:53
So it's after the interface implementation.
-
6:57
So, as you can see, after the end, @end over here.
-
7:01
So we need to give our protocol a name. So, the protocol names are basically the
-
7:06
name of the class that needs a protocol followed by the suffix delegate.
-
7:13
Now, it's usually a protocol on NSObject, so we'll leave that as is.
-
7:18
And then we define our methods.
-
7:20
Now similarly, as you define methods in your @interface, you
-
7:24
can have class methods or you can have instance methods.
-
7:28
So I'll create a instance method called buttonPressed.
-
7:35
Now mind you, this can be called anything you want.
-
7:38
I'm simply calling it buttonPressed because we're
-
7:40
delegating that button pressed action to our delegate.
-
7:46
Alright, so now that we've defined our protocol, it's always
-
7:49
good practice to define what kind of delegate this is.
-
7:54
So, as you can see in these angle brackets
-
7:57
over here, you specified NSObject, which means that the
-
8:00
protocol is of type NF, NSObject. Similarly, you can mention
-
8:07
that this delegate should only be of type THView custom delegate.
-
8:16
You don't want the other class just implementing any kind of delegate
-
8:20
and hoping that this will work, cuz otherwise you'll get a run-time error.
-
8:25
At least when you put
-
8:26
this here, you will get a compiler warning if that delegate hasn't been specified.
-
8:33
We'll come to it when we actually define the delegate in the view controller.
-
8:38
So you'll get a better understanding of why I'm doing this.
-
8:42
Now of course, we're getting an error
-
8:43
here saying that, cannot find protocol declaration.
-
8:48
That's because our protocol is defined after
-
8:51
the@Interface, so one way we can prevent that
-
8:57
error is just cause copying the @protocol ThCustomViewDelegate.
-
9:02
Just as we define an @class, which is a forward declaration, that
-
9:06
hey, this is a class that's going to be implemented in the future.
-
9:11
Similarly we can specify a forward declaration for our protocol.
-
9:16
So basically we're telling the compiler that this is a forward
-
9:20
declaration for a protocol and we're gonna declare it later on somewhere.
-
9:25
And later on, in this case, is right after our @interface declaration.
-
9:30
So, here we have actually created our own, very own protocol.
-
9:35
Now you've must have seen these protocols with
-
9:38
table view controllers or scroll views or text fields.
-
9:41
There are so many delicates defined for you in the UIKit framework.
-
9:46
And here we are defining our very own delegate.
-
9:51
So let's go ahead and see how we can implement this delegate.
-
9:55
So, when we go back to our THViewController.m, and
-
10:01
here in our self.customView, we can refer to that delegate property.
-
10:07
So .customView.delegate
-
10:14
and here we can just specify self.
-
10:17
Because we're saying we are going to be the delegate for the custom view.
-
10:21
We're gonna take over the responsibility of that button
-
10:25
press method, or any other methods the protocol provides.
-
10:31
So, as you can see here, I get a compiler warning and if I click here it says
-
10:37
assigning id THCustomViewDelicate from incompatible type, so that's
-
10:43
why we specify the THCustomViewDelegate in angle brackets.
-
10:49
Because it's saying like, are you really haven't implemented this delegate.
-
10:53
And by implementing, we have to go to the
-
10:56
interface definition of our view controllers.
-
10:59
So let's go to the .h file.
-
11:02
And here is where we specify THCustomViewDelegate.
-
11:08
So that's where we need to specify it and as you can see, we get an error saying
-
11:14
that it cannot find the protocol. So let's Import our THCustomView.
-
11:23
So that error will go away.
-
11:25
And so now when we go back to
-
11:28
our implementation, we don't get the error anymore.
-
11:32
You know, it, it's satisfied that you're gonna be implementing this delegate.
-
11:37
Now, we get another warning here, saying
-
11:39
that method, buttonPressed in protocol not implemented.
-
11:45
That's because we have to implement the methods required
-
11:48
by our protocol.
-
11:52
So, here we'll go and define the button press method.
-
12:01
So we'll say self.customView set text.
-
12:08
And let's set the text, we'll say button pressed
-
12:15
view controller.
-
12:20
So, are we done?
-
12:21
Well, let's run our application and see if this works,
-
12:26
and it won't work but let me show you anyway.
-
12:30
So it says button pressed custom view, and
-
12:32
it should really be saying, button pressed view controller.
-
12:36
Let me remove this space here so that work's consistent.
-
12:41
So why doesn't it work?
-
12:42
We've set our delegates, we've set our button pressed methods.
-
12:47
Well.
-
12:48
All that is fine. We've defined our protocol and
-
12:51
we've set the delegate, but somewhere in our THCustomView implementation,
-
12:58
we need to instruct it that it needs to delegate that buttonPressed method.
-
13:03
We aren't delegating that responsibility anywhere.
-
13:07
So, as you can see, in this buttonPressed method, we're simply setting the text.
-
13:11
So this is the last piece of the puzzle where we check our delegate object,
-
13:17
so we'll say, if self.delegate
-
13:23
responds to selector, so here we're checking to see
-
13:28
if our delegate actually has this method. Does it have this
-
13:33
method implemented, buttonPressed and if it does,
-
13:43
then let's delegate that buttonPressed method, to the method of our delegate.
-
13:52
So there is another method, called perform selector.
-
13:57
So if you were passing an argument, you could use perform selector with object.
-
14:02
In our case, we are not passing an argument so
-
14:05
we will just say perform selector and then add selector, buttonPressed.
-
14:13
So basically what this is doing here is performing this method of our delegate.
-
14:21
And in this case, our delegate is our view controller, could it be something else?
-
14:26
Sure, it could be any other class. And I will say else,
-
14:33
so if it doesn't respond to the buttonPressed
-
14:38
method, then we're just gonna do our default action.
-
14:46
You don't have to do this but I just wanted to show
-
14:49
that you can have default behavior or you could have delegated behavior.
-
14:55
So now if we run our application and I hit Press Me,
-
14:58
you'll notice that it says, button pressed: view controller, as it should.
-
15:05
So going back to our code, one last thing that you want to note is
-
15:10
that in our protocol we can define some of the methods as optional.
-
15:16
As you notice that when we didn't define any of these methods
-
15:20
as optional, the compiler complains saying
-
15:23
that we hadn't implemented the buttonPressed method.
-
15:27
So, how do you define it as optional? Well, you can
-
15:30
just simply put the keyword @optional and basically it'll say whatever
-
15:35
methods follow this @optional definition these methods will be optional.
-
15:41
So now if we go back to our view controller implementation and I remove the
-
15:48
implementation of the buttonPressed method, you'll notice
-
15:51
that I don't get a compiler warning anymore.
-
15:54
And if I run my application,
-
15:56
it's simply going to use the default behavior.
-
16:01
Basically, buttonPressed custom view, so that buttonPressed custom view
-
16:05
is coming from my custom view and not the delegate.
-
16:09
So there you have it.
-
16:10
This is what delegates are all about.
-
16:11
They're about delegating control or responsibility to another class.
-
16:16
Now this doesn't have to be between views
-
16:19
or controls, this could be between view controllers or
-
16:22
your custom class.
-
16:23
So, don't think that you're restricted to
-
16:25
just UIView subclasses when creating a delegate.
You need to sign up for Treehouse in order to download course files.
Sign up