forked from fullonrager/rys-objective-c-tutorial-archive
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprotocols.html
More file actions
370 lines (284 loc) · 19.6 KB
/
protocols.html
File metadata and controls
370 lines (284 loc) · 19.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
<!DOCTYPE html>
<html lang='en'>
<head>
<title>Protocols - Ry’s Objective-C Tutorial - RyPress</title>
<meta charset='UTF-8' />
<meta name='description' content="A protocol is a group of related properties and methods that can be
implemented by any class. They are more flexible than a normal class
interface, since they let you reuse a single API declaration in completely
unrelated classes. This makes it possible to represent horizontal relationships
on top of an existing class hierarchy." />
<meta name='viewport'
content='width=device-width, initial-scale=1.0, maximum-scale=1.0' />
<link rel="icon" type="image/png" href="media/favicon.png" />
<link rel="stylesheet" href="media/style.css" />
<link rel="stylesheet" href="media/pygments.css" />
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-37121774-2', 'auto');
ga('send', 'pageview');
</script>
</head>
<body>
<div id='page'>
<div id='content'>
<nav id='main-nav'>
<a href='/'><img src='media/logo-small.png'
width='120px'
alt='RyPress - Quality Software Tutorials'/></a>
<ul>
<li><a href='/'>Tutorials</a></li>
<li><a href='/secure/purchases.php'>Purchases</a></li>
<li><a href='/about.php'>About</a></li>
</ul>
</nav>
<div class='divider'></div>
<table class="icon-and-text"><tr>
<td><a href="index"><img src="media/icons/index.png" width="40px" height="40px"></a></td>
<td><p>You’re
reading
<a href="index.html"><em>Ry’s Objective-C Tutorial</em></a></p></td>
</tr></table><div class="divider"></div>
<h1 id="protocols">Protocols</h1>
<p>A protocol is a group of related properties and methods that can be
implemented by <em>any</em> class. They are more flexible than a normal class
interface, since they let you reuse a single API declaration in completely
unrelated classes. This makes it possible to represent horizontal relationships
on top of an existing class hierarchy.</p>
<figure>
<img style="max-width: 470px" src="media/protocols/protocol-overview.png">
<figcaption>Unrelated classes adopting the <code>StreetLegal</code>
protocol</figcaption>
</figure>
<p>This is a relatively short module covering the basics behind working with
protocols. We’ll also see how they fit into Objective-C’s dynamic
typing system.</p>
<h2 id="creating-protocols">Creating Protocols</h2>
<p>Like class interfaces, protocols typically reside in a <code>.h</code>
file. To add a protocol to your Xcode project, navigate to
<em>File > New> File…</em> or use the
<em>Cmd+N</em> shortcut. Select <em>Objective-C protocol</em> under the
<em>iOS > Cocoa Touch</em> category.</p>
<figure>
<img style="max-width: 500px" src="media/protocols/creating-a-protocol.png">
<figcaption>Creating a protocol in Xcode</figcaption>
</figure>
<p>In this module, we’ll be working with a protocol called
<code>StreetLegal</code>. Enter this in the next window, and save it in the
project root.</p>
<p>Our protocol will capture the necessary behaviors of a street-legal vehicle.
Defining these characteristics in a protocol lets you apply them to arbitrary
objects instead of forcing them to inherit from the same abstract superclass. A
simple version of the <code>StreetLegal</code> protocol might look something
like the following:</p>
<pre><code class="c1">// StreetLegal.h</code>
<code class="cp">#import</code> <code class="l"><Foundation/Foundation.h></code><code class="cp"></code>
<code class="k">@protocol</code> <code class="nc">StreetLegal</code> <code class="nl"><NSObject></code>
<code class="k">-</code> <code class="p">(</code><code class="kt">void</code><code class="p">)</code><code class="nf">signalStop</code><code class="p">;</code>
<code class="k">-</code> <code class="p">(</code><code class="kt">void</code><code class="p">)</code><code class="nf">signalLeftTurn</code><code class="p">;</code>
<code class="k">-</code> <code class="p">(</code><code class="kt">void</code><code class="p">)</code><code class="nf">signalRightTurn</code><code class="p">;</code>
<code class="k">@end</code>
</pre>
<p>Any objects that adopt this protocol are <em>guaranteed</em> to implement
all of the above methods. The <code><NSObject></code> after the protocol
name incorporates the <a href="http://developer.apple.com/library/ios/#documentation/cocoa/reference/foundation/Protocols/NSObject_Protocol/Reference/NSObject.html"><code>NSObject</code>
protocol</a> (not to be confused with the <a href="https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nsobject_Class/Reference/Reference.html"><code>NSObject</code>
class</a>) into the <code>StreetLegal</code> protocol. That is, any objects
conforming to the <code>StreetLegal</code> protocol are required to conform to
the <code>NSObject</code> protocol, too.</p>
<h2 id="adopting-protocols">Adopting Protocols</h2>
<p>The above API can be adopted by a class by adding it in angled brackets
after the class/superclass name. Create a new classed called
<code>Bicycle</code> and change its header to the following. Note that you need
to import the protocol before you can use it.</p>
<pre><code class="c1">// Bicycle.h</code>
<code class="cp">#import</code> <code class="l"><Foundation/Foundation.h></code><code class="cp"></code>
<code class="cp">#import</code> <code class="l">"StreetLegal.h"</code><code class="cp"></code>
<code class="k">@interface</code> <code class="nc">Bicycle</code> : <code class="nc">NSObject</code> <code class="nl"><StreetLegal></code>
<code class="k">-</code> <code class="p">(</code><code class="kt">void</code><code class="p">)</code><code class="nf">startPedaling</code><code class="p">;</code>
<code class="k">-</code> <code class="p">(</code><code class="kt">void</code><code class="p">)</code><code class="nf">removeFrontWheel</code><code class="p">;</code>
<code class="k">-</code> <code class="p">(</code><code class="kt">void</code><code class="p">)</code><code class="nf">lockToStructure:</code><code class="p">(</code><code class="kt">id</code><code class="p">)</code><code class="nv">theStructure</code><code class="p">;</code>
<code class="k">@end</code>
</pre>
<p>Adopting the protocol is like adding all of the methods in
<code>StreetLegal.h</code> to <code>Bicycle.h</code>. This would work the exact
same way even if <code>Bicycle</code> inherited from a different superclass.
Multiple protocols can be adopted by separating them with commas (e.g.,
<code><StreetLegal, SomeOtherProtocol></code>).</p>
<p>There’s nothing special about the <code>Bicycle</code>
implementation—it just has to make sure all of the methods declared by
<code>Bicycle.h</code> <em>and</em> <code>StreetLegal.h</code> are
implemented:</p>
<pre><code class="c1">// Bicycle.m</code>
<code class="cp">#import</code> <code class="l">"Bicycle.h"</code><code class="cp"></code>
<code class="k">@implementation</code> <code class="nc">Bicycle</code>
<code class="k">-</code> <code class="p">(</code><code class="kt">void</code><code class="p">)</code><code class="nf">signalStop</code> <code class="p">{</code>
<code class="nb">NSLog</code><code class="p">(</code><code class="s">@"Bending left arm downwards"</code><code class="p">);</code>
<code class="p">}</code>
<code class="k">-</code> <code class="p">(</code><code class="kt">void</code><code class="p">)</code><code class="nf">signalLeftTurn</code> <code class="p">{</code>
<code class="nb">NSLog</code><code class="p">(</code><code class="s">@"Extending left arm outwards"</code><code class="p">);</code>
<code class="p">}</code>
<code class="k">-</code> <code class="p">(</code><code class="kt">void</code><code class="p">)</code><code class="nf">signalRightTurn</code> <code class="p">{</code>
<code class="nb">NSLog</code><code class="p">(</code><code class="s">@"Bending left arm upwards"</code><code class="p">);</code>
<code class="p">}</code>
<code class="k">-</code> <code class="p">(</code><code class="kt">void</code><code class="p">)</code><code class="nf">startPedaling</code> <code class="p">{</code>
<code class="nb">NSLog</code><code class="p">(</code><code class="s">@"Here we go!"</code><code class="p">);</code>
<code class="p">}</code>
<code class="k">-</code> <code class="p">(</code><code class="kt">void</code><code class="p">)</code><code class="nf">removeFrontWheel</code> <code class="p">{</code>
<code class="nb">NSLog</code><code class="p">(</code><code class="s">@"Front wheel is off."</code>
<code class="s">"Should probably replace that before pedaling..."</code><code class="p">);</code>
<code class="p">}</code>
<code class="k">-</code> <code class="p">(</code><code class="kt">void</code><code class="p">)</code><code class="nf">lockToStructure:</code><code class="p">(</code><code class="kt">id</code><code class="p">)</code><code class="nv">theStructure</code> <code class="p">{</code>
<code class="nb">NSLog</code><code class="p">(</code><code class="s">@"Locked to structure. Don't forget the combination!"</code><code class="p">);</code>
<code class="p">}</code>
<code class="k">@end</code>
</pre>
<p>Now, when you use the <code>Bicycle</code> class, you can assume it responds
to the API defined by the protocol. It’s as though
<code>signalStop</code>, <code>signalLeftTurn</code>, and
<code>signalRightTurn</code> were declared in <code>Bicycle.h</code>:</p>
<pre><code class="c1">// main.m</code>
<code class="cp">#import</code> <code class="l"><Foundation/Foundation.h></code><code class="cp"></code>
<code class="cp">#import</code> <code class="l">"Bicycle.h"</code><code class="cp"></code>
<code class="kt">int</code> <code class="nf">main</code><code class="p">(</code><code class="kt">int</code> <code class="n">argc</code><code class="p">,</code> <code class="kt">const</code> <code class="kt">char</code> <code class="o">*</code> <code class="n">argv</code><code class="p">[])</code> <code class="p">{</code>
<code class="k">@autoreleasepool</code> <code class="p">{</code>
<code class="n">Bicycle</code> <code class="o">*</code><code class="n">bike</code> <code class="o">=</code> <code class="p">[[</code><code class="n">Bicycle</code> <code class="nf">alloc</code><code class="p">]</code> <code class="nf">init</code><code class="p">];</code>
<code class="p">[</code><code class="n">bike</code> <code class="nf">startPedaling</code><code class="p">];</code>
<code class="p">[</code><code class="n">bike</code> <code class="nf">signalLeftTurn</code><code class="p">];</code>
<code class="p">[</code><code class="n">bike</code> <code class="nf">signalStop</code><code class="p">];</code>
<code class="p">[</code><code class="n">bike</code> <code class="nf">lockToStructure:</code><code class="kc">nil</code><code class="p">];</code>
<code class="p">}</code>
<code class="k">return</code> <code class="mi">0</code><code class="p">;</code>
<code class="p">}</code>
</pre>
<h2 id="type-checking-with-protocols">Type Checking With Protocols</h2>
<p>Just like classes, protocols can be used to type check variables. To make
sure an object adopts a protocol, put the protocol name after the data type in
the variable declaration, as shown below. The next code snippet also assumes
that you have created a <code>Car</code> class that adopts the
<code>StreetLegal</code> protocol:</p>
<pre><code class="c1">// main.m</code>
<code class="cp">#import</code> <code class="l"><Foundation/Foundation.h></code><code class="cp"></code>
<code class="cp">#import</code> <code class="l">"Bicycle.h"</code><code class="cp"></code>
<code class="cp">#import</code> <code class="l">"Car.h"</code><code class="cp"></code>
<code class="cp">#import</code> <code class="l">"StreetLegal.h"</code><code class="cp"></code>
<code class="kt">int</code> <code class="nf">main</code><code class="p">(</code><code class="kt">int</code> <code class="n">argc</code><code class="p">,</code> <code class="kt">const</code> <code class="kt">char</code> <code class="o">*</code> <code class="n">argv</code><code class="p">[])</code> <code class="p">{</code>
<code class="k">@autoreleasepool</code> <code class="p">{</code>
<code class="kt">id</code> <code class="nl"><StreetLegal></code> <code class="n">mysteryVehicle</code> <code class="o">=</code> <code class="p">[[</code><code class="n">Car</code> <code class="nf">alloc</code><code class="p">]</code> <code class="nf">init</code><code class="p">];</code>
<code class="p">[</code><code class="n">mysteryVehicle</code> <code class="nf">signalLeftTurn</code><code class="p">];</code>
<code class="n">mysteryVehicle</code> <code class="o">=</code> <code class="p">[[</code><code class="n">Bicycle</code> <code class="nf">alloc</code><code class="p">]</code> <code class="nf">init</code><code class="p">];</code>
<code class="p">[</code><code class="n">mysteryVehicle</code> <code class="nf">signalLeftTurn</code><code class="p">];</code>
<code class="p">}</code>
<code class="k">return</code> <code class="mi">0</code><code class="p">;</code>
<code class="p">}</code>
</pre>
<p>It doesn’t matter if <code>Car</code> and <code>Bicycle</code> inherit
from the same superclass—the fact that they both adopt the
<code>StreetLegal</code> protocol lets us store either of them in a variable
declared with <code>id <StreetLegal></code>. This is an example of how
protocols can capture common functionality between unrelated classes.</p>
<p>Objects can also be checked against a protocol using the
<code>conformsToProtocol:</code> method defined by the <code>NSObject</code>
protocol. It takes a protocol object as an argument, which can be obtained via
the <code>@protocol()</code> directive. This works much like the <a href="methods.html#selectors"><code>@selector()</code></a> directive, but you
pass the protocol name instead of a method name, like so:</p>
<pre><code class="k">if</code> <code class="p">([</code><code class="n">mysteryVehicle</code> <code class="nf">conformsToProtocol:</code><code class="k">@protocol</code><code class="p">(</code><code class="n">StreetLegal</code><code class="p">)])</code> <code class="p">{</code>
<code class="p">[</code><code class="n">mysteryVehicle</code> <code class="nf">signalStop</code><code class="p">];</code>
<code class="p">[</code><code class="n">mysteryVehicle</code> <code class="nf">signalLeftTurn</code><code class="p">];</code>
<code class="p">[</code><code class="n">mysteryVehicle</code> <code class="nf">signalRightTurn</code><code class="p">];</code>
<code class="p">}</code>
</pre>
<p>Using protocols in this manner is like saying, “Make sure this object
has this particular set of functionality.” This is a very powerful tool
for dynamic typing, as it lets you use a well-defined API without worrying
about what kind of object you’re dealing with.</p>
<h2 id="protocols-in-the-real-world">Protocols In The Real World</h2>
<p>A more realistic use case can be seen in your everyday iOS and OS X
application development. The entry point into any app is an “application
delegate” object that handles the major events in a program’s life
cycle. Instead of forcing the delegate to inherit from any particular
superclass, the <a href="http://developer.apple.com/library/ios/#documentation/uikit/reference/UIKit_Framework/_index.html">UIKit
Framework</a> just makes you adopt a protocol:</p>
<pre><code class="k">@interface</code> <code class="nc">YourAppDelegate</code> : <code class="nc">UIResponder</code> <code class="nl"><UIApplicationDelegate></code>
</pre>
<p>As long as it responds to the methods defined by <a href="https://developer.apple.com/library/ios/documentation/uikit/reference/uiapplicationdelegate_protocol/Reference/Reference.html"><code>UIApplicationDelegate</code></a>,
you can use <em>any</em> object as your application delegate. Implementing the
delegate design pattern through protocols instead of subclassing gives
developers much more leeway when it comes to organizing their applications.</p>
<p>You can see a concrete example of this in the <a href="http://rypress.com/tutorials/cocoa/interface-builder">Interface
Builder</a> chapter of <a href="http://rypress.com/tutorials/cocoa">Ry’s
Cocoa Tutorial</a>. It uses the project’s default app delegate to respond
to user input.</p>
<h2 id="summary">Summary</h2>
<p>In this module, we added another organizational tool to our collection.
Protocols are a way to abstract shared properties and methods into a dedicated
file. This helps reduce redundant code and lets you dynamically check if an
object supports an arbitrary set of functionality.</p>
<p> You’ll find many protocols throughout the Cocoa frameworks. A common
use case is to let you alter the behavior of certain classes without the need
to subclass them. For instance, the <a href="http://rypress.com/tutorials/cocoa/ui-components/table-views"><em>Table
View</em></a>, <a href="http://rypress.com/tutorials/cocoa/ui-components/outline-views"><em>Outline
View</em></a>, and <a href="http://rypress.com/tutorials/cocoa/ui-components/collection-views"><em>Collection
View</em></a> UI components all use a data source and delegate object to
configure their internal behavior. The data source and delegate are defined as
protocols, so you can implement the necessary methods in <em>any</em> object
you want.</p>
<p>The next module introduces categories, which are a flexible option for
modularizing classes and providing opt-in support for an API.</p>
<div class="divider" style="margin-top: 2em; margin-bottom: 1.3em;"></div><table class="icon-and-text advert"><tr>
<td><a href="http://rypress.com/tutorials/cocoa"><img src="media/advert-image.png" width="120px" height="165px" class="cover"></a></td>
<td><p id="advert-text">Be sure to check out <a href="http://rypress.com/tutorials/cocoa">Ry’s Cocoa Tutorial</a>. This
brand new guide is a complete walkthrough of Mac App development, and it
leverages all of the Objective-C skills that we just discussed. <a href="http://rypress.com/tutorials/cocoa">Learn more ›</a></p></td>
</tr></table>
<div id='mailing-list'>
<div class='divider' style='margin: 1.8em -22px;'></div>
<h3>Mailing List</h3>
<p>Sign up for my low-volume mailing list to find out when new content is
released. Next up is a comprehensive <a
href='https://developer.apple.com/swift/'>Swift</a> tutorial planned for late
January.</p>
<form id='mailing-list-form'
action='/secure/mailing-list/request-add' method='get'>
<label>
<div class='label'>Email Address:</div>
<div class='input'>
<input name='email'
style='width: 200px;'
type='email' />
</div>
</label>
<input id='mailing-list-button'
class='button'
style='margin-top: .5em;'
type='submit' value='Subscribe'/>
</form>
<div style='clear: both'></div>
<p class='fine-print'>You’ll only receive emails when new tutorials are
released, and your contact information will never be shared with third
parties. <a href='/secure/mailing-list/unsubscribe'>Click here</a> to
unsubscribe.</p>
</div>
<div class='divider'></div>
<footer id='footer' class='fine-print'>
<ul>
<li><a href='/licensing.php'>© 2012-2014</a></li>
<li><a href='/'>RyPress.com</a></li>
<li>
<a href='/licensing.php'>All Rights Reserved</a>
</li>
<li>
<a href='/tos.php'>Terms of Service</a>
</li>
<li>
<a href='/privacy.php'>Privacy Policy</a>
</li>
</ul>
</footer>
</div> <!-- .content -->
</div> <!-- .page -->
</body>
</html>