You are on page 1of 976

www.it-ebooks.

info
www.it-ebooks.info
iOS 6 Programming Cookbook
Vandad Nahavandipoor
Beijing Cambridge Farnham Kln Sebastopol Tokyo
www.it-ebooks.info
iOS 6 Programming Cookbook
Ly Vanuau Nahavanuipooi
Copyiight 2013 Vanuau Nahavanuipooi. All iights ieseiveu.
Piinteu in the Uniteu States ol Ameiica.
PuLlisheu Ly O`Reilly Meuia, Inc., 1005 Giavenstein Highway Noith, SeLastopol, CA 95+72.
O`Reilly Looks may Le puichaseu loi euucational, Lusiness, oi sales piomotional use. Online euitions
aie also availaLle loi most titles (http://ny.sajariboo|son|inc.con). Foi moie inloimation, contact oui
coipoiate/institutional sales uepaitment: S00-99S-993S oi corporatcorci||y.con.
Editors: Anuy Oiam anu Rachel Roumeliotis
Production Editor: Rachel Steely
Copyeditor: ]asmine Kwityn
Proofreader: ]ason Schneiueiman
Indexer: BoL Plahlei
Cover Designer: Kaien Montgomeiy
Interior Designer: Daviu Futato
Illustrator: ReLecca Demaiest
DecemLei 2012: Fiist Euition.
Revision History for the First Edition:
2012-11-19 Fiist ielease
See http://orci||y.con/cata|og/crrata.csp?isbn=9781119312753 loi ielease uetails.
Nutshell HanuLook, the Nutshell HanuLook logo, anu the O`Reilly logo aie iegisteieu tiauemaiks ol
O`Reilly Meuia, Inc. iOS Progranning Coo|boo|, image ol a shiew teniec, anu ielateu tiaue uiess aie
tiauemaiks ol O`Reilly Meuia, Inc.
Many ol the uesignations useu Ly manulactuieis anu selleis to uistinguish theii piouucts aie claimeu as
tiauemaiks. Vheie those uesignations appeai in this Look, anu O`Reilly Meuia, Inc., was awaie ol a
tiauemaik claim, the uesignations have Leen piinteu in caps oi initial caps.
Vhile eveiy piecaution has Leen taken in the piepaiation ol this Look, the puLlishei anu authoi assume
no iesponsiLility loi eiiois oi omissions, oi loi uamages iesulting liom the use ol the inloimation con-
taineu heiein.
ISBN: 97S-1-++9-3+275-3
LSI
1353339+79
www.it-ebooks.info
Table of Contents
Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi
1. The Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1 Cieating a Simple iOS App in Xcoue 2
1.2 Unueistanuing Inteilace Builuei 5
1.3 Compiling iOS Apps 7
1.+ Running iOS Apps on the Simulatoi 11
1.5 Running iOS Apps on iOS Devices 12
1.6 Packaging iOS Apps loi DistiiLution 15
1.7 Declaiing VaiiaLles in OLjective-C 20
1.S Allocating anu Making Use ol Stiings 23
1.9 Compaiing Values in OLjective-C with an il Statement 27
1.10 Implementing Loops with loi Statements 30
1.11 Implementing while Loops 32
1.12 Cieating Custom Classes 35
1.13 Delining Functionality loi Classes 3S
1.1+ Delining Two oi Moie Methous with the Same Name +3
1.15 Allocating anu Initializing OLjects +6
1.16 Auuing Piopeities to Classes +S
1.17 Moving liom Manual Releience Counting to Automatic Releience
Counting 52
1.1S Typecasting with Automatic Releience Counting 57
1.19 Delegating Tasks with Piotocols 60
1.20 Deteimining Vhethei Instance oi Class Methous Aie AvailaLle 66
1.21 Deteimining Vhethei a Class Is AvailaLle at Runtime 69
1.22 Allocating anu Making Use ol NumLeis 70
1.23 Allocating anu Making Use ol Aiiays 72
1.2+ Allocating anu Making Use ol Dictionaiies 77
1.25 Allocating anu Making Use ol Sets S0
1.26 Cieating Bunules S3
1.27 Loauing Data liom the Main Bunule S+
1.2S Loauing Data liom Othei Bunules SS
iii
www.it-ebooks.info
1.29 Senuing Notilications with NSNotilicationCentei 91
1.30 Listening loi Notilications Sent liom NSNotilicationCentei 9+
2. Implementing Controllers and Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
2.1 Displaying Aleits with UIAleitView 100
2.2 Cieating anu Using Switches with UISwitch 107
2.3 Customizing the UISwitch 111
2.+ Picking Values with UIPickeiView 11+
2.5 Picking the Date anu Time with UIDatePickei 122
2.6 Implementing Range Pickeis with UISliuei 126
2.7 Customizing the UISliuei 130
2.S Giouping Compact Options with UISegmenteuContiol 135
2.9 Customizing the UISegmenteuContiol 1+0
2.10 Piesenting anu Managing Views with UIViewContiollei 1+6
2.11 Piesenting Shaiing Options with UIActivityViewContiollei 151
2.12 Implementing Navigation with UINavigationContiollei 155
2.13 Manipulating a Navigation Contiollei`s Aiiay ol View Contiolleis 161
2.1+ Displaying an Image on a Navigation Bai 162
2.15 Auuing Buttons to Navigation Bais Using UIBaiButtonItem 163
2.16 Piesenting Multiple View Contiolleis with UITaLBaiContiollei 171
2.17 Displaying Static Text with UILaLel 177
2.1S Customizing the UILaLel 1S1
2.19 Accepting Usei Text Input with UITextFielu 1S3
2.20 Displaying Long Lines ol Text with UITextView 192
2.21 Auuing Buttons to the Usei Inteilace with UIButton 196
2.22 Displaying Images with UIImageView 200
2.23 Cieating SciollaLle Content with UISciollView 20+
2.2+ Loauing VeL Pages with UIVeLView 209
2.25 Piesenting Mastei-Detail Views with UISplitViewContiollei 213
2.26 EnaLling Paging with UIPageViewContiollei 219
2.27 Displaying Popoveis with UIPopoveiContiollei 223
2.2S Displaying Piogiess with UIPiogiessView 232
2.29 Listening anu Reacting to KeyLoaiu Notilications 23+
2.30 Constiucting anu Displaying Styleu Texts 2+S
3. Auto Layout and the Visual Format Language . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
3.1 Placing UI Components in the Centei ol the Scieen 256
3.2 Delining Hoiizontal anu Veitical Constiaints with the
Visual Foimat Language 259
3.3 Utilizing Cioss View Constiaints 265
3.+ Conliguiing Auto Layout Constiaints in Inteilace Builuei 273
iv | Table of Contents
www.it-ebooks.info
4. Constructing and Using Table Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
+.1 Instantiating a TaLle View 279
+.2 Assigning a Delegate to a TaLle View 2S1
+.3 Populating a TaLle View with Data 2S3
+.+ Receiving anu Hanuling TaLle View Events 2S7
+.5 Using Dilleient Types ol Accessoiies in a TaLle View Cell 2SS
+.6 Cieating Custom TaLle View Cell Accessoiies 290
+.7 Displaying Hieiaichical Data in TaLle Views 293
+.S EnaLling Swipe Deletion ol TaLle View Cells 29+
+.9 Constiucting Heaueis anu Footeis in TaLle Views 297
+.10 Displaying Context Menus on TaLle View Cells 306
+.11 Moving Cells anu Sections in TaLle Views 310
+.12 Deleting Cells anu Sections liom TaLle Views 317
+.13 Utilizing the UITaLleViewContiollei loi Easy Cieation ol TaLle
Views 325
+.1+ Displaying a Reliesh Contiol loi TaLle Views 332
5. Storyboards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337
5.1 Cieating a Pioject with StoiyLoaius 33S
5.2 Auuing a Navigation Contiollei to a StoiyLoaiu 3+0
5.3 Passing Data Fiom One Scieen to Anothei 350
5.+ Auuing a StoiyLoaiu to an Existing Pioject 352
6. Concurrency . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355
6.1 Constiucting Block OLjects 361
6.2 Accessing VaiiaLles in Block OLjects 365
6.3 Invoking Block OLjects 371
6.+ Dispatching Tasks to Gianu Cential Dispatch 372
6.5 Peiloiming UI-Relateu Tasks with GCD 373
6.6 Executing Non-UI Relateu Tasks Synchionously with GCD 377
6.7 Executing Non-UI Relateu Tasks Asynchionously with GCD 3S0
6.S Peiloiming Tasks Altei a Delay with GCD 3S6
6.9 Peiloiming a Task Only Once with GCD 3S9
6.10 Giouping Tasks Togethei with GCD 391
6.11 Constiucting Youi Own Dispatch Queues with GCD 39+
6.12 Running Tasks Synchionously with Opeiations 397
6.13 Running Tasks Asynchionously with Opeiations +0+
6.1+ Cieating Depenuency Between Opeiations +11
6.15 Cieating Timeis +13
6.16 Cieating Concuiiency with Thieaus +1S
6.17 Invoking Backgiounu Methous +23
6.1S Exiting Thieaus anu Timeis +25
Table of Contents | v
www.it-ebooks.info
7. Core Location and Maps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 429
7.1 Cieating a Map View +30
7.2 Hanuling the Events ol a Map View +32
7.3 Pinpointing the Location ol a Device +3+
7.+ Displaying Pins on a Map View +37
7.5 Displaying Pins with Dilleient Colois on a Map View +39
7.6 Displaying Custom Pins on a Map View ++6
7.7 Conveiting Meaninglul Auuiesses to Longituue anu Latituue ++S
7.S Conveiting Longituue anu Latituue to a Meaninglul Auuiess +50
8. Implementing Gesture Recognizers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 453
S.1 Detecting Swipe Gestuies +55
S.2 Detecting Rotation Gestuies +57
S.3 Detecting Panning anu Diagging Gestuies +60
S.+ Detecting Long Piess Gestuies +63
S.5 Detecting Tap Gestuies +66
S.6 Detecting Pinch Gestuies +6S
9. Networking, JSON, XML, and Twitter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 471
9.1 Downloauing Asynchionously with NSURLConnection +71
9.2 Hanuling Timeouts in Asynchionous Connections +7+
9.3 Downloauing Synchionously with NSURLConnection +75
9.+ Mouilying a URL Reguest with NSMutaLleURLReguest +7S
9.5 Senuing HTTP GET Reguests with NSURLConnection +79
9.6 Senuing HTTP POST Reguests with NSURLConnection +S1
9.7 Senuing HTTP DELETE Reguests with NSURLConnection +S+
9.S Senuing HTTP PUT Reguests with NSURLConnection +S6
9.9 Seiializing Aiiays anu Dictionaiies into ]SON +SS
9.10 Deseiializing ]SON into Aiiays anu Dictionaiies +91
9.11 Integiating Twittei Functionality into Youi Apps +9+
9.12 Paising XML with NSXMLPaisei +99
10. Audio and Video . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 505
10.1 Playing Auuio Files 505
10.2 Hanuling Inteiiuptions while Playing Auuio 507
10.3 Recoiuing Auuio 50S
10.+ Hanuling Inteiiuptions while Recoiuing Auuio 515
10.5 Playing Auuio ovei Othei Active Sounus 516
10.6 Playing Viueo Files 519
10.7 Captuiing ThumLnails liom a Viueo File 523
10.S Accessing the Music LiLiaiy 526
vi | Table of Contents
www.it-ebooks.info
11. Address Book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 535
11.1 Reguesting Access to the Auuiess Book 537
11.2 Retiieving a Releience to an Auuiess Book 5+0
11.3 Retiieving All the People in the Auuiess Book 5+3
11.+ Retiieving Piopeities ol Auuiess Book Entiies 5++
11.5 Inseiting a Peison Entiy into the Auuiess Book 5+9
11.6 Inseiting a Gioup Entiy into the Auuiess Book 552
11.7 Auuing Peisons to Gioups 555
11.S Seaiching the Auuiess Book 557
11.9 Retiieving anu Setting a Peison`s Auuiess Book Image 562
12. Files and Folder Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 571
12.1 Finuing the Paths ol the Most Uselul Folueis on Disk 573
12.2 Viiting to anu Reauing liom Files 575
12.3 Cieating Folueis on Disk 5S0
12.+ Enumeiating Files anu Folueis 5S1
12.5 Deleting Files anu Folueis 5S6
12.6 Secuiing Files on Disk 590
12.7 Saving OLjects to Files 595
13. Camera and the Photo Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 599
13.1 Detecting anu PioLing the Cameia 601
13.2 Taking Photos with the Cameia 606
13.3 Taking Viueos with the Cameia 610
13.+ Stoiing Photos in the Photo LiLiaiy 613
13.5 Stoiing Viueos in the Photo LiLiaiy 616
13.6 Retiieving Photos anu Viueos liom the Photo LiLiaiy 61S
13.7 Retiieving Assets liom the Assets LiLiaiy 620
13.S Euiting Viueos on an iOS Device 627
14. Multitasking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 633
1+.1 Detecting the AvailaLility ol Multitasking 63+
1+.2 Completing a Long-Running Task in the Backgiounu 635
1+.3 Receiving Local Notilications in the Backgiounu 63S
1+.+ Playing Auuio in the Backgiounu 6+6
1+.5 Hanuling Location Changes in the Backgiounu 6+S
1+.6 Saving anu Loauing the State ol Multitasking iOS Apps 651
1+.7 Hanuling Netwoik Connections in the Backgiounu 65+
1+.S Hanuling Notilications Deliveieu to a Vaking App 657
1+.9 Responuing to Changes in App Settings 659
1+.10 Opting Out ol Multitasking 662
Table of Contents | vii
www.it-ebooks.info
15. Core Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 663
15.1 Cieating a Coie Data Mouel with Xcoue 666
15.2 Geneiating Class Files loi Coie Data Entities 670
15.3 Cieating anu Saving Data Using Coie Data 672
15.+ Reauing Data liom Coie Data 67+
15.5 Deleting Data liom Coie Data 677
15.6 Soiting Data in Coie Data 6S0
15.7 Boosting Data Access in TaLle Views 6S2
15.S Implementing Relationships in Coie Data 693
16. Dates, Calendars, and Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 701
16.1 Retiieving the List ol Calenuais 70+
16.2 Auuing Events to Calenuais 706
16.3 Accessing the Contents ol Calenuais 710
16.+ Removing Events liom Calenuais 713
16.5 Auuing Recuiiing Events to Calenuais 71S
16.6 Retiieving the Attenuees ol an Event 722
16.7 Auuing Alaims to Calenuais 727
16.S Hanuling Event Changeu Notilications 729
16.9 Piesenting Event View Contiolleis 732
16.10 Piesenting Event Euit View Contiolleis 735
17. Graphics and Animations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 739
17.1 Enumeiating anu Loauing Fonts 7+7
17.2 Diawing Text 7+9
17.3 Constiucting, Setting, anu Using Colois 750
17.+ Diawing Images 756
17.5 Constiucting ResizaLle Images 759
17.6 Diawing Lines 765
17.7 Constiucting Paths 771
17.S Diawing Rectangles 77+
17.9 Auuing Shauows to Shapes 77S
17.10 Diawing Giauients 7S3
17.11 Displacing Shapes Diawn on Giaphic Contexts 790
17.12 Scaling Shapes Diawn on Giaphic Contexts 79+
17.13 Rotating Shapes Diawn on Giaphic Contexts 797
17.1+ Animating anu Moving Views 79S
17.15 Animating anu Scaling Views S07
17.16 Animating anu Rotating Views S0S
18. Core Motion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 811
1S.1 Detecting the AvailaLility ol an Acceleiometei S12
1S.2 Detecting the AvailaLility ol a Gyioscope S1+
viii | Table of Contents
www.it-ebooks.info
1S.3 Retiieving Acceleiometei Data S16
1S.+ Detecting Shakes on an iOS Device S19
1S.5 Retiieving Gyioscope Data S22
19. iCloud . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 825
19.1 Setting Up Youi App loi iClouu S26
19.2 Stoiing anu Synchionizing Dictionaiies in iClouu S31
19.3 Cieating anu Managing Folueis loi Apps in iClouu S35
19.+ Seaiching loi Files anu Folueis in iClouu S+1
19.5 Stoiing Usei Documents in iClouu S51
19.6 Managing the State ol Documents in iClouu S65
19.7 Hanuling Conllicts in iClouu Documents S6S
20. Pass Kit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 879
20.1 Cieating Pass Kit Ceitilicates SS2
20.2 Cieating Pass Files S90
20.3 Pioviuing Icons anu Images loi Passes S99
20.+ Piepaiing Youi Passes loi Digital Signatuie 901
20.5 Signing Passes Digitally 903
20.6 DistiiLuting Passes Using Email 90S
20.7 DistiiLuting Passes Using VeL Seivices 911
20.S EnaLling Youi iOS Apps to Access Passes on iOS Devices 913
20.9 Inteiacting with PassLook Piogiammatically 917
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 923
Table of Contents | ix
www.it-ebooks.info
www.it-ebooks.info
Preface
The long-awaiteu iOS 6 SDK (Soltwaie Development Kit) is linally out, anu we neeu
to leain aLout all the gieat leatuies that this ielease olleis us. Apple uiu a gieat joL
auuing new leatuies to the SDK anu, ol couise, to iOS itsell. iOS 6 is much moie staLle
than the pievious veisions ol iOS, as you woulu expect. Things move veiy last in Apple`s
woilu, anu the iOS SDK is no exception. OLviously, picking up this Look is an inui-
cation that you aie ieauy to stait leaining all theie is to know aLout iOS 6 SDK, anu
that is lantastic.
I`ve peisonally woikeu with companies ol vaiious sizes aiounu the woilu anu have Leen
ueveloping soltwaie pietty much since I was aLout seven yeais olu. (I staiteu out on
my lathei`s Commouoie 6+ Leloie moving on to an Intel S01S6 machine, an S02S6,
anu then Pentium machines.) I uiu a lot ol assemLly uevelopment as well as some OS
piogiamming, incluuing wiiting a keinel ol a toy opeiating system. I ieally enjoy solt-
waie uevelopment anu have tiue passion loi it. I can expiess mysell using piogiamming,
anu that`s pioLaLly the main ieason I enjoy wiiting apps anu soltwaie in geneial. Since
2007, I`ve solely locuseu on wiiting iOS apps, anu have Leen woiking with some ieally
high-piolile companies aiounu the woilu to help them with theii piojects. I`ve woikeu
with Scium Masteis (loi whom I have much iespect), pioject manageis, ueliveiy man-
ageis, ielease manageis, testeis, anu lellow iOS uevelopeisanu have uone my Lest to
leain as much as possiLle liom them. This euition ol the Look is the piouuct ol all the
knowleuge that I have gaineu in many yeais wiiting iOS apps.
This euition ol the Look is especially exciting loi me, Lecause ol all the mouilications
anu line-tuning we have uone to it as a iesult ol going thiough the leeuLack that we
ieceiveu in the last two euitions. In this euition, oLviously you will leain all aLout the
new leatuies ol iOS 6 SDK. On top ol that, you will leain aLout Pass Kit, Auto Layout
constiaints, lile/loluei management, customization ol UI components, anu much
moie. Ol couise, you will also leain aLout all the cool new leatuies that Apple has
auueu to the LLVM compilei anu the iuntime, such as autosynthesizeu piopeities,
expiession Loxing, anu collection suLsciipting.
xi
www.it-ebooks.info
Audience
I assume you aie comloitaLle with the iOS uevelopment enviionment anu know how
to cieate an app loi the iPhone oi iPau. This Look uoes not get novice piogiammeis
staiteu, Lut piesents uselul ways to get things uone loi iOS piogiammeis ianging liom
novices to expeits.
Organization of This Book
In this Look, we will uiscuss liamewoiks anu classes that aie availaLle in iOS 6 SDK.
This Look uoes its Lest to teach you the latest anu the gieatest APIs. As you know, some
useis ol youi apps may still Le on oluei veisions ol iOS, so please consiuei those useis
anu choose youi APIs wisely, uepenuing on the minimum iOS veision that you want
to taiget with youi apps.
Heie is a concise Lieakuown ol the mateiial each chaptei coveis:
Chaptei 1, Thc Basics
Explains how OLjective-C classes aie stiuctuieu anu how oLjects can Le instanti-
ateu. The chaptei talks aLout piopeities anu uelegates as well as memoiy man-
agement in OLjective-C. Even il you aie competent in OLjective-C, I stiongly
suggest that you ieau this chaptei, even il you only skim thiough it, to unueistanu
the Lasic mateiial that is useu in the iest ol the Look.
Chaptei 2, |np|cncnting Contro||crs and \icws
DesciiLes vaiious appioaches to constiucting youi iOS application`s usei inteilace
Ly taking auvantage ol uilleient tools the SDK pioviues. This chaptei also intio-
uuces you to leatuies that aie only availaLle on the iPau, such as the popovei anu
split view contiolleis.
Chaptei 3, Auto Layout and thc \isua| Iornat Languagc
Explains how you can take auvantage ol Auto Layout in the iOS SDK in oiuei to
constiuct youi UI in such a way that it can Le iesizeu anu stietcheu to pietty much
any scieen uimension.
Chaptei +, Constructing and Using Tab|c \icws
Shows how you can woik with taLle views to cieate piolessional-looking iOS
applications. TaLle views aie veiy uynamic in natuie, anu as a iesult, piogiammeis
sometimes have uilliculty unueistanuing how they shoulu woik with them. By
ieauing this chaptei anu tiying out the example coue, you will gain the knowleuge
that is ieguiieu to comloitaLly woik with taLle views.
Chaptei 5, Storyboards
Demonstiates the piocess ol storyboarding, the new way to ueline the connections
Letween uilleient scieens in youi app. The gieat thing aLout stoiyLoaiuing is that
you uon`t have to know anything aLout iOS piogiamming to get a simple app
iunning. This helps piouuct analysts, piouuct owneis, oi uesigneis who woik
xii | Preface
www.it-ebooks.info
inuepenuently ol uevelopeis to gain knowleuge ol the UI components iOS olleis
anu to Luilu moie ioLust piouucts. Piogiammeis can also take auvantage ol stoiy-
Loaiuing to easily cieate piototypes. StoiyLoaiuing is just lun, whethei you uo it
on papei oi using Xcoue.
Chaptei 6, Concurrcncy
As humans, we can uo many things simultaneously without thinking much aLout
it. Vith auvances in computei technology, moLile uevices aie also aLle to multi-
task, anu pioviue piogiammeis with tools anu mechanisms that can accomplish
moie than one task at the same time. This is calleu concurrcncy. In this chaptei,
you will leain aLout Gianu Cential Dispatch, Apple`s pieleiieu way ol achieving
concuiiency in iOS. You will also leain aLout timeis, thieaus, anu opeiations.
Chaptei 7, Corc Location and Maps
DesciiLes how you shoulu use Map Kit anu Coie Location APIs to uevelop loca-
tion-awaie iOS applications. Fiist you will leain aLout maps, anu then you will
leain how to uetect a uevice`s location anu tailoi youi maps with custom annota-
tions. You will also leain aLout geocouing anu ieveise geocouing, as well as some
ol the methous ol the Coie Location liamewoik, which aie only availaLle in the
iOS + SDK anu latei.
Chaptei S, |np|cncnting Gcsturc Rccognizcrs
Demonstiates how to use gestuie iecognizeis, which enaLle youi useis to easily
anu intuitively manipulate the giaphical inteilace ol youi iOS applications. In this
chaptei, you will leain how to use all availaLle gestuie iecognizeis in the iOS SDK,
with woiking examples testeu on iOS 5 on uilleient uevices such as the iPhone
3GS, iPhone +, anu iPau.
Chaptei 9, Nctwor|ing, jSON, XML, and Twittcr
Demonstiates how to uownloau uata liom a URL anu paise XML liles. You will
leain aLout synchionous anu asynchionous connections anu theii pios anu cons.
You will also leain aLout caching liles in memoiy anu on uisk to avoiu consuming
the possiLly limiteu Lanuwiuth ol an iOS uevice on which youi application coulu
Le iunning.
Chaptei 10, Audio and \idco
Discusses the AV Founuation anu Meuia Playei liamewoiks that aie availaLle on
the iOS SDK. You will leain how to play auuio anu viueo liles anu how to hanule
inteiiuptions, such as a phone call, while the auuio oi viueo is Leing playeu in iOS
6. This chaptei also explains how to iecoiu auuio using an iOS uevice`s Luilt-in
miciophone(s). At the enu ol the chaptei, you will leain how to access the iPou
LiLiaiy anu play its meuia content, all liom insiue youi application.
Chaptei 11, Addrcss Boo|
Explains the Auuiess Book liamewoik anu how to ietiieve contacts, gioups, anu
theii inloimation liom the Auuiess Book uataLase on an iOS uevice. The Auuiess
Book liamewoik is composeu entiiely ol C APIs. Because ol this, many OLjective-
C uevelopeis linu it uillicult to use this liamewoik, as compaieu to liamewoiks
Preface | xiii
www.it-ebooks.info
that pioviue an OLjective-C inteilace. Altei ieauing this chaptei anu tiying the
examples loi youisell, you will leel much moie conliuent using the Auuiess Book
liamewoik.
Chaptei 12, Ii|cs and Io|dcr Managcncnt
One ol the most impoitant tasks that, as uevelopeis, we want to peiloim in oui
iOS apps is manipulating liles anu lolueis. Vhethei this means cieating, ieauing
liom, wiiting to, oi ueleting them, this chaptei contains enough mateiial to get
you up anu iunning with lile anu loluei management in iOS SDK.
Chaptei 13, Cancra and thc Photo Library
Demonstiates how you can ueteimine the availaLility ol liont- anu Lack-lacing
cameias on an iOS uevice. Some ol the iecipes in this chaptei aie specilic to iOS +
anu aLove. You will also leain how to access the Photo LiLiaiy using the Assets
LiLiaiy liamewoik, which is availaLle in iOS + anu latei. At the enu ol the chaptei,
you will leain aLout euiting viueos iight on an iOS uevice using a Luilt-in view
contiollei.
Chaptei 1+, Mu|titas|ing
Explains, with examples, how to cieate multitasking-awaie applications that iun
Leautilully on iOS + anu aLove. You will leain aLout Lackgiounu piocessing, in-
cluuing how to play auuio anu ietiieve useis` locations in the Lackgiounu, as well
as how to uownloau content liom a URL while youi application is iunning in the
Lackgiounu.
Chaptei 15, Corc Data
DesciiLes how to maintain peisistent stoiage loi youi iOS applications using Coie
Data. You will leain how to auu to, uelete liom, anu euit Coie Data oLjects anu
how to Loost access to uata in a taLle view. In auuition, you will leain how to
manage ielationships Letween Coie Data oLjects.
Chaptei 16, Datcs, Ca|cndars, and Evcnts
Demonstiates the use ol the Event Kit anu Event Kit UI liamewoiks, which aie
availaLle on iOS + anu latei, in oiuei to manage calenuais anu events on an iOS
uevice. You will see how to cieate, mouily, save, anu uelete events. You will also
leain, thiough examples, how to auu alaims to calenuai events anu how to set up
CalDAV calenuais so that you can shaie a single calenuai among multiple uevices.
Chaptei 17, Graphics and Aninations
Intiouuces the Coie Giaphics liamewoik. You will leain how to uiaw images anu
text on a giaphics context, giaL the contents ol a giaphics context anu save it as
an image, anu much moie.
Chaptei 1S, Corc Motion
Explains the Coie Motion liamewoik. Using Coie Motion, you will access
the acceleiometei anu the gyioscope on an iOS uevice. You will also leain how to
uetect shakes on a uevice. Ol couise, not all iOS uevices aie eguippeu with an
xiv | Preface
www.it-ebooks.info
acceleiometei anu a gyioscope, so you will also leain how to uetect the availaLility
ol the ieguiieu haiuwaie.
Chaptei 19, iC|oud
Shows how to use the iClouu seivice, which ties uevices togethei anu allows them
to shaie uata to pioviue a seamless usei expeiience as the usei moves liom one
uevice to anothei.
Chaptei 20, Pass Kit
Peihaps one ol the most impoitant upuates in iOS 6 is the intiouuction ol Pass-
Look: a viitual wallet, il you will, capaLle ol managing youi coupons, Loaiuing
passes, iail anu Lus tickets, anu much moie. In this chaptei, you will leain all theie
is to know in oiuei to Le aLle to cieate youi own uigitally signeu passes anu uis-
tiiLute them to youi useis easily.
Additional Resources
Fiom time to time, I ielei to ollicial Apple uocumentation. Some ol Apple`s uesciiptions
aie iight on the maik, anu theie is no point in tiying to iestate them. Thioughout this
Look, I have listeu the most impoitant uocuments anu guiues in the ollicial Apple
uocumentation that eveiy piolessional iOS uevelopei shoulu ieau.
Foi staiteis, I suggest that you have a look at the iOS Human Inteilace Guiuelines loi
all iOS uevices. This uocument will tell you eveiything you neeu to know aLout uevel-
oping engaging anu intuitive usei inteilaces loi all iOS uevices. Eveiy iOS piogiammei
shoulu ieau this uocument. In lact, I Lelieve this shoulu Le ieguiieu ieauing loi the
piouuct uesign anu uevelopment teams ol any company that uevelops iOS applications.
I also suggest that you skim thiough the iOS Application Piogiamming Guiue in the
iOS Releience LiLiaiy loi some tips anu auvice on how to make gieat iOS applications:
One ol the things you will notice when ieauing Chaptei 1+ is the use ol Llock oLjects.
This Look concisely explains Llock oLjects, Lut il you ieguiie luithei uetails on the
suLject, I suggest you ieau A Shoit Piactical Guiue to Blocks, availaLle at this URL:
http://bit.|y/TsSMNU.
Thioughout this Look, you will see ieleiences to Lunules anu loauing images anu
uata liom Lunules. You will ieau a concise oveiview aLout Lunules in this Look, Lut il
you ieguiie luithei inloimation, heau ovei to the Bunule Piogiamming Guiue, avail-
aLle at this URL: http://bit.|y/XdLKE.
Conventions Used in This Book
The lollowing typogiaphical conventions aie useu in this Look:
|ta|ic
Inuicates new teims, URLs, lilenames, lile extensions, anu uiiectoiies
Preface | xv
www.it-ebooks.info
Constant width
Inuicates vaiiaLles anu othei coue elements, the contents ol liles, anu the output
liom commanus
Constant width bold
Highlights text in examples that is new oi paiticulaily signilicant in a iecipe
Constant width italic
Shows text that shoulu Le ieplaceu with usei-supplieu values
This icon signilies a tip, suggestion, oi geneial note.
Using Code Examples
This Look is heie to help you get youi joL uone. In geneial, you may use the coue in
this Look in youi piogiams anu uocumentation. You uo not neeu to contact us loi
peimission unless you`ie iepiouucing a signilicant poition ol the coue. Foi example,
wiiting a piogiam that uses seveial chunks ol coue liom this Look uoes not ieguiie
peimission. Selling oi uistiiLuting a CD-ROM ol examples liom O`Reilly Looks docs
ieguiie peimission. Answeiing a guestion Ly citing this Look anu guoting example
coue uoes not ieguiie peimission. Incoipoiating a signilicant amount ol example coue
liom this Look into youi piouuct`s uocumentation docs ieguiie peimission.
Ve appieciate, Lut uo not ieguiie, attiiLution. An attiiLution usually incluues the
title, authoi, puLlishei, anu ISBN. Foi example: iOS Progranning Coo|boo| Ly
Vanuau Nahavanuipooi (O`Reilly). Copyiight 2013 Vanuau Nahavanuipooi,
97S-1-++93-+275-3.
Il you leel youi use ol coue examples lalls outsiue laii use oi the peimission given heie,
leel liee to contact us at pcrnissionsorci||y.con.
Wed Like to Hear from You
Eveiy example anu coue snippet in this Look has Leen testeu on the iPhone 3GS, iPhone
+, iPhone +S, iPhone 5, iPau, anu an iPhone/iPau Simulatoi, Lut occasionally you may
encountei pioLlemsloi example, il you have a uilleient veision ol the SDK than the
veision on which the example coue was compileu anu testeu. The inloimation in this
Look has also Leen veiilieu at each step ol the piouuction piocess. Howevei, mistakes
anu oveisights can occui, anu we will giatelully ieceive uetails ol any you linu, as well
as any suggestions you woulu like to make loi lutuie euitions. You can contact the
authoi anu euitois at:
O`Reilly Meuia, Inc.
xvi | Preface
www.it-ebooks.info
1005 Giavenstein Highway Noith
SeLastopol, CA 95+72
(S00) 99S-993S (in the Uniteu States oi Canaua)
(707) S29-0515 (inteinational oi local)
(707) S29-010+ (lax)
Ve have a weL page loi this Look, wheie we list eiiata, examples, anu any auuitional
inloimation. You can access this page at:
http://orci|.|y/iOS_Progranning_CB
To access the souice coues loi this Look, please see the authoi`s weLsite at:
https://github.con/vandadnp/ios--progranning-coo|boo|-sourcc-codcs
To comment oi ask technical guestions aLout this Look, senu email to the lollowing
auuiess, mentioning the Look`s ISBN (97S1++93+2753):
boo|qucstionsorci||y.con
Foi moie inloimation aLout oui Looks, conleiences, Resouice Centeis, anu the O`Reil-
ly Netwoik, see oui weLsite at:
http://www.orci||y.con
Safari Books Online
Salaii Books Online (www.sajariboo|son|inc.con) is an on-uemanu uigital
liLiaiy that ueliveis expeit content in Loth Look anu viueo loim liom the
woilu`s leauing authois in technology anu Lusiness.
Technology piolessionals, soltwaie uevelopeis, weL uesigneis, anu Lusiness anu cie-
ative piolessionals use Salaii Books Online as theii piimaiy iesouice loi ieseaich,
pioLlem solving, leaining, anu ceitilication tiaining.
Salaii Books Online olleis a iange ol piouuct mixes anu piicing piogiams loi oigani-
zations, goveinment agencies, anu inuiviuuals. SuLsciiLeis have access to thousanus
ol Looks, tiaining viueos, anu piepuLlication manusciipts in one lully seaichaLle ua-
taLase liom puLlisheis like O`Reilly Meuia, Pientice Hall Piolessional, Auuison-Vesley
Piolessional, Miciosolt Piess, Sams, Que, Peachpit Piess, Focal Piess, Cisco Piess, ]ohn
Viley e Sons, Syngiess, Moigan Kaulmann, IBM ReuLooks, Packt, AuoLe Piess, FT
Piess, Apiess, Manning, New Riueis, McGiaw-Hill, ]ones e Baitlett, Couise Tech-
nology, anu uozens moie. Foi moie inloimation aLout Salaii Books Online, please visit
us online.
Acknowledgments
I woulu like to acknowleuge Anuy Oiam, my much-iespecteu euitoi, anu eveiyone at
O`Reilly Meuia loi theii continuous suppoit anu inspiiation, especially Rachel Rou-
Preface | xvii
www.it-ebooks.info
meliotis, Biian ]epson, Rachel B. Steely, anu Maiia Stallone. Thanks also go to Saiah
Schneiuei loi helping me get my iepositoiy soiteu out.
I am also giatelul to my wonueilul ievieweis, Chiis Deveis, Mikhail Maunani, anu
Niklas Saeis, loi the lantastic joL they uiu ieviewing this euition ol the Look. Vhen I
was a kiu, I thought I coulu uo eveiything on my own. But as I`ve matuieu, it has Lecome
moie anu moie appaient to me that although we humans aie limitless in what we can
achieve, without a goou suppoit system theie is just so much we cannot uo. Realizing
anu constantly ieminuing mysell ol this when I am suiiounueu Ly my liienus, I woulu
like to take this oppoitunity anu thank them loi theii continuous suppoit anu uncon-
uitional love.
Last, Lut not least, Lig thanks to Alina Rizzoni, Biuno, anu Tommy Packham loi theii
continuous suppoit anu love. RamLo anu Piolessoi T], I want to say hello to you, too.
Goou Loys!
xviii | Preface
www.it-ebooks.info
CHAPTER 1
The Basics
1.0 Introduction
A lot has changeu in iPhone, iPau, anu iPou touch piogiamming since the intiouuction
ol iOS 5. The whole iuntime anu the way we wiite OLjective-C coue have uiamatically
changeu. ARC (Automatic Releience Counting) is now intiouuceu into the LLVM
Compilei, which in some ways gives us moie llexiLility anu in othei ways makes the
iuntime moie liagile. In this chaptei, we will get uown anu uiity with oLjects anu how
we can use them using the mouein OLjective-C iuntime unuei ARC.
As the name ol the language hints at, OLjective-C is all aLout manipulating objccts.
These aie containeis loi all the things you manipulate in the piogiam, ianging liom
something simple, like a point at the coinei ol a iectangle, to entiie winuows containing
all kinus ol wiugets. Apple`s Cocoa liLiaiies even ueline simple values such as integeis
as oLjects. OLjects aie uelineu accoiuing to c|asscs, anu theieloie these two teims aie
commonly useu inteichangeaLly. But actually, a class is just a specilication loi uelining
oLjects; each oLject is saiu to Le an instancc ol its class. Each classanu theieloie the
oLjects that aie cieateu liom that classis a set ol piopeities, tasks, methous, enu-
meiations, anu much moie. In an oLject-oiienteu piogiamming language, classes can
inheiit liom each othei much like a peison can inheiit ceitain tiaits anu chaiacteiistics
liom his paients.
OLjective-C uoes not allow multiple inheiitance. Theieloie, eveiy class
is the uiiect uescenuant ol, at most, one othei class.
The ioot class ol most OLjective-C oLjects is the NSObject class. This class manages the
iuntime capaLilities olleieu Ly iOS; as a iesult, any class that uiiectly oi inuiiectly
inheiits liom NSObject will inheiit these capaLilities as well. As we will see latei in this
chaptei, oLjects that inheiit liom NSObject can take auvantage ol OLjective-C`s uis-
tinctive memoiy management mouel.
1
www.it-ebooks.info
1.1 Creating a Simple iOS App in Xcode
Problem
You`ve staiteu to leain iOS Piogiamming anu you want to cieate a ieally simple iOS
Pioject anu app in Xcoue.
Solution
Cieate a new iOS Pioject in Xcoue anu then iun it in the iOS Simulatoi using Commanu
-Shilt-R.
Discussion
I`ll assume you have a Mac anu you have alieauy installeu the Xcoue set ol tools. Now
you want to cieate an iOS Pioject anu iun that app on the iOS Simulatoi. This piocess
is ieally stiaightloiwaiu:
1. Open Xcoue il you uon`t have it open yet.
2. Select File on the menu Lai, select New, anu then select New Pioject. You will Le
gieeteu with a scieen similai to that shown in Figuie 1-1.
Iigurc 1-1. Thc Ncw Projcct dia|og in Xcodc
2 | Chapter 1: The Basics
www.it-ebooks.info
3. In the New Pioject uialog (Figuie 1-1), on the lelt, make suie the Application cat-
egoiy is selecteu unuei the iOS main categoiy. Then select Page-Baseu Application
on the iight-hanu siue anu piess the Next Lutton.
+. You will now neeu to entei youi piouuct name (App Name) anu youi company
iuentiliei. This uniguely iuentilies youi piouuct loi youi own company. Set youi
piouuct name to Crcating a Sinp|c iOS App in Xcodc. The company iuentiliei is
noimally a uomain name with the components ieveiseu. My company name is
Pixolity, anu theieloie I will set the Company Name to com.pixolity as shown in
Figuie 1-2. Leave the iest ol the values in this scieen just the way I`ve lelt them in
Figuie 1-2 anu piess the Next Lutton.
5. You will now Le askeu to save youi pioject on a uisk. Select youi uesiieu location
anu piess the Cieate Lutton, as shown in Figuie 1-3. Xcoue will now cieate youi
pioject liles anu the stiuctuie ol youi pioject.
6. Now, Leloie iunning youi app, make suie you have unpluggeu any iPhones oi
iPaus/iPous that you have connecteu to youi computei. The ieason Lehinu this is
that il a uevice is connecteu to youi Mac, Xcoue will tiy to iun youi apps on the
uevice insteau ol the simulatoi, anu il you haven`t conliguieu youi uevice loi ue-
velopment, you might get Llockeu anu not Le aLle to iun youi apps.
Iigurc 1-2. Sctting thc ncw projcct`s scttings
1.1 Creating a Simple iOS App in Xcode | 3
www.it-ebooks.info
7. Fiom the uiop-uown on the top-lelt coinei ol Xcoue, make suie iPhone Simulatoi
oi iPau Simulatoi is selecteu. In this example, I will make suie iPau Simulatoi is
selecteu, as shown in Figuie 1-+.
S. Now that eveiything is ieauy, piess the Commanu-Shilt-R keys on youi keyLoaiu
oi simply go to the Piouuct menu anu then piess the Run Lutton as shown in
Figuie 1-5.
Congiatulations. Now you have a simple app iunning in iOS Simulatoi. As you saw,
theie aie vaiious uilleient iOS pioject templates that you can choose liom (Fig-
uie 1-1). Heie is a list ol some ol the hanuy pioject templates that you can use:
Iigurc 1-3. Saving a ncw iOS projcct on dis| using Xcodc
Iigurc 1-1. Running your iOS App on iPad Sinu|ator
4 | Chapter 1: The Basics
www.it-ebooks.info
Mastcr-Dctai| App|ication
This pioject template will set up a split view contiollei loi youi us. Split view
contiolleis aie explaineu in Chaptei 2, |np|cncnting Contro||crs and \icws.
Pagc-Bascd App|ication
This template will allow youi app to have an iBooks usei inteilace, wheie the usei
will Le aLle to llip thiough the pages that aie uiawn Ly the app. You`ll leain moie
aLout this in Chaptei 2.
Enpty App|ication
An empty application is simply maue out ol the most Lasic components that any
iOS app has. I use this template a lot to set up my iOS apps the way I like them to
Le set up, without any pieconliguiation Ly Xcoue.
1.2 Understanding Interface Builder
Problem
You want to stait uesigning a usei inteilace loi youi iOS apps Lut uon`t want to waste
time couing.
Solution
Use Inteilace Builuei.
Iigurc 1-5. Thc Run ncnu itcn in Xcodc
1.2 Understanding Interface Builder | 5
www.it-ebooks.info
Discussion
Inteilace Builuei, oi IB, is integiateu into Xcoue as a tool loi cieating a usei inteilace
loi youi Mac anu iOS apps. IB manipulates .xib liles, which aie sometimes calleu nib
liles to iellect the lile extension they hau in past Apple piouucts. A niL lile is Lasically
the compileu (Linaiy) veision ol an XIB lile which itsell is an XML lile that is manageu
Ly IB. XIB liles aie in XML loimat to make them easiei to use with veision contiol
systems anu text-Laseu tools.
Let`s go aheau anu stait using IB. To uo this, liist cieate an iOS App using the Single
View Application iOS Pioject template in Xcoue. Follow the instiuctions in
Recipe 1.1, Lut insteau ol Page-Baseu Application template (Figuie 1-1), use the Single
View Application template anu lollow it to the last uialog to save youi pioject to uisk.
I`ve nameu the pioject Unueistanuing Inteilace Builuei.
Make suie youi app is a Univeisal app, as shown in Figuie 1-2.
Altei youi pioject is cieateu, the liist thing you neeu to uo is make suie it is going to
iun on iPhone Simulatoi, as shown in Figuie 1-6.
Now piess Commanu-Shilt-R to iun youi application. You will then see the iOS Sim-
ulatoi showing youi empty application, as shown in Figuie 1-7.
Now linu the lile Undcrstanding_|ntcrjacc_Bui|dcr\icwContro||cr_iPhonc.xib in youi
pioject anu click on it. Inteilace Builuei will open up within Xcoue anu will uisplay
youi usei inteilace to you. Now that you have IB open, select liom Xcoue menus the
View option, anu then Utilities, anu linally select Show OLject LiLiaiy (Figuie 1-S).
Now il you have a look at the OLject LiLiaiy, you can see that you have plenty ol choice
as to what you want to put on youi inteilace. This incluues Luttons, on/oll switches,
piogiess Lais, taLle views, etc. Foi now, uiag anu uiop a Lutton on youi usei inteilace.
It`s as simple as that (Figuie 1-9).
Iigurc 1-. Choosing to run your app on iPhonc Sinu|ator
6 | Chapter 1: The Basics
www.it-ebooks.info
Right altei this, liom the Xcoue menus, select File anu then Save to make suie youi
Undcrstanding_|ntcrjacc_Bui|dcr\icwContro||cr_iPhonc.xib is saveu. Then go aheau
anu iun youi app on iOS Simulatoi (Figuie 1-10).
You might Le suipiiseu, Lut loi now that is a|| that we neeu to know aLout Inteilace
Builuei.
See Also
Recipe 1.1
1.3 Compiling iOS Apps
Problem
You have leaineu how to cieate an iOS app anu wonuei how it Lehaves.
Solution
Compile anu iun youi iOS apps using Apple`s latest compilei. Then test youi app on
iOS Simulatoi anu also, pieleiaLly, on a uevice.
Discussion
Cieating an iOS App can Le categoiizeu unuei the lollowing tasks:
1. Planning
Iigurc 1-7. An cnpty Sing|c \icw App|ication running on iOS Sinu|ator
1.3 Compiling iOS Apps | 7
www.it-ebooks.info
2. Piototyping
3. Designing
+. Implementing anu Testing
5. Deliveiing
Duiing the implementation ol an app, you will constantly neeu to iun youi app on a
simulatoi oi on vaiious uevices to make suie it is consistent, auheies to the uesign
guiuelines that you oi youi teammates cieateu loi this pioject, anu most impoitantly,
is staLle enough loi the App Stoie.
Ciashes pioviue one ol the majoi ieasons loi app iejections in the Apple
App Stoie. Apps that aie not staLle anu ciash olten aie not goou enough
loi consumeis, anu Apple is veiy likely to ieject them. So always make
suie that you thoioughly test youi apps on iOS Simulatoi anu on uevi-
ces.
Iigurc 1-8. U| Objccts in thc Objcct Library in |ntcrjacc Bui|dcr
8 | Chapter 1: The Basics
www.it-ebooks.info
Vhen we wiite oui coue, as we will leain veiy soon, we neeu to make suie that what
we aie wiiting is coiiect. The piocess Ly which Xcoue changes oui coue into executaLle
instiuctions is calleu conpi|ation. The compilei uoes the compilation. In Xcoue, we use
vaiious Luilu commanus to compile oui apps:
Bui|d jor Running
Use this when you want to ueLug youi applications on the simulatoi oi on a uevice.
DeLugging is the piocess Ly which you can linu mistakes in youi coue.
Iigurc 1-9. A button on a nib
Iigurc 1-10. A button on thc U| oj your app
1.3 Compiling iOS Apps | 9
www.it-ebooks.info
Bui|d jor Tcsting
Use this Luilu setting to iun unit-tests that you`ve wiitten loi youi apps. Unit tests,
in shoit, aie a set ol instiuctions that you pioviue to Xcoue. Xcoue will iun these
instiuctions Leloie it makes the linal Luilu. These instiuctions have one puipose
only: to make suie that each pait ol the app you`ve wiitten is in lull woiking oiuei.
Bui|d jor Proji|ing
Il you want to test the peiloimance ol youi app, use this setting. Pioliling is the
piocess Ly which you can linu Lottlenecks, memoiy leaks, anu othei guality-ielateu
issues not coveieu Ly unit testing.
Bui|d jor Archiving
Vhen you aie suie youi app is piouuction guality oi simply want to uistiiLute it
to testeis, use this setting.
To compile youi apps in Xcoue, simply select the Piouuct menu item, choose Builu
Foi, anu then choose whichevei Luilu setting you Lelieve is ielevant to the task you
want to accomplish.
Vhat uo you think happens il you have an eiioi in youi coue? In Recipe 1.1 we cieateu
a simple Page-Baseu Application, so let`s go Lack to that app. Now open the Root-
\icwContro||cr.n lile in youi pioject anu look loi this coue:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
Change this coue to the lollowing:
- (void)viewWillAppear:(BOOL)animated
{
[super nonExistentMethod];
[super viewWillAppear:animated];
}
Il you now tiy to use Piouuct menu, Builu Foi, anu then Builu Foi Running, you will
get the lollowing eiioi liom Xcoue:
error: Automatic Reference Counting Issue: Receiver type 'UIViewController'
for instance message does not declare a method
with selector 'nonExistentMethod'
This is what the compilei is telling you: the coue that you`ve wiitten cannot Le compileu
anu tianslateu to piopei instiuctions to the CPU. In this paiticulai case, this is Lecause
the compilei uoesn`t unueistanu what nonExistentMethod actually is. This illustiates a
goou compilei that wains olanu sometimes stops you liom makingmistakes that
make youi apps unstaLle.
See Also
Recipe 1.1
10 | Chapter 1: The Basics
www.it-ebooks.info
1.4 Running iOS Apps on the Simulator
Problem
You`ve piepaieu an iOS pioject in Xcoue anu woulu like to iun it in iOS Simulatoi to
make suie it woiks.
Solution
You neeu to use the Scheme LieauciumL Lutton on the top-lelt coinei ol Xcoue to liist
select the pioject that you wish to iun on the iOS Simulatoi anu then select the simulatoi
that you wish to iun youi app on (iPhone/iPau).
Discussion
Follow these steps:
1. Finu the Scheme LieauciumL Lutton on the top-lelt coinei ol Xcoue`s winuow.
This Lutton looks like that shown in Figuie 1-11.
Iigurc 1-11. Thc Schcnc brcadcrunb button in Xcodc
2. In Xcoue, you can have multiple piojects on the same woikspace. Foi example, at
the time ol wiiting this iecipe, I have one pioject pei iecipe, auueu to one Lig pioject
that I`ve cieateu loi this Look. The lelt siue ol the Scheme Lutton shows you the
pioject that`s cuiiently selecteu. So il I click on the lelt siue ol the Scheme Lutton,
I`ll see something similai to Figuie 1-12. So go aheau anu click on the lelt siue ol
the Scheme Lutton anu select the pioject that you wish to iun on the iOS Simulatoi.
3. The iight siue ol the Scheme Lutton lets you choose which uevice/simulatoi you
wish to iun youi app on. I`ve selecteu iPhone Simulatoi. Go aheau anu piess the
iight siue ol the Scheme Lutton to select which simulatoi you woulu like to iun
youi app on (Figuie 1-13).
Beai in minu that the options piesenteu to you on the iight siue ol the
Scheme Lutton uepenu entiiely on how youi pioject is set up. In the
seconu stage ol cieating an iOS Pioject, Xcoue asks you which uevice(s)
you woulu like youi app to iun on (in the Device Family uiop-uown).
You can see this Lox in Figuie 1-2. A Univeisal app is an app that iuns
on Loth iPau anu iPhone. Theie aie also options to select to make youi
app iun only on iPhone oi only on the iPau.
1.4 Running iOS Apps on the Simulator | 11
www.it-ebooks.info
Now that you have selecteu which simulatoi you woulu like to iun youi app on, simply
go to the Piouuct menu in Xcoue anu select Run. Xcoue will compile youi app
(Recipe 1.3) il it`s not compileu yet anu will then iun it on youi selecteu simulatoi.
See Also
Recipe 1.3
1.5 Running iOS Apps on iOS Devices
Problem
You`ve cieateu an iOS App anu now you want to iun it on a uevice.
Solution
Simply plug youi uevice into youi computei using the USB caLle that comes with youi
uevice. Follow the steps in Recipe 1.+ to make suie you have selecteu the iight pioject
in Xcoue. Insteau ol choosing the simulatoi (as shown in Recipe 1.+) in the Scheme
LieauciumL Lutton, choose youi uevice, go to Piouuct, anu piess Run.
Iigurc 1-12. Thc projcct currcnt|y sc|cctcd
Iigurc 1-13. Sc|ccting thc iPhonc Sinu|ator
12 | Chapter 1: The Basics
www.it-ebooks.info
Discussion
Each veision ol Xcoue suppoits a seiies ol iOS veisions. By support I mean that the
latest veision ol Xcoue, loi instance, may not Le capaLle ol compiling anu iunning an
iOS app on a seconu-geneiation iPou touch with iOS 3.0 installeu on it. The ieason is
that the utilities Luilt loi each veision ol Xcoue allow you to iun youi iOS apps on a
limiteu numLei ol veisions ol iOS on uevices. The same is tiue loi iOS Simulatoi. Il
you uownloau the latest veision ol Xcoue, you will notice that you might only Le aLle
to simulate youi apps on iOS Simulatoi 5.0 anu nothing Leloie that.
The way to uetect whethei Xcoue has uetecteu youi uevice is to plug in youi uevice,
wait a lew seconus loi the sync to happen, anu see whethei the name ol youi uevice
appeais in the iight hall ol the Scheme LieauciumL Lutton.
Il you`ve waiteu loi the uevice to sync anu still the Scheme Lutton is showing iOS
Dcvicc in its list insteau ol the name ol youi uevice, you neeu to make suie that youi
uevice can Le useu loi uevelopment puiposes. Simply lollow these instiuctions:
1. Select the Vinuow menu.
2. Unuei the Vinuow menu, select Oiganizei.
3. On top ol Oiganizei, make suie the Devices item is selecteu, as shown in Fig-
uie 1-1+.
Iigurc 1-11. Sc|ccting thc Dcviccs button in Organizcr
+. On the lelt siue ol Oiganizei`s Devices scieen, make suie you`ve selecteu youi
uevice Ly clicking on it (Figuie 1-15).
5. As you can see, the uevice has a giay light insteau ol gieen. The giay light tells us
that this uevice is not ieauy loi uevelopment. Altei clicking on the uevice in the
list, you will then see a Lutton on the iight siue ol the scieen laLeleu Use loi De-
velopment. Piess that Lutton. Once you piess this Lutton, you will see a piogiess
Lai appeai on the scieen anu Xcoue will stait uetecting this uevice.
6. At this stage, Xcoue might show a Login scieen. This scieen asks loi youi iOS
Developei Poital`s cieuentials. This means that Xcoue wants to uetect whethei the
UDID (Unigue Device ID) ol youi uevice has alieauy Leen auueu to youi poital oi
not. Il it has not Leen auueu, Xcoue will auu it loi you. So just go aheau anu pioviue
youi iOS Poital cieuentials to Xcoue (see Figuie 1-16) anu then piess the Login
Lutton.
1.5 Running iOS Apps on iOS Devices | 13
www.it-ebooks.info
7. Il eveiything goes line anu Xcoue uetects that the iOS veision on youi uevice is
something that it can suppoit, it will uisplay the gieen light next to youi uevice on
the lelt-hanu siue ol Oiganizei`s Devices scieen, as shown in Figuie 1-17.
S. Now close Oiganizei anu come Lack to Xcoue. Il you now click on the iight siue
ol the Scheme LieauciumL Lutton, you will Le aLle to see youi uevice listeu theie,
as shown in Figuie 1-1S.
Il Xcoue cannot uetect the veision ol iOS installeu on youi uevice, it will uisplay an
amLei light next to it. In this case, you eithei neeu to get a veision ol Xcoue that uoes
suppoit youi uevice`s iOS veision, oi you neeu to change the veision ol iOS on youi
uevice to match what Xcoue suppoits. Xcoue will uisplay the list ol iOS veisions that
it suppoits altei uisplaying the amLei light next to youi uevice. Xcoue, in lact, will give
you the ieason why it cannot iun iOS apps on youi uevice. Il the ieason stems liom
the veision ol iOS on youi uevice, the suppoiteu veisions ol iOS will ceitainly Le uis-
playeu in Oiganizei`s Devices section.
Iigurc 1-15. A dcvicc that is not rcady jor dcvc|opncnt
Iigurc 1-1. Xcodc waiting jor iOS Porta| crcdcntia|s
14 | Chapter 1: The Basics
www.it-ebooks.info
See Also
Recipe 1.+
1.6 Packaging iOS Apps for Distribution
Problem
You want to senu youi iOS app to otheis so that they can test youi app oi have a look
at it bcjorc you suLmit youi app to the App Stoie.
Solution
You neeu to aichive youi application.
Discussion
In oiuei to aichive an application, you neeu to lollow ceitain steps:
1. Make suie that you have lully testeu the app on the simulatoi anu you aie happy
that youi app is staLle.
Iigurc 1-17. An iOS dcvicc rcady jor dcvc|opncnt
Iigurc 1-18. An iOS dcvicc showing up in thc Schcnc brcadcrunb button in Xcodc
1.6 Packaging iOS Apps for Distribution | 15
www.it-ebooks.info
2. Gathei the UDIDs (Unigue Device Iuentilieis) ol all those uevices on which you
want to iun youi app. You can ask youi liienus anu colleagues loi these il the
uevices Lelong to them.
3. Auu these UDIDs to youi iOS Poital.
+. Cieate an Au Hoc DistiiLution piovision piolile. Piovision pioliles aie a mix ol
Linaiy anu XML content that allow an application to Le executeu on uevices that
have Leen linkeu to that piovision piolile.
5. Altei you have youi piovision pioliles (a lile that enus with the .nobi|cprovision
extension), tell Xcoue to use that piovision piolile loi ielease puiposes, as we will
soon see.
6. Vithin Xcoue, select the Piouuct menu anu then choose Aichive. Xcoue will now
aichive youi application anu, when that is uone, uisplay Oiganizei to you. Heie
you can expoit youi aichiveu application as a lile (with the .ipa extension) that
youi testeis/colleagues/liienus can uiag anu uiop into theii iTunes oi iPhone Con-
liguiation Utility to install youi app on theii iOS uevices.
To uistiiLute youi iOS app to testeis/colleagues anu liienus, you have to cieate an Au
Hoc piovision piolile. Follow these steps to cieate youi Au Hoc piovision piolile:
1. Log into the iOS Dev Centei.
2. Select iOS Piovision Poital liom the iight siue ol the scieen.
3. Il you have not cieateu a DistiiLution ceitilicate yet, lollow these steps:
On the lelthanu siue ol iOS Piovision Piolile, select Ceitilicates.
On the iighthanu siue, select the DistiiLution taL on the top ol the scieen.
Follow the instiuctions on the scieen, which will ask you to use Keychain
Access to cieate a new ceitilicate on youi computei anu then uploau that cei-
tilicate to the poital. Altei this, you will have youi DistiiLution ceitilicate.
Click on the Downloau Lutton to the iight siue ol youi DistiiLution ceitilicate
to uownloau it. Altei you`ve uownloaueu it on youi computei, uouLle-click
on it to install it in youi Keychain Access.
+. Now move to the Devices item on the lelt siue ol the scieen.
5. Select the Auu Devices Lutton on the iight siue ol the scieen.
6. Entei the uevice name anu the uevice UDID in the Loxes pioviueu. Il enteiing moie
than one uevice, piess the - Lutton altei eveiy uevice to make ioom loi a new
uevice. You can auu a maximum ol 100 uevices to each piovision poital (except
loi Enteipiise poitals, which we won`t covei in this Look, as they aie given only
to Lig oiganizations).
16 | Chapter 1: The Basics
www.it-ebooks.info
Altei a uevice is auueu to youi iOS poital, it cannot Le iemoveu loi the
peiiou that you holu this poital (which is usually a yeai). Altei youi
poital has expiieu anu when it has Leen ieneweu, you will get a chance
to uelete any unwanteu uevices, so make suie you aie not auuing uevices
to youi poital without consiueiing this.
7. Once you aie uone auuing the uevices, piess the SuLmit Lutton.
S. Select Piovisioning on the lelt siue ol the scieen.
9. Select the DistiiLution taL on the iighthanu siue ol the scieen.
10. Select the New Piolile Lutton on the iight siue ol the scieen.
11. In the Cieate iOS DistiiLution Piovisioning Piolile scieen, make suie the Distii-
Lution Methou is Au Hoc (Figuie 1-19).
Iigurc 1-19. Crcating a ncw Ad Hoc provision proji|c
12. Unuei Piolile Name, give a uesciiptive name to youi piovision piolile. Foi instance,
something like Vilucaiu Au Hoc Piolile. Be cieative anu uesciiptive.
13. In the App ID uiop-uown, pick Xcoue: Vilucaiu AppID. This will allow you to
piovision youi apps iegaiuless ol theii App Iuentilieis so that you can use the same
Au Hoc piovision piolile loi all youi iOS apps.
1+. In the Devices section, select all the uevices on which you want this piovision
piolile to woik. Devices that aie not selecteu in this list will not Le aLle to iun youi
apps.
15. Altei you aie uone selecting the uevices, piess the SuLmit Lutton.
16. Now heau Lack to the DistiiLution taL ol the Piovisioning section anu piess the
Downloau Lutton loi the piovision piolile that you just cieateu. Il the status ol
1.6 Packaging iOS Apps for Distribution | 17
www.it-ebooks.info
this piolile is Penuing, ieliesh youi page in youi Liowsei until the piovision piolile
is cieateu.
17. Now that you have this piovision piolile uownloaueu on youi computei, uiag anu
uiop it into iTunes. iTunes will then install this piolile loi you.
All uone. Ve aie now ieauy to cieate an aichiveu app. Follow these steps:
1. Select youi piolile lile in Xcoue (this is the lile with the Llue icon).
2. Now you will see the taigets youi app suppoits. Select the uesiieu taiget.
3. Select Builu Settings on the iight siue ol the scieen (Figuie 1-20).
+. In the Builu Settings taL, scioll uown until you get to the Coue Signing categoiy,
as shown in Figuie 1-20.
5. Unuei Coue Signing Iuentity Release anu Coue Signing Iuentity Release Any
iOS SDK, make suie you pick the piovision piolile that you cieateu eailiei in this
iecipe.
6. On the Scheme LieauciumL (Figuie 1-11), make suie you`ve chosen iOS Device/
Youi Device Name insteau ol iOS Simulatoi (iPau oi iPhone). Unuei the simulatoi,
you cannot cieate an app loi uistiiLution.
7. Heau ovei to the Piouuct menu anu choose Aichive.
Iigurc 1-20. Xcodc Disp|aying thc Bui|d Scttings oj an iOS App
Altei the aichiving piocess is linisheu, Xcoue will open Oiganizei loi you anu will
uisplay the Aichives taL, as uepicteu in Figuie 1-21.
18 | Chapter 1: The Basics
www.it-ebooks.info
Iigurc 1-21. An archivcd app|ication in Organizcr
S. Select the Shaie Lutton on the top-iight siue ol the scieen. You will Le piesenteu
with a uialog similai to that shown in Figuie 1-22.
9. Keep the Contents selection as iOS App Stoie Package (.ipa lile), as shown in
Figuie 1-22.
10. In the Iuentity uiop-uown, again, choose the piovision piolile with which you want
to sign youi app. Ve cieateu this piovision piolile Leloie, iememLei? Choose the
same piolile again. Once you aie uone, piess Next.
11. You will now Le askeu to specily the location wheie you woulu like to save this
lile. Select youi uesiieu location anu lilename, then piess Save.
All uone. Now you have a lile with an .ipa extension. Vhen senuing this lile to youi
liienus/colleagues/etc., make suie you senu the piovision piolile (which you cieateu
in the iOS Dev Poital) as well. They will neeu Loth ol these liles (the .ipa anu
the .nobi|cprovision liles) in oiuei to install youi aichiveu apps on theii uevices.
A usei can use eithei iTunes oi iPhone Conliguiation Utility (Loth aie liee) in oiuei to
install youi apps on theii uevices. I peisonally iecommenu iPhone Conliguiation Utility
1.6 Packaging iOS Apps for Distribution | 19
www.it-ebooks.info
(oi iCU) since it is ceitainly moie ioLust when it comes to installing Au Hoc apps on
uevices. iTunes has some issues when installing aichiveu apps on uevices, which I am
not going to Loie you with. The moie you woik with these two pieces ol soltwaie, the
moie you get to know aLout theii auvantages anu uisauvantages.
1.7 Declaring Variables in Objective-C
Problem
You want to use vaiiaLles with cleai names in youi iOS apps.
Solution
Apple conventions uictate ceitain iules loi vaiiaLle names. Deteimine the type ol the
vaiiaLle (loi instance, integei, aiiay, stiing, etc.) anu then a uesciiptive name loi it. In
an empty line ol coue, place the type ol youi vaiiaLle liist, lollowing Ly its name.
VaiiaLle names aie auviseu to lollow these iules:
1. Follow the camelCase naming convention. Il the vaiiaLle name is one woiu, all
letteis must Le loweicase. Il the vaiiaLle name is moie than one woiu, the liist
woiu must Le entiiely loweicase anu the suLseguent woius must have theii liist
lettei uppeicase anu the iest ol theii letteis loweicase. Foi instance, il you want to
Iigurc 1-22. Sc|ccting thc typc oj archivc wc want to crcatc
20 | Chapter 1: The Basics
www.it-ebooks.info
have a countei vaiiaLle, you can simply name it counter. Il you want to call youi
vaiiaLle liist countei, ueclaie it firstCounter. The vaiiaLle name my veiy long
vaiiaLle name woulu Lecome myVeryLongVariableName. (Names ol that length aie
guite common in iOS piogiams.)
2. VaiiaLles shoulu iueally have no unueiline in theii names. Foi instance, my_
variable_name can anu peihaps shoulu Le changeu to myVariableName.
3. VaiiaLle names shoulu contain only letteis anu numLeis (no punctuation such as
commas oi uashes). This is a iestiiction in the OLjective-C language anu many
othei languages, Lut this helps keeping vaiiaLle names tiuy.
Let`s have a look at a lew examples. Theie aie a lew piimitive uata types in OLjective-
C. A uata type is a name that specilies the type ol a vaiiaLle. Foi instance, you can say
that you have an integei vaiiaLle ol type NSInteger oi an integei vaiiaLle ol type NSUIn
teger, wheie the loimei is a signeu vaiiaLle anu the lattei is unsigneu (note the U
altei NS) in the lattei example).
Signeu integeis can contain negative numLeis, wheieas unsigneu inte-
geis cannot.
Ve can then ueline these vaiiaLles in oui souice coue like so:
NSInteger signedInteger = -123; /* Can take negative numbers */
NSUInteger unsignedInteger = 123; /* Cannot take negative numbers */
Theie aie ceitain iules, as mentioneu Leloie, aLout naming youi vaiiaLles (loi instance,
the camelCase iule). Howevei, othei aspects ol youi vaiiaLle naming convention ue-
penu entiiely on youi choice. In geneial, I auvise that you always assume you aie
woiking loi a Lig oiganization (whethei it is youi own company oi someLouy else`s
company) anu lollow these iules:
1. Give uesciiptive names to youi vaiiaLles. Avoiu names such as i oi x. These
names will nevei make any sense to anyLouy else Lut youisell anu chances aie that
they won`t make sense to you eithei il you leave the pioject loi some time anu come
Lack to it altei a lew months. The compilei uoesn`t ieally caie il the vaiiaLle name
is 50 letteis long. Il that makes youi vaiiaLle name moie uesciiptive anu you cannot
uo without it, then go loi it.
2. Avoiu cieating vague vaiiaLle names. Foi instance, il you have a stiing vaiiaLle anu
you want to place the lull name ol a peison in that vaiiaLle, avoiu giving it names
such as theStiing oi theGuy oi theGiil. These make no sense at all. It is Lest
to give a name such as lullName oi liistAnuLastName iathei than something
that conluses eveiyLouy who looks at youi souice coue, incluuing youisell!
1.7 Declaring Variables in Objective-C | 21
www.it-ebooks.info
3. Avoiu giving names to youi vaiiaLles that aie likely to leau to mistyping. Foi in-
stance, it is much Lettei to call youi vaiiaLle lullName iathei than
lullname. It is Lest to avoiu unueilines in vaiiaLles all togethei.
Discussion
VaiiaLles aie placeholueis loi uata that you want to holu in memoiy. Foi instance, il
you want to uelete 100 liles liom the uisk anu those liles aie nameu 1.png, 2.png, on
to 100.png, it woulu Le Lest to cieate a countei vaiiaLle that staits liom 1 anu goes all
the way to 100 anu then use the content ol that vaiiaLle (the numLei) to uelete the liles.
Piogiammeis use vaiiaLles to uo aiithmetic oi simple opeiations, such as pielixing the
last name ol a peison with theii liist name to cieate the iesulting lull name.
Eveiy vaiiaLle has to have a type. The type ol a vaiiaLle tells the compilei anu the
machine that iuns that piogiam, what type ol vaiiaLle that is anu what soit ol value it
holus. Foi example, a vaiiaLle that is an integei can holu the value 123 Lut cannot holu
a value with uecimal places such as 123.+56. Foi the lattei, we will neeu a lloating-
point vaiiaLle. Integei anu lloating-point heie aie the uata types anu, in OLjective-C,
aie uelineu with NSInteger anu float. Heie aie some ol the commonly useu uata types
in OLjective-C:
NSInteger
VaiiaLles ol this type can stoie signeu (positive oi negative) integei values.
NSUInteger
VaiiaLles ol this type can stoie unsigneu (only positive oi zeio) integei values.
float
VaiiaLles ol this type can stoie lloating-point values (values that have uecimals in
them, such as 1.23 oi 73.12).
NSString
VaiiaLles ol this type can stoie stiings, such as my stiing oi Mis Thomson.
NSArray
VaiiaLles ol this type can stoie an aiiay ol oLjects. Foi instance, il you have ieau
10 liles liom the uisk, you can stoie theii uata in an aiiay. An aiiay can contain
moie than one instance ol the same value.
NSSet
VaiiaLles ol this type can stoie unigue instances ol vaiiaLles. Sets aie similai to
aiiays in that they can stoie multiple value Lut each value can only appeai at most
once in a set.
22 | Chapter 1: The Basics
www.it-ebooks.info
1.8 Allocating and Making Use of Strings
Problem
You want to woik with stiings in OLjective-C
Solution
Use NSString anu NSMutableString classes.
Discussion
The NSString anu NSMutableString classes allow you to stoie a stiing ol chaiacteis in
memoiy. The NSString class is immutaLle, meaning that once it is cieateu, its contents
cannot Le mouilieu. MutaLle stiings iepiesenteu with the NSMutableString can Le
mouilieu once they aie cieateu. Ve will see an example ol Loth ol these classes veiy
soon.
OLjective-C stiings shoulu Le placeu insiue uouLle guotes. The staiting uouLle-guote
shoulu Le pielixeu with an at sign (). Foi instance, the sentence Hello, World, iep-
iesenteu as a stiing in OLjective-C, is wiitten like so:
@"Hello, World"
Theie aie vaiious ways ol placing a stiing insiue an instance ol NSString oi NSMutable
String classes. Heie is how:
NSString *simpleString = @"This is a simple string";
NSString *anotherString =
[NSString stringWithString:@"This is another simple string"];
NSString *oneMorestring =
[[NSString alloc] initWithString:@"One more!"];
NSMutableString *mutableOne =
[NSMutableString stringWithString:@"Mutable String"];
NSMutableString *anotherMutableOne =
[[NSMutableString alloc] initWithString:@"A retained one"];
NSMutableString *thirdMutableOne =
[NSMutableString stringWithString:simpleString];
Il you aie woiking with stiings, you aie pioLaLly going to neeu the length ol youi stiing
oLjects liom time to time to make specilic uecisions at iuntime. Imagine this scenaiio:
you have askeu youi usei to entei hei name in a text lielu. Vhen she piesses the Lutton
to conliim hei name, you woulu neeu to check whethei she has in lact enteieu hei
name. You can uo this Ly calling the length methou on an instance ol NSString oi any
ol its suLclasses, incluuing NSMutableString, as shown heie:
1.8 Allocating and Making Use of Strings | 23
www.it-ebooks.info
NSString *userName = ...;
if ([userName length] == 0){
/* The user didn't enter her name */
} else {
/* The user did in fact enter her name */
}
Anothei thing that you might want to know aLout stiings is how you can conveit a
stiing to its eguivalent integial value, i.e., conveiting a stiing to an integei, lloat, oi
uouLle. You can use the integerValue, floatValue, anu doubleValue methous ol
NSString (oi any ol its suLclasses) to ietiieve the integei, lloat anu uouLle values ol a
stiing, like so:
NSString *simpleString = @"123.456";
NSInteger integerOfString = [simpleString integerValue];
NSLog(@"integerOfString = %ld", (long)integerOfString);
CGFloat floatOfString = [simpleString floatValue];
NSLog(@"floatOfString = %f", floatOfString);
double doubleOfString = [simpleString doubleValue];
NSLog(@"doubleOfString = %f", doubleOfString);
The output ol this coue is:
integerOfString = 123
floatOfString = 123.456001
doubleOfString = 123.456000
Il you woulu like to woik with C Stiings, you can! You will use them like NSString
without the leauing at sign, like so:
char *cString = "This is a C String";
Il you want to conveit an NSString to a C Stiing, you must use the UTF8String methou
ol NSString, like so:
const char *cString = [@"Objective-C String" UTF8String];
NSLog(@"cString = %s", cString);
You can use the %s loimat speciliei to piint a C Stiing out to the console.
In contiast, use the %@ loimat speciliei to piint out NSString oLjects.
To conveit a C Stiing to NSString, you must use the stringWithUTF8String: methou ol
the NSString class, as uemonstiateu heie:
NSString *objectString = [NSString stringWithUTF8String:"C String"];
NSLog(@"objectString = %@", objectString);
24 | Chapter 1: The Basics
www.it-ebooks.info
In oiuei to linu a stiing insiue anothei stiing, you can use the rangeOfString: methou
ol NSString. The ietuin value ol this methou is ol type NSRange:
typedef struct _NSRange {
NSUInteger location;
NSUInteger length;
} NSRange;
Il the stiing that you aie looking loi (neeule) is lounu insiue the taiget stiing (haystack),
the location memLei ol the NSRange stiuctuie will Le set to the zeio-Laseu inuex ol
the liist chaiactei ol neeule in haystack. Il neeule cannot Le lounu in haystack, the
location memLei gets set to NSNotFound. Let`s have a look at an example:
NSString *haystack = @"My Simple String";
NSString *needle = @"Simple";
NSRange range = [haystack rangeOfString:needle];
if (range.location == NSNotFound){
/* Could NOT find needle in haystack */
} else {
/* Found the needle in the haystack */
NSLog(@"Found %@ in %@ at location %lu",
needle,
haystack,
(unsigned long)range.location);
}
The seaich uone Ly the rangeOfString: methou ol NSString class is case-
sensitive.
In the Platloim Depenuencies section ol the Stiing Piogiamming Guiue
puLlisheu Ly Apple, it`s Leen explaineu why we neeu to typecast integial
values with specilieis such as unsigned long. I highly iecommenu that
you visit the aloiementioneu guiue online.
Il you want to have moie contiol ovei how youi seaich is uone on a stiing, you can use
the rangeOfString:options: methou, wheie the options paiametei is ol type NSString
CompareOptions.
enum {
NSCaseInsensitiveSearch = 1,
NSLiteralSearch = 2,
NSBackwardsSearch = 4,
NSAnchoredSearch = 8,
NSNumericSearch = 64,
NSDiacriticInsensitiveSearch = 128,
NSWidthInsensitiveSearch = 256,
NSForcedOrderingSearch = 512,
NSRegularExpressionSearch = 1024
1.8 Allocating and Making Use of Strings | 25
www.it-ebooks.info
};
typedef NSUInteger NSStringCompareOptions;
As you can see, the values in this enumeiation aie multiples ol 2. That inuicates that
you can mix them with the logical OR opeiatoi (the ' pipe chaiactei). Let`s say we want
to seaich loi a stiing insiue anothei stiing Lut we aie not conceineu aLout the case-
sensitivity ol the seaich. All we want is to linu a stiing insiue anothei stiing, whethei
the case matches oi not. Heie is how we can uo it:
NSString *haystack = @"My Simple String";
NSString *needle = @"simple";
NSRange range = [haystack rangeOfString:needle
options:NSCaseInsensitiveSearch];
if (range.location == NSNotFound){
/* Could NOT find needle in haystack */
} else {
/* Found the needle in the haystack */
NSLog(@"Found %@ in %@ at location %lu",
needle,
haystack,
(unsigned long)range.location);
}
You can see that we aie using the rangeOfString:options: methou ol NSString with the
NSCaseInsensitiveSearch value, which tells the iuntime that we want the seaich to Le
peiloimeu without any iegaiu to case-sensitivity.
MutaLle stiings aie similai to immutaLle stiings. Howevei, they can Le mouilieu uuiing
iuntime. Let`s see an example:
NSMutableString *mutableString =
[[NSMutableString alloc] initWithString:@"My MacBook"];
/* Add string to the end of this string */
[mutableString appendString:@" Pro"];
/* Remove the "My " string from the string */
[mutableString
replaceOccurrencesOfString:@"My "
withString:[NSString string] /* Empty string */
options:NSCaseInsensitiveSearch /* Case-insensitive */
range:NSMakeRange(0, [mutableString length])]; /* All to the end */
NSLog(@"mutableString = %@", mutableString);
Vhen the mutableString stiing gets piinteu to the console, you will see this:
mutableString = MacBook Pro
You can see that we staiteu with the stiing "My MacBook" anu then iemoveu the "My "
stiing liom that oiiginal stiing. So now we have "MacBook". Altei this, we appenueu the
stiing " Pro" to the enu ol this stiing to get the linal value, which is "MacBook Pro".
26 | Chapter 1: The Basics
www.it-ebooks.info
1.9 Comparing Values in Objective-C with an if Statement
Problem
You want to compaie two values in OLjective-C.
Solution
Use il statements. Please ielei to the Discussion section ol this iecipe loi moie inloi-
mation aLout uilleient scenaiios unuei which you might want to use il statements.
Discussion
Ve use il statements in oui eveiyuay conveisations. Foi instance, you might say Il I
get a holu ol him, I`ll tell him... oi I woulu put the computei to sleep il it uiun`t take
so long to come Lack up. All these statements have a condition. Il statements in
OLjective-C also have a conuition. You can even make them moie sophisticateu, having
youi app uo something il a conuition is met anu something else il the conuition is
not met. The Lasic loim ol an il statement is:
if (condition){
/* Your code to get executed if the condition is met */
}
As long as the conuition is a value othei than zeio/nil/NULL, the coue
insiue the il statement will iun.
An il statement that has an otheiwise clause in it is known as an il-else statement,
anu its loimat is:
if (condition){
/* Your code to get executed if the condition is met */
} else {
/* Code to get executed if condition is not met */
}
The else clause ol the il-else statement can also contain its own il statement! That might
sounu stiange, Lut consiuei this scenaiio. In ieal lile, you can say something similai to
this: I will go get a cup ol collee. Il the place is open, I will get a tall latte; il it`s closeu
anu the othei place is open, I will get a cappuccino; otheiwise, I will just come Lack
home anu make tea loi mysell. The pait wheie we saiu ...il it`s closeu anu the othei
place is open... is an else statement with an il statement emLeuueu in it. Heie is how
you woulu implement that in OLjective-C:
1.9 Comparing Values in Objective-C with an if Statement | 27
www.it-ebooks.info
if (Coffee place A is open){
Get a Tall Latte from coffee place A} else if (Coffee place B is open){
Get a Cappuccino from coffee place B
} else {
Come back home and make tea
}
The conuition loi an il statement, iegaiuless ol whethei it is a stanualone il statement
(like the liist conuition in the last example) oi emLeuueu insiue an else statement, must
iesolve to a Loolean value. A Loolean value is eithei YES oi NO. Foi instance, the lollowing
coue will a|ways get executeu, iegaiuless ol which conuition/uevice you iun it on:
if (YES){
/* This code will get executed whenever the app gets to it */
} else {
/* The app will NEVER get here */
}
The ieason Lehinu this is that the conuition loi the il statement in this example is always
met as long as the YES is the conuition. To make things moie exciting, you can uo
compaiisons in the conuition supplieu to an il statement, like so:
NSInteger integer1 = 123;
NSInteger integer2 = 456;
if (integer1 == integer2){
NSLog(@"Integers are equal.");
} else {
NSLog(@"Integers are not equal.");
}
Note that a uouLle egual sign is useu insiue the conuitional. A common
eiioi is to use a single egual sign, which is a totally uilleient opeiatoi.
The uouLle egual sign uoes a compaiison anu ietuins a Boolean iesult,
which is what you noimally want in a conuitional. A single egual sign
changes the value ol the lelt-hanu vaiiaLle anu ietuins the value set,
which the conuition tiies to inteipiet as a Boolean value. Although oc-
casionally appiopiiate, it`s usually a seiious eiioi to use a single egual
sign.
Il you aie compaiing oLjects, it is Lest to use the isEqual: instance methou ol the
NSObject class:
NSObject *object1 = [[NSObject alloc] init];
NSObject *object2 = object1;
if ([object1 isEqual:object2]){
NSLog(@"Both objects are equal.");
} else {
NSLog(@"Objects are not equal.");
}
28 | Chapter 1: The Basics
www.it-ebooks.info
Foi now, you uon`t have to woiiy aLout what oLjects aie. This will Le
explaineu in uetail in othei iecipes in this chaptei.
Some oLjects such as stiings, howevei, have theii own compaiison methous, changing
the way we compaie two stiings. Foi instance, you can have two stiing oLjects that
contain the same chaiacteis. Il you compaie them using theii isEqual: instance meth-
ou, you will get the iesult NO, Lecause they aie uilleient oLjects. Howevei, they might
still contain the exact same chaiacteis. Because ol this, uilleient classes expose theii
own compaiison methous in OLjective-C. Foi moie inloimation aLout classes, please
ielei to Recipe 1.12. To leain moie aLout oLjects, ielei to Recipe 1.15.
An il statement anu its else statement can Le wiitten with oi without cuily Liaces. Using
the loimei syntax (with cuily Liaces), you can execute multiple lines ol coue altei the
conuition is satislieu. Howevei, without cuily Liaces, you can wiite only one line ol
coue loi each conuition. Heie is an example ol the lattei syntax without cuily Liaces:
NSString *shortString = @"Hello!";
if ([shortString length] == 0)
NSLog(@"This is an empty string");
else
NSLog(@"This is not an empty string.");
Be extia caielul with logging anu il statements without cuily Liaces.
Olten, when a piouuct goes to piouuction, a piouuction managei might
attempt to comment out all youi NSLog methous simply Ly ieplacing all
occuiiences ol NSLog with //NSLog. Il you have il statements without
cuily Liaces, as in oui last example, the piouuction managei`s com-
menteu-out coue will look like this:
NSString *shortString = @"Hello!";
if ([shortString length] == 0)
//NSLog(@"This is an empty string");
else
//NSLog(@"This is not an empty string.");
This will Lieak the coue anu people in the company will not Le happy.
It uoesn`t mattei whethei they aie not happy at you oi not happy at the
piouuction managei. That woulu Le a team elloit gone wiong, so you
will all Le to Llame. To avoiu this, make suie that you always wiite youi
il statements with cuily Liaces.
See Also
Recipe 1.12; Recipe 1.15
1.9 Comparing Values in Objective-C with an if Statement | 29
www.it-ebooks.info
1.10 Implementing Loops with for Statements
Problem
You want to implement a coue that iepeats a ceitain numLei ol times, peihaps applying
the same pioceuuie to eveiy element in an aiiay oi some othei changing values.
Solution
Use the loi statement. The loimat ol this statement is:
for (code to execute before loop;
condition to be met for the loop to terminate;
code to execute in every iteration of the loop){
}
All thiee clauses ol the loi loop aie optional. In othei woius, you can
have a loi loop that looks like this:
for (;;){ YOUR CODE HERE }
This is known as an inlinite-loop oi a loop that has no conuition to
teiminate anu will iun loievei. This is a veiy Lau piogiamming piactice
inueeu anu you shoulu avoiu using it Ly all means while ueveloping iOS
piogiams.
Discussion
Loops aie uselul in piogiamming Lecause you will olten neeu to stait a loop liom one
place to anothei, liom one inuex to anothei, oi liom stait to stop. Foi instance, you
might want to loop thiough all chaiacteis insiue a stiing anu count how many A
chaiacteis you can linu in it. Anothei example is a loop that linus all liles in a uiiectoiy.
This is a loop that linus the numLei ol liles anu then staits liom the liist one until it
gets to the last one.
Usually, piogiammeis ieguiie a countei in theii loops. Foi instance, you might want
to ieau all the chaiacteis insiue a C-Stiing. Foi this, you will neeu the inuex ol each
chaiactei. Il youi stiing is 10 chaiacteis long, you will neeu to go liom inuex 0 to 9. Il
youi stiing is 20 chaiacteis long, you have to ieau liom inuex 0 to 19. Since the length
ol youi stiing is a vaiiaLle, you can put it as the exit-conuitional ol youi loop. Heie is
an example:
char *myString = "This is my string";
NSUInteger counter = 0;
for (counter = 0; /* Start from index 0 */
counter < strlen(myString); /* Exit loop when we reach last character */
counter++){ /* Increment the index in every iteration */
30 | Chapter 1: The Basics
www.it-ebooks.info
char character = myString[counter];
NSLog(@"%c", character);
}
The coue that gets executeu Leloie the loop (as noteu in the Solution section ol this
iecipe) is oLviously optional. In lact, all thiee main paits ol a loi loop aie optional, Lut
it is iecommenueu that you think aLout how you intenu to use youi loops anu use the
thiee main paits ol the loi statement accoiuingly.
Let`s have a look at wheie you woulu want to skip the liist statement ol youi loi loop.
As you coulu see in the pievious section, oui counter vaiiaLle was set to 0 Leloie we
even staiteu oui loop. Howevei, we aie setting it to 0 again once oui loop is aLout to
stait. This is unnecessaiy in this example, Lut theie is nothing wiong with that ap-
pioach. Il you leel you uon`t neeu the ieuunuant coue, simply iemove it:
char *myString = "This is my string";
NSUInteger counter = 0;
for (; /* empty section */
counter < strlen(myString); /* Exit loop when we reach last character */
counter++){ /* Increment the index in every iteration */
char character = myString[counter];
NSLog(@"%c", character);
}
The seconu clause ol any for loop is veiy impoitant Lecause this is the conuitional that
allows youi loop to exit. Having no conuition in the seconu clause is similai to having
a nevei-enuing loop, oi an inlinite loop, as it is known. Theieloie, it is Lest to think
aLout the conuition that allows youi piogiam to enu the loop anu continue on its path
ol execution.
Any vaiiaLle uelineu in the liist clause ol a for loop is accessiLle insiue the loop Lut
not outsiue it. Foi instance:
for (NSUInteger counter = 0;
counter < 10;
counter++){
NSLog(@"%lu", (unsigned long)counter);
}
/* "counter" is NOT accessible here. This line will throw compile time error */
NSLog(@"%lu", (unsigned long)counter);
The thiiu clause insiue a for loop is veiy inteiesting inueeu. This is the statement that
gets executeu ajtcr eveiy iteiation ol youi loop. This incluues the last iteiation. Foi
instance:
NSUInteger counter = 0;
for (counter = 0;
counter < 4;
1.10 Implementing Loops with for Statements | 31
www.it-ebooks.info
counter++){
NSLog(@"%lu", (unsigned long)counter);
}
NSLog(@"%lu", (unsigned long)counter);
This will piint the lollowing values to the console:
0
1
2
3
4
So oui countei did get to numLei +, although in oui loop we askeu that the countei
shoulu Le less than +. This pioves the point that when oui loop linishes, in the last
iteiation, the thiiu clause ol oui loi loop gets executeu. But the coue insiue oui loop
won`t Le calleu, since the enu-conuition (seconu clause) will not Le met anu oui loop
will linish.
1.11 Implementing while Loops
Problem
You want to let a piece ol coue iun ovei anu ovei again until a ceitain conuition is met.
Solution
Use while loops anu specily youi exit conuition. Heie is the loimat loi the while loop:
while (condition){
CODE
}
As long as the conuition is a value othei than zeio/nil/NULL, the while
loop will iun.
Discussion
The while loop is the aiiogant Liothei ol the loi loop (see Recipe 1.10) Lecause while
loops only take a conuition that shoulu Le met loi the loop to iun. Il the conuition is
positive, the loop will always iun until the conuition Lecomes negative. Foi instance,
a while loop coulu Le implementeu to make an icon in the Dock in Mac OS X jump up
anu uown until the usei taps on that icon (this is actually a veiy Lau usei expeiience;
icons in the Dock shoulun`t jump up anu uown continuously, Lut loi a shoit inteival,
oi even a lixeu numLei ol times, usually 3). The exit conuition loi the while loop is the
usei`s tapping on that icon. As long as the usei hasn`t tappeu on the icon, the icon will
jump up anu uown.
32 | Chapter 1: The Basics
www.it-ebooks.info
A while loop is awkwaiu to use with a countei Lecause ol its syntax. Il you ieguiie a
countei to contiol youi loop, it is Lettei to use a loi loop. Il you uo ieguiie a while loop
Lut still want to have access to a countei, you will neeu to manage the countei manually,
like so:
NSUInteger counter = 0;
while (counter < 10){
NSLog(@"Counter = %lu", (unsigned long)counter);
counter++;
}
]ust as you can have positive conuitions loi youi while loops, you can have negative
conuitions as well:
BOOL shouldExitLoop = NO;
NSUInteger counter = 0;
while (shouldExitLoop == NO){
counter++;
if (counter >= 10){
shouldExitLoop = YES;
}
}
NSLog(@"Counter = %lu", (unsigned long)counter);
The output ol this piogiam is:
Counter = 10
So what we aie uoing is simply iunning a loop loi as long as oui countei is less than
10. Il the value ol the countei (aujusteu insiue the loop itsell) goes ovei oi Lecomes
egual to 10, then we exit oui loop. ]ust like a loi loop, you can cieate an inlinite loop
using a while loop, although this is a teiiiLle piogiamming piactice anu you shoulu
avoiu it Ly all means:
while (YES){
/* Infinite loop */
}
You must make suie that you have an exit stiategy in youi while anu loi loops. Foi
this, you neeu to keep an eye on the conuition loi youi loops anu make suie that the
conuition will Le met at some point without making youi loops hog all the memoiy
anu/oi system iesouices while they iun, while using autoielease oLjects. As you know,
an autoielease oLject only gets ieleaseu when the autoielease pool owning that oLject
gets uiaineu oi ieleaseu. Il you uo not have an autoielease pool insiue youi loop con-
tinuously ieleasing autoielease oLjects, youi loop might enu up consuming too much
memoiy anu youi app might get teiminateu Ly iOS.
Heie is anothei usage ol a while loop:
char *myString = "Some Random String";
NSUInteger counter = 0;
char character;
1.11 Implementing while Loops | 33
www.it-ebooks.info
while ((character = myString[counter++]) != 'R' &&
counter < strlen(myString)){
/* Empty */
}
NSLog(@"Found the letter R at character #%lu", (unsigned long)counter+1);
Heie we aie seaiching insiue a stiing loi the liist occuiience ol the lettei R. As soon as
we linu it, we exit oui while loop. Ve have incluueu anothei conuition: il we ieach the
enu ol the stiing (strlen(myString)), we enu the loop, so we uon`t wanuei oll into
unuelineu memoiy anu cause a ciash oi a secuiity llaw. (This is calleu a bujjcr ovcrj|ow.)
This algoiithm has a Lug, howevei: it ietuins a wiong iesults when the lettei R isn`t in
the stiing at all. Because the while loop linishes when we get to the enu ol the stiing,
we always piint a message to the console saying that the lettei R was lounu at some
inuex. I will leave it up to you to lix this algoiithm. As a hint, you might want to use a
Boolean value when you uo linu the lettei R anu then latei use that llag to ueteimine
whethei the lettei was lounu. To use that Loolean technigue, you might neeu to change
the way the while loop is set up, Lut I think you get the iuea.
A while loop is uselul loi tiaveising an aiiay. Foi instance, a C Stiing is an aiiay ol
chaiacteis enuing with a zeio Lyte. Il you aie seaiching loi a specilic chaiactei in this
aiiay, you can simply wiite a while loop that staits liom the liist chaiactei anu iuns
until it linus the zeio teiminatoi that enus the stiing. Heie is an example:
char *cString = "My String";
char *stringPointer = cString;
while (*stringPointer != 0x00){
NSLog(@"%c", *stringPointer);
stringPointer++;
}
This example will piint all the chaiacteis insiue the stiing until it gets to the zeio tei-
minatoi ol the stiing. Using a while loop, you can even cieate a lunction similai to the
strlen() lunction that is aLle to linu the length ol a C Stiing, like so:
NSUInteger lengthOfCString(const char *paramString){
NSUInteger result = 0;
if (paramString == NULL){
return 0;
}
char *stringPointer = (char *)paramString;
while (*stringPointer != 0x00){
result++;
stringPointer++;
}
return result;
}
34 | Chapter 1: The Basics
www.it-ebooks.info
It`s Lettei to use the Luilt-in strlen loi two ieasons: it has Leen opti-
mizeu to make the Lest use ol the unueilying haiuwaie, anu it`s less
likely to contain a Lug.
See Also
Recipe 1.10
1.12 Creating Custom Classes
Problem
You want to pack a set ol ielateu lunctionalities into a ieusaLle entity loi immeuiate oi
latei use.
Solution
Cieate youi own classes.
Discussion
Let`s say you want to wiite a calculatoi piogiam. You aie cieating the usei inteilace
anu you want each Lutton on the calculatoi to have a Llack Lackgiounu, white text
anu have a bunp usei inteilace, just like a ieal Lutton. Aien`t these all common tiaits
among all the Luttons you want to place on youi UI? You got it! It`s Lest that we cieate
a class to iepiesent all oui Luttons anu wiite the coue once to ieuse multiple times.
Classes in oLjective-C aie noimally iepiesenteu with the lollowing coue:
Hcadcr ji|c
This is wheie you ueline what youi class Lasically uoes: accept usei input, iotate
a shape, oi whatevei. But the heauei lile uoes not implement any ol that lunction-
ality. Heauei liles have a .h extension.
|np|cncntation ji|c
Altei uelining the lunctionality ol youi class in the heauei lile, heie you wiite the
actual coue loi all that lunctionality. Implementation liles have a .n extension.
Let`s go a Lit moie into uetail Ly going aheau anu cieating a class. Follow these steps:
1. In Xcoue, go to the File menu anu then select New File.
2. A uialog will appeai, similai to that shown in Figuie 1-23. Heie simply select OL-
jective-C class liom the list to the iight. Make suie iOS is selecteu on the lelthanu
siue. Altei this, piess the Next Lutton.
3. In the next scieen, make suie the SuLclass ol text Lox says NSObject. Now piess
the Next Lutton (Figuie 1-2+).
1.12 Creating Custom Classes | 35
www.it-ebooks.info
+. In the next scieen, as shown in Figuie 1-25, make suie that the Save As text Lox
says Peison, which is what we`ll name oui class. On the Lottom ol this uialog, make
suie that you aie saving youi class in the coiiect gioup/loluei.
Now two liles will get auueu to youi pioject. One is calleu Pcrson.h anu the othei
Pcrson.n. The liist one is the heauei anu the seconu one is the implementation. Let`s
have a look at the contents ol the Pcrson.h lile:
#import <Foundation/Foundation.h>
@interface Person : NSObject
@end
How aLout the contents ol Pcrson.n?
#import "Person.h"
@implementation Person
- (id)init
{
self = [super init];
if (self) {
// Initialization code here.
}
Iigurc 1-23. Thc Add Ii|c dia|og in Xcodc
36 | Chapter 1: The Basics
www.it-ebooks.info
return self;
}
@end
Ve can see that Xcoue has piepopulateu these liles with some content. Ve still uon`t
ieally know what this content is, Lut it`s a stait to oui coue. Now we have a class nameu
Peison. Vheie uiu we get this name? It`s not the name ol the lile itsell, Lut Xcoue took
the lile name in Figuie 1-25 anu useu it as the class name. Il you have a look at the
contents ol the Pcrson.h again, you will notice this line ol coue:
@interface Person : NSObject
In shoit, what comes altei the @interface keywoiu is youi class name in this case. Il
you uon`t like this name, simply iight-click on it anu then select Relactoi anu then
Rename. This will guiue you thiough a ielactoiing piocess thiough which you can
iename youi class. Xcoue will make suie that the name ol youi class will Le changeu
thioughout youi coue, il you have ieleiieu to it anywheie.
Iigurc 1-21. Sctting thc basc c|ass oj our ncw c|ass
1.12 Creating Custom Classes | 37
www.it-ebooks.info
1.13 Defining Functionality for Classes
Problem
You want to ueline some lunctionality loi youi classes anu allow them to Le ieuseu latei.
Solution
Cieate instance oi class methous loi youi classes in oiuei to cieate ieusaLle Llocks ol
coue, oi simply call a methou in youi piogiam.
Discussion
Neaily eveiy piogiamming language cieates proccdurcs anu junctions to encapsulate
specilic lunctionality, especially lunctionality that the piogiammei uses ovei anu ovei.
Some languages consiuei pioceuuie anu lunction just teims loi the same thing,
while otheis make a uistinction Letween them. A pioceuuie is a Llock ol coue with a
name anu an optional set ol paiameteis. It uoes not have a ietuin value. In OLjective-
C, a pioceuuie ietuins void to inuicate it uoes not ietuin a value. A lunction is similai
Lut uoes have a ietuin value. Heie is a simple pioceuuie (with an empty Louy) wiitten
in C:
Iigurc 1-25. Crcating a c|ass ca||cd Pcrson in Xcodc
38 | Chapter 1: The Basics
www.it-ebooks.info
void sendEmailTo(const char *paramTo,
const char *paramSubject,
const char *paramEmailMessage){
/* send the email here ... */
}
This pioceuuie is nameu sendEmailTo anu has thiee paiameteis: paramTo, param
Subject, anu paramEmailMessage. Ve can then call this pioceuuie as lollows:
sendEmailTo("somebody@somewhere.com",
"My Subject",
"Please read my email");
Tuining this pioceuuie into a lunction that ietuins a Boolean value, we will have coue
similai to this:
BOOL sendEmailTo(const char *paramTo,
const char *paramSubject,
const char *paramEmailMessage){
/* send the email here ... */
if (paramTo == nil ||
paramSubject == nil ||
paramEmailMessage == nil){
/* One or some of the parameters are nil */
NSLog(@"Nil parameter(s) is/are provided.");
return NO;
}
return YES;
}
Calling this lunction is similai to calling the sendEmailTo pioceuuie except that with a
lunction, we can ietiieve the ietuin value, like so:
BOOL isSuccessful = sendEmailTo("somebody@somewhere.com",
"My Subject",
"Please read my email");
if (isSuccessful){
/* Successfully sent the email */
} else {
/* Failed to send the email. Perhaps we should display
an error message to the user */
}
In OLjective-C, each methou is cieateu loi a class. Cieating OLjective-C methous is
guite uilleient liom wiiting pioceuuies anu lunctions in a piogiamming language such
as C. Methous lall into two categoiies: instancc oi c|ass. Instance methous aie methous
that can Le calleu on an instance ol the class (that is, on each oLject you cieate Laseu
on the class), wheieas class methous get calleu on the class itsell anu uo not ieguiie an
instance ol the class to Le cieateu Ly the piogiammei. To cieate a methou in OLjective-
C, lollow these steps in the .n lile ol youi taiget class:
1.13 Defining Functionality for Classes | 39
www.it-ebooks.info
1. Type il you want an instance methou oi + il you want a class methou.
2. Choose the ietuin type ol youi methou anu enclose it within paienthesesloi
instance, (void) loi no ietuin value, (BOOL) loi a Boolean value, (NSObject *) to
ietuin an instance ol NSObject, anu so on.
3. Choose a name loi youi methou. Stait the name with a loweicase lettei. It is com-
mon in OLjective-C to stait methou names with a loweicase letteiloi instance,
sendEmailTo insteau ol SendEmailTo.
+. Il you uo not want any paiameteis loi youi methou, jump to step 9.
5. Choose two names loi youi paiametei. One name Lecomes a pait ol the methou
name anu will Le useu liom outsiue the methou (this is optional loi all paiameteis
except the liist). The othei name will Le useu as a paiametei name insiue the
methou. Theie is an exception to this in which the liist name ol the liist paiametei
ol a methou is pait ol the name ol the methou that you chose in step 3. Foi this
liist paiametei, you must only choose a seconu name, which Lecomes the paiam-
etei name useu insiue the methou itsell.
6. Once you aie uone choosing the name loi youi paiametei, choose the uata type ol
the methou anu enclose it within paientheses.
7. Put a colon altei youi paiametei`s liist chosen name (il any), anu put the paien-
theses that caiiy the uata type ol youi methou lolloweu Ly the seconu name loi
youi paiametei.
S. Repeat steps 5 thiough 7 loi any othei paiameteis that you might have.
9. Inseit an open cuily Liace ({) altei the methou name anu paiametei names (il you
have paiameteis) anu a closing cuily Liace (}) at the enu.
Going Lack to the sendEmailTo pioceuuie example that we saw eailiei, let`s attempt to
cieate the same pioceuuie as a methou in OLjective-C:
- (BOOL) sendEmailTo:(NSString *)paramTo
withSubject:(NSString *)paramSubject
andEmailMessage:(NSString *)paramEmailMessage{
/* Send the email and return an appropriate value */
if ([paramTo length] == 0 ||
[paramSubject length] == 0 ||
[paramEmailMessage length] == 0){
/* One or some of the parameters are empty */
NSLog(@"Empty parameter(s) is/are provided.");
return NO;
}
return YES;
}
40 | Chapter 1: The Basics
www.it-ebooks.info
This is an instance methou (-) that ietuins a Boolean value (BOOL). The name ol this
methou is sendEmailTo:withSubject:andEmailMessage: anu it has thiee paiameteis. Ve
can then call this methou in this way:
[self sendEmailTo:@"someone@somewhere.com"
withSubject:@"My Subject"
andEmailMessage:@"Please read my email."];
As mentioneu pieviously, the liist name ol eveiy paiametei (except the liist) is optional.
In othei woius, we can constiuct the sendEmailTo:withSubject:andEmailMessage:
methou in anothei way with a uilleient name:
- (BOOL) sendEmailTo:(NSString *)paramTo
:(NSString *)paramSubject
:(NSString *)paramEmailMessage{
/* Send the email and return an appropriate value */
if (paramTo length] == 0 ||
[paramSubject length] == 0 ||
[paramEmailMessage length] == 0){
NSLog(@"Empty parameter(s) is/are provided.");
return NO;
}
return YES;
}
I heavily uiscouiage you liom wiiting methous that have no exteinal
names loi theii paiameteis. This is inueeu a veiy Lau piogiamming
piactice anu will conluse you anu those whom you woik with on the
same team, iegaiuless ol how well you might have uocumenteu youi
coue.
Ve can call this methou like so:
[self sendEmailTo:@"someone@somewhere.com"
:@"My Subject"
:@"Please read my email."];
As you can see, the liist implementation is easiei to unueistanu when you look at the
invocation, since you can see the name ol each paiametei in the call itsell.
Declaiing anu implementing a class methou is similai to ueclaiing anu implementing
an instance methou. Heie aie a couple ol things you have to keep in minu when ue-
claiing anu implementing a class methou:
The methou type iuentiliei ol a class methou is + insteau ol the - type iuentiliei loi
instance methous.
You can access self in a class methou.
1.13 Defining Functionality for Classes | 41
www.it-ebooks.info
Class methous aie uselul when you want to pioviue new methous ol instantiation
loi youi classes. Foi example, a class methou nameu allocAndInit coulu Loth al-
locate anu initialize an oLject anu ietuin the oLject to its callei.
Suppose we want to cieate a class nameu MyClass. In this class, we want to implement
a class methou nameu allocAndInit that will allocate anu initialize an instance ol
MyClass anu ietuin the iesult to the callei. The heauei lile ol this class will look like this:
#import <Foundation/Foundation.h>
@interface MyClass : NSObject
+ (id) allocAndInit;
@end
The implementation ol this class methou will Le veiy stiaightloiwaiu. A simple allo-
cation lolloweu Ly an initialization:
#import "MyClass.h"
@implementation MyClass
+ (id) allocAndInit{
MyClass *result = [[MyClass alloc] init];
return result;
}
@end
In oui app uelegate now we can use this class methou to allocate anu initialize an
instance ol MyClass, like so:
#import "AppDelegate.h"
#import "MyClass.h"
@implementation AppDelegate
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
MyClass *instance1 = [MyClass allocAndInit];
NSLog(@"Instance 1 = %@", instance1);
self.window = [[UIWindow alloc]
initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
42 | Chapter 1: The Basics
www.it-ebooks.info
1.14 Defining Two or More Methods with the Same Name
Problem
You woulu like to implement two oi moie methous with the same name in one oLject.
In oLject-oiienteu piogiamming, this is calleu ncthod ovcr|oading. Howevei, in OL-
jective-C, methou oveiloauing uoes not exist in the same way as it uoes in othei pio-
giamming languages such as C--.
Solution
Use the same name loi youi methou, Lut keep the nunbcr anu/oi the nancs ol youi
paiameteis uilleient in eveiy methou:
- (void) drawRectangle{
[self drawRectangleInRect:CGRectMake(0.0f, 0.0f, 4.0f, 4.0f)];
}
- (void) drawRectangleInRect:(CGRect)paramInRect{
[self drawRectangleInRect:paramInRect
withColor:[UIColor blueColor]];
}
- (void) drawRectangleInRect:(CGRect)paramInRect
withColor:(UIColor*)paramColor{
[self drawRectangleInRect:paramInRect
withColor:paramColor
andFilled:YES];
}
- (void) drawRectangleInRect:(CGRect)paramInRect
withColor:(UIColor*)paramColor
andFilled:(BOOL)paramFilled{
/* Draw the rectangle here */
}
This example shows a typical pattein in oveiloauing. Each iectangle can Le uiawn eithei
lilleu (soliu coloi) oi empty (showing just its Lounuaiies). The liist pioceuuie is a
convenience pioceuuie that allows the callei to avoiu specilying how to lill the iec-
tangle. In oui implementation ol the liist pioceuuie, we meiely call the seconu pioce-
uuie, making the choice loi the callei (andFilled:YES) The seconu pioceuuie gives the
callei contiol ovei lilling.
1.14 Defining Two or More Methods with the Same Name | 43
www.it-ebooks.info
Discussion
You can ueline two methous with the same name so long as they uillei in the paiameteis
they accept. One ieasons loi uoing this is one lunction olleis moie customization
(thiough paiameteiization) than the othei lunction.
Methou oveiloauing is a piogiamming language leatuie suppoiteu Ly OLjective-C,
C--, ]ava, anu a lew othei languages. Using this leatuie, piogiammeis can cieate
uilleient methous with the same name, in the same oLject. Howevei, methou ovei-
loauing in OLjective-C uilleis liom that which can Le useu in C--. Foi instance, in C
--, to oveiloau a methou, the piogiammei neeus to assign a uilleient numLei ol pa-
iameteis to the same methou anu/oi change a paiametei`s uata type.
In OLjective-C, howevei, you simply change the name ol at least one paiametei.
Changing the type ol paiameteis will not woik:
- (void) method1:(NSInteger)param1{
/* We have one parameter only */
}
- (void) method1:(NSString *)param1{
/* This will not compile as we already have a
method called [method1] with one parameter */
}
Changing the ietuin value ol these methous will not woik eithei:
- (int) method1:(NSInteger)param1{
/* We have one parameter only */
return param1;
}
- (NSString *) method1:(NSString *)param1{
/* This will not compile as we already have a
method called [method1] with one parameter */
return param1;
}
As a iesult, you neeu to change the nunbcr oj paranctcrs oi the nanc ol (at least) one
paiametei that each methou accepts. Heie is an example wheie we have changeu the
numLei ol paiameteis:
- (NSInteger) method1:(NSInteger)param1{
return param1;
44 | Chapter 1: The Basics
www.it-ebooks.info
}
- (NSString*) method1:(NSString *)param1
andParam2:(NSString *)param2{
NSString *result = param1;
if ([param1 length] > 0 &&
[param2 length] > 0){
result = [result stringByAppendingString:param2];
}
return result;
}
Heie is an example ol changing the name ol a paiametei:
- (void) drawCircleWithCenter:(CGPoint)paramCenter
radius:(CGFloat)paramRadius{
/* Draw the circle here */
}
- (void) drawCircleWithCenter:(CGPoint)paramCenter
Radius:(CGFloat)paramRadius{
/* Draw the circle here */
}
Can you spot the uilleience Letween the ueclaiations ol these two methous? The liist
methou`s seconu paiametei is calleu radius (with a loweicase r) wheieas the seconu
methou`s seconu paiametei is calleu Radius (with an uppeicase R). This will set these
two methous apait anu allows youi piogiam to get compileu. Howevei, Apple has
guiuelines loi choosing methou names as well as what to uo anu what not to uo when
constiucting methous. Foi moie inloimation, please ielei to the Couing Guiuelines
loi Cocoa Apple uocumentation availaLle heie.
Heie is anothei example ol two methous that uiaw a ciicle Lut have uilleient names
loi theii seconu paiametei:
- (void) drawCircleWithCenter:(CGPoint)paramCenterPoint
radiusInPoints:(CGFloat)paramRadiusInPoints{
/* Draw the circle here */
}
- (void) drawCircleWithCenter:(CGPoint)paramCenterPoint
radiusInMillimeters:(CGFloat)paramRadiusInMillimeters{
/* Draw the circle here */
}
Heie is a concise extiact ol the things to look out loi when constiucting anu woiking
with methous:
1.14 Defining Two or More Methods with the Same Name | 45
www.it-ebooks.info
Have youi methou names uesciiLe what the methou uoes cleaily, without using
too much jaigon anu aLLieviations. A list ol acceptaLle aLLieviations is in the
Couing Guiuelines.
Have each paiametei name uesciiLe the paiametei anu its puipose. On a methou
with exactly thiee paiameteis, you can use the woiu and to stait the name ol the
last paiametei il the methou is piogiammeu to peiloim two sepaiate actions. In
any othei case, ieliain liom using and to stait a paiametei name. An example ol
the name ol a methou that peiloims two actions anu uses the woiu and in its name
is prefixFirstName:withInitials:andMakeInitialisUppercase:, wheie the methou
can pielix a liist name (ol type NSString) with the initials (ol type NSString again)
ol that inuiviuual. In auuition, the methou accepts a Loolean paiametei nameu
andMakeInitialsUppercase which, il set to YES, will pielix the liist name with an
uppeicase eguivalent ol the initials passeu to the methou. Il this paiametei is set
to NO, the methou will use the initials it is given, without changing theii case, to
pielix the liist name paiametei.
Stait methou names with a loweicase lettei.
Foi uelegate methous, stait the methou name with the name ol the class that in-
vokes that uelegate methou.
See Also
Recipe 1.13
1.15 Allocating and Initializing Objects
Problem
You want to cieate an instance ol a new oLject, Lut you uon`t unueistanu the uilleience
Letween a||ocation anu initia|ization anu why you shoulu have to Loth allocate anu
initialize an oLject Leloie you can use it.
Solution
You must Loth allocate anu initialize an oLject Leloie using it. An oLject can Le a||o-
catcd using the alloc instance methou. This class methou will allocate memoiy to holu
the oLject anu its instance vaiiaLles anu methous. Howevei, allocation leaves memoiy
unuelineu. So in auuition, each oLject must Le initia|izcd, which sets the values ol its
uata. One initialization methou must Le the dcsignatcd initia|izcr, which is noimally
the initialization methou with the most paiameteis. Foi instance, the initWithFrame:
methou is the uesignateu initializei ol oLjects ol type UIView. Always allocate anu ini-
tialize youi oLjects, in that oiuei, Leloie using them.
46 | Chapter 1: The Basics
www.it-ebooks.info
Vhen implementing a new oLject, uo not oveiiiue the alloc methou. This methou is
ueclaieu in NSObject. Insteau, oveiiiue the init methou anu cieate custom initialization
methous that hanule ieguiieu paiameteis loi the specilic oLject you aie woiking on.
Discussion
An oLject that inheiits liom NSObject must Le piepaieu loi use in two steps:
A||ocation
The allocation is uone Ly invoking the alloc methou, which is implementeu in the
NSObject class. This methou cieates the inteinal stiuctuie ol a new oLject anu sets
all instance vaiiaLles` values to zeio. Altei this step is uone, the init methou takes
caie ol setting up the uelault values ol vaiiaLles anu peiloiming othei tasks, such
as instantiating othei inteinal oLjects.
|nitia|ization
Initialization is the piocess Ly which a class piepaies each ol its instances` stoiage
(vaiiaLles), ieguiieu inteinal uata stiuctuie anu whatnot. Think ol allocation as
getting insiue a cai anu initialization as switching on the ignition.
Let`s look at an example. Ve aie cieating a class nameu MyObject. Heie is the .h lile:
#import <Foundation/Foundation.h>
@interface MyObject : NSObject
- (void) doSomething;
@end
The implementation ol this class is as lollows (the .n lile):
#import "MyObject.h"
@implementation MyObject
- (void) doSomething{
/* Perform a task here */
NSLog(@"%s", __FUNCTION__);
}
@end
the doSomething instance methou ol the MyObject oLject will attempt to piint the name
ol the cuiient lunction to the console winuow. Now let`s go aheau anu invoke this
methou Ly instantiating an oLject ol type MyObject:
MyObject *someObject = [[MyObject alloc] init];
/* Do something with the object, call some methods, etc. */
[someObject doSomething];
This coue will woik aLsolutely line. Now tiy to skip initializing youi oLject:
1.15 Allocating and Initializing Objects | 47
www.it-ebooks.info
MyObject *someObject = [MyObject alloc];
/* Do something with the object, call some methods, etc. */
[someObject doSomething];
Il you iun this coue now, you will iealize that it woiks aLsolutely line, too. So, what
has happeneu heie? Ve thought we hau to initialize the oLject Leloie we coulu use it.
Peihaps Apple can explain this Lehavioi Lettei:
An oLject isn`t ieauy to Le useu until it has Leen initializeu. The init methou uelineu in
the NSOLject class uoes no initialization; it simply ietuins sell.
Simply put, this means the init methou is a placeholuei loi tasks that some classes
neeu to peiloim Leloie they aie useu, such as setting up extia uata stiuctuies oi opening
liles. NSObject itsellalong with many ol the classes you will useuoes not have to
initialize anything in paiticulai. Howevei, it is a goou piogiamming piactice to always
iun the init methou ol an oLject altei allocating it in case the paient ol youi class has
oveiiiuuen this methou to pioviue a custom initialization. Please Leai in minu that the
ietuin value loi initializei methous ol an oLject is ol type id, so the initializei methou
might even ietuin an oLject that is not the same oLject that the alloc methou ietuineu
to you. This technigue is calleu two-stagc crcation anu is extiemely hanuy. Howevei,
uiscussing this technigue is outsiue the scope ol this Look. Foi moie inloimation aLout
two-stage cieation, please ielei to Cocoa Dcsign Pattcrns Ly Eiik M. Buck anu Donalu
A. Yacktman (Auuison-Vesley Piolessional).
1.16 Adding Properties to Classes
Problem
You want to auu piopeities to youi classes so that you can take auvantage ol uot no-
tation to access those values, as opposeu to using methous on youi classes.
Solution
Deline piopeities in youi classes using the @property keywoiu.
Discussion
Anything auuiesseu via uot notation is a piopeity, which is a shortcut to a methou.
Vhat uoes that mean? Vell, let`s have a look at an example:
NSObject *myObject = [[NSObject alloc] init];
myObject.accessibilityHint = @"Some string";
You can see that we allocateu anu initializeu an oLject ol type NSObject anu useu
uot notation to access a piopeity calleu accessibilityHint in that oLject. Vheie uiu
accessibilityHint come liom?
48 | Chapter 1: The Basics
www.it-ebooks.info
It`s guite simple. A piopeity is uelineu using the @property keywoiu. In lact, il you holu
uown the Commanu key on youi keyLoaiu in Xcoue, anu simply click on the accessi
bilityHint piopeity in the example that we just saw, you will Le ieuiiecteu to the
NSObjcct.h lile wheie you will see this:
@property(nonatomic, copy) NSString *accessibilityHint;
But what is a piopeity? It is a high-level language leatuiea shoitcut, il you willthat
allows uevelopeis to easily access getteis anu settei methous on instances ol a class
without having to ielei to the gettei anu/oi the settei methou at all. Il you want to set
a piopeity`s value, you simply use the eguals sign to uo so. Il you want to ieau liom
the piopeity, you simply point to it using uot notation.
Let`s look at this in uetail. In Recipe 1.12, we saw how we cieate classes. Ve cieateu a
class calleu Person. Then in Recipe 1.13, we leaineu how to auu methous to oui classes.
Now, Ly comLining the concepts exploieu in these two iecipes, we can leain moie
aLout piopeities. To stait, let`s go to the Pcrson.h lile anu ueline a piopeity calleu
firstName:
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property (nonatomic, strong) NSString *firstName;
@end
You will leain all aLout new Automatic Releience Counting keywoius,
such as strong, in Recipe 1.17.
A nonatomic piopeity is a piopeity that is not meant to Le accesseu anu changeu Ly
multiple thieaus at the same time. Such a piopeity oi vaiiaLle is not thieau-sale. A
thieau-sale (atomic) vaiiaLle will pievent multiple thieaus liom wiiting to it at the same
time, oi a thieau liom ieauing it while anothei thieau is wiiting to it. Foi peiloimance
ieasons (as well as the oveiheau necessaiy loi hanuling such vaiiaLles), atomic piop-
eities aie not Ly uelault pioviueu in iOS Ly the iuntime. Only apps uevelopeu loi the
Mac can take auvantage ol Loth atomic anu nonatomic piopeities. Il you want youi
piopeities to Le atomic, you will neeu to hanule thieauing anu access on youi own
using locks oi othei mechanisms that aie outsiue the scope ol this Look.
In teims ol the settei anu the gettei methous, loitunately, we uon`t have to wiite these
two methous loi piopeities manually. The LLVM compilei automatically geneiates
these settei anu gettei methous Ly putting a hiuuen @synthesize in the implementation
ol oui oLject. This keywoiu simply cieates a gettei anu a settei methou loi that piop-
eity. Foi instance, il you simply cieate a piopeity nameu firstName, the compilei will
take the lollowing actions on youi Lehall:
1.16 Adding Properties to Classes | 49
www.it-ebooks.info
Cieates an instance methou loi you nameu _firstName. This iule applies similaily
to any othei piopeity name.
Tiiggeis the lollowing synthesize loi you in youi implementation lile without you
having to touch it:
@synthesize firstName = _firstName
Unuei Automatic Releience Counting, it also takes caie ol ueallocating youi piop-
eities loi you.
Now we can go aheau anu use oui Person class. Heie is an example:
#import "SomeOtherClass.h"
#import "Person.h"
@implementation SomeOtherClass
- (void) makeNewPerson{
Person *newPerson = [[Person alloc] init];
newPerson.firstName = @"Andrew";
NSLog(@"First name = %@", newPerson.firstName);
NSLog(@"First name = %@", [newPerson firstName]);
}
@end
The example coue piints the liist name ol newPerson twice, liist using its firstName
piopeity anu then Ly calling the firstName gcttcr ncthod on that oLject. Both will point
to the same methou, which @synthesize cieateu loi us in the Pcrson.n lile.
In an oluei veision ol the OLjective-C iuntime, loi @property to woik,
we also hau to ueline an instancc variab|c. An instance vaiiaLle is a vaii-
aLle whose memoiy management is uone Ly the piogiammei heisell.
Instance vaiiaLles aie also not exposeu to classes outsiue the scope ol
the class that uelines them (i.e., they aie not exposeu to any class that
simply impoits the class with the instance vaiiaLle). Instance vaiiaLles
aie noimally calleu ivars Ly piolessional OLjective-C uevelopeis (ivai is
pionounceu I-VAR).
Vith the new iuntime, we uon`t have to ueline ivais anymoie. Ve sim-
ply ueline the piopeity anu the LLVM compilei uelines the ivai loi us.
Il you aie using the GCC compilei, which is iathei unlikely, you will see
Lig uilleiences liom how the LLVM compilei tieats ivais. Foi instance,
in GCC +.2, an ivai is not accessiLle to any suLclass ol a class, wheieas
il you aie using LLVM Compilei, a suLclass ol a class can use its supei-
class`s ivais. So make suie you aie using Apple`s latest compilei, which
is LLVM. Il a piopeity is ieau-only, the only way that piopeity`s value
can change is loi the class that uelines that piopeity to use the ivai ol
that piopeity to change the piopeity`s value.
50 | Chapter 1: The Basics
www.it-ebooks.info
Il you want to liuule aiounu with settei anu gettei methous, you aie liee to uo so. Even
il you have useu @synthesize to allow the compilei to geneiate the settei anu gettei
methous ol a piopeity loi you, you can still go aheau anu oveiiiue those methous. Foi
instance, in this example, I change the setFirstName: settei methou ol the firstName
piopeity ol the Person:
#import "Person.h"
@implementation Person
- (void) setFirstName:(NSString *)paramFirstName{
_firstName = [paramFirstName stringByAppendingString:@" Jr"];
}
- (id)init
{
self = [super init];
if (self) {
// Initialization code here.
_lastName = @"Carnegie";
}
return self;
}
@end
I have oveiiiuuen the settei methou ol my firstName piopeity to auu a ]i sullix to
any stiing that I am tolu to assign to the firstName piopeity. So when the settei anu
getteis aie invokeu, as Leloie:
Person *newPerson = [[Person alloc] init];
newPerson.firstName = @"Andrew";
NSLog(@"First name = %@", newPerson.firstName);
NSLog(@"First name = %@", [newPerson firstName]);
NSLog(@"Last name = %@", newPerson.lastName);
Ve will get the lollowing piinteu out to the console winuow:
First name = Andrew Jr
First name = Andrew Jr
Last name = Carnegie
Il you want to ueline a ieau-only piopeity, all you have to uo is to ueline youi piopeity
using the @readonly keywoiu, like so:
@property (nonatomic, strong, readonly) NSString *lastName;
See Also
Recipe 1.12; Recipe 1.13; Recipe 1.17
1.16 Adding Properties to Classes | 51
www.it-ebooks.info
1.17 Moving from Manual Reference Counting to Automatic
Reference Counting
Problem
You want to leain aLout Automatic Releience Counting, Apple`s new Compilei solu-
tion to solving the heauache that piogiammeis hau to ueal with when woiking with
oLjects anu memoiy management in OLjective-C.
Automatic Releience Counting eliminates many ol the manual ieleience
counting issues that ultimately iesulteu in iOS apps that woulu ciash
heie anu theie anu woulu Le veiy unstaLle when ueployeu on usei ue-
vices. ARC iemoves this heauache Ly leaving most ol the memoiy man-
agement complexity to the compilei.
Solution
Stuuy the new stoiage attiiLutes intiouuceu with the latest LLVM compilei: strong,
weak, anu unsafe_unretained.
Discussion
To use Automatic Releience Counting (ARC) in the latest LLVM compilei, we neeu to
ueal with stoiage that is stiong, weak, oi unsale anu unietaineu. Any oLject unuei ARC
is manageu with one ol these stoiage attiiLutes. Heie is a shoit explanation loi each one:
strong
An oLject ol this type is automatically ietaineu at iuntime anu will Le valiu until
the enu ol its scope, wheie it will automatically Le ieleaseu. Foi those lamiliai with
OLjective-C`s tiauitional way ol memoiy management, this keywoiu is similai to
the retain keywoiu.
weak
This is zeioing weak ieleiencing. Il a vaiiaLle is uelineu with this keywoiu, when
the oLject to which this vaiiaLle points gets ueallocateu, this value will get set to
nil. Foi instance, il you have a stiong stiing piopeity anu a weak stiing piopeity
anu set the weak piopeity`s value to the stiong piopeity`s value, when the stiong
piopeity gets ueallocateu, the weak piopeity`s value will get set to nil.
unsafe_unretained
This is simply pointing one vaiiaLle to anothei. This will not ietain the oLject into
the new vaiiaLle, it will simply assign the oLject to the vaiiaLle.
By uelault, all |oca| vaiiaLles aie stiong vaiiaLles. In contiast, piopeities must explicitly
specily theii stoiage attiiLute. In othei woius, the compilei won`t assume that all
piopeities without a stoiage attiiLute aie Ly uelault stiong piopeities. So uo make suie
52 | Chapter 1: The Basics
www.it-ebooks.info
that you specily the stoiage attiiLutes loi youi piopeities. Let`s have a look at an ex-
ample ol the strong stoiage attiiLute. Let`s assume we have two piopeities calleu
string1 anu string2:
#import <UIKit/UIKit.h>
@interface Moving_from_Manual_Reference_Counting_to_ARCAppDelegate
: UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (nonatomic, strong) NSString *string1;
@property (nonatomic, strong) NSString *string2;
@end
Now il we initialize the string1 piopeity with the stiing value ol String 1 anu assign
this piopeity`s value to the string2 piopeity, we will see that with the strong stoiage
attiiLute, the string2 piopeity will keep its value even altei string1 is ueallocateu:
#import "Moving_from_Manual_Reference_Counting_to_ARCAppDelegate.h"
@implementation Moving_from_Manual_Reference_Counting_to_ARCAppDelegate
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
self.string1 = @"String 1";
self.string2 = self.string1;
self.string1 = nil;
NSLog(@"String 2 = %@", self.string2);
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Memoiy allocateu loi an oLject is uisposeu ol when all stiong vaiiaLles
pointing to that memoiy aie ueallocateu.
The output ol this piogiam is this:
String 2 = String 1
the strong, weak, anu unsafe_unretained aie most lieguently useu when ueclaiing
piopeities. You can take auvantage ol these stoiage specilieis even when ueclaiing local
vaiiaLles, Lut you neeu to change the specilieis a Lit. The strong speciliei`s inline
eguivalent is __strong, weak speciliei`s inline eguivalent is __weak, anu unsafe_unre
1.17 Moving from Manual Reference Counting to Automatic Reference Counting | 53
www.it-ebooks.info
tained speciliei`s inline eguivalent is __unsafe_unretained. (Note that each ol those
keywoius Legins with two unueiline chaiacteis.) Heie is an example:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
/* All local variables are by default strong, so just emphasize that. We
really don't have to mention __strong for the first variable but
to make it clear, we will set it. No harm in doing so. */
__strong NSString *yourString = @"Your String";
__weak NSString *myString = yourString;
yourString = nil;
__unsafe_unretained NSString *theirString = myString;
/* All pointers will be nil at this time */
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
the unsafe_unretained stoiage speciliei is tiuly unsale, as its name implies. The ieason
loi it Leing unsale is il the oLject to which an unsafe_unretained vaiiaLle points gets
ueallocateu, this vaiiaLle will not get set to nil anu will point to a uangling location in
the memoiy. Accessing this location might cause youi application to ciash. To avoiu
this, you shoulu Le using the zeioing weak ieleiencing stoiage speciliei, weak oi its
inline eguivalent __weak.
Let`s see an example loi zeioing weak ieleiencing. Let`s change oui string2 piopeity`s
stoiage speciliei to weak insteau ol stiong:
#import <UIKit/UIKit.h>
@interface Moving_from_Manual_Reference_Counting_to_ARCAppDelegate
: UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (nonatomic, strong) NSString *string1;
@property (nonatomic, weak) NSString *string2;
@end
Vhen oui app staits loi the liist time, we will initialize the stiong string1 piopeity anu
will assign string1 to string2. Ve will then set the value ol the string1 piopeity to
nil. Then we will wait. This is aLsolutely ciucial. Il immeuiately altei setting the value
ol string1 to nil, you piint out the value ol string2, chances aie that you will get
incoiiect iesults insteau ol nil. So you neeu to make suie that youi app`s iun loop has
gotten iiu ol all invaliuateu oLjects. In oiuei to achieve this, we will piint the value ol
strong2 when oui app gets sent to the Lackgiounu. (This is causeu Ly the usei piessing
the home Lutton on theii iOS uevice.) Once we`ie iunning in the Lackgiounu, we know
54 | Chapter 1: The Basics
www.it-ebooks.info
that the iun loop has alieauy gotten iiu ol invaliuateu oLjects in the memoiy anu the
iesults that we will get will Le accuiate:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
self.string1 = [[NSString alloc] initWithUTF8String:"String 1"];
self.string2 = self.string1;
self.string1 = nil;
/* All pointers will be nil at this time */
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationDidEnterBackground:(UIApplication *)application{
NSLog(@"String 2 = %@", self.string2);
}
Now iun this app, wait a seconu oi two, anu piess the Home Lutton on the uevice/
simulatoi. You will notice that the lollowing iesults will get piinteu to the console
winuow:
String 2 = (null)
This easily pioveu that the zeioing weak ieleiences woik peilectly unuei ARC. Now
to check how uangeious the unsafe_unretained stoiage speciliei is, let`s go aheau anu
change the string2 piopeity`s stoiage speciliei to unsafe_unretained anu iepeat the
exact same piactice as we uiu loi the weak piopeity:
#import <UIKit/UIKit.h>
@interface Moving_from_Manual_Reference_Counting_to_ARCAppDelegate
: UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (nonatomic, strong) NSString *string1;
@property (nonatomic, unsafe_unretained) NSString *string2;
@end
Now il you leave the implementation ol youi app uelegate as we hau implementeu it
in the pievious example (piinting the value ol string2 piopeity when oui app gets sent
to the Lackgiounu), anu you iepeat the same pioceuuie anu open youi app anu senu
it to the Lackgiounu, you will ciash! This means that when oui app was sent to the
Lackgiounu, we tiieu to piint out the contents ol an invaliuateu memoiy location that
the string2 piopeity was pointing to. Since the string2 piopeity was unsale anu
1.17 Moving from Manual Reference Counting to Automatic Reference Counting | 55
www.it-ebooks.info
unietaineu, it uiun`t know that the oLject that it was pointing to (in string1) was alieauy
ueallocateu when string1 was set to nil.
In auuition to the aloiementioneu thiee stoiage specilieis, we can also use the __auto
releasing speciliei. This stoiage speciliei is most hanuy when we want to pass an oLject
Ly ieleience to a methou. This is ieguiieu loi when you want to call a methou anu leave
that methou iesponsiLle loi allocating, initializing, anu ietuining an instance ol a class.
The callei methou will then have no iesponsiLility at all to ielease the ietuineu instance
anu will leave it to the iuntime to ueciue when it is Lest to ielease the allocateu instance
ol that class (hanuleu Ly autoielease pools). Foi instance, il you have a methou that
neeus to pass an eiioi ol type NSError to the callei methou, the callei methou will pass
an uninitializeu anu unallocateu instance ol NSError to this methou. This means the
callei uiun`t allocate memoiy loi this eiioi vaiiaLle, so oui methou shoulu uo so. To
uo this, you must specily that this eiioi paiametei neeus to Le automatically ieleaseu
Ly the iuntime when the iight time comes:
- (void) generateErrorInVariable:(__autoreleasing NSError **)paramError{
NSArray *objects = [[NSArray alloc] initWithObjects:@"A simple error", nil];
NSArray *keys =
[[NSArray alloc] initWithObjects:NSLocalizedDescriptionKey, nil];
NSDictionary *errorDictionary = [[NSDictionary alloc] initWithObjects:objects
forKeys:keys];
*paramError = [[NSError alloc] initWithDomain:@"MyApp"
code:1
userInfo:errorDictionary];
}
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
NSError *error = nil;
[self generateErrorInVariable:&error];
NSLog(@"Error = %@", error);
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
In this example, the application:didFinishLaunchingWithOptions: methou uiun`t al-
locate the instance ol NSError; the generateErrorInVariable methou uiu. But loi the
compilei to unueistanu the scope ol the eiioi oLject, the generateErrorInVariable
56 | Chapter 1: The Basics
www.it-ebooks.info
methou mentioneu to the compilei that the oLject which will Le cieateu into its eiioi
paiametei neeus to Le automatically ieleaseu il it is no longei neeueu.
1.18 Typecasting with Automatic Reference Counting
Problem
You want to know how to use the new typecasting lacilities unuei Automatic Releience
Counting in oiuei to avoiu memoiy leaks when woiking with Coie Founuation oLjects
insiue youi OLjective-C coue.
Solution
Use the __bridge, __bridge_transfer, anu __bridge_retained typecasting specilieis.
Discussion
Typecasting is the piocess ol pointing one value ol type A to anothei value ol type B.
Foi instance, il you have a Coie Founuation stiing oLject ol type CFStringRef anu you
woulu like to place it insiue an OLjective-C stiing ol type NSString, you can easily cieate
an eiioi:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
CFStringRef coreFoundationString =
CFStringCreateWithCString(CFAllocatorGetDefault(),
"C String",
kCFStringEncodingUTF8);
/* Compile time error!!! */
NSString *objCString = coreFoundationString;
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Heie, we aie assigning the value ol the Coie Founuation stiing coreFoundationString
to the OLjective-C stiing ol type NSString nameu objCString. Oui compilei will get
conluseu Lecause it uoesn`t know what we aie intenuing to uo with the memoiy as-
signeu to each one ol these oLjects. Auuitionally, we will enu up with a memoiy leak
Lecause the compilei uoesn`t know how to get iiu ol the Coie Founuation oLject loi
us automatically. RememLei that Automatic Releience Counting uoes not woik loi
Coie Founuation oLjects, so we neeu to assist the compilei. To uo this, let`s tiy to
unueistanu what each one ol these typecasting specilieis uoes:
1.18 Typecasting with Automatic Reference Counting | 57
www.it-ebooks.info
__bridge
Simply typecasts the oLject on the iight siue ol the eguation to the lelt siue. This
will not mouily the ietain count on any ol the oLjects; neithei the one on the lelt
noi the one on the iight siue ol the eguation.
__bridge_transfer
This typecast will assign the oLject on the iight siue to the oLject on the lelt anu
will ielease the oLject on the iight siue. So il you have a Coie Founuation stiing,
like the one we saw Leloie, that you have just cieateu anu want to place it insiue
a local vaiiaLle ol type NSString (local vaiiaLles aie Ly uelault stiong, see
Recipe 1.17), then you shoulu use this typecasting option Lecause then you won`t
have to ielease the Coie Founuation stiing altei the assignment. Ve will see an
example ol this soon.
__bridge_retained
This is similai to the __bridge_transfer typecast, Lut will ietain the oLject on the
iight siue ol the eguation as well.
Let`s tiy to lix the example coue we saw Leloie. Oui goal is to place the Coie Founuation
stiing into an instance ol NSString (stiong, Ly uelault) anu then automatically ielease
the Coie Founuation stiing. To uo this, we must use the __bridge_transfer typecasting
option:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
CFStringRef coreFoundationString =
CFStringCreateWithCString(CFAllocatorGetDefault(),
"C String",
kCFStringEncodingUTF8);
/* Compile time error!!! */
NSString *objCString = (__bridge_transfer NSString *)coreFoundationString;
NSLog(@"String = %@", objCString);
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Vhat happeneu heie was that we cieateu a new Coie Founuation oLject. The ietain
count on this oLject is 1 at this time. Then we typecasteu anu assigneu it, using the
__bridge_transfer typecast option, to a stiong local vaiiaLle ol type NSString. But this
time, Lecause the compilei sees the typecasting, it will ietain the Coie Founuation stiing
anu place it insiue the local vaiiaLle (since the local vaiiaLle is strong Ly uelault) anu
altei the assignment, will ielease the Coie Founuation stiing. Peilect! Exactly what we
wanteu.
58 | Chapter 1: The Basics
www.it-ebooks.info
Now let`s have a look at when we woulu use __bridge_retained. This typecasting option
is useu whenevei we woulu like the oLject on the iight siue ol the eguation to still exist
altei the assignment. Heie is an example:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
CFStringRef coreFoundationString =
CFStringCreateWithCString(CFAllocatorGetDefault(),
"C String",
kCFStringEncodingUTF8);
id unknownObjectType = (__bridge id)coreFoundationString;
CFStringRef anotherString = (__bridge_retained CFStringRef)unknownObjectType;
NSString *objCString = (__bridge_transfer NSString *)coreFoundationString;
NSLog(@"String = %@", objCString);
objCString = nil;
CFRelease(anotherString);
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Heie is what is happening in this coue:
1. Ve allocateu a Coie Founuation stiing anu placeu it insiue the coreFoundation
String local vaiiaLle. Since this is a Coie Founuation oLject, ARC will not apply
stoiage attiiLutes to it, so we neeu to hanule its memoiy manually. Its ietain count
is 1, as with any newly cieateu vaiiaLle.
2. Then we typecast this Coie Founuation stiing to a geneiic oLject ol type id. Note
that we uiun`t ietain oi ielease this oLject, so the ietain count on Loth
unknownObjectType anu coreFoundationString stays 1. Ve simply typecasteu it to
an oLject ol type id.
3. Now we aie ietaining the geneiic oLject ol type id anu placing the iesulting oLject
into anothei Coie Founuation stiing. At this time, the ietain count on the core
FoundationString, unknownObjectType, anu anotherString vaiiaLles is 2 anu all
thiee ol these vaiiaLles point to the same location in the memoiy.
+. Vhat we aie uoing altei that is to assign the value insiue coreFoundationString to
a stiong local NSString using the __bridge_transfer typecasting option. This will
make suie that the coreFoundationString oLject will get ieleaseu altei this assign-
ment (the ietain count will go liom 2 to 1) anu it will again Le ietaineu (Lecause
ol the stiong NSString vaiiaLle, shooting the ietain count liom 1 to 2 again) So now
1.18 Typecasting with Automatic Reference Counting | 59
www.it-ebooks.info
coreFoundationString, unknownObjectType, anotherString anu the objCString vaii-
aLles all point to the same stiing with the ietain count ol 2.
5. The next stop is setting oui stiong local vaiiaLle objCString to nil. This will ielease
this vaiiaLle anu oui stiing`s ietain count will go Lack to 1. All these local vaiiaLles
aie still valiu anu you can ieau liom them Lecause the ietain count ol the stiing
that all ol them point to is still 1.
6. Then we aie explicitly ieleasing the value in the anotherString vaiiaLle. This will
set the ielease count ol oui oLject liom 1 to 0 anu oui stiing oLject will get
ueallocateu. At this point, you shoulu not use any ol these local vaiiaLles Lecause
they aie pointing to a ueallocateu oLjectexcept loi the objCString stiong local
vaiiaLle, whose value was set to nil Ly us.
See Also
Recipe 1.17
1.19 Delegating Tasks with Protocols
Problem
You want to make suie a ceitain oLject implements a set ol methous oi piopeities.
Solution
Use a piotocol.
Discussion
A piotocol is the ueclaiation (as opposeu to implementation) ol a set ol methous anu/
oi piopeities in a heauei lile (usually with the extension ol .h). Any oLject that you
ueclaie to conloim to such piotocol is iesponsiLle loi wiiting the implementation ol
those methous anu piopeities, uepenuing on whethei the piotocol specilies them as
ieguiieu oi optional.
Think ol piotocols as sets ol iules, with some iules Leing optional anu otheis manua-
toiy. Any oLject saying that it conloims to that piotocol must lollow those iules. Let`s
see a simple example ol this. Ve will go aheau anu ueline a piotocol calleu Person
Protocol. Foi this, you neeu to cieate a new piotocol lile, so lollow these steps liist:
1. In Xcoue, while youi pioject is open, go to the File menu anu then choose New
New File...
2. Now make suie iOS is the main categoiy on the lelt siue ol the New File uialog anu
then choose the Cocoa Touch suLcategoiy. Once that is uone, choose the OLjec-
tive-C Piotocol item anu piess Next (see Figuie 1-26).
60 | Chapter 1: The Basics
www.it-ebooks.info
3. Now you will Le askeu to save this lile anu specily a name loi it. Give it the name
PersonProtocol anu piess Save (see Figuie 1-27).
Now we have oui heauei lile. Let`s get on with the actual ueclaiation ol oui piotocol.
Oui oLjective with this new PersonProtocol piotocol is to govein the iules on any class
that impeisonates a Peison, oi in othei woius, says that it is a Peison class. Foi
instance, in youi application, you can have a class nameu Inlant, Mothei, Fathei, Son,
Daughtei, Stiangei, etc. You can then make all these classes conloim to the Person
Protocol piotocol, which will ueline the types ol Lehavioi each ol these classes must
implement. Let`s say that, loi eveiy peison, we neeu at least a liist name, a last name,
anu an age:
#import <Foundation/Foundation.h>
@protocol PersonProtocol <NSObject>
@property (nonatomic, strong) NSString *firstName;
@property (nonatomic, strong) NSString *lastName;
@property (nonatomic, unsafe_unretained) NSUInteger age;
@end
Now let`s cieate a class calleu Fathei anu make suie that this class conloims to oui
PersonProtocol piotocol. To cieate this class, lollow these steps:
Iigurc 1-2. Crcating a ncw protoco|
1.19 Delegating Tasks with Protocols | 61
www.it-ebooks.info
1. In Xcoue, while in youi pioject, go to the File menu anu then select New New
File...
2. In the New File uialog, make suie iOS is the main categoiy anu then choose the
Cocoa Touch suLcategoiy. Altei that is uone, select the OLjective-C class item in
the list on the iighthanu siue. Now piess the Next Lutton (see Figuie 1-2S).
3. In this scieen (see Figuie 1-29), make suie we aie cieating a suLclass ol NSObject.
Once that is uone, piess the Next Lutton.
+. Now you aie askeu to save the new class. Give it the name ol Fathei, anu piess the
Cieate Lutton (see Figuie 1-30).
Fantastic, we now have oui Father class anu the PersonProtocol piotocol. Open the
heauei lile ol the Father class anu make suie that it conloims to the PersonProtocol
piotocol:
#import <Foundation/Foundation.h>
#import "PersonProtocol.h"
@interface Father : NSObject <PersonProtocol>
@end
Iigurc 1-27. Saving thc ncw protoco|
62 | Chapter 1: The Basics
www.it-ebooks.info
Now il you attempt to compile youi app (Ly piessing Commanu-Shilt-R simultane-
ously), you will get wainings liom the compilei, similai to those shown in Figuie 1-31.
As you can see, the compilei unueistanus that the Father class wants to conloim to the
PersonProtocol piotocol. Howevei, the Father class isn`t implementing the ieguiieu
settei anu gettei methous ol the piopeities uelineu in the PersonProtocol piotocol. Ve
aie seeing these wainings Lecause anything uelineu in a piotocol Ly uelault is ieguiieu
liom its conloiming classes. Reguiieu methous anu piopeities in a piotocol can ex-
plicitly Le maikeu with the @required keywoiu. Il you want to specily that lolloweis ol
a piotocol aie liee to choose to implement oi not implement youi methous oi piopei-
ties, you can simply tell the compilei that those methous/piopeities aie optional, using
the @optional keywoiu.
Let`s go Lack to PcrsonProtoco|.h anu maik the firstName, lastName, anu age piopeities
as optional, Lut auu a methou to the piotocol calleu breathe anu make it a ieguiieu
methou, Lecause, let`s lace it, eveiyLouy has got to Lieathe:
#import <Foundation/Foundation.h>
@protocol PersonProtocol <NSObject>
@optional
@property (nonatomic, strong) NSString *firstName;
Iigurc 1-28. Crcating a Iathcr c|ass
1.19 Delegating Tasks with Protocols | 63
www.it-ebooks.info
@property (nonatomic, strong) NSString *lastName;
@property (nonatomic, unsafe_unretained) NSUInteger age;
@required
- (void) breathe;
@end
Now il you compile youi application, you will get completely uilleient wainings (see
Figuie 1-32).
Now il you go to the Father class anu ueline anu implement the breathe methou, even
il the methou implementation is empty, the compilei will Le happy with that. Remem-
Lei, the Father class now uoesn`t have to implement the thiee aloiementioneu piop-
eities Lecause they aie now uelineu as optional in the PersonProtocol piotocol. Heie
is now the coiiect uelinition ol the Father class:
#import <Foundation/Foundation.h>
#import "PersonProtocol.h"
@interface Father : NSObject <PersonProtocol>
- (void) breathe;
@end
Iigurc 1-29. Subc|assing NSObjcct to crcatc a Iathcr c|ass
64 | Chapter 1: The Basics
www.it-ebooks.info
Anu heie is the coiiect implementation ol the Father class:
#import "Father.h"
@implementation Father
- (void) breathe{
/* Implement this method here */
}
@end
Iigurc 1-30. Saving thc Iathcr c|ass on dis|
Iigurc 1-31. Warnings jron thc conpi|cr rc|atcd to thc protoco| wc arc conjorning to
1.19 Delegating Tasks with Protocols | 65
www.it-ebooks.info
Attempt to compile youi app now anu you`ll notice that the compilei is peilectly happy
with oui implementation.
Cocoa Touch has given piotocols a ieally nice meaning in OLjective-C. In Cocoa
Touch, piotocols aie the peilect means loi uelining dc|cgatc objccts. A uelegate oLject
is an oLject that anothei oLject consults when something happens in that oLject. Foi
instance, a iepaiiman is the uelegate loi a Lioken-uown cai. Il something happens to
youi cai, you go to youi iepaiiman anu ask him to lix the cai loi you (although some
pielei to iepaii the cai themselves, in which case they aie theii own uelegate loi theii
cai). So in Cocoa Touch, many classes expect a uelegate oLject anu make suie that
whatevei oLject is assigneu as theii uelegate conloims to a ceitain piotocol.
Foi instance, as we will see in Chaptei +, the UITableView class uelines anu implements
a piopeity calleu delegate, which is ieguiieu to conloim to the UITableViewDelegate
piotocol. This piotocol simply lays uown the law to those oLjects that want to Lecome
the uelegate oLject ol a taLle view. The piotocol ieguiies those oLjects to implement
ceitain methous oi in some cases, specilies that some methous/piopeities aie optional
so the uelegate oLject is liee to implement oi not implement them. Now, when a usei
selects a iow in a taLle, the UITableView can call the tableView:didSelectRowAtIndex
Path: methou with the assuiance that the UITableViewDelegate at least uelineu the
methou. The methou may Le coiiectly oi incoiiectly coueu, Lut at least it`s piesent, so
the piogiam won`t ciash at iuntime Lecause ol a nonexistent methou (selectoi).
1.20 Determining Whether Instance or Class Methods Are
Available
Problem
Youi uevelopment SDK is the newest SDK, Lut you want to suppoit uevices iunning
oluei iOS veisions anu APIs.
Iigurc 1-32. Thc Iathcr c|ass docs not inp|cncnt thc brcathc ncthod dcjincd in thc PcrsonProtoco|
protoco|
66 | Chapter 1: The Basics
www.it-ebooks.info
Solution
Use the instancesRespondToSelector: class methou ol NSObject to ueteimine whethei
a specilic selectoi exists in an instance ol that class.
A selectoi is the name ol youi methou without the paiametei uata types.
Foi instance, given the lollowing methou ueclaiation:
- (BOOL) doesString:(NSString *)paramNeedle
existInString:(NSString *)paramHaystack;
The selectoi loi this methou woulu Le doesString:existInString:.
To ueteimine whethei a class itsell iesponus to a class methou, use the responds
ToSelector: class methou ol youi class. You can use the same methou on an instance
ol a class to ueteimine whethei that instance iesponus to an instance methou, as well
as the instancesRespondToSelector: class methou ol the NSObject class.
Discussion
Theie aie two impoitant concepts with iegaiu to iOS SDK that you neeu to iememLei:
Basc SDK
The SDK that you use to compile youi application. This can Le the latest anu the
gieatest SDK with access to all the new APIs availaLle in iOS SDK.
Dcp|oyncnt SDK/Targct
This is the SDK that will Le useu when you compile youi app to iun on uevices.
Because ol the lact that you aie essentially compiling youi apps with two SDKs, one
the Lase anu the othei the ueployment SDK, uepenuing on which piolile you aie using
(uevice oi simulatoi), youi piogiam might Le vulneiaLle to invoking methous in classes
that aie availaLle only in the latest SDK, Lut not the ueployment SDK. So you might
neeu to check liom time to time loi the existence ol instance oi class methous at
iuntime.
Let me give you an example. The iOS SDK has a class calleu NSArray. As you will see
in Recipe 1.23, you can simply allocate anu initialize an oLject ol this type anu stait
using its methous. A mutaLle aiiay (an aiiay that can Le changeu altei it has Leen
constiucteu) is ol type NSMutableArray anu olleis soiting mechanisms that you can use
to soit the elements insiue the aiiay. Theie aie vaiious soiting methous, some ol which
aie availaLle only in newei SDKs. So what you can uo is ueteimine which ol the soiting
(instance) methous aie availaLle at iuntime anu then use those methous to soit the
aiiay:
1.20 Determining Whether Instance or Class Methods Are Available | 67
www.it-ebooks.info
NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:
@"Item 1",
@"Item 4",
@"Item 2",
@"Item 5",
@"Item 3", nil];
NSLog(@"Array = %@", array);
if ([NSArray instancesRespondToSelector:@selector(sortUsingComparator:)]){
/* Use the sortUsingComparator: instance method of the array to sort it */
}
else if ([NSArray instancesRespondToSelector:
@selector(sortUsingFunction:context:)]){
/* Use the sortUsingFunction:context: instance
method of the array to sort */
}
else {
/* Do something else */
}
So in this example, we aie checking the existence ol the specilic instance methous using
the instancesRespondToSelector: class methou ol the NSMutableArray class (which itsell
is a suLclass ol NSArray). Alteinatively, we coulu use the respondsToSelector: instance
methou ol oui aiiay:
NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:
@"Item 1",
@"Item 4",
@"Item 2",
@"Item 5",
@"Item 3", nil];
NSLog(@"Array = %@", array);
if ([array respondsToSelector:@selector(sortUsingComparator:)]){
/* Use the sortUsingComparator: instance method of the array to sort it */
}
else if ([array respondsToSelector:@selector(sortUsingFunction:context:)]){
/* Use the sortUsingFunction:context: instance
method of the array to sort */
}
else {
/* Do something else */
}
68 | Chapter 1: The Basics
www.it-ebooks.info
Fantastic. Ve checkeu the existence ol instance methous. How aLout class methous?
The NSArray class again has vaiious class methous, two ol which aie the array
WithObjects: anu the arrayWithObjects:count: methous. Ve can ueteimine theii avail-
aLility at iuntime anu use them to initialize the aiiay:
NSArray *array = nil;
if ([NSArray respondsToSelector:@selector(arrayWithObjects:count:)]){
NSString *strings[4];
strings[0] = @"String 1";
strings[1] = @"String 2";
strings[2] = @"String 3";
strings[3] = @"String 4";
array = [NSArray arrayWithObjects:strings
count:4];
}
else if ([NSArray respondsToSelector:@selector(arrayWithObjects:)]){
array = [NSArray arrayWithObjects:
@"String 1",
@"String 2",
@"String 3",
@"String 4",
nil];
}
else {
/* Do something else */
}
NSLog(@"Array = %@", array);
See Also
Recipe 1.23
1.21 Determining Whether a Class Is Available at Runtime
Problem
You aie using a lew classes that aie availaLle in the latest SDK, Lut you aie unsuie
whethei they aie availaLle on uevices that will Le iunning youi app, Lecause youi
ueployment taiget is eailiei than the latest SDK.
Solution
Use the NSClassFromString lunction. Pass the name ol youi class to this methou as a
stiing. Il the ietuin value ol this lunction is nil, that class is not availaLle on the uevice
that iuns youi app; otheiwise, that class is availaLle on the uevice anu you can go aheau
anu use it as you wish. Heie is an example:
1.21 Determining Whether a Class Is Available at Runtime | 69
www.it-ebooks.info
if (NSClassFromString(@"NSJSONSerialization") != nil){
/* You can use this class */
[NSJSONSerialization JSONObjectWithData:... /* Put data here */
options:... /* Put options here */
error:...]; /* Handle errors here */
} else {
/* That class is not available */
}
Discussion
It`s no seciet that useis aie slow in upgiauing theii opeiating systems. Voiking loi
vaiious companies, I can conliim that usually aiounu 30 ol iOS uevices touay aie
iunning veisions ol iOS that aie aLout a yeai oi a yeai-anu-a-hall olu. Foi instance, il
touay we aie woiking with iOS 6, theie aie still iOS uevices out theie iunning iOS 3.
Revenue is impoitant to uevelopeis, so we neeu to make suie that we suppoit oluei
uevices to some extent, so that we can cieate a Liggei usei Lase than we woulu Ly
pushing out an app that only iuns on iOS 6.
Some ol the classes that we use aie availaLle only on specilic veisions ol iOS. Foi in-
stance, the NSJSONSerialization class is availaLle only in iOS 5 SDK anu only uevices
iunning iOS 5 will Le aLle to iun such coue. Howevei, il you aie planning to suppoit
iOS + as well as iOS 5, then you can, at iuntime, uetect the availaLility ol the aloie-
mentioneu class using the NSClassFromString lunction, anu pass the name ol the class
that you want to use as a paiametei to this lunction. Il the ietuin value ol this lunction
is nil, that means the class that you specilieu cannot Le instantiateu on the specilic
uevice iunning youi app. In this situation, you will neeu to choose an alteinative path
anu instantiate anothei class that is availaLle on the uevice, which caiiies out similai
lunctionalities as the aLsent class.
1.22 Allocating and Making Use of Numbers
Problem
You neeu to use integial values oi encapsulate numLeis in oLjects.
Solution
Use NSNumber loi an oLject-oiienteu appioach to hanuling numLeis. Il you ieguiie sim-
ple numLeis (nonoLjects), use NSInteger to holu signeu (positive anu negative) values,
NSUInteger to holu unsigneu (only positive oi zeio) values, anu CGFloat anu double to
holu lloating-point values.
70 | Chapter 1: The Basics
www.it-ebooks.info
Discussion
]ust as we place stiings insiue instances ol NSString, we can place numLeis insiue in-
stances ol NSNumber. Vhy? you might ask. The answei is simple: to allow an oLject
to caiiy the value ol oui numLeis so that we can save this value to uisk easily, loau it
liom uisk, anu simply allow a single oLject to caiiy signeu anu unsigneu integial anu
lloating-point values, without the neeu loi typecasting oi uelining multiple vaiiaLles.
The possiLilities aie viitually enuless.
Let`s have a look at constiucting instances ol NSNumber:
NSNumber *signedNumber = @-123456;
NSNumber *unsignedNumber = @123456;
NSNumber *floatNumber = @123456.123456f;
NSNumber *doubleNumber = @123456.1234567890;
]ust as we placeu signeu anu unsigneu integeis anu lloating-point values into an in-
stance ol NSNumber class, we can ietiieve those values using some ieally hanuy instance
methous ol NSNumber class, as shown heie:
NSNumber *signedNumber = @-123456;
NSNumber *unsignedNumber = @123456;
NSNumber *floatNumber = @123.123456f;
NSNumber *doubleNumber = @123.1234567890;
NSInteger signedValue = [signedNumber integerValue];
NSUInteger unsignedValue = [unsignedNumber unsignedIntegerValue];
CGFloat floatValue = [floatNumber floatValue];
double doubleValue = [doubleNumber doubleValue];
NSLog(@"signedValue = %ld, \n"\
"unsignedValue = %lu \n"\
"floatValue = %f \n"\
"doubleValue = %f",
(long)signedValue,
(unsigned long)unsignedValue,
floatValue,
doubleValue);
Ve aie using the new leatuies availaLle in the LLVM compilei loi iOS 6 SDK to cieate
oui numLeis. Ve can simply place oui numLeis stiaight altei an at sign (@) anu oui
compilei will conveit these numLeis to instances ol the NSNumber class. This technigue
is calleu cxprcssion boxing. Il you uon`t want to use this leatuie, you can still use the
vaiious methous ol the NSNumber class to constiuct instances ol this class.
Heie aie the methous ol NSNumber that you can use in youi coue to actually geneiate
instances ol NSNumber class:
numberWithInteger:
Encapsulates an integei into an instance ol NSNumber.
1.22 Allocating and Making Use of Numbers | 71
www.it-ebooks.info
numberWithUnsignedInteger:
Encapsulates an unsigneu integei (only positive oi zeio numLeis) into an instance
ol NSNumber.
numberWithFloat:
Encapsulates a lloating-point value into an instance ol NSNumber.
numberWithDouble:
Encapsulates a uouLle value into an instance ol NSNumber.
Anu heie aie the methous that you can use to extiact puie numLeis liom instances ol
NSNumber:
integerValue
Retuins an integei ol type NSInteger liom the NSNumber on which this methou is
calleu.
unsignedIntegerValue
Retuins an unsigneu integei ol type NSUInteger liom the NSNumber on which this
methou is calleu.
floatValue
Retuins a lloating-point value ol type CGFloat liom the NSNumber on which this
methou is calleu.
doubleValue
Retuins a uouLle value ol type double liom the NSNumber on which this methou is
calleu.
Il you want to conveit a numLei to a stiing, simply conveit it to any ol the iaw integial/
lloat values that you think can contain the whole ol that numLei, anu then loimat youi
stiing using a loimat iuentiliei that suits youi uata. Foi instance, to tuin an unsigneu
integei into an instance ol NSString, you can use the %lu loimat speciliei, like so:
NSNumber *unsignedNumber = @123456;
/* Convert an unsigned integer inside an NSNumber to NSString */
NSString *stringValueOfNumber =
[NSString stringWithFormat:@"%lu",
(unsigned long)[unsignedNumber unsignedIntegerValue]];
NSLog(@"String from Number = %@", stringValueOfNumber);
1.23 Allocating and Making Use of Arrays
Problem
You want to stoie a seiies ol oLjects into anothei oLject loi latei use.
72 | Chapter 1: The Basics
www.it-ebooks.info
Solution
Use NSArray anu NSMutableArray classes to stoie oLjects into aiiays that aie lixeu anu
that you can change, iespectively.
Discussion
An oLject ol type NSArray oi any ol its suLclasses has the capaLility to stoie n numLei
ol othei oLjects, wheie n will Le ueteimineu Ly the iuntime anu is inlluenceu Ly how
much memoiy is availaLle at the time. These oLjects can then Le accesseu using theii
inuex. Foi instance, let`s say you have 10 paiis ol socks. Now imagine placing them all
on a llat suilace liom lelt to iight anu calling them socks 1, socks 2, socks 3, anu so on.
So the leltmost paii ol socks is now auuiesseu as socks 1, the paii next to it is calleu
socks 2, anu the iightmost paii is calleu socks 10. Isn`t that easiei than saying something
like the Llue socks next to my ieu socks? That`s exactly what aiiays uo: they make
aiianging items much easiei.
You can place any oLject ol type NSObject oi any ol its suLclasses into
an aiiay ol type NSArray (oi suLclasses ol that type). An aiiay can contain
a mix ol uilleient types ol oLjects. Not all oLjects have to Le ol the same
type. In othei woius, you can have one aiiay with stiings, numLeis,
uictionaiies, oi even othei aiiays insiue it. Aiiays can contain any oLject
as long as those oLjects can Le wiappeu in the id uata type wiappei.
The piimaiy uilleience Letween NSArray anu NSMutableArray is that a mutaLle aiiay can
Le changeu/mouilieu altei it has Leen allocateu anu initializeu, wheieas an immutaLle
aiiay, NSArray, cannot.
Let`s have a look at an example. Fiist, cieate an instance ol NSString anu two instances
ol NSNumber anu place them in an immutaLle aiiay:
NSArray *array = @[@"My String", @123, @-123];
NSLog(@"array = %@", array);
Vhen you iun this piogiam, the lollowing text is piinteu to youi console:
array = (
"My String",
123,
"-123"
)
Ve useu the new collection suLsciipting leatuies ol oui LLVM compilei to constiuct
the aiiay. These let us constiuct the aiiay using the @[] collection loimat anu place oui
oLjects Letween the opening anu the closing sguaie Liackets. This syntax cieates an
instance ol an aiiay loi us. Vhen using this methou ol constiucting youi aiiays, pass
youi oLjects that neeu to Le placeu insiue the aiiay one Ly one.
1.23 Allocating and Making Use of Arrays | 73
www.it-ebooks.info
Ve can also use the arrayWithObjects: class methou ol NSArray to cieate an autoielease
aiiay, like so:
NSArray *array = [NSArray arrayWithObjects:
stringObject,
signedNumber,
unsignedNumber, nil];
You can call the count methou on youi aiiay to get the numLei ol oLjects in that aiiay.
You can go thiough youi aiiay using a loi loop oi using an enumeiatoi. Let`s have a
look at the solution with a loi loop liist:
NSArray *array = @[@"My String", @123, @-123];
NSUInteger counter = 0;
for (counter = 0;
counter < [array count];
counter++){
id object = array[counter];
NSLog(@"Object = %@", object);
}
Anu heie is the output:
Object = My String
Object = -123
Object = 123
Asiue liom the [] syntax to access a specilic oLject in an aiiay, we can also use the
objectAtIndex: methou to get an oLject at a specilic inuex. RememLei that inuexes aie
zeio Laseu. In othei woius, when the countei ieaches -1, the loop has to stop Lecause
theie can Le no negative inuexes in an aiiay.
As mentioneu Leloie, you can also use last enumeiation to go thiough oLjects ol an
aiiay. Fast enumeiation is a language leatuie in OLjective-C that allows you to enu-
meiate oLjects in an aiiay oi uictionaiy (oi any othei oLject that suppoits last enu-
meiation) without having to use any countei oi loi loop. The loimat is as lollows:
for (Type variableName in array/dictionary/etc){ ... }
Suppose we want to coue the pievious example without the oveiheau ol a countei
vaiiaLle. Heie is how we can uo it using last enumeiation:
for (id object in array){
NSLog(@"Object = %@", object);
}
The iesults aie piactically iuentical to the iesults we got liom the pievious veision ol
this coue that useu a countei vaiiaLle.
MutaLle aiiays aie veiy inteiesting. As you pioLaLly have alieauy guesseu, immutaLle
aiiays cannot Le mouilieu once allocateu anu initializeu. MutaLle aiiays, howevei, can
Le mouilieu altei theii allocation anu initialization. Let`s have a look at an example:
74 | Chapter 1: The Basics
www.it-ebooks.info
NSArray *anotherArray = @[@"String 1", @"String 2", @"String 3"];
NSMutableArray *mutableArray = [NSMutableArray arrayWithArray:
@[@"My String", @123, @-123]];
[mutableArray addObject:@123];
[mutableArray removeObject:@-123];
[mutableArray addObjectsFromArray:anotherArray];
for (id object in mutableArray){
NSLog(@"Object = %@", object);
}
Beloie we go into analyzing the coue, let`s have a look at its output:
Object = My String
Object = 123
Object = 123
Object = String 1
Object = String 2
Object = String 3
You might Le wonueiing what just happeneu. Vell, let`s have a look at what methous
ol the NSMutableArray class we actually useu:
addObject:
This methou allows us to auu an oLject to the enu ol a mutaLle aiiay.
removeObject:
Using this methou, we can iemove a specilic oLject liom the aiiay. RememLei that
we pass an oLject to this methou, not an inuex ol the oLject. To iemove an oLject
using an inuex into the aiiay, we must use the removeObjectAtIndex: methou.
addObjectsFromArray:
Vith this methou, we can auu oLjects liom one aiiay (eithei mutaLle oi immuta-
Lle) into oui mutaLle aiiay.
Beai in minu that uuiing last enumeiation ol a mutaLle aiiay, you must
not auu to oi iemove anything liom that aiiay oi you will get a iuntime
eiioi. This is the uelault Lehavioi ol mutaLle aiiays uuiing last enu-
meiation. Theie aie two ways ol avoiuing this. Eithei simply lollow the
iule ol not mouilying an aiiay while last enumeiating it, oi, il you pielei
the moie pioactive appioach, you can suLclass NSMutableArray anu
change the Lehavioi loi youisell. This topic is outsiue the scope ol this
Look anu will not Le uiscusseu.
Il you aie inteiesteu in Llock oLjects (anu we`ll see goou ieasons to Le, latei in the Look,
in Chaptei 6), you can also enumeiate oLjects in youi aiiays using the enumerate
ObjectsUsingBlock: methou. The Llock oLject passeu to this methou shoulu:
Retuin no value.
Have thiee paiameteis:
1.23 Allocating and Making Use of Arrays | 75
www.it-ebooks.info
Fiist paiametei ol type id, which will Le the oLject Leing enumeiateu at each
loop ol enumeiation.
Seconu paiametei ol type NSUInteger, which will tell you the inuex ol the cui-
ient oLject Leing enumeiateu.
Last Lut not least, a paiametei ol type *BOOL, which you can use to stop the
enumeiation. This is a pointei to a Loolean vaiiaLle, which shoulu Le NO as
long as you want the enumeiation to pioceeu. You can change the value ol
this pointei to YES in oiuei to stop the enumeiation at any time. You woulu
use this il you aie looking loi an oLject in an aiiay anu you woulu like to stop
the enumeiation as soon as you`ve lounu that oLject, since theie is no point
continuing the enumeiation il you`ve alieauy lounu youi oLject.
NSArray *myArray = @[
@"String 1",
@"String 2",
@"String 3",
@"String 4"];
[myArray enumerateObjectsUsingBlock:
^(__strong id obj, NSUInteger idx, BOOL *stop) {
NSLog(@"Object = %@", obj);
}];
Il you neeu to soit an aiiay, simply use the new Llock-Laseu soiting methous ol
NSArray oi NSMutableArray. ]ust iememLei that the soiting methous ol NSArray ietuin
a new instance ol NSArray anu leave the oiiginal aiiay intact, since NSArray cannot Le
mouilieu (soiting can mouily an aiiay) altei it has Leen allocateu anu initializeu. This
is in compaiison to the soiting methous ol NSMutableArray, wheie the oiiginal aiiay
will Le the taiget ol soiting anu the soiting methous will not ietuin a new aiiay. Let`s
look at soiting a mutaLle aiiay:
NSMutableArray *myArray = [NSMutableArray arrayWithArray:@[
@"String 2",
@"String 4",
@"String 1",
@"String 3"]];
[myArray sortUsingComparator:
^NSComparisonResult(__strong id obj1, __strong id obj2) {
NSString *string1 = (NSString *)obj1;
NSString *string2 = (NSString *)obj2;
return [string1 compare:string2];
}];
NSLog(@"myArray = %@", myArray);
NSLog(@"%d", [@"String 3" compare:@"String 1"]);
The iesults will then Le piinteu to the console, as lollows:
76 | Chapter 1: The Basics
www.it-ebooks.info
myArray = (
"String 1",
"String 2",
"String 3",
"String 4"
)
So, what happeneu? Ve simply calleu the sortUsingComparator: methou ol oui aiiay.
This methou takes in a Llock oLject (maikeu Ly the initial ^ chaiactei) that has to ietuin
a value ol type NSComparisonResult. This value can Le any ol the lollowing:
NSOrderedSame
The two values Leing compaieu aie egual.
NSOrderedAscending
The value on the lelt ol the compaiison is smallei than the value on the iight. Think
ol it as this: tiansition liom value 1 (lelt) to value 2 (iight) is ascenuing, meaning
that value 1 is smallei.
NSOrderedDescending
The value on the iight is smallei than the value on the lelt. In othei woius, the
tiansition liom value 1 (lelt) to value 2 (iight) is uescenuing, meaning that value 1
is Liggei than value 2.
So il we get String 3 as value 1 (lelt) anu String 1 as value 2 (iight), the soit lunction
compaies the two S chaiacteis anu linus them the same, then the two t chaiacteis, anu
so on. Finally, when the soit lunction ieaches the 3 anu the 1, it linus that 1 is lowei
than 3 in the UTF-S stiing chaiactei set, anu theieloie that the seconu element is lowei
than the liist.
The Llock oLject suLmitteu to the sortUsingComparator: methou takes two paiameteis:
Iirst objcct oj typc id
This is the liist oLject in the compaiison in each iteiation.
Sccond objcct oj typc id
This is the seconu oLject in the compaiison in each iteiation.
So when soiting the aiiay, simply use a Llock-Laseu appioach. It`s the way Apple is
pushing uevelopeis to go loiwaiu with theii implementations, so it`s goou to know
aLout Llock oLjects.
1.24 Allocating and Making Use of Dictionaries
Problem
You want to stoie key-value uata in an oLject, oi you woulu like to ietiieve oLjects liom
an aiiay using a key into the aiiay, Lut aiiays won`t guite sullice loi this puipose, as
they uo not lacilitate linuing oLjects insiue the aiiay using a key oi a maikei loi that
oLject.
1.24 Allocating and Making Use of Dictionaries | 77
www.it-ebooks.info
Solution
Use NSDictionary anu its mutaLle counteipait, NSMutableDictionary.
Discussion
A uictionaiy is a special containei loi oLjects in which each oLject is given a key, which
itsell is an oLject. That is one ol the key uilleiences Letween uictionaiies anu aiiays.
An aiiay has a numeiic inuex into each item/oLject that it holus, wheieas a uictionaiy
holus a key to each item. I`ll show you what I mean.
Let`s say we want to stoie a peison`s liist name, last name, anu age into an aiiay anu
then into a uictionaiy. This is how we woulu stoie those values in an aiiay:
NSArray *person = @[
@"Anthony",
@"Robbins",
@51];
NSLog(@"First Name = %@", person[0]);
NSLog(@"Last Name = %@", person[1]);
NSLog(@"Age = %@", person[2]);
You can see that we aie using an inuex into the aiiay to access each one ol these values.
Vith uictionaiies, we give each value a |cy, which is an oLject, anu then use that key
to access those values. Let`s look at the same example Lut this time using uictionaiies.
Ve have a "First Name" key with the value "Anthony" anu so on:
NSDictionary *person = @{
@"First Name" : @"Anthony",
@"Last Name" : @"Robbins",
@"Age" : @51
};
NSLog(@"First Name = %@", person[@"First Name"]);
NSLog(@"Last Name = %@", person[@"Last Name"]);
NSLog(@"Age = %@", person[@"Age"]);
The iesults will then Le piinteu out as shown heie:
First Name = Anthony
Last Name = Robbins
Age = 51
As you can see, we initializeu the uictionaiy with values anu keys. Ve give a value
lolloweu Ly the key loi that value. Vhen we useu NSLog, we piinteu out each value Ly
hanuing the key to the uictionaiy`s objectForKey: methou.
The mutaLle veision ol NSDictionary, NSMutableDictionary, can Le mouilieu altei it has
Leen allocateu anu initializeu. Foi instance, il we want to iemove the oLject associateu
with the key Age liom oui uictionaiy altei its initialization, we woulu use a mutaLle
uictionaiy like so:
78 | Chapter 1: The Basics
www.it-ebooks.info
NSMutableDictionary *person = [@{
@"First Name" : @"Anthony",
@"Last Name" : @"Robbins",
@"Age" : @51
} mutableCopy];
[person removeObjectForKey:@"Age"];
NSLog(@"First Name = %@", person[@"First Name"]);
NSLog(@"Last Name = %@", person[@"Last Name"]);
NSLog(@"Age = %@", person[@"Age"]);
Ve have simply iemoveu the oLject associateu with the key Age. The iesults piinteu to
the console winuow will Le similai to this:
First Name = Anthony
Last Name = Robbins
Age = (null)
"Age" is not just empty, Lut totally missing.
Il you want to enumeiate all keys with theii oLjects insiue a uictionaiy, you can simply
use the enumerateKeysAndObjectsUsingBlock: methou ol the uictionaiy. In the pievious
example, the methou woulu piint the "First Name" anu "Last Name" elements, Lut not
"Age", Lecause we iemoveu it. The paiametei to this methou is a Llock oLject with no
ietuin value anu thiee paiameteis:
Kcy
An id that tells you which key is Leing enumeiateu at the moment.
Objcct
An id that gives you the oLject associateu with the key Leing cuiiently enumeiateu.
A pointcr to a va|uc oj typc BOOL
At any point uuiing the enumeiation, il you want to stop the piocess, you can
simply put the value YES into this pointei`s memoiy auuiess. Keep it untoucheu il
you want to enumeiate thiough all the keys in the uictionaiy.
Let`s see an example:
NSDictionary *person = @{
@"First Name" : @"Anthony",
@"Last Name" : @"Robbins",
@"Age" : @51
};
1.24 Allocating and Making Use of Dictionaries | 79
www.it-ebooks.info
[person enumerateKeysAndObjectsUsingBlock:
^(__strong id key, __strong id obj, BOOL *stop) {
NSLog(@"Key = %@, Object For Key = %@", key, obj);
}];
Anu the iesults, which get piinteu to the console winuow, aie shown heie:
Key = Last Name, Object For Key = Robbins
Key = First Name, Object For Key = Anthony
Key = Age, Object For Key = 51
Il you want to uo a manual last enumeiation without Llock oLjects, you can use the
allKeys methou ol the uictionaiy to go thiough all methous anu, once you enumeiate
the keys, use the keys to linu the oLjects associateu with the keys using the objectFor
Key: methou, like so:
for (id keyInDictionary in [person allKeys]){
id objectForKey = [person objectForKey:keyInDictionary];
NSLog(@"Key = %@, Object For Key = %@", keyInDictionary, objectForKey);
}
Beai in minu that you can tiaveise the keys in a uictionaiy in vaiious ways. Ve`ve just
seen two ways ol uoing this. Theie is anothei methou that we can use: calling the
keyEnumerator methou ol the uictionaiy to get an oLject ol type NSEnumerator. Heie is
an example:
NSEnumerator *keys = [person keyEnumerator];
id keyInDictionary = nil;
while ((keyInDictionary = [keys nextObject]) != nil){
id objectForKey = [person objectForKey:keyInDictionary];
NSLog(@"Key = %@, Object For Key = %@", keyInDictionary, objectForKey);
}
Vhen using the keyEnumerator methou ol a mutaLle uictionaiy, you aie
not alloweu to change the values insiue the uictionaiy while going
thiough the keys. The same iule, il you iememLei, applies to mutaLle
aiiays as well.
1.25 Allocating and Making Use of Sets
Problem
You woulu like to stoie an aiiay ol oLjects Lut you uon`t want any one oLject to appeai
moie than once in the aiiay.
80 | Chapter 1: The Basics
www.it-ebooks.info
Solution
Use sets insteau ol aiiays.
Discussion
Sets aie veiy similai to aiiays. The Lig uilleience is that sets allow oLjects to Le auueu
only once. The seconu time you tiy to auu the same oLject, it will Le iejecteu Ly the
set. Ve use NSSet loi immutaLle anu NSMutableSet loi mutaLle sets. Let`s have a look
at an example ol an immutaLle set:
NSString *hisName = @"Robert";
NSString *hisLastName = @"Kiyosaki";
NSString *herName = @"Kim";
NSString *herLastName = @"Kiyosaki";
NSSet *setOfNames = [[NSSet alloc] initWithObjects:
hisName,
hisLastName,
herName,
herLastName, nil];
NSLog(@"Set = %@", setOfNames);
Ve cieateu an immutaLle set anu passeu + stiing oLjects to its initializei methou. So
let`s see what gets piinteu out to the console winuow with oui NSLog:
Set = {(
Kim,
Robert,
Kiyosaki
)}
You can see that the last name Kiyosaki was auueu only once to the list. Oui set iejecteu
the seconu auuition ol the same oLject to the list. It is vcry impoitant to unueistanu
that a set uoesn`t just uo a compaiison on wheie in memoiy an oLject sits, Lut it actually
looks into its contents. hisLastName anu herLastName aie two sepaiate vaiiaLles, anu
they will sit in two uilleient places in the memoiy. Oui set, howevei, manageu to
unueistanu that we aie passing instances ol NSString to it anu uiu a compaiison on the
contcnts ol these stiings to linu out that we hau alieauy auueu the Kiyosaki last name
to the set. So only one instance enueu up in the set.
Now let`s have a look at constiucting mutaLle sets:
NSMutableSet *setOfNames = [[NSMutableSet alloc] initWithObjects:
hisName,
hisLastName, nil];
[setOfNames addObject:herName];
[setOfNames addObject:herLastName];
1.25 Allocating and Making Use of Sets | 81
www.it-ebooks.info
Ve simply useu the addObject: methou ol NSMutableSet to auu new oLjects to oui set.
You can also use the removeObject: methou to iemove an oLject. Again, iememLei that
the contents ol the oLject mattei, not its memoiy auuiess. So il you want to iemove a
stiing liom the set, simply pass that stiing to the removeObject: methou, even il youi
new stiing is in a uilleient vaiiaLle oi somewheie else in memoiy. As long as the con-
tents ol that stiing/oLject aie the same, you will get the iesults you want:
NSMutableSet *setOfNames = [[NSMutableSet alloc] initWithObjects:
hisName,
hisLastName,
herName,
herLastName, nil];
[setOfNames removeObject:@"Kiyosaki"];
NSLog(@"Set = %@", setOfNames);
Anu the iesults get piinteu to the console winuow:
Set = {(
Kim,
Robert
)}
Il you want to last enumeiate all oLjects in a set, use the enumerateObjectsUsing
Block: methou. The Llock oLject that you pass to this methou shoulu ietuin no value
anu shoulu have two paiameteis:
A |cy oj typc id
Contains the oLject in the set that is Leing cuiiently enumeiateu.
A pointcr to a boo|can va|uc oj typc BOOL
Il you want to stop the enumeiation at any time, simply place a Loolean value ol
type YES into the memoiy auuiess ol this vaiiaLle.
Let`s have a look at an example. Let`s say I want to tiy to linu the stiing Kiyosaki in a
set that I have:
[setOfNames enumerateObjectsUsingBlock:^(__strong id obj, BOOL *stop) {
if ([obj isKindOfClass:[NSString class]]){
NSString *string = (NSString *)obj;
if ([string isEqualToString:@"Kiyosaki"]){
NSLog(@"Found %@ in the set", string);
*stop = YES;
}
}
}];
Il the enumeiation can linu a stiing with the value ol Kiyosaki in the set, we piint a
stiing to the console anu teiminate the enumeiation Ly placing the value ol YES into
the seconu paiametei ol oui enumeiatoi Llock oLject.
82 | Chapter 1: The Basics
www.it-ebooks.info
Theie aie othei hanuy methous loi sets. Use the count methou to get the numLei ol
oLjects cuiiently in a set. You can also use the allObjects methou to get an aiiay ol all
the oLjects in the set. Il you want to extiact an oLject liom the set, with no concein loi
which one, call the anyObject on youi set. This methou will ietuin, as its name implies,
a ianuom oLject in the set, no mattei wheie in the set it is. You will get nil liom this
methou il the set is empty.
1.26 Creating Bundles
Problem
You want to gioup youi iesouices into hieiaichical stiuctuies anu Le aLle to access
those iesouices at iuntime with ease.
Solution
Follow these steps to successlully cieate a Lunule:
1. Cieate a ioot loluei on youi uisk that will latei Lecome youi Lunule. Foi instance,
let`s give this loluei the name Rcsourccs.
2. Unuei the Rcsourccs loluei, cieate thiee moie lolueis nameu |nagcs, \idcos, anu
Sounds.
3. Unuei the thiee aloiementioneu lolueis, place ielateu iesouices. Foi instance,
place one oi moie images in the |nagcs loluei anu one oi moie viueo liles unuei
the \idcos loluei anu so on.
+. Once you aie uone, iename youi Rcsourccs loluei to Rcsourccs.bund|c. Once you
auu this extension to youi loluei name, OS X will ask loi youi conliimation anu a
uialog similai to that shown in Figuie 1-33 will appeai on the scieen. Piess Auu on
the uialog to auu the .bund|c extension to the Rcsourccs loluei.
Iigurc 1-33. Adding a .bund|c cxtcnsion to a jo|dcr nanc in ordcr to turn it into a bund|c
1.26 Creating Bundles | 83
www.it-ebooks.info
Discussion
Bunules aie simple lolueis with a .bund|c extension. They have two main uistinctions
liom iegulai lolueis:
1. Cocoa Touch pioviues an inteilace thiough which you can access Lunules anu
theii iesouices ieally easily.
2. Il a Lunule is auueu to the Navigatoi on the lelthanu siue ol Xcoue, any liles auueu
to oi iemoveu liom the Lunule outsiue Xcoue will, iespectively, appeai in oi uis-
appeai immeuiately liom Xcoue`s navigatoi. In contiast, il you hau auueu a noimal
loluei to Xcoue`s navigatoi anu then went anu ueleteu a lile liom that loluei on
uisk, without using Xcoue`s help, you woulu see that lile maikeu with ieu coloi in
Xcoue iathei than getting ueleteu immeuiately. Bunules can Le veiy uselul, espe-
cially il you want to auu liles to youi lolueis manually using Finuei insteau ol using
Xcoue.
Main Lunules aie llat Lunules, in that all liles insiue the main Lunule will Le stoieu in
one uiiectoiy (its ioot uiiectoiy). Bunules cieateu Ly piogiammeis can have suLuiiec-
toiies. Any Lunule, incluuing the main Lunule, can contain othei Lunules.
Eveiy iOS application comes with at least one Lunule, calleu the main Lunule. The
main Lunule contains youi app`s Linaiy coue anu any othei iesouice you aie using
insiue youi application, such as ietina images, sounus, HTML liles, anu whatnot. The
main Lunule, in othei woius, contains the iesouices that get compileu into youi linal
Linaiy that you will suLmit to the App Stoie oi uistiiLute in youi oiganization. These
iesouices can then Le uynamically loaueu using the NSBundle class`s mainBundle class
methou.
Although you can auu two oi moie Lunules with the same name to one
iOS pioject, it is Lest not to complicate things like that. The ieason this
situation coulu get complicateu is that when we stait loauing iesouices
liom oui Lunules, we will liist neeu to linu oui Lunules Ly theii path.
Il you have two Lunules with the same name, it will Lecome guite uil-
licult to uetect which is which. So as a goou piactice, make suie that
youi Lunules have uilleient names when you auu them to youi Xcoue
piojects.
1.27 Loading Data from the Main Bundle
Problem
You have auueu a iesouice (such as an image) to youi Xcoue pioject anu now, at
iuntime, you woulu like to access that iesouice.
84 | Chapter 1: The Basics
www.it-ebooks.info
Solution
Use the mainBundle class methou ol the NSBundle class in oiuei to ietiieve youi main
Lunule. Once that is uone, use the pathForResource:ofType: methou ol youi main
Lunule to ietiieve the path loi that specilic iesouice. Once the path is uetecteu, ue-
penuing on the type ol iesouice, you can eithei pass the path to youi lile to a class such
as UIImage oi NSData, oi you can manually access the lile using NSFileManager.
It is ieguiieu that you give a unigue name to each iesouice insiue youi
main Lunule. Foi instance, it is not goou piactice to have a lile nameu
Dcjau|t.png in moie than one place insiue youi main Lunule. Dilleient
ways ol loauing a iesouice liom a Lunule coulu then yielu uilleient ie-
sults. As a iesult, make suie you give unigue names to youi liles insiue
any Lunule, iegaiuless ol whethei it is the main Lunule oi a custom
Lunule that you`ve cieateu (see Recipe 1.26).
Discussion
To access the main Lunule, we can use the mainBundle class methou ol the NSBundle
class. Bunules aie all ol type NSBundle anu once you have an instance ol a Lunule, you
can loau iesouices liom that Lunule.
Eveiy app`s main Lunule has a llat hieiaichy on uisk when it is compileu
loi suLmission to App Stoie. That means all the liles that get wiappeu
up in youi app Lunule will Le placeu on the ioot loluei ol the main
Lunule. In othei woius, the main Lunule has only one loluei, the ioot
loluei, anu all liles anu iesouices aie stoieu in that loluei. Even il you
have a loluei on uisk with a lew liles in it anu uiag anu uiop it into
Xcoue, only the liles in that loluei will Le placeu in the main Lunule`s
lile hieiaichy, not the loluei itsell.
Foi instance, let`s say that you have an image calleu A|anSugar.png sitting on youi
uesktop. Simply uiag anu uiop it into Xcoue. At this point, Xcoue will uisplay a uialog
to you, asking you which pioject this lile has to Le auueu to anu whethei you want this
lile to Le copieu ovei to the pioject`s loluei, il neeu Le. This uialog will look similai to
that shown in Figuie 1-3+.
In this uialog, make suie that the Copy items into uestination gioup`s loluei (il neeu-
eu) item is selecteu. This will copy the lile that you uiop into Xcoue to the taiget app`s
loluei. Now, il you uelete the lile on youi uesktop, it won`t get ueleteu liom youi pioject
Lecause youi pioject has its own copy. It`s geneially goou piactice to uo this unless,
loi specilic ieasons, you ueciue not to (anu I`ve expeiienceu many ol these ieasons
mysell). Altei you uiag anu uiop the lile, the lile A|anSugar.png is in the pioject`s main
Lunule anu you can ietiieve its path in this way:
1.27 Loading Data from the Main Bundle | 85
www.it-ebooks.info
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
NSString *alanSugarFilePath =
[[NSBundle mainBundle] pathForResource:@"AlanSugar"
ofType:@"png"];
if ([alanSugarFilePath length] > 0){
UIImage *image = [UIImage imageWithContentsOfFile:alanSugarFilePath];
if (image != nil){
NSLog(@"Successfully loaded the file as an image.");
} else {
NSLog(@"Failed to load the file as an image.");
}
} else {
NSLog(@"Could not find this file in the main bundle.");
}
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Iigurc 1-31. Xcodc as|ing which projcct a ji|c has to bc addcd to
86 | Chapter 1: The Basics
www.it-ebooks.info
The output ol the pathForResource:ofType: methou ol NSBundle will Le eithei a valiu
path oi nil il the specilieu iesouice cannot Le lounu in the taiget Lunule. So altei you
call this methou, it is Lest to check whethei the path coulu actually Le ietiieveu. Il so,
the coue shown passes the path ol the lile to the UIImage class in oiuei to loau the
A|anSugar.png lile into memoiy as an image.
Similaily, il you wanteu to loau the uata ol that lile into memoiy, insteau ol ietiieving
this image as an image oLject, you coulu use the NSData class:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
NSString *alanSugarFilePath =
[[NSBundle mainBundle] pathForResource:@"AlanSugar"
ofType:@"png"];
if ([alanSugarFilePath length] > 0){
NSError *readError = nil;
NSData *dataForFile =
[[NSData alloc] initWithContentsOfFile:alanSugarFilePath
options:NSMappedRead
error:&readError];
if (readError == nil &&
dataForFile != nil){
NSLog(@"Successfully loaded the data.");
} else if (readError == nil &&
dataForFile == nil){
NSLog(@"No data could be loaded.");
} else {
NSLog(@"An error occured while loading data. Error = %@", readError);
}
} else {
NSLog(@"Could not find this file in the main bundle.");
}
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
See Also
Recipe 1.26
1.27 Loading Data from the Main Bundle | 87
www.it-ebooks.info
1.28 Loading Data from Other Bundles
Problem
You have incluueu a lew images oi othei iesouices in a sepaiate Lunule insiue youi
main Lunule anu you woulu like to access those iesouices at iuntime.
Solution
Finu the path to youi Lunule at iuntime using the pathForResource:ofType: methou ol
youi main Lunule. Once you have the path to youi Lunule, simply access it using the
bundleWithPath: class methou ol NSBundle.
Beloie continuing with this iecipe, please lollow the instiuctions in
Recipe 1.26 to cieate a Lunule calleu Rcsourccs.bund|c anu place it insiue
youi main Lunule.
Discussion
Il you have lolloweu the instiuctions in Recipe 1.26, you now have a Lunule calleu
Rcsourccs.bund|c insiue this Lunule you have a loluei calleu |nagcs. Let`s now put an
image insiue this loluei. Altei I placeu an image calleu A|anSugar.png into the Lunule,
Figuie 1-35 shows what the Lunule contains.
Iigurc 1-35. P|acing an inagc insidc thc bund|c which wc crcatcd bcjorc
88 | Chapter 1: The Basics
www.it-ebooks.info
Since the Rcsourccs.bund|c is auueu to oui app`s main Lunule, we will neeu to use the
main Lunule in oiuei to linu the path to oui Rcsourccs.bund|c. Once that is uone, we
can uiiectly access the liles (only A|anSugar.png iight now) insiue this Lunule. Since
Lunules othei than the main Lunule can have lolueis emLeuueu insiue them, to access
liles insiue lolueis ol a Lunule othei than the main Lunule it is Lest to use the pathFor
Resource:ofType:inDirectory: methou ol NSBundle to explicitly specily the loluei in
which a specilic lile/iesouice exists.
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
NSString *resourcesBundlePath =
[[NSBundle mainBundle] pathForResource:@"Resources"
ofType:@"bundle"];
if ([resourcesBundlePath length] > 0){
NSBundle *resourcesBundle = [NSBundle bundleWithPath:resourcesBundlePath];
if (resourcesBundle != nil){
NSString *pathToAlanSugarImage =
[resourcesBundle pathForResource:@"AlanSugar"
ofType:@"png"
inDirectory:@"Images"];
if ([pathToAlanSugarImage length] > 0){
UIImage *image = [UIImage imageWithContentsOfFile:pathToAlanSugarImage];
if (image != nil){
NSLog(@"Successfully loaded the image from the bundle.");
} else {
NSLog(@"Failed to load the image.");
}
} else {
NSLog(@"Failed to find the file inside the bundle.");
}
} else {
NSLog(@"Failed to load the bundle.");
}
} else {
NSLog(@"Could not find the bundle.");
}
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
1.28 Loading Data from Other Bundles | 89
www.it-ebooks.info
return YES;
}
Il you aie attempting to linu all the iesouices which aie stoieu in a specilic loluei insiue
a Lunule, you can use the pathsForResourcesOfType:inDirectory: methou ol the
NSBundle class. In this coue, we will attempt to linu the path to all the .png liles insiue
the |nagcs loluei ol oui Rcsourccs.bund|c Lunule:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
NSString *resourcesBundlePath =
[[NSBundle mainBundle] pathForResource:@"Resources"
ofType:@"bundle"];
if ([resourcesBundlePath length] > 0){
NSBundle *resourcesBundle = [NSBundle bundleWithPath:resourcesBundlePath];
if (resourcesBundle != nil){
NSArray *PNGPaths = [resourcesBundle pathsForResourcesOfType:@"png"
inDirectory:@"images"];
[PNGPaths
enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(@"Path %lu = %@", (unsigned long)idx+1, obj);
}];
} else {
NSLog(@"Failed to load the bundle.");
}
} else {
NSLog(@"Could not find the bundle.");
}
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
the enumerateObjectsUsingBlock: methou ol NSArray accepts a Llock
oLject as its paiametei. Foi moie inloimation aLout enumer
ateObjectsUsingBlock: anu the Llock oLject it accepts, please ielei to
Recipe 1.25.
90 | Chapter 1: The Basics
www.it-ebooks.info
See Also
Recipe 1.25; Recipe 1.26
1.29 Sending Notifications with NSNotificationCenter
Problem
You want to Lioaucast an event in youi app anu allow any oLject that is willing to listen
to it to take action, uepenuing on the notilication that you aie Lioaucasting.
Solution
Use the postNotificationName:object:userInfo: methou ol the uelault notilication
centei ol type NSNotificationCenter to post a notilication that caiiies an oLject (usually
the oLject that liies the notilication) anu a usei-inlo uictionaiy that can caiiy extia
inloimation aLout the notilication anu/oi the oLject that liies the notilication.
Discussion
Notijication ccntcrs aie uispatch centials loi notijication objccts. Foi instance, when the
keyLoaiu pops up anywheie while the usei is insiue youi app, iOS will senu a notili-
cation to youi app. Any oLject insiue youi app willing to listen to this notilication can
auu itsell to the uelault notilication centei as an obscrvcr loi that paiticulai notilication.
Once youi oLject`s liletime comes to an enu, it must iemove itsell liom the notilication
centei`s uispatch taLle. As a iesult, a notilication is a message that gets Lioaucasteu to
oLseiveis thiough a notilication centei. A notilication centei is an instance ol
NSNotificationCenter class. Ve ietiieve the uelault notilication centei oLject using the
defaultCenter class methou ol NSNotificationCenter.
Notilications aie oLjects ol type NSNotification. A notilication oLject has a name
(specilieu as NSString) anu can caiiy two key pieces ol inloimation:
You can specily the name ol youi notilications youisell. You uon`t have
to use an API loi that. ]ust make suie that youi notilication names aie
unigue enough that they won`t clash with a system notilication.
Scndcr Objcct
This is the instance ol the oLject that liies the notilication. The oLseivei can access
this oLject using the object instance methou ol the NSNotification class.
Uscr-|njo Dictionary
This is an optional uictionaiy that the senuei oLject can cieate anu senu alongsiue
a notilication oLject. This uictionaiy usually contains moie inloimation aLout the
notilication. Foi instance, when a keyLoaiu is aLout to get uisplayeu in iOS loi any
1.29 Sending Notifications with NSNotificationCenter | 91
www.it-ebooks.info
component insiue youi app, iOS senus the UIKeyboardWillShowNotification noti-
lication to the uelault notilication centei. The usei-inlo uictionaiy ol this notili-
cation contains values such as the iectangle ol the keyLoaiu Leloie anu altei
animation anu the animation uuiation ol the keyLoaiu. Using this uata, an oLseivei
can make a uecision as to, loi instance, what to uo with UI components that po-
tentially will Le oLstiucteu once the keyLoaiu gets uisplayeu on the scieen.
Notilications aie a gieat way ol implementing uecoupleu coue. By that
I mean, using notilications, you can get iiu ol completion hanuleis anu
uelegation. Howevei, theie is one potential caveat aLout notilications:
they aie not ueliveieu immeuiately. They aie uispatcheu Ly notilication
centeis, anu the implementation ol NSNotificationCenter is hiuuen
liom application piogiammeis. Deliveiy might sometimes Le uelayeu
Ly a lew milliseconus oi, in extieme cases (which I have nevei encoun-
teieu), a lew seconus. As a iesult, it is up to you to ueciue wheie to anu
wheie not to use notilications.
In oiuei to constiuct a notilication ol type NSNotification, use the notificationWith
Name:object:userInfo: class methou ol the NSNotificationClass, as we will soon see.
It is Lest to sullix youi notilication names with the woiu Notification.
Foi instance, it is peimitteu to give youi notilication a name similai to
ResultOfAppendingTwoStrings. Howevei, it is Lettei to give the name
ResultOfAppendingTwoStringsNotification, as that cleaily says what
this name Lelongs to.
Let`s have a look at an example. Ve`ll simply take a liist name anu a last name, appenu
them to cieate one stiing (liist name - last name) anu then Lioaucast the iesult using
the uelault notilication centei. Ve will uo that in the implementation ol oui app uel-
egate as soon as the usei launches oui app:
#import "AppDelegate.h"
@implementation AppDelegate
/* The notification name */
const NSString *ResultOfAppendingTwoStringsNotification =
@"ResultOfAppendingTwoStringsNotification";
/* Keys inside the dictionary that our notification sends */
const NSString
*ResultOfAppendingTwoStringsFirstStringInfoKey = @"firstString";
const NSString
*ResultOfAppendingTwoStringsSecondStringInfoKey = @"secondString";
const NSString
*ResultOfAppendingTwoStringsResultStringInfoKey = @"resultString";
92 | Chapter 1: The Basics
www.it-ebooks.info
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
NSString *firstName = @"Anthony";
NSString *lastName = @"Robbins";
NSString *fullName = [firstName stringByAppendingString:lastName];
NSArray *objects = [[NSArray alloc] initWithObjects:
firstName,
lastName,
fullName,
nil];
NSArray *keys = [[NSArray alloc] initWithObjects:
ResultOfAppendingTwoStringsFirstStringInfoKey,
ResultOfAppendingTwoStringsSecondStringInfoKey,
ResultOfAppendingTwoStringsResultStringInfoKey,
nil];
NSDictionary *userInfo = [[NSDictionary alloc] initWithObjects:objects
forKeys:keys];
NSNotification *notificationObject =
[NSNotification
notificationWithName:(NSString *)ResultOfAppendingTwoStringsNotification
object:self
userInfo:userInfo];
[[NSNotificationCenter defaultCenter] postNotification:notificationObject];
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Ol couise, you uon`t have to specily an oLject oi a usei-inlo uictionaiy loi eveiy noti-
lication that you wish to Lioaucast. Howevei, il you aie woiking with a team ol ue-
velopeis on the same app oi il you aie wiiting a static liLiaiy, I suggest that you lully
uocument youi notilications anu cleaily mention whethei youi notilications caiiy an
oLject anu/oi an usei-inlo uictionaiy with them. Il they uo, you must say what oLject
each notilication caiiies anu what keys anu values aie insiue the usei-inlo uictionaiy.
Il you aie planning on not senuing an oLject oi a usei-inlo uictionaiy, then I suggest
you use the postNotificationName:object: instance methou ol NSBundle. Specily a
stiing that iepiesents the name ol youi notilication as the liist paiametei, anu nil as
the seconu paiametei, which is the oLject that shoulu Le caiiieu with the notilication.
Heie is an example:
#import "AppDelegate.h"
@implementation AppDelegate
1.29 Sending Notifications with NSNotificationCenter | 93
www.it-ebooks.info
/* The notification name */
const NSString *NetworkConnectivityWasFoundNotification =
@"NetworkConnectivityWasFoundNotification";
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
[[NSNotificationCenter defaultCenter]
postNotificationName:(NSString *)NetworkConnectivityWasFoundNotification
object:nil];
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
1.30 Listening for Notifications Sent from
NSNotificationCenter
Problem
You want to listen loi uilleient system anu custom notilications Lioaucast using
NSNotificationCenter.
Solution
Auu youi oLseivei oLject to the notilication centei using the addObserver:selec
tor:name:object: instance methou ol NSNotificationCenter Leloie a notilication is
Lioaucast. To stop oLseiving a notilication, use the removeObserver:name:object: in-
stance methou ol NSNotificationCenter anu pass youi oLseivei oLject, then the name
ol the notilication that you want to stop oLseiving anu the oLject that you oiiginally
suLsciiLeu to (this will Le explaineu in uetail in the Discussion section ol this iecipe).
Discussion
Any oLject can Lioaucast a notilication anu any oLject within the same app can opt
into listening loi notilications with specilic names. Two notilications with the same
name can Le Lioaucast, Lut they must come liom two uilleient oLjects. Foi instance,
you can have a notilication with the name ol DOWNLOAD_COMPLETED that gets liieu liom
two classes, one Leing a uownloau managei that uownloaus images liom the Inteinet
anu anothei Leing a uownloau managei that uownloaus uata liom an accessoiy con-
necteu to the iOS uevice. An oLseivei might Le inteiesteu only in the notilications ol
this name coming liom a specilic oLject; loi instance, the uownloau managei that
uownloaus uata liom the accessoiy. You can specily this souice oLject (Lioaucastei)
94 | Chapter 1: The Basics
www.it-ebooks.info
when you stait listening loi notilications, using the object paiametei ol the
addObserver:selector:name:object: methou ol the notilication centei.
Heie is a Liiel uesciiption ol each ol the paiameteis that the addObserver:selec
tor:name:object: accepts:
addObserver
The oLject that will ieceive the notilications (oLseivei).
selector
The selectoi (methou) to Le calleu on the oLseivei when the notilication is Lioau-
casteu anu ieceiveu Ly the oLseivei. This methou takes a single aigument ol type
NSNotification.
name
The name ol the notilication to oLseive.
object
Optionally specilies the souice ol the Lioaucast notilication. Il this paiametei is
nil, notilications ol the specilieu name will Le ieceiveu Ly the oLseivei iegaiuless
ol which oLject Lioaucasts them. Il this paiametei is set, only the notilications ol
the specilieu name that aie Lioaucast Ly the given oLject will Le oLseiveu.
In Recipe 1.29 we leaineu how to post notilications. Let`s now tiy oLseiving the noti-
lication that we leaineu to post theie:
#import "AppDelegate.h"
@implementation AppDelegate
/* The notification name */
const NSString *ResultOfAppendingTwoStringsNotification =
@"ResultOfAppendingTwoStringsNotification";
/* Keys inside the dictionary that our notification sends */
const NSString
*ResultOfAppendingTwoStringsFirstStringInfoKey = @"firstString";
const NSString
*ResultOfAppendingTwoStringsSecondStringInfoKey = @"secondString";
const NSString
*ResultOfAppendingTwoStringsResultStringInfoKey = @"resultString";
- (void) broadcastNotification{
NSString *firstName = @"Anthony";
NSString *lastName = @"Robbins";
NSString *fullName = [firstName stringByAppendingString:lastName];
NSArray *objects = [[NSArray alloc] initWithObjects:
firstName,
lastName,
fullName,
1.30 Listening for Notifications Sent from NSNotificationCenter | 95
www.it-ebooks.info
nil]; NSArray *keys = [[NSArray alloc] initWithObjects:
ResultOfAppendingTwoStringsFirstStringInfoKey,
ResultOfAppendingTwoStringsSecondStringInfoKey,
ResultOfAppendingTwoStringsResultStringInfoKey,
nil];
NSDictionary *userInfo = [[NSDictionary alloc] initWithObjects:objects
forKeys:keys];
NSNotification *notificationObject =
[NSNotification
notificationWithName:(NSString *)ResultOfAppendingTwoStringsNotification
object:self
userInfo:userInfo];
[[NSNotificationCenter defaultCenter] postNotification:notificationObject];
}
- (void) appendingIsFinished:(NSNotification *)paramNotification{
NSLog(@"Notification is received.");
NSLog(@"Notification Object = %@", [paramNotification object]);
NSLog(@"Notification User-Info Dict = %@", [paramNotification userInfo]);
}
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
/* Listen for the notification */
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(appendingIsFinished:)
name:(NSString *)ResultOfAppendingTwoStringsNotification
object:self];
[self broadcastNotification];
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillTerminate:(UIApplication *)application{
/* We no longer observe ANY notifications */
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
Vhen you iun this app, you will see something similai to the lollowing piinteu to the
console winuow:
96 | Chapter 1: The Basics
www.it-ebooks.info
Notification is received.
Notification Object = <AppDelegate: 0x7408490>
Notification User-Info Dict = {
firstString = Anthony;
resultString = AnthonyRobbins;
secondString = Robbins;
}
As you can see, we aie using the removeObserver: methou ol oui notilication centei to
iemove oui oLject as an oLseivei ol all notilications. Theie aie uilleient ways ol ie-
moving youi oLjects liom the chain ol oLseiveis. Eithei you can guit colu-tuikey, as
we have uone heiethat is, iemove youi oLject completely liom oLseiving any noti-
licationoi you can iemove youi oLject liom oLseiving specilic notilications at any
time uuiing the liletime ol youi application. Il you want to specily the notilications
you aie iemoving youi oLject liom oLseiving, simply call the removeObserver:
name:object: methou ol youi notilication centei anu specily the name ol the notilica-
tion liom which you aie unsuLsciiLing, as well as (optionally) the oLject that was
senuing the notilications.
See Also
Recipe 1.29
1.30 Listening for Notifications Sent from NSNotificationCenter | 97
www.it-ebooks.info
www.it-ebooks.info
CHAPTER 2
Implementing Controllers and Views
2.0 Introduction
All iOS applications essentially use the Mouel-View-Contiollei, oi MVC aichitectuie.
Mouel, view, anu contiollei aie the thiee main components ol an iOS application liom
an aichitectuial peispective.
The mouel is the Liain ol the application. It uoes the calculations anu cieates a viitual
woilu loi itsell that can live without the views anu contiolleis. In othei woius, think
ol a mouel as a viitual copy ol youi application, without a lace!
A view is the winuow thiough which youi useis inteiact with youi application. It uis-
plays what`s insiue the mouel most ol the time, Lut in auuition to that, it accepts useis`
inteiactions. Any inteiaction Letween the usei anu youi application is sent to a view,
which then can Le captuieu Ly a view contiollei anu sent to the mouel.
Contiolleis in iOS piogiamming usually ielei to vicw contro||crs. Think ol view con-
tiolleis as a Liiuge Letween the mouel anu youi views. They inteipiet what is happening
on one siue (what the usei uoes on the view siue, oi the inloimation pioviueu Ly the
mouel) anu use that inloimation to altei the othei siue as neeueu.
In this chaptei, you will leain how the stiuctuie ol an iOS application is cieateu anu
how to use views anu view contiolleis to cieate intuitive applications.
In this chaptei, loi most ol the UI (Usei Inteilace) components that we
cieate, we aie using a Single View Application template in Xcoue. To
iepiouuce the examples, lollow the instiuctions in Recipe 1.1 Lut in-
steau ol a Page-Baseu Application, cieate a Single View Application.
Make suie that youi app is Univeisal, as opposeu to an iPhone oi iPau
app. A Univeisal app can iun on Loth iPhone anu iPau.
99
www.it-ebooks.info
2.1 Displaying Alerts with UIAlertView
Problem
You want to uisplay a message to youi useis in the loim ol an aleit. This coulu Le useu
to ask them to conliim an action, ask loi theii useiname anu passwoiu, oi simply let
them entei some simple text that you can use in youi app.
Solution
Utilize UIAlertView.
Discussion
Il you aie an iOS usei, you have most ceitainly alieauy seen an aleit view. Figuie 2-1
uepicts an example.
Iigurc 2-1. An a|crt vicw tc||ing thc uscr that shc nccds an activc |ntcrnct conncction
The Lest way to initialize an aleit view is, ol couise, Ly using its uesignateu initializei:
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle:@"Title"
message:@"Message"
delegate:nil
cancelButtonTitle:@"Cancel"
otherButtonTitles:@"Ok", nil];
[alertView show];
Vhen this aleit view is uisplayeu to the usei, she will see something similai to that
shown in Figuie 2-2:
100 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
Iigurc 2-2. A sinp|c a|crt vicw disp|aycd to thc uscr
In oiuei to uisplay an aleit view to the usei, we use the aleit view`s show methou. Let`s
have a look at the uesciiption loi each ol the paiameteis that we passeu to the initializei
ol the aleit view:
title
The stiing that the aleit view will uisplay on the top when it is shown to the usei.
This stiing is Title in Figuie 2-2.
message
The actual message that gets uisplayeu to the usei. In Figuie 2-2, this message is
set to Message.
delegate
The optional uelegate oLject that we pass to the aleit view. This oLject will then
get notilieu whenevei the aleit`s state changes; loi instance, when the usei taps on
a Lutton on the aleit view. The oLject passeu to this paiametei must conloim to
the UIAlertViewDelegate piotocol.
cancelButtonTitle
A stiing that will get assigneu to the cancel Lutton on an aleit view. An aleit view
that has a cancel Lutton usually asks the usei loi an action. Il the usei isn`t com-
loitaLle with peiloiming that action, he oi she will piess the cancel Lutton. This
Lutton`s title uoes not necessaiily have to say Cancel. It is up to you to specily a
title loi this Lutton. This paiametei is optional.
otherButtonTitles
Titles ol any othei Luttons that you want to have appeai on the aleit view. Sepaiate
the titles with commas anu make suie you teiminate the list ol titles with a nil,
which is calleu a scntinc|. This paiametei is optional.
2.1 Displaying Alerts with UIAlertView | 101
www.it-ebooks.info
It is possiLle to cieate an aleit view without any Luttons. An aleit view
without a Lutton cannot Le uismisseu Ly the usei. Il you cieate such a
view, you, as the piogiammei, neeu to make suie this aleit view will get
uismisseu automatically; loi instance, thiee seconus altei it is uisplayeu.
An aleit view without any Luttons that uoes not uismiss itsell automat-
ically gives a ieally pooi usei expeiience. Not only will youi app get low
iatings on the App Stoie loi Llocking the UI liom usei access, Lut chan-
ces aie that youi app will get iejecteu Ly Apple.
Aleit views can take vaiious styles. The UIAlertView class has a piopeity calleu alert
ViewStyle ol type UIAlertViewStyle:
typedef enum {
UIAlertViewStyleDefault = 0,
UIAlertViewStyleSecureTextInput,
UIAlertViewStylePlainTextInput,
UIAlertViewStyleLoginAndPasswordInput
} UIAlertViewStyle;
Heie is what each ol these styles will uo:
UIAlertViewStyleDefault
This is the uelault style ol an aleit view, as we saw in Figuie 2-2.
UIAlertViewStyleSecureTextInput
Vith this style, the aleit view will contain a secuie text lielu, which hiues the actual
chaiacteis typeu Ly the usei. Foi instance, il you aie asking the usei loi hei online
Lanking cieuentials, you might choose this style ol aleit view.
UIAlertViewStylePlainTextInput
Unuei this style, the aleit view will uisplay a non-secuie text lielu to the usei. This
style is gieat il you simply want to ask the usei loi plain-text entiy, such as hei
phone numLei.
UIAlertViewStyleLoginAndPasswordInput
Vith this style, the aleit view will uisplay two text lielus: a non-secuie one loi a
useiname anu a secuie one loi a passwoiu.
Il you neeu to get notilieu when the usei inteiacts with the aleit view, specily a uelegate
oLject to youi aleit view. This uelegate must conloim to the UIAlertViewDelegate pio-
tocol. The most impoitant methou uelineu in this piotocol is the alertView:clicked
ButtonAtIndex: methou, which gets calleu as soon as the usei taps on one ol the Luttons
in the aleit view. The Lutton inuex is passeu to you thiough the clicked
ButtonAtIndex paiametei.
As an example, let`s uisplay an aleit view to the usei anu ask whethei she woulu like
to visit a weLsite in Salaii altei having piesseu a link to that weLsite availaLle in oui
UI. Ve will uisplay two Luttons on oui aleit view: Yes anu No. In oui aleit view uel-
egate, we will uetect which Lutton she tappeu on anu will take action accoiuingly.
Let`s liist implement two veiy simple methous that ietuin the title ol oui two Luttons:
102 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
- (NSString *) yesButtonTitle{
return @"Yes";
}
- (NSString *) noButtonTitle{
return @"No";
}
Now we neeu to make suie that we aie conloiming to the UIAlertViewDelegate piotocol
in oui view contiollei:
#import <UIKit/UIKit.h>
@interface Displaying_Alerts_with_UIAlertViewViewController
: UIViewController <UIAlertViewDelegate>
@end
The next step is to cieate anu uisplay oui aleit view to the usei:
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
self.view.backgroundColor = [UIColor whiteColor];
NSString *message = @"Are you sure you want to open this link in Safari?";
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle:@"Open Link"
message:message
delegate:self
cancelButtonTitle:[self noButtonTitle]
otherButtonTitles:[self yesButtonTitle], nil];
[alertView show];
}
So now, oui aleit view will look similai to that shown in Figuie 2-3.
Now we neeu a way to know whethei the usei selecteu the Yes oi the No option in oui
aleit view. Foi this, we will neeu to implement the alertView:clickedButtonAtIndex:
methou ol oui aleit view uelegate:
- (void) alertView:(UIAlertView *)alertView
clickedButtonAtIndex:(NSInteger)buttonIndex{
NSString *buttonTitle = [alertView buttonTitleAtIndex:buttonIndex];
if ([buttonTitle isEqualToString:[self yesButtonTitle]]){
NSLog(@"User pressed the Yes button.");
}
else if ([buttonTitle isEqualToString:[self noButtonTitle]]){
NSLog(@"User pressed the No button.");
}
}
2.1 Displaying Alerts with UIAlertView | 103
www.it-ebooks.info
Please Leai in minu that in Lig piojects wheie multiple uevelopeis woik
on the same souice coue, it is usually easiei to compaie the titles ol
Luttons ol aleit views to iespective stiings, iathei than picking which
Lutton the usei selecteu on an aleit view Laseu on the inuex ol that
Lutton. Foi the inuex solution to woik, the piogiammei has to linu out
the coue that constiucteu the aleit view anu, Laseu on the coue, linu
out which Lutton has what inuex. Vheieas, in oui solution, any uevel-
opei, even without any knowleuge as to how the aleit view was con-
stiucteu, can tell which il statement uoes what.
As you can see, we aie using the buttonTitleAtIndex: methou ol UIAlertView. Ve pass
the zeio-Laseu inuex ol a Lutton insiue that aleit view to this methou anu will get the
stiing that iepiesents the title ol that Lutton, il any. Using this methou, we can uetei-
mine which Lutton the usei has tappeu on. The inuex ol that Lutton will Le passeu to
us as the buttonIndex paiametei ol the alertView:clickedButtonAtIndex: methou, Lut
il you neeu the title ol that Lutton, you will then neeu to use the buttonTitleAtIndex:
methou ol UIAlertView. That is it; joL uone!
You can also use an aleit view loi text entiy, such as to ask the usei loi his cieuit caiu
numLei oi auuiess. Foi this, as mentioneu Leloie, we neeu to use the UIAlert
ViewStylePlainTextInput aleit view style. Heie is an example:
- (void) viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle:@"Credit Card Number"
message:@"Please enter your credit card number:"
delegate:self
Iigurc 2-3. An a|crt vicw with Ycs and No buttons
104 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
cancelButtonTitle:@"Cancel"
otherButtonTitles:@"Ok", nil];
[alertView setAlertViewStyle:UIAlertViewStylePlainTextInput];
/* Display a numerical keypad for this text field */
UITextField *textField = [alertView textFieldAtIndex:0];
textField.keyboardType = UIKeyboardTypeNumberPad;
[alertView show];
}
Il we iun oui app on the simulatoi now, we will get a iesult similai to Figuie 2-+.
Iigurc 2-1. An a|crt vicw with p|ain tcxt input
Ve uiu change the aleit view`s style to UIAlertViewStylePlainTextInput in this coue,
Lut we uiu something else as well. Ve ietiieveu the ieleience to the liist anu the only
text lielu that we knew we woulu have on the aleit view, anu useu that text lielu`s
ieleience to change the keyLoaiu type ol the text lielu. Foi moie inloimation aLout
text lielus, please ielei to Recipe 2.19.
In auuition to a plain text entiy, you can ask the usei loi secuie text. You woulu noi-
mally use this il the text that the usei is enteiing is sensitive, such as a passwoiu (see
Figuie 2-5). Heie is an example:
- (void) viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle:@"Password"
message:@"Please enter your password:"
delegate:self
cancelButtonTitle:@"Cancel"
otherButtonTitles:@"Ok", nil];
2.1 Displaying Alerts with UIAlertView | 105
www.it-ebooks.info
[alertView setAlertViewStyle:UIAlertViewStyleSecureTextInput];
[alertView show];
}
Iigurc 2-5. Sccurc tcxt cntry in an a|crt vicw
Anu as you can see, the style we`ve chosen is UIAlertViewStyleSecureTextInput. This
style is veiy similai to the UIAlertViewStylePlainTextInput style, except that the text
lielu is set to suLstitute some neutial chaiactei loi each chaiactei ol the enteieu text.
The next style, which is guite uselul, uisplays two text lielus, one loi a useiname anu
the othei loi a passwoiu. The liist is a plain text entiy lielu anu the othei one is secuie:
- (void) viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle:@"Password"
message:@"Please enter your credentials:"
delegate:self
cancelButtonTitle:@"Cancel"
otherButtonTitles:@"Ok", nil];
[alertView setAlertViewStyle:UIAlertViewStyleLoginAndPasswordInput];
[alertView show];
}
The iesults will look similai to that shown in Figuie 2-6.
106 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
Iigurc 2-. Login and password sty|c oj a|crt vicw
See Also
Recipe 2.19
2.2 Creating and Using Switches with UISwitch
Problem
You woulu like to give youi useis the aLility to tuin an option on oi oll.
Solution
Use the UISwitch class.
Discussion
The UISwitch class pioviues an On/Oll contiol like the one shown in Figuie 2-7 loi
Auto-Capitalization, Auto-Coiiection, anu so on.
2.2 Creating and Using Switches with UISwitch | 107
www.it-ebooks.info
Iigurc 2-7. U|Switch uscd in thc Scttings app on an iPhonc
In oiuei to cieate a switch, you can eithei use Inteilace Builuei oi simply cieate youi
instance in coue. Let`s uo it thiough coue. So next the challenge is to ueteimine which
class to place youi coue in. It neeus to Le in a View Contiollei class, which we haven`t
uiscusseu yet, Lut loi the a Single View Application type ol app we`ie cieating in this
chaptei, you can linu the view contiollei`s .h (heauei) lile thiough a name that is Laseu
on the name ol youi pioject anu enus with \icwContro||cr.h. Foi instance, I have nameu
my pioject Creating and Using Switches with UISwitch, so the .h lile ol my view con-
tiollei is calleu Crcating_and_Using_Switchcs_with_U|Switch\icwContro||cr.h. Open
that lile now.
In the latest veision ol Xcoue, cieating a Single View Application pioject
will cieate the heauei anu implementation liles ol a view contiollei
simply nameu ViewContiollei. Theieloie the heauei lile ol youi view
contiollei will Le in the lile nameu \icwContro||cr.h anu the implemen-
tation in a lile nameu \icwContro||cr.n.
Let`s cieate a piopeity ol type UISwitch anu call it mySwitch:
#import <UIKit/UIKit.h>
@interface Creating_and_Using_Switches_with_UISwitchViewController
: UIViewController
@property (nonatomic, strong) UISwitch *mySwitch;
@end
108 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
Ve can go aheau now anu cieate oui switch. Finu the viewDidLoad methou in youi view
contiollei`s implementation lile:
- (void)viewDidLoad{
[super viewDidLoad];
}
Let`s cieate oui switch anu place it on oui view contiollei`s view:
- (void)viewDidLoad{
[super viewDidLoad];
/* Make sure our view is white */
self.view.backgroundColor = [UIColor whiteColor];
/* Create the switch */
self.mySwitch = [[UISwitch alloc] initWithFrame:
CGRectMake(100, 100, 0, 0)];
[self.view addSubview:self.mySwitch];
}
So we aie allocating an oLject ol type UISwitch anu using the initWithFrame: initializei
to initialize oui switch. Note that the paiametei that we have to pass to this methou is
ol type CGRect. A CGRect uenotes the Lounuaiies ol a iectangle using the (x, y) position
ol the top-lelt coinei ol the iectangle anu its wiuth anu height. Ve can constiuct a
CGRect using the CGRectMake inline methou, wheie the liist two paiameteis passeu to
this methou aie the (x, y) positions anu the next two aie the wiuth anu height ol the
iectangle.
Altei we`ve cieateu the switch, we simply auu it to oui view contiollei`s view.
In this example, we aie changing the Lackgiounu coloi ol oui view con-
tiollei`s view to white (as opposeu to the uelault Single View Applica-
tion`s giay Lackgiounu coloi), just to make oui app look nicei.
Now let`s iun oui app on iPhone Simulatoi. Figuie 2-S shows what happens.
As you can see, the switch`s uelault state is oll. Ve can change this Ly changing the
value ol the on piopeity ol the instance ol UISwitch. Alteinatively, you can call the
setOn: methou on the switch, as shown heie:
[self.mySwitch setOn:YES];
Ve can also use the setOn:animated: methou ol the switch. The animated paiametei
accepts a Boolean value. Il this Boolean value is set to YES, the change in the switch`s
state (liom on to oll oi oll to on) will Le animateu, just as il the usei was inteiacting
with it.
2.2 Creating and Using Switches with UISwitch | 109
www.it-ebooks.info
OLviously, you can ieau liom the on piopeity ol the switch to linu out whethei the
switch is on oi oll at the moment. Alteinatively, you can use the isOn methou ol the
switch, as shown heie:
if ([self.mySwitch isOn]){
NSLog(@"The switch is on.");
} else {
NSLog(@"The switch is off.");
}
Il you want to get notilieu whcn the switch gets tuineu on oi oll, you will neeu to auu
youi class as the targct loi the switch, using the addTarget:action:forControlEvents:
methou ol UISwitch, as shown heie:
[self.mySwitch addTarget:self
action:@selector(switchIsChanged:)
forControlEvents:UIControlEventValueChanged];
Then implement the switchIsChanged: methou. Vhen the iuntime calls this methou
loi the UIControlEventValueChanged event ol the switch, it will pass the switch as the
paiametei to this methou, so you can linu out which switch has liieu this event:
- (void) switchIsChanged:(UISwitch *)paramSender{
NSLog(@"Sender is = %@", paramSender);
if ([paramSender isOn]){
NSLog(@"The switch is turned on.");
} else {
NSLog(@"The switch is turned off.");
}
}
Iigurc 2-8. A switch p|accd on a vicw
110 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
Now go aheau anu iun the app on iOS Simulatoi. You will see messages similai to this
in the console winuow:
Sender is = <UISwitch: 0x6e13500;
frame = (100 100; 79 27);
layer = <CALayer: 0x6e13700>>
The switch is turned off.
Sender is = <UISwitch: 0x6e13500;
frame = (100 100; 79 27);
layer = <CALayer: 0x6e13700>>
The switch is turned on.
2.3 Customizing the UISwitch
Problem
You have placeu UISwitch instances on youi UI anu woulu now like to customize them
to match youi UI.
Solution
Simply use one ol the tint/image customization piopeities ol the UISwitch such as the
tintColor oi the onTintColor.
Discussion
In Loth iOS 5 anu iOS 6 SDKs, Apple has uone a lantastic joL ol Liinging customization
to UI components such as the UISwitch. In pievious SDKs, uevelopeis weie going as
lai as suLclassing UISwitch just to change its appeaiance anu coloi. Now, iOS 6 SDK
makes this much simplei.
Theie aie two main ways ol customizing a switch:
Tint Co|ors
Tint colois aie colois that you can apply to a UI component such as a UISwitch.
The tint coloi will Le applieu on top ol the cuiient coloi ol the component. Foi
instance, in a noimal UISwitch, you will Le aLle to see uilleient colois. Vhen you
apply the tint coloi on top, the noimal coloi ol the contiol will Le mixeu with the
tint coloi, giving a j|avor ol the tint coloi on the UI contiol.
|nagcs
A switch has two images:
On |nagc
The image that iepiesents the on state ol the switch. The wiuth ol this image
is 77 points anu its height is 22.
Ojj |nagc
The image that iepiesents the switch in its ojj state. This image, like the on
state ol the switch, is 77 points in wiuth anu 22 points in height.
2.3 Customizing the UISwitch | 111
www.it-ebooks.info
Figuie 2-9 shows an example ol the on anu oll image ol a switch.
Iigurc 2-9. Thc on and ojj inagcs on a U|Switch
Now that we know the two states (on anu oll) ol a switch, let`s get staiteu Ly leaining
how we can change the tint coloi ol the switch UI component. This can Le achieveu
Ly the use ol thiee impoitant piopeities ol the UISwitch class:
tintColor
This is the tint coloi that will Le applieu to the oll state ol the switch. Unloitunately,
Apple has not taken the time to name this piopeity offTintColor insteau ol tint
Color to make it moie explicit. This piopeity is ol type UIColor.
thumbTintColor
This is the tint coloi that will Le applieu to the little knoL on the switch. This
piopeity is ol type UIColor.
onTintColor
This tint coloi will Le applieu to the switch in its on state. This piopeity is ol type
UIColor as well.
112 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
Heie is a simple coue snippet that will change the on-moue tint coloi ol the switch to
ieu, the oll-moue tint coloi to Liown, anu the knoL`s tint coloi to gieen. It is not the
Lest comLination ol colois, Lut will uemonstiate what this iecipe is tiying to explain:
- (CGRect) roundedValuesInRect:(CGRect)paramRect{
paramRect.origin.x = round(CGRectGetMinX(paramRect));
paramRect.origin.y = round(CGRectGetMinY(paramRect));
paramRect.size.width = round(CGRectGetWidth(paramRect));
paramRect.size.height = round(CGRectGetHeight(paramRect));
return paramRect;
}
- (void)viewDidLoad
{
[super viewDidLoad];
/* Create the switch */
self.view.backgroundColor = [UIColor whiteColor];
self.mainSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
self.mainSwitch.center = self.view.center;
/* Make sure the switch won't appear blurry on iOS Simulator */
self.mainSwitch.frame = [self roundedValuesInRect:self.mainSwitch.frame];
[self.view addSubview:self.mainSwitch];
/* Customize the switch */
/* Adjust the off-mode tint color */
self.mainSwitch.tintColor = [UIColor redColor];
/* Adjust the on-mode tint color */
self.mainSwitch.onTintColor = [UIColor brownColor];
/* Also change the knob's tint color */
self.mainSwitch.thumbTintColor = [UIColor greenColor];
}
In this coue snippet, we have coueu a methou nameu roundedValuesIn
Rect:. The sole puipose ol this methou is to iounu the x, y, wiuth, anu
height ol a given CGRect stiuctuie anu ietuin the iounueu values as a
CGRect. The ieason we aie uoing this is that on iOS Simulatoi, il any ol
the x, y, wiuth, oi height ol youi UI Components aie not iounu, the
contiols may appeai Lluiiy on the scieen. This is just an aitilact ol the
iOS Simulatoi anu uoes not appeai on ieal iOS uevices, so you can coue
without having to woiiy aLout this. But il you ieally want things to look
aLsolutely gieat on the simulatoi, you just neeu to take this into con-
siueiation. Some uevelopeis aie not ieally Lotheieu with this as long as
the iesults aie gieat on the uevice, anu that`s the appioach I also suggest
you take.
Now that we aie uone with the tint colois on a switch, let`s move on to customizing
the appeaiance ol the switch using its on anu oll images. As mentioneu Leloie, Loth
the on anu the oll images in a switch shoulu Le 77 points wiue anu 22 points tall. Foi
2.3 Customizing the UISwitch | 113
www.it-ebooks.info
this, I have piepaieu a new set ol on anu oll images (in Loth noimal anu ietina ieso-
lutions). I have auueu them to my Xcoue pioject unuei the (ietina) names ol
On2x.png anu Ojj2x.png anu I`ve also placeu the non-ietina llavoi ol the same
images in the pioject. Now what we have to uo is to constiuct oui switch Lut assign
oui custom on anu oll images to the switch, using the lollowing piopeities on UISwitch:
onImage
As explaineu Leloie, this will Le the image that is uisplayeu when the switch is in
its on moue.
offImage
The image that iepiesents the switch when it is in oll moue.
Anu heie is oui coue snippet to achieve this new look:
- (void)viewDidLoad
{
[super viewDidLoad];
/* Create the switch */
self.view.backgroundColor = [UIColor whiteColor];
self.mainSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
self.mainSwitch.center = self.view.center;
/* Make sure the switch won't appear blurry on iOS Simulator */
self.mainSwitch.frame = [self roundedValuesInRect:self.mainSwitch.frame];
[self.view addSubview:self.mainSwitch];
/* Customize the switch */
self.mainSwitch.onImage = [UIImage imageNamed:@"On"];
self.mainSwitch.offImage = [UIImage imageNamed:@"Off"];
}
Figuie 2-10 shows how the custom switch will look when it`s in on-moue:
See Also
Recipe 2.2
2.4 Picking Values with UIPickerView
Problem
You want to allow the useis ol youi app to select liom a list ol values.
Solution
Use the UIPickerView class.
114 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
Discussion
A pickei view is a giaphical element that allows you to uisplay seiies ol values to youi
useis anu allow them to pick one. The Timei section ol the Clock app on the iPhone
is a gieat example ol this (Figuie 2-11).
As you can see, this specilic pickei view has two sepaiate anu inuepenuent visual ele-
ments. One is on the lelt anu one is on the iight. The lelt component is uisplaying houis
(such as 0 houis, 1, 2, etc.) anu the component on the iight is uisplaying minutes (such
as 1S, 19, 20 mins, 21, 22, etc.). These two items aie calleu conponcnts. Each compo-
nent has iows. Any item in any ol the components is in lact iepiesenteu Ly a iow, as
we will soon see. Foi instance, in the lelt component, 0 houis is a iow, 1 is a iow,
etc.
Let`s go aheau anu cieate a pickei view on oui view contiollei`s view. Il you uon`t know
wheie youi view contiollei`s souice coue is, please have a look at Recipe 2.2, wheie
this suLject is uiscusseu.
Fiist let`s go to the .h (heauei) lile ol oui view contiollei anu ueline oui pickei view:
#import <UIKit/UIKit.h>
@interface Picking_Values_with_UIPickerViewViewController
: UIViewController
Iigurc 2-10. A U|Switch with a custon on and ojj inagc
2.4 Picking Values with UIPickerView | 115
www.it-ebooks.info
@property (nonatomic, strong) UIPickerView *myPicker;
@end
Now let`s cieate the pickei view in the viewDidLoad methou ol oui view contiollei:
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.myPicker = [[UIPickerView alloc] init];
self.myPicker.center = self.view.center;
[self.view addSubview:self.myPicker];
}
It`s woith noting that in this example, we aie centeiing oui pickei view at the centei ol
oui view so when you iun this app, you will see something similai to that shown in
Figuie 2-12.
Iigurc 2-11. A pic|cr vicw on top oj thc scrccn
116 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
Iigurc 2-12. An unpopu|atcd and cnpty pic|cr with its dcjau|t b|ac| co|or
The ieason this pickei view is showing up as a plain Llack coloi is that we have not yet
populateu it with any values. Let`s uo that. Ve uo that Ly specilying a uata souice loi
the pickei view anu then making suie that oui view contiollei sticks to the piotocol
that the uata souice ieguiies. The uata souice ol an instance ol UIPickerView must
conloim to the UIPickerViewDataSource piotocol, so let`s go aheau anu make oui view
contiollei conloim to this piotocol in the .h lile:
#import <UIKit/UIKit.h>
@interface Picking_Values_with_UIPickerViewViewController
: UIViewController <UIPickerViewDataSource>
@property (nonatomic, strong) UIPickerView *myPicker;
@end
Goou. Let`s now change oui coue in the implementation lile to make suie we select the
cuiient view contiollei as the uata souice ol the pickei view:
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.myPicker = [[UIPickerView alloc] init];
self.myPicker.dataSource = self;
self.myPicker.center = self.view.center;
[self.view addSubview:self.myPicker];
}
2.4 Picking Values with UIPickerView | 117
www.it-ebooks.info
Altei this, il you tiy to compile youi application, you will see that you aie getting
wainings liom the compilei. These wainings aie telling you that you have not yet im-
plementeu some ol the methous that the UIPickerViewDataSource piotocol wants you
to implement. The way to lix this is to go Lack to youi .h (heauei) lile, holu uown the
Commanu key, anu then click on the UIPickerViewDataSource text. That will senu you
to the place in youi coue wheie this piotocol is uelineu, wheie you will see something
similai to this:
@protocol UIPickerViewDataSource<NSObject>
@required
// returns the number of 'columns' to display.
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView;
// returns the # of rows in each component..
- (NSInteger)pickerView:(UIPickerView *)pickerView
numberOfRowsInComponent:(NSInteger)component;
@end
Can you see the @required keywoiu theie? That is telling us that whichevei class wants
to Lecome the uata souice ol a pickei view nust implement these methous. Goou ueal.
Let`s go implement them in oui view contiollei`s implementation lile:
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
NSInteger result = 0;
if ([pickerView isEqual:self.myPicker]){
result = 1;
}
return result;
}
- (NSInteger) pickerView:(UIPickerView *)pickerView
numberOfRowsInComponent:(NSInteger)component{
NSInteger result = 0;
if ([pickerView isEqual:self.myPicker]){
result = 10;
}
return result;
}
So what is happening heie? Let`s have a look at what each one ol these uata souice
methous expects:
numberOfComponentsInPickerView:
This methou passes you a pickei view oLject as its paiametei anu expects you to
ietuin an integei, telling the iuntime how many components you woulu like that
pickei view to ienuei.
118 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
pickerView:numberOfRowsInComponent:
Foi each component that gets auueu to a pickei view, you will neeu to tell the
system aLout the numLei ol iows that you woulu like to ienuei in that component.
This methou passes you an instance ol pickei view anu you will neeu to ietuin an
integei to it, telling the iuntime how many iows you want the system to ienuei loi
that component.
So in this case, we aie asking the system to uisplay 1 component with 10 iows only loi
a pickei view that we have cieateu Leloie, calleu myPicker.
Compile anu iun youi application on the iPhone Simulatoi (Figuie 2-13). Ewww, what
is that?
Iigurc 2-13. A pic|cr vicw, not |nowing what to rcndcr
It looks like oui pickei view knows how many components it shoulu have anu how
many iows it shoulu ienuei in that component Lut uoesn`t know what tcxt to uisplay
loi each iow. That is something we neeu to uo now, anu we uo that Ly pioviuing a
uelegate to the pickei view. The uelegate ol an instance ol UIPickerView has to conloim
to the UIPickerViewDelegate piotocol anu must implement all the @required methous
ol that piotocol. Let`s stait with oui view contiollei`s heauei lile:
@interface Picking_Values_with_UIPickerViewViewController
: UIViewController
<UIPickerViewDataSource, UIPickerViewDelegate>
@property (nonatomic, strong) UIPickerView *myPicker;
@end
Theie is only one methou in the UIPickerViewDelegate we aie inteiesteu in: the picker
View:titleForRow:forComponent: methou. This methou will pass you the inuex ol the
2.4 Picking Values with UIPickerView | 119
www.it-ebooks.info
cuiient section anu the inuex ol the cuiient iow in that section loi a pickei view anu
it expects you to ietuin an instance ol NSString. This stiing will then get ienueieu loi
that specilic iow insiue the component. In heie, I woulu simply like to uisplay the liist
iow as Row 1, anu then continue to Row 2, Row 3, etc., till the enu. RememLei, we
also have to set the delegate piopeity ol oui pickei view:
self.myPicker.delegate = self;
Anu now we will hanule the uelegate methou we just leaineu aLout:
- (NSString *)pickerView:(UIPickerView *)pickerView
titleForRow:(NSInteger)row
forComponent:(NSInteger)component{
NSString *result = nil;
if ([pickerView isEqual:self.myPicker]){
/* Row is zero-based and we want the first row (with index 0)
to be rendered as Row 1 so we have to +1 every row index */
result = [NSString stringWithFormat:@"Row %ld", (long)row + 1];
}
return result;
}
Now let`s iun oui app anu see what happens (Figuie 2-1+).
Iigurc 2-11. A pic|cr vicw with onc scction and a jcw rows
All goou? Il you now ielei Lack to Figuie 2-11, you will notice a hoiizontal Lai iunning
acioss the pickei view. It tuins out that UIPickerView has a piopeity calleu showsSelec
tionIndicator, which Ly uelault is set to NO. You can eithei uiiectly set the value ol this
120 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
piopeity to YES oi use the setShowsSelectionIndicator: methou ol the pickei view to
tuin this inuicatoi on:
self.myPicker.showsSelectionIndicator = YES;
Anu now we will iun oui app in iOS Simulatoi anu see how it looks (Figuie 2-15).
Iigurc 2-15. A pic|cr vicw with sc|cction indicator
Now imagine that you have cieateu this pickei view in youi linal application. Vhat is
the use ol a pickei view il we cannot uetect what the usei has actually selecteu in each
one ol its components? Vell, it`s goou that Apple has alieauy thought ol that anu given
us the aLility to ask the pickei view aLout this. Ve can call the selectedRowInCompo
nent: methou ol a UIPickerView anu pass the zeio-Laseu inuex ol a component to get
an integei Lack, anu this integei will Le the zeio-Laseu inuex ol the iow that is cuiiently
selecteu in that component.
Il at iuntime, you neeu to mouily the values in youi pickei view, you neeu to make suie
that youi pickei view ieloaus its uata liom its uata souice anu uelegate. To uo that, you
can eithei loice all the components to ieloau theii uata, using the reloadAllCompo
nents methou, oi you can ask a specilic component to ieloau its uata, using the reload
Component: methou anu passing the inuex ol the component that has to Le ieloaueu.
See Also
Recipe 2.2
2.4 Picking Values with UIPickerView | 121
www.it-ebooks.info
2.5 Picking the Date and Time with UIDatePicker
Problem
You want to allow the useis ol youi app to select a uate anu time using an intuitive anu
ieauy-maue usei inteilace.
Solution
Use the UIDatePicker class.
Discussion
UIDatePicker is veiy similai to the UIPickerView class. The uate pickei is in lact a pie-
populateu pickei view. A goou example ol the uate pickei contiol is in the Calenuai
app on the iPhone (Figuie 2-16).
Iigurc 2-1. A datc pic|cr shown at thc botton oj thc scrccn
Let`s get staiteu Ly liist ueclaiing a piopeity ol type UIDatePicker anu then allocating
anu initializing this piopeity anu auuing it to the view ol oui view contiollei:
#import <UIKit/UIKit.h>
@interface Picking_Date_and_Time_with_UIDatePickerViewController
: UIViewController
122 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
@property (nonatomic, strong) UIDatePicker *myDatePicker;
@end
Anu now let`s instantiate the uate pickei, as planneu:
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.myDatePicker = [[UIDatePicker alloc] init];
self.myDatePicker.center = self.view.center;
[self.view addSubview:self.myDatePicker];
}
Now let`s iun the app anu see how it looks in Figuie 2-17.
Iigurc 2-17. A sinp|c datc pic|cr
You can see that the uate pickei, Ly uelault, has pickeu touay`s uate. The liist thing
that we neeu to know aLout uate pickeis is that they can have uilleient styles oi moues.
This moue can Le changeu thiough the datePickerMode piopeity, which is ol type
UIDatePickerMode:
typedef enum {
UIDatePickerModeTime,
UIDatePickerModeDate,
UIDatePickerModeDateAndTime,
UIDatePickerModeCountDownTimer,
} UIDatePickerMode;
Depenuing on what you neeu, you can set the moue ol youi uate pickei to any ol the
values listeu in the UIDatePickerMode enumeiation. I`ll show some ol these as we go
along.
2.5 Picking the Date and Time with UIDatePicker | 123
www.it-ebooks.info
Now that you have successlully uisplayeu a uate pickei on the scieen, you can attempt
to ietiieve its cuiiently-selecteu uate using its date piopeity. Alteinatively, you can call
the date methou on the uate pickei, like so:
NSDate *currentDate = self.myDatePicker.date;
NSLog(@"Date = %@", currentDate);
]ust like the UISwitch class, a uate pickei also senus action messages to its taigets
whenevei the selection ol uate in it has changeu. To iesponu to these messages, the
ieceivei must auu itsell as the taiget ol the uate pickei, using the addTarget:action:for
ControlEvents: methou, like so:
- (void) datePickerDateChanged:(UIDatePicker *)paramDatePicker{
if ([paramDatePicker isEqual:self.myDatePicker]){
NSLog(@"Selected date = %@", paramDatePicker.date);
}
}
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.myDatePicker = [[UIDatePicker alloc] init];
self.myDatePicker.center = self.view.center;
[self.view addSubview:self.myDatePicker];
[self.myDatePicker addTarget:self
action:@selector(datePickerDateChanged:)
forControlEvents:UIControlEventValueChanged];
}
Now, eveiy time the usei changes the uate, you will get a message liom the uate pickei.
Vith a uate pickei, you also have the aLility to set the minimum anu the maximum
uates that it can uisplay. Foi this, let`s liist switch oui uate pickei moue to
UIDatePickerModeDate anu then, using the maximumDate anu the minimumDate piopeities,
aujust this iange:
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.myDatePicker = [[UIDatePicker alloc] init];
self.myDatePicker.center = self.view.center;
self.myDatePicker.datePickerMode = UIDatePickerModeDate;
[self.view addSubview:self.myDatePicker];
NSTimeInterval oneYearTime = 365 * 24 * 60 * 60;
NSDate *todayDate = [NSDate date];
NSDate *oneYearFromToday = [todayDate
dateByAddingTimeInterval:oneYearTime];
124 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
NSDate *twoYearsFromToday = [todayDate
dateByAddingTimeInterval:2 * oneYearTime];
self.myDatePicker.minimumDate = oneYearFromToday;
self.myDatePicker.maximumDate = twoYearsFromToday;
}
Vith these two piopeities, we can then limit the usei`s selection on the uate to a specilic
iange, as shown in Figuie 2-1S. In this example coue, we have limiteu the usei`s input
ol uates to the iange ol a yeai to two yeais liom now.
Iigurc 2-18. Mininun and naxinun datcs app|icd to a datc pic|cr
Il you want to use the uate pickei as a countuown timei, you must set youi uate pickei
moue to UIDatePickerModeCountDownTimer anu use the countDownDuration piopeity ol
the uate pickei to specily the uelault countuown uuiation. Foi instance, il you want to
piesent a countuown pickei to the usei anu set the uelault countuown uuiation to two
minutes, you woulu wiite youi coue like this:
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.myDatePicker = [[UIDatePicker alloc] init];
self.myDatePicker.center = self.view.center;
self.myDatePicker.datePickerMode = UIDatePickerModeCountDownTimer;
[self.view addSubview:self.myDatePicker];
NSTimeInterval twoMinutes = 2 * 60;
[self.myDatePicker setCountDownDuration:twoMinutes];
}
The iesults aie shown in Figuie 2-19.
2.5 Picking the Date and Time with UIDatePicker | 125
www.it-ebooks.info
Iigurc 2-19. A two-ninutc countdown duration sct on a datc pic|cr
2.6 Implementing Range Pickers with UISlider
Problem
You woulu like to allow youi useis to specily a value within a iange, using an easy-to-
use anu intuitive UI.
Solution
Use the UISlider class.
Discussion
You`ve ceitainly seen sliueis Leloie. Figuie 2-20 shows an example.
To cieate a sliuei, instantiate an oLject ol type UISlider. Let`s uive iight in anu cieate
a sliuei anu place it on oui view contiollei`s view. Ve`ll stait with oui view contiollei`s
heauei lile:
#import <UIKit/UIKit.h>
@interface Implementing_Range_Pickers_with_UISliderViewController
: UIViewController
@property (nonatomic, strong) UISlider *mySlider;
@end
126 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
Iigurc 2-20. Thc vo|unc s|idcr at thc botton oj thc scrccn
Anu now let`s go to the viewDidLoad methou anu cieate oui sliuei component. In this
coue, we aie going to give oui sliuei a iange Letween 0 to 100 anu set its uelault position
to Le hallway Letween stait anu enu.
The iange ol a sliuei has nothing to uo with its appeaiance. Ve use the
iange specilieis ol a sliuei to tell the sliuei to calculate its value Laseu
on the ielative position within the iange. Foi instance, il the iange ol a
sliuei is pioviueu as 0 to 100, when the knoL on the sliuei is on the
leltmost pait, the value piopeity ol the sliuei is 0, anu il the knoL is to
the iightmost siue ol the sliuei, the value piopeity woulu Le 100.
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.mySlider = [[UISlider alloc] initWithFrame:CGRectMake(0.0f,
0.0f,
200.0f,
23.0f)];
self.mySlider.center = self.view.center;
self.mySlider.minimumValue = 0.0f;
self.mySlider.maximumValue = 100.0f;
self.mySlider.value = self.mySlider.maximumValue / 2.0;
[self.view addSubview:self.mySlider];
}
2.6 Implementing Range Pickers with UISlider | 127
www.it-ebooks.info
Vhat uo the iesults look like? You can now iun the app on the simulatoi anu you`ll
get iesults like those shown in Figuie 2-21.
Iigurc 2-21. A sinp|c s|idcr at thc ccntcr oj thc scrccn
Ve useu a lew piopeities ol the sliuei to get the iesults we wanteu. Vhat weie they?
minimumValue
Specilies the minimum value ol the iange that the sliuei shoulu suppoit.
maximumValue
Specilies the maximum value that the sliuei shoulu suppoit.
value
The cuiient value ol the sliuei. This is a ieau/wiite piopeity, meaning that you can
Loth ieau liom it anu wiite to it. Il you want the sliuei`s knoL to Le moveu to this
value in an animateu moue, you can call the setValue:animated: methou ol the
sliuei anu pass YES as the animated paiametei.
The little knoL on a sliuei is calleu the thunb. Ve will soon see how we
can customize the sliuei anu I will Le using the teim thunb to uesciiLe
the knoL on the sliuei, so please keep that in minu.
Il you wish to ieceive an event whenevei the sliuei`s thumL has moveu, you must auu
youi oLject as the taiget ol the sliuei, using the sliuei`s addTarget:action:forControl
Events: methou:
- (void) sliderValueChanged:(UISlider *)paramSender{
if ([paramSender isEqual:self.mySlider]){
128 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
NSLog(@"New value = %f", paramSender.value);
}
}- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.mySlider = [[UISlider alloc] initWithFrame:CGRectMake(0.0f,
0.0f,
200.0f,
23.0f)];
self.mySlider.center = self.view.center;
self.mySlider.minimumValue = 0.0f;
self.mySlider.maximumValue = 100.0f;
self.mySlider.value = self.mySlider.maximumValue / 2.0;
[self.view addSubview:self.mySlider];
[self.mySlider addTarget:self
action:@selector(sliderValueChanged:)
forControlEvents:UIControlEventValueChanged];
}
Il you iun the application on the simulatoi now, you will notice that the sliderValue
Changed: taiget methou gets calleu whcncvcr and as soon as the sliuei`s thumL moves.
This might Le what you want, Lut in some cases, you might neeu to get notilieu only
altei the usei has let go ol the thumL on the sliuei anu let it settle. Il you want to wait
to Le notilieu, set the continuous piopeity ol the sliuei to NO. This piopeity, when set
to YES (its uelault value), will call the sliuei`s taigets continuously whi|c the thumL
moves.
The iOS SDK also gives us the aLility to mouily how a sliuei looks. Foi instance, the
thumL on the sliuei can have a uilleient image. To change the image ol the thumL,
simply use the setThumbImage:forState: methou anu pass an image along with a seconu
paiametei that can take any ol these values:
UIControlStateNormal
The noimal state ol the thumL, with no usei lingei on this component.
UIControlStateHighlighted
The image that has to Le uisplayeu loi the thumL while the usei is moving hei
lingei on this component.
I have piepaieu two images: one loi the noimal state ol the thumL anu the othei one
loi the highlighteu (toucheu) state ol the thumL. Let`s go aheau anu auu them to the
sliuei:
[self.mySlider setThumbImage:[UIImage imageNamed:@"ThumbNormal.png"]
forState:UIControlStateNormal];
[self.mySlider setThumbImage:[UIImage imageNamed:@"ThumbHighlighted.png"]
forState:UIControlStateHighlighted];
Anu now let`s have a look anu see how oui noimal thumL image looks in the simulatoi
(Figuie 2-22).
2.6 Implementing Range Pickers with UISlider | 129
www.it-ebooks.info
Iigurc 2-22. A s|idcr with a custon thunb inagc
2.7 Customizing the UISlider
Problem
You aie using the uelault appeaiance ol the UISlider UI component anu now you want
to Le aLle to customize this look anu leel.
Solution
Eithei mouily the tint colois ol the uilleient paits ol the sliuei, oi pioviue youi own
images loi the paits.
Discussion
Apple has uone a gieat joL giving us methous to customize UI components in iOS 6
SDK. One customization is to mouily the tint colois ol vaiious paits ol the UI compo-
nent. Let`s take a simple UISlider as an example. I have Lioken it uown into its uilleient
UI components in Figuie 2-23.
A methou anu piopeity exists loi each ol these components in UISlider that allow you
to change the appeaiance ol the sliuei. The easiest ol these piopeities to use aie the
ones that mouily the tint coloi ol these components. The piopeities aie:
130 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
Iigurc 2-23. Dijjcrcnt conponcnts oj a U|S|idcr
minimumTrackTintColor
This piopeity changes the tint coloi ol the minimum value tiack view ol the sliuei.
thumbTintColor
This piopeity, as its name shows, changes the tint coloi ol the thumL view ol the
sliuei.
maximumTrackTintColor
This piopeity changes the tint coloi ol the maximum value tiack view ol the sliuei.
All these piopeities aie ol type UIColor.
The lollowing sample coue instantiates a UISlider anu places it at the centei ol the view
ol the view contiollei. It also sets the tint coloi ol the minimum value tiacking view ol
the sliuei to ieu, the tint coloi ol the thumL view ol the sliuei to Llack, anu the tint
coloi ol the maximum value tiacking view ol the sliuei to gieen:
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong) UISlider *slider;
@end
@implementation ViewController
- (void)viewDidLoad{
[super viewDidLoad];
/* Create the slider */
self.slider = [[UISlider alloc] initWithFrame:CGRectMake(0.0f,
0.0f,
118.0f,
23.0f)];
self.slider.value = 0.5;
self.slider.minimumValue = 0.0f;
self.slider.maximumValue = 1.0f;
2.7 Customizing the UISlider | 131
www.it-ebooks.info
self.slider.center = self.view.center;
[self.view addSubview:self.slider];
/* Set the tint color of the minimum value */
self.slider.minimumTrackTintColor = [UIColor redColor];
/* Set the tint color of the thumb */
self.slider.maximumTrackTintColor = [UIColor greenColor];
/* Set the tint color of the maximum value */
self.slider.thumbTintColor = [UIColor blackColor];
}
- (void)didReceiveMemoryWarning{
[super didReceiveMemoryWarning];
}
@end
Il you iun the app now, you will see something similai to what is shown in Figuie 2-2+.
Iigurc 2-21. Thc tint co|or oj a|| thc dijjcrcnt conponcnts oj a s|idcr arc nodijicd
Sometimes you may want to have moie contiol ovei how a sliuei looks on the scieen.
Foi this, tint colois may not Le sullicient. That`s why Apple has pioviueu othei ways
ol mouilying the look anu leel ol a sliuei, allowing you to pioviue images loi uilleient
components in the sliuei. These images aie:
132 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
Mininun va|uc inagc
This is the image that will Le uisplayeu to the outei-lelt siue ol the sliuei. By uelault,
no image is pioviueu loi the minimum value image, so you cannot ieally see this
il you cieate a new sliuei on a view. You can use this image to give youi useis an
inuication ol what the minimum value in youi sliuei may mean in the context ol
youi app. Foi instance, in an app wheie the usei is alloweu to inciease oi ueciease
the Liightness ol the scieen, the minimum value image may uisplay a uim lightLulL,
suggesting to useis that moving the thumL in the sliuei to the lelt (towaiu the
minimum value) will ieuuce the Liightness ol the scieen luithei. To change this
image, use the setMinimumValueImage: instance methou ol the sliuei. The image
neeus to Le 23 points wiue anu 23 points tall. OLviously, loi ietina uisplays, simply
pioviue the same image Lut twice as Lig.
Mininun trac| inagc
This is the image that will Le uisplayeu loi the tiack ol the sliuei on the lelt siue ol
the thumL. To change this image, use the setMinimumTrackImage:forState: in-
stance methou ol the sliuei. The image neeus to Le 11 points wiue anu 9 points
tall, anu Le constiucteu as a iesizaLle image (see Recipe 17.5). OLviously, you neeu
to pioviue a +6x+6 image loi ietina uisplays.
Thunb inagc
The image loi the thumL; the only moving component in the sliuei. To change this
image, use the setThumbImage:forState: instance methou ol the sliuei. The image
neeus to Le 23 points wiue anu 23 points tall.
Maxinun trac| inagc
The image loi the tiack ol the sliuei to the iight ol the thumL. To change this image,
use the setMaximumTrackImage:forState: instance methou ol the sliuei. The image
neeus to Le 11 points wiue anu 9 points tall, anu Le constiucteu as a iesizaLle image
(see Recipe 17.5).
Maxinun va|uc inagc
The maximum value image is the image that gets uisplayeu on the outei-iight siue
ol the sliuei. This is similai to the minimum value image, Lut ol couise uepicts the
maximum value ol the sliuei insteau. To continue the example that we ieau aLout
loi the minimum value image, the image loi the maximum value can Le a Liight
light with iays emitting liom it, suggesting to the usei that the luithei they move
the sliuei to the iight, the Liightei the uisplay gets. To change this image, use the
setMaximumValueImage: instance methou ol the sliuei. The image neeus to Le 23
points wiue anu 23 points tall.
The images that you pioviue loi the minimum anu the maximum tiack
neeu to Le iesizaLle. Foi moie inloimation aLout iesizaLle images, see
Recipe 17.5.
2.7 Customizing the UISlider | 133
www.it-ebooks.info
Foi the sake ol this exeicise, I have cieateu live unigue images loi each one ol the
components ol the sliuei. I`ve maue suie that the minimum anu the maximum tiack
images aie iesizaLle images. Vhat I am tiying to achieve with the customization ol this
sliuei component is to make the usei think that they aie changing the tempeiatuie
settings ol a ioom, wheie moving the sliuei to the lelt means less heat anu moving to
the iight means moie heat. So heie is the coue that cieates a sliuei anu skins its vaiious
components:
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong) UISlider *slider;
@end
@implementation ViewController
/*
This method returns a resizable image for the
minimum track component of the slider
*/
- (UIImage *) minimumTrackImage{
UIImage *result = [UIImage imageNamed:@"MinimumTrack"];
UIEdgeInsets edgeInsets;
edgeInsets.left = 4.0f;
edgeInsets.top = 0.0f;
edgeInsets.right = 0.0f;
edgeInsets.bottom = 0.0f;
result = [result resizableImageWithCapInsets:edgeInsets];
return result;
}
/*
Similar to the previous method, this one returns the resizable maximum
track image for the slider
*/
- (UIImage *) maximumTrackImage{
UIImage *result = [UIImage imageNamed:@"MaximumTrack"];
UIEdgeInsets edgeInsets;
edgeInsets.left = 0.0f;
edgeInsets.top = 0.0f;
edgeInsets.right = 3.0f;
edgeInsets.bottom = 0.0f;
result = [result resizableImageWithCapInsets:edgeInsets];
return result;
}
- (void)viewDidLoad{
[super viewDidLoad];
/* Create the slider */
self.slider = [[UISlider alloc] initWithFrame:CGRectMake(0.0f,
0.0f,
218.0f,
23.0f)];
134 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
self.slider.value = 0.5;
self.slider.minimumValue = 0.0f;
self.slider.maximumValue = 1.0f;
self.slider.center = self.view.center;
[self.view addSubview:self.slider];
/* Change the minimum value image */
[self.slider setMinimumValueImage:[UIImage imageNamed:@"MinimumValue"]];
/* Change the minimum track image */
[self.slider setMinimumTrackImage:[self minimumTrackImage]
forState:UIControlStateNormal];
/* Change the thumb image for both untouched and touched states */
[self.slider setThumbImage:[UIImage imageNamed:@"Thumb"]
forState:UIControlStateNormal];
[self.slider setThumbImage:[UIImage imageNamed:@"Thumb"]
forState:UIControlStateHighlighted];
/* Change the maximum track image */
[self.slider setMaximumTrackImage:[self maximumTrackImage]
forState:UIControlStateNormal];
/* Change the maximum value image */
[self.slider setMaximumValueImage:[UIImage imageNamed:@"MaximumValue"]];
}
- (void)didReceiveMemoryWarning{
[super didReceiveMemoryWarning];
}
@end
The iesults aie shown in Figuie 2-25.
See Also
Recipe 2.6
2.8 Grouping Compact Options with UISegmentedControl
Problem
You woulu like to piesent a lew options to youi useis liom which they can pick, thiough
a UI that is compact, simple, anu easy to unueistanu.
Solution
Use the UISegmentedControl class, an example ol which is shown in Figuie 2-26.
2.8 Grouping Compact Options with UISegmentedControl | 135
www.it-ebooks.info
Discussion
A segmenteu contiol is a UI component that allows you to uisplay, in a compact UI,
seiies ol options loi the usei to choose liom. To show a segmenteu contiol, cieate an
instance ol UISegmentedControl. Let`s stait with oui view contiollei`s .h lile:
#import <UIKit/UIKit.h>
@interface Grouping_Compact_Options_with_UISegmentedControlViewController
: UIViewController
@property (nonatomic, strong) UISegmentedControl *mySegmentedControl;
@end
Anu cieate the segmenteu contiol in the viewDidLoad methou ol youi view contiollei:
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
NSArray *segments = [[NSArray alloc] initWithObjects:
@"iPhone",
@"iPad",
@"iPod",
@"iMac", nil];
self.mySegmentedControl = [[UISegmentedControl alloc]
initWithItems:segments];
self.mySegmentedControl.center = self.view.center;
Iigurc 2-25. A ju||y custonizcd s|idcr is p|accd in thc ccntcr oj our vicw
136 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
[self.view addSubview:self.mySegmentedControl];
}
Ve aie simply using an aiiay ol stiings to pioviue the uilleient options that oui seg-
menteu contiol has to uisplay. Ve initialize oui segmenteu contiol using the
initWithObjects: initializei anu pass the aiiay ol stiings anu images to the segmenteu
contiol. The iesults will look like what we saw in Figuie 2-26.
Now the usei can pick onc ol the options in the segmenteu contiol. Let`s say she has
pickeu iPad. The segmenteu contiol will then change its usei inteilace to show the usei
what option she has selecteu, as uepicteu in Figuie 2-27.
Now the guestion is, how uo you iecognize when the usei selects a new option in a
segmenteu contiol? The answei is simple. ]ust as with a UISwitch oi a UISlider, use the
addTarget:action:forControlEvents: methou ol the segmenteu contiol to auu a taiget
to it. Pioviue the value ol UIControlEventValueChanged loi the forControlEvents pa-
iametei, Lecause that is the event that gets liieu when the usei selects a new option in
a segmenteu contiol:
- (void) segmentChanged:(UISegmentedControl *)paramSender{
if ([paramSender isEqual:self.mySegmentedControl]){
NSInteger selectedSegmentIndex = [paramSender selectedSegmentIndex];
NSString *selectedSegmentText =
[paramSender titleForSegmentAtIndex:selectedSegmentIndex];
NSLog(@"Segment %ld with %@ text is selected",
(long)selectedSegmentIndex,
selectedSegmentText);
Iigurc 2-2. A scgncntcd contro| disp|aying jour options
2.8 Grouping Compact Options with UISegmentedControl | 137
www.it-ebooks.info
}
}
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
NSArray *segments = [[NSArray alloc] initWithObjects:
@"iPhone",
@"iPad",
@"iPod",
@"iMac", nil];
self.mySegmentedControl = [[UISegmentedControl alloc]
initWithItems:segments];
self.mySegmentedControl.center = self.view.center;
[self.view addSubview:self.mySegmentedControl];
[self.mySegmentedControl addTarget:self
action:@selector(segmentChanged:)
forControlEvents:UIControlEventValueChanged];
}
Il the usei staits liom the lelt siue anu selects each ol the options in Figuie 2-26, all the
way to the iight siue ol the contiol, the lollowing text will piint out to the console:
Segment 0 with iPhone text is selected
Segment 1 with iPad text is selected
Segment 2 with iPod text is selected
Segment 3 with iMac text is selected
As you can see, we useu the selectedSegmentIndex methou ol the segmenteu contiol to
linu the inuex ol the cuiiently selecteu item. Il no item is selecteu, this methou ietuins
Iigurc 2-27. Uscr has sc|cctcd onc oj thc itcns in a scgncntcd contro|
138 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
the value 1. Ve also useu the titleForSegmentAtIndex: methou. Simply pass the inuex
ol an option in the segmenteu contiol to this methou, anu the segmenteu contiol will
ietuin the text loi that item. Simple, isn`t it?
As you might have noticeu, once the usei selects an option in a segmenteu contiol, that
option will get selecteu anu will rcnain selecteu, as shown in Figuie 2-27. Il you want
the usei to Le aLle to select an option Lut you woulu like the Lutton loi that option to
Lounce Lack to its oiiginal shape once it has Leen selecteu (just like a noimal Lutton
that Lounces Lack up once it is tappeu), you neeu to set the momentary piopeity ol the
segmenteu contiol to YES:
self.mySegmentedControl.momentary = YES;
One ol the ieally neat leatuies ol segmenteu contiols is that they can contain images
insteau ol text. To uo this, simply use the initWithObjects: initializei methou ol the
UISegmentedControl class anu pass the stiings anu images that will Le useu to initialize
the segmenteu UI contiol:
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
NSArray *segments = [[NSArray alloc] initWithObjects:
@"iPhone",
[UIImage imageNamed:@"iPad.png"],
@"iPod",
@"iMac", nil];
self.mySegmentedControl = [[UISegmentedControl alloc]
initWithItems:segments];
CGRect segmentedFrame = self.mySegmentedControl.frame;
segmentedFrame.size.height = 64.0f;
segmentedFrame.size.width = 300.0f;
self.mySegmentedControl.frame = segmentedFrame;
self.mySegmentedControl.center = self.view.center;
[self.view addSubview:self.mySegmentedControl];
}
In this example, the iPad.png lile is simply an image ol an iPau, with a
iesolution ol 36+7 pixels.
The iesults aie shown in Figuie 2-2S.
2.8 Grouping Compact Options with UISegmentedControl | 139
www.it-ebooks.info
Iigurc 2-28. A scgncntcd contro| with an option disp|aycd as an inagc
One ol the leatuies ol segmenteu contiols is that we can select theii style using the
segmentedControlStyle piopeity. This piopeity is ol type UISegmentedControlStyle:
typedef enum {
UISegmentedControlStylePlain,
UISegmentedControlStyleBordered,
UISegmentedControlStyleBar,
UISegmentedControlStyleBezeled,
} UISegmentedControlStyle;
The uelault style ol a segmenteu contiol is UISegmentedControlStylePlain. You can
change the style ol youi segmenteu contiols to any ol the values listeu in the UISegmen
tedControlStyle enumeiation. Figuie 2-29 is an example ol a Lezeleu segmenteu con-
tiol.
2.9 Customizing the UISegmentedControl
Problem
You have alieauy placeu a segmenteu contiol oi two on youi UI, anu now want to Le
aLle to customize them to match youi UI`s theme.
Solution
Eithei apply tint coloi to the segmenteu contiol oi cieate youi own images anu apply
them to this component.
140 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
Discussion
Tint colois aie the easiest way ol applying new colois to youi UI components. The
UISegmentedControl class has a piopeity nameu tintColor that you can utilize to change
the tint coloi ol youi segmenteu contiol. Theie is one impoitant thing that you have
to Leai in minu Leloie attempting to change the value ol the aloiementioneu piopeity:
the style ol youi segmenteu contiol has to Le set to UISegmentedControlStyleBar. You
can change the style ol youi segmenteu contiol Ly changing the value ol the segmented
ControlStyle piopeity ol youi contiol. Heie is an example:
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong) UISegmentedControl *segmentedControl;
@end
@implementation ViewController
- (void)viewDidLoad{
[super viewDidLoad];
NSArray *items = @[@"Item 1", @"Item 2", @"Item 3"];
self.segmentedControl = [[UISegmentedControl alloc] initWithItems:items];
/* We have to do this if we want to change the tint color */
self.segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar;
[self.view addSubview:self.segmentedControl];
self.segmentedControl.center = CGPointMake(self.view.center.x + 25.0f,
self.view.center.y);
/* Change the tint color now */
self.segmentedControl.tintColor = [UIColor blueColor];
Iigurc 2-29. A bczc|cd scgncntcd contro|
2.9 Customizing the UISegmentedControl | 141
www.it-ebooks.info
}
- (void)didReceiveMemoryWarning{
[super didReceiveMemoryWarning];
}
@end
Anu the output ol this piogiam is shown in Figuie 2-30.
Iigurc 2-30. A scgncntcd contro| with a nodijicd tint co|or
Even though changing the tint coloi ol the segmenteu contiol gives you some contiol
ovei how you customize its appeaiance, some may say that is not enough. Foi this
ieason, you can also set custom images loi uilleient components ol the segmenteu
contiol thiough the lollowing methous:
setBackgroundImage:forState:barMetrics:
This methou can set the Lackgiounu images ol the segmenteu contiol. The for
State paiametei uelines which state ol the component shoulu have the Lackgiounu
image you specily. Theie aie two states: selecteu (altei the usei has piesseu that
item uown) anu unselecteu (the initial state, when the usei has not selecteu the
contiol yet). Pass UIControlStateNormal to change the unselecteu moue anu UICon
trolStateSelected to change the selecteu moue.
142 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
setDividerImage:forLeftSegmentState:rightSegmentState:barMetrics:
This methou can set the image ol the uiviuei that is visiLle Letween the uilleient
items in the segmenteu contiol. You have to pioviue thiee images loi the uiviuei:
Diviuei that sits Letween two unselecteu segmenteu items.
Diviuei that sits Letween a selecteu (on the lelt) anu an unselecteu (on the
iight) item.
Diviuei that sits Letween an unselecteu (on the lelt) anu a selecteu (on the
iight) item.
I have cieateu all these images in ietina anu non-ietina moues loi the pioject that I am
going to uemonstiate to you iight now. Let`s take it one step at a time. Since we neeu
thiee uiviuei images, it`s Lest to cieate some soit ol convenient methous to cieate the
images loi the thiee states loi us. I have cieateu an enumeiation ol stiings that list the
image names that a methou can use loi the uiviuei images. Heie is the top ol the im-
plementation ol oui view contiollei:
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong) UISegmentedControl *segmentedControl;
@end
NSString *const DividerImageTypeUnselectedUnselected = @"Unselected-Unselected";
NSString *const DividerImageTypeSelectedUnselected = @"Selected-Unselected";
NSString *const DividerImageTypeUnselectedSelected = @"Unselected-Selected";
typedef NSString *DividerImageType;
@implementation ViewController
Since the selecteu/unselecteu Lackgiounu images aie similai in size anu uillei only in
lilenames, it`s Lest to cieate just one methou that can ietuin one ol these images to us,
choosing the image Laseu on a paiametei that can take a Boolean value inuicating
whethei an item was selecteu oi unselecteu. Also, we have thiee uiviuei images, which
can all Le ietuineu Ly a single methou. Ve will pass one ol the pieviously uelineu
DividerImageType stiings to this methou as a paiametei. Anu since these image types
aie uelineu as stiings containing the actual lilenames, the methou can consume the
lilenames anu cieate images liom the lilenames, like so:
- (UIImage *) segmentImageInSelectedMode:(BOOL)paramInSelectedMode{
UIImage *result;
if (paramInSelectedMode){
result = [UIImage imageNamed:@"Selected"];
} else {
result = [UIImage imageNamed:@"Unselected"];
}
UIEdgeInsets edgeInsets;
edgeInsets.left = 8.0f;
edgeInsets.top = 0.0f;
edgeInsets.right = 8.0f;
2.9 Customizing the UISegmentedControl | 143
www.it-ebooks.info
edgeInsets.bottom = 0.0f;
result = [result resizableImageWithCapInsets:edgeInsets];
return result;
}
- (UIImage *) dividerImageOfType:(DividerImageType)paramType{
UIImage *result = [UIImage imageNamed:paramType];
UIEdgeInsets edgeInsets;
edgeInsets.left = 25.0f;
edgeInsets.top = 0.0f;
edgeInsets.right = 25.0f;
edgeInsets.bottom = 0.0f;
result = [result resizableImageWithCapInsets:edgeInsets];
return result;
}
Now we will just utilize these methous to get oui images:
- (UIImage *) normalImage{
return [self segmentImageInSelectedMode:NO];
}
- (UIImage *) selectedImage{
return [self segmentImageInSelectedMode:YES];
}
- (UIImage *) dividerUnselectedUnselected{
return [self dividerImageOfType:DividerImageTypeUnselectedUnselected];
}
- (UIImage *) dividerSelectedUnselected{
return [self dividerImageOfType:DividerImageTypeSelectedUnselected];
}
- (UIImage *) dividerUnselectedSelected{
return [self dividerImageOfType:DividerImageTypeUnselectedSelected];
}
Using these methous that we just wiote, we will now wiite othei methous that will
change the Lackgiounu anu uiviuei images ol oui segmenteu contiol. Ve will use the
lollowing methous in the viewDidLoad methou ol oui view contiollei:
- (void) setBackgroundImages{
[self.segmentedControl setBackgroundImage:[self normalImage]
forState:UIControlStateNormal
barMetrics:UIBarMetricsDefault];
[self.segmentedControl setBackgroundImage:[self selectedImage]
forState:UIControlStateSelected
barMetrics:UIBarMetricsDefault];
}
144 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
- (void) setDividerImages{
[self.segmentedControl setDividerImage:[self dividerUnselectedUnselected]
forLeftSegmentState:UIControlStateNormal
rightSegmentState:UIControlStateNormal
barMetrics:UIBarMetricsDefault];
[self.segmentedControl setDividerImage:[self dividerSelectedUnselected]
forLeftSegmentState:UIControlStateSelected
rightSegmentState:UIControlStateNormal
barMetrics:UIBarMetricsDefault];
[self.segmentedControl setDividerImage:[self dividerUnselectedSelected]
forLeftSegmentState:UIControlStateNormal
rightSegmentState:UIControlStateSelected
barMetrics:UIBarMetricsDefault];
}
Anu heie is oui viewDidLoad methou:
- (void)viewDidLoad{
[super viewDidLoad];
NSArray *items = @[@"Item 1", @"Item 2", @"Item 3"];
self.segmentedControl = [[UISegmentedControl alloc] initWithItems:items];
[self.view addSubview:self.segmentedControl];
self.segmentedControl.center = CGPointMake(self.view.center.x - 50.0f,
self.view.center.y);
[self setBackgroundImages];
[self setDividerImages];
/* Make sure in the normal state of the control that the text is light
gray color and there is no shadow for the font */
[self.segmentedControl
setTitleTextAttributes:
@{
UITextAttributeTextColor:[UIColor lightGrayColor],
UITextAttributeTextShadowColor: [UIColor clearColor],
}
forState:UIControlStateNormal];
/* In the selected state of the segmented control, make sure the text
is rendered in white */
[self.segmentedControl
setTitleTextAttributes:@{UITextAttributeTextColor:[UIColor whiteColor]}
forState:UIControlStateSelected];
}
- (void)didReceiveMemoryWarning{
[super didReceiveMemoryWarning];
}
@end
2.9 Customizing the UISegmentedControl | 145
www.it-ebooks.info
In this methou, we aie uoing the lollowing:
1. Instantiating the segmenteu contiol.
2. Setting the Lackgiounu images ol selecteu/unselecteu moues.
3. Setting the uiviuei images.
+. Changing the lont coloi anu the shauow settings ol the lont in unselecteu moue ol
the segmenteu contiol.
5. Changing the lont coloi ol the segmenteu contiol in selecteu moue.
Figuie 2-31 shows how oui segmenteu contiol will look once ienueieu on the scieen.
Iigurc 2-31. Thc jinishcd custonizcd scgncntcd contro| is disp|aycd on thc scrccn
See Also
Recipe 2.S
2.10 Presenting and Managing Views with UIViewController
Problem
You want to switch Letween uilleient views in youi application.
146 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
Solution
Use the UIViewController class.
Discussion
Apple`s stiategy loi iOS uevelopment was to use the Mouel-View-Contiollei (MVC)
uivision ol laLoi. Views aie what get uisplayeu to useis, while the mouel is the uata
that the app manages, oi the engine ol the app. The contiollei is the Liiuge Letween
the mouel anu the view. The contiollei, oi in this case, view contiollei, manages the
ielationship Letween the view anu the mouel. Vhy uoesn`t the view uo that insteau?
Vell, the answei is guite simple: the view`s coue woulu get messy anu that uesign choice
woulu tightly couple oui views with the mouel, which is not a goou piactice.
Beloie iunning this iecipe, you neeu to have an Xcoue pioject alieauy
cieateu. Follow the instiuctions in Recipe 1.1, Lut insteau ol a Pages-
Baseu Application, cieate an Empty Application.
View contiolleis can Le loaueu liom .xib liles (loi use with Inteilace Builuei), oi simply
Le cieateu piogiammatically. Ve will liist have a look at cieating a view contiollei
without a .xib lile.
Xcoue helps us cieate view contiolleis. Now that you have cieateu an application using
the Empty Application template in Xcoue, lollow these steps to cieate a new view
contiollei loi youi app:
1. In Xcoue, select the File menu anu then choose New New File...
2. In the New File uialog, make suie iOS is the selecteu categoiy on the lelt anu that
Cocoa Touch is the chosen suLcategoiy. Once you`ve uone that, select the UIView
Controller suLclass liom the iighthanu siue ol the uialog anu then piess Next, as
shown in Figuie 2-32.
3. In the next scieen, make suie that the SuLclass ol text lielu says UIView
Controller anu also make suie that neithei the Taigeteu loi iPau noi Vith XIB
loi usei inteilace checkLoxes aie selecteu, as shown in Figuie 2-33. Piess Next.
+. On the next scieen (Save As), give youi view contiollei`s lile the name ol Root-
\icwContro||cr anu piess the Save Lutton, as shown in Figuie 2-3+.
2.10 Presenting and Managing Views with UIViewController | 147
www.it-ebooks.info
Iigurc 2-32. Ncw vicw contro||cr subc|ass
Iigurc 2-33. A custon vicw contro||cr with no .xib ji|c
148 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
Iigurc 2-31. Saving a vicw contro||cr without an xib ji|c
5. Now linu youi application uelegate`s .h lile. I have nameu my pioject Presenting
and Managing Views with UIViewController anu Lecause ol this, my application
uelegate`s class is calleu Presenting_and_Managing_Views_with_UIViewController
AppDelegate. The .h lile ol my app uelegate is theieloie Prcscnting_and_Manag-
ing_\icws_with_U|\icwContro||crAppDc|cgatc.h. In this lile, ueclaie a piopeity ol
type RootViewController:
#import <UIKit/UIKit.h>
@class RootViewController;
@interface Presenting_and_Managing_Views_with_UIViewControllerAppDelegate :
UIResponder <UIApplicationDelegate>
@property (nonatomic, strong) UIWindow *window;
@property (nonatomic, strong) RootViewController *rootViewController;
@end
6. Now linu the application:didFinishLaunchingWithOptions: methou ol the app
uelegate insiue the implementation (.n) lile, anu instantiate the view contiollei
anu auu it to youi winuow:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
2.10 Presenting and Managing Views with UIViewController | 149
www.it-ebooks.info
self.window = [[UIWindow alloc]
initWithFrame:[[UIScreen mainScreen] bounds]];
[self.window makeKeyAndVisible];
self.rootViewController = [[RootViewController alloc]
initWithNibName:nil
bundle:NULL];
[self.window addSubview:self.rootViewController.view];
return YES;
}
Ve auu the vicw oj thc vicw contro||cr to the winuow, not the view
contiollei itsell.
Now il you iun youi app on the simulatoi, you will see a Llack scieen. The ieason is
that oui view contiollei`s view uoesn`t have a Lackgiounu coloi yet. So go to the
Root\icwContro||cr.n lile anu linu the viewDidLoad methou, which is in a state similai
to this:
/*
- (void)viewDidLoad
{
[super viewDidLoad];
}
*/
Remove the comment lines liom aiounu this methou:
- (void)viewDidLoad{
[super viewDidLoad];
}
Now let`s set the Lackgiounu coloi ol oui view contiollei`s view to white:
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
}
Go aheau anu iun the app on the simulatoi. You will now see a plain white view on
the scieen. Congiatulations! You just cieateu a view contiollei anu now you have access
to the view contiollei anu its view oLject.
Vhile cieating the view contiollei (Figuie 2-33), il you hau selecteu the Vith XIB loi
usei inteilace checkLox, Xcoue woulu have also geneiateu a .xib lile loi you. In that
150 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
case, you woulu have to loau youi view contiollei jron that .xib lile Ly passing
the .xib lile`s lull name to the initWithNibName paiametei ol the initWithNibName:bun
dle: methou ol the view contiollei, like so:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
self.window = [[UIWindow alloc]
initWithFrame:[[UIScreen mainScreen] bounds]];
[self.window makeKeyAndVisible];
self.rootViewController = [[RootViewController alloc]
initWithNibName:@"RootViewController"
bundle:NULL];
[self.window addSubview:self.rootViewController.view];
return YES;
}
Il you did cieate a .xib lile while cieating youi view contiollei, you can now select that
lile in Xcoue anu uesign youi usei inteilace with Inteilace Builuei.
See Also
Recipe 1.1
2.11 Presenting Sharing Options with
UIActivityViewController
Problem
You want to Le aLle to allow youi useis to shaie content insiue youi apps with theii
liienus, thiough an inteilace similai to that shown in Figuie 2-35, using uilleient shai-
ing options availaLle in iOS, such as FaceLook anu Twittei.
Solution
Cieate an instance ol the UIActivityViewController class anu shaie youi content
thiough this class, as we will see in the Discussion section ol this iecipe.
The instances ol UIActivityViewController must Le piesenteu moually
on the iPhone anu insiue a popovei on an iPau. Foi moie inloimation
aLout popoveis, ielei to Recipe 2.27.
2.11 Presenting Sharing Options with UIActivityViewController | 151
www.it-ebooks.info
Discussion
Theie aie many shaiing options insiue iOS 6, anu all aie Luilt into the coie ol the OS.
Foi instance, FaceLook anu Twittei integiation is now an integial pait ol the coie ol
iOS anu you can shaie pietty much any content liom anywheie you want. Thiiu-paity
apps like ouis can also use all the shaiing lunctionalities availaLle in iOS without having
to think aLout the low-level uetails ol these seivices anu how iOS pioviues these shaiing
options. The Leauty ol this whole thing is that you mention what you want to shaie
anu iOS will pick the shaiing options that aie capaLle ol hanuling the items that you
want to shaie. Foi instance, il you want to shaie images anu text, iOS will uisplay many
moie items to you than il you want to shaie an auuio lile.
Shaiing uata is veiy easy in iOS. All you have to uo is instantiate the UIActivityView
Controller class using its initWithActivityItems:applicationActivities: initializei.
The paiameteis to this methou aie:
initWithActivityItems
The aiiay ol items that you want to shaie. These can Le instances ol NSString,
UIImage, oi instances ol any ol youi custom classes that conloim to the UIActivi
tyItemSource piotocol. Ve will talk aLout this piotocol latei in uetail.
applicationActivities
This is an aiiay ol instances ol UIActivity that iepiesent the activities that youi
own application suppoits. Foi instance, you can inuicate heie whethei youi ap-
Iigurc 2-35. Thc activity vicw contro||cr disp|aycd on an iOS dcvicc
152 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
plication can hanule its own shaiing ol images anu stiings. Ve will not go into
uetail aLout this paiametei anu will simply pass nil as its value, telling iOS that we
want to stick to the system shaiing options.
So let`s say that you have a text lielu wheie the usei can entei text to Le shaieu, anu a
Shaie Lutton iight neai it. Vhen the usei piesses the Shaie Lutton, you will simply pass
the text ol the text lielu to youi instance ol the UIActivityViewController class. Heie
is oui coue now. Ve aie wiiting this coue loi iPhone, so we will piesent oui activity
view contiollei as a moual view contiollei:
Now let`s uiscuss what to uo il you want shaiing options to Le uisplayeu
as soon as youi view contiollei is uisplayeu on the scieen. The viewDi
dAppear methou ol youi view contiollei will Le calleu when the view ol
youi view contiollei is uisplayeu on the scieen anu is guaianteeu to Le
in the view hieiaichy ol youi app, meaning that you can now uisplay
othei views on top ol youi view contiollei`s view. Do not attempt to
piesent the activity view contiollei in the viewDidLoad methou ol youi
view contiollei. At that stage in the app, youi view contiollei`s view is
still not attacheu to the view hieiaichy ol the application, so attempting
to piesent a view contiollei on the view will not woik. Youi view must
Le piesent in the hieiaichy ol the views loi youi moual views to woik.
Foi this ieason, you neeu to piesent the shaiing view contiollei in the
viewDidAppear methou ol youi view contiollei.
Since we aie putting a text lielu on oui view contiollei, we neeu to make suie that we
aie hanuling its uelegate messages, especially the textFieldShouldReturn: methou ol
the UITextFieldDelegate piotocol. Theieloie, we aie going to elect oui view contiollei
as the uelegate ol the text lielu. Also, we aie going to attach an action methou to oui
Shaie Lutton. Once the Lutton is tappeu, we want to make suie theie is something in
the text lielu to shaie. Il theie isn`t, we will simply uisplay an aleit to the usei telling
them why we cannot shaie the content ol the text lielu. Il theie is some text in the text
lielu, we will pop up an instance ol the UIActivityViewController class. So let`s Legin
with the heauei lile ol oui view contiollei:
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController <UITextFieldDelegate>
@end
The next thing is to go to the implementation lile ol oui view contiollei anu ueline oui
UI components:
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong) UITextField *textField;
@property (nonatomic, strong) UIButton *buttonShare;
2.11 Presenting Sharing Options with UIActivityViewController | 153
www.it-ebooks.info
@property (nonatomic, strong) UIActivityViewController *activityViewController;
@end
@implementation ViewController
...
Altei this, we will simply wiite two methous loi oui view contiollei, each ol which is
aLle to cieate one ol oui UI components anu place it on oui view contiollei`s view. One
will cieate the text lielu, anu the othei will cieate the Lutton next to it:
- (void) createTextField{
self.textField = [[UITextField alloc] initWithFrame:CGRectMake(20.0f,
35.0f,
280.0f,
30.0f)];
self.textField.translatesAutoresizingMaskIntoConstraints = NO;
self.textField.borderStyle = UITextBorderStyleRoundedRect;
self.textField.placeholder = @"Enter text to share...";
self.textField.delegate = self;
[self.view addSubview:self.textField];
}
- (void) createButton{
self.buttonShare = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.buttonShare.translatesAutoresizingMaskIntoConstraints = NO;
self.buttonShare.frame = CGRectMake(20.0f, 80.0f, 280.0f, 44.0f);
[self.buttonShare setTitle:@"Share" forState:UIControlStateNormal];
[self.buttonShare addTarget:self
action:@selector(handleShare:)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.buttonShare];
}
Once we aie uone with that, we just have to call these two methous in the viewDid
Load methou ol oui view contiollei. This will allow the UI components to Le placeu on
the view ol oui view contiollei:
- (void)viewDidLoad{
[super viewDidLoad];
[self createTextField];
[self createButton];
}
- (void)didReceiveMemoryWarning{
[super didReceiveMemoryWarning];
}
In the textFieldShouldReturn:, all we uo is uismiss the keyLoaiu in oiuei to iesign the
text lielu`s active state. This simply means that when a usei has Leen euiting the text
154 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
lielu anu then piesses the Retuin/Entei Lutton on the keyLoaiu, the keyLoaiu shoulu
Le uismisseu. Beai in minu that the createTextField methou that we just coueu has set
oui view contiollei as the uelegate ol the text lielu. So we have to implement the aloie-
mentioneu methou as lollows:
- (BOOL) textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
return YES;
}
Last Lut not least is the hanulei methou ol oui Lutton. As you saw, the createButton
methou cieates the Lutton loi us anu elects the handleShare: methou to hanule the
touch uown insiue action ol the Lutton. So let`s coue this methou:
- (void) handleShare:(id)paramSender{
if ([self.textField.text length] == 0){
NSString *message = @"Please enter a text and then press Share";
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil
message:message
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alertView show];
return;
}
self.activityViewController = [[UIActivityViewController alloc]
initWithActivityItems:@[self.textField.text]
applicationActivities:nil];
[self presentViewController:self.activityViewController
animated:YES
completion:^{
/* Nothing for now */
}];
}
Now il you iun the app, entei some text in the text lielu, anu then piess the Shaie
Lutton, you will see something similai to Figuie 2-36.
See Also
Recipe 2.27
2.12 Implementing Navigation with UINavigationController
Problem
You woulu like to allow youi useis to move liom one view contiollei to the othei with
a smooth anu Luilt-in animation.
2.12 Implementing Navigation with UINavigationController | 155
www.it-ebooks.info
Solution
Use a UINavigationController wiuget.
Discussion
Il you`ve useu an iPhone, iPou touch, oi iPau Leloie, chances aie that you have alieauy
seen a navigation contiollei in action. Foi instance, il you go to the Settings app on
youi phone anu then piess an option such as Vallpapei (Figuie 2-37), you will see the
Settings` main scieen get pulleu out ol the scieen liom the lelt anu the Vallpapei scieen
pushing its way into the scieen liom the iight. That is the magic ol navigation contiol-
leis. They allow you to push view contiolleis onto a stack anu pop them liom the stack.
The view contiollei on top ol the stack is the top view contiollei anu is the one seen
Ly the usei at that moment. So only the top view contiollei gets uisplayeu to the usei,
anu is changeu eithei Ly popping (iemoving) it oi Ly pushing anothei view contiollei
onto the stack.
Now we aie going to auu a navigation contiollei to oui pioject, Lut we neeu a pioject
liist. Please lollow the instiuctions in Recipe 2.10 to cieate an empty application with
a simple view contiollei. In this iecipe, we will expanu on Recipe 2.10. Let`s stait with
the .h lile ol oui app uelegate:
Iigurc 2-3. Sharing options disp|aycd jor thc instancc oj string that wc arc trying to sharc
156 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
Iigurc 2-37. Scttings vicw contro||cr pushing thc Wa||papcr vicw contro||cr
#import <UIKit/UIKit.h>
@class RootViewController;
@interface Implementing_Navigation_with_UINavigationControllerAppDelegate
: UIResponder <UIApplicationDelegate>
@property (nonatomic, strong) UIWindow *window;
@property (nonatomic, strong) UINavigationController *navigationController;
@property (nonatomic, strong) RootViewController *rootViewController;
@end
Now we have to initialize oui navigation contiollei using its initWithRootViewControl
ler: methou anu pass oui ioot view contiollei as its paiametei. Then we will auu the
navigation contiollei`s view to the winuow:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
self.window = [[UIWindow alloc]
initWithFrame:[[UIScreen mainScreen] bounds]];
[self.window makeKeyAndVisible];
self.rootViewController = [[RootViewController alloc]
initWithNibName:nil
2.12 Implementing Navigation with UINavigationController | 157
www.it-ebooks.info
bundle:NULL];
self.navigationController =
[[UINavigationController alloc]
initWithRootViewController:self.rootViewController];
[self.window addSubview:self.navigationController.view];
return YES;
}
Now let`s iun oui app in the simulatoi, as shown in Figuie 2-3S.
The liist thing you might notice in Figuie 2-3S is the Lai on top ol the scieen. The
scieen isn`t plain white anymoie. Vhat`s the new wiuget? A navigation Lai. Ve will
Le using that Lai a lot loi navigation, placing Luttons theie, anu so loith. That Lai is
also capaLle ol uisplaying a title. Each view contiollei specilies a title loi itsell, anu the
navigation contiollei will automatically uisplay that title once the view contiollei is
pusheu into the stack.
Iigurc 2-38. An cnpty vicw contro||cr disp|aycd insidc a navigation contro||cr
Let`s go to oui ioot view contiollei`s implementation lile, insiue the viewDidLoad meth-
ou, anu set the title piopeity ol oui view contiollei to First Controller:
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.title = @"First Controller";
}
Run the app again anu you will see something similai to that shown in Figuie 2-39.
158 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
Iigurc 2-39. A vicw contro||cr with tit|c
Now let`s go anu cieate a seconu view contiollei, without a .xib lile, anu call it Second
ViewController. Follow the same piocess that you leaineu in Recipe 2.10. Once you
aie uone cieating this view contiollei, give it a title ol Second Controller.
#import "SecondViewController.h"
@implementation SecondViewController
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.title = @"Second Controller";
}
...
Oui plan is to push the seconu view contiollei on top ol the liist view contiollei live
seconus altei the liist view contiollei appeais on the scieen. So let`s liist impoit the
seconu view contiollei into the liist one:
#import "RootViewController.h"
#import "SecondViewController.h"
@implementation RootViewController
...
Now go Lack to the implementation ol the ioot view contiollei anu coue the view
DidAppear: methou like this:
- (void) pushSecondController{
SecondViewController *secondController = [[SecondViewController alloc]
2.12 Implementing Navigation with UINavigationController | 159
www.it-ebooks.info
initWithNibName:nil
bundle:NULL];
[self.navigationController pushViewController:secondController
animated:YES];
}
- (void) viewDidAppear:(BOOL)paramAnimated{
[super viewDidAppear:paramAnimated];
[self performSelector:@selector(pushSecondController)
withObject:nil
afterDelay:5.0f];
}
Ve aie using the performSelector:withObject:afterDelay: methou ol NSObject to
call oui new methou, pushSecondController, live seconus altei oui liist view contiollei
successlully uisplays its view. In the pushSecondController methou, we aie simply using
the navigationController piopeity ol oui view contiollei (this is Luilt into UIView
Controller anu is not something that we coueu) to push an instance ol SecondView
Controller into the stack ol view contiolleis. The iesult is similai to what you can see
in Figuie 2-+0.
Iigurc 2-10. A vicw contro||cr is pushcd on top oj anothcr onc
You can see that the navigation Lai is uisplaying the title ol the top view contiollei anu
even spoits a Lack Lutton that will take the usei Lack to the pievious view contiollei.
You can push as many view contiolleis as you like into the stack anu the navigation
contiollei will woik the navigation Lai to uisplay the ielevant Lack Luttons that allow
the usei to Lack thiough youi application`s UI, all the way to the liist scieen.
Ve leaineu aLout pushing a view contiollei. How aLout popping oi iemoving a view
contiollei liom the stack ol the navigation contiollei? The answei is stiaightloiwaiu:
160 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
using the popViewControllerAnimated: methou ol the navigation contiollei. Let`s make
oui seconu view contiollei pop itsell oll ol the stack automatically live seconus altei it
is uisplayeu on the scieen:
- (void) goBack{
[self.navigationController popViewControllerAnimated:YES];
}- (void) viewDidAppear:(BOOL)paramAnimated{
[super viewDidAppear:paramAnimated];
[self performSelector:@selector(goBack)
withObject:nil
afterDelay:5.0f];
}
So il you open the app in the simulatoi now anu wait live seconus altei the liist view
contiollei is uisplayeu, you will see that the seconu view contiollei will automatically
get uisplayeu on the scieen. Vait anothei live seconus now anu the seconu view con-
tiollei will automatically go Lack to the liist view contiollei.
See Also
Recipe 2.10
2.13 Manipulating a Navigation Controllers Array of View
Controllers
Problem
You woulu like to uiiectly manipulate the aiiay ol view contiolleis associateu with a
specilic navigation contiollei.
Solution
Use the viewControllers piopeity ol the UINavigationController class to access anu
mouily the aiiay ol view contiolleis associateu with a navigation contiollei:
- (void) goBack{
/* Get the current array of View Controllers */
NSArray *currentControllers = self.navigationController.viewControllers;
/* Create a mutable array out of this array */
NSMutableArray *newControllers = [NSMutableArray
arrayWithArray:currentControllers];
/* Remove the last object from the array */
[newControllers removeLastObject];
/* Assign this array to the Navigation Controller */
self.navigationController.viewControllers = newControllers
}
2.13 Manipulating a Navigation Controllers Array of View Controllers | 161
www.it-ebooks.info
You can call this methou insiue any view contiollei in oiuei to pop the last view con-
tiollei liom the hieiaichy ol the navigation contiollei associateu with the cuiient view
contiollei.
Discussion
An instance ol the UINavigationController class holus an aiiay ol UIViewController
oLjects. Altei ietiieving this aiiay, you can manipulate it in any way you wish. Foi
instance, you can iemove a view contiollei liom an aiLitiaiy place in the aiiay.
Manipulating the view contiolleis ol a navigation contiollei uiiectly Ly assigning an
aiiay to the viewControllers piopeity ol the navigation contiollei will commit the op-
eiation without a tiansition/animation. Il you wish this opeiation to Le animateu, use
the setViewControllers:animated: methou ol the UINavigationController class, as
shown in the lollowing snippet:
- (void) goBack{
/* Get the current array of View Controllers */
NSArray *currentControllers = self.navigationController.viewControllers;
/* Create a mutable array out of this array */
NSMutableArray *newControllers = [NSMutableArray
arrayWithArray:currentControllers];
/* Remove the last object from the array */
[newControllers removeLastObject];
/* Assign this array to the Navigation Controller with animation */
[self.navigationController setViewControllers:newControllers
animated:YES];
}
2.14 Displaying an Image on a Navigation Bar
Problem
You want to uisplay an image insteau ol text as the title ol the cuiient view contiollei
on the navigation contiollei.
Solution
Use the titleView piopeity ol the view contiollei`s navigation item:
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
/* Create an Image View to replace the Title View */
UIImageView *imageView =
[[UIImageView alloc]
initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 40.0f)];
162 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
imageView.contentMode = UIViewContentModeScaleAspectFit;
/* Load an image. Be careful, this image will be cached */
UIImage *image = [UIImage imageNamed:@"FullSizeLogo.png"];
/* Set the image of the Image View */
[imageView setImage:image];
/* Set the Title View */
self.navigationItem.titleView = imageView;
}
The pieceuing coue must Le executeu in a view contiollei that is placeu
insiue a navigation contiollei.
Discussion
The navigation item ol eveiy view contiollei can uisplay two uilleient types ol content
in the title aiea ol the view contiollei to which it is assigneu:
Simple text
A view
Il you want to use text, you can use the title piopeity ol the navigation item. Howevei,
il you want moie contiol ovei the title oi il you simply want to uisplay an image oi any
othei view up on the navigation Lai, you can use the titleView piopeity ol the navi-
gation item ol a view contiollei. You can assign any oLject that is a suLclass ol the
UIView class. In oui example, we cieateu an image view anu assigneu an image to it.
Then we uisplayeu it as the title ol the cuiient view contiollei on the navigation con-
tiollei.
2.15 Adding Buttons to Navigation Bars Using
UIBarButtonItem
Problem
You want to auu Luttons to a navigation Lai.
Solution
Use the UIBarButtonItem class.
2.15 Adding Buttons to Navigation Bars Using UIBarButtonItem | 163
www.it-ebooks.info
Discussion
A navigation Lai can contain uilleient items. Buttons aie olten uisplayeu on the lelt
anu the iight siues. These Luttons aie ol class UIBarButtonItem anu can take many
uilleient shapes anu loims. Let`s have a look at an example in Figuie 2-+1.
Iigurc 2-11. Dijjcrcnt buttons disp|aycd on a navigation bar
You might Le suipiiseu that the Lai on the botton ol Figuie 2-+1 is also a navigation
Lai! Navigation Lais aie ol class UINavigationBar anu can Le cieateu at any time anu
auueu to any view. So just look at all the uilleient Luttons with uilleient shapes that
have Leen auueu to the navigation Lais in Figuie 2-+1. The ones on the top iight have
up anu uown aiiows, the one on the top lelt has an aiiow pointing to the lelt, anu the
ones on the Lottom navigation Lai have all soits ol shapes. Ve will have a look at
cieating some ol these Luttons in this iecipe.
Foi this iecipe, you must lollow the instiuctions in Recipe 1.1 to cieate
an Empty application. Then lollow the instiuctions in Recipe 2.12 to
auu a navigation contiollei to youi app uelegate.
In oiuei to cieate a navigation Lutton, we must:
1. Cieate an instance ol UIBarButtonItem.
164 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
2. Auu that Lutton to the navigation Lai ol a view contiollei using the view contiol-
lei`s navigationItem piopeity. The navigationItem piopeity allows us to inteiact
with the navigation Lai. This piopeity has two otheis on itsell: rightBarButton
Item anu leftBarButtonItem. Both these piopeities aie ol type UIBarButtonItem.
Let`s then have a look at an example wheie we auu a Lutton to the iight siue ol oui
navigation Lai. In this Lutton we will uisplay the text Add:
- (void) performAdd:(id)paramSender{
NSLog(@"Action method got called.");
}
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.title = @"First Controller";
self.navigationItem.rightBarButtonItem =
[[UIBarButtonItem alloc] initWithTitle:@"Add"
style:UIBarButtonItemStylePlain
target:self
action:@selector(performAdd:)];
}
Vhen we iun oui app now, we will see something similai to Figuie 2-+2.
Iigurc 2-12. A navigation button addcd to a navigation bar
That was easy. But il you aie an iOS usei, you pioLaLly have noticeu that the system
apps that come pieconliguieu on iOS have a uilleient Auu Lutton. Figuie 2-+3 shows
an example in the Alaim section ol the Clock app on the iPhone (notice the - Lutton
on the top iight ol the navigation Lai).
2.15 Adding Buttons to Navigation Bars Using UIBarButtonItem | 165
www.it-ebooks.info
Iigurc 2-13. Thc propcr way oj crcating an Add button
It tuins out that the iOS SDK allows us to cieate systcn Luttons on the navigation Lai.
Ve uo that Ly using the initWithBarButtonSystemItem:target:action: initializei ol the
UIBarButtonItem class:
- (void) performAdd:(id)paramSender{
NSLog(@"Action method got called.");
}
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.title = @"First Controller";
self.navigationItem.rightBarButtonItem =
[[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
target:self
action:@selector(performAdd:)];
}
Anu the iesults aie exactly what we weie looking loi (Figuie 2-++).
166 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
Iigurc 2-11. A systcn Add button
The liist paiametei ol the initWithBarButtonSystemItem:target:action: initializei
methou ol the navigation Lutton can have any ol the values listeu in the UIBarButton
SystemItem enumeiation:
typedef enum {
UIBarButtonSystemItemDone,
UIBarButtonSystemItemCancel,
UIBarButtonSystemItemEdit,
UIBarButtonSystemItemSave,
UIBarButtonSystemItemAdd,
UIBarButtonSystemItemFlexibleSpace,
UIBarButtonSystemItemFixedSpace,
UIBarButtonSystemItemCompose,
UIBarButtonSystemItemReply,
UIBarButtonSystemItemAction,
UIBarButtonSystemItemOrganize,
UIBarButtonSystemItemBookmarks,
UIBarButtonSystemItemSearch,
UIBarButtonSystemItemRefresh,
UIBarButtonSystemItemStop,
UIBarButtonSystemItemCamera,
UIBarButtonSystemItemTrash,
UIBarButtonSystemItemPlay,
UIBarButtonSystemItemPause,
UIBarButtonSystemItemRewind,
UIBarButtonSystemItemFastForward,
UIBarButtonSystemItemUndo,
UIBarButtonSystemItemRedo,
UIBarButtonSystemItemPageCurl,
} UIBarButtonSystemItem;
2.15 Adding Buttons to Navigation Bars Using UIBarButtonItem | 167
www.it-ebooks.info
One ol the ieally gieat initializeis ol the UIBarButtonItem class is the initWithCustom
View: methou. As its paiametei, this methou accepts any view. This means we can even
auu a UISwitch (see Recipe 2.2) as a Lutton on the navigation Lai. This won`t look veiy
goou, Lut let`s give it a tiy:
- (void) switchIsChanged:(UISwitch *)paramSender{
if ([paramSender isOn]){
NSLog(@"Switch is on.");
} else {
NSLog(@"Switch is off.");
}
}
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.title = @"First Controller";
UISwitch *simpleSwitch = [[UISwitch alloc] init];
simpleSwitch.on = YES;
[simpleSwitch addTarget:self
action:@selector(switchIsChanged:)
forControlEvents:UIControlEventValueChanged];
self.navigationItem.rightBarButtonItem =
[[UIBarButtonItem alloc] initWithCustomView:simpleSwitch];
}
Anu Figuie 2-+5 shows the iesults.
Iigurc 2-15. A switch addcd to a navigation bar
You can cieate pietty amazing navigation Lai Luttons. ]ust take a look at what Apple
has uone with the up anu uown aiiows on the top-iight coinei ol Figuie 2-+1. Let`s uo
168 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
the same thing, shall we? Vell, it looks like the Lutton actually contains a segmenteu
contiol (see Recipe 2.S). So we shoulu cieate a segmenteu contiol with two segments,
auu it to a navigation Lutton, anu linally place the navigation Lutton on the navigation
Lai. Let`s get staiteu:
- (void) segmentedControlTapped:(UISegmentedControl *)paramSender{
if ([paramSender selectedSegmentIndex] == 0){
/* Up button */
NSLog(@"Up");
} else if ([paramSender selectedSegmentIndex] == 1){
/* Down button */
NSLog(@"Down");
}
}
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.title = @"First Controller";
NSArray *items = [[NSArray alloc] initWithObjects:
[UIImage imageNamed:@"UpArrow.png"],
[UIImage imageNamed:@"DownArrow.png"], nil];
UISegmentedControl *segmentedControl = [[UISegmentedControl alloc]
initWithItems:items];
segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar;
segmentedControl.momentary = YES;
[segmentedControl addTarget:self
action:@selector(segmentedControlTapped:)
forControlEvents:UIControlEventValueChanged];
self.navigationItem.rightBarButtonItem =
[[UIBarButtonItem alloc] initWithCustomView:segmentedControl];
}
I manually cieateu the aiiow images. They aie not piesent in the iOS
SDK. Cieating these images is guite easy, though. They aie simple tii-
angles: one pointing up anu the othei pointing uown. Il you aie giaph-
ically challengeu, mayLe you coulu linu some images using a seaich
engine?
Anu Figuie 2-+6 shows what the output looks like.
2.15 Adding Buttons to Navigation Bars Using UIBarButtonItem | 169
www.it-ebooks.info
Iigurc 2-1. A scgncntcd contro| insidc a navigation button
The navigationItem ol eveiy view contiollei also has two veiy inteiesting methous:
setRightBarButtonItem:animated:
Sets the navigation Lai`s iight Lutton.
setLeftBarButtonItem:animated:
Sets the navigation Lai`s lelt Lutton.
Both methous allow you to specily whethei you want the placement to Le animateu.
Pass the value ol YES to the animated paiametei il you want the placement to Le ani-
mateu. Heie is an example:
UIBarButtonItem *rightBarButton =
[[UIBarButtonItem alloc] initWithCustomView:segmentedControl];
[self.navigationItem setRightBarButtonItem:rightBarButton
animated:YES];
See Also
Recipe 1.1; Recipe 2.2; Recipe 2.S; Recipe 2.12
170 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
2.16 Presenting Multiple View Controllers with
UITabBarController
Problem
You woulu like to give youi useis the option to switch liom one section ol youi app to
anothei, with ease.
Solution
Use the UITabBarController class.
Discussion
Il you use youi iPhone as an alaim clock, you have ceitainly seen a taL Lai. Have a look
at Figuie 2-+3. The Lottom icons laLeleu Voilu Clock, Alaim, Stopwatch, anu Timei
aie paits ol a taL Lai. The whole Llack Lai at the Lottom ol the scieen is a taL Lai anu
the aloiementioneu icons aie taL Lai items.
A taL Lai is a containei contiollei. In othei woius, we cieate instances ol UITabBar
Controller anu auu them to the winuow ol oui application. Foi each taL Lai item, we
auu a navigation contiollei oi a view contiollei to the taL Lai, anu those items will
appeai as taL Lai items. A taL Lai contiollei contains a taL Lai ol type UITabBar. Ve
uon`t cieate this oLject manually. Ve cieate the taL Lai contiollei, anu that will cieate
the taL Lai oLject loi us. To make things simple, iememLei that we instantiate a taL
Lai contiollei anu set the view contiolleis ol that taL Lai to instances ol eithei UIView
Controller oi UINavigationController il we intenu to have navigation contiolleis loi
each ol the taL Lai items (aka, the view contiolleis set loi the taL Lai contiollei). Nav-
igation contiolleis aie ol type UINavigationController that aie suLclasses ol UIView
Controller. Theieloie, a navigation contiollei is a view contiollei, Lut view contiolleis
ol type UIViewController aie not navigation contiolleis.
So let`s assume we have two view contiolleis with class names FirstViewController
anu SecondViewController. Ve now go into oui app uelegate anu ueline oui view con-
tiolleis anu oui taL Lai:
#import <UIKit/UIKit.h>
@class FirstViewController;
@class SecondViewController;
@interface Presenting_Multiple_View_Controllers_with_UITabBarControllerAppDelegate
: UIResponder <UIApplicationDelegate>
@property (nonatomic, strong) UIWindow *window;
@property (nonatomic, strong) FirstViewController *firstViewController;
@property (nonatomic, strong) SecondViewController *secondViewController;
@property (nonatomic, strong) UITabBarController *tabBarController;
2.16 Presenting Multiple View Controllers with UITabBarController | 171
www.it-ebooks.info
@end
Now let`s go anu instantiate oui view contiolleis anu taL Lai contiollei:
#import "Presenting_Multiple_View_Controllers_with_UITabBarControllerAppDelegate.h"
#import "FirstViewController.h"
#import "SecondViewController.h"
@implementation Presenting_Multiple_View_Controllers_with_UITabBarControllerAppDelegate
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
// Override point for customization after application launch.
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
[self.window makeKeyAndVisible];
self.firstViewController = [[FirstViewController alloc]
initWithNibName:nil
bundle:NULL];
self.secondViewController = [[SecondViewController alloc]
initWithNibName:nil
bundle:NULL];
NSArray *twoViewControllers = [[NSArray alloc]
initWithObjects:
self.firstViewController,
self.secondViewController, nil];
self.tabBarController = [[UITabBarController alloc] init];
[self.tabBarController setViewControllers:twoViewControllers];
[self.window addSubview:self.tabBarController.view];
return YES;
}
A taL Lai, when uisplayeu on the scieen, will uisplay taL Lai items just like those we
saw in Figuie 2-+3. The name ol each ol these taL Lai items comes liom the title ol the
view contiollei that is iepiesenting that taL Lai item, so let`s go aheau anu set the title
loi Loth oui view contiolleis.
Vhen a taL Lai loaus up, it loaus only the view ol the liist view contiollei
in its items. All othei view contiolleis will Le initializeu, Lut theii views
won`t Le loaueu. This means that any coue that you have wiitten in the
viewDidLoad ol the seconu view contiollei will not get executeu until
altei the usei taps on the seconu taL Lai item loi the liist time. So il you
assign a title to the seconu view contiollei in its viewDidLoad anu iun
youi app, you will linu that the title in the taL Lai item is still empty.
172 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
Foi the liist view contiollei, we choose the title First:
#import "FirstViewController.h"
@implementation FirstViewController
- (id)initWithNibName:(NSString *)nibNameOrNil
bundle:(NSBundle *)nibBundleOrNil{
self = [super initWithNibName:nibNameOrNil
bundle:nibBundleOrNil];
if (self != nil) {
self.title = @"First";
}
return self;
}
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
}
...
Anu loi the seconu view contiollei, we pick the title Second:
#import "SecondViewController.h"
@implementation SecondViewController
- (id)initWithNibName:(NSString *)nibNameOrNil
bundle:(NSBundle *)nibBundleOrNil{
self = [super initWithNibName:nibNameOrNil
bundle:nibBundleOrNil];
if (self != nil) {
self.title = @"Second";
}
return self;
}
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];}
...
Now let`s iun oui app anu see what happens (Figuie 2-+7).
2.16 Presenting Multiple View Controllers with UITabBarController | 173
www.it-ebooks.info
Iigurc 2-17. A vcry sinp|c tab bar popu|atcd with two vicw contro||crs
You can see that oui view contiolleis uo not have a navigation Lai. Vhat shoulu we
uo? It`s easy. RememLei that a UINavigationController is actually a suLclass ol UIView
Controller. So, we can auu instances ol navigation contiolleis to a taL Lai, anu insiue
each navigation contiollei, we can loau a view contiollei. Vhat aie we waiting loi,
then? Let`s stait with the heauei lile ol oui app uelegate:
#import <UIKit/UIKit.h>
@class FirstViewController;
@class SecondViewController;
@interface Presenting_Multiple_View_Controllers_with_UITabBarControllerAppDelegate
: UIResponder <UIApplicationDelegate>
@property (nonatomic, strong) UIWindow *window;
@property (nonatomic, strong) FirstViewController *firstViewController;
@property (nonatomic, strong)
UINavigationController *firstNavigationController;
@property (nonatomic, strong) SecondViewController *secondViewController;
@property (nonatomic, strong)
UINavigationController *secondNavigationController;
@property (nonatomic, strong) UITabBarController *tabBarController;
@end
Now that we have the ueclaiation in place, let`s implement the taL Lai contiollei in the
implementation lile ol oui app uelegate:
174 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
// Override point for customization after application launch.
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
[self.window makeKeyAndVisible];
self.firstViewController = [[FirstViewController alloc]
initWithNibName:nil
bundle:NULL];
self.firstNavigationController =
[[UINavigationController alloc]
initWithRootViewController:self.firstViewController];
self.secondViewController = [[SecondViewController alloc]
initWithNibName:nil
bundle:NULL];
self.secondNavigationController =
[[UINavigationController alloc]
initWithRootViewController:self.secondViewController];
NSArray *twoNavControllers = [[NSArray alloc]
initWithObjects:
self.firstNavigationController,
self.secondNavigationController, nil];
self.tabBarController = [[UITabBarController alloc] init];
[self.tabBarController setViewControllers:twoNavControllers];
[self.window addSubview:self.tabBarController.view];
return YES;
}
Anu the iesults? Exactly what we wanteu (Figuie 2-+S).
As we can see in Figuie 2-+3, each taL Lai item can have text anu an image. Ve`ve
leaineu that, using the title piopeity ol a view contiollei, we can specily this text, Lut
what aLout the image? It tuins out that eveiy view contiollei has a piopeity calleu
tabItem. This piopeity is the taL item loi the cuiient view contiollei, anu you can use
this piopeity to set the image ol the taL Lai item thiough the image piopeity ol the taL
item. I`ve alieauy uesigneu two images, a iectangle anu a ciicle. I`m going to uisplay
them as the taL Lai item image loi each ol my view contiolleis. Heie is coue loi the
liist view contiollei:
#import "FirstViewController.h"
@implementation FirstViewController
- (id)initWithNibName:(NSString *)nibNameOrNil
bundle:(NSBundle *)nibBundleOrNil{
2.16 Presenting Multiple View Controllers with UITabBarController | 175
www.it-ebooks.info
self = [super initWithNibName:nibNameOrNil
bundle:nibBundleOrNil];
if (self != nil) {
self.title = @"First";
self.tabBarItem.image = [UIImage imageNamed:@"FirstTab.png"];
}
return self;
}
...
Anu heie it is loi the seconu view contiollei:
#import "SecondViewController.h"
@implementation SecondViewController
- (id)initWithNibName:(NSString *)nibNameOrNil
bundle:(NSBundle *)nibBundleOrNil{
self = [super initWithNibName:nibNameOrNil
bundle:nibBundleOrNil];
if (self != nil) {
self.title = @"Second";
self.tabBarItem.image = [UIImage imageNamed:@"SecondTab.png"];
}
return self;
}
...
Iigurc 2-18. A tab bar disp|aying vicw contro||crs insidc navigation contro||crs
176 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
Running the app in the simulatoi, we will see that the images aie uisplayeu piopeily
(Figuie 2-+9).
Iigurc 2-19. Tab bar itcns with inagcs
2.17 Displaying Static Text with UILabel
Problem
You want to uisplay text to youi useis. You woulu also like to contiol the text`s lont
anu coloi.
A static text is text that is not uiiectly changeaLle Ly the usei at iuntime.
Solution
Use the UILabel class.
Discussion
LaLels aie eveiywheie in iOS. You can see them in piactically eveiy application, except
loi games wheie the content is usually ienueieu with OpenGL ES insteau ol the coie
uiawing liamewoiks in iOS. Figuie 2-50 shows seveial laLels in the Settings app on the
iPhone.
2.17 Displaying Static Text with UILabel | 177
www.it-ebooks.info
Iigurc 2-50. Labc|s as tit|cs oj cach onc oj thc scttings
You can see that the laLels aie uisplaying text in the Settings app, such as Geneial,
iClouu, Twittei, Phone, FaceTime, etc.
To cieate a laLel, instantiate an oLject ol type UILabel. Setting oi getting the text ol a
laLel can Le uone thiough its text piopeity. So let`s ueline a laLel in oui view contiollei`s
heauei lile:
#import <UIKit/UIKit.h>
@interface Displaying_Static_Text_with_UILabelViewController
: UIViewController
@property (nonatomic, strong) UILabel *myLabel;
@end
Now in the viewDidLoad methou, instantiate the laLel anu tell the iuntime wheie the
laLel has to Le positioneu (thiough its liame piopeity) on the view to which it will Le
auueu (in this case, oui view contiollei`s view):
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
CGRect labelFrame = CGRectMake(0.0f,
0.0f,
178 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
100.0f,
23.0f);
self.myLabel = [[UILabel alloc] initWithFrame:labelFrame];
self.myLabel.text = @"iOS 6 Programming Cookbook";
self.myLabel.font = [UIFont boldSystemFontOfSize:14.0f];
self.myLabel.center = self.view.center;
[self.view addSubview:self.myLabel];
}
Now let`s iun oui app anu see what happens (see Figuie 2-51).
Iigurc 2-51. A |abc| that is too sna|| in width to contain its contcnts
You can see that the contents ol the laLel aie tiuncateu, with tiailing lull stops, Lecause
the wiuth ol the laLel isn`t enough to contain the whole contents. One solution woulu
Le to make the wiuth longei, Lut how aLout the height? Vhat il we wanteu the text to
wiap to the next line? OK, go aheau anu change the height liom 23.0f to 50.0f:
CGRect labelFrame = CGRectMake(0.0f,
0.0f,
100.0f,
50.0f);
Il you iun youi app now, you will get cxact|y the same iesults that you got in Fig-
uie 2-51. You might ask, I incieaseu the height, so why uiun`t the content wiap to the
next line? It tuins out that UILabel class has a piopeity calleu numberOfLines that neeus
to Le aujusteu to the numLei ol lines the laLel has to wiap the text to, in case it iuns
out ol hoiizontal space. Il you set this value to 3, it tells the laLel that you want the text
to wiap to a maximum ol thiee lines il it cannot lit the text into one line:
self.myLabel.numberOfLines = 3;
2.17 Displaying Static Text with UILabel | 179
www.it-ebooks.info
Il you iun the app now, you will get the uesiieu iesults (see Figuie 2-52).
Iigurc 2-52. A |abc| wrapping its contcnts to thrcc |incs
In some situations, you might not know how many lines aie ieguiieu to
uisplay a ceitain text in a laLel. In those instances, you neeu to set the
numberOfLines piopeity ol youi laLel to 0.
Il you want youi laLel`s liame to stay static anu you want the lont insiue youi laLel to
aujust itsell to lit into the Lounuaiies ol the laLel, you neeu to set the adjustsFontSize
ToFitWidth piopeity ol youi laLel to YES. Foi instance, il the height ol oui laLel was
23.0f, as we see in Figuie 2-51, we coulu aujust the lont ol the laLel to lit into the
Lounuaiies. Heie is how it woiks:
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
CGRect labelFrame = CGRectMake(0.0f,
0.0f,
100.0f,
23.0f);
self.myLabel = [[UILabel alloc] initWithFrame:labelFrame];
self.myLabel.adjustsFontSizeToFitWidth = YES;
self.myLabel.text = @"iOS 6 Programming Cookbook";
self.myLabel.font = [UIFont boldSystemFontOfSize:14.0f]; self.myLabel.center =
self.view.center;
[self.view addSubview:self.myLabel];
}
180 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
2.18 Customizing the UILabel
Problem
You want to Le aLle to customize the appeaiance ol youi laLels, liom shauow settings
to alignment settings.
Solution
Use the lollowing piopeities ol the UILabel class, uepenuing on youi ieguiiements:
shadowColor
This piopeity is ol type UIColor anu, as its name shows, it specilies the coloi ol the
uiopshauow to ienuei loi youi laLel. Il you aie setting this piopeity, you shoulu
also set the shadowOffset piopeity.
shadowOffset
This piopeity is ol type CGSize anu it specilies the ollset ol the uiopshauow liom
the text. Foi instance, il you set this piopeity to (1, 0), the uiopshauow will appeai
1 point to the iight ol the text. Il you set this piopeity to (1, 2), the uiopshauow
will appeai 1 point to the iight anu 2 points uown liom the text. Il you set this
piopeity to (-2, -10), the uiopshauow will ienuei 2 points to the lelt anu 10 points
aLove the text.
numberOfLines
This piopeity is an integei that specilies how many lines ol text the laLel is aLle to
ienuei. By uelault, this piopeity`s value is set to 1, meaning any laLel that you
cieate Ly uelault can hanule 1 line ol text. Il you want 2 lines ol text, loi instance,
set this piopeity to 2. Il you want unlimiteu lines ol text to Le ienueieu in youi
text lielu oi you simply uon`t know how many lines ol text you will enu up uis-
playing, set this piopeity to 0. (I know, it`s ieally stiange. Insteau ol NSInteger
Max oi something similai, Apple has ueciueu that 0 means unlimiteu!)
lineBreakMode
This piopeity is ol type NSLineBreakMode anu specilies how you want to line-wiap
the text insiue youi text lielu. Foi instance, il you set this piopeity to NSLineBreak
ByWordWrapping, woius will Le kept togethei, Lut the stiing will Le wiappeu to the
next line il theie is not enough space to uisplay it. Alteinatively, il you set this
piopeity to NSLineBreakByCharWrapping, woius may Le Lioken acioss lines when
text is wiappeu. You woulu pioLaLly use NSLineBreakByCharWrapping only il the
space is veiy tight anu you neeu to lit as much inloimation as possiLle on the scieen.
I peisonally uo not iecommenu using this option il you want to keep a consistent
anu cleai usei inteilace.
2.18 Customizing the UILabel | 181
www.it-ebooks.info
textAlignment
This piopeity is ol type NSTextAlignment anu sets the hoiizontal alignment ol the
text in youi laLel. Foi instance, you can set the value ol this piopeity to NSText
AlignmentCenter to hoiizontally centei-align youi text.
textColor
This piopeity is ol type UIColor anu uelines the coloi ol the text insiue the laLel.
font
This piopeity ol type UIFont specilies the lont with which the text insiue youi laLel
will get ienueieu.
adjustsFontSizeToFitWidth
This piopeity is ol type BOOL. Vhen set to YES, it will change the size ol the lont to
lit youi laLel. Foi instance, il you have a small laLel anu the text you aie tiying to
set in it is too Lig to lit, il this piopeity is set to YES, the iuntime will automatically
ieuuce the lont size ol youi laLel to make suie the text will lit into the laLel. In
contiast, il this piopeity is set to NO, the cuiient line/woiu/chaiactei wiapping
option is taken into account anu youi text will Le ienueieu in an incomplete man-
nei with just a lew woius Leing uisplayeu.
Discussion
LaLels aie one ol the easiest UI components we can utilize in oui applications. Although
laLels aie simple, they aie ieally poweilul. Customization ol laLels is theieloie veiy
impoitant in oiuei to uelivei the Lest usei expeiience. Foi this ieason, Apple has given
us plenty ol ways to customize the instances ol UILabel. Let us have a look at an ex-
ample. Ve`ll cieate a simple Single View Application with one view contiollei, place a
simple laLel at the centei ol the scieen with a huge lont, anu wiite iOS SDK in it. Ve
will set the Lackgiounu coloi ol oui view to white, the text coloi ol oui laLel to Llack,
anu the shauow coloi ol oui laLel to light giay. Ve will make suie a uiopshauow
appeais at the Lottom iighthanu siue ol oui laLel. Figuie 2-53 shows the ellect oui app
shoulu piouuce.
Anu heie is oui coue to achieve this:
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong) UILabel *label;
@end
@implementation ViewController
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.label = [[UILabel alloc] init];
self.label.backgroundColor = [UIColor clearColor];
self.label.text = @"iOS SDK";
self.label.font = [UIFont boldSystemFontOfSize:70.0f];
182 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
self.label.textColor = [UIColor blackColor];
self.label.shadowColor = [UIColor lightGrayColor];
self.label.shadowOffset = CGSizeMake(2.0f, 2.0f);
[self.label sizeToFit];
self.label.center = self.view.center;
[self.view addSubview:self.label];
}
@end
See Also
Recipe 2.17; Recipe 2.30
2.19 Accepting User Text Input with UITextField
Problem
You want to accept text input in youi usei inteilace.
Solution
Use the UITextField class.
Iigurc 2-53. How our |abc| is custonizcd and rcndcrcd on thc scrccn
2.19 Accepting User Text Input with UITextField | 183
www.it-ebooks.info
Discussion
A text lielu is veiy much like a laLel in that it can uisplay text, Lut a text lielu can also
accept text entiy at iuntime. Figuie 2-5+ shows two text lielus in the Twittei section
ol the Settings app on an iPhone.
Iigurc 2-51. Uscrnanc and password tcxt jic|ds a||owing tcxt cntry
A text lielu allows only a single line ol text to Le input/uisplayeu. As a
iesult, the uelault height ol a text lielu is only 31 points. In Inteilace
Builuei, this height cannot Le mouilieu, Lut il you aie cieating youi text
lielu in coue, you can change the text lielu`s height. A change in height,
though, will not change the numLei ol lines you can ienuei in a text
lielu, which is always 1.
Let`s stait with the heauei lile ol oui view contiollei to ueline oui text lielu:
#import <UIKit/UIKit.h>
@interface Accepting_User_Text_Input_with_UITextFieldViewController
: UIViewController
@property (nonatomic, strong) UITextField *myTextField;
@end
184 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
Anu then let`s cieate the text lielu:
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
CGRect textFieldFrame = CGRectMake(0.0f,
0.0f,
200.0f,
31.0f);
self.myTextField = [[UITextField alloc]
initWithFrame:textFieldFrame];
self.myTextField.borderStyle = UITextBorderStyleRoundedRect;
self.myTextField.contentVerticalAlignment =
UIControlContentVerticalAlignmentCenter;
self.myTextField.textAlignment = UITextAlignmentCenter;
self.myTextField.text = @"Sir Richard Branson";
self.myTextField.center = self.view.center;
[self.view addSubview:self.myTextField];
}
Beloie looking at the uetails ol the coue, let`s liist have a look at the iesults (Figuie 2-55).
Iigurc 2-55. A sinp|c tcxt jic|d with ccntcr a|igncd tcxt
In oiuei to cieate this text lielu, we useu vaiious piopeities ol UITextField. These aie:
2.19 Accepting User Text Input with UITextField | 185
www.it-ebooks.info
borderStyle
This piopeity is ol type UITextBorderStyle anu specilies how the text lielu shoulu
ienuei its Loiueis.
contentVerticalAlignment
This value is ol type UIControlContentVerticalAlignment anu tells the text lielu
how the text shoulu appeai, veitically, in the Lounuaiies ol the contiol. Il we uiun`t
centei the text veitically, it woulu appeai on the top-lelt coinei ol the text lielu Ly
uelault.
textAlignment
This piopeity is ol type UITextAlignment anu specilies the hoiizontal alignment ol
the text in a text lielu. In this example, we have centeieu the text hoiizontally (as
well as veitically).
text
This is a ieau/wiite piopeity: you can Loth ieau liom it anu wiite to it. Reauing
liom it will ietuin the text lielu`s cuiient text anu wiiting to it will set the text lielu`s
text to the value that you specily.
A text lielu senus uelegate messages to its uelegate oLject. These messages get sent, loi
instance, when the usei staits euiting the text insiue a text lielu, when the usei enteis
any chaiactei into the text lielu (changing its contents in any way), anu when the usei
linishes euiting the lielu (Ly leaving the lielu). To get notilieu ol these events, set the
delegate piopeity ol the text lielu to youi oLject. The uelegate ol a text lielu must
conloim to the UITextFieldDelegate piotocol, so let`s liist take caie ol this:
#import <UIKit/UIKit.h>
@interface Accepting_User_Text_Input_with_UITextFieldViewController
: UIViewController <UITextFieldDelegate>
@property (nonatomic, strong) UITextField *myTextField;
@end
Holu uown the Commanu key on youi computei anu click on the UITextFieldDele
gate piotocol in Xcoue. You will see all the methous that this piotocol gives you contiol
ovei. Heie aie those methous with uesciiption ol when they get calleu:
textFieldShouldBeginEditing:
A methou that ietuins a BOOL telling the text lielu (the paiametei to this methou)
whethei it shoulu stait getting euiteu Ly the usei oi not. Retuin NO il you uon`t
want the usei to euit youi text lielu. This methou gets liieu as soon as the usei taps
on the text lielu with the goal ol euiting its content (assuming the text lielu allows
euiting).
textFieldDidBeginEditing:
Gets calleu when the text lielu staits to get euiteu Ly the usei. This methou gets
calleu when the usei has alieauy tappeu on the text lielu anu the textFieldShould
186 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
BeginEditing: uelegate methou ol the text lielu ietuineu YES, telling the text lielu
it is OK loi the usei to euit the content ol the text lielu.
textFieldShouldEndEditing:
Retuins a BOOL telling the text lielu whethei it shoulu enu its cuiient euiting session
oi not. This methou gets calleu when the usei is aLout to leave the text lielu oi the
liist iesponuei is switching to anothei uata entiy lielu. Il you ietuin NO liom this
methou, the usei will not Le aLle to switch to anothei text entiy lielu, anu the
keyLoaiu will stay on the scieen.
textFieldDidEndEditing:
Gets calleu when the euiting session ol the text lielu enus. This happens when the
usei ueciues to euit some othei uata entiy lielu oi uses a Lutton pioviueu Ly the
suppliei ol the app to uismiss the keyLoaiu shown loi the text lielu.
textField:shouldChangeCharactersInRange:replacementString:
Gets calleu whenevei the text insiue the text lielu is mouilieu. The ietuin value ol
this methou is a Boolean. Il you ietuin YES, you say that you allow the text to Le
changeu. Il you ietuin NO, the change in the text ol the text lielu will not Le con-
liimeu anu will not happen.
textFieldShouldClear:
Each text lielu has a c|car Lutton that is usually a ciiculai X Lutton. Vhen the usei
piesses this Lutton, the contents ol the text lielu will automatically get eiaseu. Ve
neeu to manually enaLle the cleai Lutton, though. Il you have enaLleu the cleai
Lutton anu you ietuin NO to this methou, that gives the usei the impiession that
youi app isn`t woiking, so make suie you know what you aie uoing. It is a veiy
pooi usei expeiience il the usei sees a cleai Lutton anu piesses it, Lut uoesn`t see
the text in the text lielu get eiaseu.
textFieldShouldReturn:
Gets calleu when the usei has piesseu the Retuin/Entei key on the keyLoaiu, tiying
to uismiss the keyLoaiu. You shoulu assign the text lielu as the liist iesponuei in
this methou.
Let`s mix this iecipe with Recipe 2.17 anu cieate a uynamic text laLel unuei oui text
lielu. Ve`ll also uisplay the total numLei ol chaiacteis enteieu in oui text lielu in the
laLel. Let`s stait with oui heauei lile:
#import <UIKit/UIKit.h>
@interface Accepting_User_Text_Input_with_UITextFieldViewController
: UIViewController <UITextFieldDelegate>
@property (nonatomic, strong) UITextField *myTextField;
@property (nonatomic, strong) UILabel *labelCounter;
@end
2.19 Accepting User Text Input with UITextField | 187
www.it-ebooks.info
Now loi the cieation ol the text lielu along with the laLel anu the text lielu uelegate
methous we ieguiie. Ve skip implementing many ol the UITextFieldDelegate methous,
Lecause we uon`t neeu all ol them in this example:
- (void) calculateAndDisplayTextFieldLengthWithText:(NSString *)paramText{
NSString *characterOrCharacters = @"Characters";
if ([paramText length] == 1){
characterOrCharacters = @"Character";
}
self.labelCounter.text = [NSString stringWithFormat:@"%lu %@",
(unsigned long)[paramText length],
characterOrCharacters];
}
- (BOOL) textField:(UITextField *)textField
shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string{
BOOL result = YES;
if ([textField isEqual:self.myTextField]){
NSString *wholeText =
[textField.text stringByReplacingCharactersInRange:range
withString:string];
[self calculateAndDisplayTextFieldLengthWithText:wholeText];
}
return result;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
return YES;
}
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
CGRect textFieldFrame = CGRectMake(38.0f,
30.0f,
220.0f,
31.0f);
self.myTextField = [[UITextField alloc]
initWithFrame:textFieldFrame];
self.myTextField.delegate = self;
self.myTextField.borderStyle = UITextBorderStyleRoundedRect;

self.myTextField.contentVerticalAlignment =
188 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
UIControlContentVerticalAlignmentCenter;
self.myTextField.textAlignment = UITextAlignmentCenter;
self.myTextField.text = @"Sir Richard Branson";
[self.view addSubview:self.myTextField];
CGRect labelCounterFrame = self.myTextField.frame;
labelCounterFrame.origin.y += textFieldFrame.size.height + 10;
self.labelCounter = [[UILabel alloc] initWithFrame:labelCounterFrame];
[self.view addSubview:self.labelCounter];
[self calculateAndDisplayTextFieldLengthWithText:self.myTextField.text];
}
One impoitant calculation we aie uoing is in the textField:shouldChangeCharactersIn
Range:replacementString: methou. Theie, we ueclaie anu use a vaiiaLle calleu whole
Text. Vhen this methou gets calleu, the replacementString paiametei specilies the
stiing that the usei has enteieu into the text lielu. You might Le thinking that the usei
can entei only one chaiactei at a time, so why can`t this lielu Le a char? But uon`t loiget
that the usei can paste a whole chunk ol text into a text lielu, so this paiametei neeus
to Le a stiing. The shouldChangeCharactersInRange paiametei specilies wheie, in teims
ol location insiue the text lielu`s text, the usei is enteiing the text. So using these two
paiameteis, we will cieate a stiing that liist ieaus the whole text insiue the text lielu
anu then uses the given iange to place the new text insiue the olu text. Vith this, we
will come up with the text that will appeai in the text lielu ajtcr the textField:should
ChangeCharactersInRange:replacementString: methou ietuins YES. Figuie 2-56 shows
how oui app looks when it gets iun on the simulatoi.
Iigurc 2-5. Rcsponding to dc|cgatc ncssagcs oj a tcxt jic|d
2.19 Accepting User Text Input with UITextField | 189
www.it-ebooks.info
In auuition to uisplaying text, a text lielu can also uisplay a p|accho|dcr. A placeholuei
is the text uisplayeu bcjorc the usei has enteieu any text in the text lielu, while the text
lielu`s text piopeity is empty. This can Le any stiing that you wish, anu setting it will
help give the usei an inuication as to what this text lielu is loi. Many use this placeholuei
to tell the usei what type ol value she can entei in that text lielu. Foi instance, in
Figuie 2-5+, the two text lielus (useiname anu passwoiu) have placeholueis that say
Reguiieu. You can use the placeholder piopeity ol the text lielu to set oi get the
cuiient placeholuei. Heie is an example:
self.myTextField = [[UITextField alloc]
initWithFrame:textFieldFrame];
self.myTextField.delegate = self;
self.myTextField.borderStyle = UITextBorderStyleRoundedRect;
self.myTextField.contentVerticalAlignment =
UIControlContentVerticalAlignmentCenter;
self.myTextField.textAlignment = UITextAlignmentCenter;
self.myTextField.placeholder = @"Enter text here...";
[self.view addSubview:self.myTextField];
The iesults aie shown in Figuie 2-57.
Iigurc 2-57. A p|accho|dcr is shown whcn thc uscr has not cntcrcd any tcxt in a tcxt jic|d
Text lielus have two ieally neat piopeities calleu leftView anu rightView. These two
piopeities aie ol type UIView anu aie ieau/wiite. They appeai, as theii names imply, on
the lelt anu the iight siue ol a text lielu il you assign a view to them. One place you
190 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
might use a lelt view, loi instance, is il you aie uisplaying a cuiiency text lielu wheie
you woulu like to uisplay the cuiiency ol the usei`s cuiient countiy in the lelt view, as
a UILabel. Heie is how we can accomplish that:
UILabel *currencyLabel = [[UILabel alloc] initWithFrame:CGRectZero];
currencyLabel.text = [[[NSNumberFormatter alloc] init] currencySymbol];
currencyLabel.font = self.myTextField.font;
[currencyLabel sizeToFit];
self.myTextField.leftView = currencyLabel;
self.myTextField.leftViewMode = UITextFieldViewModeAlways;
Il we simply assign a view to the leftView oi to the rightView piopeities ol a text lielu,
those views will not appeai automatically Ly uelault. Vhen they show up on the scieen
uepenus on the moue that goveins theii appeaiance, anu you can contiol that moue
using the leftViewMode anu rightViewMode piopeities, iespectively. These moues aie ol
type UITextFieldViewMode:
typedef enum {
UITextFieldViewModeNever,
UITextFieldViewModeWhileEditing,
UITextFieldViewModeUnlessEditing,
UITextFieldViewModeAlways
} UITextFieldViewMode;
So il, loi instance, you set the lelt view moue to UITextFieldViewModeWhileEditing anu
assign a value to it, it will appeai only while the usei is euiting the text lielu. Conveisely,
il you set this value to UITextFieldViewModeUnlessEditing, the lelt view will appeai only
while the usei is not euiting the text lielu. As soon as euiting staits, the lelt view will
uisappeai. Let`s have a look at oui coue now in the simulatoi (Figuie 2-5S).
Iigurc 2-58. A tcxt jic|d with a |cjt vicw
2.19 Accepting User Text Input with UITextField | 191
www.it-ebooks.info
See Also
Recipe 2.17
2.20 Displaying Long Lines of Text with UITextView
Problem
You want to uisplay multiple lines ol text in youi UI insiue one sciollaLle view.
Solution
Use the UITextView class.
Discussion
The UITextView class can uisplay multiple lines ol text anu contain sciollaLle content,
meaning that il the contents iun oll the Lounuaiies ol the text view, the text view`s
inteinal components allow the usei to scioll the text up anu uown to see uilleient paits
ol the text. An example ol a text view in an iOS app is the Notes app on the iPhone
(Figuie 2-59).
Iigurc 2-59. Notcs app on thc iPhonc uscs a tcxt vicw to rcndcr tcxt
192 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
Let`s cieate a text view anu see how it woiks. Ve stait oll Ly ueclaiing the text view in
oui view contiollei`s heauei lile:
#import <UIKit/UIKit.h>
@interface Displaying_Long_Lines_of_Text_with_UITextViewViewController
: UIViewController
@property (nonatomic, strong) UITextView *myTextView;
@end
Now it`s time to cieate the text view itsell. Ve will make the text view as Lig as the
view contiollei`s view:
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.myTextView = [[UITextView alloc] initWithFrame:self.view.bounds];
self.myTextView.text = @"Some text here...";
self.myTextView.font = [UIFont systemFontOfSize:16.0f];
[self.view addSubview:self.myTextView];
}
Now let`s iun the app in iOS Simulatoi anu see how it looks (Figuie 2-60).
Iigurc 2-0. A tcxt vicw consuning thc cntirc boundary oj thc scrccn
Il you tap on the text lielu, you will notice a keyLoaiu pop up liom the Lottom ol the
scieen, concealing almost hall the entiie aiea ol the text view. That means il the usei
2.20 Displaying Long Lines of Text with UITextView | 193
www.it-ebooks.info
staits typing text anu gets to the miuule ol the text view, the iest ol the text that she
types will not Le visiLle to hei (Figuie 2-61).
Iigurc 2-1. Kcyboard concca|ing ha|j thc sizc oj a tcxt vicw
To iemeuy this, we have to listen loi ceitain notilications:
UIKeyboardWillShowNotification
Gets sent Ly the system whenevei the keyLoaiu is Liought up on the scieen loi any
component, Le it a text lielu, a text view, etc.
UIKeyboardDidShowNotification
Gets sent Ly the system when the keyLoaiu has alieauy Leen uisplayeu.
UIKeyboardWillHideNotification
Gets sent Ly the system when the keyLoaiu is aLout to hiue.
UIKeyboardDidHideNotification
Gets sent Ly the system when the keyLoaiu is now lully hiuuen.
The keyLoaiu notilications contain a uictionaiy, accessiLle thiough the
userInfo piopeity, that specilies the Lounuaiies ol the keyLoaiu on the
scieen. This piopeity is ol type NSDictionary. One ol the keys in this
uictionaiy is UIKeyboardFrameEndUserInfoKey, which contains an oLject
ol type NSValue that itsell contains the iectangulai Lounuaiies ol the
keyLoaiu when it is lully shown. This iectangulai aiea is uenoteu with
a CGRect.
So oui stiategy is to linu out when the keyLoaiu is getting uisplayeu anu then somehow
iesize oui text view. Foi this, we will use the contentInset piopeity ol UITextView to
specily the maigins ol contents in the text view liom top, lelt, Lottom, anu iight:
194 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
- (void) handleKeyboardDidShow:(NSNotification *)paramNotification{
/* Get the frame of the keyboard */
NSValue *keyboardRectAsObject =
[[paramNotification userInfo]
objectForKey:UIKeyboardFrameEndUserInfoKey];
/* Place it in a CGRect */
CGRect keyboardRect;
[keyboardRectAsObject getValue:&keyboardRect];
/* Give a bottom margin to our text view that makes it
reach to the top of the keyboard */
self.myTextView.contentInset =
UIEdgeInsetsMake(0.0f,
0.0f,
keyboardRect.size.height,
0.0f);
}
- (void) handleKeyboardWillHide:(NSNotification *)paramNotification{
/* Make the text view as big as the whole view again */
self.myTextView.contentInset = UIEdgeInsetsZero;
}
- (void) viewWillAppear:(BOOL)paramAnimated{
[super viewWillAppear:paramAnimated];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(handleKeyboardDidShow:)
name:UIKeyboardDidShowNotification
object:nil];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(handleKeyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
self.view.backgroundColor = [UIColor whiteColor];
self.myTextView = [[UITextView alloc] initWithFrame:self.view.bounds];
self.myTextView.text = @"Some text here...";
self.myTextView.font = [UIFont systemFontOfSize:16.0f];
[self.view addSubview:self.myTextView];
}
- (void) viewWillDisappear:(BOOL)paramAnimated{
[super viewWillDisappear:paramAnimated];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
2.20 Displaying Long Lines of Text with UITextView | 195
www.it-ebooks.info
In this coue, we stait looking loi keyLoaiu notilications in viewWillAppear: anu we stop
listening to keyLoaiu notilications in viewWillDisappear:. Removing youi view con-
tiollei as the listenei is impoitant, Lecause when youi view contiollei is no longei
uisplayeu, you pioLaLly uon`t want to ieceive keyLoaiu notilications liieu Ly any othei
view contiollei. Theie may Le times when a view contiollei in the Lackgiounu neeus
to ieceive notilications, Lut these aie iaie anu you must noimally make suie to stop
listening loi notilications in viewWillDisappear:. I`ve seen many applications piogiam-
meis Lieak theii apps Ly not taking caie ol this simple logic.
Il you intenu to change youi UI stiuctuie when the keyLoaiu gets uis-
playeu anu when the keyLoaiu is uismisseu, the only methou that you
can iely on is to use the keyLoaiu notilications. Delegate messages ol
UITextField get liieu when the text lielu is getting euiteu, whethei theie
is a solt keyLoaiu on the scieen oi not. RememLei, a usei can have a
Bluetooth keyLoaiu connecteu to his iOS uevice anu use it to euit the
content ol text lielus anu any othei uata entiy in youi apps. In the case
ol a Bluetooth keyLoaiu, no solt keyLoaiu will Le uisplayeu on the
scieenanu il you change youi UI when youi text lielus stait to get
euiteu, you might unnecessaiily change the UI while the Bluetooth key-
Loaiu usei is euiting text.
Now, il the usei tiies to entei some text into the text view, the keyLoaiu will pop up,
anu we take the height ol the keyLoaiu anu assign that value as the Lottom maigin ol
the contents insiue the text view. This makes oui text view`s contents smallei in size
anu allows the usei to entei as much text as she wishes without the keyLoaiu Llocking
hei view.
2.21 Adding Buttons to the User Interface with UIButton
Problem
You want to uisplay a Lutton on youi UI anu hanule the touch events loi that Lutton.
Solution
Use the UIButton class.
Discussion
Buttons allow useis to initiate an action in youi apps. Foi instance, the iClouu Settings
Lunule in the Settings app piesents a Delete Account Lutton in Figuie 2-62. Il you piess
this Lutton, the iClouu app will take action. The action uepenus on the app. Not all
apps act the same when a Delete Lutton is piesseu Ly the usei. Buttons can have images
in them as well as text, as we will soon see.
196 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
Iigurc 2-2. A Dc|ctc Account button
A Lutton can assign actions to uilleient tiiggeis. Foi instance, a Lutton can liie one
action when the usei puts hei lingei uown on the Lutton anu anothei action when she
lilts hei lingei oll the Lutton. These Lecome actions anu the oLjects implementing the
actions Lecome taigets. Let`s go aheau anu ueline a Lutton in oui view contiollei`s
heauei lile:
#import <UIKit/UIKit.h>
@interface Adding_Buttons_to_the_User_Interface_with_UIButtonViewController
: UIViewController
@property (nonatomic, strong) UIButton *myButton;
@end
The uelault height ol UIButton is 37.0l points.
Next, we move on to the implementation ol the Lutton (Figuie 2-63):
- (void) buttonIsPressed:(UIButton *)paramSender{
NSLog(@"Button is pressed.");
2.21 Adding Buttons to the User Interface with UIButton | 197
www.it-ebooks.info
}- (void) buttonIsTapped:(UIButton *)paramSender{
NSLog(@"Button is tapped.");
}
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.myButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.myButton.frame = CGRectMake(110.0f,
200.0f,
100.0f,
37.0f);
[self.myButton setTitle:@"Press Me"
forState:UIControlStateNormal];
[self.myButton setTitle:@"I'm Pressed"
forState:UIControlStateHighlighted];
[self.myButton addTarget:self
action:@selector(buttonIsPressed:)
forControlEvents:UIControlEventTouchDown];
[self.myButton addTarget:self
action:@selector(buttonIsTapped:)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.myButton];
}
Iigurc 2-3. A roundcd rcctang|c button in thc nidd|c oj thc scrccn
198 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
In this example coue, we aie using the setTitle:forState: methou ol oui Lutton to set
two uilleient titles loi the Lutton. The title is the text that gets uisplayeu on the Lutton.
A Lutton can Le in uilleient states at uilleient timessuch as noimal anu highlighteu
(piesseu uown)anu can uisplay a uilleient title in each state. So in this case, when
the usei sees the Lutton loi the liist time, he will ieau Press Me. Once he piesses the
Lutton, the title ol the Lutton will change to I'm Pressed.
Ve uiu a similai thing with the actions that the Lutton liies. Ve useu the addTar
get:action:forControlEvents: methou to specily two actions loi oui Lutton:
1. An action to Le liieu when the usei piesses the Lutton uown.
2. Anothei action to Le liieu when the usei has piesseu the Lutton anu has lilteu his
lingei oll the Lutton. This completes a touch-up-insidc action.
The othei thing that you neeu to know aLout UIButton is that it must always Le assigneu
a type, which you uo Ly initializing it with a call to the class methou buttonWithType,
as shown in the example coue. As the paiametei to this methou, pass a value ol type
UIButtonType:
typedef enum {
UIButtonTypeCustom = 0,
UIButtonTypeRoundedRect,
UIButtonTypeDetailDisclosure,
UIButtonTypeInfoLight,
UIButtonTypeInfoDark,
UIButtonTypeContactAdd,
} UIButtonType;
A Lutton can also ienuei an image. An image will ieplace the uelault look anu leel ol
the Lutton. Vhen you have an image oi seiies ol images that you want to assign to
uilleient states ol a Lutton, make suie youi Lutton is ol type UIButtonTypeCustom. I have
piepaieu two images heie: one loi the noimal state ol the Lutton anu the othei loi the
highlighteu (piesseu) state. I will now cieate my custom Lutton anu assign two images
to it. One image is loi the noimal state ol the Lutton, anu the othei loi the highlighteu
state:
UIImage *normalImage = [UIImage imageNamed:@"NormalBlueButton.png"];
UIImage *highlightedImage = [UIImage imageNamed:@"HighlightedBlueButton"];
self.myButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.myButton.frame = CGRectMake(110.0f,
200.0f,
100.0f,
37.0f);
[self.myButton setBackgroundImage:normalImage
forState:UIControlStateNormal];
[self.myButton setTitle:@"Normal"
forState:UIControlStateNormal];
[self.myButton setBackgroundImage:highlightedImage
2.21 Adding Buttons to the User Interface with UIButton | 199
www.it-ebooks.info
forState:UIControlStateHighlighted];
[self.myButton setTitle:@"Pressed"
forState:UIControlStateHighlighted];
Figuie 2-6+ shows what the app looks like when we iun it in the iOS Simulatoi. Ve
aie using the setBackgroundImage:forState: methou ol the Lutton to set a Lackgiounu
image. Vith a Lackgiounu image, we can still use the setTitle:forState: methous to
ienuei text on top ol the Lackgiounu image. Il youi images contain text anu you uon`t
neeu the title loi a Lutton, you can insteau use the setImage:forState: methou oi simply
iemove the titles liom the Lutton.
Iigurc 2-1. A button with a bac|ground inagc
2.22 Displaying Images with UIImageView
Problem
You woulu like to uisplay images to youi useis on youi app`s UI.
Solution
Use the UIImageView class.
Discussion
The UIImageView is one ol the least complicateu classes in the iOS SDK. As you know,
an image view is iesponsiLle loi uisplaying images. Theie aie no tips oi tiicks involveu.
All you have to uo is to instantiate an oLject ol type UIImageView anu auu it to youi
200 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
views. Now, I have a pictuie ol Apple MacBook Aii anu I woulu like to uisplay it in an
image view. Let`s stait with oui view contiollei`s heauei lile:
#import <UIKit/UIKit.h>
@interface Displaying_Images_with_UIImageViewViewController
: UIViewController
@property (nonatomic, strong) UIImageView *myImageView;
@end
Go aheau anu instantiate the image view anu place the image in it:
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
UIImage *macBookAir = [UIImage imageNamed:@"MacBookAir.png"];
self.myImageView = [[UIImageView alloc] initWithImage:macBookAir];
self.myImageView.center = self.view.center;
[self.view addSubview:self.myImageView];
}
Now il we iun the app, we will see something similai to Figuie 2-65.
Iigurc 2-5. An inagc vicw that is too big to jit on thc scrccn
I shoulu mention that the MacBook Aii image that I`m loauing into this image view is
9S0519 pixels anu as you can see, it ceitainly uoesn`t lit into the iPhone scieen. So
how uo we solve this pioLlem? Fiist, we neeu to make suie that we aie initializing oui
image view using the initWithFrame: methou, insteau ol the initWithImage: methou
2.22 Displaying Images with UIImageView | 201
www.it-ebooks.info
as the lattei will set the wiuth anu height ol the image view to the exact wiuth anu
height ol the image. So let`s iemeuy that liist:
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
UIImage *macBookAir = [UIImage imageNamed:@"MacBookAir.png"];
self.myImageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
self.myImageView.image = macBookAir;
self.myImageView.center = self.view.center;
[self.view addSubview:self.myImageView];
}
So how uoes the app look now? See Figuie 2-66.
Iigurc 2-. An inagc whosc width is squishcd to jit thc width oj thc scrccn
This isn`t ieally what we wanteu to uo, is it? Ol couise, we got the liame ol the image
view iight, Lut the way the image is ienueieu in the image view isn`t guite iight. So
what can we uo? Ve can iectily this Ly setting the contentMode piopeity ol the image
view. This piopeity is ol type UIContentMode:
typedef enum {
UIViewContentModeScaleToFill,
UIViewContentModeScaleAspectFit,
UIViewContentModeScaleAspectFill,
UIViewContentModeRedraw,
UIViewContentModeCenter,
UIViewContentModeTop,
UIViewContentModeBottom,
202 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
UIViewContentModeLeft,
UIViewContentModeRight,
UIViewContentModeTopLeft,
UIViewContentModeTopRight,
UIViewContentModeBottomLeft,
UIViewContentModeBottomRight,
} UIViewContentMode;
Heie is an explanation ol some ol the most uselul values in the UIViewContentMode
enumeiation:
UIViewContentModeScaleToFill
This will scale the image insiue the image view to lill the entiie Lounuaiies ol the
image view.
UIViewContentModeScaleAspectFit
This will make suie the image insiue the image view will have the iight aspect iatio
anu lits insiue the image view`s Lounuaiies.
UIViewContentModeScaleAspectFill
This will makes suie the image insiue the image view will have the iight aspect iatio
anu lills the entiie Lounuaiies ol the image view. Foi this value to woik piopeily,
make suie that you have set the clipsToBounds piopeity ol the image view to YES.
The clipsToBounds piopeity ol UIView uenotes whethei the suLviews ol
that view shoulu Le clippeu il they go outsiue the Lounuaiies ol the view.
You use this piopeity il you want to Le aLsolutely ceitain that the suL-
views ol a specilic view will not get ienueieu outsiue the Lounuaiies ol
that view (oi that they uo get ienueieu outsiue the Lounuaiies, uepenu-
ing on youi ieguiiements).
So to make suie the image lits into the image view`s Lounuaiies anu that the aspect
iatio ol the image is iight, we neeu to use the UIViewContentModeScaleAspectFit content
moue:
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
UIImage *macBookAir = [UIImage imageNamed:@"MacBookAir.png"];
self.myImageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
self.myImageView.contentMode = UIViewContentModeScaleAspectFit;
self.myImageView.image = macBookAir;
self.myImageView.center = self.view.center;
[self.view addSubview:self.myImageView];
}
Anu the iesults will Le exactly what we expecteu (Figuie 2-67).
2.22 Displaying Images with UIImageView | 203
www.it-ebooks.info
Iigurc 2-7. Thc aspcct ratio oj inagc vicw is abso|utc|y spot on
2.23 Creating Scrollable Content with UIScrollView
Problem
You have content that neeus to get uisplayeu on the scieen, Lut it ieguiies moie ieal
estate than what the uevice`s scieen allows loi.
Solution
Use the UIScrollView class.
Discussion
Scioll views aie one ol the leatuies that make iOS a ieally neat opeiating system. They
aie piactically eveiywheie. You`ve Leen to the Clock oi the Contacts apps, haven`t you?
Have you seen how the content can Le sciolleu up anu uown? Vell that`s the magic ol
scioll views.
Theie ieally is one Lasic concept you neeu to leain aLout scioll views: the contcnt
sizc, which lets the scioll view conloim to the size ol what it`s uisplaying The content
size is a value ol type CGSize that specilies the wiuth anu the height ol the contents ol
a scioll view. A scioll view, as its name implies, is a suLclass ol UIView, so you can simply
auu youi views to a scioll view using its addSubview: methou. Howevei, you neeu to
make suie that the scioll view`s content size is set piopeily, otheiwise, the contents
insiue the scioll view won`t scioll.
204 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
As an example, let`s linu a Lig image anu loau it to an image view. I will auu the same
image that I useu in Recipe 2.22: a MacBook Aii image. I will auu it to an image view
anu place it in a scioll view. Then I will use the contentSize ol the scioll view to make
suie this content size is egual to the size ol the image (wiuth anu height). Fiist, let`s
stait with the heauei lile ol oui view contiollei:
#import <UIKit/UIKit.h>
@interface Creating_Scrollable_Content_with_UIScrollViewViewController
: UIViewController
@property (nonatomic, strong) UIImageView *myImageView;
@property (nonatomic, strong) UIScrollView *myScrollView;
@end
Anu let`s place the image view insiue the scioll view:
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
UIImage *imageToLoad = [UIImage imageNamed:@"MacBookAir.png"];
self.myImageView = [[UIImageView alloc] initWithImage:imageToLoad];
self.myScrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
[self.myScrollView addSubview:self.myImageView];
self.myScrollView.contentSize = self.myImageView.bounds.size;
[self.view addSubview:self.myScrollView];
}
Il you now loau up the app in iOS Simulatoi, you will see that you can scioll the image
hoiizontally anu veitically. The challenge heie, ol couise, is to pioviue an image that
is Liggei than the scieen`s Lounuaiies. Foi example, il you pioviue an image that is
2020 pixels, the scioll view won`t Le ol much use to you. In lact, it woulu Le wiong
to place such an image into a scioll view, as the scioll view woulu piactically Le useless
in that scenaiio. Theie woulu Le nothing to scioll Lecause the image is smallei than
the scieen size.
One ol the hanuy leatuies ol UIScrollView is suppoit loi uelegation, so that it can iepoit
ieally impoitant events to the app thiough a uelegate. A uelegate loi a scioll view must
conloim to the UIScrollViewDelegate piotocol. Some ol the methous uelineu in this
piotocol aie:
scrollViewDidScroll:
Gets calleu whenevei the contents ol a scioll view get sciolleu.
scrollViewWillBeginDecelerating:
Gets calleu when the usei sciolls the contents ol a scioll view anu lilts his lingei
oll ol the scieen, as the scioll view sciolls.
2.23 Creating Scrollable Content with UIScrollView | 205
www.it-ebooks.info
scrollViewDidEndDecelerating:
Gets calleu when the scioll view has linisheu sciolling its contents.
scrollViewDidEndDragging:willDecelerate:
Gets calleu when the usei linishes uiagging the contents ol the scioll view. This
methou is veiy similai to the scrollViewDidEndDecelerating: methou but you neeu
to Leai in minu that the usei can uiag the contents ol a scioll view without sciolling
the contents. She can simply put hei lingei on the content, move hei lingei to any
location on the scieen anu lilt hei lingei without giving the contents any momen-
tum to move. This is uiagging as opposeu to sciolling. Sciolling is similai to uiag-
ging, Lut the usei will give momentum to the contents` movement Ly lilting hei
lingei oll the scieen while the content is Leing uiaggeu aiounu, anu not waiting
loi the content to stop Leloie lilting the lingei oll the scieen. Diagging is compa-
iaLle to holuing uown the acceleiatoi in a cai oi peualing on a Licycle, wheieas
sciolling is compaiaLle to coasting in a cai oi on a Licycle.
So let`s auu some lun to oui pievious app. Now the goal is to set the alpha level ol the
image insiue oui image view to 0.50l (hall tianspaient) when the usei staits to scioll
the scioll view anu set this alpha Lack to 1.0l (opague) when the usei linishes sciolling.
Let`s Legin Ly conloiming to the UIScrollViewDelegate piotocol:
#import <UIKit/UIKit.h>
@interface Creating_Scrollable_Content_with_UIScrollViewViewController
: UIViewController <UIScrollViewDelegate>
@property (nonatomic, strong) UIImageView *myImageView;
@property (nonatomic, strong) UIScrollView *myScrollView;
@end
Then let`s implement this lunctionality:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
/* Gets called when user scrolls or drags */
self.myScrollView.alpha = 0.50f;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
/* Gets called only after scrolling */
self.myScrollView.alpha = 1.0f;
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView
willDecelerate:(BOOL)decelerate{
/* Make sure the alpha is reset even if the user is dragging */
self.myScrollView.alpha = 1.0f;
}
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
206 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
UIImage *imageToLoad = [UIImage imageNamed:@"MacBookAir.png"];
self.myImageView = [[UIImageView alloc] initWithImage:imageToLoad];
self.myScrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
[self.myScrollView addSubview:self.myImageView];
self.myScrollView.contentSize = self.myImageView.bounds.size;
self.myScrollView.delegate = self;
[self.view addSubview:self.myScrollView];
}
As you might have noticeu, scioll views have indicators. An inuicatoi is the little tiacking
line that appeais on the siues ol a scioll view when its contents aie getting sciolleu anu
moveu. Figuie 2-6S shows an example.
Iigurc 2-8. B|ac| indicators appcaring on thc right and botton oj a scro|| vicw
Inuicatois simply show the usei wheie the cuiient view is in ielation to the content
(top, hallway uown, etc.). You can contiol what the inuicatois look like Ly changing
the value ol the indicatorStyle piopeity. Foi instance, heie I have changeu the inui-
catoi style ol my scioll view to white:
self.myScrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
One ol the gieat leatuies ol scioll views is that they allow pagination. Pagination is the
same as sciolling, Lut locks the sciolling when the usei moves to the next pagc. You
have peihaps alieauy seen this il you`ve evei useu the Photos app on the iPhone oi iPau.
Vhen you aie looking at photos, you can swipe Letween them. Each swipe Liings the
next oi pievious photo onto the scieen. Youi swiping nevei sciolls all the way to the
enu oi all the way to the stait. Vhen the sciolling staits, the scioll view uetects the next
image to uisplay, sciolls anu Lounces to that image, anu stops the sciolling animation.
2.23 Creating Scrollable Content with UIScrollView | 207
www.it-ebooks.info
That`s pagination. Il you haven`t tiieu it alieauy, I uige you to uo so, Lecause otheiwise
I coulu go on anu on anu none ol this woulu make sense unless you lookeu at an app
that suppoits pagination.
Foi this example coue, I`ve piepaieu thiee images: an iPhone, iPau, anu a MacBook
Aii. I`ve placeu them in theii inuiviuual image views anu auueu them to a scioll view.
Then we can enaLle pagination Ly setting the value ol the pagingEnabled piopeity ol
the scioll view to YES:
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
UIImage *iPhone = [UIImage imageNamed:@"iPhone.png"];
UIImage *iPad = [UIImage imageNamed:@"iPad.png"];
UIImage *macBookAir = [UIImage imageNamed:@"MacBookAir.png"];
CGRect scrollViewRect = self.view.bounds;
self.myScrollView = [[UIScrollView alloc] initWithFrame:scrollViewRect];
self.myScrollView.pagingEnabled = YES;
self.myScrollView.contentSize = CGSizeMake(scrollViewRect.size.width * 3.0f,
scrollViewRect.size.height);
[self.view addSubview:self.myScrollView];
CGRect imageViewRect = self.view.bounds;
UIImageView *iPhoneImageView = [self newImageViewWithImage:iPhone
frame:imageViewRect];
[self.myScrollView addSubview:iPhoneImageView];
/* Go to next page by moving the x position of the next image view */
imageViewRect.origin.x += imageViewRect.size.width;
UIImageView *iPadImageView = [self newImageViewWithImage:iPad
frame:imageViewRect];
[self.myScrollView addSubview:iPadImageView];
/* Go to next page by moving the x position of the next image view */
imageViewRect.origin.x += imageViewRect.size.width;
UIImageView *macBookAirImageView =
[self newImageViewWithImage:macBookAir
frame:imageViewRect];
[self.myScrollView addSubview:macBookAirImageView];
}
Now we have thiee pages ol sciollaLle content (Figuie 2-69).
208 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
Iigurc 2-9. Scro||ing through pagcs in a pagc-cnab|cd scro|| vicw
2.24 Loading Web Pages with UIWebView
Problem
You want to loau a weL page uynamically iight insiue youi iOS app.
Solution
Use the UIWebView class.
Discussion
A weL view is what the Salaii Liowsei uses on iOS to loau weL content. You have the
whole powei ol Salaii in youi iOS apps thiough the UIWebView class. All you have to uo
is to place a weL view on youi UI anu use one ol its loauing methous:
loadData:MIMEType:textEncodingName:baseURL:
Loaus an instance ol NSData into the weL view.
loadHTMLString:baseURL:
Loaus an instance ol NSString into the weL view. The stiing shoulu Le a valiu
HTML, oi in othei woius, something that a weL Liowsei can ienuei.
loadRequest:
Loaus an instance ol NSURLRequest. This is uselul when you want to loau the con-
tents ol a iemote URL into a weL view insiue youi application.
Let`s see an example. Ve`ll stait with the heauei lile ol oui view contiollei:
2.24 Loading Web Pages with UIWebView | 209
www.it-ebooks.info
#import <UIKit/UIKit.h>
@interface Loading_Web_Pages_with_UIWebViewViewController
: UIViewController
@property (nonatomic, strong) UIWebView *myWebView;
@end
Now I woulu like to loau the stiing iOS 6 Programming Cookbook into the weL view. To
piove things aie woiking as expecteu anu that oui weL view is capaLle ol ienueiing
iich text, I will go aheau anu make the Programming pait Lolu while leaving the iest ol
the text intact (Figuie 2-70):
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.myWebView = [[UIWebView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:self.myWebView];
NSString *htmlString = @"iOS 6 Programming <strong>Cookbook</strong>";
[self.myWebView loadHTMLString:htmlString
baseURL:nil];
}
Iigurc 2-70. Loading rich tcxt into a wcb vicw
Anothei way to use a weL view is to loau a iemote URL into it. Foi this puipose, we
can use the loadRequest: methou. Let`s go aheau anu look at an example wheie we will
loau Apple`s main page into a weL view in oui iOS app (Figuie 2-71):
210 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.myWebView = [[UIWebView alloc] initWithFrame:self.view.bounds];
self.myWebView.scalesPageToFit = YES;
[self.view addSubview:self.myWebView];
NSURL *url = [NSURL URLWithString:@"http://www.apple.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.myWebView loadRequest:request];
}
Iigurc 2-71. App|c`s honc pagc |oadcd into a wcb vicw
It might take guite a while loi a weL view to loau the contents that you pass to it. You
might have noticeu that when loauing content in Salaii, you get a little activity inuicatoi
in the top-lelt coinei ol the scieen telling you that the uevice is Lusy loauing the con-
tents. Figuie 2-72 shows an example.
Iigurc 2-72. A progrcss bar indicating a |oading proccss
2.24 Loading Web Pages with UIWebView | 211
www.it-ebooks.info
iOS accomplishes this thiough uelegation. Ve will suLsciiLe as the uelegate ol a weL
view, anu the weL view will notily us when it staits to loau content. Vhen the content
is lully loaueu, we get a message liom the weL view inloiming us aLout this. Ve uo
this thiough the delegate piopeity ol the weL view. A uelegate ol a weL view must
conloim to the UIWebViewDelegate piotocol.
Let`s go aheau anu implement the little activity inuicatoi in oui view contiollei. Please
Leai in minu that the activity inuicatoi is alieauy a pait ol the application anu we uon`t
have to cieate it. Ve can contiol it using the setNetworkActivityIndicatorVisible:
methou ol UIApplication. So let`s stait with the heauei lile ol oui view contiollei:
#import <UIKit/UIKit.h>
@interface Loading_Web_Pages_with_UIWebViewViewController
: UIViewController <UIWebViewDelegate>
@property (nonatomic, strong) UIWebView *myWebView;
@end
Then, uo the implementation. Heie we will use thiee ol the methous ueclaieu in the
UIWebViewDelegate piotocol:
webViewDidStartLoad:
This methou gets calleu as soon as the weL view staits loauing content.
webViewDidFinishLoad:
This methou gets calleu as soon as the weL view linishes loauing content.
webView:didFailLoadWithError:
This methou gets calleu when the weL view stops loauing content, loi instance
Lecause ol an eiioi oi a Lioken netwoik connection.
- (void)webViewDidStartLoad:(UIWebView *)webView{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
}
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.myWebView = [[UIWebView alloc] initWithFrame:self.view.bounds];
self.myWebView.delegate = self;
self.myWebView.scalesPageToFit = YES;
[self.view addSubview:self.myWebView];
212 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
NSURL *url = [NSURL URLWithString:@"http://www.apple.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.myWebView loadRequest:request];
}
2.25 Presenting Master-Detail Views with
UISplitViewController
Problem
You want to take maximum auvantage ol iPau`s ielatively laige scieen Ly piesenting
two siue-Ly-siue view contiolleis.
Solution
Use the UISplitViewController class.
Discussion
Split view contiolleis aie piesent only on the iPau. Il you`ve useu an iPau, you`ve pioL-
aLly alieauy seen them. ]ust open the Settings app in lanuscape moue anu have a look.
Can you see the split view contiollei theie in Figuie 2-73?
A split view contiollei has lelt anu iight siues. The lelt siue uisplays the main settings,
anu tapping on each one ol those settings shows the uetails ol that setting item on the
iight siue ol the split view contiollei.
Nevei attempt to instantiate an oLject ol type UISplitViewController
on a uevice othei than an iPau. This will iaise an exception.
Apple has maue it extiemely easy to cieate split view contiollei Laseu applications.
Simply lollow these steps to cieate youi app Laseu on split view contiolleis:
1. In Xcoue, navigate to the File menu anu choose New New Pioject...
2. In the New Pioject scieen, pick iOS Application on the lelt siue anu then pick
Mastei-Detail Application (as shown in Figuie 2-7+) anu piess Next.
3. In this scieen, pick youi Piouuct Name anu make suie youi Device Family is Uni-
veisal. Ve want to make suie oui app iuns Loth on the iPhone anu the iPau. Once
you aie uone, piess Next (see Figuie 2-75).
2.25 Presenting Master-Detail Views with UISplitViewController | 213
www.it-ebooks.info
Iigurc 2-71. Pic|ing thc Mastcr-Dctai| App|ication projcct tcnp|atc in Xcodc
Iigurc 2-73. Sp|it vicw contro||cr in thc Scttings app on thc iPad
214 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
Iigurc 2-75. Sctting thc nastcr-dctai| projcct scttings in Xcodc
+. Now pick wheie you woulu like to save youi pioject. Once uone, piess the Cieate
Lutton (see Figuie 2-76).
Iigurc 2-7. Saving thc ncw nastcr-dctai| app|ication on dis|
2.25 Presenting Master-Detail Views with UISplitViewController | 215
www.it-ebooks.info
Now the pioject is cieateu. In the Scheme LieauciumL Lutton on the top-lelt coinei ol
Xcoue, make suie youi app is set to iun on the iPau Simulatoi insteau ol the iPhone
Simulatoi. Il you cieate a univeisal mastei-uetail app in Xcoue, Xcoue makes suie that
youi app iuns on the iPhone as well, Lut when you iun youi app on the iPhone, the
stiuctuie ol the app will Le uilleient. It will have a navigation contiollei with a view
contiollei insiue it, wheieas iunning the same app on the iPau will use a split view
contiollei with two view contiolleis insiue it.
Theie aie two liles that aie veiy impoitant to note in the split view contiollei pioject
template:
Root\icwContro||cr
The mastei view contiollei that appeais on the lelt siue ol the split view contiollei
on the iPau. On the iPhone, it is the liist view contiollei that the usei sees.
Dctai|\icwContro||cr
The uetail view contiollei that appeais on the iight siue ol the split view contiollei
on the iPau. On the iPhone, it is the view contiollei that gets pusheu onto the stack
once the usei taps on any ol the items on the ioot (liist, mastei) view contiollei.
Now you neeu to think aLout communication Letween the mastei anu the uetail view
contiollei. Do you want the communication to Le uone thiough the app uelegate, oi
uo you want the mastei view contiollei to senu messages to the uetail view contiollei
uiiectly? That`s ieally up to you.
Il you iun the app in iPau Simulatoi, you`ll notice that in lanuscape moue, you can see
oui mastei anu uetail view contiolleis in the split view contiollei, Lut as soon as you
iotate the oiientation to poitiait, youi mastei view contiollei is gone anu is ieplaceu
with a Mastei navigation Lutton on the top-lelt siue ol the navigation Lai ol the uetail
view contiollei. Although this is goou, we weien`t expecting it, since we weie com-
paiing it with the Settings app on the iPau. Il you iotate the settings app to poitiait on
an iPau, you can still see Loth the mastei anu the uetail view contiolleis. How can we
accomplish this? It tuins out Apple has exposeu an API to us thiough which we can uo
it. Simply go to the Dctai|\icwContro||cr.n lile anu implement this methou:
- (BOOL) splitViewController:(UISplitViewController *)svc
shouldHideViewController:(UIViewController *)vc
inOrientation:(UIInterfaceOrientation)orientation{
return NO;
}
This methou is availaLle only in iOS 5.0 SDK anu aLove.
Il you ietuin NO liom this methou, iOS will not hiue the mastei view contiollei in eithei
oiientation anu Loth the mastei anu the uetail view contiolleis will Le visiLle in Loth
216 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
lanuscape anu poitiait oiientations. Now that we have implementeu this methou, we
won`t neeu those two methous anymoie:
- (void)splitViewController:(UISplitViewController *)svc
willHideViewController:(UIViewController *)aViewController
withBarButtonItem:(UIBarButtonItem *)barButtonItem
forPopoverController: (UIPopoverController *)pc{
barButtonItem.title = @"Master";
NSMutableArray *items = [[self.toolbar items] mutableCopy];
[items insertObject:barButtonItem atIndex:0];
[self.toolbar setItems:items animated:YES];
self.popoverController = pc;
}
- (void)splitViewController:(UISplitViewController *)svc
willShowViewController:(UIViewController *)aViewController
invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem{
NSMutableArray *items = [[self.toolbar items] mutableCopy];
[items removeObjectAtIndex:0];
[self.toolbar setItems:items animated:YES];
self.popoverController = nil;
}
These methous weie theie simply to manage the navigation Lai Lutton loi us, Lut now
that we aie not using that Lutton any moie, we can get iiu ol the methous. You can
comment them out, oi just iemove them liom the Dctai|\icwContro||cr.n lile.
At the moment, communication Letween the mastei anu the uetail view contiollei
thiough messaging seems impossiLle, Lecause the mastei uoesn`t have a ieleience to
the uetail view contiollei. Let`s iemeuy that, shall we? The app uelegate is the oLject
that cieateu Loth these view contiolleis, so we can keep the ieleience to the uetail view
contiollei in app uelegate anu ieau it in the mastei view contiollei. Let`s auu a piopeity
to oui app uelegate anu call it detailViewController:
#import <UIKit/UIKit.h>
@class DetailViewController;
@interface Presenting_Master_Detail_Views_with_UISplitViewControllerAppDelegate
: UIResponder <UIApplicationDelegate>
@property (nonatomic, strong) UIWindow *window;
@property (nonatomic, strong) UINavigationController *navigationController;
@property (nonatomic, strong) UISplitViewController *splitViewController;
@property (nonatomic, strong)
DetailViewController *detailViewController;
@end
In the app uelegate`s implementation lile, we can see the application:didFinishLaun
chingWithOptions: selectoi. Finu this line ol coue in that methou:
2.25 Presenting Master-Detail Views with UISplitViewController | 217
www.it-ebooks.info
DetailViewController *detailViewController =
[[DetailViewController alloc] initWithNibName:@"DetailViewController_iPad"
bundle:nil];
Theie, the app will instantiate an oLject ol type DetailViewController anu will place it
insiue the split view contiollei. Howevei, as you can see, detailViewController in this
coue is a local vaiiaLle. It shauows oui piopeity that has the same name, so we neeu
to iemove the local vaiiaLle ueclaiation anu change it to this:
detailViewController =
[[DetailViewController alloc] initWithNibName:@"DetailViewController_iPad"
bundle:nil];
Now in the ioot view contiollei (mastei), linu this methou:
- (void) tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if ([[UIDevice currentDevice] userInterfaceIdiom]
== UIUserInterfaceIdiomPhone) {
DetailViewController *detailViewController =
[[DetailViewController alloc]
initWithNibName:@"DetailViewController_iPhone"
bundle:nil];
[self.navigationController pushViewController:detailViewController
animated:YES];
} else {
/* iPad */
}
}
This methou gets calleu whenevei the usei taps on one ol the items in the mastei view
contiollei. As you can see, the logic is empty il the uevice is an iPau, so let`s go aheau
anu ietiieve the ieleience to the uetail view contiollei thiough the app uelegate:
- (void) tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if ([[UIDevice currentDevice] userInterfaceIdiom]
== UIUserInterfaceIdiomPhone) {
DetailViewController *detailViewController =
[[DetailViewController alloc]
initWithNibName:@"DetailViewController_iPhone"
bundle:nil];
[self.navigationController pushViewController:detailViewController
animated:YES];
} else {
/* iPad */
Presenting_Master_Detail_Views_with_UISplitViewControllerAppDelegate
*appDelegate = [[UIApplication sharedApplication] delegate];
218 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
NSLog(@"%@", appDelegate.detailViewController);
}
}
Gieat. Now we have a ieleience to the uetail view contiollei. Using this ieleience, you
can now senu messages to the uetail view contiollei anu ask it to peiloim vaiious tasks
Laseu on the usei`s selection on the mastei view contiollei.
2.26 Enabling Paging with UIPageViewController
Problem
You want to cieate an app that woiks similaily to iBooks, wheie the usei can llip
thiough the pages ol a Look as il it weie a ieal Look, to pioviue an intuitive anu ieal
usei expeiience.
Solution
Use UIPageViewController.
Discussion
Xcoue has a template loi page view contiolleis. It`s Lest to liist see how they look Leloie
ieauing an explanation ol what they actually aie. So lollow these steps to cieate youi
app to use page view contiolleis:
Page view contiolleis woik Loth on the iPhone anu the iPau.
1. In Xcoue, go to the File menu anu then choose New New Pioject...
2. On the lelthanu siue ol the New Pioject winuow, make suie you`ve selecteu iOS
anu then Application. Once that is uone, pick the Page-Baseu Application template
liom the iight siue anu piess Next, as shown in Figuie 2-7S.
3. Now, select a piouuct name anu make suie the Device Family that you`ve chosen
is Univeisal, as you noimally woulu want youi app to iun on Loth the iPhone anu
the iPau (see Figuie 2-77). Once you aie uone, piess Next.
+. Select wheie you want to save youi pioject. Once you aie uone, piess the Cieate
Lutton. You have now successlully cieateu youi pioject.
2.26 Enabling Paging with UIPageViewController | 219
www.it-ebooks.info
Iigurc 2-77. Sctting thc projcct scttings oj a pagc-bascd app
Iigurc 2-78. Crcating a Pagc-Bascd App|ication in Xcodc
You can now see that Xcoue has cieateu guite a lew classes in youi pioject. Let`s have
a guick look at what each one ol these classes uoes:
220 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
Delegate Class
The app uelegate simply cieates an instance ol the RootViewController class anu
piesents it to the usei. Theie is one .xib loi iPau anu anothei one ol iPhone, Lut
Loth aie using the aloiementioneu class.
RootViewController
Cieates an instance ol UIPageViewController anu auus that view contiollei to itsell.
So the UI ol this view contiollei is actually a mix ol two view contiolleis: the
RootViewController itsell anu a UIPageViewController.
DataViewController
Foi eveiy page in the page view contiollei, an instance ol this class gets piesenteu
to this usei. This class is a suLclass ol UIViewController.
ModelController
This is simply a suLclass ol NSObject that conloims to the UIPageViewController
DataSource piotocol. This class is the uata souice ol the page view contiollei.
So you can see that a page view contiollei has Loth a uelegate anu a uata souice. Vith
Xcoue`s uelault page-Laseu application template, the ioot view contiollei Lecomes the
uelegate anu the mouel contiollei Lecomes the uata souice ol the page view contiollei.
In oiuei to unueistanu how a page view contiollei ieally woiks, we neeu to unueistanu
its uelegation anu uata souice piotocols. Let`s stait with the uelegate, UIPageViewCon
trollerDelegate. This piotocol has two impoitant methous:
- (void)pageViewController:(UIPageViewController *)pageViewController
didFinishAnimating:(BOOL)finished
previousViewControllers:(NSArray *)previousViewControllers
transitionCompleted:(BOOL)completed;
- (UIPageViewControllerSpineLocation)
pageViewController:(UIPageViewController *)pageViewController
spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation;
The liist methou gets calleu when the usei tuins to the next oi the pievious page, or il
the usei initiates the movement liom one page to the othei Lut ueciues against it while
the page is moving (in which case, the usei gets sent Lack to the page she was in Leloie).
The transitionCompleted will get set to YES il this was a successlul page animation, oi
set to NO il the usei ueciueu against the movement anu cancelleu it in the miuule ol the
animation.
The seconu methou gets calleu whenevei the uevice oiientation changes. You can use
this methou to specily the location ol the spine loi the pages Ly ietuining a value ol
type UIPageViewControllerSpineLocation:
enum {
UIPageViewControllerSpineLocationNone = 0,
UIPageViewControllerSpineLocationMin = 1,
UIPageViewControllerSpineLocationMid = 2,
UIPageViewControllerSpineLocationMax = 3
};
typedef NSInteger UIPageViewControllerSpineLocation;
2.26 Enabling Paging with UIPageViewController | 221
www.it-ebooks.info
This might Le a Lit conlusing to you, Lut let me uemonstiate. Il we aie using a UIPage
ViewControllerSpineLocationMin spine location, the page view contiollei will ieguiie
only one view contiollei to piesent to the usei, anu when the usei goes to the next page,
a new view contiollei will Le piesenteu to him. Howevei, il we set the spine location
to UIPageViewControllerSpineLocationMid, we will Le ieguiieu to uisplay 2 view con-
tiolleis at the same time: one on the lelt anu anothei on the iight, with the spine sitting
Letween them. Let me show you what I mean. In Figuie 2-79 you can see an example
ol a page view contiollei in lanuscape moue, with the spine location set to UIPageView
ControllerSpineLocationMin.
Iigurc 2-79. Onc vicw contro||cr prcscntcd in a pagc vicw contro||cr in |andscapc nodc
Now il we ietuin the spine location ol UIPageViewControllerSpineLocationMid, we will
get iesults similai to Figuie 2-S0.
As you can see in that image, the spine is locateu exactly in the centei ol the scieen
Letween two view contiolleis. Once the usei llips a page liom iight to the lelt, the page
iests on the lelt anu the page view contiollei ieveals a new view contiollei on the iight
siue. This whole logic is in this uelegate methou:
- (UIPageViewControllerSpineLocation)pageViewController
:(UIPageViewController *)pageViewController
spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation;
Ve`ve now coveieu the uelegate ol the page view contiollei, Lut how aLout the uata
souice? The uata souice ol a page view contiollei must conloim to the UIPage
ViewControllerDataSource. Two impoitant methous that this piotocol exposes aie:
- (UIViewController *)
pageViewController:(UIPageViewController *)pageViewController
222 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
viewControllerBeforeViewController:(UIViewController *)viewController;
- (UIViewController *)
pageViewController:(UIPageViewController *)pageViewController
viewControllerAfterViewController:(UIViewController *)viewController;
The liist methou gets calleu when the page view contiollei alieauy has a view contiollei
on the scieen anu neeus to know which pievious view contiollei to ienuei. This hap-
pens when the usei ueciues to llip to the next page. The seconu methou is calleu when
the page view contiollei neeus to liguie out which view contiollei to uisplay altei the
view contiollei that is Leing llippeu.
Xcoue, as you`ve alieauy seen, has gieatly simplilieu setting up a page-Laseu applica-
tion. All you ieally neeu to uo now is to pioviue content to the uata mouel (ModelCon
troller) anu oll you go. Il you neeu to customize the colois anu images in youi view
contiolleis, uo so Ly eithei using the Inteilace Builuei to mouily the .xib liles uiiectly
oi wiite youi own coue in the implementation ol each ol the view contiolleis.
2.27 Displaying Popovers with UIPopoverController
Problem
You want to uisplay content on an iPau without Llocking the whole scieen.
Solution
Use popoveis.
Iigurc 2-80. Two vicw contro||crs disp|aycd in a pagc vicw contro||cr in |andscapc nodc
2.27 Displaying Popovers with UIPopoverController | 223
www.it-ebooks.info
Discussion
Popoveis aie useu to uisplay auuitional inloimation on the iPau scieen. An example
can Le seen in the Salaii app on the iPau. Vhen the usei taps on the Bookmaiks Lutton,
she will see a popovei uisplaying the Lookmaiks content on the scieen (see Figuie 2-S1).
Iigurc 2-81. Thc boo|nar|s popovcr in thc Sajari app on an iPad
The uelault Lehavioi ol popoveis is that when the usei taps somewheie outsiue the
iegion ol the popovei, the popovei will automatically get uismisseu. You can ask the
popovei to not get uismisseu il the usei taps on specilic paits ol the scieen, as we will
see latei. Popoveis piesent theii content Ly using a view contiollei. Note that you can
also piesent navigation contiolleis insiue popoveis, Lecause navigation contiolleis aie
a suLclass ol UIViewController.
Popoveis can Le useu only on iPau uevices. Il you have a view contiollei
whose coue iuns Loth on an iPau anu on an iPhone, you neeu to make
suie that you aie not instantiating the popovei on a uevice othei than
the iPau.
Popoveis can Le piesenteu to the usei in two ways:
1. Fiom insiue a navigation Lutton, an instance ol UIBarButtonItem
2. Fiom insiue a iectangulai aiea in a view
Vhen a uevice oiientation is changeu (the uevice is iotateu), popoveis aie eithei uis-
misseu oi hiuuen tempoiaiily. You neeu to make suie that you give youi useis a goou
expeiience Ly ieuisplaying the popovei altei the oiientation change has settleu, il pos-
siLle. In ceitain cases, youi popovei might get uismisseu automatically altei an oiien-
tation change. Foi instance, il the usei taps on a navigation Lutton in lanuscape moue
you might uisplay a popovei on the scieen. Suppose youi app is uesigneu so that when
the oiientation changes to poitiait, the navigation Lutton is iemoveu liom the
224 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
navigation Lai loi some ieason. Now, the coiiect usei expeiience woulu Le to hiue the
popovei associateu with that navigation Lai altei the oiientation ol the uevice is
changeu to poitiait. In some instances, though, you will neeu to play with popoveis a
Lit to give youi useis a goou expeiience, Lecause hanuling uevice oiientation is not
always as stiaightloiwaiu as in the aloiementioneu scenaiio.
To cieate the uemo popovei app, we neeu to liist come up with a stiategy Laseu on oui
ieguiiements. Foi this example, we want to Luilu an app with a view contiollei loaueu
insiue a navigation contiollei. The ioot view contiollei will uisplay a - Lutton on the
iight coinei ol its navigation Lai. Vhen the - Lutton is tappeu on an iPau uevice, it
will uisplay a popovei with two Luttons on it. The liist Lutton will say Photo anu the
seconu Lutton will say Auuio. Vhen the same navigation Lutton is tappeu on an
iPhone uevice, we will uisplay an aleit view with thiee Luttons: the two aloiementioneu
Luttons, anu a cancel Lutton so that the usei can cancel the aleit view il he wishes to.
Vhen these Luttons aie tappeu (whethei on the aleit view on an iPhone oi the popovei
on an iPau), we won`t ieally uo anything. Ve will simply uismiss the aleit view oi the
popovei.
Go aheau anu cieate a Single View univeisal pioject in Xcoue anu name the pioject
Displaying_Popovers_with_UIPopoverControllerViewController. Then go to youi app
uelegate`s heauei lile anu ueline a navigation contiollei:
#import <UIKit/UIKit.h>
@class Displaying_Popovers_with_UIPopoverControllerViewController;
@interface Displaying_Popovers_with_UIPopoverControllerAppDelegate
: UIResponder <UIApplicationDelegate>
@property (nonatomic, strong) UIWindow *window;
@property (nonatomic, strong)
Displaying_Popovers_with_UIPopoverControllerViewController *viewController;
@property (nonatomic, strong) UINavigationController *navigationController;
@end
Next, instantiate youi navigation contiollei in the app uelegate`s implementation lile,
Lut insteau ol the view contiollei, uisplay the navigation contiollei to the usei:
#import "Displaying_Popovers_with_UIPopoverControllerAppDelegate.h"
#import "Displaying_Popovers_with_UIPopoverControllerViewController.h"
@implementation Displaying_Popovers_with_UIPopoverControllerAppDelegate
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
2.27 Displaying Popovers with UIPopoverController | 225
www.it-ebooks.info
UIUserInterfaceIdiom uiIdiom = [[UIDevice currentDevice] userInterfaceIdiom];
NSString *viewControllerClass =
@"Displaying_Popovers_with_UIPopoverControllerViewController_iPad";
if (uiIdiom == UIUserInterfaceIdiomPhone) {
viewControllerClass =
@"Displaying_Popovers_with_UIPopoverControllerViewController_iPhone";
}
self.viewController =
[[Displaying_Popovers_with_UIPopoverControllerViewController alloc]
initWithNibName:viewControllerClass
bundle:nil];
self.navigationController = [[UINavigationController alloc]
initWithRootViewController:self.viewController];
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
return YES;
}
Altei this, we neeu to go into the uelinition lile ol oui view contiollei anu ueline a
piopeity ol type UIPopoverController:
#import <UIKit/UIKit.h>
@interface Displaying_Popovers_with_UIPopoverControllerViewController
: UIViewController <UIAlertViewDelegate>
@property (nonatomic, strong) UIPopoverController *popoverController;
@property (nonatomic, strong) UIBarButtonItem *barButtonAdd;
@end
You can see that we aie also uelining a piopeity calleu barButtonAdd in oui view con-
tiollei. This is the navigation Lutton that we will auu on oui navigation Lai. Oui plan
is to uisplay oui popovei when the usei taps on this Lutton (you can ieau moie aLout
navigation Luttons in Recipe 2.15). Howevei, we neeu to make suie we instantiate the
popovei only il the uevice is an iPau. Beloie we go aheau anu implement oui ioot view
contiollei with the navigation Lutton, let`s go aheau anu cieate a suLclass ol UIView
Controller anu name it PopoverContentViewController. Ve will uisplay the contents
ol this view contiollei insiue oui popovei latei. See Recipe 2.10 loi inloimation aLout
view contiolleis anu ways ol cieating them.
The content view contiollei uisplayeu insiue the popovei will have two Luttons (as pei
oui ieguiiements). Howevei, this view contiollei will neeu to have a ieleience to the
popovei contiollei in oiuei to uismiss the popovei when the usei taps on any ol the
Luttons. Foi this, we neeu to ueline a piopeity in oui content view contiollei to ielei
to the popovei:
226 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
#import <UIKit/UIKit.h>
@interface PopoverContentViewController : UIViewController
@property (nonatomic, strong) UIButton *buttonPhoto;
@property (nonatomic, strong) UIButton *buttonAudio;
/* We shouldnt define this as strong. That will create a retain cycle
between the popover controller and the content view controller, since the
popover controller retains the content view controller and the view controller
retains the popover controller */
@property (nonatomic, weak) UIPopoverController *popoverController;
@end
Now we will go anu synthesize the popovei contiollei in the implementation lile ol oui
content view contiollei:
#import "PopoverContentViewController.h"
@implementation PopoverContentViewController
@synthesize popoverController;
...
Altei this, we`ll cieate oui two Luttons in the content view contiollei anu link them to
theii action methous. These methous will take caie ol uismissing the popovei that is
uisplaying this view contiollei. RememLei, the popovei contiollei will Le iesponsiLle
loi assigning itsell to the popoverController piopeity ol the content view contiollei:
#import "PopoverContentViewController.h"
@implementation PopoverContentViewController
@synthesize popoverController;
- (BOOL) isInPopover{
Class popoverClass = NSClassFromString(@"UIPopoverController");
if (popoverClass != nil &&
UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad &&
self.popoverController != nil){
return YES;
} else {
return NO;
}
}
- (void) gotoAppleWebsite:(id)paramSender{
if ([self isInPopover]){
/* Go to website and then dismiss popover */
2.27 Displaying Popovers with UIPopoverController | 227
www.it-ebooks.info
[self.popoverController dismissPopoverAnimated:YES];
} else {
/* Handle case for iPhone */
}
}
- (void) gotoAppleStoreWebsite:(id)paramSender{
if ([self isInPopover]){
/* Go to website and then dismiss popover */
[self.popoverController dismissPopoverAnimated:YES];
} else {
/* Handle case for iPhone */
}
}
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.contentSizeForViewInPopover = CGSizeMake(200.0f, 125.0f);
CGRect buttonRect = CGRectMake(20.0f,
20.0f,
160.0f,
37.0f);
self.buttonPhoto = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[self.buttonPhoto setTitle:@"Photo"
forState:UIControlStateNormal];
[self.buttonPhoto addTarget:self
action:@selector(gotoAppleWebsite:)
forControlEvents:UIControlEventTouchUpInside];
self.buttonPhoto.frame = buttonRect;
[self.view addSubview:self.buttonPhoto];
buttonRect.origin.y += 50.0f;
self.buttonAudio = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[self.buttonAudio setTitle:@"Audio"
forState:UIControlStateNormal];
[self.buttonAudio addTarget:self
action:@selector(gotoAppleStoreWebsite:)
forControlEvents:UIControlEventTouchUpInside];
self.buttonAudio.frame = buttonRect;
[self.view addSubview:self.buttonAudio];
228 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
}
- (BOOL)shouldAutorotateToInterfaceOrientation
:(UIInterfaceOrientation)interfaceOrientation{
return YES;
}
@end
Now in the viewDidLoad methou ol oui ioot view contiollei, we will cieate oui navi-
gation Lutton. Baseu on the uevice type, when the navigation Lai is tappeu, we will
uisplay eithei a popovei (on the iPau) oi an aleit view (on the iPhone):
- (void)viewDidLoad{
[super viewDidLoad];
/* See if this class exists on the iOS running the app */
Class popoverClass = NSClassFromString(@"UIPopoverController");
if (popoverClass != nil &&
UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad){
PopoverContentViewController *content =
[[PopoverContentViewController alloc] initWithNibName:nil
bundle:nil];
self.popoverController = [[UIPopoverController alloc]
initWithContentViewController:content];
content.popoverController = self.popoverController;
self.barButtonAdd = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
target:self
action:@selector(performAddWithPopover:)];
} else {
self.barButtonAdd = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
target:self
action:@selector(performAddWithAlertView:)];
}
[self.navigationItem setRightBarButtonItem:self.barButtonAdd
animated:NO];
}
- (BOOL)shouldAutorotateToInterfaceOrientation
:(UIInterfaceOrientation)interfaceOrientation{
2.27 Displaying Popovers with UIPopoverController | 229
www.it-ebooks.info
return YES;
}
The popovei contiollei sets a ieleience to itsell in the content view con-
tiollei altei its initialization. This is veiy impoitant. A popovei contiol-
lei cannot Le initializeu without a content view contiollei. Once the
popovei is initializeu with a content view contiollei, you can go aheau
anu change the content view contiollei in the popovei contiollei, Lut
not uuiing the initialization.
Ve have electeu the performAddWithPopover: methou to Le invokeu when the - navi-
gation Lai Lutton is tappeu on an iPau uevice. Il the uevice isn`t an iPau, we`ve askeu
the - navigation Lai Lutton to invoke the performAddWithAlertView: methou. Let`s go
aheau anu implement these methous anu also take caie ol the uelegate methous ol oui
aleit view, so that we know what aleit view Lutton the usei tappeu on an iPhone:
- (NSString *) photoButtonTitle{
return @"Photo";
}
- (NSString *) audioButtonTitle{
return @"Audio";
}
- (void) alertView:(UIAlertView *)alertView
didDismissWithButtonIndex:(NSInteger)buttonIndex{
NSString *buttonTitle = [alertView buttonTitleAtIndex:buttonIndex];
if ([buttonTitle isEqualToString:[self photoButtonTitle]]){
/* Adding a photo ... */
}
else if ([buttonTitle isEqualToString:[self audioButtonTitle]]){
/* Adding an audio... */
}
}
- (void) performAddWithAlertView:(id)paramSender{
[[[UIAlertView alloc] initWithTitle:nil
message:@"Add..."
delegate:self
cancelButtonTitle:@"Cancel"
otherButtonTitles:
[self photoButtonTitle],
[self audioButtonTitle], nil] show];
}
- (void) performAddWithPopover:(id)paramSender{
230 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
[self.popoverController
presentPopoverFromBarButtonItem:self.barButtonAdd
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
}
Il you now iun youi app on iPau Simulatoi anu tap the - Lutton on the navigation Lai,
you will see an inteilace similai to Figuie 2-S2:
Iigurc 2-82. Our sinp|c popovcr disp|aycd whcn a navigation button was tappcd
Il you iun the same univeisal app on the iPhone Simulatoi anu tap the - Lutton on the
navigation Lai, you will see iesults similai to Figuie 2-S3.
Iigurc 2-83. Popovcrs arc rcp|accd by a|crt vicw in a univcrsa| app
2.27 Displaying Popovers with UIPopoverController | 231
www.it-ebooks.info
Ve useu an impoitant piopeity ol oui content view contiollei: contentSizeForView
InPopover. The popovei, when uisplaying its content view contiollei, will ieau the value
ol this piopeity automatically anu will aujust its size (wiuth anu height) to thissize.
Also, we useu the presentPopoverFromBarButtonItem:permittedArrowDirections:anima
ted: methou ol oui popovei in oui ioot view contiollei to uisplay the popovei ovei a
navigation Lai Lutton. The liist paiametei to this methou is the navigation Lai Lutton
liom which the popovei contiollei has to Le uisplayeu. The seconu paiametei specilies
the uiiection ol the popovei when it appeais, in ielation to the oLject liom which it
appeais. Foi example, in Figuie 2-S2, you can see that oui popovei`s aiiow is pointing
up towaius the navigation Lai Lutton. The value that you pass to this paiametei must
Le ol type UIPopoverArrowDirection:
enum {
UIPopoverArrowDirectionUp = 1UL << 0,
UIPopoverArrowDirectionDown = 1UL << 1,
UIPopoverArrowDirectionLeft = 1UL << 2,
UIPopoverArrowDirectionRight = 1UL << 3,
UIPopoverArrowDirectionAny = UIPopoverArrowDirectionUp |
UIPopoverArrowDirectionDown |
UIPopoverArrowDirectionLeft |
UIPopoverArrowDirectionRight,
UIPopoverArrowDirectionUnknown = NSUIntegerMax
};
typedef NSUInteger UIPopoverArrowDirection;
See Also
Recipe 2.10; Recipe 2.15
2.28 Displaying Progress with UIProgressView
Problem
You want to uisplay a piogiess Lai on the scieen, uepicting the piogiess ol a ceitain
task; loi instance, the piogiess ol uownloauing a lile liom a URL.
Solution
Instantiate a view ol type UIProgressView anu place it on anothei view.
Discussion
A piogiess view is what piogiammeis geneially call a piogiess Lai. An example ol a
piogiess view is uepicteu in Figuie 2-S+.
232 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
Iigurc 2-81. A sinp|c progrcss vicw
Piogiess views aie geneially uisplayeu to useis to show them the piogiess ol a task that
has a well-uelineu staiting anu enuing point. Foi instance, uownloauing 30 liles is a
well-uelineu task with a specilic staiting anu enuing point. This task oLviously linishes
when all 30 liles have Leen uownloaueu. A piogiess view is an instance ol UIProgress
View anu is initializeu using the uesignateu initializei ol this class, the initWithProg
ressViewStyle: methou. This methou takes in the style ol the piogiess Lai to Le cieateu
as a paiametei. This paiametei is ol type UIProgressViewStyle anu can theieloie Le one
ol the lollowing values:
UIProgressViewStyleDefault
This is the uelault style ol the piogiess view. An example ol this is the piogiess
view shown in Figuie 2-S+.
UIProgressViewStyleBar
This is similai to the UIProgressViewStyleDefault Lut is meant to Le useu loi pio-
giess views that aie to Le auueu to a toolLai.
An instance ol UIProgressView uelines a piopeity calleu progress (ol type float). This
piopeity tells iOS how the Lai insiue the piogiess view shoulu Le ienueieu. This value
must Le in the iange -0 to -1.0. Il the value ol -0 is given, the piogiess Lai won`t
appeai to have staiteu yet. A value ol -1.0 shows the piogiess ol 100. The piogiess
uepicteu in Figuie 2-S+ is 0.5 (oi 50).
To get useu to cieating piogiess views, let`s cieate one similai to what we saw in
Figuie 2-S+. Fiist things liist: ueline a piopeity loi youi piogiess view:
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
2.28 Displaying Progress with UIProgressView | 233
www.it-ebooks.info
@property (nonatomic, strong) UIProgressView *progressView;
@end
Then instantiate an oLject ol type UIProgressView:
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.progressView = [[UIProgressView alloc]
initWithProgressViewStyle:UIProgressViewStyleBar];
self.progressView.center = self.view.center;
self.progressView.progress = 0.5f;
[self.view addSubview:self.progressView];
}
OLviously, cieating a piogiess view is veiy stiaightloiwaiu. All you ieally neeu to uo
is to uisplay youi piogiess coiiectly, Lecause the progress piopeity ol a piogiess view
shoulu Le in the iange -0 to -1.0, which is a noimalizeu value. So il you have 30 tasks
to take caie ol anu you have completeu 20 ol them so lai, you neeu to assign the iesult
ol the lollowing eguation to the progress piopeity ol youi piogiess view:
self.progressView.progress = 20.0f / 30.0f;
The ieason the values 20 anu 30 aie passeu to the eguation as lloating-
point values is to tell the compilei that the uivision has to happen on
lloating-point values, piouucing a value with uecimal numLeis. Il you
pioviueu the integei uivision 20/30 to the compilei to place insiue the
progress piopeity ol youi piogiess view, you woulu get the integial
value ol 0 out ol the uivision, Lecause the compilei will peiloim integei
uivision that tiuncates the iesult to the next lowei integei. In shoit, youi
piogiess view woulu show zeio piogiess all the way to the enu, when
30/30 piouuces the iesult ol 1; not ol much value to the usei.
2.29 Listening and Reacting to Keyboard Notifications
Problem
You aie allowing the usei to entei some text in youi UI, using some component such
as a text lielu oi text view that ieguiies the keyLoaiu`s piesence. Howevei, when the
keyLoaiu pops up on the scieen, it oLstiucts a goou hall ol youi UI, ienueiing it useless.
You want to avoiu this situation.
234 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
Solution
Listen to keyLoaiu notilications anu move youi UI components up/uown oi completely
ieshullle youi components, so that with the keyLoaiu oLstiucting the scieen, what is
essential to the usei is still visiLle to him. Foi moie inloimation aLout the actual noti-
lications sent Ly the keyLoaiu, please ielei to the Discussion section ol this iecipe.
Discussion
iOS uevices uo not have a physical keyLoaiu. They have a soltwaie keyLoaiu that pops
up whenevei the usei has to entei some text into something like a text lielu (UIText
Field, see Recipe 2.19 loi moie inloimation) oi a text view (UITextView, see
Recipe 2.20 loi moie inloimation). On the iPau, the usei can even split the keyLoaiu
anu move it up anu uown. These aie some ol the euge cases that you might want to
take caie ol when uesigning youi usei inteilace. You can woik with the UI uesigneis
in youi company (il you have access to such expeits) anu let them know aLout the
possiLility ol the usei splitting the keyLoaiu on the iPau. They will neeu to know aLout
that Leloie making the ait anu cieatives. Ve will uiscuss that euge case in this iecipe.
Let`s have a look at the keyLoaiu on the iPhone liist. The keyLoaiu can get uisplayeu
in poitiait anu lanuscape moue. In poitiait, the keyLoaiu on an iPhone looks like
Figuie 2-S5.
Iigurc 2-85. Portrait-nodc |cyboard on an iPhonc
The keyLoaiu in lanuscape moue on an iPhone will look similai to that shown in
Figuie 2-S6.
2.29 Listening and Reacting to Keyboard Notifications | 235
www.it-ebooks.info
Iigurc 2-8. Thc |cyboard in |andscapc nodc on an iPhonc
On the iPau, howevei, the keyLoaiu is a Lit uilleient. The most oLvious uilleience is
that the keyLoaiu is actually much Liggei in size than the one on the iPhone, since the
iPau scieen is physically Liggei. Also, the usei can split the keyLoaiu il she wants to.
Figuie 2-S7 shows an example ol the iPau keyLoaiu in poitiait moue. The lanuscape
keyLoaiu on an iPau is oLviously wiuei, Lut contains the same keys as the poitiait-
moue keyLoaiu uoes (Figuie 2-SS). Finally, Figuie 2-S9 shows an example ol the split
keyLoaiu on the iPau, in lanuscape moue (the keyLoaiu can Le split in Loth lanuscape
moue anu poitiait moue).
Iigurc 2-87. Thc iPad |cyboard in portrait nodc
236 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
Iigurc 2-88. Thc iPad |cyboard in |andscapc nodc
Iigurc 2-89. Sp|it |cyboard on thc iPad in |andscapc nodc
iOS Lioaucasts vaiious notilications ielateu to the uisplay ol the keyLoaiu on the
scieen. Heie is a list ol these notilications anu a Liiel explanation loi each one:
UIKeyboardWillShowNotification
This notilication gets Lioaucast when the keyLoaiu is aLout to get uisplayeu on
the scieen. This notilication caiiies with it a usei-inlo uictionaiy that contains
2.29 Listening and Reacting to Keyboard Notifications | 237
www.it-ebooks.info
vaiious inloimation aLout the keyLoaiu, the animation that the keyLoaiu will use
to get uisplayeu on the scieen, anu moie.
UIKeyboardDidShowNotification
This notilication gets Lioaucast when the keyLoaiu gets uisplayeu on the scieen.
UIKeyboardWillHideNotification
This notilication gets Lioaucast when the keyLoaiu is aLout to get iemoveu liom
the scieen. This notilication will caiiy with it a usei-inlo uictionaiy that contains
vaiious Lits anu pieces ol inloimation aLout the keyLoaiu, the keyLoaiu`s anima-
tion when it is hiuing, the uuiation ol the animation, etc.
UIKeyboardDidHideNotification
This notilication gets Lioaucast when the keyLoaiu gets lully hiuuen altei it was
Leing shown on the scieen.
As alieauy mentioneu, only the UIKeyboardWillShowNotification anu the UIKeyboard
WillHideNotification notilications caiiy a usei-inlo uictionaiy with them with valiu
keys anu values in those uictionaiies. Heie aie the keys in those uictionaiies that you
might Le inteiesteu in:
UIKeyboardAnimationCurveUserInfoKey
The value ol this key specilies the type ol animation cuive the keyLoaiu is using to
show oi hiue itsell. This key contains a value (encapsulateu in an oLject ol type
NSValue) ol type NSNumber that itsell contains an unsigneu integei ol type NSUInte
ger.
UIKeyboardAnimationDurationUserInfoKey
The value ol this key specilies the uuiation ol animation the keyLoaiu is using to
show oi hiue itsell, in seconus. This key contains a value (encapsulateu in an oLject
ol type NSValue) ol type NSNumber that itsell contains a uouLle value ol type double.
UIKeyboardFrameBeginUserInfoKey
The value ol this key specilies the liame ol the keyLoaiu Leloie the animation
happens. Il the keyLoaiu is aLout to get uisplayeu, this will Le the liame Leloie the
keyLoaiu appeais. Il the keyLoaiu is alieauy uisplayeu anu is aLout to hiue, this
will Le the liame ol the keyLoaiu as it is on the scieen, Leloie it animates out ol
the scieen. This key contains a value (encapsulateu in an oLject ol type NSValue)
ol type CGRect.
UIKeyboardFrameEndUserInfoKey
The value ol this key specilies the liame ol the keyLoaiu altei the animation hap-
pens. Il the keyLoaiu is aLout to get uisplayeu, this will Le the liame altei the
keyLoaiu animates up anu is lully uisplayeu. Il the keyLoaiu is alieauy uisplayeu
anu is aLout to hiue, this will Le the liame ol the keyLoaiu altei it is lully hiuuen.
This key contains a value (encapsulateu in an oLject ol type NSValue) ol type CGRect.
238 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
The liames that get iepoiteu Ly iOS as the Leginning anu enuing liames
ol the keyLoaiu uo not take into account the oiientation ol the uevice.
You neeu to conveit the iepoiteu CGRect values to a ielevant oiienta-
tion-awaie cooiuinate, as we will see soon in this iecipe.
Let`s have a look at an example, shall we? Let`s cieate a simple taLle view on oui view
contiollei`s view anu change its content inset (the maigins liom top, iight, Lottom, anu
lelt siue ol the taLle view) when the keyLoaiu gets uisplayeu. Ve will populate this
taLle view with 100 cells, enough to lill the entiie scieen on Loth the iPhone anu the
iPau (in a Univeisal app), so let`s stait with the heauei lile ol oui view contiollei:
The CGRectIntersection lunction that we aie going to use in this iecipe
is uelineu anu implementeu in the CoieGiaphics liamewoik. To Le aLle
to compile this coue, you will neeu to make suie that you have linkeu
youi app against the aloiementioneu liamewoik. You can uo so Ly se-
lecting youi pioject`s icon in Xcoue, then selecting youi taiget liom the
list that appeais on the iighthanu siue. Now you neeu to select the Builu
Phases taL. In the Link Binaiy Vith LiLiaiies Lox, make suie that youi
taiget is linkeu against this liamewoik. Il not, you can piess the - Lutton
in that Lox anu simply auu that liamewoik to the list ol liamewoiks
youi app links against.
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
<UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate>
@property (nonatomic, strong) UITableView *myTableView;
@end
Next, we will instantiate the taLle view when oui view loaus:
- (void)viewDidLoad{
[super viewDidLoad];
self.myTableView = [[UITableView alloc]
initWithFrame:self.view.bounds
style:UITableViewStyleGrouped];
self.myTableView.delegate = self;
self.myTableView.dataSource = self;
self.myTableView.autoresizingMask = UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;
[self.view addSubview:self.myTableView];
}
2.29 Listening and Reacting to Keyboard Notifications | 239
www.it-ebooks.info
Altei this, we will neeu to populate oui taLle view with 100 cells anu in each cell, cieate
a text lielu as the accessoiy view. Ve uo this to allow the usei to tiiggei the keyLoaiu
to pop up. Il we uon`t have a text lielu oi some means loi the usei to entei text, we will
nevei Le aLle to get the keyLoaiu on the scieen, so let`s uo that now:
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
/* Make sure the Done button on the keyboard for each text field
(accessory views of each cell) dismisses the keyboard */
[textField resignFirstResponder];
return YES;
}
- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
- (NSInteger) tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section{
return 100;
}
- (UITableViewCell *) tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *result = nil;
static NSString *CellIdentifier = @"CellIdentifier";
result = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (result == nil){
result = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
result.selectionStyle = UITableViewCellSelectionStyleNone;
}
result.textLabel.text = [NSString stringWithFormat:
@"Cell %ld", (long)indexPath.row];
CGRect accessoryRect = CGRectMake(0.0f,
0.0f,
150.0f,
31.0f);
UITextField *accesssory = [[UITextField alloc] initWithFrame:accessoryRect];
accesssory.borderStyle = UITextBorderStyleRoundedRect;
accesssory.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
accesssory.placeholder = @"Enter Text";
accesssory.delegate = self;
result.accessoryView = accesssory;
return result;
}
240 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
Fantastic. Il you now iun youi app on iPhone Simulatoi, you will see something similai
to Figuie 2-90.
Iigurc 2-90. A tab|c vicw with tcxt jic|ds jor acccssory vicw oj cach cc||
Go aheau now anu tap on the liist text lielu (in the liist cell). Now scioll the taLle view
all the way uown to the last cell anu see what happens, You can`t see the last 5-6 cells,
can you? Vhat you can see in poitiait moue on an iPhone will Le similai to that shown
in Figuie 2-91.
Iigurc 2-91. Kcyboard obstructing thc botton ha|j oj a tab|c vicw
2.29 Listening and Reacting to Keyboard Notifications | 241
www.it-ebooks.info
Vhat we can now uo is to listen loi the UIKeyboardWillShowNotification anu the UIKey
boardWillHideNotification notilications anu aujust oui taLle view`s content inset ac-
coiuingly:
- (void) viewDidAppear:(BOOL)paramAnimated{
[super viewDidAppear:paramAnimated];
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self
selector:@selector(handleKeyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[center addObserver:self
selector:@selector(handleKeyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
- (void) viewDidDisappear:(BOOL)paramAnimated{
[super viewDidDisappear:paramAnimated];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
A common mistake piogiammeis make is to keep listening loi keyLoaiu
notilications even il theii view contiollei`s view is not on the scieen.
They stait listening loi notilications in the viewDidLoad methou anu
iemove themselves as the oLseivei in viewDidUnload oi the dealloc
methou il they uon`t have ARC enaLleu. This is a pioLlematic appioach
Lecause when youi view is oll the scieen anu the keyLoaiu is getting
uisplayeu on some othei view, you shoulu not Le aujusting any com-
ponents on youi hiuuen view contiollei. Keep in minu that keyLoaiu
notilications, just like any othei notilication, aie Lioaucast to all oL-
seivei oLjects, so you neeu to take extia caie that you uo not ieact to
keyLoaiu notilications while youi view is ollscieen.
Now that we have staiteu listening loi keyLoaiu notilications, we can implement the
oLseivei methous that we suLmitteu to NSNotificationCenter. The handleKeyboard
WillShow: methou will Le iesponsiLle loi setting the content inset ol oui taLle view:
- (void) handleKeyboardWillShow:(NSNotification *)paramNotification{
NSDictionary *userInfo = [paramNotification userInfo];
NSValue *animationCurveObject =
[userInfo valueForKey:UIKeyboardAnimationCurveUserInfoKey];
NSValue *animationDurationObject =
[userInfo valueForKey:UIKeyboardAnimationDurationUserInfoKey];
NSValue *keyboardEndRectObject =
242 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
[userInfo valueForKey:UIKeyboardFrameEndUserInfoKey];
NSUInteger animationCurve = 0;
double animationDuration = 0.0f;
CGRect keyboardEndRect = CGRectMake(0, 0, 0, 0);
[animationCurveObject getValue:&animationCurve];
[animationDurationObject getValue:&animationDuration];
[keyboardEndRectObject getValue:&keyboardEndRect];
[UIView beginAnimations:@"changeTableViewContentInset"
context:NULL];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:(UIViewAnimationCurve)animationCurve];
UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
CGRect intersectionOfKeyboardRectAndWindowRect =
CGRectIntersection(window.frame, keyboardEndRect);
CGFloat bottomInset = intersectionOfKeyboardRectAndWindowRect.size.height;
self.myTableView.contentInset = UIEdgeInsetsMake(0.0f,
0.0f,
bottomInset,
0.0f);
NSIndexPath *indexPathOfOwnerCell = nil;
/* Also, make sure the selected text field is visible on the screen */
NSInteger numberOfCells = [self.myTableView.dataSource
tableView:self.myTableView
numberOfRowsInSection:0];
/* So let's go through all the cells and find their accessory text fields.
Once we have the reference to those text fields, we can see which one of
them is the first responder (has the keyboard) and we will make a call
to the table view to make sure that, after the keyboard is displayed,
that specific cell is NOT obstructed by the keyboard */
for (NSInteger counter = 0;
counter < numberOfCells;
counter++){
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:counter
inSection:0];
UITableViewCell *cell = [self.myTableView cellForRowAtIndexPath:indexPath];
UITextField *textField = (UITextField *)cell.accessoryView;
if ([textField isKindOfClass:[UITextField class]] == NO){
continue;
}
if ([textField isFirstResponder]){
indexPathOfOwnerCell = indexPath;
break;
}
}
[UIView commitAnimations];
2.29 Listening and Reacting to Keyboard Notifications | 243
www.it-ebooks.info
if (indexPathOfOwnerCell != nil){
[self.myTableView scrollToRowAtIndexPath:indexPathOfOwnerCell
atScrollPosition:UITableViewScrollPositionMiddle
animated:YES];
}
}
So heie is what we aie uoing in this methou, in that oiuei:
1. Retiieve the uilleient animation piopeities ol the keyLoaiu, incluuing its animation
time, its animation cuive, anu the liame that the keyLoaiu will have once its ani-
mation linisheu. Ve uo this using the usei-inlo uictionaiy ol the UIKeyboardWill
ShowNotification notilication.
2. Ve then stait an animation Llock that will change the content inset ol oui taLle
view. Beloie we uo this, we neeu to know how much ol the aiea ol oui taLle view
the keyLoaiu will Le oLstiucting.
3. Using the CGRectIntersection lunction, we ietiieve the inteisection Letween oui
winuow`s liame anu the liame ol the keyLoaiu when it has linisheu its animation.
Using this technigue, we can linu out how much ol the aiea ol oui winuow will Le
oLstiucteu Ly the keyLoaiu altei its animation, so that we can set the Lottom con-
tent inset ol the taLle view accoiuingly.
+. Ve set the piopeities ol oui animation Llock, such as its cuive anu uuiation, anu
commit the animation. The animation Llock, as mentioneu Leloie, will simply
change the content inset ol oui taLle view to lit the whole content into the visiLle
aiea ol the scieen altei the keyLoaiu pops up.
Now we neeu to move on to the implementation ol the handleKeyboardWillHide:meth-
ou:
- (void) handleKeyboardWillHide:(NSNotification *)paramNotification{
if (UIEdgeInsetsEqualToEdgeInsets(self.myTableView.contentInset,
UIEdgeInsetsZero)){
/* Our table view's content inset is intact so no need to reset it */
return;
}
NSDictionary *userInfo = [paramNotification userInfo];
NSValue *animationCurveObject =
[userInfo valueForKey:UIKeyboardAnimationCurveUserInfoKey];
NSValue *animationDurationObject =
[userInfo valueForKey:UIKeyboardAnimationDurationUserInfoKey];
NSValue *keyboardEndRectObject =
[userInfo valueForKey:UIKeyboardFrameEndUserInfoKey];
NSUInteger animationCurve = 0;
244 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
double animationDuration = 0.0f;
CGRect keyboardEndRect = CGRectMake(0, 0, 0, 0);
[animationCurveObject getValue:&animationCurve];
[animationDurationObject getValue:&animationDuration];
[keyboardEndRectObject getValue:&keyboardEndRect];
[UIView beginAnimations:@"changeTableViewContentInset"
context:NULL];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:(UIViewAnimationCurve)animationCurve];
self.myTableView.contentInset = UIEdgeInsetsZero;
[UIView commitAnimations];
}
In the handleKeyboardWillHide: methou, we aie uoing the lollowing, in this oiuei:
1. Finu out whethei the content inset ol oui taLle view has alieauy Leen changeu. Il
oui taLle view`s content inset wasn`t changeu, we shoulun`t take any luithei action.
Ve will just assume that we ieceiveu this notilication Ly mistake oi that some othei
oLject on anothei view on oui view contiollei causeu this notilication to get
Lioaucast.
2. Using the usei-inlo uictionaiy ol the UIKeyboardWillHideNotification notilication,
we get the uuiation anu cuive ol the keyLoaiu`s animation while it is tucking away.
Using this inloimation, we will cieate an animation Llock.
3. Ve set oui taLle view`s content inset to UIEdgeInsetsZero anu commit oui anima-
tion.
As mentioneu Leloie, when the keyLoaiu notilications aie Lioaucast, the cuiient oii-
entation ol the uevice is not taken into account to constiuct the staiting anu enuing
liames ol oui taLle view. Foi instance, il we log the enuing liame ol oui keyLoaiu in
the handleKeyboardWillShow: methou ol oui view contiollei on an iPhone in poitiait
moue, we will get the lollowing values:
{{0, 264}, {320, 216}}
Il you now iotate the oiientation to lanuscape anu log the values again, you will see the
lollowing value piinteu out to the console winuow:
{{0, 0}, {162, 480}}
It is immeuiately oLvious that the values aie incoiiect. As you can see, the Y position
ol the keyLoaiu is iepoiteu as 0Lut we know that when the keyLoaiu is uisplayeu in
lanuscape moue on an iPhone, the Y position is ceitainly not at 0. Fuitheimoie, the
wiuth is the wiuth ol the whole scieen, which oLviously is not 162.0 in lanuscape moue,
anu the height is almost hall ol the scieen, which makes the value ol +S0 incoiiect. The
ieason loi the incoiiect values is that iOS uoesn`t take the oiientation ol the uevice into
account when iepoiting these values to youi apps. The liames iepoiteu to youi app aie
2.29 Listening and Reacting to Keyboard Notifications | 245
www.it-ebooks.info
in the app`s main winuow`s cooiuinate system. Theieloie, to conveit these iepoiteu
liames liom the winuow`s cooiuinate system to youi view`s cooiuinate system, use the
convertRect:fromView: methou ol youi view anu pass youi app`s winuow as the from
View paiametei.
So let`s mouily the implementation ol the handleKeyboardWillShow: methou slightly to
take the conveision ol cooiuinate systems into account, liom the winuow`s to oui
view`s cooiuinate system.
The implementation ol the handleKeyboardWillHide: methou uoes not
use the iectangles in the usei-inlo uictionaiy. In this methou we always
assume that the keyLoaiu is hiuing anu that its iectangle is (0, 0, 0, 0).
- (void) handleKeyboardWillShow:(NSNotification *)paramNotification{
NSDictionary *userInfo = [paramNotification userInfo];
NSValue *animationCurveObject =
[userInfo valueForKey:UIKeyboardAnimationCurveUserInfoKey];
NSValue *animationDurationObject =
[userInfo valueForKey:UIKeyboardAnimationDurationUserInfoKey];
NSValue *keyboardEndRectObject =
[userInfo valueForKey:UIKeyboardFrameEndUserInfoKey];
NSUInteger animationCurve = 0;
double animationDuration = 0.0f;
CGRect keyboardEndRect = CGRectMake(0, 0, 0, 0);
[animationCurveObject getValue:&animationCurve];
[animationDurationObject getValue:&animationDuration];
[keyboardEndRectObject getValue:&keyboardEndRect];
UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
/* Convert the frame from window's coordinate system to
our view's coordinate system */
keyboardEndRect = [self.view convertRect:keyboardEndRect
fromView:window];
[UIView beginAnimations:@"changeTableViewContentInset"
context:NULL];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:(UIViewAnimationCurve)animationCurve];
CGRect intersectionOfKeyboardRectAndWindowRect =
CGRectIntersection(window.frame, keyboardEndRect);
CGFloat bottomInset = intersectionOfKeyboardRectAndWindowRect.size.height;
246 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
self.myTableView.contentInset = UIEdgeInsetsMake(0.0f,
0.0f,
bottomInset,
0.0f);
NSIndexPath *indexPathOfOwnerCell = nil;
/* Also, make sure the selected text field is visible on the screen */
NSInteger numberOfCells = [self.myTableView.dataSource
tableView:self.myTableView
numberOfRowsInSection:0];
/* So let's go through all the cells and find their accessory text fields.
Once we have the reference to those text fields, we can see which one of
them is the first responder (has the keyboard) and we will make a call
to the table view to make sure after the keyboard is displayed,
that specific cell is NOT obstructed by the keyboard */
for (NSInteger counter = 0;
counter < numberOfCells;
counter++){
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:counter
inSection:0];
UITableViewCell *cell = [self.myTableView cellForRowAtIndexPath:indexPath];
UITextField *textField = (UITextField *)cell.accessoryView;
if ([textField isKindOfClass:[UITextField class]] == NO){
continue;
}
if ([textField isFirstResponder]){
indexPathOfOwnerCell = indexPath;
break;
}
}
[UIView commitAnimations];
if (indexPathOfOwnerCell != nil){
[self.myTableView scrollToRowAtIndexPath:indexPathOfOwnerCell
atScrollPosition:UITableViewScrollPositionMiddle
animated:YES];
}
}
Biilliant. Now iun the app on iPhone Simulatoi anu iotate the simulatoi`s oiientation
to lanuscape anu tap on one ol the text lielus. Vhen the keyLoaiu is uisplayeu, scioll
all the way uown to the enu ol the taLle view`s content to make suie that we have given
the iight content inset, taking into account the cooiuinate system conveision to oui
taLle view (Figuie 2-92).
2.29 Listening and Reacting to Keyboard Notifications | 247
www.it-ebooks.info
Iigurc 2-92. Ca|cu|ating thc corrcct cdgc insct by ta|ing thc coordinatc systcn oj thc |cyboard into
account
See Also
Recipe 2.19; Recipe 2.20
2.30 Constructing and Displaying Styled Texts
Problem
You want to Le aLle to Le aLle to uisplay iich loimatteu text in youi UI components
without having to cieate a sepaiate UI component pei attiiLute. Foi instance, you may
want to uisplay one sentence that contains only one ol its woius wiitten in Lolu, insiue
a UILabel.
Solution
Constiuct an instance ol the NSAttributedString oi the mutaLle vaiiant ol it, the NSMu
tableAttributedString, anu eithei set it as the text ol a UI component like the UILa
bel component thiough its special attiiLuteu stiing piopeity, oi simply use the attiiL-
uteu stiing`s Luilt-in methous to uiaw the text on a canvas.
Discussion
Rich text is a thing ol legenu! A lot ol us piogiammeis have hau the ieguiiement to
uisplay mixeu-style stiings in one line ol text on oui UI. Foi instance, in one line ol text
you may have to uisplay stiaight anu italic text togethei, wheie one woiu is italic anu
the iest ol the woius aie iegulai text. Oi you may have hau to unueiline a woiu insiue
a sentence. Foi this, some ol us hau to use VeL Views, Lut that is not the optimal
solution Lecause VeL Views aie guite slow in ienueiing theii content, anu that will
uelinitely impact the peiloimance ol youi app. In iOS 6, linally, we can stait using
attiiLuteu stiings. I uon`t know what took Apple so long to intiouuce this leatuie to
iOS, as Mac uevelopeis have Leen using attiiLuteu stiings loi a long time now!
248 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
Beloie we Legin, I want to cleaily show you what I mean Ly attiiLuteu stiings, using
Figuie 2-93. Then we will set out on the jouiney to wiite the piogiam to achieve exactly
this.
Iigurc 2-93. An attributcd string is disp|aycd on thc scrccn insidc a sinp|c |abc|
]ust to Le explicit, this text is ienueieu insiue a sing|c instance ol the
UILabel class.
So what uo we see in this example? I`ll list the pieces:
Thc tcxt iOS with thc jo||owing attributcs:
Bolu lont with size ol 60 points
Backgiounu coloi ol Llack
Font coloi ol ieu
Thc tcxt SDK with thc jo||owing attributcs:
Bolu lont with size ol 60 points
Vhite text coloi
Light giay shauow
2.30 Constructing and Displaying Styled Texts | 249
www.it-ebooks.info
The Lest way to constiuct attiiLuteu stiings is to use the initWithString: methou ol
the mutaLle vaiiant ol the NSMutableAttributedString class anu pass an instance ol the
NSString to this methou. This will cieate oui attiiLuteu stiing without any attiiLutes.
Then, to assign attiiLutes to uilleient paits ol the stiing, we will use the setAttri
butes:range: methou ol the NSMutableAttributedString class. This methou takes in
two paiameteis:
setAttributes
A uictionaiy whose keys aie chaiactei attiiLutes anu the value ol each key uepenus
on the key itsell. Heie aie the most impoitant keys that you can set in this uictio-
naiy:
NSFontAttributeName
The value ol this key is an instance ol UIFont anu uelines the lont loi the specilic
iange ol youi stiing.
NSForegroundColorAttributeName
The value loi this key is ol type UIColor anu uelines the coloi loi youi text loi
the specilic iange ol youi stiing.
NSBackgroundColorAttributeName
The value ol this key is ol type UIColor anu uelines the Lackgiounu coloi on
which the specilic iange ol youi stiing has to Le uiawn.
NSShadowAttributeName
The value ol this key must Le an instance ol the NSShadow anu uelines the
shauow that you want to use unuei the specilic iange ol youi stiing.
range
A value ol type NSRange that uelines the staiting point anu the length ol chaiacteis
to which you want to apply the attiiLutes.
To see all the uilleient keys that you can pass to this methou, simply
Liowse the Apple uocumentation online loi the NSMutableAttributed
String class. I will not put the uiiect URL to this uocumentation heie
as Apple may change the URL at some point, Lut a simple seaich online
will uo the tiick.
Ve`ll Lieak oui example uown into two uictionaiies ol attiiLutes. The uictionaiy ol
attiiLutes loi the woiu iOS can Le constiucteu in this way in coue:
NSDictionary *attributesForFirstWord = @{
NSFontAttributeName : [UIFont boldSystemFontOfSize:60.0f],
NSForegroundColorAttributeName : [UIColor redColor],
NSBackgroundColorAttributeName : [UIColor blackColor]
};
Anu the woiu SDK will Le constiucteu using the lollowing attiiLutes:
250 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
NSShadow *shadow = [[NSShadow alloc] init];
shadow.shadowColor = [UIColor darkGrayColor];
shadow.shadowOffset = CGSizeMake(4.0f, 4.0f);
NSDictionary *attributesForSecondWord = @{
NSFontAttributeName : [UIFont boldSystemFontOfSize:60.0f],
NSForegroundColorAttributeName : [UIColor whiteColor],
NSBackgroundColorAttributeName : [UIColor redColor],
NSShadowAttributeName : shadow
};
Putting it togethei, we will get the lollowing coue that not only cieates oui laLel, Lut
also sets its attiiLuteu text:
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong) UILabel *label;
@end
@implementation ViewController
- (NSAttributedString *) attributedText{
NSString *string = @"iOS SDK";
NSMutableAttributedString *result = [[NSMutableAttributedString alloc]
initWithString:string];
NSDictionary *attributesForFirstWord = @{
NSFontAttributeName : [UIFont boldSystemFontOfSize:60.0f],
NSForegroundColorAttributeName : [UIColor redColor],
NSBackgroundColorAttributeName : [UIColor blackColor]
};
NSShadow *shadow = [[NSShadow alloc] init];
shadow.shadowColor = [UIColor darkGrayColor];
shadow.shadowOffset = CGSizeMake(4.0f, 4.0f);
NSDictionary *attributesForSecondWord = @{
NSFontAttributeName : [UIFont boldSystemFontOfSize:60.0f],
NSForegroundColorAttributeName : [UIColor whiteColor],
NSBackgroundColorAttributeName : [UIColor redColor],
NSShadowAttributeName : shadow
};
/* Find the string "iOS" in the whole string and sets its attribute */
[result setAttributes:attributesForFirstWord
range:[string rangeOfString:@"iOS"]];
/* Do the same thing for the string "SDK" */
[result setAttributes:attributesForSecondWord
range:[string rangeOfString:@"SDK"]];
return [[NSAttributedString alloc] initWithAttributedString:result];
2.30 Constructing and Displaying Styled Texts | 251
www.it-ebooks.info
}
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.label = [[UILabel alloc] init];
self.label.backgroundColor = [UIColor clearColor];
self.label.attributedText = [self attributedText];
[self.label sizeToFit];
self.label.center = self.view.center;
[self.view addSubview:self.label];
}
@end
See Also
Recipe 2.17; Recipe 2.1S
252 | Chapter 2: Implementing Controllers and Views
www.it-ebooks.info
CHAPTER 3
Auto Layout and the Visual Format
Language
3.0 Introduction
Aligning UI components has always Leen a Lig heauache loi piogiammeis. Most ol the
view contiolleis in complex iOS apps contain a lot ol coue just to set the liame ol UI
components on the scieen, align components hoiizontally/veitically, anu make suie
the components look goou on uilleient iOS veisions. Not only that, Lut some pio-
giammeis want to also use the same view contiolleis acioss vaiious uevices such as
iPhones anu iPaus. This auus a lot ol complexity to the coue. Apple has maue it easiei
loi us in iOS 6. They have Liought Auto Layout liom OS X ovei to iOS. Ve will Le
talking aLout the uetails ol Auto Layout in a moment, Lut let me just give you a Liiel
intiouuction to it anu explain what it is loi.
Let`s say you have a Lutton that you want to keep at the centei ol the scieen. The
ielation Letween the centei ol the Lutton anu the centei ol the view on which it iesiues
can Le simply uesciiLeu like so:
Button`s centei.x is egual to view`s centei.x
Button`s centei.y is egual to view`s centei.y
Apple noticeu that a lot ol the positioning ol UI components can Le solveu with a simple
loimula:
object1.property1 = (object2.property2 * multiplier) + constant value
Foi instance, using this loimula, I coulu simply centei a Lutton on its supeiview like so:
button.center.x = (button.superview.center.x * 1) + 0
button.center.y = (button.superview.center.y * 1) + 0
Using this loimula, you can uo some ieally lunky things uuiing the UI uevelopment ol
youi iOS apps that you coulu not uo Leloie. The aloiementioneu loimula is wiappeu
insiue a class in the iOS SDK calleu NSLayoutConstraint. Eveiy constiaint that you cieate
253
www.it-ebooks.info
(i.e., eveiy instance ol this class) iepiesents only one constiaint. Foi instance, il you
want to centei youi Lutton on the view that owns the Lutton, you have to centei the
x anu the y position ol the Lutton. That means you have to cieate two constiaints.
Centeiing simply cannot Le expiesseu Ly one constiaint. Howevei, latei in this chaptei
we will leain aLout the Visual Foimat Language, which is a gieat auuition to the iOS
language anu simplilies things even luithei in teims ol UI layouts.
Constiaints can Le cieateu Ly cioss views. Foi instance, il you have two Luttons on one
view anu you want them to Le 100 points apait veitically, you neeu to cieate the con-
stiaint loi this iule Lut auu it to the common ancestoi ol Loth the Luttons, which is
peihaps the view that owns Loth ol them. These aie the iules:
Il the constiaint is Letween two views that sit on a common immeuiate paient view,
meaning that Loth these views have the same supeiview, auu the constiaints to the
paient view.
Il the constiaint is Letween a view anu its paient view, auu the constiaint to the
paient view.
Il the constiaint is Letween two views that uo not shaie the same paient view, auu
the constiaint to the common ancestoi ol the views.
Figuie 3-1 is a giaphical uemonstiation ol how these constiaints actually woik.
Constiaints aie cieateu using the constraintWithItem:attribute:relatedBy:toItem
:attribute:multiplier:constant: class methou ol the NSLayoutConstraint class. The
uilleient paiameteis to this methou aie:
constraintWithItem
This is a paiametei ol type id anu iepiesents objcct1 in the loimula that I mentioneu
Leloie.
attribute
This iepiesents propcrty1 in oui loimula anu shoulu Le ol type NSLayoutAttribute.
relatedBy
This iepiesents the cqua|s sign in oui loimula. The value ol this paiametei is ol
type NSLayoutRelation anu, as you will soon see, you can specily not only an eguals
sign, Lut a gieatei-than oi less-than sign heie. Ve will talk aLout this in uetail in
this chaptei.
toItem
This paiametei is ol type id anu iepiesents objcct2 in oui loimula.
attribute
This paiametei is ol type NSLayoutAttribute anu iepiesents propcrty2 in oui
loimula.
multiplier
This paiametei is ol type CGFloat anu iepiesents nu|tip|icr in oui loimula.
254 | Chapter 3: Auto Layout and the Visual Format Language
www.it-ebooks.info
constant
This paiametei is also ol type CGFloat anu iepiesents constant va|uc in oui loimula.
Altei you cieate youi constiaints, you can simply auu them to the appiopiiate view
(see Figuie 3-1) using eithei one ol these methous ol the UIView class:
addConstraint:
This methou can auu a single constiaint ol type NSLayoutConstraint to the view.
addConstraints:
This methou allows you to auu an aiiay ol constiaints to the view. The constiaints
again have to Le ol type NSLayoutConstraint wiappeu insiue an aiiay ol type
NSArray.
Theie aie many things that you can achieve with Auto Layout, as you will see in the
iest ol this chaptei. Howevei, the moie you uive in, the moie you`ll iealize that the
setting ol layout automatically will mean cieating moie anu moie constiaints ol type
NSLayoutConstraint. You will notice that youi coue size keeps giowing anu Lecomes
moie uillicult to maintain. Foi this ieason, Apple has cieateu the Visual Foimat
Iigurc 3-1. Thc rc|ationship bctwccn constraints and thc vicws thcy shou|d bc addcd to
3.0 Introduction | 255
www.it-ebooks.info
Language Ly which you can expiess youi constiaints using simply ASCII chaiacteis.
Foi instance, il you have two Luttons anu you want the Luttons to always Le 100 points
apait liom each othei hoiizontally, you woulu expiess it using the Visual Foimat Lan-
guage coue wiitten like this:
[button1]-100-[button2]
Constiaints with the Visual Foimat Language aie cieateu using the constraintsWith
VisualFormat: options:metrics:views: class methou ol the NSLayoutConstraint class.
Heie is a Liiel explanation ol each one ol the paiameteis to this methou:
constraintsWithVisualFormat
The Visual Foimat Language expiession, wiitten as NSString.
options
A paiametei ol type NSLayoutFormatOptions. Foi Visual Foimat Language, we usu-
ally pass 0 to this paiametei.
metrics
A uictionaiy ol constant values that you use in youi Visual Foimat Language ex-
piession. Foi the sake ol simplicity, we will pass nil to this methou loi now.
views
This is a uictionaiy ol views that you have wiitten the constiaint loi in the liist
paiametei ol this methou. To constiuct this uictionaiy, simply use the NSDictio
naryOfVariableBindings C lunction anu pass youi view oLjects to this methou. It
will then constiuct the uictionaiy loi you. The keys in this uictionaiy aie the view
names that you shoulu Le using in the liist paiametei to this methou. Don`t woiiy
il this all is a Lit stiange iight now anu uoesn`t make sense. Soon it will! Once you
see a lew examples ol this, it will all click.
Vith this Lasic inloimation in hanu, anu without Lloating oui heaus with too much
inloimation, I Lelieve it is time to uive stiaight into this chaptei`s iecipes anu llex oui
muscles with constiaints a little Lit. Aie you ieauy? I know I am!
3.1 Placing UI Components in the Center of the Screen
Problem
You want to Le aLle to place a UI component in the centei ol the scieen. In othei woius,
you want to place a view at the centei ol its supeiview, using constiaints.
Solution
Cieate two constiaints: one to align the centei.x position ol the taiget view on its su-
peiview`s centei.x position, anu the othei to align the centei.y position ol the taiget
view on its supeiview`s centei.y position.
256 | Chapter 3: Auto Layout and the Visual Format Language
www.it-ebooks.info
Discussion
Let`s get staiteu Ly liist cieating a simple Lutton, which we will align at the centei ol
the scieen. As mentioneu in the Solution section ol this iecipe, all we have to uo is make
suie the x anu the y ol the centei ol oui Lutton is the same as the x anu y ol the centei
ol the view on which the Lutton iesiues. So loi this, we will cieate two constiaints anu
auu them to the view that owns the Lutton, calleu the supeiview ol the Lutton. Heie
is the simple coue that will achieve this:
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong) UIButton *button;
@end
@implementation ViewController
- (void)viewDidLoad{
[super viewDidLoad];
/* 1) Create our button */
self.button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.button.translatesAutoresizingMaskIntoConstraints = NO;
[self.button setTitle:@"Button" forState:UIControlStateNormal];
[self.view addSubview:self.button];
UIView *superview = self.button.superview;
/* 2) Create the constraint to put the button horizontally in the center */
NSLayoutConstraint *centerXConstraint =
[NSLayoutConstraint constraintWithItem:self.button
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeCenterX
multiplier:1.0f
constant:0.0f];
/* 3) Create the constraint to put the button vertically in the center */
NSLayoutConstraint *centerYConstraint =
[NSLayoutConstraint constraintWithItem:self.button
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeCenterY
multiplier:1.0f
constant:0.0f];
/* Add the constraints to the superview of the button */
[superview addConstraints:@[centerXConstraint, centerYConstraint]];
}
/* Suport rotation of device to all orientations */
3.1 Placing UI Components in the Center of the Screen | 257
www.it-ebooks.info
- (NSUInteger) supportedInterfaceOrientations{
return UIInterfaceOrientationMaskAll;
}
- (void)didReceiveMemoryWarning{
[super didReceiveMemoryWarning];
}
@end
This view contiollei is tiying to tell iOS that it suppoits all inteilace
oiientations that the uevice suppoits, to uemonstiate that the Lutton
will inueeu Le placeu in the centei ol the scieen iegaiuless ol the type
ol uevice anu its oiientation. Howevei, Leloie this methou takes ovei,
you neeu to make suie you have enaLleu all ieguiieu oiientations insiue
youi pioject itsell. To uo this, navigate in Xcoue to youi taiget piopei-
ties, go to the Summaiy taL, linu the Suppoiteu Inteilace Oiientations
section, anu enaLle all the availaLle oiientations, as shown in Figuie 3-2.
Iigurc 3-2. Enab|ing a|| supportcd intcrjacc oricntation in Xcodc jor your targct
Now il you iun this app on the uevice oi in the simulatoi, you will notice that a simple
Lutton is uisplayeu on the scieen. Now iotate the uevice anu note how the Lutton stays
at the centei ol the scieen. All ol this was achieveu without having to wiite a single line
ol coue loi setting the liame ol the Lutton oi listening to any type ol oiientation change
notilication anu aujusting the position ol the Lutton, thanks to Auto Layout. See Fig-
uie 3-3. This appioach is Lettei simply Lecause oui coue now will woik on any uevice
in any oiientation with any iesolution. In contiast, il we weie to set the liame ol oui
UI components, we woulu have to set the liame loi each oiientation on each uevice we
woulu want to suppoit, Lecause uilleient iOS uevices can have uilleient scieen ieso-
lutions. Foi instance, oui app now will happily Le aLle to iun on an iPau oi an iPhone
anu will ietain the Lutton in the centei ol the scieen, iegaiuless ol the oiientation oi
the iesolution ol the uevice anu its uisplay.
See Also
Recipe 3.2; Recipe 3.0
258 | Chapter 3: Auto Layout and the Visual Format Language
www.it-ebooks.info
3.2 Defining Horizontal and Vertical Constraints with the
Visual Format Language
Problem
You want to Le aLle to ueline constiaints that change the way a UI component is hoi-
izontally oi veitically aligneu on its supeiview.
Solution
Use the H: oiientation speciliei in the loimatting stiing loi youi constiaint to uictate
hoiizontal alignment, anu the V: oiientation speciliei to uictate veitical alignment.
Discussion
I won`t pietenu the Visual Foimat Language is easy to unueistanu. It is inueeu veiy
ciyptic. Foi this ieason, I will give you a lew examples that hopelully will cleai things
up. All ol these examples will change the hoiizontal alignment ol a Lutton on the scieen
(Figuie 3-+).
As you can see, the loimatting might take you some time to get useu to. Howevei, once
you get the hang ol the Lasics ol it, it will slowly stait to make sense. The same iules
apply loi veitical alignment, which uses the V: oiientation speciliei. Figuie 3-5 shows
an example.
Let`s put the things that we have leaineu so lai into piactice. How aLout wiiting con-
stiaints using the Visual Foimat Language that iepiesent a UI similai to that uepicteu
in Figuie 3-6?
Iigurc 3-3. Thc button is at thc ccntcr oj thc scrccn in cvcry oricntation
3.2 Defining Horizontal and Vertical Constraints with the Visual Format Language | 259
www.it-ebooks.info
To help apps look consistent anu make uecisions easiei loi the uesigneis
ol apps, Apple has uesigneu stanuaiu uistances oi spaces Letween UI
components. The stanuaius aie uesciiLeu in Apple`s iOS Human In-
teilace Guiuelines.
Beloie we uive into couing, let`s put uown the constiaints as we can see them in the
liguie:
The email lielu has stanuaiu veitical uistance to the top ol the view.
The conliim email lielu has stanuaiu veitical uistance to the email lielu.
The Registei Lutton has stanuaiu veitical uistance to the conliim email lielu.
All components aie hoiizontally centeieu in ielation to the paient (supei) view.
Both the email anu the conloim email lielus have stanuaiu hoiizontal uistance liom
the lelt anu the iighthanu siue ol the supei view.
The wiuth ol the Lutton is lixeu at 12S points.
Shall we uig into the coue now to achieve this? Let`s stait Ly actually uelining oui
constiaints in plain Visual Foimat Language on top ol oui view contiollei:
Iigurc 3-1. Thrcc sinp|c cxanp|cs oj thc usagc oj thc \isua| Iornat Languagc jor horizonta|
constraints
260 | Chapter 3: Auto Layout and the Visual Format Language
www.it-ebooks.info
/* Email text field constraints */
NSString *const kEmailTextFieldHorizontal = @"H:|-[_textFieldEmail]-|";
NSString *const kEmailTextFieldVertical = @"V:|-[_textFieldEmail]";
/* Confirm email text field constraints */
NSString *const kConfirmEmailHorizontal = @"H:|-[_textFieldConfirmEmail]-|";
NSString *const kConfirmEmailVertical =
@"V:[_textFieldEmail]-[_textFieldConfirmEmail]";
Iigurc 3-5. An cxanp|c oj sctting vcrtica| a|ignncnt using thc \isua| Iornat Languagc
Iigurc 3-. Thc U| that wc want to achicvc using constraints and thc \isua| Iornat Languagc
3.2 Defining Horizontal and Vertical Constraints with the Visual Format Language | 261
www.it-ebooks.info
/* Register button constraint */
NSString *const kRegisterVertical =
@"V:[_textFieldConfirmEmail]-[_registerButton]";
It is immeuiately oLvious that Loth text lielus have Loth theii hoiizontal anu veitical
constiaints uelineu in the Visual Foimat Language, Lut the Registei Lutton has only
its veitical constiaint uelineu as a Visual Foimat Language expiession. Vhy is that? It
tuins out centei aligning a UI component hoiizontally is not possiLle with the Visual
Foimat Language. Foi this, we aie going to have to use the same technigue that we
leaineu in Recipe 3.1. But that`s OK. Don`t let that stop you liom enjoying the Visual
Foimat Language anu linuing out how poweilul it tiuly is. OLviously nothing is peilect,
Lut that uoesn`t mean we shoulun`t use it.
Now let`s ueline oui UI components as piivate piopeities ol oui view contiollei in the
implementation lile ol the view contiollei:
@interface ViewController ()
@property (nonatomic, strong) UITextField *textFieldEmail;
@property (nonatomic, strong) UITextField *textFieldConfirmEmail;
@property (nonatomic, strong) UIButton *registerButton;
@end
Vhat`s next? Ve neeu to actually constiuct oui UI components in the implementation
lile ol the view contiollei. So we will wiite two hanuy methous that will help us uo this.
Again, iememLei, we aie not going to set the liame ol these UI components. Auto
Layout will latei help us with this:
- (UITextField *) textFieldWithPlaceholder:(NSString *)paramPlaceholder{
UITextField *result = [[UITextField alloc] init];
result.translatesAutoresizingMaskIntoConstraints = NO;
result.borderStyle = UITextBorderStyleRoundedRect;
result.placeholder = paramPlaceholder;
return result;
}
- (void) constructUIComponents{
self.textFieldEmail =
[self textFieldWithPlaceholder:@"Email"];
self.textFieldConfirmEmail =
[self textFieldWithPlaceholder:@"Confirm Email"];
self.registerButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.registerButton.translatesAutoresizingMaskIntoConstraints = NO;
[self.registerButton setTitle:@"Register" forState:UIControlStateNormal];
}
The textFieldWithPlaceholder: methou simply cieates text lielus that contain a given
placeholuei text anu the constructUIComponents methou cieates the two text lielus
262 | Chapter 3: Auto Layout and the Visual Format Language
www.it-ebooks.info
using the pieviously mentioneu methou anu the Lutton. You have pioLaLly noticeu
that we aie setting the translatesAutoresizingMaskIntoConstraints piopeity ol all oui
UI components to NO. This will loice UIKit not to think that autoiesizing masks have
something to uo with Auto Layout constiaints. As you know, you can set autoiesizing
masks loi youi UI components anu view contiolleis in coue anu inteilace Luiluei, as
we leaineu in Chaptei 2. Setting this piopeity to NO makes suie that UIKit won`t mix
things up anu won`t automatically tianslate autoiesizing masks to Auto Layout con-
stiaints. Setting this option is ieguiieu il you aie mixing Auto Layout piopeities ol youi
components with layout constiaints. It is geneially a goou iuea to set this piopeity ol
all youi UI components to NO whenevei you aie woiking with Auto Layout constiaints,
unless you explicitly want UIKit to tianslate autoiesizing masks to Auto Layout con-
stiaints.
Ve aie constiucting oui UI components, Lut the viewDidLoad methou ol oui view con-
tiollei oLviously neeus to auu all thiee UI components to oui view, so why not have a
little methou that will help us with this?
- (void) addUIComponentsToView:(UIView *)paramView{
[paramView addSubview:self.textFieldEmail];
[paramView addSubview:self.textFieldConfirmEmail];
[paramView addSubview:self.registerButton];
}
Ve aie almost theie. The next Lig task is to cieate methous that allow us to constiuct
anu collect all the constiaints into an aiiay. Foi this, we have thiee methous that ietuin
the constiaints ol each one ol oui UI components as an aiiay. Ve also have a hanuy
louith methou that collects all the constiaints liom all thiee UI components anu puts
them into one Lig aiiay. Heie is how we have implementeu it:
- (NSArray *) emailTextFieldConstraints{
NSMutableArray *result = [[NSMutableArray alloc] init];
NSDictionary *viewsDictionary =
NSDictionaryOfVariableBindings(_textFieldEmail);
[result addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:kEmailTextFieldHorizontal
options:0
metrics:nil
views:viewsDictionary]
];
[result addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:kEmailTextFieldVertical
options:0
metrics:nil
views:viewsDictionary]
];
3.2 Defining Horizontal and Vertical Constraints with the Visual Format Language | 263
www.it-ebooks.info
return [NSArray arrayWithArray:result];
}
- (NSArray *) confirmEmailTextFieldConstraints{
NSMutableArray *result = [[NSMutableArray alloc] init];
NSDictionary *viewsDictionary =
NSDictionaryOfVariableBindings(_textFieldConfirmEmail, _textFieldEmail);
[result addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:kConfirmEmailHorizontal
options:0
metrics:nil
views:viewsDictionary]
];
[result addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:kConfirmEmailVertical
options:0
metrics:nil
views:viewsDictionary]
];
return [NSArray arrayWithArray:result];
}
- (NSArray *) registerButtonConstraints{
NSMutableArray *result = [[NSMutableArray alloc] init];
NSDictionary *viewsDictionary =
NSDictionaryOfVariableBindings(_registerButton, _textFieldConfirmEmail);
[result addObject:
[NSLayoutConstraint constraintWithItem:self.registerButton
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1.0f
constant:0.0f]
];
[result addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:kRegisterVertical
options:0
metrics:nil
views:viewsDictionary]
];
264 | Chapter 3: Auto Layout and the Visual Format Language
www.it-ebooks.info
return [NSArray arrayWithArray:result];
}
- (NSArray *) constraints{
NSMutableArray *result = [[NSMutableArray alloc] init];
[result addObjectsFromArray:[self emailTextFieldConstraints]];
[result addObjectsFromArray:[self confirmEmailTextFieldConstraints]];
[result addObjectsFromArray:[self registerButtonConstraints]];
return [NSArray arrayWithArray:result];
}
It`s in lact the constraints instance methou ol oui view contiollei that collects all the
constiaints loi all thiee UI components anu ietuins it as one Lig aiiay. Now loi the
main pait ol the contiollei, the viewDidLoad methou:
- (void)viewDidLoad{
[super viewDidLoad];
[self constructUIComponents];
[self addUIComponentsToView:self.view];
[self.view addConstraints:[self constraints]];
}
- (NSUInteger) supportedInterfaceOrientations{
return UIInterfaceOrientationMaskAll;
}
This methou simply constiucts the UI, auuing the UI components anu theii constiaints
to itsell using the methous we wiote Leloie. Gieat stull, Lut how uoes it look on the
scieen when we iun the piogiam? Ve have alieauy seen how it looks in the poitiait
moue ol the uevice (see Figuie 3-6) Lut let`s see how it will look once we iotate the
uevice`s oiientation to lanuscape (Figuie 3-7).
See Also
Recipe 3.0; Recipe 3.1
3.3 Utilizing Cross View Constraints
Problem
You want to align a UI component in ielation to anothei UI component, Lut these UI
components have uilleient paients.
3.3 Utilizing Cross View Constraints | 265
www.it-ebooks.info
Solution
Utilizing Figuie 3-1, make suie that you linu the common UI supeiview Letween the
two UI components anu auu youi constiaint to that supeiview.
Discussion
Beloie going into too much uetail, let`s liist see what cioss view constiaints aie all
aLout. I Lelieve I can uemonstiate it to you in a pictuie Lettei than it can Le explaineu
in woius, so check out Figuie 3-S.
Iigurc 3-8. Thc inportant cross vicw constraints bctwccn two buttons arc dcpictcd in this photo
Iigurc 3-7. Thc constraints sccn to bc wor|ing just as jinc in |andscapc as thcy wor| in portrait nodc
266 | Chapter 3: Auto Layout and the Visual Format Language
www.it-ebooks.info
Many constiaints have Leen applieu to the views in this liguie, Lut let`s stait one Ly
one anu Lieak it uown into small chunks:
Ve have two giay views on the main view ol oui view contiollei. Both shoulu have
stanuaiu space liom the lelt anu the iight siue ol the view ol the view contiollei.
Theie must Le stanuaiu space liom the top ol the view to the top ol the view on
top. Theie shoulu Le stanuaiu veitical space Letween the two giay views.
Theie must Le a Lutton veitically centeieu in Loth giay views.
The Lutton on the top giay view shoulu have stanuaiu space to the lelt ol its su-
peiview.
The Lutton on the Lottom giay view shoulu have its lelthanu siue aligneu with the
iighthanu siue ol the Lutton in the top giay view. This is the cioss view constiaint
that is veiy impoitant to us.
The giay views shoulu Le aLle to get iesizeu as the view ol the view contiollei
changes oiientation.
The height ol Loth giay views must Le 100 points.
OK, let`s Legin. Ve aie going to uo all this Ly staiting liom the viewDidLoad methou ol
oui view contiollei. It`s always Lest to think ol a clean way ol putting all youi methous
togethei. OLviously, in this example, we aie woiking with guite a lew constiaints anu
views, so how can we make the viewDidLoad methou ol oui view contiollei clean? Like
this:
- (void)viewDidLoad{
[super viewDidLoad];
[self createGrayViews];
[self createButtons];
[self applyConstraintsToTopGrayView];
[self applyConstraintsToButtonOnTopGrayView];
[self applyConstraintsToBottomGrayView];
[self applyConstraintsToButtonOnBottomGrayView];
}
Ve have simply Lioken oui tasks uown into uilleient methous, which we aie soon
going to implement. Let`s go aheau anu ueline oui views in the implementation lile ol
oui view contiollei as an extension to oui inteilace:
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong) UIView *topGrayView;
@property (nonatomic, strong) UIButton *topButton;
@property (nonatomic, strong) UIView *bottomGrayView;
3.3 Utilizing Cross View Constraints | 267
www.it-ebooks.info
@property (nonatomic, strong) UIButton *bottomButton;
@end
@implementation ViewController
...
The next step is to implement the createGrayViews methou. As its name shows, this
methou is iesponsiLle loi cieating oui giay views on the scieen:
- (UIView *) newGrayView{
UIView *result = [[UIView alloc] init];
result.backgroundColor = [UIColor lightGrayColor];
result.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:result];
return result;
}
- (void) createGrayViews{
self.topGrayView = [self newGrayView];
self.bottomGrayView = [self newGrayView];
}
Simple enough? Both giay views aie getting auueu to the view ol oui view contiollei.
Gieat stull. Vhat`s next? Ve now neeu to implement the createButtons methou, Le-
cause it is getting calleu in the viewDidLoad methou ol oui view contiollei. This methou
shoulu simply cieate oui Luttons anu place them on theii associateu giay views:
- (UIButton *) newButtonPlacedOnView:(UIView *)paramView{
UIButton *result = [UIButton buttonWithType:UIButtonTypeRoundedRect];
result.translatesAutoresizingMaskIntoConstraints = NO;
[result setTitle:@"Button" forState:UIControlStateNormal];
[paramView addSubview:result];
return result;
}
- (void) createButtons{
self.topButton = [self newButtonPlacedOnView:self.topGrayView];
self.bottomButton = [self newButtonPlacedOnView:self.bottomGrayView];
}
Again, as you can see in the createButtons methou, altei the cieation ol oui giay views
anu the Luttons, we neeu to stait applying the constiaints to the giay views anu the
Luttons. Ve will stait Ly applying the constiaints to the top giay view. These con-
stiaints must covei the lollowing conuitions:
The top view has to have stanuaiu space liom the lelt anu the top ol the view ol
the view contiollei.
268 | Chapter 3: Auto Layout and the Visual Format Language
www.it-ebooks.info
The height ol this giay view has to Le 100 points.
- (void) applyConstraintsToTopGrayView{
NSDictionary *views = NSDictionaryOfVariableBindings(_topGrayView);
NSMutableArray *constraints = [[NSMutableArray alloc] init];
NSString *const kHConstraint = @"H:|-[_topGrayView]-|";
NSString *const kVConstraint = @"V:|-[_topGrayView(==100)]";
/* Horizontal constraint(s) */
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:kHConstraint
options:0
metrics:nil
views:views]
];
/* Vertical constraint(s) */
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:kVConstraint
options:0
metrics:nil
views:views]
];
[self.topGrayView.superview addConstraints:constraints];
}
It`s impoitant to note how we aie constiucting the veitical constiaint ol the top giay
view. You can see that we aie using the (==100) loimat to specily that the height ol the
top giay view has to Le 100 points. The ieason that the iuntime is inteipieting this
value as the height is Lecause ol the V: speciliei that tells the iuntime that the numLeis
we aie leeuing into the system have something to uo with the height anu the veitical
alignment ol the taiget view, iathei than the wiuth oi the hoiizontal alignment.
The next thing that we neeu to take caie ol is to set the constiaints loi the Lutton on
the top giay view. This is uone thiough the applyConstraintsToButtonOnTopGrayView
methou. This Lutton will have the lollowing constiaints, as specilieu Leloie:
It shoulu sit veitically in the centei ol the top giay view.
It shoulu have stanuaiu uistance liom the lelt ol the top giay view.
It shoulu have no specilic height oi wiuth uelineu anu shoulu lit its content, aka
the Button text that we`ve ueciueu to put in it.
- (void) applyConstraintsToButtonOnTopGrayView{
NSDictionary *views = NSDictionaryOfVariableBindings(_topButton);
NSMutableArray *constraints = [[NSMutableArray alloc] init];
3.3 Utilizing Cross View Constraints | 269
www.it-ebooks.info
NSString *const kHConstraint = @"H:|-[_topButton]";
/* Horizontal constraint(s) */
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:kHConstraint
options:0
metrics:nil
views:views]
];
/* Vertical constraint(s) */
[constraints addObject:
[NSLayoutConstraint constraintWithItem:self.topButton
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.topGrayView
attribute:NSLayoutAttributeCenterY
multiplier:1.0f
constant:0.0f]
];
[self.topButton.superview addConstraints:constraints];
}
Ve aie all uone with the top giay view anu the Lutton insiue it. Time to move on to
the Lottom giay view anu its Lutton. The methou we shoulu take caie ol now is the
applyConstraintsToBottomGrayView methou. This methou will Le setting the constiaints
loi the Lottom giay view. ]ust to iecap, the constiaints that we have to cieate loi this
view aie:
Must have stanuaiu uistance liom the lelt ol the view ol the view contiollei.
Must have stanuaiu uistance liom the Lottom ol the top giay view.
Must have the height ol 100 points.
- (void) applyConstraintsToBottomGrayView{
NSDictionary *views = NSDictionaryOfVariableBindings(_topGrayView,
_bottomGrayView);
NSMutableArray *constraints = [[NSMutableArray alloc] init];
NSString *const kHConstraint = @"H:|-[_bottomGrayView]-|";
NSString *const kVConstraint =
@"V:|-[_topGrayView]-[_bottomGrayView(==100)]";
/* Horizontal constraint(s) */
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:kHConstraint
options:0
metrics:nil
views:views]
];
270 | Chapter 3: Auto Layout and the Visual Format Language
www.it-ebooks.info
/* Vertical constraint(s) */
[constraints addObjectsFromArray:
[NSLayoutConstraint constraintsWithVisualFormat:kVConstraint
options:0
metrics:nil
views:views]
];
[self.bottomGrayView.superview addConstraints:constraints];
}
The veitical constiaints loi the Lottom giay view may look a Lit long in Visual Foimat
Language, Lut it`s veiy simple inueeu. Il you have a close look, you`ll notice that the
constiaints aie just aligning the top anu the Lottom giay view on the view ol the view
contiollei using stanuaiu uistance specilieis anu the constant height ol 100 points.
The next anu peihaps the last UI component loi which we have to wiite constiaints is
the Lutton on the Lottom giay view. The methou that will take caie ol this is calleu
applyConstraintsToButtonOnBottomGrayView. Beloie we implement this methou, let`s
talk aLout the constiaint ieguiiements loi the Lottom Lutton:
It shoulu Le veitically aligneu at the centei ol the Lottom giay view.
Its lelt siue shoulu Le aligneu with the iight siue ol the Lutton on the top giay view.
It shoulu have no specilic height oi wiuth uelineu anu shoulu lit its content, aka
the Button text that we`ve ueciueu to put in it.
- (void) applyConstraintsToButtonOnBottomGrayView{
NSDictionary *views = NSDictionaryOfVariableBindings(_topButton,
_bottomButton);
NSString *const kHConstraint = @"H:[_topButton][_bottomButton]";
/* Horizontal constraint(s) */
[self.bottomGrayView.superview addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:kHConstraint
options:0
metrics:nil
views:views]
];
/* Vertical constraint(s) */
[self.bottomButton.superview addConstraint:
[NSLayoutConstraint constraintWithItem:self.bottomButton
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.bottomGrayView
attribute:NSLayoutAttributeCenterY
multiplier:1.0f
constant:0.0f]
];
3.3 Utilizing Cross View Constraints | 271
www.it-ebooks.info
}
Last Lut not least, we neeu to make suie oui view contiollei tells the iuntime that it is
aLle to hanule all oiientations, just to uemonstiate the point ol this iecipe, so we shoulu
oveiiiue the supportedInterfaceOrientations methou ol UIViewController:
- (NSUInteger) supportedInterfaceOrientations{
return UIInterfaceOrientationMaskAll;
}
Ve aie uone with this view contiollei now. Let`s iun oui app anu see how it Lehaves
in poitiait moue (see Figuie 3-9).
Iigurc 3-9. Our app rcndcrs thc U| conponcnts in portrait nodc according to thc rcquircncnts that
wc sct
The moment ol tiuth! How aLout in lanuscape moue? Do we uaie iun the app in
lanuscape anu see whethei it Lehaves as expecteu? Let`s give it a go (see Figuie 3-10).
Peilect. I think we naileu it.
See Also
Recipe 3.0
272 | Chapter 3: Auto Layout and the Visual Format Language
www.it-ebooks.info
3.4 Configuring Auto Layout Constraints in Interface Builder
Problem
You want to Le aLle to utilize Inteilace Builuei`s powei in oiuei to cieate youi UI
constiaints.
Solution
Follow these steps:
1. Open the XIB that you want to euit in Inteilace Builuei.
2. In Inteilace Builuei, make suie that you have selecteu the view oLject on which
you want to enaLle Auto Layout, simply Ly clicking on that view oLject.
3. Click on the View Utilities Show File Inspectoi menu item.
+. In the File Inspectoi, unuei the Inteilace Builuei Document section, make suie that
the Usc Auto Layout check is enaLleu, as shown in Figuie 3-11.
Discussion
Inteilace Builuei can help us piogiammeis a lot in cieating constiaints without much
involvement liom us. Noimally, Leloie the intiouuction ol Auto Layout to iOS, the
guiueline Lais that appeaieu on the scieen while you moveu UI components aiounu
on a view weie ielateu to Autosizing masks that you coulu also cieate in coue, just like
Constiaints. Howevei, altei switching on the Use Auto Layout option in Inteilace
Builuei, the guiuelines tell you something else. They aie telling you aLout the con-
stiaints that Inteilace Builuei is cieating loi you in the Lackgiounu.
Iigurc 3-10. Thc sanc codc bchavcs as cxpcctcd in |andscapc nodc
3.4 Configuring Auto Layout Constraints in Interface Builder | 273
www.it-ebooks.info
Let`s uo a little expeiiment. Cieate a new Single View Application pioject in Xcoue.
This will cieate an application with a single view contiollei loi you. The class loi youi
view contiollei will Le ViewController anu the XIB lile loi this view contiollei will Le
\icwContro||cr.xib. Simply click on this lile to let Inteilace Builuei open it loi you.
Make suie that the Use Auto Layout option is tickeu in the File Inspectoi, as explaineu
in the Solution section ol this iecipe.
Now liom the OLject LiLiaiy, simply uiag anu uiop a Round Rcct Button onto the
centei ol the scieen until Inteilace Builuei guiuelines appeai on the scieen, telling you
that now the centei ol the Lutton is aligneu with the centei ol the scieen. Fiom the Euit
menu, now choose the Show Document Outline. Il you alieauy have the Document
Outline section ol Inteilace Builuei open, this menu item will ieau Hiue Document
Outline, in which case you uon`t have to take any action. Now in the Document Out-
line, have a look unuei a new Llue-coloieu section that has Leen cieateu loi you, nameu
Constiaints. Expanu the constiaints that Inteilace Builuei has cieateu loi you loi this
Lutton. Vhat you see now is guite similai to what is shown in Figuie 3-12.
As you can see, Inteilace Builuei cieateu two constiaints loi you. One ol the constiaints
is saying that the X position ol the centei point ol oui Lutton has to Le aligneu with
the X position ol the centei point ol the view on which the Lutton iesiues. In othei
woius, this means that the Lutton has to Le hoiizontally centeieu on its supeiview. The
othei constiaint is saying that the Lutton has to always have a uistance ol 20S points
liom the top ol its supeiview. Now il you iun this app in poitiait moue, you will see
the Lutton at the centei ol scieen, as shown in Figuie 3-13.
Now iotate the uevice to lanuscape moue anu you will see that the Lutton stays hoii-
zontally centeieu, Lut the veitical alignment is not centeieu, which is again what we
Iigurc 3-11. Enab|ing Auto Layout in |ntcrjacc Bui|dcr
274 | Chapter 3: Auto Layout and the Visual Format Language
www.it-ebooks.info
expecteu. The constiaint that Xcoue cieateu is loi the Lutton to maintain a uistance ol
20S points liom the top point ol its supeiview (see Figuie 3-1+).
Constiaints that aie cieateu using the Visual Foimat Language oi
thiough Inteilace Builuei uo not have the aLility to veitically centei-
align a component on its supeiview. To Le aLle to uo this, simply
cieate a constiaint using the constraintWithItem:attribute:related
By:toItem:attribute:multiplier:constant: class methou ol the class
NSLayoutConstraint, as uiscusseu Leloie.
It is woith noting that you can actually mouily the layout constiaints that Inteilace
Builuei has cieateu loi you. Simply click on one ol the constiaints anu then pop open
the AttiiLutes Inspectoi ol Inteilace Builuei. You shall now Le aLle to see the uilleient
Iigurc 3-12. |ntcrjacc Bui|dcr crcatcd Layout Constraints jor us
Iigurc 3-13. Thc button appcars to bc ccntcrcd on its supcrvicw in portrait nodc
3.4 Configuring Auto Layout Constraints in Interface Builder | 275
www.it-ebooks.info
piopeities that aie availaLle loi mouilication, iight in Inteilace Builuei, as shown in
Figuie 3-15.
Iigurc 3-15. Modijying a constraint in |ntcrjacc Bui|dcr
Iigurc 3-11. Thc button naintains a vcrtica| distancc oj 208 jron thc top oj its supcrvicw
276 | Chapter 3: Auto Layout and the Visual Format Language
www.it-ebooks.info
See Also
Recipe 3.0
3.4 Configuring Auto Layout Constraints in Interface Builder | 277
www.it-ebooks.info
www.it-ebooks.info
CHAPTER 4
Constructing and Using Table Views
4.0 Introduction
A taLle view is simply a sciolling view that is sepaiateu into sections, each ol which is
luithei sepaiateu into iows. Each iow is an instance ol the UITableViewCell class, anu
you can cieate custom taLle view iows Ly subc|assing this class.
Using taLle views is an iueal way to piesent a list ol items to useis. You can emLeu
images, text, anu othei oLjects into youi taLle view cells; you can customize theii height,
shape, giouping, anu much moie. The simplicity ol the stiuctuie ol taLle views is what
makes them highly customizaLle.
A taLle view can Le leu with uata using a taLle view uata souice, anu you can ieceive
vaiious events anu contiol the physical appeaiance ol taLle views using a taLle view
uelegate oLject. These aie uelineu, iespectively, in the UITableViewDataSource anu
UITableViewDelegate piotocols.
Although an instance ol UITableView suLclasses UIScrollView, taLle views can only
scioll veitically. This is moie a leatuie than a limitation. In this chaptei, we will uiscuss
the uilleient ways ol cieating, managing, anu customizing taLle views.
4.1 Instantiating a Table View
Problem
You want to place a taLle view on youi UI.
Solution
Instantiate an oLject ol type UITableView anu auu it as a suLview ol any ol youi views.
279
www.it-ebooks.info
Discussion
Theie aie two ways ol instantiating a taLle view:
1. Thiough coue
2. Using Inteilace Builuei
Il you aie using Inteilace Builuei, cieating a taLle view is as simple as uiagging anu
uiopping a taLle view liom the oLject liLiaiy into youi .xib lile. Il you aie moie com-
loitaLle cieating youi components using coue, then that is no pioLlem eithei. All you
have to uo is to instantiate an oLject ol type UITableView. Let`s stait Ly uelining oui
taLle view in oui view contiollei`s heauei lile:
#import <UIKit/UIKit.h>
@interface Instantiating_a_Table_ViewViewController : UIViewController
@property (nonatomic, strong) UITableView *myTableView;
@end
Anu cieating the view contiollei is as easy as just allocating anu initializing an instance
ol UITableView:
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.myTableView =
[[UITableView alloc] initWithFrame:self.view.bounds
style:UITableViewStylePlain];
[self.view addSubview:self.myTableView];
}
The style paiametei ol the initWithFrame:style: initializei ol the view contiollei al-
lows us to specily what type ol taLle view we neeu. Theie aie two styles that we can
choose liom:
UITableViewStylePlain
Cieates a plain taLle view with no Lackgiounu images.
UITableViewStyleGrouped
Cieates a taLle view with a Lackgiounu image anu iounueu gioup Loiueis, similai
to the Settings app.
Il you iun youi app iight now on the iPhone Simulatoi, you will see the taLle view
sitting theie with no taLle view cells populateu insiue it (Figuie +-1).
280 | Chapter 4: Constructing and Using Table Views
www.it-ebooks.info
Iigurc 1-1. A p|ain tab|c vicw with no contcnt
4.2 Assigning a Delegate to a Table View
Problem
You have ueciueu to assign a uelegate to a taLle view.
Solution
Assign an oLject that conloims to the UITableViewDelegate piotocol to the delegate
piopeity ol youi taLle view:
- (void)viewDidLoad{
[super viewDidLoad];
/* We want a full-screen Table View which is as
big as the View attached to the current
View Controller */
CGRect tableViewFrame = self.view.bounds;
self.myTableView = [[UITableView alloc]
initWithFrame:tableViewFrame
style:UITableViewStylePlain];
self.myTableView.delegate = self;
/* Add this Table View to our View */
[self.view addSubview:self.myTableView];
}
4.2 Assigning a Delegate to a Table View | 281
www.it-ebooks.info
This coue assigns the cuiient oLject as the uelegate ol the taLle view. myTableView is a
piopeity ol type UITableView Lelonging to the calling view contiollei. The statement is
emLeuueu in the viewDidLoad methou, Lecause the calling oLject heie is an instance ol
UIViewController, anu this methou is the iight place to put the statement so that the
association is maue just once.
Discussion
The UITableView class uelines a piopeity calleu delegate. The taLle view shoulu assign
to this piopeity an oLject that conloims to the UITableViewDelegate piotocol. In othei
woius, this uelegate must pronisc to ieply to the messages uelineu in this piotocol,
which aie sent to the uelegate oLject Ly the taLle view itsell. Think ol the uelegate ol a
taLle view as an oLject that listens to vaiious events sent Ly the taLle view, such as when
a cell is selecteu oi when the taLle view wants to liguie out the height ol each ol its
cells. Ve can mouily the visual appeaiance ol a taLle anu its cells (to some extent) using
Inteilace Builuei, too. ]ust open Inteilace Builuei anu select a taLle view that you pie-
viously cieateu, anu then select Tools Size Inspectoi. In the Size Inspectoi panel, you
can mouily the visual appeaiance ol the taLle view Ly changing values such as the height
ol the taLle view`s cells.
To make the uelegate oLject that you choose loi a taLle view conloim to the UITable
ViewDelegate piotocol, you neeu to auu that piotocol to that oLject`s inteilace uecla-
iation in this way:
#import <UIKit/UIKit.h>
@interface Assigning_a_Delegate_to_a_Table_ViewViewController
: UIViewController <UITableViewDelegate>
@property (nonatomic, strong) UITableView *myTableView;
@end
It is manuatoiy loi the uelegate oLject to iesponu to messages that aie
maikeu as @required Ly the UITableViewDelegate piotocol. Responuing
to othei messages is optional, Lut the uelegate must iesponu to any
messages you want to allect the taLle view.
Messages sent to the uelegate oLject ol a taLle view caiiy a paiametei that tells the
uelegate oLject which taLle view has liieu that message in its uelegate. This is veiy
impoitant to note Lecause you might, unuei ceitain ciicumstances, ieguiie moie than
one taLle view to Le placeu on one oLject (usually a view). Because ol this, it is highly
iecommenueu that you make youi uecisions Laseu on which taLle view has actually
sent that specilic message to youi uelegate oLject, like so:
- (CGFloat) tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath{
282 | Chapter 4: Constructing and Using Table Views
www.it-ebooks.info
CGFloat result = 20.0f;
if ([tableView isEqual:self.myTableView]){
result = 40.0f;
}
return result;
}
It is woith noting that the location ol a cell in a taLle view is iepiesenteu Ly its inuex
path. An inuex path is the comLination ol the section anu the iow inuex, wheie the
section inuex is the zeio-Laseu inuex specilying which giouping oi section each cell
Lelongs to, anu the cell inuex is the zeio-Laseu inuex ol that paiticulai cell in its section.
4.3 Populating a Table View with Data
Problem
You woulu like to populate youi taLle view with uata.
Solution
Conloim to the UITableViewDataSource piotocol in an oLject anu assign that oLject to
the dataSource piopeity ol a taLle view.
Discussion
Cieate an oLject that conloims to the UITableViewDataSource piotocol anu assign it to
a taLle view instance. Then, Ly iesponuing to the uata souice messages, pioviue inloi-
mation to youi taLle view. Foi this example, let`s go aheau anu ueclaie the .h lile ol oui
view contiollei, which will latei cieate a taLle view on its own view, in coue:
#import <UIKit/UIKit.h>
@interface Populating_a_Table_View_with_DataViewController
: UIViewController <UITableViewDataSource>
@property (nonatomic, strong) UITableView *myTableView;
@end
In the viewDidLoad methou ol oui view contiollei, we will cieate the taLle view anu will
assign oui view contiollei as its uata souice:
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.myTableView =
4.3 Populating a Table View with Data | 283
www.it-ebooks.info
[[UITableView alloc] initWithFrame:self.view.bounds
style:UITableViewStylePlain];
self.myTableView.dataSource = self;
/* Make sure our table view resizes correctly */
self.myTableView.autoresizingMask =
UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;
[self.view addSubview:self.myTableView];
}
Now we neeu to make suie oui taLle view iesponus to the @required methous ol the
UITableViewDataSource piotocol. Holu uown the Commanu key on youi keyLoaiu anu
click on the UITableViewDataSource piotocol`s mention in youi view contiollei`s .h lile.
This will show you the ieguiieu methous loi this piotocol.
The UITableView class uelines a piopeity calleu dataSource. This is an untypeu oLject
that must conloim to the UITableViewDataSource piotocol. Eveiy time a taLle view is
ieliesheu anu ieloaueu using the reloadData methou, the taLle view will call vaiious
methous in its uata souice to linu out aLout the uata you intenu to populate it with. A
taLle view uata souice can implement thiee impoitant methous, two ol which aie
manuatoiy loi eveiy uata souice:
numberOfSectionsInTableView:
This methou allows the uata souice to inloim the taLle view ol the numLei ol
sections that must Le loaueu into the taLle.
tableView:numberOfRowsInSection:
This methou tells the view contiollei how many cells oi iows have to Le loaueu loi
each section. The section numLei is passeu to the uata souice in the numberOfRows
InSection paiametei. The implementation ol this methou is manuatoiy in the uata
souice oLject.
tableView:cellForRowAtIndexPath:
This methou is iesponsiLle loi ietuining instances ol the UITableViewCell class as
iows that have to Le populateu into the taLle view. The implementation ol this
methou is manuatoiy in the uata souice oLject.
So let`s go aheau anu implement these methous in oui view contiollei, one Ly one.
Fiist, let`s tell the taLle view that we want it to ienuei thiee sections:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
NSInteger result = 0;

284 | Chapter 4: Constructing and Using Table Views
www.it-ebooks.info
if ([tableView isEqual:self.myTableView]){
result = 3;
}
return result;
}
Then we tell the taLle view how many iows we want it to ienuei, loi each section:
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section{
NSInteger result = 0;
if ([tableView isEqual:self.myTableView]){
switch (section){
case 0:{
result = 3;
break;
}
case 1:{
result = 5;
break;
}
case 2:{
result = 8;
break;
}
}
}
return result;
}
So up to now, we have askeu the taLle view to ienuei thiee sections with thiee iows in
the liist, live iows in the seconu, anu eight iows in the thiiu section. Vhat`s next? Ve
have to ietuin instances ol UITableViewCell to the taLle viewthe cells that we want
the taLle view to ienuei:
- (UITableViewCell *) tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *result = nil;
if ([tableView isEqual:self.myTableView]){
static NSString *TableViewCellIdentifier = @"MyCells";
result = [tableView
dequeueReusableCellWithIdentifier:TableViewCellIdentifier];
if (result == nil){
result = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:TableViewCellIdentifier];
}
4.3 Populating a Table View with Data | 285
www.it-ebooks.info
result.textLabel.text = [NSString stringWithFormat:@"Section %ld, Cell %ld",
(long)indexPath.section,
(long)indexPath.row];
}
return result;
}
Now il we iun oui app in iPhone Simulatoi, we will see the iesults ol oui woik (Fig-
uie +-2).
Iigurc 1-2. A p|ain tab|c vicw with thrcc scctions
Vhen a taLle view is ieloaueu oi ieliesheu, it gueiies its uata souice thiough the
UITableViewDataSource piotocol, asking loi vaiious Lits ol inloimation. Among the
impoitant methous pieviously mentioneu, the taLle view will liist ask loi the numLei
ol sections. Each section is iesponsiLle loi holuing iows oi cells. Altei the uata souice
specilies the numLei ol sections, the taLle view will ask loi the numLei ol iows that
have to Le loaueu into each section. The uata souice gets the zeio-Laseu inuex ol each
section anu, Laseu on this, can ueciue how many cells have to Le loaueu into each
section.
The taLle view, altei ueteimining the numLei ol cells in the sections, will continue to
ask the uata souice aLout the view that will iepiesent each cell in each section. You can
allocate instances ol the UITableViewCell class anu ietuin them to the taLle view. Theie
aie, ol couise, piopeities that can Le set loi each cell, incluuing the title, suLtitle, anu
coloi ol each cell, among othei piopeities.
286 | Chapter 4: Constructing and Using Table Views
www.it-ebooks.info
4.4 Receiving and Handling Table View Events
Problem
You woulu like to iesponu to vaiious events that a taLle view can geneiate.
Solution
Pioviue youi taLle view with a uelegate oLject.
Heie is an exceipt ol the .h lile ol a view contiollei with a taLle view:
#import <UIKit/UIKit.h>
@interface Receiving_and_Handling_Table_View_EventsViewController
: UIViewController <UITableViewDelegate, UITableViewDataSource>
@property (nonatomic, strong) UITableView *myTableView;
@end
The .n lile ol the same view contiollei implements a methou uelineu in the UITable
ViewDelegate piotocol:
- (void) tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if ([tableView isEqual:self.myTableView]){
NSLog(@"%@",
[NSString stringWithFormat:@"Cell %ld in Section %ld is selected",
(long)indexPath.row, (long)indexPath.section]);
}
}
- (void)viewDidLoad {
[super viewDidLoad];
self.myTableView = [[UITableView alloc]
initWithFrame:self.view.bounds
style:UITableViewStylePlain];
self.myTableView.autoresizingMask =
UIViewAutoresizingFlexibleHeight |
UIViewAutoresizingFlexibleWidth;
self.myTableView.dataSource = self;
self.myTableView.delegate = self;
[self.view addSubview:self.myTableView];
}
4.4 Receiving and Handling Table View Events | 287
www.it-ebooks.info
Discussion
Vhile a uata souice is iesponsiLle loi pioviuing uata to the taLle view, the taLle view
consults the uelegate whenevei an event occuis, oi il the taLle view neeus luithei in-
loimation Leloie it can complete a task. Foi instance, the taLle view invokes a uelegate`s
methou:
Vhen anu Leloie a cell is selecteu oi ueselecteu
Vhen the taLle view neeus to linu the height ol each cell
Vhen the taLle view neeus to constiuct the heauei anu lootei ol eveiy section
As you can see in the example coue in this iecipe`s Solution, the cuiient oLject is set as
the uelegate ol a taLle view. The uelegate implements the tableView:didSelect
RowAtIndexPath: selectoi in oiuei to get notilieu when the usei selects a cell oi a iow
on a taLle view. The uocumentation loi the UITableViewDelegate piotocol in the SDK
shows you all the methous that the uelegate can ueline anu the view can invoke.
See Also
UITaLleViewDelegate Piotocol Releience
4.5 Using Different Types of Accessories in a Table View Cell
Problem
You want to giaL useis` attention in a taLle view Ly uisplaying accessoiies, anu ollei
uilleient ways to inteiact with each cell in youi taLle view.
Solution
Use the accessoryType ol the UITableViewCell class, instances ol which you pioviue to
youi taLle view in its uata souice oLject:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell* result = nil;
if ([tableView isEqual:self.myTableView]){
static NSString *MyCellIdentifier = @"SimpleCell";
/* We will try to retrieve an existing cell
with the given identifier */
result = [tableView
dequeueReusableCellWithIdentifier:MyCellIdentifier];
if (result == nil){
/* If a cell with the given identifier does not
288 | Chapter 4: Constructing and Using Table Views
www.it-ebooks.info
exist, we will create the cell with the identifier
and hand it to the table view */
result = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyCellIdentifier];
}
result.textLabel.text =
[NSString stringWithFormat:@"Section %ld, Cell %ld",
(long)indexPath.section,
(long)indexPath.row];
result.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
}
return result;
}
- (NSInteger) tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section{
return 10;
}
- (void)viewDidLoad{
[super viewDidLoad];
self.myTableView = [[UITableView alloc] initWithFrame:self.view.bounds
style:UITableViewStylePlain];
self.myTableView.dataSource = self;
self.myTableView.delegate = self;
self.myTableView.autoresizingMask =
UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;
[self.view addSubview:self.myTableView];
}
Discussion
You can assign any ol the values uelineu in the UITableViewCellAccessoryType enu-
meiation to the accessoryType piopeity ol an instance ol the UITableViewCell class.
Two veiy uselul accessoiies aie the disc|osurc indicator anu the dctai| disc|osurc but-
ton. They Loth uisplay a chevion inuicating to useis that il they tap on the associateu
taLle view cell, a new view oi view contiollei will Le uisplayeu. In othei woius, the
useis will Le taken to a new scieen with luithei inloimation aLout theii cuiient selectoi.
The uilleience Letween these two accessoiies is that the uisclosuie inuicatoi piouuces
no event, wheieas the uetail uisclosuie Lutton liies an event to the uelegate when
4.5 Using Different Types of Accessories in a Table View Cell | 289
www.it-ebooks.info
piesseu. In othei woius, piessing the Lutton has a uilleient ellect liom piessing the cell
itsell. Thus, the uetail uisclosuie Lutton allows the usei to peiloim two sepaiate Lut
ielateu actions on the same iow.
Figuie +-3 shows these two uilleient accessoiies on a taLle view. The liist iow has a
uisclosuie inuicatoi anu the seconu iow has a uetail uisclosuie Lutton.
Iigurc 1-3. Two tab|c vicw cc||s with dijjcrcnt acccssorics
Il you tap any uetail uisclosuie Lutton assigneu to a taLle view cell, you will immeuiately
iealize that it tiuly is a sepaiate Lutton. Now the guestion is: how uoes the taLle view
know when the usei taps this Lutton?
TaLle views, as explaineu Leloie, liie events on theii uelegate oLject. The uetail uis-
closuie Lutton on a taLle view cell also liies an event that can Le captuieu Ly the uelegate
oLject ol a taLle view:
- (void) tableView:(UITableView *)tableView
accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath{
/* Do something when the accessory button is tapped */
NSLog(@"Accessory button is tapped for cell at index path = %@", indexPath);
UITableViewCell *ownerCell = [tableView cellForRowAtIndexPath:indexPath];
NSLog(@"Cell Title = %@", ownerCell.textLabel.text);
}
This coue linus the taLle view cell whose uetail uisclosuie Lutton has Leen tappeu anu
piints the contents ol the text laLel ol that cell into the console scieen. As a ieminuei,
you can uisplay the console scieen in Xcoue Ly selecting Run Console.
4.6 Creating Custom Table View Cell Accessories
Problem
The accessoiies pioviueu to you Ly the iOS SDK aie not sullicient, anu you woulu like
to cieate youi own accessoiies.
290 | Chapter 4: Constructing and Using Table Views
www.it-ebooks.info
Solution
Assign an instance ol the UIView class to the accessoryView piopeity ol any instance ol
the UITableViewCell class:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell* result = nil;
static NSString *MyCellIdentifier = @"SimpleCell";
/* We will try to retrieve an existing cell
with the given identifier */
result = [tableView dequeueReusableCellWithIdentifier:MyCellIdentifier];
if (result == nil){
result = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyCellIdentifier];
}
result.textLabel.text = [NSString stringWithFormat:@"Section %ld, Cell %ld",
(long)indexPath.section,
(long)indexPath.row];
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake(0.0f, 0.0f, 150.0f, 25.0f);
[button setTitle:@"Expand"
forState:UIControlStateNormal];
[button addTarget:self
action:@selector(performExpand:)
forControlEvents:UIControlEventTouchUpInside];
result.accessoryView = button;
return result;
}
As you can see, this coue uses the performExpand: methou as the selectoi loi each Lut-
ton. Heie is the uelinition ol this methou:
- (void) performExpand:(id)paramSender{
/* Take an action here */
}
This example coue snippet assigns a custom Lutton to the accessoiy view ol eveiy iow
in the taigeteu taLle. The iesult is shown in Figuie +-+.
4.6 Creating Custom Table View Cell Accessories | 291
www.it-ebooks.info
Iigurc 1-1. Tab|c vicw cc||s with custon acccssory vicws
Discussion
An oLject ol type UITableViewCell ietains a piopeity nameu accessoryView. This is the
view you can assign a value to il you aie not completely happy with the Luilt-in iOS
SDK taLle view cell accessoiies. Altei this piopeity is set, Cocoa Touch will ignoie the
value ol the accessoryType piopeity anu will use the view assigneu to the accessory
View piopeity as the accessoiy assigneu to the cell.
The coue listeu in this iecipe`s Solution cieates Luttons loi all the cells populateu into
the taLle view. Vhen a Lutton is piesseu in any cell, the performExpand: methou gets
calleu, anu il you aie like me, you have pioLaLly alieauy staiteu thinking aLout how
you can ueteimine which cell the senuei Lutton Lelongs to. So, now we have to some-
how link oui Luttons with the cells to which they Lelong.
One way to hanule this situation is to ietiieve the supeiview ol the Lutton that liies the
event. Since the accessoiy view ol the cells ol a taLle view auus the cells` accessoiy views
as theii suLviews, ietiieving the supeiview ol the Lutton will ietuin the taLle view cell
that owns the Lutton as its accessoiy view:
- (void) performExpand:(UIButton *)paramSender{
UITableViewCell *ownerCell = (UITableViewCell*)paramSender.superview;
if (ownerCell != nil){
/* Now we will retrieve the index path of the cell
which contains the section and the row of the cell */
NSIndexPath *ownerCellIndexPath =
292 | Chapter 4: Constructing and Using Table Views
www.it-ebooks.info
[self.myTableView indexPathForCell:ownerCell];
NSLog(@"Accessory in index path is tapped. Index path = %@",
ownerCellIndexPath);
/* Now we can use these two values to truly determine that
the accessory button of which cell was the sender of this event:
OwnerCellIndexPath.section
OwnerCellIndexPath.row
*/
if (ownerCellIndexPath.section == 0 &&
ownerCellIndexPath.row == 1){
/* This is the second row in the first section */
}
/* And so forth with the other checks ... */
}
}
4.7 Displaying Hierarchical Data in Table Views
Problem
You want to Le aLle to uisplay hieiaichical uata in a taLle view.
Solution
Use the inuentation lunctionality ol taLle view cells:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell* result = nil;
static NSString *MyCellIdentifier = @"SimpleCells";
result = [tableView dequeueReusableCellWithIdentifier:MyCellIdentifier];
if (result == nil){
result = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyCellIdentifier];
}
result.textLabel.text = [NSString stringWithFormat:@"Section %ld, Cell %ld",
(long)indexPath.section,
(long)indexPath.row];
result.indentationLevel = indexPath.row;
result.indentationWidth = 10.0f;
4.7 Displaying Hierarchical Data in Table Views | 293
www.it-ebooks.info
return result;
}
The inuentation level is simply multiplieu Ly the inuentation wiuth in oiuei to give a
maigin to the content view ol each cell. Figuie +-5 uepicts how these cells look when
uisplayeu insiue a taLle view.
Discussion
Although you might iaiely linu it uselul, you can apply inuentation to taLle view cells
in the iOS SDK. Each cell can have two piopeities ielateu to inuentation: indcntation
|cvc| anu indcntation width. The inuentation level is simply multiplieu Ly the inuenta-
tion wiuth, anu the iesultant value is the ollset Ly which the taLle view cell`s content
is shilteu to the iight oi lelt.
Foi instance, il the inuentation level ol a cell is set to 2 anu its inuentation wiuth is set
to 3, the iesultant value is 6. This means the content view ol the cell is shilteu to the
iight Ly six pixels when uisplayeu in a taLle view.
The inuentation level is uelineu as a signeu integei value, making it
possiLle loi you to assign negative values to it. This will oLviously shilt
the content view ol youi cells to the lelt.
The inuentation level assigneu to taLle view cells enaLles piogiammeis to piesent
hieiaichical uata, anu it is up to the piogiammei to ueteimine the inuentation level anu
the inuentation wiuth ol each cell.
4.8 Enabling Swipe Deletion of Table View Cells
Problem
You want youi application useis to Le aLle to uelete iows liom a taLle view easily.
Solution
Implement the tableView:editingStyleForRowAtIndexPath: selectoi in the uelegate anu
the tableView:commitEditingStyle:forRowAtIndexPath: selectoi in the uata souice ol
youi taLle view:
294 | Chapter 4: Constructing and Using Table Views
www.it-ebooks.info
Iigurc 1-5. Tab|c vicw cc||s with indcntation
4.8 Enabling Swipe Deletion of Table View Cells | 295
www.it-ebooks.info
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView
editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCellEditingStyle result = UITableViewCellEditingStyleNone;
if ([tableView isEqual:self.myTableView]){
result = UITableViewCellEditingStyleDelete;
}
return result;
}
- (void) setEditing:(BOOL)editing
animated:(BOOL)animated{
[super setEditing:editing
animated:animated];
[self.myTableView setEditing:editing
animated:animated];
}
- (void) tableView:(UITableView *)tableView
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath{
if (editingStyle == UITableViewCellEditingStyleDelete){
if (indexPath.row < [self.arrayOfRows count]){
/* First remove this object from the source */
[self.arrayOfRows removeObjectAtIndex:indexPath.row];
/* Then remove the associated cell from the Table View */
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationLeft];
}
}
}
The tableView:editingStyleForRowAtIndexPath: methou can enaLle ueletions. It is
calleu Ly the taLle view anu its ietuin value ueteimines what the taLle view allows the
usei to uo (inseition, ueletion, etc.). The tableView:commitEditingStyle:forRowAtIndex
Path: methou caiiies out the usei`s ieguesteu ueletion. The lattei methou is uelineu in
the uelegate, Lut its lunctionality is a Lit oveiloaueu: not only uo you use the methou
to uelete uata, Lut you also have to uelete iows liom the taLle heie.
296 | Chapter 4: Constructing and Using Table Views
www.it-ebooks.info
Discussion
The taLle view iesponus to the swipe Ly showing a Lutton on the iight siue ol the
taigeteu iow (Figuie +-6). As you can see, the taLle view is not in euiting moue, Lut the
Lutton allows the usei to uelete the iow.
This moue is enaLleu Ly implementing the tableView:editingStyleForRowAtIndex
Path: methou (ueclaieu in the UITableViewDelegate piotocol), whose ietuin value in-
uicates whethei the taLle shoulu allow inseitions, ueletions, Loth, oi neithei. By im-
plementing the tableView:commitEditingStyle:forRowAtIndexPath: methou in the uata
souice ol a taLle view, you can then get notilieu il a usei has peiloimeu an inseition oi
ueletion.
Iigurc 1-. Dc|ctc button appcaring on a tab|c vicw cc||
The seconu paiametei ol the deleteRowsAtIndexPaths:withRowAnimation: methou al-
lows you to specily an animation methou that will Le peiloimeu when iows aie ueleteu
liom a taLle view. Oui example specilies that we want iows to uisappeai Ly moving
liom iight to lelt when ueleteu.
4.9 Constructing Headers and Footers in Table Views
Problem
You want to cieate a heauei anu/oi a lootei loi a taLle view.
4.9 Constructing Headers and Footers in Table Views | 297
www.it-ebooks.info
Solution
Cieate a view (coulu Le a laLel, image view, etc., anything that uiiectly oi inuiiectly
suLclasses UIView), anu assign that view to the heauei anu/oi the lootei ol a section ol
a taLle view. You can also allocate specilic numLei ol points in height loi a heauei oi
a lootei, as we will soon see.
Discussion
A taLle view can have multiple heaueis anu looteis. Each section in a taLle view can
have its own heauei anu lootei, so il you have thiee sections in a taLle view, you can
have a maximum ol thiee heaueis anu maximum ol thiee looteis. You aie not oLligeu
to pioviue heaueis anu looteis loi any ol these sections. It is up to you to tell the taLle
view whethei you want a heauei anu/oi a lootei loi a section anu you pass these views
to the taLle view thiough its uelegate, shoulu you wish to pioviue heauei(s)/lootei(s)
loi section(s) ol youi taLle view. Heaueis anu looteis in a taLle view Lecome a pait ol
the taLle view, meaning that when the taLle view`s contents scioll, so uo the heauei(s)
anu lootei(s) insiue that taLle view. Let`s have a look at a sample heauei anu lootei in
a taLle view (Figuie +-7).
Iigurc 1-7. A jootcr jor thc top scction and thc Shortcuts hcadcr jor thc |ast scction oj a tab|c vicw
As you can see, the top section (with items such as Check Spelling anu EnaLle Caps
Lock) has a lootei that says DouLle tapping the space Lai will inseit a peiiou lolloweu
Ly a space. That is the lootei ol the top section ol that taLle view. The ieason why it
is a lootei iathei than a heauei is Lecause it is attacheu to the Lottom ol that section
iathei than the top. The last section in this taLle view also has a heauei that ieaus
Shoitcuts. The ieason why this is a heauei iathei than a lootei is Lecause it appeais
on the top ol the section iathei than the Lottom.
298 | Chapter 4: Constructing and Using Table Views
www.it-ebooks.info
Specilying the height ol a heauei anu lootei in a section insiue a taLle
view is uone thiough methous uelineu in the UITableViewDataSource.
Specilying the actual view that has to Le uisplayeu loi the heauei/lootei
ol a section in a taLle view is uone thiough methous uelineu in the
UITableViewDelegate piotocol.
Let`s go aheau anu cieate a simple app with one taLle view in it. Then let`s pioviue two
laLels, ol type UILabel, one as the heauei anu the othei as the lootei ol the only section
in oui taLle view, anu populate this one section with only thiee cells. In the heauei we
will place the text Section 1 Heauei, anu in the lootei laLel we will place the text
Section 1 Footei. Staiting with the heauei lile ol oui ioot view contiollei, we will
ueline a taLle view:
#import <UIKit/UIKit.h>
@interface Constructing_Headers_and_Footers_in_Table_ViewsViewController
: UIViewController <UITableViewDataSource, UITableViewDelegate>
@property (nonatomic, strong) UITableView *myTableView;
@end
Now we will cieate a gioupeu taLle view anu loau thiee cells into it:
- (UITableViewCell *) tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *result = nil;
static NSString *CellIdentifier = @"CellIdentifier";
result = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (result == nil){
result = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
result.textLabel.text = [[NSString alloc] initWithFormat:@"Cell %ld",
(long)indexPath.row];
return result;
}
- (NSInteger) tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section{
return 3;
}
- (void)viewDidLoad{
[super viewDidLoad];
4.9 Constructing Headers and Footers in Table Views | 299
www.it-ebooks.info
self.myTableView =
[[UITableView alloc] initWithFrame:self.view.bounds
style:UITableViewStyleGrouped];
self.myTableView.dataSource = self;
self.myTableView.delegate = self;
self.myTableView.autoresizingMask = UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;
[self.view addSubview:self.myTableView];
}
- (BOOL)shouldAutorotateToInterfaceOrientation
:(UIInterfaceOrientation)interfaceOrientation{
return YES;
}
Heie is the exciting pait. Ve can now use two impoitant methous (which aie uelineu
in UITableViewDelegate) to pioviue a laLel loi the heauei anu anothei laLel loi the lootei
ol the one section that we have loaueu into oui taLle view. These methous aie:
tableView:viewForHeaderInSection:
This methou expects a ietuin value ol type UIView. The view ietuineu liom this
methou will Le uisplayeu as the heauei ol the section specilieu Ly the viewForHea
derInSection paiametei.
tableView:viewForFooterInSection:
This methou expects a ietuin value ol type UIView. The view ietuineu liom this
methou will Le uisplayeu as the lootei ol the section specilieu Ly the viewForFoo
terInSection paiametei.
Oui task now is to implement these methous anu ietuin an instance ol UILabel. On the
heauei laLel we will entei the text Section 1 Heauei, anu on the lootei laLel the text
Section 1 Footei, as we hau planneu:
- (UIView *) tableView:(UITableView *)tableView
viewForHeaderInSection:(NSInteger)section{
UILabel *result = nil;
if ([tableView isEqual:self.myTableView] &&
section == 0){
result = [[UILabel alloc] initWithFrame:CGRectZero];
result.text = @"Section 1 Header";
result.backgroundColor = [UIColor clearColor];
[result sizeToFit];
}
return result;
}
- (UIView *) tableView:(UITableView *)tableView
300 | Chapter 4: Constructing and Using Table Views
www.it-ebooks.info
viewForFooterInSection:(NSInteger)section{
UILabel *result = nil;
if ([tableView isEqual:self.myTableView] &&
section == 0){
result = [[UILabel alloc] initWithFrame:CGRectZero];
result.text = @"Section 1 Footer";
result.backgroundColor = [UIColor clearColor];
[result sizeToFit];
}
return result;
}
Il you iun youi app on the iPhone Simulatoi now, you will ceitainly see something
stiange, as shown in Figuie +-S.
Iigurc 1-8. Thc hcadcr and jootcr |abc|s oj a tab|c vicw arc not a|igncd propcr|y
The ieason loi this misalignment ol the laLels is Lecause the taLle view uoesn`t ieally
know the height ol these views. To specily the height ol the heauei anu lootei views,
we neeu to use the lollowing two methous which aie uelineu in the UITableViewDele
gate piotocol:
tableView:heightForHeaderInSection:
The ietuin value ol this methou is ol type CGFloat, anu it specilies the height ol the
heauei loi a section in a taLle view. The section`s inuex is passeu thiough the
heightForHeaderInSection paiametei.
4.9 Constructing Headers and Footers in Table Views | 301
www.it-ebooks.info
tableView:heightForFooterInSection:
The ietuin value ol this methou is ol type CGFloat, anu it specilies the height ol the
lootei loi a section in a taLle view. The section`s inuex is passeu thiough the
heightForHeaderInSection paiametei.
- (CGFloat) tableView:(UITableView *)tableView
heightForHeaderInSection:(NSInteger)section{
CGFloat result = 0.0f;
if ([tableView isEqual:self.myTableView] &&
section == 0){
result = 30.0f;
}
return result;
}
- (CGFloat) tableView:(UITableView *)tableView
heightForFooterInSection:(NSInteger)section{
CGFloat result = 0.0f;
if ([tableView isEqual:self.myTableView] &&
section == 0){
result = 30.0f;
}
return result;
}
Running the app, you can see that the height ol the heauei anu the lootei laLels is lixeu.
Theie is still something wiong with the coue we`ve wiittenthe lelt maigin ol oui
heauei anu lootei laLels. Take a look loi youisell in Figuie +-9.
The ieason loi this is that the taLle view, Ly uelault, places heauei anu lootei views at
x point 0.0f. You might think that changing the liame ol youi heauei anu lootei laLels
will lix this issue, Lut unloitunately it uoesn`t. The solution to this pioLlem is cieating
a geneiic UIView anu placing youi heauei anu lootei laLels on that view. Retuin the
geneiic view as the heauei/lootei, Lut change the x position ol youi laLels within the
geneiic view. Ve now neeu to mouily oui implementation ol the tableView:view
ForHeaderInSection: anu the tableView:viewForFooterInSection: methous:
- (UIView *) tableView:(UITableView *)tableView
viewForHeaderInSection:(NSInteger)section{
UIView *result = nil;
if ([tableView isEqual:self.myTableView] &&
section == 0){
302 | Chapter 4: Constructing and Using Table Views
www.it-ebooks.info
UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
label.text = @"Section 1 Header";
label.backgroundColor = [UIColor clearColor];
[label sizeToFit];
/* Move the label 10 points to the right */
label.frame = CGRectMake(label.frame.origin.x + 10.0f,
5.0f, /* Go 5 points down in y axis */
label.frame.size.width,
label.frame.size.height);
/* Give the container view 10 points more in width than our label
because the label needs a 10 extra points left-margin */
CGRect resultFrame = CGRectMake(0.0f,
0.0f,
label.frame.size.width + 10.0f,
label.frame.size.height);
result = [[UIView alloc] initWithFrame:resultFrame];
[result addSubview:label];
}
return result;
}
- (UIView *) tableView:(UITableView *)tableView
viewForFooterInSection:(NSInteger)section{
UIView *result = nil;
if ([tableView isEqual:self.myTableView] &&
section == 0){
Iigurc 1-9. Thc |cjt nargin oj our hcadcr and jootcr |abc|s is not corrcct
4.9 Constructing Headers and Footers in Table Views | 303
www.it-ebooks.info
UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
label.text = @"Section 1 Footer";
label.backgroundColor = [UIColor clearColor];
[label sizeToFit];
/* Move the label 10 points to the right */
label.frame = CGRectMake(label.frame.origin.x + 10.0f,
5.0f, /* Go 5 points down in y axis */
label.frame.size.width,
label.frame.size.height);
/* Give the container view 10 points more in width than our label
because the label needs a 10 extra points left-margin */
CGRect resultFrame = CGRectMake(0.0f,
0.0f,
label.frame.size.width + 10.0f,
label.frame.size.height);
result = [[UIView alloc] initWithFrame:resultFrame];
[result addSubview:label];
}
return result;
}
Now il you iun youi app, you will get iesults similai to Figuie +-10.
Iigurc 1-10. Our hcadcr and jootcr |abc|s disp|aycd in a tab|c vicw
Vith the methous you just leaineu, you can even place images as the heauei/lootei ol
youi taLle views. Instances ol UIImageView have UIView as theii supeiclass, so you can
304 | Chapter 4: Constructing and Using Table Views
www.it-ebooks.info
easily place youi images in image views anu ietuin them as heaueis/looteis ol a taLle
view. Il all you want to place is text as the heauei/lootei ol taLle views, you can use
two hanuy methous uelineu in the UITableViewDataSource piotocol, which will save
you a lot ol hassle. Insteau ol cieating youi own laLels anu ietuining them as heaueis/
looteis ol youi taLle view, you can simply use these methous:
tableView:titleForHeaderInSection:
The ietuin value ol this methou is ol type NSString. This stiing will automatically
Le placeu insiue a laLel Ly the taLle view anu will Le uisplayeu as the heauei ol the
section, which is specilieu in the titleForHeaderInSection paiametei.
tableView:titleForFooterInSection:
The ietuin value ol this methou is ol type NSString. This stiing will automatically
Le placeu insiue a laLel Ly the taLle view anu will Le uisplayeu as the lootei ol the
section, which is specilieu in the titleForFooterInSection paiametei.
So to make oui app`s coue simplei, let`s get iiu ol oui implementation ol the table
View:viewForHeaderInSection: anu the tableView:viewForFooterInSection: methous,
anu ieplace them with the implementation ol the tableView:titleForHeaderInSec
tion: anu the tableView:titleForFooterInSection: methous:
- (NSString *) tableView:(UITableView *)tableView
titleForHeaderInSection:(NSInteger)section{
NSString *result = nil;
if ([tableView isEqual:self.myTableView] &&
section == 0){
result = @"Section 1 Header";
}
return result;
}
- (NSString *) tableView:(UITableView *)tableView
titleForFooterInSection:(NSInteger)section{
NSString *result = nil;
if ([tableView isEqual:self.myTableView] &&
section == 0){
result = @"Section 1 Footer";
}
return result;
}
Now iun youi app in the iPhone Simulatoi, anu you will see that the taLle view has
automatically cieateu a lelt-aligneu laLel loi the heauei anu a centei-aligneu laLel loi
the lootei ol the only section in oui taLle view. The alignment ol these laLels is the
4.9 Constructing Headers and Footers in Table Views | 305
www.it-ebooks.info
uelault alignment that eveiy taLle view cieates its heauei/lootei laLels with (see Fig-
uie +-11).
Iigurc 1-11. A tab|c vicw rcndcring tcxt in hcadcrs and jootcrs
4.10 Displaying Context Menus on Table View Cells
Problem
You want to give youi useis the aLility to use copy/paste options among othei opeia-
tions that they can choose, Ly holuing uown one ol theii lingeis on a taLle view cell in
youi app.
Solution
Implement the lollowing thiee methous ol the UITableViewDelegate piotocol in the
uelegate oLject ol youi taLle view:
tableView:shouldShowMenuForRowAtIndexPath:
The ietuin value ol this methou is ol type BOOL. Il you ietuin YES liom this methou,
iOS will uisplay the context menu loi the taLle view cell whose inuex gets passeu
to you thiough the shouldShowMenuForRowAtIndexPath paiametei.
tableView:canPerformAction:forRowAtIndexPath:withSender:
The ietuin value ol this methou is also ol type BOOL. Once you allow iOS to uisplay
a context menu loi a taLle view cell, iOS will call this methou multiple times anu
pass you the selectoi ol the action that you can choose to uisplay in the context
menu oi not. So, il iOS wants to ask you whethei you woulu like to show the Copy
menu to Le uisplayeu to the usei, this methou will get calleu in youi taLle view`s
306 | Chapter 4: Constructing and Using Table Views
www.it-ebooks.info
uelegate oLject anu the canPerformAction paiametei ol this methou will Le egual
to @selector(copy:). Ve will ieau moie inloimation aLout this in this iecipe`s
Discussion.
tableView:performAction:forRowAtIndexPath:withSender:
Once you allow a ceitain action to Le uisplayeu in the context menu ol a taLle view
cell, when the usei picks that action liom the menu, this methou will get calleu in
youi taLle view`s uelegate oLject. In heie, you must uo whatevei neeus to Le uone
to satisly the usei`s ieguest. Foi instance, il it is the Copy menu that the usei has
selecteu, you will neeu to use a pasteLoaiu to place the chosen taLle view cell`s
content into the pasteLoaiu.
Discussion
A taLle view can give a yes/no answei to iOS, allowing oi uisallowing the uisplay ol
availaLle system menu items loi a taLle view cell. iOS attempts to uisplay a context
menu on a taLle view cell when the usei has helu uown his lingei on the cell loi a ceitain
peiiou ol time, ioughly aLout one seconu. iOS then asks the taLle view whose cell was
the souice ol the tiiggei loi the menu. Il the taLle view gives a yes answei, iOS will then
tell the taLle view what options can Le uisplayeu in the context menu, anu the taLle
view will Le aLle to say yes oi no to any ol those items. Il theie aie live menu items
availaLle, loi instance, anu the taLle view says yes to only two ol them, then only those
two items will Le uisplayeu.
Altei the menu items aie uisplayeu to the usei, the usei can eithei tap on one ol the
items oi tap outsiue the context menu to cancel it. Once the usei taps on one ol the
menu items, iOS will senu a uelegate message to the taLle view inloiming it ol the menu
item that the usei has pickeu. Baseu on this inloimation, the taLle view can make a
uecision as to what to uo with the selecteu action.
I suggest that we liist see what actions aie actually availaLle loi a context menu on a
taLle view cell, so let`s cieate oui taLle view anu then uisplay a lew cells insiue it:
- (NSInteger) tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section{
return 3;
}
- (UITableViewCell *) tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *result = nil;
static NSString *CellIdentifier = @"CellIdentifier";
result = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (result == nil){
result = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
4.10 Displaying Context Menus on Table View Cells | 307
www.it-ebooks.info
}
result.textLabel.text = [[NSString alloc]
initWithFormat:@"Section %ld Cell %ld",
(long)indexPath.section,
(long)indexPath.row];
return result;
}
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.myTableView = [[UITableView alloc]
initWithFrame:self.view.bounds
style:UITableViewStylePlain];
self.myTableView.autoresizingMask = UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;
self.myTableView.dataSource = self;
self.myTableView.delegate = self;
[self.view addSubview:self.myTableView];
}
Now we will implement the thiee aloiementioneu methous uelineu in the UITableView
Delegate piotocol anu simply conveit the availaLle actions (ol type SEL) to stiings anu
piint them out to the console:
- (BOOL) tableView:(UITableView *)tableView
shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath{
/* Allow the context menu to be displayed on every cell */
return YES;
}
- (BOOL) tableView:(UITableView *)tableView
canPerformAction:(SEL)action
forRowAtIndexPath:(NSIndexPath *)indexPath
withSender:(id)sender{
NSLog(@"%@", NSStringFromSelector(action));
/* Allow every action for now */
return YES;
}
- (void) tableView:(UITableView *)tableView
performAction:(SEL)action
308 | Chapter 4: Constructing and Using Table Views
www.it-ebooks.info
forRowAtIndexPath:(NSIndexPath *)indexPath
withSender:(id)sender{
/* Empty for now */
}
Now iun youi app in the simulatoi oi on the uevice. You will then see thiee cells loaueu
into the taLle view. Holu uown youi lingei (il on a uevice) oi youi pointei (il using iOS
Simulatoi) on one ol the cells anu oLseive what gets piinteu out to the console winuow:
cut:
copy:
select:
selectAll:
paste:
delete:
_promptForReplace:
_showTextStyleOptions:
_define:
_accessibilitySpeak:
_accessibilityPauseSpeaking:
makeTextWritingDirectionRightToLeft:
makeTextWritingDirectionLeftToRight:
cut:
copy:
select:
selectAll:paste:
delete:
_promptForReplace:
_showTextStyleOptions:
_define:
_accessibilitySpeak:
_accessibilityPauseSpeaking:
makeTextWritingDirectionRightToLeft:
makeTextWritingDirectionLeftToRight:
These aie all the actions that iOS will allow you to show youi useis, shoulu you neeu
them. So loi instance, il you woulu like to allow youi useis to have the Copy option,
in the tableView:canPerformAction:forRowAtIndexPath:withSender: methou, simply
linu out which action iOS is asking youi peimission loi Leloie uisplaying it, anu eithei
ietuin YES oi NO:
- (BOOL) tableView:(UITableView *)tableView
canPerformAction:(SEL)action
forRowAtIndexPath:(NSIndexPath *)indexPath
withSender:(id)sender{
if (action == @selector(copy:)){
return YES;
}
return NO;
}
4.10 Displaying Context Menus on Table View Cells | 309
www.it-ebooks.info
The next step is to inteicept what menu item the usei actually selecteu liom the context
menu. Baseu on this inloimation, we can then take appiopiiate action. Foi instance, il
the usei selecteu the Copy item in the context menu (see Figuie +-12), then we can use
UIPasteBoard to copy that cell into the pasteLoaiu loi latei use:
Iigurc 1-12. Thc Copy action disp|aycd insidc a contcxt ncnu on a tab|c vicw cc||
- (void) tableView:(UITableView *)tableView
performAction:(SEL)action
forRowAtIndexPath:(NSIndexPath *)indexPath
withSender:(id)sender{
if (action == @selector(copy:)){
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
UIPasteboard *pasteBoard = [UIPasteboard generalPasteboard];
[pasteBoard setString:cell.textLabel.text];
}
}
4.11 Moving Cells and Sections in Table Views
Problem
You want to move anu shullle cells anu sections insiue a taLle view, with smooth anu
intuitive animations.
310 | Chapter 4: Constructing and Using Table Views
www.it-ebooks.info
Solution
Use the moveSection:toSection: methou ol the taLle view to move a section to a new
position. You can also use the moveRowAtIndexPath:toIndexPath: methou to move a
taLle view cell liom its cuiient place to a new place.
Discussion
Moving taLle view cells anu sections uilleis liom exchanging them. Let`s have a look
at an example that will make this easiei to unueistanu. Let`s say you have thiee sections
in youi taLle view: Sections A, B, anu C. Il you move Section A to Section C, the taLle
view will notice this move anu will then shilt Section B to the pievious position ol
Section A, anu will move Section B to the pievious position ol Section B. Howevei, il
Section B is moveu to Section C, the taLle view will not have to move Section A at all,
as it is sitting on top anu uoesn`t inteileie with the iepositioning ol Section B anu C.
In this case, Section B will Le moveu to Section C anu Section C to Section B. The same
logic will Le useu Ly the taLle view when moving cells.
To uemonstiate this, let`s cieate a taLle view anu pieloau it with thiee sections, each
ol which contains thiee cells ol its own. Let`s stait with the heauei lile ol oui view
contiollei:
#import <UIKit/UIKit.h>
@interface Moving_Cells_and_Sections_in_Table_ViewsViewController
: UIViewController <UITableViewDelegate, UITableViewDataSource>
@property (nonatomic, strong) UITableView *myTableView;
/* Each section is an array on its own, containing objects of type NSString */
@property (nonatomic, strong) NSMutableArray *arrayOfSections;
@end
Oui view contiollei will Lecome the uata souice ol the taLle view. The taLle view has
sections anu each section has iows. Ve will keep an aiiay ol aiiays; the liist aiiay is
oui aiiay ol sections, which will itsell contain othei aiiays that contain oui cells. The
arrayOfSections uelineu in the heauei lile ol oui view contiollei will Leai that iespon-
siLility. Let`s go aheau anu populate this aiiay in the implementation ol oui view con-
tiollei:
#import "Moving_Cells_and_Sections_in_Table_ViewsViewController.h"
@implementation Moving_Cells_and_Sections_in_Table_ViewsViewController
- (NSMutableArray *) newSectionWithIndex:(NSUInteger)paramIndex
withCellCount:(NSUInteger)paramCellCount{
NSMutableArray *result = [[NSMutableArray alloc] init];
NSUInteger counter = 0;
4.11 Moving Cells and Sections in Table Views | 311
www.it-ebooks.info
for (counter = 0;
counter < paramCellCount;
counter++){
[result addObject:[[NSString alloc] initWithFormat:@"Section %lu Cell %lu",
(unsigned long)paramIndex,
(unsigned long)counter+1]];
}
return result;
}
- (id) initWithNibName:(NSString *)nibNameOrNil
bundle:(NSBundle *)nibBundleOrNil{
self = [super initWithNibName:nibNameOrNil
bundle:nibBundleOrNil];
if (self != nil){
arrayOfSections = [[NSMutableArray alloc] init];
NSMutableArray *section1 = [self newSectionWithIndex:1
withCellCount:3];
NSMutableArray *section2 = [self newSectionWithIndex:2
withCellCount:3];
NSMutableArray *section3 = [self newSectionWithIndex:3
withCellCount:3];
[arrayOfSections addObject:section1];
[arrayOfSections addObject:section2];
[arrayOfSections addObject:section3];
}
return self;
}
Ve shall then instantiate oui taLle view anu implement the necessaiy methous in the
UITableViewDataSource piotocol to populate oui taLle view with uata:
- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView{
NSInteger result = 0;
if ([tableView isEqual:self.myTableView]){
result = (NSInteger)[self.arrayOfSections count];
}
return result;
}
- (NSInteger) tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section{
312 | Chapter 4: Constructing and Using Table Views
www.it-ebooks.info
NSInteger result = 0;
if ([tableView isEqual:self.myTableView]){
if ([self.arrayOfSections count] > section){
NSMutableArray *sectionArray = [self.arrayOfSections
objectAtIndex:section];
result = (NSInteger)[sectionArray count];
}
}
return result;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *result = nil;
if ([tableView isEqual:self.myTableView]){
static NSString *CellIdentifier = @"CellIdentifier";
result = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (result == nil){
result = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
NSMutableArray *sectionArray = [self.arrayOfSections
objectAtIndex:indexPath.section];
result.textLabel.text = [sectionArray objectAtIndex:indexPath.row];
}
return result;
}
- (void)viewDidLoad{
[super viewDidLoad];
self.myTableView =
[[UITableView alloc] initWithFrame:self.view.bounds
style:UITableViewStyleGrouped];
self.myTableView.autoresizingMask = UIViewAutoresizingFlexibleWidth |
4.11 Moving Cells and Sections in Table Views | 313
www.it-ebooks.info
UIViewAutoresizingFlexibleHeight;
self.myTableView.delegate = self;

self.myTableView.dataSource = self;
[self.view addSubview:self.myTableView];
}
Show time! Shall we liist have a look at how sections can Le moveu to a new position?
Let`s wiite a methou that will move Section 1 to 3:
- (void) moveSection1ToSection3{
NSMutableArray *section1 = [self.arrayOfSections objectAtIndex:0];
[self.arrayOfSections removeObject:section1];
[self.arrayOfSections addObject:section1];
[self.myTableView moveSection:0
toSection:2];
}
I will leave it up to you to ueciue when you woulu like to invoke this methou, as we
uon`t have a Lutton on oui UI at the moment. You can simply cieate a navigation
contiollei, place a navigation Lutton on it, anu then invoke this methou.
Once you iun the app noimally, you will see the sections lineu up liom 1 to 3, as in
Figuie +-13.
Iigurc 1-13. A tab|c vicw with thrcc scctions, cach containing thrcc cc||s
314 | Chapter 4: Constructing and Using Table Views
www.it-ebooks.info
Altei you invoke the moveSection1ToSection3 methou, you will see that Section 1 gets
moveu to Section 3, Section 3 moves to Section 2`s pievious position, anu linally Section
2 moves to Section 1`s pievious position (Figuie +-1+).
Iigurc 1-11. Scction 1 is novcd to Scction 3, and othcr scctions arc subscqucnt|y novcd as wc||
Moving cells is veiy similai to moving sections. To move cells, all we have to uo is to
use the moveRowAtIndexPath:toIndexPath: methou. RememLei that you can move a cell
liom one section to the same section, oi to a new section. Let`s make it easy anu move
Cell 1 in Section 1 to Cell 2 in the same section anu see what happens:
- (void) moveCell1InSection1ToCell2InSection1{
NSMutableArray *section1 = [self.arrayOfSections objectAtIndex:0];
NSString *cell1InSection1 = [section1 objectAtIndex:0];
[section1 removeObject:cell1InSection1];
[section1 insertObject:cell1InSection1
atIndex:1];
NSIndexPath *sourceIndexPath = [NSIndexPath indexPathForRow:0
inSection:0];
NSIndexPath *destinationIndexPath = [NSIndexPath indexPathForRow:1
inSection:0];
[self.myTableView moveRowAtIndexPath:sourceIndexPath
toIndexPath:destinationIndexPath];
}
So what is going on in this coue? Vell, we neeu to make suie oui uata souice holus the
coiiect uata that neeus to Le uisplayeu in oui taLle view altei we have moveu the cells
aiounu, so we iemove Cell 1 in Section 1 liist. That moves Cell 2 to Cell 1, anu Cell 3
4.11 Moving Cells and Sections in Table Views | 315
www.it-ebooks.info
to Cell 2, with a total ol 2 cells in the aiiay. Then we will inseit Cell 1 into Inuex 1
(seconu oLject) ol the aiiay. That will make oui aiiay contain Cell 2, Cell 1, anu then
Cell 3. Altei that is uone, we have actually moveu the cells in oui taLle view.
Let`s make this a Lit moie uillicult. How aLout moving Cell 2 in Section 1 to Cell 1 in
Section 2?
- (void) moveCell2InSection1ToCell1InSection2{
NSMutableArray *section1 = [self.arrayOfSections objectAtIndex:0];
NSMutableArray *section2 = [self.arrayOfSections objectAtIndex:1];
NSString *cell2InSection1 = [section1 objectAtIndex:1];
[section1 removeObject:cell2InSection1];
[section2 insertObject:cell2InSection1
atIndex:0];
NSIndexPath *sourceIndexPath = [NSIndexPath indexPathForRow:1
inSection:0];
NSIndexPath *destinationIndexPath = [NSIndexPath indexPathForRow:0
inSection:1];
[self.myTableView moveRowAtIndexPath:sourceIndexPath
toIndexPath:destinationIndexPath];
}
The iesults ol this tiansition aie shown in Figuie +-15.
Iigurc 1-15. Cc|| 2 in Scction 1 is novcd to Cc|| 1 in Scction 2
316 | Chapter 4: Constructing and Using Table Views
www.it-ebooks.info
4.12 Deleting Cells and Sections from Table Views
Problem
You want to uelete sections anu/oi cells liom taLle views using animations.
Solution
In oiuei to uelete sections liom a taLle view, lollow these steps:
1. Fiist uelete the section(s) in youi uata souice, whethei you aie using a uata mouel
like Coie Data oi a uictionaiy/aiiay.
2. Invoke the deleteSections:withRowAnimation: instance methou ol UITableView on
youi taLle view. The liist paiametei that you neeu to pass to this methou is ol type
NSIndexSet anu this oLject can Le instantiateu using the indexSetWithIndex: class
methou ol NSIndexSet class, wheie the given inuex is an unsigneu integei. Using
this appioach, you will Le aLle to uelete only one section at a time. Il you intenu
to uelete moie than one section at a time, use the indexSetWithIndexesInRange:
class methou ol NSIndexSet to cieate the inuex set using a iange anu pass that inuex
set to the aloiementioneu instance methou ol UITableView.
Il you want to uelete cells liom youi taLle view, lollow these steps:
1. Fiist, uelete the cell(s) liom youi uata souice. Again, it uoesn`t mattei il you aie
using Coie Data, a simple uictionaiy, aiiay, oi anything else. The impoitant thing
is to uelete the oLjects that iepiesent the taLle view cells liom youi uata souice.
2. Now, in oiuei to uelete the cells that coiiesponu to youi uata oLjects, invoke the
deleteRowsAtIndexPaths:withRowAnimation: instance methou ol youi taLle view.
The liist paiametei that you have to pass to this methou is an aiiay ol type NSAr
ray that must contain oLjects ol type NSIndexPath, with each inuex path iepiesent-
ing one cell in the taLle view. Each inuex path has a section anu a iow, anu can Le
constiucteu using the indexPathForRow:inSection: class methou ol NSIndexPath
class.
Discussion
In youi UI coue, sometimes you might neeu to uelete cells anu/oi sections. Foi instance,
you might have a switch (ol type UISwitch; see Recipe 2.2), anu when the switch is
tuineu on Ly the usei, you might want to inseit a lew iows into youi taLle view. Altei
the switch is tuineu oll Ly the usei, you will then want to uelete those iows. It`s not
always taLle view cells (iows) that you have to uelete. Sometimes you might neeu to
uelete a whole section oi a lew sections simultaneously liom youi taLle view. The key
loi ueleting cells anu sections liom taLle views is to liist uelete the uata coiiesponuing
to those cells/sections liom youi uata souice, anu then call the appiopiiate ueletion
methou on the taLle view. Altei the ueletion methou linishes, the taLle view will ielei
4.12 Deleting Cells and Sections from Table Views | 317
www.it-ebooks.info
Lack to its uata souice oLject. Il the numLei ol cells/sections in the uata souice uoesn`t
match the numLei ol cells/sections in the taLle view altei the ueletion is complete, youi
app will ciash. But uon`t woiiyil you evei uo make this mistake, the ueLug text that
gets piinteu to the console is uesciiptive enough to point you in the iight uiiection.
Let`s have a look at how we can uelete sections liom a taLle view. Foi this iecipe, we
will uisplay a taLle view on a view contiollei that is uisplayeu insiue a navigation con-
tiollei. Insiue the taLle view, we will uisplay two sections, one loi ouu numLeis anu
anothei loi even numLeis. Ve will only uisplay 1, 3, 5, anu 7 loi ouu numLeis anu 0,
2, +, anu 6 loi even numLeis. Foi the liist exeicise, we aie going to place a navigation
Lai Lutton on oui navigation Lai anu make that Lutton iesponsiLle loi ueleting the
section with ouu numLeis in it. Figuie +-16 shows what we want the iesults to look like.
Iigurc 1-1. Thc uscr intcrjacc to disp|ay two scctions in a tab|c vicw and a button that wi|| dc|ctc
thc Odd Nunbcrs scction
Fiist things liist. Let`s ueline oui view contiollei:
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController <UITableViewDelegate,
UITableViewDataSource>
@property (nonatomic, strong) UITableView *tableViewNumbers;
@property (nonatomic, strong) NSMutableDictionary *dictionaryOfNumbers;
@property (nonatomic, strong) UIBarButtonItem *barButtonAction;
@end
The tableViewNumbers piopeity is oui taLle view. The barButtonAction piopeity is the
Lai Lutton that we`ll uisplay on the navigation Lai. Last Lut not least, the dictionary
318 | Chapter 4: Constructing and Using Table Views
www.it-ebooks.info
OfNumbers piopeity is oui uata souice loi the taLle view. In this uictionaiy, we will place
two values ol type NSMutableArray that contain oui numLeis ol type NSNumber. They aie
mutaLle aiiays, so that, latei in this chaptei, we will Le aLle to uelete them inuiviuually
liom the aiiays in the uictionaiy. Ve will keep the keys loi these aiiays in oui uictionaiy
as static values in the implementation lile ol oui view contiollei, so that we can latei
simply extiact them liom the uictionaiy using the static keys (il the keys weie not static,
linuing oui aiiays in the uictionaiy woulu have to Le uone with stiing compaiison,
which is slightly moie time-consuming than simply associating the oLject with a static
key that uoesn`t change uuiing the liletime ol oui view contiollei). Now let`s ueline
the static stiing keys loi oui aiiays insiue the uata souice uictionaiy:
#import "ViewController.h"
@implementation ViewController
static NSString *SectionOddNumbers = @"Odd Numbers";
static NSString *SectionEvenNumbers = @"Even Numbers";
...
Ve now neeu to populate oui uata souice uictionaiy with values Leloie we cieate oui
taLle view. Heie is the simple methou that will take caie ol populating the uictionaiy
loi us:
#pragma mark - Populating the Data Source Dictionary
- (void) constructDictionaryOfNumbers{
self.dictionaryOfNumbers = [[NSMutableDictionary alloc] init];
NSMutableArray *arrayOfEvenNumbers = [[NSMutableArray alloc] initWithObjects:
[NSNumber numberWithUnsignedInteger:0],
[NSNumber numberWithUnsignedInteger:2],
[NSNumber numberWithUnsignedInteger:4],
[NSNumber numberWithUnsignedInteger:6],
nil];
NSMutableArray *arrayOfOddNumbers = [[NSMutableArray alloc] initWithObjects:
[NSNumber numberWithUnsignedInteger:1],
[NSNumber numberWithUnsignedInteger:3],
[NSNumber numberWithUnsignedInteger:5],
[NSNumber numberWithUnsignedInteger:7],
nil];
[self.dictionaryOfNumbers setObject:arrayOfEvenNumbers
forKey:SectionEvenNumbers];
[self.dictionaryOfNumbers setObject:arrayOfOddNumbers
forKey:SectionOddNumbers];
}
So lai so goou? As you can see, we have two aiiays, each ol which contains some
numLeis (one ouu anu the othei even numLeis) anu we associate them with the
4.12 Deleting Cells and Sections from Table Views | 319
www.it-ebooks.info
SectionEvenNumbers anu SectionOddNumbers keys that we ueclaieu Leloie in the imple-
mentation lile ol oui view contiollei. Now let`s go aheau anu instantiate oui taLle view:
- (void)viewDidLoad
{
[super viewDidLoad];
[self constructDictionaryOfNumbers];
self.barButtonAction =
[[UIBarButtonItem alloc] initWithTitle:@"Delete Odd Numbers"
style:UIBarButtonItemStylePlain
target:self
action:@selector(deleteOddNumbersSection:)];
[self.navigationItem setRightBarButtonItem:self.barButtonAction animated:NO];
self.tableViewNumbers = [[UITableView alloc]
initWithFrame:self.view.frame
style:UITableViewStyleGrouped];
self.tableViewNumbers.autoresizingMask = UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;
self.tableViewNumbers.delegate = self;
self.tableViewNumbers.dataSource = self;
[self.view addSubview:self.tableViewNumbers];
}
The next thing we neeu to uo is to populate oui taLle view with uata insiue oui uata
souice uictionaiy:
#pragma mark - Table View Data Source
- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView{
NSInteger result = 0;
result = [[self.dictionaryOfNumbers allKeys] count];
return result;
}
- (NSInteger) tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section{
NSInteger result = 0;
NSString *sectionNameInDictionary = [[self.dictionaryOfNumbers allKeys]
objectAtIndex:section];
NSArray *sectionArray = [self.dictionaryOfNumbers objectForKey:
sectionNameInDictionary];
result = [sectionArray count];
return result;
}
- (UITableViewCell *) tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *result = nil;
320 | Chapter 4: Constructing and Using Table Views
www.it-ebooks.info
static NSString *CellIdentifier = @"NumbersCellIdentifier";
result = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (result == nil){
result = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
NSString *sectionNameInDictionary = [[self.dictionaryOfNumbers allKeys]
objectAtIndex:indexPath.section];
NSArray *sectionArray = [self.dictionaryOfNumbers objectForKey:
sectionNameInDictionary];
NSNumber *number = [sectionArray objectAtIndex:indexPath.row];
result.textLabel.text = [NSString stringWithFormat:@"%lu",
(unsigned long)[number unsignedIntegerValue]];
return result;
}
- (NSString *) tableView:(UITableView *)tableView
titleForHeaderInSection:(NSInteger)section{
NSString *result = nil;
result = [[self.dictionaryOfNumbers allKeys] objectAtIndex:section];
return result;
}
Oui navigation Lutton is linkeu to the deleteOddNumbersSection: selectoi. This is a
methou we aie going to coue now. The puipose ol this methou, as its name implies, is
to linu the section that coiiesponus to all ouu numLeis in oui uata souice anu the taLle
view, anu iemove that section liom Loth ol these. Heie is how we will uo it:
- (void) deleteOddNumbersSection:(id)paramSender{
/* First remove the section from our data source */
NSString *key = SectionOddNumbers;
NSInteger indexForKey = [[self.dictionaryOfNumbers allKeys]
indexOfObject:key];
if (indexForKey == NSNotFound){
NSLog(@"Could not find the section in the data source.");
return;
}
[self.dictionaryOfNumbers removeObjectForKey:key];
/* Then delete the section from the table view */
NSIndexSet *sectionToDelete = [NSIndexSet indexSetWithIndex:indexForKey];
[self.tableViewNumbers deleteSections:sectionToDelete
withRowAnimation:UITableViewRowAnimationAutomatic];
/* Finally, remove the button from the navigation bar
4.12 Deleting Cells and Sections from Table Views | 321
www.it-ebooks.info
as it is not useful any longer */
[self.navigationItem setRightBarButtonItem:nil animated:YES];
}
Simple enough. Now, when the usei piesses the navigation Lai Lutton, the Ouu Num-
Leis section will uisappeai liom the taLle view. You can note that theie is an animation
that gets committeu on the taLle view while the section is Leing ueleteu. This is Lecause
ol the UITableViewRowAnimationAutomatic animation type that we aie passing to the
withRowAnimation: paiametei ol the deleteSections:withRowAnimation: methou ol oui
taLle view. Now iun the app in iOS Simulatoi anu select DeLug Toggle Slow Ani-
mations. Then attempt to piess the navigation Lai Lutton anu see what happens. You
can see the ueletion animation in slow motion. It`s neat, isn`t it? Altei the ueletion is
completeu, oui app will look similai to Figuie +-17.
Iigurc 1-17. Thc scction containing odd nunbcrs is rcnovcd jron thc tab|c vicw
Ve now know how to uelete sections liom taLle views. Let`s move to ueleting cells.
Ve aie going to change the lunctionality ol oui navigation Lai Lutton so that when it
is piesseu, it will uelete all cells in all sections ol oui taLle view with a numeiical value
gieatei than 2. That incluues all ouu anu even numLeis gieatei than 2. So let`s change
oui navigation Lai Lutton item in the viewDidLoad methou ol oui view contiollei:
- (void)viewDidLoad
{
[super viewDidLoad];
[self constructDictionaryOfNumbers];
self.barButtonAction =
[[UIBarButtonItem alloc] initWithTitle:@"Delete Numbers > 2"
322 | Chapter 4: Constructing and Using Table Views
www.it-ebooks.info
style:UIBarButtonItemStylePlain
target:self
action:@selector(deleteNumbersGreaterThan2:)];
[self.navigationItem setRightBarButtonItem:self.barButtonAction animated:NO];
self.tableViewNumbers = [[UITableView alloc]
initWithFrame:self.view.frame
style:UITableViewStyleGrouped];
self.tableViewNumbers.autoresizingMask = UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;
self.tableViewNumbers.delegate = self;
self.tableViewNumbers.dataSource = self;
[self.view addSubview:self.tableViewNumbers];
}
Figuie +-1S shows the iesults ol oui app iunning in iPhone Simulatoi.
Iigurc 1-18. A button that wi|| dc|ctc a|| cc||s containing a nunbcr grcatcr than 2
The navigation Lai Lutton is now connecteu to the deleteNumbersGreaterThan2: selec-
toi. This is a methou that we have to implement in oui view contiollei, Lut Leloie
jumping into couing it stiaightaway, let`s liist ueline what this methou shoulu uo:
1. Finu Loth aiiays ol ouu anu even numLeis in oui uata souice anu giaL the inuex
paths (ol type NSIndexPath) ol those numLeis that aie gieatei than 2. Ve will use
these inuex paths to latei uelete the coiiesponuing cells liom the taLle view.
2. Delete all the numLeis gieatei than 2 liom oui uata souice, in Loth the even anu
ouu numLei uictionaiies.
3. Delete the ielevant cells liom the taLle view. Ve collecteu the inuex paths ol these
cells in the liist step.
4.12 Deleting Cells and Sections from Table Views | 323
www.it-ebooks.info
+. Remove the navigation Lai Lutton, since it won`t Le ol any use altei the ielevant
cells have Leen ueleteu liom the uata souice anu the taLle view. Alteinatively, il
you want, you coulu just uisaLle this LuttonLut I think iemoving that Lutton
pioviues a Lettei usei expeiience, since a uisaLleu Lutton is ieally ol no use to the
usei.
- (void) deleteNumbersGreaterThan2:(id)paramSender{
NSMutableArray *arrayOfIndexPathsToDelete = [[NSMutableArray alloc] init];
NSMutableArray *arrayOfNumberObjectsToDelete = [[NSMutableArray alloc] init];
/* Step 1: gather the objects we have to delete from our data source
and their index paths */
__block NSUInteger keyIndex = 0;
[self.dictionaryOfNumbers enumerateKeysAndObjectsUsingBlock:
^(NSString *key, NSMutableArray *object, BOOL *stop) {
[object enumerateObjectsUsingBlock:
^(NSNumber *number, NSUInteger numberIndex, BOOL *stop) {
if ([number unsignedIntegerValue] > 2){
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:numberIndex
inSection:keyIndex];
[arrayOfIndexPathsToDelete addObject:indexPath];
[arrayOfNumberObjectsToDelete addObject:number];
}
}];
keyIndex++;
}];
/* Step 2: delete the objects from the data source */
if ([arrayOfNumberObjectsToDelete count] > 0){
NSMutableArray *arrayOfOddNumbers = [self.dictionaryOfNumbers
objectForKey:SectionOddNumbers];
NSMutableArray *arrayOfEvenNumbers = [self.dictionaryOfNumbers
objectForKey:SectionEvenNumbers];
[arrayOfNumberObjectsToDelete enumerateObjectsUsingBlock:
^(NSNumber *numberToDelete, NSUInteger idx, BOOL *stop) {
if ([arrayOfOddNumbers indexOfObject:numberToDelete] != NSNotFound){
[arrayOfOddNumbers removeObject:numberToDelete];
}
if ([arrayOfEvenNumbers indexOfObject:numberToDelete] != NSNotFound){
[arrayOfEvenNumbers removeObject:numberToDelete];
}
[arrayOfEvenNumbers removeObject:numberToDelete];
}];
} /* Step 3: delete the cells that correspond to the objects */
NSArray *arrayOfPaths = [[NSArray alloc]
initWithArray:arrayOfIndexPathsToDelete];
[self.tableViewNumbers
deleteRowsAtIndexPaths:arrayOfPaths
withRowAnimation:UITableViewRowAnimationAutomatic];
324 | Chapter 4: Constructing and Using Table Views
www.it-ebooks.info
[self.navigationItem setRightBarButtonItem:nil animated:YES];
}
Altei the usei piesses the Lutton on the navigation Lai, all cells containing a numLei
gieatei than 2 will Le ueleteu liom oui uata souice, anu the taLle view anu oui app will
look like Figuie +-19.
Iigurc 1-19. Wc havc dc|ctcd a|| cc||s with a va|uc grcatcr than 2
See Also
Recipe 2.2
4.13 Utilizing the UITableViewController for Easy Creation of
Table Views
Problem
You want to Le aLle to cieate taLle views guickly.
Solution
Use the UITableViewController view contiollei, which Ly uelault comes with a taLle
view contiollei.
4.13 Utilizing the UITableViewController for Easy Creation of Table Views | 325
www.it-ebooks.info
Discussion
The iOS SDK contains a ieally hanuy class calleu UITableViewController that comes
pieuelineu with a taLle view instance insiue it. In oiuei to take auvantage ol this class,
all you have to ieally uo is cieate a new class that suLclasses the aloiementioneu class.
Heie, I will walk you thiough the steps necessaiy to cieate a new Xcoue pioject that
utilizes the taLle view contiollei:
1. In Xcoue, liom the menu Lai, choose File New Pioject...
2. On the lelthanu siue ol the scieen, make suie the iOS categoiy is selecteu. Then
choose the Application suLcategoiy. On the iighthanu siue, choose the Empty
Application template anu then piess the Next Lutton, as shown in Figuie +-20.
Iigurc 1-20. Crcating a ncw cnpty app|ication that wi|| |atcr contain our tab|c vicw contro||cr
3. In the next scieen, simply choose a name loi youi pioject anu make suie that you
aie using Automatic Releience Counting. Also make suie eveiything except loi the
Oiganization Name anu the Company Iuentiliei in youi uialog is the same as the
one that I am uemonstiating to you in Figuie +-21. Once you aie uone, piess
the Next Lutton.
326 | Chapter 4: Constructing and Using Table Views
www.it-ebooks.info
Iigurc 1-21. Conjiguring our ncw cnpty app|ication in Xcodc
+. In the next scieen, you aie given the oppoitunity to save youi application to uisk.
Simply save the application in a place that makes sense to you anu piess the Cieate
Lutton.
5. In Xcoue, choose the File New File... menu.
6. In the uialog, make suie iOS is the main categoiy on the lelthanu siue anu that
Cocoa Touch is the suLcategoiy that is selecteu. Then on the iighthanu siue ol the
uialog, choose the OLjective-C class as shown in Figuie +-22.
7. In the next scieen, you get to choose the supeiclass ol youi new class. This step is
veiy impoitant. Make suie that you set youi supeiclass to UITableView
Controller. Also make suie the iest ol youi settings aie the same as those that I am
uemonstiating in Figuie +-23. Altei you aie uone, piess the Next Lutton.
S. In the next scieen, you get the chance to save youi taLle view contiollei in youi
pioject. Go on, save it as the ViewContiollei class anu piess the Cieate Lutton.
9. In the implementation lile ol youi app uelegate, iememLei to impoit this view
contiollei`s heauei lile anu then cieate an instance ol this class anu set it as the ioot
view contiollei ol youi application, as shown heie:
4.13 Utilizing the UITableViewController for Easy Creation of Table Views | 327
www.it-ebooks.info
#import "AppDelegate.h"
#import "ViewController.h"
@implementation AppDelegate
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

self.window = [[UIWindow alloc]
initWithFrame:[[UIScreen mainScreen] bounds]];

self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];

self.window.rootViewController =
[[ViewController alloc] initWithStyle:UITableViewStylePlain];

return YES;
}
Iigurc 1-22. Crcating a ncw c|ass jor our tab|c vicw contro||cr
328 | Chapter 4: Constructing and Using Table Views
www.it-ebooks.info
Iigurc 1-23. Sctting thc supcrc|ass oj our ncw objcct that wi|| bcconc thc tab|c vicw contro||cr
Now il you tiy to compile youi pioject, you will see that the compilei will give you the
lollowing wainings:
ViewController.m:47:2: Potentially incomplete method implementation.
ViewController.m:54:2: Incomplete method implementation.
This simply tells you that theie aie wainings that you have to take caie ol in the im-
plementation lile ol youi view contiollei. Il you open this lile, you will see that Apple
has inseiteu #warning macios in the taLle view contiollei class template, which aie
causing these wainings to Le uisplayeu on youi scieen. One waining is placeu insiue
the numberOfSectionsInTableView: methou anu the othei one is insiue the table
View:numberOfRowsInSection: methou. The ieason we aie seeing these wainings is that
we have not coueu the logic loi these methous. The minimum inloimation that the
taLle view contiollei must have is the numLei ol sections to uisplay, the numLei ol
iows to uisplay, anu the cell oLject to Le uisplayeu loi each iow. The ieason you aie
not seeing any wainings loi the lack ol cell oLject implementation is that Apple Ly
uelault pioviues a uummy implementation ol this methou that cieates empty cells loi
you.
4.13 Utilizing the UITableViewController for Easy Creation of Table Views | 329
www.it-ebooks.info
The taLle view contiollei Ly uelault is the uata souice anu the uelegate
ol the taLle view. You uo not have to specily a uelegate oi a uata souice
sepaiately to the taLle view.
Now let`s go into the implementation ol oui taLle view contiollei anu make suie that
we have an aiiay ol stiings (just as an example) that we can leeu into oui taLle view:
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong) NSArray *items;
@end
@implementation ViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
self.items = @[
@"Anthony Robbins",
@"Steven Paul Jobs",
@"Paul Gilbert",
@"Yngwie Malmsteen"
];
}
return self;
}
- (void) viewDidLoad{
[super viewDidLoad];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section{
return self.items.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath{

static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
330 | Chapter 4: Constructing and Using Table Views
www.it-ebooks.info
}

cell.textLabel.text = self.items[indexPath.row];

return cell;
}
@end
Now il we iun oui app, we will see something similai to what is shown in Figuie +-2+.
Iigurc 1-21. Our strings arc propcr|y disp|aycd in thc tab|c vicw
That`s pietty much all theie is to know aLout taLle view contiolleis. RememLei, as
mentioneu Leloie, that youi taLle view contiollei is the uelegate and the uata souice
ol youi taLle view now. So you can implement the methous in the UITableViewData
Source piotocol as well as the UITableViewDelegate piotocol`s methous iight in the
implementation ol youi taLle view contiollei.
See Also
Recipe +.1; Recipe +.2; Recipe +.3
4.13 Utilizing the UITableViewController for Easy Creation of Table Views | 331
www.it-ebooks.info
4.14 Displaying a Refresh Control for Table Views
Problem
You want to uisplay a nice ieliesh UI contiol on top ol youi taLle views that allows
youi useis to intuitively pull uown the taLle view in oiuei to upuate its contents. Ex-
amples ol a ieliesh contiol in two ol its uilleient states aie shown in Figuie +-25.
Iigurc 1-25. Two dijjcrcnt statcs oj thc rcjrcsh contro|
Solution
Simply cieate a taLle view contiollei (as uiscusseu in Recipe +.13) anu set its refresh
Control piopeity to a new instance ol UIRefreshControl class, as shown heie:
- (id)initWithStyle:(UITableViewStyle)style{
self = [super initWithStyle:style];
if (self) {
/* Create the refresh control */
self.refreshControl = [[UIRefreshControl alloc] init];
self.refreshControl = self.refreshControl;
[self.refreshControl addTarget:self
action:@selector(handleRefresh:)
forControlEvents:UIControlEventValueChanged];
}
return self;
}
Discussion
Reliesh contiols aie a new UI component auueu to the iOS 6 SDK. They aie simple
visual inuicatois that appeai on top ol taLle views anu tell the usei that something is
332 | Chapter 4: Constructing and Using Table Views
www.it-ebooks.info
aLout to get upuateu. Foi instance, piioi to iOS 6, in oiuei to ieliesh youi mailLox in
the Mail app, you hau to piess a ieliesh Lutton. In iOS 6, now you can simply uiag the
list ol youi emails uown, as il you wanteu to see what`s aLove theie in the list that you
haven`t ieau alieauy. Once iOS uetects this gestuie ol youis, it will tiiggei a ieliesh.
Isn`t that cool? Twittei`s iPhone app staiteu this whole thing when they auueu a ieliesh
contiol to theii apps, so kuuos to them loi this. Apple has iealizeu this is in lact a ieally
nice anu intuitive way ol upuating taLle views anu has since auueu a ueuicateu com-
ponent to the SDK to implement it. The class name loi this component is UIRefresh
Control.
Cieate a new instance ol this class simply Ly calling its init methou. Once you aie
uone, auu this instance to youi taLle view contiollei, as uesciiLeu in the Solution section
ol this iecipe.
Now you`ll want to know when the usei has tiiggeieu a ieliesh on youi taLle view. To
uo this, simply call the addTarget:action:forControlEvents: instance methou ol youi
ieliesh contiol anu pass the taiget oLject anu a selectoi on that oLject that takes caie
ol the ieliesh loi you. Pass UIControlEventValueChanged to the forControlEvents pa-
iametei ol this methou.
HeieI want to uemonstiate this to you. In this example, we will have a taLle view
contiollei that uisplays uate anu time loimatteu as stiings. Once the usei ielieshes the
list Ly pulling it uown, we will auu the cuiient uate anu time again to the list anu ieliesh
oui taLle view. This way, eveiy time the usei pulls the list uown, it tiiggeis a ieliesh
that will allow us to auu the cuiient uate anu time to the list anu ieliesh the taLle view
to uisplay the new uate anu time. So let`s stait in the implementation lile ol oui taLle
view contiollei anu ueline oui ieliesh contiol anu oui uata souice:
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong) NSMutableArray *times;
@property (nonatomic, strong) UIRefreshControl *refreshControl;
@end
@implementation ViewController
...
The times piopeity is a simple mutaLle aiiay that will contain all the instances ol
NSDate in it as the usei ielieshes the taLle view. Ve have alieauy seen the initialization
ol oui taLle view contiollei in the Solution section ol this iecipe, so I won`t wiite it
again heie. But as you saw theie, we have hookeu the UIControlEventValueChanged event
ol oui ieliesh contiol to a methou calleu handleRefresh:. In this methou, all we aie
going to uo is auu the cuiient uate anu time to oui aiiay ol uate anu times anu then
ieliesh the taLle view:
- (void) handleRefresh:(id)paramSender{
/* Put a bit of delay between when the refresh control is released
4.14 Displaying a Refresh Control for Table Views | 333
www.it-ebooks.info
and when we actually do the refreshing to make the UI look a bit
smoother than just doing the update without the animation */
int64_t delayInSeconds = 1.0f;
dispatch_time_t popTime =
dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
/* Add the current date to the list of dates that we have
so that when the table view is refreshed, a new item will appear
on the screen so that the user will see the difference between
the before and the after of the refresh */
[self.times addObject:[NSDate date]];
[self.refreshControl endRefreshing];
[self.tableView reloadData];
});
}
Last Lut not least, we will pioviue the uate to oui taLle view thiough the taLle view`s
uelegate anu uata souice methous:
- (id)initWithStyle:(UITableViewStyle)style{
self = [super initWithStyle:style];
if (self) {
self.times = [NSMutableArray arrayWithObject:[NSDate date]];

/* Create the refresh control */
self.refreshControl = [[UIRefreshControl alloc] init];
self.refreshControl = self.refreshControl;
[self.refreshControl addTarget:self
action:@selector(handleRefresh:)
forControlEvents:UIControlEventValueChanged];

}
return self;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section{
return self.times.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath{

static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
334 | Chapter 4: Constructing and Using Table Views
www.it-ebooks.info
reuseIdentifier:CellIdentifier];
}

cell.textLabel.text = [NSString stringWithFormat:@"%@",
self.times[indexPath.row]];

return cell;
}
Give this a go in eithei the simulatoi oi the uevice. Once you open the app, at liist you
will see only one uate/time auueu to the list. Keep uiagging the taLle view uown to get
moie items in the list (see Figuie +-26).
Iigurc 1-2. Our tab|c vicw contro||cr is popu|atcd by a ncw itcn cvcry tinc it is rcjrcshcd
See Also
Recipe +.13
4.14 Displaying a Refresh Control for Table Views | 335
www.it-ebooks.info
www.it-ebooks.info
CHAPTER 5
Storyboards
5.0 Introduction
iOS piogiammeis aie all useu to view contiolleis Ly now. Ve know how to use navi-
gation contiolleis in oiuei to push anu pop view contiolleis. But Apple Lelieves this
can Le uone moie easily, anu that`s the whole stoiy Lehinu stoiyLoaius. Storyboard-
ing is the new way ol uelining the connections Letween uilleient scieens in youi app.
Foi instance, il you have 20 unigue view contiolleis in youi app that you coueu a yeai
ago anu aie looking at the souice coue again now, you will neeu to linu youi way aiounu
the connections Letween these view contiolleis, anu to tiy to iememLei what view
contiollei is pusheu when a ceitain action is taken Ly the usei. This can Le veiy uillicult,
especially il you have not uocumenteu youi coue. StoiyLoaius come to the iescue. Vith
stoiyLoaius, you can now view/cieate youi entiie app`s UI anu the connections Le-
tween view contiolleis in one scieen. It`s that simple.
To take auvantage ol stoiyLoaiuing, you neeu to get acguainteu with Inteilace Builuei.
Don`t woiiy; it`s all coveieu in this chaptei.
Vith stoiyLoaius, one scieen`s woith ol content is calleu a sccnc. The ielation Letween
a scene anu a stoiyLoaiu on the iPhone can Le compaieu to a view anu a view contiollei.
In a scene, you put all youi content on the scieen to Le piesenteu to the usei at the
same time. On the iPau, moie than one scene can Le piesenteu to the usei at the same
time Lecause ol the Liggei scieen.
StoiyLoaiuing suppoits tiansitioning liom one scene to anothei. The eguivalent ol a
navigation contiollei pushing one view contiollei on top ol anothei is a scguc in stoiy-
Loaiuing. Anothei type ol tiansition is a moual view contiollei that sliues a scene liom
the Lottom ol the scieen up to lill the scieen tempoiaiily. On the iPau, moual scieens
usually appeai in the centei ol the scieen anu uim the iest ol the scieen, to point out
that they aie the main input at that moment.
337
www.it-ebooks.info
5.1 Creating a Project with Storyboards
Problem
In Xcoue, you want to cieate a pioject that uses StoiyLoaius.
Solution
Choose the Use StoiyLoaiu option in the New Pioject setting uialog (Figuie 5-1) anu
make youi app a univeisal app.
Iigurc 5-1. Thc Usc Storyboard option oj Ncw Projcct dia|og
Discussion
Il you want to cieate a pioject that uses stoiyLoaius, simply lollow these steps:
1. In Xcoue, select the File menu anu then New New Pioject...
2. In the New Pioject uialog, make suie the iOS main categoiy is selecteu anu select
the Application suLcategoiy unuei iOS. Once that is uone, on the iight siue, select
Single View Application anu piess Next, as shown in Figuie 5-2.
3. Now select a piouuct name anu make suie youi app is a Univeisal app. Apple wants
uevelopeis to stait wiiting univeisal apps whenevei they can, in oiuei loi iPau useis
to also enjoy the same apps that iPhone anu iPou touch useis have access to. In
this uialog, make suie you have checkeu the Usei StoiyLoaius checkLox, as shown
in Figuie 5-3. Altei you aie uone, piess Next.
+. You will now Le askeu to save youi pioject in a loluei. Once you aie uone, piess
the Cieate Lutton (see Figuie 5-+) anu now you have a pioject that uses stoiy-
Loaius.
Now il you have a look at the liles that Xcoue has cieateu loi you (see Figuie 5-5), you`ll
notice two liles whose names enu with .storyboard. Xcoue, Lecause this is a univeisal
app, cieateu a stoiyLoaiu loi iPhone anu anothei stoiyLoaiu loi iPau, so you can uictate
how you want youi app to look on each uevice lamily.
338 | Chapter 5: Storyboards
www.it-ebooks.info
Iigurc 5-2. Crcating a ncw app|ication to usc storyboards
Iigurc 5-3. Using storyboards jor a ncw projcct
5.1 Creating a Project with Storyboards | 339
www.it-ebooks.info
Iigurc 5-1. Saving thc storyboard app on dis|
Iigurc 5-5. Two storyboard ji|cs in a univcrsa| app
5.2 Adding a Navigation Controller to a Storyboard
Problem
You want to Le aLle to manage multiple view contiolleis insiue a stoiyLoaiu-Laseu
application.
340 | Chapter 5: Storyboards
www.it-ebooks.info
Solution
Set a navigation contiollei as the initial view contiollei ol youi stoiyLoaiu lile.
Discussion
Il you lolloweu the instiuctions in Recipe 5.1 anu aie now iunning youi app on the
iPhone Simulatoi, you`ll see just a white scieen with no navigation Lai acioss the top.
The ieason is that the initial view contiollei ol oui stoiyLoaiu lile is a view contiollei,
as opposeu to a navigation contiollei. In oiuei to auu a navigation contiollei to youi
stoiyLoaiu-Laseu app, simply lollow these steps:
1. Click on the iPhone stoiyLoaiu that Xcoue cieateu loi you. I have nameu my pioject
Adding a Navigation Bar to a Storyboard. My iPhone stoiyLoaiu lile is Main-
Storyboard_iPhonc.storyboard (the name ol the uelault stoiyLoaiu lile cieateu Ly
Xcoue, uepenuing on the veision ol Xcoue you aie using, uoes not have to have
any connection to the name ol youi pioject). Once you click on this lile, Inteilace
Builuei will uisplay its contents.
2. Once the stoiyLoaiu lile is open in IB (Inteilace Builuei), simply uouLle-click on
an empty space on the stoiyLoaiu`s canvas anu you will see the content shiink in
size anu give you moie liee space to play with, as you can see in Figuie 5-6.
Iigurc 5-. Thc zooncd out vicw oj an iPhonc storyboard
5.2 Adding a Navigation Controller to a Storyboard | 341
www.it-ebooks.info
3. Unuei the View menu, select Utilities Show OLject LiLiaiy.
+. In the OLject LiLiaiy, linu the Navigation Contiollei oLject (see Figuie 5-7) anu
uiag anu uiop it into the stoiyLoaiu, to the |cjt siue ol youi existing view contiollei
(Figuie 5-6). Now you will see something similai to Figuie 5-S.
Iigurc 5-7. Thc Navigation Contro||cr objcct in thc Objcct Library
Iigurc 5-8. A navigation contro||cr concs with its own root vicw contro||cr
342 | Chapter 5: Storyboards
www.it-ebooks.info
5. As you can see in Figuie 5-S, the navigation contiollei has now auueu anothei view
contiollei to oui UI. Vhat you neeu to uo is to simply uelete this view contiollei.
Do so Ly selecting it anu then piessing the Delete Lutton on the keyLoaiu. Now
you aie lelt with the navigation contiollei anu youi oiiginal view contiollei, as you
can see in Figuie 5-9.
Iigurc 5-9. Rcnoving thc root vicw contro||cr that concs with thc navigation contro||cr objcct
The pioject that we set up in Recipe 5.1 is a Single View Application.
This type ol application uoes not come with a navigation contiollei Ly
uelault, loi the oLvious ieason that it is a Single View Application.
Theieloie, to change this stiuctuie, we will neeu to auu the navigation
contiollei to oui stoiyLoaiu lile manually.
6. Now click once on the navigation contiollei oLject on the stoiyLoaiu. Once the
navigation contiollei oLject is selecteu, ho|d down thc Contro| |cy on your |cyboard
and thc |cjt button on your nousc anu uiag youi mouse ovei to the view contiollei
(on the iight) that was oiiginally on youi stoiyLoaiu. This will uiaw a line liom
the navigation contiollei all the way to the view contiollei, as you can see in
Figuie 5-10.
5.2 Adding a Navigation Controller to a Storyboard | 343
www.it-ebooks.info
Iigurc 5-10. Connccting thc navigation contro||cr to thc initia| vicw contro||cr
7. Now ielease youi mouse Lutton, at which point you will Le piesenteu with a uialog
asking you what type ol connection you want to cieate Letween the navigation anu
the view contiollei. Select the rootViewController item liom the list Ly simply
clicking on it (see Figuie 5-11).
S. Altei this is uone, the stoiyLoaiu will show that youi navigation contiollei is con-
necteu to the oiiginal view contiollei, as you can see in Figuie 5-12.
Iigurc 5-11. Sctting a vicw contro||cr as thc root oj a navigation contro||cr
9. The last Lut peihaps nost inportant step is to make youi navigation contiollei the
initial/ioot view contiollei. Il you uon`t uo this, the stoiyLoaiu will use the view
contiollei that it initially assigneu as the initial view contiollei. Have anothei look
at Figuie 5-12. Can you see that the view contiollei on the iight siue has a coloilul
Loiuei aiounu it? That inuicates an initial view contiollei. To make youi navigation
the initial view contiollei, simply select the Navigation Contiollei unuei the Nav-
igation Contiollei Scene panel in Inteilace Builuei, as you can see in Figuie 5-13.
344 | Chapter 5: Storyboards
www.it-ebooks.info
Now select the View menu in Xcoue anu choose View Show AttiiLutes Inspectoi.
Once the attiiLutes inspectoi is openeu, unuei the View Contiollei categoiy, check
the Is Initial View Contiollei checkLox (see Figuie 5-1+).
Iigurc 5-13. Sc|ccting thc navigation contro||cr in |ntcrjacc Bui|dcr
As you can see, youi navigation contiollei now has a Loiuei aiounu it insteau ol the
iighthanu view contiollei. Now il you iun youi application, you will notice that the
initial view contiollei has a navigation Lai on top, inuicating that this view contiollei
now has a navigation contiollei (Figuie 5-15). In the next iecipes, we will see how we
can make use ol the navigation contiollei to uisplay new scenes on the scieen.
Iigurc 5-12. Thc navigation contro||cr is conncctcd to thc initia| vicw contro||cr
5.2 Adding a Navigation Controller to a Storyboard | 345
www.it-ebooks.info
Iigurc 5-11. Sc|ccting a navigation contro||cr as thc initia| vicw contro||cr oj a storyboard
Iigurc 5-15. Thc navigation bar on a vicw contro||cr crcatcd with a storyboard
Ve now have a navigation contiollei with a view contiollei insiue it, Lut oui oLjective
now is to tiiggei an action anu then move liom one view contiollei to anotheiwhat
Apple calls a segue. All iight then; let`s place a Lutton on oui view contiollei anu push
a view contiollei into the stack once the usei piesses the Lutton. Sounus goou? Do it
as lollows:
346 | Chapter 5: Storyboards
www.it-ebooks.info
1. Go Lack to youi .storyboard lile.
2. In the OLject LiLiaiy, linu the View Contiollei oLject (see Figuie 5-16) anu uiag
anu uiop it onto the stoiyLoaiu, on the iight siue ol youi existing view contiollei,
as shown in Figuie 5-17.
Iigurc 5-1. A vicw contro||cr objcct in thc Objcct Library
Iigurc 5-17. Adding a ncw vicw contro||cr to a storyboard
3. In OLject LiLiaiy, linu the Button oLject (see Figuie 5-1S) anu uiag anu uiop it
into the liist view contiollei (see Figuie 5-19). Note that il you aie zoomeu out,
5.2 Adding a Navigation Controller to a Storyboard | 347
www.it-ebooks.info
Inteilace Builuei will not allow you to uiop a Lutton onto a view contiollei. You
neeu to uouLle-click on an empty space on youi stoiyLoaiu to zoom into it Leloie
Inteilace Builuei allows you to uiop UI components onto youi view contiolleis.
+. Now, to select the Lutton, holu uown the Contiol key on youi keyLoaiu anu the
lelt mouse Lutton ovei the Lutton, anu uiag it all the way to the seconu view con-
tiollei (see Figuie 5-20).
Iigurc 5-18. Sc|ccting thc Button objcct in thc Objcct Library
Iigurc 5-19. Dropping a button on thc jirst vicw contro||cr in our storyboard
348 | Chapter 5: Storyboards
www.it-ebooks.info
Iigurc 5-20. Connccting a button to anothcr vicw contro||cr in a storyboard
5. Now lilt youi lingeis oll the mouse Lutton anu the Contiol key on youi keyLoaiu.
You will now Le piesenteu with a uialog similai to that shown in Figuie 5-21. Click
on the performSegueWithIdentifier:sender: item.
Iigurc 5-21. Ma|ing a button pcrjorn a scguc
Now il you have a look at youi stoiyLoaiu, you will see that the liist view contiollei is
connecteu to the seconu view contiollei, as shown in Figuie 5-22.
Now il you iun youi app anu tap on the Lutton on the liist view contiollei, you`ll see
that the seconu view contiollei will automatically get pusheu onto the stack ol view
contiolleis. Once the seconu view contiollei is piesenteu, you will see a Lack Lutton
on the navigation Lai. Il you piess that Lutton, you will Le sent Lack to the liist view
contiollei.
5.2 Adding a Navigation Controller to a Storyboard | 349
www.it-ebooks.info
Iigurc 5-22. Thc jirst vicw contro||cr is conncctcd to thc sccond vicw contro||cr through a scguc
See Also
Recipe 5.1
5.3 Passing Data From One Screen to Another
Problem
You want to pass uata liom one scene to anothei using stoiyLoaius.
Solution
Use segue oLjects.
Discussion
A segue is an oLject, just like any othei oLject in OLjective-C. To caiiy out a tiansition
liom one scene to anothei, the stoiyLoaiu iuntime cieates a segue oLject loi that tian-
sition. A segue is an instance ol class UIStoryboardSegue. To stait a tiansition, the cui-
ient view contiollei (which will get pusheu out ol the scieen altei the segue) ieceives
the prepareForSegue:sender: message, wheie the prepareForSegue paiametei will Le an
350 | Chapter 5: Storyboards
www.it-ebooks.info
oLject ol type UIStoryboardSegue. Il you want to pass any uata liom the cuiient view
contiollei to the view contiollei that is aLout to appeai on the scieen, you neeu to uo
that in the prepareForSegue:sender: methou.
Foi this iecipe to make sense, you neeu to have lolloweu the instiuctions
in Recipe 5.2 anu cieateu two view contiolleis insiue a navigation con-
tiollei on youi stoiyLoaiu.
Let`s implement the prepareForSegue:sender: methou in the liist view contiollei:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
NSLog(@"Source Controller = %@", [segue sourceViewController]);
NSLog(@"Destination Controller = %@", [segue destinationViewController]);
NSLog(@"Segue Identifier = %@", [segue identifier]);
}
Il you iun this app now, you will see the iesults in the console winuow. Howevei, you
might note that the iuentiliei is nil. Each segue has an iuentiliei that uniguely iuentilies
it. Since one scene can have moie than one segue associateu with it, it`s a goou iuea to
give youi segues iuentilieis that you can then uetect in youi view contiolleis anu take
action accoiuingly.
A segue oLject in Inteilace Builuei is the connection Letween two scenes. Figuie 5-23
shows the segue as an aiiow Letween my liist view contiollei on the lelt anu the seconu
view contiollei on the iight.
Iigurc 5-23. Sc|ccting a scguc objcct in |ntcrjacc Bui|dcr
Follow these steps to give youi segue an iuentiliei:
1. Select youi segue oLject in Inteilace Builuei Ly clicking on it.
2. Fiom the View menu, select Utilities Show AttiiLutes Inspectoi.
5.3 Passing Data From One Screen to Another | 351
www.it-ebooks.info
3. In the AttiiLutes Inspectoi, in the Iuentiliei text lielu, simply wiite the iuentiliei
that you woulu like this segue to caiiy with itsell.
Vhen the stoiyLoaiu iuntime calls the prepareForSegue:sender: methou in the cuiient
view contiollei to piepaie it loi the segue, the uestination view contiollei has alieauy
Leen initializeu in the segue oLject. Now this is youi chance to pass any ieguiieu uata
to the uestination view contiollei. You can eithei set the uata uiiectly into a piopeity
ol the uestination view contiollei, oi pass youi uata Ly calling a methou on that view
contiollei; it is ieally up to you. In this coue, my seconu view contiollei is ol class
SecondViewController anu I`ve given my segue the iuentiliei ol SimpleSegueToSecond
ViewController:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
NSLog(@"Source Controller = %@", [segue sourceViewController]);
NSLog(@"Destination Controller = %@", [segue destinationViewController]);
NSLog(@"Segue Identifier = %@", [segue identifier]);
if ([[segue identifier]
isEqualToString:@"SimpleSegueToSecondViewController"]){
SecondViewController *viewController = [segue destinationViewController];
viewController.dataModel = ...; /* Write the code here */
}
}
In this example coue, the dataModal piopeity is a hypothetical piopeity ueclaieu anu
implementeu in the view contiollei that is the taiget ol oui segue. This view contiollei
is an instance ol the SecondViewController that we have cieateu loi this pioject. The
puipose ol this example is to show how you can piepaie youi view contiolleis loi a
segue anu populate necessaiy uata into the taiget view contiollei.
See Also
Recipe 5.2
5.4 Adding a Storyboard to an Existing Project
Problem
You have alieauy coueu youi app without stoiyLoaius anu now you woulu like to stait
using stoiyLoaius insteau ol hanuling the llow ol youi app manually.
Solution
Follow these steps to allow youi non-stoiyLoaiu apps to take auvantage ol stoiyLoaius:
352 | Chapter 5: Storyboards
www.it-ebooks.info
1. Fiom the File menu, choose New New File...
2. In the New File uialog, make suie you have selecteu the Resouice suLcategoiy ol
the iOS categoiy on the lelt. Then choose the StoiyLoaiu item on the iight anu
piess Next (see Figuie 5-2+).
Iigurc 5-21. Adding a storyboard to an cxisting app|ication
3. In this scieen, pick the Device Family loi which you want to cieate youi stoiyLoaiu.
Il youi app is an iPhone- oi iPau-only app, pick the appiopiiate uevice lamily. Il
youi app is univeisal, you will neeu to select one uevice lamily now, cieate the
stoiyLoaiu lile, anu then come Lack anu cieate anothei one loi youi othei uevice
lamily. Once you aie uone, piess the Next Lutton.
+. Now select wheie to save youi stoiyLoaiu. I hau a univeisal app Laseu on the Single
View Application template, so I have now cieateu two stoiyLoaiu liles unuei the
names StoryboardiPhonc.storyboard anu StoryboardiPad.storyboard.
5. In youi pioject stiuctuie, linu the |njo.p|ist lile. Note that this .p|ist lile might have
Leen stoieu unuei a uilleient name. Foi instance, I have nameu my pioject Adding
a Storyboard to an Existing Project anu my |njo.p|ist is stoieu unuei the name
Adding a Storyboard to an Existing Projcct-|njo.p|ist. Once you click on this lile,
the piopeity list euitoi will open automatically.
6. Il you have any ol these keys, uelete them liom the .p|ist lile, Lecause stoiyLoaiuing
ienueis them supeilluous:
5.4 Adding a Storyboard to an Existing Project | 353
www.it-ebooks.info
NSMainNibFile (might appeai as Main nib ji|c basc nanc).
NSMainNibFile~ipad (might appeai as Main nib ji|c basc nanc (iPad)).
7. Il you have an iPhone oi iPau only app, cieate a new key calleu UIMainStoryboard
File loi iPhone oi UIMainStoryboardFile~ipad loi iPau. Il you have a univeisal app,
cieate Loth these keys.
S. Foi the values ol these keys, pioviue the lilenames ol the stoiyLoaius that you
cieateu without the .storyboard extension.
9. Make suie to save the .p|ist lile.
10. Last, Lut peihaps most impoitant, iemove the coue that set up the view contiolleis
liom the application:didFinishLaunchingWithOptions: methou in youi app uele-
gate`s implementation. Vith stoiyLoaius, you will no longei neeu to set up view
contiolleis manually in youi app uelegate, so have a look at the aloiementioneu
methou anu iemove the unnecessaiy setup.
Discussion
Apps cieateu without stoiyLoaius (eithei on oluei veisions ol Xcoue oi using the new
veisions without stoiyLoaiuing) have a uilleient stiuctuie liom apps that use stoiy-
Loaius. Foi one thing, the stoiyLoaiu-Laseu apps no longei use a main niL lile loi theii
winuows. So this lile neeus to Le iemoveu liom the .p|ist ol oui app. The othei thing
to uo, as we saw in the Solution section, is to make oui app unueistanu what oui
stoiyLoaiu liles aie Ly setting them in the .p|ist.
Once all that is uone, we neeu to make suie that oui app uelegate is not messing with
how we intenu to loau oui stoiyLoaius. Eveiy pioject is uilleient, anu you neeu to make
suie that the app uelegate is not assigning any oLject to the rootViewController piopeity
ol the winuow. Il it uoes, youi stoiyLoaius will not Le uisplayeu anu you will spenu
houis anu houis tiying to linu out what the issue is. The easiest solution is to simply
comment out the entiie application:didFinishLaunchingWithOptions: methou anu
consiuei putting youi initialization (loi instance, initializing any uata mouels) in othei
places in youi app. An alteinative is to simply leave this methou as it is Lut comment
out any lines that might Le changing the winuow`s ioot view contiollei oLject.
354 | Chapter 5: Storyboards
www.it-ebooks.info
CHAPTER 6
Concurrency
6.0 Introduction
Concuiiency is achieveu when two oi moie tasks aie executeu at the same time. Mouein
opeiating systems have the aLility to iun tasks concuiiently, even on one CPU. They
achieve this Ly giving eveiy task a ceitain time slice liom the CPU. Foi instance, il theie
aie 10 tasks to Le executeu in one seconu, all with the same piioiity, the opeiating
system will uiviue 1000 milliseconus Ly 10 (tasks) anu will give each task 100 milli-
seconus ol the CPU time. That means all these tasks will then Le executeu in the same
seconu anu they will appeai to have Leen executeu concuiiently.
Howevei, with auvances in technology, now we have CPUs with moie than one coie.
This means that the CPU is tiuly capaLle ol executing tasks at the same time. The
opeiating system will uispatch the tasks to the CPU anu will wait until they aie uone.
It`s that simple!
Gianu Cential Dispatch, oi GCD loi shoit, is a low-level C API that woiks with Llock
oLjects. The ieal use loi GCD is to uispatch tasks to multiple coies without making
you, the piogiammei, woiiy aLout which coie is executing which task. On Mac OS X,
multicoie uevices, incluuing laptops, have Leen availaLle to useis loi guite some time.
Vith the intiouuction ol multicoie uevices such as the new iPau, piogiammeis can
wiite amazing multicoie-awaie multithieaueu apps loi iOS.
At the heait ol GCD aie uispatch gueues. Dispatch gueues, as we will soon see, aie
pools ol thieaus manageu Ly GCD on the host opeiating system, whethei iOS oi Mac
OS X. You will not Le woiking with these thieaus uiiectly. You will just woik with
uispatch gueues, uispatching tas|s to these gueues anu asking the gueues to invoke
youi tasks. GCD olleis seveial options loi iunning tasks: synchionously, asynchio-
nously, altei a ceitain uelay, etc.
To stait using GCD in youi apps, you uon`t have to impoit any special liLiaiy into youi
pioject. Apple has alieauy incoipoiateu GCD into vaiious liamewoiks, incluuing Coie
Founuation anu Cocoa/Cocoa Touch. All methous anu uata types availaLle in GCD
stait with a dispatch_ keywoiu. Foi instance, dispatch_async allows you to uispatch a
355
www.it-ebooks.info
task on a gueue loi asynchionous execution, wheieas dispatch_after allows you to iun
a Llock ol coue altei a given uelay.
Beloie GCD anu opeiations, piogiammeis hau to cieate theii own thieaus to peiloim
tasks in paiallel. Foi instance, an iOS uevelopei woulu cieate a thieau similai to this
to peiloim an opeiation 1000 times:
- (void) doCalculation{
/* Do your calculation here */
}
- (void) calculationThreadEntry{

@autoreleasepool {
NSUInteger counter = 0;
while ([[NSThread currentThread] isCancelled] == NO){
[self doCalculation];
counter++;
if (counter >= 1000){
break;
}
}
}

}
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

/* Start the thread */
[NSThread detachNewThreadSelector:@selector(calculationThreadEntry)
toTarget:self
withObject:nil];

self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
The piogiammei has to stait the thieau manually anu then cieate the ieguiieu stiuctuie
loi the thieau (entiy point, autoielease pool, anu thieau`s main loop). Vhen we wiite
the same coue with GCD, we ieally won`t have to uo much. Ve will simply place oui
coue in a Llock oLject anu uispatch that Llock oLject to GCD loi execution. Vhethei
that coue gets executeu on the main thieau oi any othei thieau uepenus on us. Heie is
an example:
dispatch_queue_t queue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
size_t numberOfIterations = 1000;dispatch_async(queue, ^(void) {
dispatch_apply(numberOfIterations, queue, ^(size_t iteration){
/* Perform the operation here */
356 | Chapter 6: Concurrency
www.it-ebooks.info
});
});
In this chaptei, you will leain all theie is to know aLout GCD anu how to use it to wiite
mouein multithieaueu apps loi iOS anu Mac OS X that will achieve Llazing peiloi-
mance on multicoie uevices such as the iPau 2.
Ve will Le woiking with uispatch gueues a lot, so please make suie that you lully
unueistanu the concept Lehinu them. Theie aie thiee types ol uispatch gueues:
Main qucuc
This gueue peiloims all its tasks on the main thieau, which is wheie Cocoa anu
Cocoa Touch ieguiie piogiammeis to call all UI-ielateu methous. Use the dis
patch_get_main_queue lunction to ietiieve the hanule to the main gueue.
Concurrcnt qucucs
These aie gueues that you can ietiieve liom GCD in oiuei to execute asynchionous
oi synchionous tasks. Multiple concuiient gueues can Le executing multiple tasks
in paiallel, without Lieaking a sweat. No moie thieau management, yippee! Use
the dispatch_get_global_queue lunction to ietiieve the hanule to a concuiient
gueue.
Scria| qucucs
These aie gueues that, no mattei whethei you suLmit synchionous oi asynchio-
nous tasks to them, will always execute theii tasks in a liist-in-liist-out (FIFO)
lashion, meaning that they can only execute one Llock oLject at a time. Howevei,
they uo not iun on the main thieau anu theieloie aie peilect loi a seiies ol tasks
that have to Le executeu in stiict oiuei without Llocking the main thieau. Use the
dispatch_queue_create lunction to cieate a seiial gueue. Once you aie uone with
the gueue, you must ielease it using the dispatch_release lunction.
At any moment uuiing the liletime ol youi application, you can use multiple uispatch
gueues at the same time. Youi system has only one main gueue, Lut you can cieate as
many seiial uispatch gueues as you want (within ieason, ol couise), loi whatevei lunc-
tionality you ieguiie loi youi app. You can also ietiieve multiple concuiient gueues
anu uispatch youi tasks to them. Tasks can Le hanueu to uispatch gueues in two loims:
Llock oLjects oi C lunctions, as we will see in Recipe 6.+.
Block oLjects aie pac|agcs ol coue that usually appeai in the loim ol methous in OL-
jective-C. Block oLjects, togethei with Gianu Cential Dispatch (GCD), cieate a hai-
monious enviionment in which you can uelivei high-peiloimance multithieaueu apps
in iOS anu Mac OS X. Vhat`s so special aLout Llock oLjects anu GCD, you might ask?
It`s simple: no moie thieaus! All you have to uo is to put youi coue in Llock oLjects
anu ask GCD to take caie ol the execution ol that coue loi you.
6.0 Introduction | 357
www.it-ebooks.info
Peihaps the most impoitant uilleience Letween Llock oLjects anu tia-
uitional lunction pointeis is that Llock oLjects copy the values ol local
vaiiaLles accesseu insiue the Llock oLjects anu keep those copies loi
local use. Il the values ol those vaiiaLles change outsiue the scope ol the
Llock oLject, you can Le suie that the Llock oLject still keeps its own
copy ol the vaiiaLle. Ve will uiscuss this in moie uetail soon.
Block oLjects in OLjective-C aie what the piogiamming lielu calls jirst-c|ass objccts.
This means you can Luilu coue uynamically, pass a Llock oLject to a methou as a
paiametei, anu ietuin a Llock oLject liom a methou. All ol these things make it easiei
to choose what you want to uo at iuntime anu change the activity ol a piogiam. In
paiticulai, Llock oLjects can Le iun in inuiviuual thieaus Ly GCD. Being OLjective-C
oLjects, Llock oLjects can Le tieateu like any othei oLject.
Block oLjects aie sometimes ieleiieu to as c|osurcs.
Constiucting Llock oLjects is similai to constiucting tiauitional C lunctions, as we will
see in Recipe 6.1. Block oLjects can have ietuin values anu can accept paiameteis. Block
oLjects can Le uelineu inline oi tieateu as a sepaiate Llock ol coue, similai to a C
lunction. Vhen cieateu inline, the scope ol vaiiaLles accessiLle to Llock oLjects is
consiueiaLly uilleient liom when a Llock oLject is implementeu as a sepaiate Llock ol
coue.
GCD woiks with Llock oLjects. Vhen peiloiming tasks with GCD, you can pass a
Llock oLject whose coue can get executeu synchionously oi asynchionously, uepenu-
ing on which methous you use in GCD. Thus, you can cieate a Llock oLject that is
iesponsiLle loi uownloauing a URL passeu to it as a paiametei. That single Llock oLject
can then Le useu in vaiious places in youi app synchionously oi asynchionously, ue-
penuing on how you woulu like to iun it. You uon`t have to make the Llock oLject
synchionous oi asynchionous pei se; you will simply call it with synchionous oi asyn-
chionous GCD methous anu the Llock oLject will just wor|.
Block oLjects aie guite new to piogiammeis wiiting iOS anu OS X apps. In lact, Llock
oLjects aie not as populai as thieaus yet, peihaps Lecause theii syntax is a Lit uilleient
liom puie OLjective-C methous anu moie complicateu. Nonetheless, Llock oLjects aie
enoimously poweilul anu Apple is making a Lig push towaiu incoipoiating them into
Apple liLiaiies. You can alieauy see these auuitions in classes such as NSMutableArray,
wheie piogiammeis can soit the aiiay using a Llock oLject.
This chaptei is ueuicateu entiiely to constiucting anu using Llock oLjects in iOS anu
Mac OS X apps, using GCD loi uispatching tasks to the opeiating system, thieaus anu
timeis. I woulu like to stiess that the only way to get useu to Llock oLjects` syntax is
358 | Chapter 6: Concurrency
www.it-ebooks.info
to wiite a lew ol them loi youisell. Have a look at the sample coue in this chaptei anu
tiy implementing youi own Llock oLjects.
Heie, you will leain the Lasics ol Llock oLjects, lolloweu Ly some moie auvanceu suL-
jects, such as Gianu Cential Dispatch, Thieaus, Timeis, Opeiations, anu Opeiation
Queues. You will unueistanu eveiything you neeu to know aLout Llock oLjects Leloie
moving to the Gianu Cential Dispatch mateiial. Fiom my expeiience, the Lest way to
leain Llock oLjects is thiough examples, so you will see a lot ol them in this chaptei.
Make suie you tiy the examples loi youisell in Xcoue to ieally gct the syntax ol Llock
oLjects.
Opeiations can Le conliguieu to iun a Llock ol coue synchionously oi asynchionously.
You can manage opeiations manually oi place them on opcration qucucs, which lacil-
itate concuiiency so that you uo not neeu to think aLout the unueilying thieau man-
agement. In this chaptei, you will see how to use opeiations anu opeiation gueues, as
well as Lasic thieaus anu timeis, to synchionously anu asynchionously execute tasks
in applications.
Cocoa pioviues thiee uilleient types ol opeiations:
B|oc| opcrations
These lacilitate the execution ol one oi moie Llock oLjects.
|nvocation opcrations
These allow you to invoke a methou in anothei, cuiiently existing oLject.
P|ain opcrations
These aie plain opeiation classes that neeu to Le suLclasseu. The coue to Le exe-
cuteu will Le wiitten insiue the main methou ol the opeiation oLject.
Opeiations, as mentioneu Leloie, can Le manageu with opeiation gueues, which have
the uata type NSOperationQueue. Altei instantiating any ol the aloiementioneu opeiation
types (Llock, invocation, oi plain opeiation), you can auu them to an opeiation gueue
anu have the gueue manage the opeiation.
An opeiation oLject can have uepenuencies on othei opeiation oLjects anu Le instiuc-
teu to wait loi the completion ol one oi moie opeiations Leloie executing the task
associateu with it. Unless you auu a uepenuency, you have no contiol ovei the oiuei
in which opeiations iun. Foi instance, auuing them to a gueue in a ceitain oiuei uoes
not guaiantee that they will execute in that oiuei, uespite the use ol the teim qucuc.
Theie aie a lew impoitant things to Leai in minu while woiking with opeiation gueues
anu opeiations:
Opeiations, Ly uelault, iun on the thieau that staits them, using theii start in-
stance methou. Il you want the opeiations to woik asynchionously, you will have
to use eithei an opeiation gueue oi a suLclass NSOperation anu uetach a new thieau
on the main instance methou ol the opeiation.
6.0 Introduction | 359
www.it-ebooks.info
An opeiation can wait loi the execution ol anothei opeiation to linish Leloie it
staits itsell. Be caielul not to cieate inteiuepenuent opeiations, a common mistake
known as a dcad|oc|. In othei woius, uo not tell opeiation A to uepenu on opei-
ation B il B alieauy uepenus on A; this will cause Loth to wait loievei, taking up
memoiy anu possiLly hanging youi application.
Opeiations can Le cancelleu. So, il you have suLclasseu NSOperation to cieate cus-
tom opeiation oLjects, you have to make suie to use the isCancelled instance
methou to check whethei the opeiation has Leen cancelleu Leloie executing the
task associateu with the opeiation. Foi instance, il youi opeiation`s task is to check
loi the availaLility ol an Inteinet connection eveiy 20 seconus, it must call the
isCancelled instance methou at the Leginning ol each iun to make suie it has not
Leen cancelleu Leloie attempting to check loi an Inteinet connection again. Il the
opeiation takes moie than a lew seconus (such as when you uownloau a lile), you
shoulu also check isCancelled peiiouically while iunning the task.
Opeiation oLjects aie key-value oLseiving (KVO) compliant on vaiious key paths
such as isFinished, isReady, anu isExecuting. Ve will Le uiscussing Key Value
Couing anu Key Value OLseiving in a latei chaptei.
Il you plan to suLclass NSOperation anu pioviue a custom implementation loi the
opeiation, you must cieate youi own autoielease pool in the main methou ol the
opeiation, which gets calleu liom the start methou. Ve will uiscuss this in uetail
latei in this chaptei.
Always keep a ieleience to the opeiation oLjects you cieate. The concuiient natuie
ol opeiation gueues might make it impossiLle loi you to ietiieve a ieleience to an
opeiation altei it has Leen auueu to the gueue.
Thieaus anu timeis aie oLjects, suLclassing NSObject. Spawning a thieau ieguiies moie
woik than cieating timeis, anu setting up a thieau loop itsell is moie uillicult than
simply listening loi a timei liiing on a selectoi. Vhen an application iuns unuei iOS,
the opeiating system cieates at least one thieau loi that application, calleu the main
thieau. Eveiy thieau anu timei must Le auueu to a iun loop. A iun loop, as its name
implies, is a loop uuiing which uilleient events can occui, such as a timei liiing oi a
thieau iunning. Discussion ol iun loops is Leyonu the scope ol this chaptei, Lut we
will ielei to them heie anu theie in iecipes.
Think ol a iun loop as a kinu ol loop that has a staiting point, a conuition loi linishing,
anu a seiies ol events to piocess uuiing its liletime. A thieau oi timei is attacheu to a
run loop, anu in lact ieguiies a iun loop to lunction.
The main thieau ol an application is the thieau that hanules the UI events. Il you
peiloim a long-iunning task on the main thieau, you will notice that the UI ol youi
application will Lecome uniesponsive oi slow to iesponu. To avoiu this, you can cieate
sepaiate thieaus anu/oi timeis, each ol which peiloims its own task (even il it is a long-
iunning task) Lut will not Llock the main thieau.
360 | Chapter 6: Concurrency
www.it-ebooks.info
6.1 Constructing Block Objects
Problem
You want to Le aLle to wiite youi own Llock oLjects oi use Llock oLjects with iOS SDK
classes.
Solution
You just neeu to unueistanu the Lasic uilleiences Letween the syntax ol Llock oLjects
anu classic C lunctions. These uilleiences aie explaineu in the Discussion section.
Discussion
Block oLjects can eithei Le inline oi coueu as inuepenuent Llocks ol coue. Let`s stait
with the lattei type. Suppose you have a methou in OLjective-C that accepts two integei
values ol type NSInteger anu ietuins the uilleience ol the two values, Ly suLtiacting
one liom the othei, as an NSInteger:
- (NSInteger) subtract:(NSInteger)paramValue
from:(NSInteger)paramFrom{
return paramFrom - paramValue;
}
That was veiy simple, wasn`t it? Now let`s tianslate this OLjective-C coue to a puie C
lunction that pioviues the same lunctionality to get one step closei to leaining the
syntax ol Llock oLjects:
NSInteger subtract(NSInteger paramValue, NSInteger paramFrom){
return paramFrom - paramValue;
}
You can see that the C lunction is guite uilleient in syntax liom its OLjective-C coun-
teipait. Now let`s have a look at how we coulu coue the same lunction as a Llock oLject:
NSInteger (^subtract)(NSInteger, NSInteger) =
^(NSInteger paramValue, NSInteger paramFrom){
return paramFrom - paramValue;
};
Beloie I go into uetails aLout the syntax ol Llock oLjects, let me show you a lew moie
examples. Suppose we have a lunction in C that takes a paiametei ol type NSUInteger
(an unsigneu integei) anu ietuins it as a stiing ol type NSString. Heie is how we im-
plement this in C:
6.1 Constructing Block Objects | 361
www.it-ebooks.info
NSString* intToString (NSUInteger paramInteger){
return [NSString stringWithFormat:@"%lu",
(unsigned long)paramInteger];
}
To leain aLout loimatting stiings with system-inuepenuent loimat
specilieis in OLjective-C, please ielei to the Stiing Piogiamming Guiue
in the iOS Developei LiLiaiy on Apple`s weLsite.
The Llock oLject eguivalent ol this C lunction is shown in Example 6-1.
Exanp|c -1. Exanp|c b|oc| objcct dcjincd as junction
NSString* (^intToString)(NSUInteger) = ^(NSUInteger paramInteger){
NSString *result = [NSString stringWithFormat:@"%lu",
(unsigned long)paramInteger];
return result;
};
The simplest loim ol an inuepenuent Llock oLject woulu Le a Llock oLject that ietuins
void anu uoes not take in any paiameteis:
void (^simpleBlock)(void) = ^{
/* Implement the block object here */
};
Block oLjects can Le invokeu in the exact same way as C lunctions. Il they have any
paiameteis, you pass those as you woulu loi a C lunction, anu any ietuin value can Le
ietiieveu exactly as you woulu ietiieve a C lunction`s ietuin value. Heie is an example:
NSString* (^intToString)(NSUInteger) = ^(NSUInteger paramInteger){
NSString *result = [NSString stringWithFormat:@"%lu",
(unsigned long)paramInteger];
return result;
};
- (void) callIntToString{
NSString *string = intToString(10);
NSLog(@"string = %@", string);
}
The callIntToString OLjective-C methou is calling the intToString Llock oLject Ly
passing the value 10 as the only paiametei to this Llock oLject anu placing the ietuin
value ol this Llock oLject in the string local vaiiaLle.
362 | Chapter 6: Concurrency
www.it-ebooks.info
Now that we know how to wiite Llock oLjects as inuepenuent Llocks ol coue, let`s have
a look at passing Llock oLjects as paiameteis to OLjective-C methous. Ve will have to
think a Lit aLstiactly to unueistanu the goal ol the lollowing example.
Suppose we have an OLjective-C methou that accepts an integei anu peiloims some
kinu ol tiansloimation on it, which may change uepenuing on what else is happening
in the piogiam. Ve know that we`ll have an integei as input anu a stiing as output,
Lut we`ll leave the exact tiansloimation up to a Llock oLject that can Le uilleient each
time the methou iuns. This methou, theieloie, will accept as paiameteis Loth the in-
tegei to Le tiansloimeu anu the Llock that will tiansloim it.
Foi the Llock oLject, we`ll use the same intToString Llock oLject that we implementeu
eailiei in Example 6-1. Now we neeu an OLjective-C methou that will accept an un-
signeu integei paiametei anu a Llock oLject as its paiametei. The unsigneu integei
paiametei is easy, Lut how uo we tell the methou that it has to accept a Llock oLject
oj thc sanc typc as the intToString Llock oLject? Fiist we typedef the signatuie ol the
intToString Llock oLject, which tells the compilei what paiameteis the Llock oLject
shoulu accept:
typedef NSString* (^IntToStringConverter)(NSUInteger paramInteger);
This typedef just tells the compilei that Llock oLjects that accept an integei paiametei
anu ietuin a stiing can simply Le iepiesenteu Ly an iuentiliei nameu IntToString
Converter. Now let`s go aheau anu wiite the OLjective-C methou that accepts Loth an
integei anu a Llock oLject ol type IntToStringConverter:
- (NSString *) convertIntToString:(NSUInteger)paramInteger
usingBlockObject:(IntToStringConverter)paramBlockObject{
return paramBlockObject(paramInteger);
}
All we have to uo now is call the convertIntToString: methou with the Llock oLject ol
choice (Example 6-2).
Exanp|c -2. Ca||ing thc b|oc| objcct in anothcr ncthod
- (void) doTheConversion{
NSString *result = [self convertIntToString:123
usingBlockObject:intToString];
NSLog(@"result = %@", result);
}
Now that we know something aLout inuepenuent Llock oLjects, let`s tuin to inline
Llock oLjects. In the doTheConversion methou we just saw, we passeu the intTo
String Llock oLject as the paiametei to the convertIntToString:usingBlockObject:
methou. Vhat il we uiun`t have a Llock oLject ieauy to Le passeu to this methou? Vell,
6.1 Constructing Block Objects | 363
www.it-ebooks.info
that woulun`t Le a pioLlem. As mentioneu Leloie, Llock oLjects aie liist-class lunctions
anu can Le constiucteu at iuntime. Let`s have a look at an alteinative implementation
ol the doTheConversion methou (Example 6-3).
Exanp|c -3. Exanp|c b|oc| objcct dcjincd as a junction
- (void) doTheConversion{
IntToStringConverter inlineConverter = ^(NSUInteger paramInteger){
NSString *result = [NSString stringWithFormat:@"%lu",
(unsigned long)paramInteger];
return result;
};
NSString *result = [self convertIntToString:123
usingBlockObject:inlineConverter];
NSLog(@"result = %@", result);
}
Compaie Example 6-3 to Example 6-1. I have iemoveu the initial coue that pioviueu
the Llock oLject`s signatuie, which consisteu ol a name anu aigument, (^intToString)
(NSUInteger). I lelt the iest ol the Llock oLject intact; it is now an anonymous oLject.
But this uoesn`t mean I have no way to ielei to the Llock oLject. I assign it using an
egual sign to a type anu a name: IntToStringConverter inlineConverter. Now I can
use the uata type to enloice piopei use in methous, anu use the name to actually pass
the Llock oLject.
In auuition to constiucting Llock oLjects inline as just shown, we can constiuct a Llock
oLject whi|c passing it as a paiametei:
- (void) doTheConversion{
NSString *result =
[self convertIntToString:123
usingBlockObject:^NSString *(NSUInteger paramInteger) {
NSString *result = [NSString stringWithFormat:@"%lu",
(unsigned long)paramInteger];
return result;
}];
NSLog(@"result = %@", result);
}
Compaie this example with Example 6-2. Both methous use a Llock oLject thiough
the usingBlockObject syntax. But wheieas the eailiei veision ieleiieu to a pieviously
ueclaieu Llock oLject Ly name (intToString), this one simply cieates a Llock oLject on
364 | Chapter 6: Concurrency
www.it-ebooks.info
the lly. In this coue, we constiucteu an inline Llock oLject that gets passeu to the
convertIntToString:usingBlockObject: methou as the seconu paiametei.
6.2 Accessing Variables in Block Objects
Problem
You want to unueistanu the uilleience Letween accessing vaiiaLles in OLjective-C
methous anu accessing those vaiiaLles in Llock oLjects.
Solution
Heie is a Liiel summaiy ol what you must know aLout vaiiaLles in Llock oLjects:
Local vaiiaLles in Llock oLjects woik exactly the same as in OLjective-C methous.
Foi inline Llock oLjects, local vaiiaLles constitute not only vaiiaLles uelineu within
the Llock, Lut also the vaiiaLles that have Leen uelineu in the methou that imple-
ments that Llock oLject. (Examples will come shoitly.)
You cannot ielei to self in inuepenuent Llock oLjects implementeu in an OLjec-
tive-C class. Il you neeu to access self, you must pass that oLject to the Llock oLject
as a paiametei. Ve will see an example ol this soon.
You can ielei to self in an inline Llock oLject only il self is piesent in the lexical
scope insiue which the Llock oLject is cieateu.
Foi inline Llock oLjects, local vaiiaLles that aie uelineu insidc the Llock oLject`s
implementation can Le ieau liom anu wiitten to. In othei woius, the Llock oLject
has ieau-wiite access to vaiiaLles uelineu insiue the Llock oLject`s Louy.
Foi inline Llock oLjects, vaiiaLles local to the OLjective-C methou that implements
that Llock can only Le ieau liom, not wiitten to. Theie is an exception, though: a
Llock oLject can wiite to such vaiiaLles il they aie uelineu with the __block stoiage
type. Ve will see an example ol this as well.
Suppose you have an oLject ol type NSObject anu insiue that oLject`s implemen-
tation you aie using a Llock oLject in conjunction with GCD. Insiue this Llock
oLject, you will have ieau-wiite access to ueclaieu piopeities ol that NSObject insiue
which youi Llock is implementeu.
You can access ueclaieu piopeities ol youi NSObject insiue inuepenuent Llock oL-
jects on|y ij you use the settei anu gettei methous ol these piopeities. You cannot
access ueclaieu piopeities ol an oLject using uot notation insiue an inuepenuent
Llock oLject.
Discussion
Let`s liist see how we can use vaiiaLles that aie local to the implementation ol two
Llock oLjects. One is an inline Llock oLject anu the othei an inuepenuent Llock oLject:
6.2 Accessing Variables in Block Objects | 365
www.it-ebooks.info
void (^independentBlockObject)(void) = ^(void){
NSInteger localInteger = 10;
NSLog(@"local integer = %ld", (long)localInteger);
localInteger = 20;
NSLog(@"local integer = %ld", (long)localInteger);
};
Invoking this Llock oLject, the values we assigneu aie piinteu to the console winuow:
local integer = 10
local integer = 20
So lai, so goou. Now let`s have a look at inline Llock oLjects anu vaiiaLles that aie local
to them:
- (void) simpleMethod{
NSUInteger outsideVariable = 10;
NSMutableArray *array = [[NSMutableArray alloc]
initWithObjects:@"obj1",
@"obj2", nil];
[array sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSUInteger insideVariable = 20;
NSLog(@"Outside variable = %lu", (unsigned long)outsideVariable);
NSLog(@"Inside variable = %lu", (unsigned long)insideVariable);
/* Return value for the block object */
return NSOrderedSame;
}];
}
The sortUsingComparator: instance methou ol NSMutableArray attempts
to soit a mutaLle aiiay. The goal ol this example coue is just to uemon-
stiate the use ol local vaiiaLles, so you uon`t have to know what this
methou actually uoes.
The Llock oLject can ieau anu wiite its own insideVariable local vaiiaLle. Howevei,
the Llock oLject has ieau-only access to the outsideVariable vaiiaLle Ly uelault. In
oiuei to allow the Llock oLject to wiite to outsideVariable, we must pielix outside
Variable with the __block stoiage type:
- (void) simpleMethod{
366 | Chapter 6: Concurrency
www.it-ebooks.info
__block NSUInteger outsideVariable = 10;
NSMutableArray *array = [[NSMutableArray alloc]
initWithObjects:@"obj1",
@"obj2", nil];
[array sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSUInteger insideVariable = 20;
outsideVariable = 30;
NSLog(@"Outside variable = %lu", (unsigned long)outsideVariable);
NSLog(@"Inside variable = %lu", (unsigned long)insideVariable);
/* Return value for the block object */
return NSOrderedSame;
}];
}
Accessing self in inline Llock oLjects is line as long as self is uelineu in the lexical
scope insiue which the inline Llock oLject is cieateu. Foi instance, in this example, the
Llock oLject will Le aLle to access self, since simpleMethod is an instance methou ol an
OLjective-C class:
- (void) simpleMethod{
NSMutableArray *array = [[NSMutableArray alloc]
initWithObjects:@"obj1",
@"obj2", nil];
[array sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSLog(@"self = %@", self);
/* Return value for the block object */
return NSOrderedSame;
}];
}
You cannot, without a change in youi Llock oLject`s implementation, access self in
an inuepenuent Llock oLject. Attempting to compile this coue will give you a compile-
time eiioi:
void (^incorrectBlockObject)(void) = ^{
NSLog(@"self = %@", self); /* self is undefined here */
};
Il you want to access self in an inuepenuent Llock oLject, simply pass the oLject that
self iepiesents as a paiametei to youi Llock oLject:
6.2 Accessing Variables in Block Objects | 367
www.it-ebooks.info
void (^correctBlockObject)(id) = ^(id self){
NSLog(@"self = %@", self);
};
- (void) callCorrectBlockObject{
correctBlockObject(self);
}
You uon`t have to assign the name self to this paiametei. You can sim-
ply call this paiametei anything else. Howevei, il you call this paiametei
self, you can simply giaL youi Llock oLject`s coue latei anu place it in
an OLjective-C methou`s implementation without having to change
eveiy instance ol youi vaiiaLle`s name to self loi it to Le unueistoou Ly
the compilei.
Let`s have a look at ueclaieu piopeities anu how Llock oLjects can access them. Foi
inline Llock oLjects, you can use uot notation to ieau liom oi wiite to ueclaieu piop-
eities ol self. Foi instance, let`s say we have a ueclaieu piopeity ol type NSString calleu
stringProperty in the class:
#import <UIKit/UIKit.h>
@interface GCDAppDelegate : NSObject <UIApplicationDelegate>
@property (nonatomic, strong) NSString *stringProperty;
@end
Now we can simply access this piopeity in an inline Llock oLject like so:
#import "GCDAppDelegate.h"
@implementation GCDAppDelegate
- (void) simpleMethod{
NSMutableArray *array = [[NSMutableArray alloc]
initWithObjects:@"obj1",
@"obj2", nil];
[array sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSLog(@"self = %@", self);
self.stringProperty = @"Block Objects";
NSLog(@"String property = %@", self.stringProperty);
/* Return value for the block object */
368 | Chapter 6: Concurrency
www.it-ebooks.info
return NSOrderedSame;
}];
}
@end
In an inuepenuent Llock oLject, howevei, you cannot use uot notation to ieau liom oi
wiite to a ueclaieu piopeity:
void (^correctBlockObject)(id) = ^(id self){
NSLog(@"self = %@", self);
/* Should use setter method instead of this */
self.stringProperty = @"Block Objects"; /* Compile-time Error */
/* Should use getter method instead of this */
NSLog(@"self.stringProperty = %@",
self.stringProperty); /* Compile-time Error */
};
Insteau ol uot notation in this scenaiio, use the gettei anu the settei methous ol this
piopeity:
void (^correctBlockObject)(id) = ^(id self){
NSLog(@"self = %@", self);
/* This will work fine */
[self setStringProperty:@"Block Objects"];
/* This will work fine as well */
NSLog(@"self.stringProperty = %@",
[self stringProperty]);
};
Vhen it comes to inline Llock oLjects, theie is one vcry impoitant iule that you have
to iememLei: inline Llock oLjects copy the value loi the vaiiaLles in theii lexical scope.
Il you uon`t unueistanu what that means, uon`t woiiy. Let`s have a look at an example:
typedef void (^BlockWithNoParams)(void);
- (void) scopeTest{
NSUInteger integerValue = 10;
/*************** Definition of internal block object ***************/
BlockWithNoParams myBlock = ^{
NSLog(@"Integer value inside the block = %lu",
(unsigned long)integerValue);
};
/*************** End definition of internal block object ***************/
6.2 Accessing Variables in Block Objects | 369
www.it-ebooks.info
integerValue = 20;
/* Call the block here after changing the
value of the integerValue variable */
myBlock();
NSLog(@"Integer value outside the block = %lu",
(unsigned long)integerValue);
}
Ve aie ueclaiing an integei local vaiiaLle anu initially assigning the value ol 10 to it.
Ve then implement the Llock oLject, Lut don`t ca|| thc b|oc| objcct yct. Altei the Llock
oLject is inp|cncntcd, we simply change the value ol the local vaiiaLle that the Llock
oLject will latei tiy to ieau when we call it. Right altei changing the local vaiiaLle`s
value to 20, we call the Llock oLject. You woulu expect the Llock oLject to piint the
value 20 loi the vaiiaLle, Lut it won`t. It will piint 10, as you can see heie:
Integer value inside the block = 10
Integer value outside the block = 20
Vhat`s happening heie is that the Llock oLject is keeping a ieau-only copy ol the
integerValue vaiiaLle loi itsell iight wheie the Llock is implementeu. You might Le
thinking: why is the Llock oLject captuiing a rcad-on|y value ol the local vaiiaLle
integerValue? The answei is simple, anu we`ve alieauy leaineu it in this section. Unless
pielixeu with stoiage type __block, local vaiiaLles in the lexical scope ol a Llock oLject
aie just passeu to the Llock oLject as ieau-only vaiiaLles. Theieloie, to change this
Lehavioi, we coulu change the implementation ol the scopeTest methou to pielix the
integerValue vaiiaLle with __block stoiage type, like so:
- (void) scopeTest{
__block NSUInteger integerValue = 10;
/*************** Definition of internal block object ***************/
BlockWithNoParams myBlock = ^{
NSLog(@"Integer value inside the block = %lu",
(unsigned long)integerValue);
};
/*************** End definition of internal block object ***************/
integerValue = 20;
/* Call the block here after changing the
value of the integerValue variable */
myBlock();
NSLog(@"Integer value outside the block = %lu",
(unsigned long)integerValue);
}
370 | Chapter 6: Concurrency
www.it-ebooks.info
Now il we get the iesults liom the console winuow altei the scopeTest methou is calleu,
we will see this:
Integer value inside the block = 20
Integer value outside the block = 20
This section shoulu have given you sullicient inloimation aLout using vaiiaLles with
Llock oLjects. I suggest that you wiite a lew Llock oLjects anu use vaiiaLles insiue them,
assigning to them anu ieauing liom them, to get a Lettei unueistanuing ol how Llock
oLjects use vaiiaLles. Keep coming Lack to this section il you loiget the iules that govein
vaiiaLle access in Llock oLjects.
6.3 Invoking Block Objects
Problem
You`ve leaineu how to constiuct Llock oLjects, anu now you want to execute youi
Llock oLjects to get iesults.
Solution
Execute youi Llock oLjects the same way you execute a C lunction, as shown in the
Discussion section.
Discussion
Ve`ve seen examples ol invoking Llock oLjects in Recipes 6.1 anu 6.2. This section
contains moie conciete examples.
Il you have an inuepenuent Llock oLject, you can simply invoke it just like you woulu
invoke a C lunction:
void (^simpleBlock)(NSString *) = ^(NSString *paramString){
/* Implement the block object here and use the
paramString parameter */
};
- (void) callSimpleBlock{
simpleBlock(@"O'Reilly");
}
Il you want to invoke an inuepenuent Llock oLject within anothei inuepenuent Llock
oLject, lollow the same instiuctions Ly invoking the new Llock oLject just as you woulu
invoke a C methou:
/*************** Definition of first block object ***************/
NSString *(^trimString)(NSString *) = ^(NSString *inputString){
NSString *result = [inputString stringByTrimmingCharactersInSet:
6.3 Invoking Block Objects | 371
www.it-ebooks.info
[NSCharacterSet whitespaceCharacterSet]];
return result;
};
/*************** End definition of first block object ***************/
/*************** Definition of second block object ***************/
NSString *(^trimWithOtherBlock)(NSString *) = ^(NSString *inputString){
return trimString(inputString);
};
/*************** End definition of second block object ***************/
- (void) callTrimBlock{
NSString *trimmedString = trimWithOtherBlock(@" O'Reilly ");
NSLog(@"Trimmed string = %@", trimmedString);
}
In this example, go aheau anu invoke the callTrimBlock OLjective-C methou:
[self callTrimBlock];
The callTrimBlock methou will call the trimWithOtherBlock Llock oLject, anu the trim
WithOtherBlock Llock oLject will call the trimString Llock oLject in oiuei to tiim the
given stiing. Tiimming a stiing is easy anu can Le uone in one line ol coue, Lut this
example coue shows how you can call Llock oLjects within Llock oLjects.
See Also
Recipe 6.1; Recipe 6.2
6.4 Dispatching Tasks to Grand Central Dispatch
Problem
You want to leain how to cieate a Llock ol coue that can Le executeu Ly GCD.
Solution
Theie aie two ways to suLmit tasks to uispatch gueues:
Block OLjects (see Recipe 6.1)
C lunctions
Discussion
Block oLjects aie the Lest way ol utilizing GCD anu its enoimous powei. Some GCD
lunctions have Leen extenueu to allow piogiammeis to use C lunctions insteau ol Llock
oLjects. Howevei, the tiuth is that only a limiteu set ol GCD lunctions allow piogiam-
372 | Chapter 6: Concurrency
www.it-ebooks.info
meis to use C lunctions, so please uo ieau the iecipe aLout Llock oLjects (Recipe 6.1)
Leloie pioceeuing any luithei.
C lunctions that have to Le supplieu to vaiious GCD lunctions shoulu Le ol type
dispatch_function_t, which is uelineu as lollows in the Apple liLiaiies:
typedef void (*dispatch_function_t)(void *);
So il we want to cieate a lunction nameu, loi instance, myGCDFunction, we woulu have
to implement it in this way:
void myGCDFunction(void * paraContext){
/* Do the work here */
}
The paraContext paiametei ieleis to the context that GCD allows pio-
giammeis to pass to theii C lunctions when they uispatch tasks to them.
Ve will leain aLout this shoitly.
Block oLjects that get passeu to GCD lunctions uon`t always lollow the same stiuctuie.
Some must accept paiameteis anu some shoulun`t, Lut none ol the Llock oLjects suL-
mitteu to GCD ietuin a value.
In the next thiee sections, you will leain how to suLmit tasks to GCD loi execution
whethei they aie in the loim ol Llock oLjects oi C lunctions.
See Also
Recipe 6.1
6.5 Performing UI-Related Tasks with GCD
Problem
You aie using GCD loi concuiiency anu you woulu like to know what the Lest way ol
woiking with UI-ielateu APIs is.
Solution
Use the dispatch_get_main_queue lunction.
Discussion
UI-ielateu tasks have to Le peiloimeu on the main thieau, so the main gueue is the
only canuiuate loi UI task execution in GCD. Ve can use the dispatch_
get_main_queue lunction to get the hanule to the main uispatch gueue.
6.5 Performing UI-Related Tasks with GCD | 373
www.it-ebooks.info
Theie aie two ways ol uispatching tasks to the main gueue. Both aie asynchionous,
letting youi piogiam continue even when the task is not yet executeu:
dispatch_async junction
Executes a Llock oLject on a uispatch gueue.
dispatch_async_f junction
Executes a C lunction on a uispatch gueue.
The dispatch_sync methou cannot Le calleu on the main gueue Lecause
it will Llock the thieau inuelinitely anu cause youi application to ueau-
lock. All tasks suLmitteu to the main gueue thiough GCD must Le suL-
mitteu asynchionously.
Let`s have a look at using the dispatch_async lunction. It accepts two paiameteis:
Dispatch qucuc hand|c
The uispatch gueue on which the task has to Le executeu.
B|oc| objcct
The Llock oLject to Le sent to the uispatch gueue loi asynchionous execution.
Heie is an example. This coue will uisplay an aleit in iOS to the usei, using the main
gueue:
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_async(mainQueue, ^(void) {

[[[UIAlertView alloc] initWithTitle:@"GCD"
message:@"GCD is amazing!"
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil, nil] show];

});
As you`ve noticeu, the dispatch_async GCD lunction has no paiameteis
oi ietuin value. The Llock oLject that is suLmitteu to this lunction must
gathei its own uata in oiuei to complete its task. In the coue snippet
that we just saw, the aleit view has all the values that it neeus to linish
its task. Howevei, this might not always Le the case. In such instances,
you must make suie the Llock oLject suLmitteu to GCD has access in
its scope to all the values that it ieguiies.
Running this app in iOS Simulatoi, the usei will get iesults similai to those shown in
Figuie 6-1.
374 | Chapter 6: Concurrency
www.it-ebooks.info
This might not seem veiy impiessive, il you think aLout it. So what makes the main
gueue tiuly inteiesting? The answei is simple: when you aie getting the maximum
peiloimance liom GCD to uo some heavy calculation on concuiient oi seiial thieaus,
you might want to uisplay the iesults to youi usei oi move a component on the scieen.
Foi that, you nust use the main gueue, Lecause it is UI-ielateu woik. The lunctions
shown in this section aie the on|y ways to get out ol a seiial oi a concuiient gueue while
still utilizing GCD to upuate youi UI, so you can imagine how impoitant they aie.
Insteau ol suLmitting a Llock oLject loi execution on the main gueue, you can suLmit
a C lunction oLject. SuLmit all UI-ielateu C lunctions loi execution in GCD to the
dispatch_async_f lunction. Ve can get the same iesults as we got in Figuie 6-1, using
C lunctions insteau ol Llock oLjects, with a lew aujustments to the coue.
As mentioneu Leloie, with the dispatch_async_f lunction, we can suLmit a pointei to
an application-uelineu context, which can then Le useu Ly the C lunction that gets
calleu. So, let`s cieate a stiuctuie that holus values such as an aleit view`s title, message,
anu cancel-Lutton`s title. Vhen the app staits, we will put all the values in this stiuctuie
anu pass it to the C lunction to uisplay. Heie is how we ueline the stiuctuie:
typedef struct{
char *title;
char *message;
char *cancelButtonTitle;
} AlertViewData;
Now let`s go anu implement a C lunction that we will latei call with GCD. This C
lunction shoulu expect a paiametei ol type void *, which we will then typecast to
AlertViewData *. In othei woius, we expect the callei ol this lunction to pass us a
ieleience to the uata loi the aleit view, encapsulateu insiue the AlertViewData stiuctuie:
Iigurc -1. An a|crt disp|aycd using asynchronous GCD ca||s
6.5 Performing UI-Related Tasks with GCD | 375
www.it-ebooks.info
void displayAlertView(void *paramContext){

AlertViewData *alertData = (AlertViewData *)paramContext;

NSString *title =
[NSString stringWithUTF8String:alertData->title];

NSString *message =
[NSString stringWithUTF8String:alertData->message];

NSString *cancelButtonTitle =
[NSString stringWithUTF8String:alertData->cancelButtonTitle];

[[[UIAlertView alloc] initWithTitle:title
message:message
delegate:nil
cancelButtonTitle:cancelButtonTitle
otherButtonTitles:nil, nil] show];

free(alertData);

}
The ieason we aie freeing the context passeu to us in heie insteau ol in
the callei is that the callei is going to execute this C lunction asynchio-
nously anu cannot know when the C lunction will linish executing.
Theieloie, the callei has to malloc enough space loi the AlertViewData
context anu the displayAlertView C lunction has to liee that space.
Anu now let`s call the displayAlertView lunction on the main gueue anu pass the con-
text (the stiuctuie that holus the aleit view`s uata) to it:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

dispatch_queue_t mainQueue = dispatch_get_main_queue();

AlertViewData *context = (AlertViewData *)
malloc(sizeof(AlertViewData));

if (context != NULL){
context->title = "GCD";
context->message = "GCD is amazing.";
context->cancelButtonTitle = "OK";

dispatch_async_f(mainQueue,
(void *)context,
displayAlertView);
}

self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];

376 | Chapter 6: Concurrency
www.it-ebooks.info
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Il you invoke the currentThread class methou ol the NSThread class, you will linu out
that the Llock oLjects oi the C lunctions you uispatch to the main gueue aie inueeu
iunning on the main thieau:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

dispatch_queue_t mainQueue = dispatch_get_main_queue();

dispatch_async(mainQueue, ^(void) {
NSLog(@"Current thread = %@", [NSThread currentThread]);
NSLog(@"Main thread = %@", [NSThread mainThread]);
});

self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
The output ol this coue woulu Le similai to that shown heie:
Current thread = <NSThread: 0x4b0e4e0>{name = (null), num = 1}
Main thread = <NSThread: 0x4b0e4e0>{name = (null), num = 1}
Now that you know how to peiloim UI-ielateu tasks using GCD, it is time we moveu
to othei suLjects, such as peiloiming tasks in paiallel using concuiient gueues (see
Recipes 6.6 anu Recipe 6.7) anu mixing the coue with UI-ielateu coue il neeu Le.
6.6 Executing Non-UI Related Tasks Synchronously with GCD
Problem
You want to peiloim synchionous tasks that uo not involve any UI-ielateu coue.
Solution
Use the dispatch_sync lunction.
Discussion
Theie aie times when you want to peiloim tasks that have nothing to uo with the UI
oi inteiact with the UI as well as uoing othei tasks that take up a lot ol time. Foi instance,
you might want to uownloau an image anu uisplay it to the usei altei it is uownloaueu.
The uownloauing piocess has aLsolutely nothing to uo with the UI.
6.6 Executing Non-UI Related Tasks Synchronously with GCD | 377
www.it-ebooks.info
Foi any task that uoesn`t involve the UI, you can use gloLal concuiient gueues in GCD.
These allow eithei synchionous oi asynchionous execution. But synchionous execu-
tion uoes not mean youi piogiam waits loi the coue to linish Leloie continuing. It
simply means that the concuiient gueue will wait until youi task has linisheu Leloie it
continues to the next Llock ol coue on the gueue. Vhen you put a Llock oLject on a
concuiient gueue, youi own piogiam a|ways continues iight away without waiting loi
the gueue to execute the coue. This is Lecause concuiient gueues, as theii name implies,
iun theii coue on thieaus othei than the main thieau. (Theie is one exception to this:
when a task is suLmitteu to a concuiient oi a seiial gueue using the dispatch_sync
lunction, iOS will, il possiLle, iun the task on the currcnt thieau, which night Le the
main thieau, uepenuing on wheie the coue path is at the moment. This is an optimi-
zation that has Leen piogiammeu on GCD, as we shall soon see.)
Il you suLmit a task to a concuiient gueue synchionously, anu at the same time suLmit
anothei synchionous task to anothcr concuiient gueue, these two synchionous tasks
will iun asynchionously in ielation to each othei Lecause they aie iunning two dijjcrcnt
concurrcnt qucucs. It`s impoitant to unueistanu this Lecause sometimes, as we`ll see,
you want to make suie task A linishes Leloie task B staits. To ensuie that, suLmit them
synchionously to the sanc gueue.
You can peiloim synchionous tasks on a uispatch gueue using the dispatch_sync lunc-
tion. All you have to uo is to pioviue it with the hanule ol the gueue that has to iun the
task anu a Llock ol coue to execute on that gueue.
Let`s look at an example. It piints the integeis 1 to 1000 twice, one complete seguence
altei the othei, without Llocking the main thieau. Ve can cieate a Llock oLject that
uoes the counting loi us anu synchionously call the same Llock oLject twice:
void (^printFrom1To1000)(void) = ^{
NSUInteger counter = 0;
for (counter = 1;
counter <= 1000;
counter++){
NSLog(@"Counter = %lu - Thread = %@",
(unsigned long)counter,
[NSThread currentThread]);
}
};
Now let`s go anu invoke this Llock oLject using GCD:
dispatch_queue_t concurrentQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_sync(concurrentQueue, printFrom1To1000);
dispatch_sync(concurrentQueue, printFrom1To1000);
378 | Chapter 6: Concurrency
www.it-ebooks.info
Il you iun this coue, you might notice the counting taking place on the main thieau,
even though you`ve askeu a concuiient gueue to execute the task. It tuins out this is
an optimization Ly GCD. The dispatch_sync lunction will use the cuiient thieauthe
thieau you`ie using when you uispatch the taskwhenevei possiLle, as a pait ol an
optimization that has Leen piogiammeu into GCD. Heie is what Apple says aLout it:
As an optimization, this lunction invokes the Llock on the cuiient thieau when possiLle.
Gianu Cential Dispatch (GCD) Releience
To execute a C lunction insteau ol a Llock oLject, synchionously, on a uispatch gueue,
use the dispatch_sync_f lunction. Let`s simply tianslate the coue we`ve wiitten loi the
printFrom1To1000 Llock oLject to its eguivalent C lunction, like so:
void printFrom1To1000(void *paramContext){
NSUInteger counter = 0;
for (counter = 1;
counter <= 1000;
counter++){
NSLog(@"Counter = %lu - Thread = %@",
(unsigned long)counter,
[NSThread currentThread]);
}
}
Anu now we can use the dispatch_sync_f lunction to execute the printFrom1To1000
lunction on a concuiient gueue, as uemonstiateu heie:
dispatch_queue_t concurrentQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_sync_f(concurrentQueue,
NULL,
printFrom1To1000);
dispatch_sync_f(concurrentQueue,
NULL,
printFrom1To1000);
The liist paiametei ol the dispatch_get_global_queue lunction specilies the piioiity ol
the concuiient gueue that GCD has to ietiieve loi the piogiammei. The highei the
piioiity, the moie CPU timeslices will Le pioviueu to the coue getting executeu on that
gueue. You can use any ol these values loi the liist paiametei to the dispatch_
get_global_queue lunction:
DISPATCH_QUEUE_PRIORITY_LOW
Fewei timeslices will Le applieu to youi task than noimal tasks.
DISPATCH_QUEUE_PRIORITY_DEFAULT
The uelault system piioiity loi coue execution will Le applieu to youi task.
6.6 Executing Non-UI Related Tasks Synchronously with GCD | 379
www.it-ebooks.info
DISPATCH_QUEUE_PRIORITY_HIGH
Moie timeslices will Le applieu to youi task than noimal tasks.
The seconu paiametei ol the dispatch_get_global_queue lunction is
ieseiveu anu you shoulu always pass the value 0 to it.
In this section you saw how you can uispatch tasks to concuiient gueues loi synchio-
nous execution. The next section shows asynchionous execution on concuiient
gueues, while Recipe 6.11 will show you how to execute tasks synchionously anu
asynchionously on seiial gueues that you cieate loi youi applications.
See Also
Recipe 6.7; Recipe 6.11
6.7 Executing Non-UI Related Tasks Asynchronously with GCD
Problem
You want to Le aLle to execute non-UI ielateu tasks asynchionously, with the help ol
GCD.
Solution
This is wheie GCD can show its tiue powei: executing Llocks ol coue asynchionously
on the main, seiial, oi concuiient gueues. I piomise that, Ly the enu ol this section,
you will Le completely convinceu GCD is the lutuie ol multithieau applications, com-
pletely ieplacing thieaus in mouein apps.
In oiuei to execute asynchionous tasks on a uispatch gueue, you must use one ol these
lunctions:
dispatch_async
SuLmits a Llock oLject to a uispatch gueue (Loth specilieu Ly paiameteis) loi
asynchionous execution.
dispatch_async_f
SuLmits a C lunction to a uispatch gueue, along with a context ieleience (all thiee
specilieu Ly paiameteis), loi asynchionous execution.
Discussion
Let`s have a look at a ieal example. Ve`ll wiite an iOS app that is aLle to uownloau an
image liom a URL on the Inteinet. Altei the uownloau is linisheu, the app shoulu
380 | Chapter 6: Concurrency
www.it-ebooks.info
uisplay the image to the usei. Heie is the plan anu how we will use what we`ve leaineu
so lai aLout GCD in oiuei to accomplish it:
1. Ve aie going to launch a Llock oLject asynchionously on a concuiient gueue.
2. Once in this Llock, we will launch anothei Llock oLject synchronous|y, using the
dispatch_sync lunction, to uownloau the image liom a URL. Ve uo this Lecause
we want the iest ol the coue in this concuiient gueue to wait until the image is
uownloaueu. Theieloie, we aie only making the concuiient gueue wait; not the
iest ol the gueues. Synchionously uownloauing a URL liom an asynchionous coue
Llock holus up just the gueue iunning the synchionous lunction, not the main
thieau. The whole opeiation is still asynchionous when we look at it liom the main
thieau`s peispective. All we caie aLout is that we aie not Llocking the main thieau
while uownloauing the image.
3. Right altei the image is uownloaueu, we will synchionously execute a Llock oLject
on the nain qucuc (see Recipe 6.5) in oiuei to uisplay the image to the usei on the
UI.
The skeleton loi the plan is as simple as this:
dispatch_queue_t concurrentQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{
__block UIImage *image = nil;
dispatch_sync(concurrentQueue, ^{
/* Download the image here */
});
dispatch_sync(dispatch_get_main_queue(), ^{
/* Show the image to the user here on the main queue*/
});
});
The seconu dispatch_sync call, which uisplays the image, will Le executeu on the gueue
altei the liist synchionous call, which uownloaus the image. That`s exactly what we
want, Lecause we havc to wait loi the image to Le lully uownloaueu Leloie we can
uisplay it to the usei. So altei the image is uownloaueu, we execute the seconu Llock
oLject, Lut this time on the main gueue.
Let`s uownloau the image anu uisplay it to the usei now. Ve will uo this in the view
DidAppear: instance methou ol a view contiollei uisplayeu in an iPhone app:
- (void) viewDidAppear:(BOOL)paramAnimated{

dispatch_queue_t concurrentQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_async(concurrentQueue, ^{
6.7 Executing Non-UI Related Tasks Asynchronously with GCD | 381
www.it-ebooks.info

__block UIImage *image = nil;

dispatch_sync(concurrentQueue, ^{
/* Download the image here */

/* iPad's image from Apple's website. Wrap it into two
lines as the URL is too long to fit into one line */
NSString *urlAsString = @"http://images.apple.com/mobileme/features"\
"/images/ipad_findyouripad_20100518.jpg";

NSURL *url = [NSURL URLWithString:urlAsString];

NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];

NSError *downloadError = nil;
NSData *imageData = [NSURLConnection
sendSynchronousRequest:urlRequest
returningResponse:nil
error:&downloadError];

if (downloadError == nil &&
imageData != nil){

image = [UIImage imageWithData:imageData];
/* We have the image. We can use it now */

}
else if (downloadError != nil){
NSLog(@"Error happened = %@", downloadError);
} else {
NSLog(@"No data could get downloaded from the URL.");
}

});

dispatch_sync(dispatch_get_main_queue(), ^{
/* Show the image to the user here on the main queue*/

if (image != nil){
/* Create the image view here */
UIImageView *imageView = [[UIImageView alloc]
initWithFrame:self.view.bounds];

/* Set the image */
[imageView setImage:image];

/* Make sure the image is not scaled incorrectly */
[imageView setContentMode:UIViewContentModeScaleAspectFit];

/* Add the image to this view controller's view */
[self.view addSubview:imageView];

} else {
NSLog(@"Image isn't downloaded. Nothing to display.");
382 | Chapter 6: Concurrency
www.it-ebooks.info
}

});

});

}
As you can see in Figuie 6-2, we have successlully uownloaueu the image anu also
cieateu an image view to uisplay the image to the usei on the UI.
Iigurc -2. Down|oading and disp|aying inagcs to uscrs, using GCD
Let`s move on to anothei example. Let`s say that we have an aiiay ol 10,000 ianuom
numLeis that have Leen stoieu in a lile on uisk anu we want to loau this aiiay into
memoiy, soit the numLeis in an ascenuing lashion (with the smallest numLei appeaiing
liist in the list), anu then uisplay the list to the usei. The contiol useu loi the uisplay
uepenus on whethei you aie couing this loi iOS (iueally, you`u use an instance ol
UITableView) oi Mac OS X (NSTableView woulu Le a goou canuiuate). Since we uon`t
have an aiiay, why uon`t we cieate the aiiay liist, then loau it, anu linally uisplay it?
Heie aie two methous that will help us linu the location wheie we want to save the
aiiay ol 10,000 ianuom numLeis on uisk on the uevice:
- (NSString *) fileLocation{

/* Get the document folder(s) */
NSArray *folders =
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES);

6.7 Executing Non-UI Related Tasks Asynchronously with GCD | 383
www.it-ebooks.info
/* Did we find anything? */
if ([folders count] == 0){
return nil;
}

/* Get the first folder */
NSString *documentsFolder = [folders objectAtIndex:0];

/* Append the file name to the end of the documents path */
return [documentsFolder
stringByAppendingPathComponent:@"list.txt"];

}
- (BOOL) hasFileAlreadyBeenCreated{

BOOL result = NO;

NSFileManager *fileManager = [[NSFileManager alloc] init];
if ([fileManager fileExistsAtPath:[self fileLocation]]){
result = YES;
}

return result;
}
Now the impoitant pait: we want to save an aiiay ol 10,000 ianuom numLeis to uisk
ij and on|y ij we have not cieateu this aiiay Leloie on uisk. Il we have, we will loau the
aiiay liom uisk immeuiately. Il we have not cieateu this aiiay Leloie on uisk, we will
liist cieate it anu then move on to loauing it liom uisk. At the enu, il the aiiay was
successlully ieau liom uisk, we will soit the aiiay in an ascenuing lashion anu linally
uisplay the iesults to the usei on the UI. I will leave uisplaying the iesults to the usei
up to you:
dispatch_queue_t concurrentQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
/* If we have not already saved an array of 10,000
random numbers to the disk before, generate these numbers now
and then save them to the disk in an array */
dispatch_async(concurrentQueue, ^{

NSUInteger numberOfValuesRequired = 10000;

if ([self hasFileAlreadyBeenCreated] == NO){
dispatch_sync(concurrentQueue, ^{

NSMutableArray *arrayOfRandomNumbers =
[[NSMutableArray alloc] initWithCapacity:numberOfValuesRequired];

NSUInteger counter = 0;
for (counter = 0;
counter < numberOfValuesRequired;
counter++){
384 | Chapter 6: Concurrency
www.it-ebooks.info
unsigned int randomNumber =
arc4random() % ((unsigned int)RAND_MAX + 1);

[arrayOfRandomNumbers addObject:
[NSNumber numberWithUnsignedInt:randomNumber]];
}

/* Now let's write the array to disk */
[arrayOfRandomNumbers writeToFile:[self fileLocation]
atomically:YES];

});
}

__block NSMutableArray *randomNumbers = nil;

/* Read the numbers from disk and sort them in an
ascending fashion */
dispatch_sync(concurrentQueue, ^{

/* If the file has now been created, we have to read it */
if ([self hasFileAlreadyBeenCreated]){
randomNumbers = [[NSMutableArray alloc]
initWithContentsOfFile:[self fileLocation]];

/* Now sort the numbers */
[randomNumbers sortUsingComparator:
^NSComparisonResult(id obj1, id obj2) {

NSNumber *number1 = (NSNumber *)obj1;
NSNumber *number2 = (NSNumber *)obj2;
return [number1 compare:number2];

}];
}
});


dispatch_async(dispatch_get_main_queue(), ^{
if ([randomNumbers count] > 0){
/* Refresh the UI here using the numbers in the
randomNumbers array */
}
});

});
Theie is a lot moie to GCD than synchionous anu asynchionous Llock oi lunction
execution. In Recipe 6.10, you will leain how to gioup Llock oLjects togethei anu
piepaie them loi execution on a uispatch gueue. I also suggest that you have a look at
Recipes 6.S anu 6.9 to leain aLout othei lunctionalities that GCD can pioviue to pio-
giammeis.
6.7 Executing Non-UI Related Tasks Asynchronously with GCD | 385
www.it-ebooks.info
See Also
Recipe 6.5; Recipe 6.S; Recipe 6.9
6.8 Performing Tasks After a Delay with GCD
Problem
You want to Le aLle to execute coue, Lut altei a ceitain amount ol uelay, which you
woulu like to specily using GCD.
Solution
Use the dispatch_after anu dispatch_after_f lunctions.
Discussion
Vith Coie Founuation, you can invoke a selectoi in an oLject altei a given peiiou ol
time, using the performSelector:withObject:afterDelay: methou ol the NSObject class.
Heie is an example:
- (void) printString:(NSString *)paramString{
NSLog(@"%@", paramString);
}
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

[self performSelector:@selector(printString:)
withObject:@"Grand Central Dispatch"
afterDelay:3.0];
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];

// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
In this example, we aie asking the iuntime to call the printString: methou altei thiee
seconus ol uelay. Ve can uo the same thing in GCD using the dispatch_after anu
dispatch_after_f lunctions, each ol which is uesciiLeu heie:
dispatch_after
Dispatches a Llock oLject to a uispatch gueue altei a given peiiou ol time, specilieu
in nanoseconus. These aie the paiameteis that this lunction ieguiies:
386 | Chapter 6: Concurrency
www.it-ebooks.info
Dc|ay in nanoscconds
The numLei ol nanoseconus GCD has to wait on a given uispatch gueue
(specilieu Ly the seconu paiametei) Leloie it executes the given Llock oLject
(specilieu Ly the thiiu paiametei).
Dispatch qucuc
The uispatch gueue on which the Llock oLject (specilieu Ly the thiiu paiam-
etei) has to Le executeu altei the given uelay (specilieu Ly the liist paiametei).
B|oc| objcct
The Llock oLject to Le invokeu altei the specilieu numLei ol nanoseconus on
the given uispatch gueue. This Llock oLject shoulu have no ietuin value anu
shoulu accept no paiameteis (see Recipe 6.1).
dispatch_after_f
Dispatches a C lunction to GCD loi execution altei a given peiiou ol time, specilieu
in nanoseconus. This lunction accepts loui paiameteis:
Dc|ay in nanoscconds
The numLei ol nanoseconus GCD has to wait on a given uispatch gueue
(specilieu Ly the seconu paiametei) Leloie it executes the given lunction
(specilieu Ly the louith paiametei).
Dispatch qucuc
The uispatch gueue on which the C lunction (specilieu Ly the louith paiam-
etei) has to Le executeu altei the given uelay (specilieu Ly the liist paiametei).
Contcxt
The memoiy auuiess ol a value in the heap to Le passeu to the C lunction (loi
an example, see Recipe 6.5).
C junction
The auuiess ol the C lunction that has to Le executeu altei a ceitain peiiou ol
time (specilieu Ly the liist paiametei) on the given uispatch gueue (specilieu
Ly the seconu paiametei).
Although the uelays aie in nanoseconus, it is up to iOS to ueciue the
gianulaiity ol uispatch uelay, anu this uelay might not Le as piecise as
what you hope when you specily a value in nanoseconus.
Let`s have a look at an example loi dispatch_after liist:
double delayInSeconds = 2.0;
dispatch_time_t delayInNanoSeconds =
dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_queue_t concurrentQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
6.8 Performing Tasks After a Delay with GCD | 387
www.it-ebooks.info
dispatch_after(delayInNanoSeconds, concurrentQueue, ^(void){
/* Perform your operations here */
});
As you can see, the nanoseconus uelay paiametei loi Loth the dispatch_after anu
dispatch_after_f lunctions has to Le ol type dispatch_time_t, which is an aLstiact
iepiesentation ol aLsolute time. To get the value loi this paiametei, you can use the
dispatch_time lunction as uemonstiateu in this sample coue. Heie aie the paiameteis
that you can pass to the dispatch_time lunction:
Basc tinc
Il this value was uenoteu with B anu the uelta paiametei was uenoteu with D, the
iesulting time liom this lunction woulu Le egual to B - D. You can set this pa-
iametei`s value to DISPATCH_TIME_NOW to uenote now as the Lase time anu then
specily the uelta liom now using the uelta paiametei.
Dc|ta to add to basc tinc
This paiametei is the nanoseconus that will get auueu to the Lase time paiametei
to cieate the iesult ol this lunction.
Foi example, to uenote a time 3 seconus liom now, you coulu wiite youi coue like so:
dispatch_time_t delay =
dispatch_time(DISPATCH_TIME_NOW, 3.0f * NSEC_PER_SEC);
Oi to uenote hall a seconu liom now:
dispatch_time_t delay =
dispatch_time(DISPATCH_TIME_NOW, (1.0 / 2.0f) * NSEC_PER_SEC);
Now let`s have a look at how we can use the dispatch_after_f lunction:
void processSomething(void *paramContext){
/* Do your processing here */
NSLog(@"Processing...");
}
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
double delayInSeconds = 2.0;

dispatch_time_t delayInNanoSeconds =
dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);

dispatch_queue_t concurrentQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_after_f(delayInNanoSeconds,
concurrentQueue,
NULL,
processSomething);
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
388 | Chapter 6: Concurrency
www.it-ebooks.info

// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
See Also
Recipe 6.1; Recipe 6.5
6.9 Performing a Task Only Once with GCD
Problem
You want to make suie a piece ol coue gets executeu only once uuiing the liletime ol
youi application, even il it gets calleu moie than once liom uilleient places in youi coue
(such as the initializei loi a singleton).
Solution
Use the dispatch_once lunction.
Discussion
Allocating anu initializing a singleton is one ol the tasks that has to happen exactly once
uuiing the liletime ol an app. I am suie you know ol othei scenaiios wheie you hau to
make suie a piece ol coue was executeu only once uuiing the liletime ol youi applica-
tion.
GCD lets you specily an iuentiliei loi a piece ol coue when you attempt to execute it.
Il GCD uetects that this iuentiliei has Leen passeu to the liamewoik Leloie, it won`t
execute that Llock ol coue again. The lunction that allows you to uo this is dis
patch_once, which accepts two paiameteis:
To|cn
A token ol type dispatch_once_t that holus the token geneiateu Ly GCD when the
Llock ol coue is executeu loi the liist time. Il you want a piece ol coue to Le executeu
at most once, you must specily the same token to this methou whenevei it is in-
vokeu in the app. Ve will see an example ol this soon.
B|oc| objcct
The Llock oLject to get executeu at most once. This Llock oLject ietuins no values
anu accepts no paiameteis.
6.9 Performing a Task Only Once with GCD | 389
www.it-ebooks.info
dispatch_once always executes its task on the cuiient gueue Leing useu
Ly the coue that issues the call, Le it a seiial gueue, a concuiient gueue,
oi the main gueue.
Heie is an example:
static dispatch_once_t onceToken;
void (^executedOnlyOnce)(void) = ^{

static NSUInteger numberOfEntries = 0;
numberOfEntries++;
NSLog(@"Executed %lu time(s)", (unsigned long)numberOfEntries);

};
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

dispatch_queue_t concurrentQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_once(&onceToken, ^{
dispatch_async(concurrentQueue,
executedOnlyOnce);
});

dispatch_once(&onceToken, ^{
dispatch_async(concurrentQueue,
executedOnlyOnce);
});

self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];

self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;

}
As you can see, although we aie attempting to invoke the executedOnlyOnce Llock oLject
twice, using the dispatch_once lunction, in ieality GCD is only executing this Llock
oLject once, since the iuentiliei passeu to the dispatch_once lunction is the same Loth
times.
Apple, in its Cocoa Funuamentals Guiue, shows piogiammeis how to cieate a single-
ton. This souice coue is guite olu anu has not yct bccn updatcd to use GCD anu Auto-
matic Releience Counting. Ve can change this mouel to make use ol GCD anu the
dispatch_once lunction in oiuei to initialize a shaieu instance ol an oLject, like so:
390 | Chapter 6: Concurrency
www.it-ebooks.info
#import "MySingleton.h"
@implementation MySingleton
- (id) sharedInstance{
static MySingleton *SharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SharedInstance = [MySingleton new];
});
return SharedInstance;
}
@end
6.10 Grouping Tasks Together with GCD
Problem
You want to gioup Llocks ol coue togethei anu ensuie that all ol them get executeu Ly
GCD one Ly one, as uepenuencies ol one anothei.
Solution
Use the dispatch_group_create lunction to cieate gioups in GCD.
Discussion
GCD lets us cieate groups, which allow you to place youi tasks in one place, iun all ol
them, anu get a notilication at the enu liom GCD. This has many valuaLle applications.
Foi instance, suppose you have a UI-Laseu app anu want to ieloau the components on
youi UI. You have a taLle view, a scioll view, anu an image view. You want to ieloau
the contents ol these components using these methous:
- (void) reloadTableView{
/* Reload the table view here */
NSLog(@"%s", __FUNCTION__);
}
- (void) reloadScrollView{
/* Do the work here */
NSLog(@"%s", __FUNCTION__);
}
- (void) reloadImageView{
/* Reload the image view here */
NSLog(@"%s", __FUNCTION__);
}
At the moment these methous aie empty, Lut you can put the ielevant UI coue in them
latei. Now we want to call these thiee methous, one altei the othei, anu we want to
6.10 Grouping Tasks Together with GCD | 391
www.it-ebooks.info
know when GCD has linisheu calling these methous so that we can uisplay a message
to the usei. Foi this, we shoulu Le using a gioup. You shoulu know aLout loui lunctions
when woiking with gioups in GCD:
dispatch_group_create
Cieates a gioup hanule. Once you aie uone with this gioup hanule, you shoulu
uispose ol it using the dispatch_release lunction.
dispatch_group_async
SuLmits a Llock ol coue loi execution on a gioup. You must specily the uispatch
gueue on which the Llock ol coue has to Le executeu as wc|| as the gioup to which
this Llock ol coue Lelongs.
dispatch_group_notify
Allows you to suLmit a Llock oLject that shoulu Le executeu once all tasks auueu
to the gioup loi execution have linisheu theii woik. This lunction also allows you
to specily the uispatch gueue on which that Llock oLject has to Le executeu.
dispatch_release
Use this lunction to uispose ol any uispatch gioups that you cieate using the
dispatch_group_create lunction.
Let`s have a look at an example. As explaineu, in the example we want to invoke the
reloadTableView, reloadScrollView, anu reloadImageView methous one altei the othei
anu then uisplay a message to the usei once we aie uone. Ve can utilize GCD`s poweilul
giouping lacilities in oiuei to accomplish this:
dispatch_group_t taskGroup = dispatch_group_create();
dispatch_queue_t mainQueue = dispatch_get_main_queue();
/* Reload the table view on the main queue */
dispatch_group_async(taskGroup, mainQueue, ^{
[self reloadTableView];
});
/* Reload the scroll view on the main queue */
dispatch_group_async(taskGroup, mainQueue, ^{
[self reloadScrollView];
});
/* Reload the image view on the main queue */
dispatch_group_async(taskGroup, mainQueue, ^{
[self reloadImageView];
});
/* At the end when we are done, dispatch the following block */
dispatch_group_notify(taskGroup, mainQueue, ^{
/* Do some processing here */
[[[UIAlertView alloc] initWithTitle:@"Finished"
message:@"All tasks are finished"
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil, nil] show];
392 | Chapter 6: Concurrency
www.it-ebooks.info

});
/* We are done with the group */
dispatch_release(taskGroup);
In auuition to dispatch_group_async, you can also uispatch asynchionous C lunctions
to a uispatch gioup using the dispatch_group_async_f lunction.
GCDAppDelegate is simply the name ol the class liom which this example
is taken. Ve have to use this class name in oiuei to typecast a context
oLject so that the compilei will unueistanu the commanus.
Like so:
void reloadAllComponents(void *context){

Grouping_Tasks_Together_with_GCDAppDelegate *self =
(__bridge Grouping_Tasks_Together_with_GCDAppDelegate *)context;

[self reloadTableView];
[self reloadScrollView];
[self reloadImageView];

}
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

dispatch_group_t taskGroup = dispatch_group_create();
dispatch_queue_t mainQueue = dispatch_get_main_queue();

dispatch_group_async_f(taskGroup,
mainQueue,
(__bridge void *)self,
reloadAllComponents);

/* At the end when we are done, dispatch the following block */
dispatch_group_notify(taskGroup, mainQueue, ^{
/* Do some processing here */
[[[UIAlertView alloc] initWithTitle:@"Finished"
message:@"All tasks are finished"
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil, nil] show];

});

/* We are done with the group */
dispatch_release(taskGroup);

self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
6.10 Grouping Tasks Together with GCD | 393
www.it-ebooks.info
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Since the dispatch_group_async_f lunction accepts a C lunction as the
Llock ol coue to Le executeu, the C lunction must have a ieleience to
self to Le aLle to invoke instance methous ol the cuiient oLject in which
the C lunction is implementeu. That is the ieason Lehinu passing self
as the context pointei in the dispatch_group_async_f lunction. Foi moie
inloimation aLout contexts anu C lunctions, please ielei to Recipe 6.5.
Once all the given tasks aie linisheu, the usei will see a iesult similai to that shown in
Figuie 6-3.
Iigurc -3. Managing a group oj tas|s with GCD
See Also
Recipe 6.5
6.11 Constructing Your Own Dispatch Queues with GCD
Problem
You want to cieate youi own uniguely nameu uispatch gueues.
394 | Chapter 6: Concurrency
www.it-ebooks.info
Solution
Use the dispatch_queue_create lunction.
Discussion
Vith GCD, you can cieate youi own seiial uispatch gueues (see Recipe 6.0 to ieau
aLout seiial gueues). Seiial uispatch gueues iun theii tasks in a liist-in-liist-out (FIFO)
lashion. The asynchionous tasks on seiial gueues will not Le peiloimeu on the main
thieau, howevei, making seiial gueues highly uesiiaLle loi concuiient FIFO tasks.
All synchionous tasks suLmitteu to a seiial gueue will Le executeu on the cuiient thieau
Leing useu Ly the coue that is suLmitting the task, whenevei possiLle. But asynchionous
tasks suLmitteu to a seiial gueue will always Le executeu on a thieau othei than the
main thieau.
Ve`ll use the dispatch_queue_create lunction to cieate seiial gueues. The liist paiam-
etei in this lunction is a C stiing (char *) that will uniguely iuentily that seiial gueue
in the systcn. The ieason I am emphasizing systcn is Lecause this iuentiliei is a system-
wiue iuentiliei, meaning that il youi app cieates a new seiial gueue with the iuentiliei
ol serialQueue1 anu someLouy else`s app uoes the same, the iesults ol cieating a new
seiial gueue with the same name aie unuelineu Ly GCD. Because ol this, Apple stiongly
iecommenus that you use a ieveise DNS loimat loi iuentilieis. Reveise DNS iuentilieis
aie usually constiucteu in this way: com.COMPANY. PRODUCT. IDENTIFIER. Foi instance, I
coulu cieate two seiial gueues anu assign these names to them:
com.pixolity.GCD.serialQueue1
com.pixolity.GCD.serialQueue2
Altei you`ve cieateu youi seiial gueue, you can stait uispatching tasks to it using the
vaiious GCD lunctions you`ve leaineu in this Look. Once you aie uone with the seiial
uispatch gueue that you`ve just cieateu, you nust uispose ol it using the dis
patch_release lunction.
Voulu you like to see an example? I thought so!
dispatch_queue_t firstSerialQueue =
dispatch_queue_create("com.pixolity.GCD.serialQueue1", 0);
dispatch_async(firstSerialQueue, ^{
NSUInteger counter = 0;
for (counter = 0;
counter < 5;
counter++){
NSLog(@"First iteration, counter = %lu", (unsigned long)counter);
}
});
dispatch_async(firstSerialQueue, ^{
NSUInteger counter = 0;
for (counter = 0;
6.11 Constructing Your Own Dispatch Queues with GCD | 395
www.it-ebooks.info
counter < 5;
counter++){
NSLog(@"Second iteration, counter = %lu", (unsigned long)counter);
}
});
dispatch_async(firstSerialQueue, ^{
NSUInteger counter = 0;
for (counter = 0;
counter < 5;
counter++){
NSLog(@"Third iteration, counter = %lu", (unsigned long)counter);
}
});
dispatch_release(firstSerialQueue);
Il you iun this coue anu have a look at the output piinteu to the console winuow, you
will see iesults similai to these:
First iteration, counter = 0
First iteration, counter = 1
First iteration, counter = 2
First iteration, counter = 3
First iteration, counter = 4
Second iteration, counter = 0
Second iteration, counter = 1
Second iteration, counter = 2
Second iteration, counter = 3
Second iteration, counter = 4
Third iteration, counter = 0
Third iteration, counter = 1
Third iteration, counter = 2
Third iteration, counter = 3
Third iteration, counter = 4
It`s oLvious that, although we uispatcheu the Llock oLjects asynchionously to the seiial
gueue, the gueue has executeu theii coue in a FIFO lashion. Ve can mouily the same
sample coue to make use ol dispatch_async_f lunction insteau ol the dispatch_async
lunction, like so:
void firstIteration(void *paramContext){

NSUInteger counter = 0;
for (counter = 0;
counter < 5;
counter++){
NSLog(@"First iteration, counter = %lu", (unsigned long)counter);
}
}
void secondIteration(void *paramContext){

NSUInteger counter = 0;
for (counter = 0;
396 | Chapter 6: Concurrency
www.it-ebooks.info
counter < 5;
counter++){
NSLog(@"Second iteration, counter = %lu", (unsigned long)counter);
}
}
void thirdIteration(void *paramContext){

NSUInteger counter = 0;
for (counter = 0;
counter < 5;
counter++){
NSLog(@"Third iteration, counter = %lu", (unsigned long)counter);
}
}
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

dispatch_queue_t firstSerialQueue =
dispatch_queue_create("com.pixolity.GCD.serialQueue1", 0);

dispatch_async_f(firstSerialQueue, NULL, firstIteration);
dispatch_async_f(firstSerialQueue, NULL, secondIteration);
dispatch_async_f(firstSerialQueue, NULL, thirdIteration);

dispatch_release(firstSerialQueue);

self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
6.12 Running Tasks Synchronously with Operations
Problem
You want to iun a seiies ol tasks synchionously.
Solution
Cieate opeiations anu stait them manually:
#import <UIKit/UIKit.h>
@interface Running_Tasks_Synchronously_with_OperationsAppDelegate
: UIResponder <UIApplicationDelegate>
6.12 Running Tasks Synchronously with Operations | 397
www.it-ebooks.info
@property (strong, nonatomic) UIWindow *window;
@property (nonatomic, strong) NSInvocationOperation *simpleOperation;
@end
The implementation ol the application uelegate is as lollows:
- (void) simpleOperationEntry:(id)paramObject{

NSLog(@"Parameter Object = %@", paramObject);
NSLog(@"Main Thread = %@", [NSThread mainThread]);
NSLog(@"Current Thread = %@", [NSThread currentThread]);

}
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

NSNumber *simpleObject = [NSNumber numberWithInteger:123];

self.simpleOperation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:@selector(simpleOperationEntry:)
object:simpleObject];

[self.simpleOperation start];

self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
The output ol this piogiam (in the console winuow) will Le similai to this:
Parameter Object = 123
Main Thread = <NSThread: 0x6810280>{name = (null), num = 1}
Current Thread = <NSThread: 0x6810280>{name = (null), num = 1}
As the name ol this class implies (NSInvocationOperation), the main iesponsiLility ol
an oLject ol this type is to invoke a methou in an oLject. This is the most stiaightloiwaiu
way to invoke a methou insiue an oLject using opeiations.
Discussion
An invocation opeiation, as uesciiLeu in this chaptei`s Intiouuction, is aLle to invoke
a methou insiue an oLject. Vhat is so special aLout this? you might ask. The invo-
cation opeiation`s powei can Le uemonstiateu when it is auueu to an opeiation gueue.
Vith an opeiation gueue, an invocation opeiation can invoke a methou in a taiget
oLject asynchionously anu in paiallel to the thieau that staiteu the opeiation. Il you
have a look at the output piinteu to the console (in this iecipe`s Solution), you will
notice that the cuiient thieau insiue the methou invokeu Ly the invocation opeiation
398 | Chapter 6: Concurrency
www.it-ebooks.info
is the same as the main thieau since the main thieau in the application:didFin
ishLaunchingWithOptions: methou staiteu the opeiation using its start methou. In
Recipe 6.13, we will leain how to take auvantage ol opeiation gueues to iun tasks
asynchionously.
In auuition to invocation opeiations, you can use Llock oi plain opeiations to peiloim
tasks synchionously. Heie is an example using a Llock opeiation to count numLeis
liom zeio to 999 (insiue the .h lile ol the application uelegate):
#import <UIKit/UIKit.h>
@interface Running_Tasks_Synchronously_with_OperationsAppDelegate
: UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (nonatomic, strong) NSBlockOperation *simpleOperation;
@end
Heie is the implementation ol the application uelegate (.n lile):
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

self.simpleOperation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"Main Thread = %@", [NSThread mainThread]);
NSLog(@"Current Thread = %@", [NSThread currentThread]);
NSUInteger counter = 0;
for (counter = 0;
counter < 1000;
counter++){
NSLog(@"Count = %lu", (unsigned long)counter);
}
}];

/* Start the operation */
[self.simpleOperation start];
/* Print something out just to test if we have to wait
for the block to execute its code or not */
NSLog(@"Main thread is here");

self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Il we iun the application, we will see the values 0 to 999 piinteu out to the scieen
lolloweu Ly the Main thieau is heie message, like this:
Main Thread = <NSThread: 0x6810280>{name = (null), num = 1}
Current Thread = <NSThread: 0x6810280>{name = (null), num = 1}
...
Count = 991
6.12 Running Tasks Synchronously with Operations | 399
www.it-ebooks.info
Count = 992
Count = 993
Count = 994
Count = 995
Count = 996
Count = 997
Count = 998
Count = 999
Main thread is here
This pioves that since the Llock opeiation was staiteu in the application:didFinish
LaunchingWithOptions: methou, which itsell iuns on the main thieau, the coue insiue
the Llock was also iunning on the main thieau. The main point to take liom the log
messages is that the opeiation Llockeu the main thieau anu the main thieau`s coue
continueu to Le executeu altei the woik loi the Llock opeiation was uone. This is a
veiy Lau piogiamming piactice. In lact, iOS uevelopeis must peiloim any tiick anu use
any technigue that they know ol to keep the main thieau iesponsive so that it can uo
the key joL ol piocessing useis` input. Heie is what Apple has to say aLout this:
You shoulu Le caielul what woik you peiloim liom the main thieau ol youi application.
The main thieau is wheie youi application hanules touch events anu othei usei input.
To ensuie that youi application is always iesponsive to the usei, you shoulu nevei use
the main thieau to peiloim long-iunning tasks oi to peiloim tasks with a potentially
unLounueu enu, such as tasks that access the netwoik. Insteau, you shoulu always move
those tasks onto Lackgiounu thieaus. The pieleiieu way to uo so is to wiap each task in
an opeiation oLject anu auu it to an opeiation gueue, Lut you can also cieate explicit
thieaus youisell.
To ieau moie aLout this suLject, Liowse thiough the Peiloimance Tuning uocument
in the iOS Releience LiLiaiy, availaLle at this URL.
In auuition to invocation anu Llock opeiations, you can also suLclass NSOperation anu
peiloim youi task in that class. Beloie getting staiteu, you must keep a lew things in
minu while suLclassing NSOperation:
Il you aie not planning on using an opeiation gueue, you have to uetach a new
thieau ol youi own in the start methou ol the opeiation. Il you uo not want to use
an opeiation gueue anu you uo not want youi opeiation to iun asynchionously
liom othei opeiations that you stait manually, you can simply call the main methou
ol youi opeiation insiue the start methou.
Two impoitant methous in an instance ol NSOperation must Le oveiiiuuen Ly youi
own implementation ol the opeiation: isExecuting anu isFinished. These can Le
calleu liom any othei oLject. In these methous, you must ietuin a thieau-sale value
that you can manipulate liom insiue the opeiation. As soon as youi opeiation
staits, you must, thiough KVO, inloim any listeneis that you aie changing the
values that these two methous ietuin. Ve will see how this woiks in the example
coue.
400 | Chapter 6: Concurrency
www.it-ebooks.info
You must pioviue youi own autoielease pool insiue the main methou ol the opei-
ation in case youi opeiation will Le auueu to an opeiation gueue at some point in
the lutuie. You must make suie youi opeiations woik in Loth ways: whethei you
stait them manually oi they get staiteu Ly an opeiation gueue.
You must have an initialization methou loi youi opeiations. Theie must Le only
one uesignateu initializei methou pei opeiation. All othei initializei methous, in-
cluuing the uelault init methou ol an opeiation, must call the uesignateu initializei
that has the most numLei ol paiameteis. Othei initializei methous must make suie
they pass appiopiiate paiameteis (il any) to the uesignateu initializei.
Heie is the ueclaiation ol the opeiation oLject (.h lile):
#import <Foundation/Foundation.h>
@interface CountingOperation : NSOperation

/* Designated Initializer */
- (id) initWithStartingCount:(NSUInteger)paramStartingCount
endingCount:(NSUInteger)paramEndingCount;
@end
The implementation (.n lile) ol the opeiation might Le a Lit long, Lut hopelully it`s
easy to unueistanu:
#import "CountingOperation.h"
@implementation CountingOperation
NSUInteger startingCount;
NSUInteger endingCount;
BOOL finished;
BOOL executing;
- (id) init {
return([self initWithStartingCount:0
endingCount:1000]);
}
- (id) initWithStartingCount:(NSUInteger)paramStartingCount
endingCount:(NSUInteger)paramEndingCount{

self = [super init];

if (self != nil){
/* Keep these values for the main method */
startingCount = paramStartingCount;
endingCount = paramEndingCount;

}

return(self);
6.12 Running Tasks Synchronously with Operations | 401
www.it-ebooks.info

}
- (void) start {

/* If we are cancelled before starting, then
we have to return immediately and generate the
required KVO notifications */
if ([self isCancelled]){
/* If this operation *is* cancelled */
/* KVO compliance */
[self willChangeValueForKey:@"isFinished"];
finished = YES;
[self didChangeValueForKey:@"isFinished"];
return;

} else {
/* If this operation is *not* cancelled */
/* KVO compliance */
[self willChangeValueForKey:@"isExecuting"];
executing = YES;
/* Call the main method from inside the start method */
[self didChangeValueForKey:@"isExecuting"];
[self main];

}

}
- (void) main {

@try {
/* Here is the autorelease pool */
@autoreleasepool {
/* Keep a local variable here that must get set to YES
whenever we are done with the task */
BOOL taskIsFinished = NO;

/* Create a while loop here that only exists
if the taskIsFinished variable is set to YES or
the operation has been cancelled */
while (taskIsFinished == NO &&
[self isCancelled] == NO){

/* Perform the task here */
NSLog(@"Main Thread = %@", [NSThread mainThread]);
NSLog(@"Current Thread = %@", [NSThread currentThread]);
NSUInteger counter = startingCount;
for (counter = startingCount;
counter < endingCount;
counter++){
NSLog(@"Count = %lu", (unsigned long)counter);
}
402 | Chapter 6: Concurrency
www.it-ebooks.info
/* Very important. This way we can get out of the
loop and we are still complying with the cancellation
rules of operations */
taskIsFinished = YES;

}

/* KVO compliance. Generate the
required KVO notifications */
[self willChangeValueForKey:@"isFinished"];
[self willChangeValueForKey:@"isExecuting"];
finished = YES;
executing = NO;
[self didChangeValueForKey:@"isFinished"];
[self didChangeValueForKey:@"isExecuting"];
}
}
@catch (NSException * e) {
NSLog(@"Exception %@", e);
}

}
- (BOOL) isFinished{
/* Simply return the value */
return(finished);
}
- (BOOL) isExecuting{
/* Simply return the value */
return(executing);
}
@end
Ve can stait this opeiation like so:
#import "Running_Tasks_Synchronously_with_OperationsAppDelegate.h"
#import "CountingOperation.h"
@implementation Running_Tasks_Synchronously_with_OperationsAppDelegate
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

self.simpleOperation = [[CountingOperation alloc] initWithStartingCount:0
endingCount:1000];

[self.simpleOperation start];

NSLog(@"Main thread is here");

self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
6.12 Running Tasks Synchronously with Operations | 403
www.it-ebooks.info
[self.window makeKeyAndVisible];
return YES;
}
@end
Il we iun the coue, we will see the lollowing iesults in the console winuow, just as we
uiu when we useu a Llock opeiation:
Main Thread = <NSThread: 0x6810260>{name = (null), num = 1}
Current Thread = <NSThread: 0x6810260>{name = (null), num = 1}
...
Count = 993
Count = 994
Count = 995
Count = 996
Count = 997
Count = 998
Count = 999
Main thread is here
See Also
Recipe 6.13
6.13 Running Tasks Asynchronously with Operations
Problem
You want to execute opeiations concuiiently.
Solution
Use opeiation gueues. Alteinatively, suLclass NSOperation anu uetach a new thieau on
the main methou.
Discussion
As mentioneu in Recipe 6.12, opeiations, Ly uelault, iun on the thieau that calls the
start methou. Usually we stait opeiations on the main thieau, Lut at the same time
we expect the opeiations to iun on theii own thieaus anu not take the main thieau`s
time slice. The Lest solution loi us woulu Le to use opeiation gueues. Howevei, il you
want to manage youi opeiations manually, which I uo not iecommenu, you can suL-
class NSOperation anu uetach a new thieau on the main methou. Please ielei to
Recipe 6.16 loi moie inloimation aLout uetacheu thieaus.
Let`s go aheau anu use an opeiation gueue anu auu two simple invocation opeiations
to it. (Foi moie inloimation aLout invocation opeiations, please ielei to this chaptei`s
Intiouuction. Foi auuitional example coue on invocation opeiations, please ielei to
404 | Chapter 6: Concurrency
www.it-ebooks.info
Recipe 6.12.) Heie is the ueclaiation (.h lile) ol the application uelegate that utilizes an
opeiation gueue anu two invocation opeiations:
#import <UIKit/UIKit.h>
@interface Running_Tasks_Asynchronously_with_OperationsAppDelegate
: UIResponder <UIApplicationDelegate>
@property (nonatomic, strong) UIWindow *window;
@property (nonatomic, strong) NSOperationQueue *operationQueue;
@property (nonatomic, strong) NSInvocationOperation *firstOperation;
@property (nonatomic, strong) NSInvocationOperation *secondOperation;
@end
The implementation (.n lile) ol the application uelegate is as lollows:
#import "Running_Tasks_Asynchronously_with_OperationsAppDelegate.h"
@implementation Running_Tasks_Asynchronously_with_OperationsAppDelegate
- (void) firstOperationEntry:(id)paramObject{

NSLog(@"%s", __FUNCTION__);
NSLog(@"Parameter Object = %@", paramObject);
NSLog(@"Main Thread = %@", [NSThread mainThread]);
NSLog(@"Current Thread = %@", [NSThread currentThread]);

}
- (void) secondOperationEntry:(id)paramObject{

NSLog(@"%s", __FUNCTION__);
NSLog(@"Parameter Object = %@", paramObject);
NSLog(@"Main Thread = %@", [NSThread mainThread]);
NSLog(@"Current Thread = %@", [NSThread currentThread]);

}
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

NSNumber *firstNumber = [NSNumber numberWithInteger:111];
NSNumber *secondNumber = [NSNumber numberWithInteger:222];

self.firstOperation =[[NSInvocationOperation alloc]
initWithTarget:self
selector:@selector(firstOperationEntry:)
object:firstNumber];

self.secondOperation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:@selector(secondOperationEntry:)
object:secondNumber];

self.operationQueue = [[NSOperationQueue alloc] init];
6.13 Running Tasks Asynchronously with Operations | 405
www.it-ebooks.info

/* Add the operations to the queue */
[self.operationQueue addOperation:self.firstOperation];
[self.operationQueue addOperation:self.secondOperation];

NSLog(@"Main thread is here");

self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
@end
Heie is what is happening in the implementation ol the coue:
Ve have two methous: firstOperationEntry: anu secondOperationEntry:. Each
methou accepts an oLject as a paiametei anu piints out the cuiient thieau, the
main thieau, anu the paiametei to the console winuow. These aie the entiy meth-
ous ol the invocation opeiations that will Le auueu to an opeiation gueue.
Ve initialize two oLjects ol type NSInvocationOperation anu set the taiget selectoi
to each opeiation entiy point uesciiLeu pieviously.
Ve then initialize an oLject ol type NSOperationQueue. (It coulu also Le cieateu
Leloie the entiy methous.) The gueue oLject will Le iesponsiLle loi managing the
concuiiency in the opeiation oLjects.
Ve invoke the addOperation: instance methou ol NSOperationQueue to auu each
invocation opeiation to the opeiation gueue. At this point, the opeiation gueue
may oi may not immeuiately stait the invocation opeiations thiough theii start
methous. Howevei, it is veiy impoitant to Leai in minu that altei auuing opeiations
to an opeiation gueue, you must not stait the opeiations manually. You must leave
this to the opeiation gueue.
Now let`s iun the example coue once anu see the iesults in the console winuow:
[Running_Tasks_Asynchronously_with_OperationsAppDelegate firstOperationEntry:]
Main thread is here
Parameter Object = 111
[Running_Tasks_Asynchronously_with_OperationsAppDelegate secondOperationEntry:]
Main Thread = <NSThread: 0x6810260>{name = (null), num = 1}
Parameter Object = 222
Current Thread = <NSThread: 0x6805c20>{name = (null), num = 3}
Main Thread = <NSThread: 0x6810260>{name = (null), num = 1}
Current Thread = <NSThread: 0x6b2d1d0>{name = (null), num = 4}
Biilliant! This pioves that the invocation opeiations aie iunning on theii own thieaus
in paiallel to the main thieau without Llocking the main thieau at all. Now let`s iun
the same coue a couple moie times anu oLseive the output in the console winuow. Il
you uo this, chances aie that you will get a completely uilleient iesult, such as this:
406 | Chapter 6: Concurrency
www.it-ebooks.info
Main thread is here
[Running_Tasks_Asynchronously_with_OperationsAppDelegate firstOperationEntry:]
[Running_Tasks_Asynchronously_with_OperationsAppDelegate secondOperationEntry:]
Parameter Object = 111
Main Thread = <NSThread: 0x6810260>{name = (null), num = 1}
Current Thread = <NSThread: 0x68247c0>{name = (null), num = 3}
Parameter Object = 222
Main Thread = <NSThread: 0x6810260>{name = (null), num = 1}
Current Thread = <NSThread: 0x6819b00>{name = (null), num = 4}
You can cleaily oLseive that the main thieau is not Llockeu anu that Loth invocation
opeiations aie iunning in paiallel with the main thieau. This just pioves the concui-
iency in the opeiation gueue when two nonconcuiient opeiations aie auueu to it. The
opeiation gueue manages the thieaus ieguiieu to iun the opeiations.
Il we weie to suLclass NSOperation anu auu the instances ol the new class to an op-
eiation gueue, we woulu uo things slightly uilleiently. Keep a lew things in minu:
Plain opeiations that suLclass NSOperation, when auueu to an opeiation gueue,
will iun asynchionously. Foi this ieason, you must oveiiiue the isConcurrent in-
stance methou ol NSOperation anu ietuin the value YES.
You must piepaie youi opeiation loi cancellation Ly checking the value ol the
isCancelled methou peiiouically while peiloiming the main task ol the opeiation
anu in the start methou Leloie you even iun the opeiation. The start methou will
get calleu Ly the opeiation gueue in this case altei the opeiation is auueu to the
gueue. In this methou, check whethei the opeiation is cancelleu using the isCan
celled methou. Il the opeiation is cancelleu, simply ietuin liom the start methou.
Il not, call the main methou liom insiue the start methou.
Oveiiiue the main methou with youi own implementation ol the main task that is
to Le caiiieu out Ly the opeiation. Make suie to allocate anu initialize youi own
autoielease pool in this methou anu to ielease the pool just Leloie ietuining.
Oveiiiue the isFinished anu isExecuting methous ol youi opeiation anu ietuin
appiopiiate BOOL values to ieveal whethei the opeiation is linisheu oi is executing
at the time.
Heie is the ueclaiation (.h lile) ol the opeiation:
#import <Foundation/Foundation.h>
@interface SimpleOperation : NSOperation
/* Designated Initializer */
- (id) initWithObject:(NSObject *)paramObject;
@end
The implementation ol the opeiation is as lollows:
#import "SimpleOperation.h"
@implementation SimpleOperation
6.13 Running Tasks Asynchronously with Operations | 407
www.it-ebooks.info
NSObject *givenObject;
BOOL finished;
BOOL executing;
- (id) init {
NSNumber *dummyObject = [NSNumber numberWithInteger:123];
return([self initWithObject:dummyObject]);
}
- (id) initWithObject:(NSObject *)paramObject{
self = [super init];
if (self != nil){
/* Keep these values for the main method */
givenObject = paramObject;
}
return(self);
}
- (void) start {

/* If we are cancelled before starting, then
we have to return immediately and generate the
required KVO notifications */
if ([self isCancelled]){
/* If this operation *is* cancelled */
/* KVO compliance */
[self willChangeValueForKey:@"isFinished"];
finished = YES;
[self didChangeValueForKey:@"isFinished"];
return;

} else {
/* If this operation is *not* cancelled */
/* KVO compliance */
[self willChangeValueForKey:@"isExecuting"];
executing = YES;
/* Call the main method from inside the start method */
[self didChangeValueForKey:@"isExecuting"];
[self main];
}

}
- (void) main {

@try {
@autoreleasepool {
/* Keep a local variable here that must get set to YES
whenever we are done with the task */
BOOL taskIsFinished = NO;

/* Create a while loop here that only exists
if the taskIsFinished variable is set to YES or
the operation has been cancelled */
408 | Chapter 6: Concurrency
www.it-ebooks.info
while (taskIsFinished == NO &&
[self isCancelled] == NO){

/* Perform the task here */
NSLog(@"%s", __FUNCTION__);
NSLog(@"Parameter Object = %@", givenObject);
NSLog(@"Main Thread = %@", [NSThread mainThread]);
NSLog(@"Current Thread = %@", [NSThread currentThread]);

/* Very important. This way we can get out of the
loop and we are still complying with the cancellation
rules of operations */
taskIsFinished = YES;

}

/* KVO compliance. Generate the
required KVO notifications */
[self willChangeValueForKey:@"isFinished"];
[self willChangeValueForKey:@"isExecuting"];
finished = YES;
executing = NO;
[self didChangeValueForKey:@"isFinished"];
[self didChangeValueForKey:@"isExecuting"];
}
}
@catch (NSException * e) {
NSLog(@"Exception %@", e);
}

}
- (BOOL) isConcurrent{
return YES;
}
- (BOOL) isFinished{
/* Simply return the value */
return finished;
}
- (BOOL) isExecuting{
/* Simply return the value */
return executing;
}
@end
You can now use this opeiation class in any othei class, such as youi application uel-
egate. Heie is the ueclaiation ol the application uelegate to utilize this new opeiation
class anu auu it in an opeiation gueue:
#import <UIKit/UIKit.h>
@class SimpleOperation;
6.13 Running Tasks Asynchronously with Operations | 409
www.it-ebooks.info
@interface Running_Tasks_Asynchronously_with_OperationsAppDelegate
: UIResponder <UIApplicationDelegate>
@property (nonatomic, strong) UIWindow *window;
@property (nonatomic, strong) NSOperationQueue *operationQueue;
@property (nonatomic, strong) SimpleOperation *firstOperation;
@property (nonatomic, strong) SimpleOperation *secondOperation;
@end
The implementation ol the application uelegate is as lollows:
#import "Running_Tasks_Asynchronously_with_OperationsAppDelegate.h"
#import "SimpleOperation.h"
@implementation Running_Tasks_Asynchronously_with_OperationsAppDelegate
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

NSNumber *firstNumber = [NSNumber numberWithInteger:111];
NSNumber *secondNumber = [NSNumber numberWithInteger:222];
self.firstOperation = [[SimpleOperation alloc]
initWithObject:firstNumber];
self.secondOperation = [[SimpleOperation alloc]
initWithObject:secondNumber];

self.operationQueue = [[NSOperationQueue alloc] init];

/* Add the operations to the queue */
[self.operationQueue addOperation:self.firstOperation];
[self.operationQueue addOperation:self.secondOperation];

NSLog(@"Main thread is here");

self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
@end
The iesults piinteu to the console winuow will Le similai to what we saw eailiei when
we useu concuiient invocation opeiations:
Main thread is here
-[SimpleOperation main]
-[SimpleOperation main]
Parameter Object = 222
Parameter Object = 222
Main Thread = <NSThread: 0x6810260>{name = (null), num = 1}
410 | Chapter 6: Concurrency
www.it-ebooks.info
Main Thread = <NSThread: 0x6810260>{name = (null), num = 1}
Current Thread = <NSThread: 0x6a10b90>{name = (null), num = 3}
Current Thread = <NSThread: 0x6a13f50>{name = (null), num = 4}
See Also
Recipe 6.12; Recipe 6.16
6.14 Creating Dependency Between Operations
Problem
You want to stait a ceitain task only altei anothei task has linisheu executing.
Solution
Il opeiation B has to wait loi opeiation A Leloie it can iun the task associateu with it,
opeiation B has to auu opeiation A as its uepenuency using the addDependency: instance
methou ol NSOperation, as shown heie:
[self.firstOperation addDependency:self.secondOperation];
Both the firstOperation anu the secondOperation piopeities aie ol type NSInvoca
tionOperation, as we will see in this iecipe`s Discussion. In this example coue, the liist
opeiation will not Le executeu Ly the opeiation gueue until altei the seconu opeiation`s
task is linisheu.
Discussion
An opeiation will not stait executing until all the opeiations on which it uepenus have
successlully linisheu executing the tasks associateu with them. By uelault, an opeiation,
altei initialization, has no uepenuency on othei opeiations.
Il we want to intiouuce uepenuencies to the example coue uesciiLeu in Recipe 6.13,
we can slightly mouily the application uelegate`s implementation anu use the add
Dependency: instance methou to have the liist opeiation wait loi the seconu opeiation:
#import "Creating_Dependency_Between_OperationsAppDelegate.h"
@implementation Creating_Dependency_Between_OperationsAppDelegate
- (void) firstOperationEntry:(id)paramObject{

NSLog(@"First Operation - Parameter Object = %@",
paramObject);

NSLog(@"First Operation - Main Thread = %@",
[NSThread mainThread]);

NSLog(@"First Operation - Current Thread = %@",
[NSThread currentThread]);
6.14 Creating Dependency Between Operations | 411
www.it-ebooks.info

}
- (void) secondOperationEntry:(id)paramObject{

NSLog(@"Second Operation - Parameter Object = %@",
paramObject);

NSLog(@"Second Operation - Main Thread = %@",
[NSThread mainThread]);

NSLog(@"Second Operation - Current Thread = %@",
[NSThread currentThread]);

}
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

NSNumber *firstNumber = [NSNumber numberWithInteger:111];
NSNumber *secondNumber = [NSNumber numberWithInteger:222];

self.firstOperation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:@selector(firstOperationEntry:)
object:firstNumber];

self.secondOperation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:@selector(secondOperationEntry:)
object:secondNumber];

[self.firstOperation addDependency:self.secondOperation];

self.operationQueue = [[NSOperationQueue alloc] init];

/* Add the operations to the queue */
[self.operationQueue addOperation:self.firstOperation];
[self.operationQueue addOperation:self.secondOperation];

NSLog(@"Main thread is here");

self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
@end
Now il you execute the piogiam, you will see a iesult similai to this in the console
winuow:
Second Operation - Parameter Object = 222
Main thread is here
412 | Chapter 6: Concurrency
www.it-ebooks.info
Second Operation - Main Thread = <NSThread: 0x6810250>{name = (null), num = 1}
Second Operation - Current Thread = <NSThread: 0x6836ab0>{name = (null), num = 3}
First Operation - Parameter Object = 111
First Operation - Main Thread = <NSThread: 0x6810250>{name = (null), num = 1}
First Operation - Current Thread = <NSThread: 0x6836ab0>{name = (null), num = 3}
It`s guite oLvious that although the opeiation gueue attempteu to iun Loth opeiations
in paiallel, the liist opeiation hau a uepenuency on the seconu opeiation, anu theieloie
the seconu opeiation hau to linish Leloie the liist opeiation coulu iun.
Il at any time you want to Lieak the uepenuency Letween two opeiations, you can use
the removeDependency: instance methou ol an opeiation oLject.
See Also
Recipe 6.13
6.15 Creating Timers
Problem
You woulu like to peiloim a specilic task iepeateuly with a ceitain uelay. Foi instance,
you want to upuate a view on youi scieen eveiy seconu that youi application is iunning.
Solution
Use a timei:
- (void) paint:(NSTimer *)paramTimer{
/* Do something here */
NSLog(@"Painting");
}
- (void) startPainting{

self.paintingTimer = [NSTimer
scheduledTimerWithTimeInterval:1.0
target:self
selector:@selector(paint:)
userInfo:nil
repeats:YES];

}
- (void) stopPainting{
if (self.paintingTimer != nil){
[self.paintingTimer invalidate];
}
}
- (void)applicationWillResignActive:(UIApplication *)application{
[self stopPainting];
6.15 Creating Timers | 413
www.it-ebooks.info
}
- (void)applicationDidBecomeActive:(UIApplication *)application{
[self startPainting];
}
The invalidate methou will also ielease the timei, so that we uon`t have to uo that
manually. As you can see, we have uelineu a piopeity calleu paintingTimer that is
ueclaieu in this way in the heauei lile (.h lile):
#import <UIKit/UIKit.h>
@interface Creating_TimersAppDelegate : UIResponder <UIApplicationDelegate>
@property (nonatomic, strong) UIWindow *window;
@property (nonatomic, strong) NSTimer *paintingTimer;
@end
Discussion
A timei is an oLject that liies an event at specilieu inteivals. A timei must Le scheuuleu
in a iun loop. Delining an NSTimer oLject cieates a nonscheuuleu timei that uoes noth-
ing Lut is availaLle to the piogiam when you want to scheuule it. Once you issue a call,
e.g. scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:, the time
Lecomes a scheuuleu timei anu will liie the event you ieguest. A scheuuleu timei is a
timei that is auueu to a iun loop. To get any timei to liie its taiget event, we must
scheuule that timei on a iun loop. This is uemonstiateu in a latei example wheie we
cieate a nonscheuuleu timei anu then manually scheuule it on the main iun loop ol the
application.
Once a timei is cieateu anu auueu to a run loop, eithei explicitly oi implicitly, the timei
will stait calling a methou in its taiget oLject (as specilieu Ly the piogiammei) eveiy
n seconus (n is specilieu Ly the piogiammei as well). Because n is lloating-point, you
can specily a liaction ol a seconu.
Theie aie vaiious ways to cieate, initialize, anu scheuule timeis. One ol the easiest ways
is thiough the scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:
class methou ol NSTimer. Heie aie the uilleient paiameteis ol this methou:
scheduledTimerWithTimeInterval
This is the numLei ol seconus the timei has to wait Leloie it liies an event. Foi
example, il you want the timei to call a methou in its taiget oLject twice pei seconu,
you have to set this paiametei to 0.5 (1 seconu uiviueu Ly 2); il you want the taiget
methou to Le calleu loui times pei seconu, this paiametei shoulu Le set to 0.25 (1
seconu uiviueu Ly +).
target
This is the oLject that will ieceive the event.
414 | Chapter 6: Concurrency
www.it-ebooks.info
selector
This is the methou signatuie in the taiget oLject that will ieceive the event.
userInfo
This is the oLject that will Le ietaineu in the timei loi latei ieleience (in the taiget
methou ol the taiget oLject).
repeats
This specilies whethei the timei must call its taiget methou iepeateuly (in which
case this paiametei has to Le set to YES), oi just once anu then stop (in which case
this paiametei has to Le set to NO).
Once a timei is cieateu anu auueu to a iun loop, you can stop anu ielease
that timei using the invalidate instance methou ol the NSTimer class.
This not only will ielease the timei, Lut also will ielease the oLject, il
any, that was passeu loi the timei to ietain uuiing its liletime (e.g., the
oLject passeu to the userInfo paiametei ol the scheduledTimerWith
TimeInterval:target:selector:userInfo:repeats: class methou ol
NSTimer). Il you pass NO to the repeats paiametei, the timei will inva-
liuate itsell altei the liist pass anu suLseguently will ielease the oLject
it hau ietaineu (il any).
Theie aie othei methous you can use to cieate a scheuuleu timei. One ol them is the
scheduledTimerWithTimeInterval:invocation:repeats: class methou ol NSTimer:
- (void) paint:(NSTimer *)paramTimer{
/* Do something here */
NSLog(@"Painting");
}
- (void) startPainting{

/* Here is the selector that we want to call */
SEL selectorToCall = @selector(paint:);
/* Here we compose a method signature out of the selector.
We know that the selector is in the current class so it is easy
to construct the method signature */
NSMethodSignature *methodSignature =
[[self class] instanceMethodSignatureForSelector:selectorToCall];

/* Now base the invocation on the method signature. We need this
invocation to schedule a timer */
NSInvocation *invocation =
[NSInvocation invocationWithMethodSignature:methodSignature];
[invocation setTarget:self];
[invocation setSelector:selectorToCall];

/* Start a scheduled timer now */
self.paintingTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
invocation:invocation
6.15 Creating Timers | 415
www.it-ebooks.info
repeats:YES];

}
- (void) stopPainting{
if (self.paintingTimer != nil){
[self.paintingTimer invalidate];
}
}
- (void)applicationWillResignActive:(UIApplication *)application{
[self stopPainting];
}
- (void)applicationDidBecomeActive:(UIApplication *)application{
[self startPainting];
}
Scheuuling a timei can Le compaieu to staiting a cai`s engine. A scheuuleu timei is a
iunning cai engine. A nonscheuuleu timei is a cai engine that is ieauy to Le staiteu,
Lut is not iunning yet. Ve can scheuule anu unscheuule timeis whenevei we want in
the application, just like we might neeu the engine ol a cai to Le on oi oll uepenuing
on the situation we aie in. Il you want to scheuule a timei manually at a ceitain time
in youi application, you can use the timerWithTimeInterval:target:selector:user
Info:repeats: class methou ol NSTimer, anu when you aie ieauy, you can auu the timei
to youi iun loop ol choice:
- (void) startPainting{

self.paintingTimer = [NSTimer timerWithTimeInterval:1.0
target:self
selector:@selector(paint:)
userInfo:nil
repeats:YES];

/* Do your processing here and, whenever you are ready,
use the addTimer:forMode instance method of the NSRunLoop class
in order to schedule the timer on that run loop */

[[NSRunLoop currentRunLoop] addTimer:self.paintingTimer
forMode:NSDefaultRunLoopMode];

}
The currentRunLoop anu mainRunLoop class methous ol NSRunLoop ietuin
the cuiient anu main iun loops ol the application, iespectively, as theii
names imply.
]ust like you can use the scheduledTimerWithTimeInterval:invocation:repeats: vaiiant
ol cieating scheuuleu timeis using invocations, you can also use the timerWith
416 | Chapter 6: Concurrency
www.it-ebooks.info
TimeInterval:invocation:repeats: class methou ol NSTimer to cieate an unscheuuleu
timei using an invocation:
- (void) paint:(NSTimer *)paramTimer{
/* Do something here */
NSLog(@"Painting");
}
- (void) startPainting{

/* Here is the selector that we want to call */
SEL selectorToCall = @selector(paint:);
/* Here we compose a method signature out of the selector. We
know that the selector is in the current class so it is easy
to construct the method signature */
NSMethodSignature *methodSignature =
[[self class] instanceMethodSignatureForSelector:selectorToCall];

/* Now base the invocation on the method signature. We need this
invocation to schedule a timer */
NSInvocation *invocation =
[NSInvocation invocationWithMethodSignature:methodSignature];

[invocation setTarget:self];
[invocation setSelector:selectorToCall];

self.paintingTimer = [NSTimer timerWithTimeInterval:1.0
invocation:invocation
repeats:YES];;

/* Do your processing here and, whenever you are ready,
use the addTimer:forMode instance method of the NSRunLoop class
in order to schedule the timer on that run loop */

[[NSRunLoop currentRunLoop] addTimer:self.paintingTimer
forMode:NSDefaultRunLoopMode];

}
- (void) stopPainting{
if (self.paintingTimer != nil){
[self.paintingTimer invalidate];
}
}
- (void)applicationWillResignActive:(UIApplication *)application{
[self stopPainting];
}
- (void)applicationDidBecomeActive:(UIApplication *)application{
[self startPainting];
}
The taiget methou ol a timei ieceives the instance ol the timei that calls it as its
paiametei. Foi instance, the paint: methou intiouuceu initially in this iecipe
6.15 Creating Timers | 417
www.it-ebooks.info
uemonstiates how the timei gets passeu to its taiget methou, Ly uelault, as the taiget
methou`s one anu only paiametei:
- (void) paint:(NSTimer *)paramTimer{
/* Do something here */
NSLog(@"Painting");
}
This paiametei pioviues you with a ieleience to the timei that is liiing this methou.
You can, loi instance, pievent the timei liom iunning again using the invalidate
methou, il neeueu. You can also invoke the userInfo methou ol the NSTimer instance
in oiuei to ietiieve the oLject Leing ietaineu Ly the timei (il any). This oLject is just an
oLject passeu to the initialization methous ol NSTimer, anu it gets uiiectly passeu to the
timei loi lutuie ieleience.
6.16 Creating Concurrency with Threads
Problem
You woulu like to have maximum contiol ovei how sepaiate tasks iun in youi appli-
cation. Foi instance, you woulu like to iun a long calculation ieguesteu Ly the usei
while lieeing the main UI thieau to inteiact with the usei anu uo othei things.
Solution
Utilize thieaus in youi application, like so:
- (void) downloadNewFile:(id)paramObject{

@autoreleasepool {
NSString *fileURL = (NSString *)paramObject;

NSURL *url = [NSURL URLWithString:fileURL];

NSURLRequest *request = [NSURLRequest requestWithURL:url];

NSURLResponse *response = nil;
NSError *error = nil;

NSData *downloadedData =
[NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];

if ([downloadedData length] > 0){
/* Fully downloaded */
} else {
/* Nothing was downloaded. Check the Error value */
}
}

418 | Chapter 6: Concurrency
www.it-ebooks.info
}
- (void)viewDidLoad {
[super viewDidLoad];

NSString *fileToDownload = @"http://www.OReilly.com";

[NSThread detachNewThreadSelector:@selector(downloadNewFile:)
toTarget:self
withObject:fileToDownload];

}
Discussion
Any iOS application is maue out ol one oi moie thieaus. In iOS, a noimal application
with one view contiollei coulu initially have up to loui oi live thieaus cieateu Ly the
system liLiaiies to which the application is linkeu. At least one thieau will Le cieateu
loi youi application whethei you use multiple thieaus oi not. It is calleu the main UI
thieau attacheu to the main iun loop.
To unueistanu how uselul thieaus aie, let`s uo an expeiiment. Suppose we have thiee
loops:
- (void) firstCounter{

NSUInteger counter = 0;
for (counter = 0;
counter < 1000;
counter++){
NSLog(@"First Counter = %lu", (unsigned long)counter);
}

}
- (void) secondCounter{

NSUInteger counter = 0;
for (counter = 0;
counter < 1000;
counter++){
NSLog(@"Second Counter = %lu", (unsigned long)counter);
}

}
- (void) thirdCounter{

NSUInteger counter = 0;

6.16 Creating Concurrency with Threads | 419
www.it-ebooks.info
for (counter = 0;
counter < 1000;
counter++){
NSLog(@"Third Counter = %lu", (unsigned long)counter);
}

}
Veiy simple, aien`t they? All they uo is go liom zeio to 1,000, piinting theii countei
numLeis. Now suppose you want to iun these counteis as we woulu noimally uo:
- (void) viewDidLoad{
[super viewDidLoad];
[self firstCounter];
[self secondCounter];
[self thirdCounter];
}
This coue uoes not necessaiily have to Le in a view contiollei`s viewDid
Load methou.
Now open the console winuow anu iun this application. You will see the liist countei`s
complete iun, lolloweu Ly the seconu countei anu then the thiiu countei. This means
these loops aie Leing iun on the same thieau. Each one Llocks the iest ol the thieau`s
coue liom Leing executeu until it linishes its loop.
Vhat il we wanteu all these counteis to iun at the same time? Ol couise, we woulu
have to cieate sepaiate thieaus loi each one. But wait a minute! Ve alieauy leaineu
that the application cieates thieaus loi us when it loaus anu that whatevei coue we
have Leen wiiting so lai in the application, wheievei it was, was Leing executeu in a
thieau. So, we just have to cieate two thieaus loi the liist anu seconu counteis anu
leave the thiiu countei to uo its joL in the main thieau:
- (void) firstCounter{

@autoreleasepool {
NSUInteger counter = 0;
for (counter = 0;
counter < 1000;
counter++){
NSLog(@"First Counter = %lu", (unsigned long)counter);
}
}

}
- (void) secondCounter{

@autoreleasepool {
NSUInteger counter = 0;
420 | Chapter 6: Concurrency
www.it-ebooks.info
for (counter = 0;
counter < 1000;
counter++){
NSLog(@"Second Counter = %lu", (unsigned long)counter);
}
}

}
- (void) thirdCounter{

NSUInteger counter = 0;
for (counter = 0;
counter < 1000;
counter++){
NSLog(@"Third Counter = %lu", (unsigned long)counter);
}

}
- (void)viewDidLoad {

[super viewDidLoad];

[NSThread detachNewThreadSelector:@selector(firstCounter)
toTarget:self
withObject:nil];


[NSThread detachNewThreadSelector:@selector(secondCounter)
toTarget:self
withObject:nil];

/* Run this on the main thread */
[self thirdCounter];

}
The thirdCounter methou uoes not have an autoielease pool since it is
not iun in a new uetacheu thieau. This methou will Le iun in the ap-
plication`s main thieau, which has an autoielease pool cieateu loi it
automatically at the staitup ol eveiy Cocoa Touch application.
The calls to detachNewThreadSelector neai the enu ol the coue iun the liist anu seconu
counteis as sepaiate thieaus. Now il you iun the application, you will notice output
such as the lollowing, in the console winuow:
Second Counter = 921
Third Counter = 301
Second Counter = 922
Second Counter = 923
Second Counter = 924
First Counter = 956
6.16 Creating Concurrency with Threads | 421
www.it-ebooks.info
Second Counter = 925
First Counter = 957
Second Counter = 926
First Counter = 958
Third Counter = 302
Second Counter = 927
Third Counter = 303
Second Counter = 928
In othei woius, all thiee counteis iun at once, anu inteileave theii output ianuomly.
Eveiy thieau must cieate an autoielease pool. An autoielease pool inteinally keeps a
ieleience to oLjects that aie Leing autoieleaseu Leloie the pool itsell is ieleaseu. This
is a veiy impoitant mechanism in a ieleience-counteu memoiy management enviion-
ment such as Cocoa Touch, wheie oLjects can Le autoieleaseu. Vhenevei we allocate
instances ol oLjects, the ietain count ol the oLjects gets set to 1. Il we maik the oLjects
as autoielease, the ietain count iemains at 1, Lut when the autoielease pool in which
the oLject was cieateu is ieleaseu, the autoielease oLject is also sent a release message.
Il its ietain count is still 1 at that point, the oLject gets ueallocateu.
Eveiy thieau ieguiies an autoielease pool to Le cieateu loi it as the liist oLject that is
allocateu in that thieau. Il you uon`t uo this, any oLject that you allocate in youi thieau
will leak when the thieau exists. To unueistanu this Lettei, let`s have a look at the
lollowing coue:
- (void) autoreleaseThread:(id)paramSender{

NSBundle *mainBundle = [NSBundle mainBundle];
NSString *filePath = [mainBundle pathForResource:@"AnImage"
ofType:@"png"];

UIImage *image = [UIImage imageWithContentsOfFile:filePath];

/* Do something with the image */
NSLog(@"Image = %@", image);

}
- (void)viewDidLoad {

[super viewDidLoad];

[NSThread detachNewThreadSelector:@selector(autoreleaseThread:)
toTarget:self
withObject:self];

}
Il you iun this coue anu keep an eye on the console winuow, you will ieceive a message
similai to this:
*** __NSAutoreleaseNoPool(): Object 0x5b2c990 of
class NSCFString autoreleased with no pool in place - just leaking
*** __NSAutoreleaseNoPool(): Object 0x5b2ca30 of
422 | Chapter 6: Concurrency
www.it-ebooks.info
class NSPathStore2 autoreleased with no pool in place - just leaking
*** __NSAutoreleaseNoPool(): Object 0x5b205c0 of
class NSPathStore2 autoreleased with no pool in place - just leaking
*** __NSAutoreleaseNoPool(): Object 0x5b2d650 of
class UIImage autoreleased with no pool in place - just leaking
This shows that the autoielease UIImage instance we cieateu is cieating a memoiy leak
anu, in auuition, so is the NSString instance calleu FilePath anu othei oLjects that
woulu noimally magically get ueallocateu. This is Lecause in the thieau, we loigot
to allocate anu initialize an autoielease pool as the liist thing we uiu. The lollowing is
the coiiect coue, which you can test loi youisell to make suie it uoesn`t leak:
- (void) autoreleaseThread:(id)paramSender{

@autoreleasepool {
NSBundle *mainBundle = [NSBundle mainBundle];
NSString *filePath = [mainBundle pathForResource:@"AnImage"
ofType:@"png"];

UIImage *image = [UIImage imageWithContentsOfFile:filePath];

/* Do something with the image */
NSLog(@"Image = %@", image);
}

}
6.17 Invoking Background Methods
Problem
You want to know an easy way to cieate thieaus without having to ueal with thieaus
uiiectly.
Solution
Use the performSelectorInBackground:withObject: instance methou ol NSObject:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

[self performSelectorInBackground:@selector(firstCounter)
withObject:nil];

[self performSelectorInBackground:@selector(secondCounter)
withObject:nil];

[self performSelectorInBackground:@selector(thirdCounter)
withObject:nil];

self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
6.17 Invoking Background Methods | 423
www.it-ebooks.info
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
The countei methous aie implementeu in this way:
- (void) firstCounter{

@autoreleasepool {
NSUInteger counter = 0;
for (counter = 0;
counter < 1000;
counter++){
NSLog(@"First Counter = %lu", (unsigned long)counter);
}
}

}
- (void) secondCounter{

@autoreleasepool {
NSUInteger counter = 0;
for (counter = 0;
counter < 1000;
counter++){
NSLog(@"Second Counter = %lu", (unsigned long)counter);
}
}

}
- (void) thirdCounter{

@autoreleasepool {
NSUInteger counter = 0;
for (counter = 0;
counter < 1000;
counter++){
NSLog(@"Third Counter = %lu", (unsigned long)counter);
}
}

}
Discussion
The performSelectorInBackground:withObject: methou cieates a new thieau in the
Lackgiounu loi us. This is eguivalent to the cieating a new thieau loi the selectois. The
most impoitant thing we have to keep in minu is that since this methou cieates a thieau
on the given selectoi, the selectoi must have an autoielease pool just like any othei
thieau in a ieleience-counteu memoiy enviionment.
424 | Chapter 6: Concurrency
www.it-ebooks.info
6.18 Exiting Threads and Timers
Problem
You woulu like to stop a thieau oi a timei, oi pievent one liom liiing again.
Solution
Foi timeis, use the invalidate instance methou ol NSTimer. Foi thieaus, use the can
cel methou. Avoiu using the exit methou ol thieaus, as it uoes not give the thieau a
chance to clean up altei itsell anu youi application will enu up leaking iesouices:
NSThread *thread = /* Get the reference to your thread here */;
[thread cancel];
NSTimer *timer = /* Get the reference to your timer here */;
[timer invalidate];
Discussion
Exiting a timei is guite stiaightloiwaiu; you can simply call the timei`s invalidate
instance methou. Altei you call that methou, the timei will not liie any moie events to
its taiget oLject.
Howevei, thieaus aie a Lit moie complicateu to exit. Vhen a thieau is sleeping anu its
cancel methou is calleu, the thieau`s loop will still peiloim its task lully Leloie exiting.
Let me uemonstiate this loi you:
- (void) threadEntryPoint{

@autoreleasepool {
NSLog(@"Thread Entry Point");
while ([[NSThread currentThread] isCancelled] == NO){
[NSThread sleepForTimeInterval:4];
NSLog(@"Thread Loop");
}
NSLog(@"Thread Finished");
}

}
- (void) stopThread{

NSLog(@"Cancelling the Thread");
[self.myThread cancel];
NSLog(@"Releasing the thread");
self.myThread = nil;

}
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

6.18 Exiting Threads and Timers | 425
www.it-ebooks.info
self.myThread = [[NSThread alloc]
initWithTarget:self
selector:@selector(threadEntryPoint)
object:nil]; [self performSelector:@selector(stopThread)
withObject:nil
afterDelay:3.0f];

[self.myThread start];

self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
This coue cieates an instance ol NSThread anu staits the thieau immeuiately. The thieau
sleeps loi loui seconus in eveiy loop Leloie peiloiming its task. Howevei, Leloie the
thieau is staiteu, we aie calling the stopThread methou ol the view contiollei (which
we have wiitten) with a thiee-seconu uelay. This methou calls the cancel methou ol
the thieau in an attempt to make the thieau exit its loop. Now let`s iun the application
anu see what gets piinteu to the console scieen:
...
Thread Entry Point
Cancelling the Thread
Releasing the thread
Thread Loop
Thread Finished
You can cleaily see that the thieau linisheu its cuiient loop Leloie exiting, even though
the ieguest to cancel it was liieu in the miuule ol the loop. This is a veiy common pitlall
that can Le avoiueu simply Ly checking whethei the thieau is cancelleu Leloie at-
tempting to peiloim a task with exteinal siue ellects insiue the thieau`s loop. Ve can
iewiite the example as lollows so that the opeiation with an exteinal ellect (wiiting to
the log) checks liist to make suie the thieau hasn`t Leen cancelleu:
- (void) threadEntryPoint{

@autoreleasepool {
NSLog(@"Thread Entry Point");
while ([[NSThread currentThread] isCancelled] == NO){
[NSThread sleepForTimeInterval:4];
if ([[NSThread currentThread] isCancelled] == NO){
NSLog(@"Thread Loop");
}
}
NSLog(@"Thread Finished");
}

}
- (void) stopThread{
426 | Chapter 6: Concurrency
www.it-ebooks.info
NSLog(@"Cancelling the Thread");
[self.myThread cancel];
NSLog(@"Releasing the thread");
self.myThread = nil;

}
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

self.myThread = [[NSThread alloc]
initWithTarget:self
selector:@selector(threadEntryPoint)
object:nil];

[self performSelector:@selector(stopThread)
withObject:nil
afterDelay:3.0f];

[self.myThread start];

self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
6.18 Exiting Threads and Timers | 427
www.it-ebooks.info
www.it-ebooks.info
CHAPTER 7
Core Location and Maps
7.0 Introduction
The Coie Location anu Map Kit liamewoiks can Le useu to cieate location-awaie anu
map-Laseu applications. The Coie Location liamewoik uses the uevice`s inteinal haiu-
waie to ueteimine the cuiient location ol the uevice. The Map Kit liamewoik enaLles
youi application to uisplay maps to youi useis, put custom annotations on the maps,
anu so on. The availaLility ol location seivices liom the puie piogiamming peispective
uepenus on the availaLility ol haiuwaie on the uevice; il the haiuwaie is theie, it must
Le enaLleu anu switcheu on loi the Map Kit anu Coie Location liamewoiks to woik.
An iOS uevice with GPS seivices can use 2G, EDGE, 3G, +G, anu othei technologies
to ueteimine the usei`s location. Piesently, almost all iOS uevices suppoit location
seivices, Lut it is goou piogiamming piactice to check the availaLility ol location seiv-
ices Leloie staiting to use them, as we cannot pieuict whethei in the lutuie Apple will
ielease a uevice with all haiuwaie ieguiieu to suppoit location seivices.
To use the Coie Location anu Map Kit liamewoiks, you neeu to liist auu them to youi
pioject anu make suie appiopiiate heauei liles aie impoiteu. Follow these steps to auu
these two liamewoiks to youi pioject:
1. Click on youi pioject icon in Xcoue.
2. Select the taiget to which you want to auu the liamewoiks, as shown in Figuie 7-1.
3. Select the Builu Phases taL on the top (Figuie 7-1).
+. Expanu the Link Binaiy Vith LiLiaiies Lox anu piess the - Lutton.
5. In the uialog, you will see the list ol all availaLle liamewoiks anu static liLiaiies.
Finu anu select Loth CoreLocation.framework anu MapKit.framework anu then piess
Auu, as shown in Figuie 7-2.
Altei auuing these two liamewoiks, you will neeu to auu two heauei liles to youi .n
lile (oi to youi .h lile, il you aie ieleiiing to any entity that is incluueu in eithei ol the
two aloiementioneu liamewoiks):
429
www.it-ebooks.info
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>
7.1 Creating a Map View
Problem
You want to instantiate anu uisplay a map on a view.
Solution
Cieate an instance ol the MKMapView class anu auu it to a view oi assign it as a suLview
ol youi view contiollei. Heie is the sample .h lile ol a view contiollei that cieates an
instance ol MKMapView anu uisplays it lull-scieen on its view:
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
@interface Creating_a_Map_ViewViewController : UIViewController
@property (nonatomic, strong) MKMapView *myMapView;
@end
Iigurc 7-1. Sc|ccting thc targct to which wc want to add thc jrancwor|s
430 | Chapter 7: Core Location and Maps
www.it-ebooks.info
This is a simple ioot view contiollei with a vaiiaLle ol type MKMapView. Latei in the
implementation ol this view contiollei (.n lile), we will initialize the map anu set its
type to Satellite, like so:
#import "Creating_a_Map_ViewViewController.h"
@implementation Creating_a_Map_ViewViewController
- (void)didReceiveMemoryWarning{
[super didReceiveMemoryWarning];
}
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.myMapView = [[MKMapView alloc]
initWithFrame:self.view.bounds];
/* Set the map type to Satellite */
self.myMapView.mapType = MKMapTypeSatellite;
self.myMapView.autoresizingMask =
UIViewAutoresizingFlexibleWidth |
Iigurc 7-2. Adding thc CorcLocation and thc MapKit jrancwor|s to a projcct
7.1 Creating a Map View | 431
www.it-ebooks.info
UIViewAutoresizingFlexibleHeight;
/* Add it to our view */
[self.view addSubview:self.myMapView];
}
- (BOOL)shouldAutorotateToInterfaceOrientation
:(UIInterfaceOrientation)interfaceOrientation{
return YES;
}
@end
Discussion
Cieating an instance ol the MKMapView class is guite stiaightloiwaiu. Ve can simply
assign a liame to it using its constiuctoi, anu altei the map is cieateu, auu it as a suLview
ol the view on the scieen just so that we can see it.
MKMapView is a suLclass ol UIView, so you can manipulate any map view
the way you manipulate an instance ol UIView. Ve use a UIView piopeity,
loi instance, insetting the backgroundColor piopeity ol oui view.
Il you haven`t alieauy noticeu, the MKMapView class has a piopeity calleu mapType that
can Le set to satellite, stanuaiu, oi hyLiiu. In this example, we aie using the satellite
map type (see Figuie 7-3).
You can change the visual iepiesentation type ol a map view using the mapType piopeity
ol the MKMapView instance. Heie aie the uilleient values you can use loi this piopeity:
MKMapTypeStandard
Use this map type to uisplay a stanuaiu map (this is the uelault).
MKMapTypeSatellite
Use this map type to uisplay a satellite image map (as uepicteu in Figuie 7-3).
MKMapTypeHybrid
Use this map type to uisplay a stanuaiu map oveilaiu on a satellite image map.
7.2 Handling the Events of a Map View
Problem
You want to hanule vaiious events that a map view can senu to its uelegate.
432 | Chapter 7: Core Location and Maps
www.it-ebooks.info
Solution
Assign a uelegate oLject that conloims to the MKMapViewDelegate piotocol to the dele
gate piopeity ol an instance ol the MKMapView class:
/* Create a map as big as our view */
self.myMapView = [[MKMapView alloc]
initWithFrame:self.view.bounds];
/* Set the map type to Satellite */
self.myMapView.mapType = MKMapTypeSatellite;
self.myMapView.delegate = self;
self.myMapView.autoresizingMask =
UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;
/* Add it to our view */
[self.view addSubview:self.myMapView];
This coue can easily iun in the viewDidLoad methou ol a view contiollei oLject that has
a piopeity nameu MapView ol type MKMapView:
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
@interface Handling_the_Events_of_a_Map_ViewViewController
Iigurc 7-3. A satc||itc nap vicw
7.2 Handling the Events of a Map View | 433
www.it-ebooks.info
: UIViewController <MKMapViewDelegate>
@property (nonatomic, strong) MKMapView *myMapView;
@end
Discussion
The uelegate oLject ol an instance ol the MKMapView class must implement the methous
uelineu in the MKMapViewDelegate piotocol in oiuei to ieceive vaiious messages liom
the map view anu, as we will see latei, to pioviue inloimation to the map view. Vaiious
methous aie uelineu in the MKMapViewDelegate piotocol, such as the mapViewWill
StartLoadingMap: methou that will get calleu in the uelegate oLject whenevei the map
loauing piocess staits. Beai in minu that a uelegate loi a map view is not a ieguiieu
oLject, meaning that you can cieate map views without assigning uelegates to them;
these views simply won`t iesponu to usei manipulation.
Heie is a list ol some ol the methous ueclaieu in the MKMapViewDelegate piotocol anu
what they aie meant to iepoit to the uelegate oLject ol an instance ol MKMapView:
mapViewWillStartLoadingMap:
This methou is calleu on the uelegate oLject whenevei the map view staits to loau
the uata that visually iepiesents the map to the usei.
mapView:viewForAnnotation:
This methou is calleu on the uelegate oLject whenevei the map view is asking loi
an instance ol MKAnnotationView to visually iepiesent an annotation on the map.
Foi moie inloimation aLout this, please ielei to Recipe 7.+.
mapViewWillStartLocatingUser:
This methou, as its name implies, gets calleu on the uelegate oLject whenevei the
map view staits to uetect the usei`s location. Foi inloimation aLout linuing a usei`s
location, please ielei to Recipe 7.3.
mapView:regionDidChangeAnimated:
This methou gets calleu on the uelegate oLject whenevei the iegion uisplayeu Ly
the map changes.
See Also
Recipe 7.3; Recipe 7.+
7.3 Pinpointing the Location of a Device
Problem
You want to linu the latituue anu longituue ol a uevice.
434 | Chapter 7: Core Location and Maps
www.it-ebooks.info
Solution
Use the CLLocationManager class:
if ([CLLocationManager locationServicesEnabled]){
self.myLocationManager = [[CLLocationManager alloc] init];
self.myLocationManager.delegate = self;
self.myLocationManager.purpose =
@"To provide functionality based on user's current location.";
[self.myLocationManager startUpdatingLocation];
} else {
/* Location services are not enabled.
Take appropriate action: for instance, prompt the
user to enable location services */
NSLog(@"Location services are not enabled");
}
In this coue, myLocationManager is a piopeity ol type CLLocationManager. The cuiient
class is also the uelegate ol the location managei in this sample coue.
Discussion
The Coie Location liamewoik in the SDK pioviues lunctionality loi piogiammeis to
uetect the cuiient spatial location ol an iOS uevice. Because in iOS, the usei is alloweu
to uisaLle location seivices using Settings, Leloie instantiating an oLject ol type
CLLocationManager, it is Lest to liist ueteimine whethei location seivices aie enaLleu
on the uevice.
The uelegate oLject ol an instance ol CLLocationManager must conloim
to the CLLocationManagerDelegate piotocol.
This is how we will ueclaie oui location managei oLject in the .h lile ol a view contiollei
(the oLject cieating an instance ol CLLocationManager uoes not necessaiily have to Le a
view contiollei):
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
@interface Pinpointing_the_Location_of_a_DeviceViewController
: UIViewController <CLLocationManagerDelegate>
@property (nonatomic, strong) CLLocationManager *myLocationManager;
@end
The implementation ol oui view contiollei is as lollows:
7.3 Pinpointing the Location of a Device | 435
www.it-ebooks.info
#import "Pinpointing_the_Location_of_a_DeviceViewController.h"
@implementation Pinpointing_the_Location_of_a_DeviceViewController
- (void)didReceiveMemoryWarning{
[super didReceiveMemoryWarning];
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation{
/* We received the new location */
NSLog(@"Latitude = %f", newLocation.coordinate.latitude);
NSLog(@"Longitude = %f", newLocation.coordinate.longitude);
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error{
/* Failed to receive user's location */
}
- (void)viewDidLoad {
[super viewDidLoad]; if ([CLLocationManager locationServicesEnabled]){
self.myLocationManager = [[CLLocationManager alloc] init];
self.myLocationManager.delegate = self;
self.myLocationManager.purpose =
@"To provide functionality based on user's current location.";
[self.myLocationManager startUpdatingLocation];
} else {
/* Location services are not enabled.
Take appropriate action: for instance, prompt the
user to enable location services */
NSLog(@"Location services are not enabled");
}
}
- (BOOL)shouldAutorotateToInterfaceOrientation
:(UIInterfaceOrientation)interfaceOrientation{
return YES;
}
@end
The startUpdateLocation instance methou ol CLLocationManager iepoits the success oi
lailuie ol ietiieving the usei`s location to its uelegate thiough the locationMan
ager:didUpdateToLocation:fromLocation: methou anu the locationManager:didFailWi
thError: methou ol its uelegate oLject, in that oiuei.
436 | Chapter 7: Core Location and Maps
www.it-ebooks.info
The locationServicesEnabled class methou ol CLLocationManager is
availaLle in SDK +.0 anu latei.
The CLLocationManager class implements a piopeity nameu purpose. This piopeity al-
lows us to customize the message that is shown to the useis ol oui application, asking
whethei they will allow the use ol location seivices loi oui application using Coie
Location lunctionalities. A goou piactice is to use localizeu stiings loi the value ol this
piopeity.
7.4 Displaying Pins on a Map View
Problem
You want to point out a specilic location on a map to the usei.
Solution
Use Luilt-in map view annotations. Follow these steps:
1. Cieate a new class anu call it MyAnnotation.
2. Make suie this class conloims to the MKAnnotation piotocol.
3. Deline a piopeity loi this class ol type CLLocationCoordinate2D anu name it coor
dinate. Make suie you set it as a readonly piopeity since the coordinate piopeity
is uelineu as readonly in the MKAnnotation piotocol.
+. Optionally, ueline two piopeities ol type NSString, namely title anu subtitle,
which will Le aLle to caiiy the title anu the suLtitle inloimation loi youi annotation
view. Both ol these piopeities aie readonly as well.
5. Cieate an initializei methou loi youi class that will accept a paiametei ol type
CLLocationCoordinate2D. In this methou, assign the passeu location paiametei to
the piopeity that we uelineu in step 3. Since this piopeity is readonly, it cannot Le
assigneu Ly coue outsiue the scope ol this class. Theieloie, the initializei ol this
class acts as a Liiuge heie anu allows us to inuiiectly assign a value to this piopeity.
Ve will uo the same thing loi the title anu subtitle piopeities.
6. Instantiate the MyAnnotation class anu auu it to youi map using the addAnnota
tion: methou ol the MKMapView class.
Discussion
As explaineu in this iecipe`s Solution, we must cieate an oLject that conloims to the
MKAnnotation piotocol, anu latei instantiate this oLject anu pass it to the map to Le
uisplayeu. Ve will wiite the .h lile ol this oLject like so:
7.4 Displaying Pins on a Map View | 437
www.it-ebooks.info
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
@interface MyAnnotation : NSObject <MKAnnotation>
@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
@property (nonatomic, copy, readonly) NSString *title;
@property (nonatomic, copy, readonly) NSString *subtitle;
- (id) initWithCoordinates:(CLLocationCoordinate2D)paramCoordinates
title:(NSString *)paramTitle
subTitle:(NSString *)paramSubTitle;
@end
The .n lile ol the MyAnnotation class sets up the class to uisplay location inloimation
as lollows:
#import "MyAnnotation.h"
@implementation MyAnnotation
- (id) initWithCoordinates:(CLLocationCoordinate2D)paramCoordinates
title:(NSString *)paramTitle
subTitle:(NSString *)paramSubTitle{

self = [super init];

if (self != nil){
_coordinate = paramCoordinates;
_title = paramTitle;
_subtitle = paramSubTitle;
}

return(self);

}
@end
Latei, we will instantiate this class anu auu it to oui map, loi instance, in the .n lile ol
a view contiollei that cieates anu uisplays a map view:
#import "Displaying_Pins_on_a_Map_ViewViewController.h"
#import "MyAnnotation.h"
@implementation Displaying_Pins_on_a_Map_ViewViewController
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidLoad {
[super viewDidLoad];
438 | Chapter 7: Core Location and Maps
www.it-ebooks.info
/* Create a map as big as our view */
self.myMapView = [[MKMapView alloc]
initWithFrame:self.view.bounds];
self.myMapView.delegate = self;
/* Set the map type to Standard */
self.myMapView.mapType = MKMapTypeStandard;
self.myMapView.autoresizingMask =
UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;
/* Add it to our view */
[self.view addSubview:self.myMapView];
/* This is just a sample location */
CLLocationCoordinate2D location =
CLLocationCoordinate2DMake(50.82191692907181, -0.13811767101287842);
/* Create the annotation using the location */
MyAnnotation *annotation =
[[MyAnnotation alloc] initWithCoordinates:location
title:@"My Title"
subTitle:@"My Sub Title"];
/* And eventually add it to the map */
[self.myMapView addAnnotation:annotation];
}
- (BOOL)shouldAutorotateToInterfaceOrientation
:(UIInterfaceOrientation)interfaceOrientation{
return YES;
}
@end
Figuie 7-+ uepicts the output ol the piogiam when iun in iPhone Simulatoi.
7.5 Displaying Pins with Different Colors on a Map View
Problem
The uelault coloi loi pins uioppeu on a map view is ieu. You want to Le aLle to uisplay
pins in uilleient colois in auuition to the uelault coloi.
Solution
Retuin instances ol MKPinAnnotationView to youi map view thiough the mapView:view
ForAnnotation: uelegate methou.
7.5 Displaying Pins with Different Colors on a Map View | 439
www.it-ebooks.info
Eveiy annotation that is auueu to an instance ol MKMapView has a coiiesponuing view
that gets uisplayeu on the map view. These views aie calleu annotation vicws. An
annotation view is an oLject ol type MKAnnotationView, which is a suLclass ol UIView. Il
the uelegate oLject ol a map view implements the mapView:viewForAnnotation: uelegate
methou, the uelegate oLject will have to ietuin instances ol the MKAnnotationView class
to iepiesent (anu optionally, customize) the annotation views to Le uisplayeu on a map
view.
Discussion
To set up oui piogiam so we can customize the coloi (choosing liom the uelault SDK
pin colois) ol the annotation view that gets uioppeu on a map view to iepiesent the
annotation, we must ietuin an instance ol the MKPinAnnotationView class insteau ol an
instance ol MKAnnotationView in the mapView:viewForAnnotation: uelegate methou. Beai
in minu that the MKPinAnnotationView class is a suLclass ol the MKAnnotationView class.
- (MKAnnotationView *)mapView:(MKMapView *)mapView
viewForAnnotation:(id <MKAnnotation>)annotation{
MKAnnotationView *result = nil;
if ([annotation isKindOfClass:[MyAnnotation class]] == NO){
return result;
}
Iigurc 7-1. A bui|t-in pin droppcd on a nap
440 | Chapter 7: Core Location and Maps
www.it-ebooks.info
if ([mapView isEqual:self.myMapView] == NO){
/* We want to process this event only for the Map View
that we have created previously */
return result;
}
/* First, typecast the annotation for which the Map View has
fired this delegate message */
MyAnnotation *senderAnnotation = (MyAnnotation *)annotation;
/* Using the class method we have defined in our custom
annotation class, we will attempt to get a reusable
identifier for the pin we are about
to create */
NSString *pinReusableIdentifier =
[MyAnnotation
reusableIdentifierforPinColor:senderAnnotation.pinColor];
/* Using the identifier we retrieved above, we will
attempt to reuse a pin in the sender Map View */
MKPinAnnotationView *annotationView = (MKPinAnnotationView *)
[mapView
dequeueReusableAnnotationViewWithIdentifier:pinReusableIdentifier];
if (annotationView == nil){
/* If we fail to reuse a pin, then we will create one */
annotationView = [[MKPinAnnotationView alloc]
initWithAnnotation:senderAnnotation
reuseIdentifier:pinReusableIdentifier];
/* Make sure we can see the callouts on top of
each pin in case we have assigned title and/or
subtitle to each pin */
[annotationView setCanShowCallout:YES];
}

/* Now make sure, whether we have reused a pin or created a new one,
that the color of the pin matches the color of the annotation */
annotationView.pinColor = senderAnnotation.pinColor;
result = annotationView;
return result;
}
An annotation view must Le ieuseu Ly giving it an iuentiliei (an NSString). By uetei-
mining which type ol pin you woulu like to uisplay on a map view anu setting a unigue
iuentiliei loi each type ol pin (e.g., Llue pins can Le tieateu as one type ol pin anu ieu
pins as anothei), you must ieuse the piopei type ol pin using the dequeueReusableAnno
tationViewWithIdentifier: instance methou ol MKMapView as uemonstiateu in the coue.
Ve have set the mechanism ol ietiieving the unigue iuentilieis ol each pin in oui custom
MyAnnotation class. Heie is the .h lile ol the MyAnnotation class:
7.5 Displaying Pins with Different Colors on a Map View | 441
www.it-ebooks.info
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
/* These are the standard SDK pin colors. We are setting
unique identifiers per color for each pin so that later we
can reuse the pins that have already been created with the same
color */
#define REUSABLE_PIN_RED @"Red"
#define REUSABLE_PIN_GREEN @"Green"
#define REUSABLE_PIN_PURPLE @"Purple"
@interface MyAnnotation : NSObject <MKAnnotation>
/* unsafe_unretained since this is not an object. We can skip this and leave
it to the compiler to decide. weak or strong won't work as this is not
an object */
@property (nonatomic, unsafe_unretained, readonly)
CLLocationCoordinate2D coordinate;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *subtitle;
/* unsafe_unretained for the same reason as the coordinate property */
@property (nonatomic, unsafe_unretained) MKPinAnnotationColor pinColor;
- (id) initWithCoordinates:(CLLocationCoordinate2D)paramCoordinates
title:(NSString*)paramTitle
subTitle:(NSString*)paramSubTitle;
+ (NSString *) reusableIdentifierforPinColor
:(MKPinAnnotationColor)paramColor;
@end
Annotations aie not the same as annotation views. An annotation is the location that
you want to show on a map, anu an annotation view is the view that iepiesents that
annotation on the map. The MyAnnotation class is the annotation, not the annotation
view. Vhen we cieate an annotation Ly instantiating the MyAnnotation class, we can
assign a coloi to it using the pinColor piopeity that we have uelineu anu implementeu.
Vhen the time comes loi a map view to uisplay an annotation, the map view will call
the mapView:viewForAnnotation: uelegate methou anu ask its uelegate loi an annotation
view. The forAnnotation paiametei ol this methou passes the annotation that neeus to
Le uisplayeu. By getting a ieleience to the annotation, we can type-cast the annotation
to an instance ol MyAnnotation, ietiieve its pinColor piopeity, anu Laseu on that, cieate
an instance ol MKPinAnnotationView with the given pin coloi anu ietuin it to the map
view.
This is the .n lile ol MyAnnotation:
#import "MyAnnotation.h"
@implementation MyAnnotation
442 | Chapter 7: Core Location and Maps
www.it-ebooks.info
+ (NSString *) reusableIdentifierforPinColor
:(MKPinAnnotationColor)paramColor{

NSString *result = nil;

switch (paramColor){
case MKPinAnnotationColorRed:{
result = REUSABLE_PIN_RED;
break;
}
case MKPinAnnotationColorGreen:{
result = REUSABLE_PIN_GREEN;
break;
}
case MKPinAnnotationColorPurple:{
result = REUSABLE_PIN_PURPLE;
break;
}
}

return result;
}
- (id) initWithCoordinates:(CLLocationCoordinate2D)paramCoordinates
title:(NSString*)paramTitle
subTitle:(NSString*)paramSubTitle{

self = [super init];

if (self != nil){
_coordinate = paramCoordinates;
_title = paramTitle;
_subtitle = paramSubTitle;
_pinColor = MKPinAnnotationColorGreen;
}

return self;

}
@end
Altei implementing the MyAnnotation class, it`s time to use it in oui application (in this
example, we will use it in a view contiollei). Heie is the .h lile ol the view contiollei:
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
@interface Displaying_Pins_with_Different_Colors_on_a_Map_ViewViewController
: UIViewController <MKMapViewDelegate>
@property (nonatomic, strong) MKMapView *myMapView;
@end
7.5 Displaying Pins with Different Colors on a Map View | 443
www.it-ebooks.info
The implementation is in the .n lile like so:
#import "Displaying_Pins_with_Different_Colors_on_a_Map_ViewViewController.h"
#import "MyAnnotation.h"
@implementation
Displaying_Pins_with_Different_Colors_on_a_Map_ViewViewController
- (void)didReceiveMemoryWarning{
[super didReceiveMemoryWarning];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView
viewForAnnotation:(id <MKAnnotation>)annotation{
MKAnnotationView *result = nil;
if ([annotation isKindOfClass:[MyAnnotation class]] == NO){
return result;
}
if ([mapView isEqual:self.myMapView] == NO){
/* We want to process this event only for the Map View
that we have created previously */
return result;
}
/* First typecast the annotation for which the Map View has
fired this delegate message */
MyAnnotation *senderAnnotation = (MyAnnotation *)annotation;
/* Using the class method we have defined in our custom
annotation class, we will attempt to get a reusable
identifier for the pin we are about
to create */ NSString *pinReusableIdentifier =
[MyAnnotation
reusableIdentifierforPinColor:senderAnnotation.pinColor];
/* Using the identifier we retrieved above, we will
attempt to reuse a pin in the sender Map View */
MKPinAnnotationView *annotationView = (MKPinAnnotationView *)
[mapView
dequeueReusableAnnotationViewWithIdentifier:pinReusableIdentifier];
if (annotationView == nil){
/* If we fail to reuse a pin, then we will create one */
annotationView = [[MKPinAnnotationView alloc]
initWithAnnotation:senderAnnotation
reuseIdentifier:pinReusableIdentifier];
/* Make sure we can see the callouts on top of
each pin in case we have assigned title and/or
subtitle to each pin */
[annotationView setCanShowCallout:YES];
}
444 | Chapter 7: Core Location and Maps
www.it-ebooks.info
/* Now make sure, whether we have reused a pin or not, that
the color of the pin matches the color of the annotation */
annotationView.pinColor = senderAnnotation.pinColor;
result = annotationView;
return result;
}
- (void)viewDidLoad {
[super viewDidLoad];
/* Create a map as big as our view */
self.myMapView = [[MKMapView alloc]
initWithFrame:self.view.bounds];
self.myMapView.delegate = self;
/* Set the map type to Standard */
self.myMapView.mapType = MKMapTypeStandard;
self.myMapView.autoresizingMask =
UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;
/* Add it to our view */
[self.view addSubview:self.myMapView];
/* This is just a sample location */
CLLocationCoordinate2D location;
location.latitude = 50.82191692907181;
location.longitude = -0.13811767101287842;
/* Create the annotation using the location */
MyAnnotation *annotation =
[[MyAnnotation alloc] initWithCoordinates:location
title:@"My Title"
subTitle:@"My Sub Title"];
annotation.pinColor = MKPinAnnotationColorPurple;
/* And eventually add it to the map */
[self.myMapView addAnnotation:annotation];
}
- (BOOL)shouldAutorotateToInterfaceOrientation
:(UIInterfaceOrientation)interfaceOrientation{
return YES;
}
@end
The iesults aie shown in Figuie 7-5.
7.5 Displaying Pins with Different Colors on a Map View | 445
www.it-ebooks.info
7.6 Displaying Custom Pins on a Map View
Problem
Insteau ol the uelault iOS SDK pins, you woulu like to uisplay youi own images as pins
on a map view.
Solution
Loau an aiLitiaiy image into an instance ol the UIImage class anu assign it to the
image piopeity ol the MKAnnotationView instance that you ietuin to youi map view as
a pin:
- (MKAnnotationView *)mapView:(MKMapView *)mapView
viewForAnnotation:(id <MKAnnotation>)annotation{
MKAnnotationView *result = nil;
if ([annotation isKindOfClass:[MyAnnotation class]] == NO){
return result;
} if ([mapView isEqual:self.myMapView] == NO){
/* We want to process this event only for the Map View
that we have created previously */
return result;
}
Iigurc 7-5. A pin with an a|tcrnativc co|or disp|aycd on a nap vicw
446 | Chapter 7: Core Location and Maps
www.it-ebooks.info
/* First typecast the annotation for which the Map View has
fired this delegate message */
MyAnnotation *senderAnnotation = (MyAnnotation *)annotation;
/* Using the class method we have defined in our custom
annotation class, we will attempt to get a reusable
identifier for the pin we are about to create */
NSString *pinReusableIdentifier =
[MyAnnotation
reusableIdentifierforPinColor:senderAnnotation.pinColor];
/* Using the identifier we retrieved above, we will
attempt to reuse a pin in the sender Map View */
MKPinAnnotationView *annotationView = (MKPinAnnotationView *)
[mapView
dequeueReusableAnnotationViewWithIdentifier:
pinReusableIdentifier];
if (annotationView == nil){
/* If we fail to reuse a pin, then we will create one */
annotationView =
[[MKPinAnnotationView alloc] initWithAnnotation:senderAnnotation
reuseIdentifier:pinReusableIdentifier];
/* Make sure we can see the callouts on top of
each pin in case we have assigned title and/or
subtitle to each pin */
annotationView.canShowCallout = YES;
}
UIImage *pinImage = [UIImage imageNamed:@"BluePin.png"];
if (pinImage != nil){
annotationView.image = pinImage;
}
result = annotationView;
return result;
}
In this coue, we aie uisplaying an image nameu B|ucPin.png (in oui application Lunule)
loi any pin that is uioppeu on the map. Foi the uelinition anu the implementation ol
the MyAnnotation class, ielei to Recipe 7.5.
Discussion
The uelegate oLject ol an instance ol the MKMapView class must conloim to the MKMap
ViewDelegate piotocol anu implement the mapView:viewForAnnotation: methou. The
ietuin value ol this methou is an instance ol the MKAnnotationView class. Any oLject
that suLclasses the aloiementioneu class, Ly uelault, inheiits a piopeity calleu image.
7.6 Displaying Custom Pins on a Map View | 447
www.it-ebooks.info
Assigning a value to this piopeity will ieplace the uelault image pioviueu Ly the Map
Kit liamewoik, as shown in Figuie 7-6.
See Also
Recipe 7.5
Iigurc 7-. A custon inagc disp|aycd on a nap vicw
7.7 Converting Meaningful Addresses to Longitude and
Latitude
Problem
You have an auuiess ol a location anu you want to linu the spatial location (|ongitudc,
|atitudc) ol that auuiess.
Solution
Use the geocodeAddressString:completionHandler: methou ol the CLGeocoder class.
448 | Chapter 7: Core Location and Maps
www.it-ebooks.info
Discussion
Rcvcrsc gcocoding is the piocess ol ietiieving a meaninglul auuiess, city anu countiy,
anu so on, using spatial locations (Longitudc, Latitudc). Gcocoding, on the othei hanu,
is the piocess ol linuing the spatial locations ol a given auuiess. Both geocouing anu
ieveise geocouing lacilities aie encapsulateu into the CLGeocoder class in the Coie Lo-
cation liamewoik.
Ve geocoue spatial locations Ly passing the auuiess as NSString to the geocodeAddress
String:completionHandler: methou ol the CLGeocoder class. The completionHandler
paiametei ol this methou accepts a Llock oLject that ietuins no value anu has two
paiameteis:
1. A placemaiks aiiay (ol type NSArray), which will Le set to the locations that match-
eu youi seaich.
2. An eiioi (ol type NSError), which will get set to an eiioi coue il the geocouing lails.
Let`s go aheau anu ueclaie a piopeity ol type CLGeocoder liist:
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
@interface
Converting_Meaningful_Addresses_to_Longitude_and_LatitudeViewController
: UIViewController
@property (nonatomic, strong) CLGeocoder *myGeocoder;
@end
Now, let`s go aheau anu implement the coue to geocoue an auuiess:
- (void)didReceiveMemoryWarning{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidLoad{
[super viewDidLoad]; /* We have our address */
NSString *oreillyAddress =
@"1005 Gravenstein Highway North, Sebastopol, CA 95472, USA";
self.myGeocoder = [[CLGeocoder alloc] init];
[self.myGeocoder
geocodeAddressString:oreillyAddress
completionHandler:^(NSArray *placemarks, NSError *error) {
if ([placemarks count] > 0 &&
error == nil){
NSLog(@"Found %lu placemark(s).", (unsigned long)[placemarks count]);
CLPlacemark *firstPlacemark = [placemarks objectAtIndex:0];
NSLog(@"Longitude = %f", firstPlacemark.location.coordinate.longitude);
NSLog(@"Latitude = %f", firstPlacemark.location.coordinate.latitude);
7.7 Converting Meaningful Addresses to Longitude and Latitude | 449
www.it-ebooks.info
}
else if ([placemarks count] == 0 &&
error == nil){
NSLog(@"Found no placemarks.");
}
else if (error != nil){
NSLog(@"An error occurred = %@", error);
}
}];
}
Once the piogiam is iun, even in the simulatoi, you will get the lollowing values piinteu
to the console winuow il you have a woiking anu active netwoik connection:
Found 1 placemark(s).
Longitude = -122.841135
Latitude = 38.410373
7.8 Converting Longitude and Latitude to a Meaningful
Address
Problem
You have the latituue anu longituue ol a spatial location anu you want to ietiieve the
auuiess ol this location.
Solution
Retiieving a meaninglul auuiess using spatial x anu y cooiuinates is calleu rcvcrsc
gcocoding. To uo this, cieate anu use an instance ol the CLGeocoder class anu pioviue a
completion Llock oLject, making suie that the Llock oLject has no ietuin value anu
accepts two paiameteis:
1. A placemaiks aiiay (ol type NSArray), which will Le set to the locations which
matcheu youi seaich.
2. An eiioi (ol type NSError), which will get set to an eiioi coue il the ieveise geo-
couing lails.
Altei instantiating an oLject ol type CLGeocoder, we will use its reverseGeocodeLoca
tion:completionHandler: methou to uo the ieveise geocouing.
The .h lile ol a simple view contiollei loi this puipose is uelineu like so:
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
@interface
Converting_Longitude_and_Latitude_to_a_Meaningful_AddressViewController
450 | Chapter 7: Core Location and Maps
www.it-ebooks.info
: UIViewController
@property (nonatomic, strong) CLGeocoder *myGeocoder;
@end
You can uo the ieveise geocouing when youi view loaus:
- (void)viewDidLoad{
[super viewDidLoad];
CLLocation *location = [[CLLocation alloc]
initWithLatitude:+38.4112810
longitude:-122.8409780f];
self.myGeocoder = [[CLGeocoder alloc] init];
[self.myGeocoder
reverseGeocodeLocation:location
completionHandler:^(NSArray *placemarks, NSError *error) {
if (error == nil &&
[placemarks count] > 0){
CLPlacemark *placemark = [placemarks objectAtIndex:0];
/* We received the results */
NSLog(@"Country = %@", placemark.country);
NSLog(@"Postal Code = %@", placemark.postalCode);
NSLog(@"Locality = %@", placemark.locality);
}
else if (error == nil &&
[placemarks count] == 0){
NSLog(@"No results were returned.");
}
else if (error != nil){
NSLog(@"An error occurred = %@", error);
}
}];
}
The placemarks aiiay, il the opeiation is successlul, will contain oLjects ol type
CLPlacemark, which maik the auuiesses that match the longituue anu latituue we passeu
to the reverseGeocodeLocation:completionHandler: methou. So all we have to uo is
make suie that theie weie no eiiois, anu that the aiiay ol placemaiks contains at least
one placemaik.
The NSLog methous in the pieceuing coue wiite the ieveise geocoueu auuiess to the
console winuow:
Country = United States
Postal Code = 95472
Locality = Sebastopol
7.8 Converting Longitude and Latitude to a Meaningful Address | 451
www.it-ebooks.info
Discussion
Each application has a limit on the numLei ol ieveise geocouing ieguests that it can
make each uay. The amount uepenus on the Lackenu pioviuei loi the location seivices
in iOS. Theie aie vaiious paiu online seivices that expose thiiu paity APIs to uevelopeis.
I cannot piomote any ol these seivices, Lut leel liee to Liowse the Inteinet loi them il
you woulu like to get iiu ol limitations that cuiiently exist in iOS SDK loi ieveise
geocouing spatial cooiuinates. To peiloim a ieveise geocouing ieguest, you must cieate
an instance ol the CLGeocoder class. This class ieguiies an active netwoik connection
in oiuei to piocess ieguests successlully. The ieveise geocoueu values aie iepoiteu to
the completion hanulei Llock that is passeu to the reverseGeocodeLocation:completion
Handler: methou.
452 | Chapter 7: Core Location and Maps
www.it-ebooks.info
CHAPTER 8
Implementing Gesture Recognizers
8.0 Introduction
Gestuies aie a comLination ol touch events. An example ol a gestuie can Le lounu in
the uelault iOS Photo application, which allows the usei to zoom into anu out ol a
photo while pinching the photo in anu out using two lingeis. Some ol the most
common gestuie event uetection coue is encapsulateu into ieusaLle classes Luilt into
the iOS SDK. These classes can Le useu to uetect swipe, pinch, pan, tap, uiag, long
piess, anu iotation gestuies.
Gestuie iecognizeis must Le auueu to instances ol the UIView class. A single view can
have moie than one gestuie iecognizei. Once a view catches the gestuie, that view will
Le iesponsiLle loi passing uown the same gestuie to othei views in the hieiaichy, il
neeueu.
Some touch events ieguiieu Ly an application might Le complicateu to piocess anu
might ieguiie the same event to Le uetectaLle in othei views in the same application.
This intiouuces the ieguiiements loi ieusaLle gestuie iecognizeis. Theie aie six gestuie
iecognizeis in iOS SDK 5 anu aLove:
Swipe
Rotation
Pinch
Pan
Long piess
Tap
The Lasic liamewoik loi hanuling a gestuie thiough a Luilt-in gestuie iecognizei is as
lollows:
453
www.it-ebooks.info
1. Cieate an oLject ol the iight uata type loi the gestuie iecognizei you want.
2. Auu this oLject as a gestuie iecognizei to the view that will ieceive the gestuie.
3. Viite a methou that is calleu when the gestuie occuis anu that takes the action
you want.
The methou associateu as the taiget methou ol any gestuie iecognizei must lollow
these iules:
It must ietuin void.
It must eithei accept no paiameteis, oi accept a single paiametei ol type UIGesture
Recognizer in which the system will pass the gestuie iecognizei that calls this
methou.
Heie aie two examples:
- (void) tapRecognizer:(UITapGestureRecognizer *)paramSender{
/* */
}
- (void) tapRecognizer{
/* */
}
Gestuie iecognizeis aie uiviueu into two categoiies: discrctc anu continuous. Disciete
gestuie iecognizeis uetect theii gestuie events anu, once uetecteu, call a methou in theii
iespective owneis. Continuous gestuie iecognizeis keep theii ownei oLjects inloimeu
ol the events as they happen, anu will call the methou in theii taiget oLject iepeateuly
as the event happens anu until it enus.
Foi instance, a uouLle-tap event is uisciete. Even though it consists ol two taps, the
system iecognizes that the taps occuiieu close enough togethei to Le tieateu as a single
event. The uouLle-tap gestuie iecognizei calls the methou in its taiget oLject once the
uouLle-tap event is uetecteu.
An example ol a continuous gestuie iecognizei is iotation. This gestuie staits as soon
as the usei staits the iotation anu only linishes when the usei lilts his lingeis oll the
scieen. The methou pioviueu to the iotation gestuie iecognizei class gets calleu at shoit
inteivals until the event is linisheu.
Gestuie iecognizeis can Le auueu to any instance ol the UIView class using the addGes
tureRecognizer: methou ol the view, anu when neeueu, they can Le iemoveu liom the
view using the removeGestureRecognizer: methou.
The UIGestureRecognizer class has a piopeity nameu state. The state piopeity iepie-
sents the uilleient states the gestuie iecognizei can have thioughout the iecognition
piocess. Disciete anu continuous gestuie iecognizeis go thiough uilleient sets ol states.
Disciete gestuie iecognizeis can pass thiough the lollowing states:
454 | Chapter 8: Implementing Gesture Recognizers
www.it-ebooks.info
1. UIGestureRecognizerStatePossible
2. UIGestureRecognizerStateRecognized
3. UIGestureRecognizerStateFailed
Depenuing on the situation, a uisciete gestuie iecognizei might senu the UIGestureRe
cognizerStateRecognized state to its taiget, oi it might senu the UIGestureRecognizer
StateFailed state il an eiioi occuis uuiing the iecognition piocess.
Continuous gestuie iecognizeis take a uilleient path in the states they senu to theii
taigets:
1. UIGestureRecognizerStatePossible
2. UIGestureRecognizerStateBegan
3. UIGestureRecognizerStateChanged
+. UIGestureRecognizerStateEnded
5. UIGestureRecognizerStateFailed
A gestuie iecognizei`s state is changeu to UIGestureRecognizerStatePos
sible when it is gatheiing inloimation aLout touch events on a view anu
night at any point uetect the ielevant gestuie. In auuition to the aloie-
mentioneu states ol a continuous gestuie iecognizei, the UIGestureRe
cognizerStateCancelled state can also Le geneiateu il anything intei-
iupts the gestuie. Foi instance, an incoming phone call can inteiiupt a
pan gestuie. In that case, the state ol the gestuie iecognizei will Le
changeu to UIGestureRecognizerStateCancelled anu no luithei messag-
es will Le calleu on the ieceivei oLject Ly that gestuie iecognizei unless
the usei iestaits the gestuie seguence.
Again, il the continuous gestuie iecognizei stumLles upon a situation that cannot Le
lixeu inteinally, it will enu with the UIGestureRecognizerStateFailed state insteau ol
UIGestureRecognizerStateEnded.
8.1 Detecting Swipe Gestures
Problem
You want to Le aLle to uetect when the usei peiloims a swipe gestuie on a viewloi
instance, swiping a pictuie out ol the winuow.
Solution
Instantiate an oLject ol type UISwipeGestureRecognizer anu auu it to an instance ol
UIView:
8.1 Detecting Swipe Gestures | 455
www.it-ebooks.info
- (void)viewDidLoad {
[super viewDidLoad];

/* Instantiate the object */
self.swipeGestureRecognizer = [[UISwipeGestureRecognizer alloc]
initWithTarget:self
action:@selector(handleSwipes:)];

/* Swipes that are performed from right to
left are to be detected */
self.swipeGestureRecognizer.direction =
UISwipeGestureRecognizerDirectionLeft;

/* Just one finger needed */
self.swipeGestureRecognizer.numberOfTouchesRequired = 1;

/* Add it to the view */
[self.view addGestureRecognizer:self.swipeGestureRecognizer];

}
A gestuie iecognizei coulu Le cieateu as a stanualone oLject, Lut heie, Lecause we aie
using it just loi one view, we have cieateu it as a piopeity ol the view contiollei that
will ieceive the gestuie (self.swipeGestureRecognizer). This iecipe`s Discussion shows
the handleSwipes: methou useu in this coue as the taiget loi the swipe gestuie iecog-
nizei.
Discussion
The swipe gestuie is one ol the most stiaightloiwaiu motions that Luilt-in iOS SDK
gestuie iecognizeis will iegistei. It is a simple movement ol one oi moie lingeis on a
view liom one uiiection to anothei. The UISwipeGestureRecognizer, like othei gestuie
iecognizeis, inheiits liom the UIGestureRecognizer class anu auus vaiious lunctional-
ities to this class, such as piopeities that allow us to specily the uiiection in which the
swipe gestuies have to Le peiloimeu in oiuei to Le uetecteu, oi how many lingeis the
usei has to holu on the scieen to Le aLle to peiloim a swipe gestuie. Please Leai in minu
that swipe gestuies aie uisciete gestuies.
The handleSwipes: methou that we useu loi the gestuie iecognizei instance can Le
implementeu in this way:
- (void) handleSwipes:(UISwipeGestureRecognizer *)paramSender{

if (paramSender.direction & UISwipeGestureRecognizerDirectionDown){
NSLog(@"Swiped Down.");
}
if (paramSender.direction & UISwipeGestureRecognizerDirectionLeft){
NSLog(@"Swiped Left.");
}
if (paramSender.direction & UISwipeGestureRecognizerDirectionRight){
NSLog(@"Swiped Right.");
}
456 | Chapter 8: Implementing Gesture Recognizers
www.it-ebooks.info
if (paramSender.direction & UISwipeGestureRecognizerDirectionUp){
NSLog(@"Swiped Up.");
}

}
You can comLine moie than one uiiection in the direction piopeity ol
an instance ol the UISwipeGestureRecognizer class Ly using the Litwise
OR opeianu. In OLjective-C, this is uone with the pipe (|) chaiactei.
Foi instance, to uetect uiagonal swipes to the Lottom-lelt coinei ol the
scieen, you can comLine the UISwipeGestureRecognizerDirectionLeft
anu UISwipeGestureRecognizerDirectionDown values using the pipe chai-
actei when constiucting youi swipe gestuie iecognizei. In the example,
we aie attempting to uetect only swipes liom the iight siue to the lelt.
Although swipe gestuies aie usually peiloimeu with one lingei, the numLei ol lingeis
ieguiieu loi the swipe gestuie to Le iecognizeu can also Le specilieu with the number
OfTouchesRequired piopeity ol the UISwipeGestureRecognizer class.
8.2 Detecting Rotation Gestures
Problem
You want to uetect when a usei is attempting to iotate an element on the scieen using
hei lingeis.
Solution
Cieate an instance ol the UIRotationGestureRecognizer class anu attach it to youi taiget
view:
- (void)viewDidLoad {
[super viewDidLoad];

self.view.backgroundColor = [UIColor whiteColor];
self.helloWorldLabel = [[UILabel alloc] initWithFrame:CGRectZero];
self.helloWorldLabel.text = @"Hello, World!";
self.helloWorldLabel.font = [UIFont systemFontOfSize:16.0f];
[self.helloWorldLabel sizeToFit];
self.helloWorldLabel.center = self.view.center;
[self.view addSubview:self.helloWorldLabel];

self.rotationGestureRecognizer = [[UIRotationGestureRecognizer alloc]
initWithTarget:self
action:@selector(handleRotations:)];

[self.view addGestureRecognizer:self.rotationGestureRecognizer];

}
8.2 Detecting Rotation Gestures | 457
www.it-ebooks.info
Discussion
The UIRotationGestureRecognizer, as its name implies, is the peilect canuiuate among
gestuie iecognizeis to uetect iotation gestuies anu to help you Luilu moie intuitive
giaphical usei inteilaces. Foi instance, when the usei encounteis an image on the scieen
in youi application in lull-scieen moue, it is guite intuitive loi him to attempt to coiiect
the oiientation Ly iotating the image.
The UIRotationGestureRecognizer class implements a piopeity nameu rotation that
specilies the total amount anu uiiection ol iotation ieguesteu Ly the usei`s gestuie, in
iauians. The iotation is ueteimineu liom the lingeis` initial position (UIGestureRecog
nizerStateBegan) anu linal position (UIGestureRecognizerStateEnded).
To iotate UI elements that inheiit liom UIView class, you can pass the rotation piopeity
ol the iotation gestuie iecognizei to the CGAffineTransformMakeRotation lunction to
make an alline tiansloim, as shown in the example.
The coue in this iecipe`s Solution passes the cuiient oLject, in this case a view contiollei,
to the taiget ol the iotation gestuie iecognizei. The taiget selectoi is specilieu as han
dleRotations:, a methou we have to implement. But Leloie we uo that, let`s have a look
at the heauei lile ol the view contiollei:
#import <UIKit/UIKit.h>
@interface Detecting_Rotation_GesturesViewController : UIViewController
@property (nonatomic, strong)
UIRotationGestureRecognizer *rotationGestureRecognizer;
@property (nonatomic, strong)
UILabel *helloWorldLabel;
/* We can remove the nonatomic and the unsafe_unretained marks from this
property declaration. On a float value, the compiler will generate both
these for us automatically */
@property (nonatomic, unsafe_unretained)
CGFloat rotationAngleInRadians;
@end
Beloie we caiiy on, let`s have a look at what each one ol these piopeities uoes anu why
they aie ueclaieu:
helloWorldLabel
This is a laLel we must cieate on the view ol the view contiollei. Then we will wiite
the coue to iotate this laLel whenevei the usei attempts to peiloim iotation gestuies
on the view that owns this laLel (in this case, the view ol the view contiollei).
rotationGestureRecognizer
This is the instance ol the iotation gestuie iecognizei that we will latei allocate anu
initialize.
458 | Chapter 8: Implementing Gesture Recognizers
www.it-ebooks.info
rotationAngleInRadians
This is the value we will gueiy as the exact iotation angle ol oui laLel. Initially we
will set this to zeio. Since the iotation angles iepoiteu Ly a iotation gestuie iecog-
nizei aie ieset eveiy time the iotation gestuie is staiteu again, we can keep the value
ol the iotation gestuie iecognizei whenevei it goes into the UIGestureRecognizer
StateEnded state. The next time the gestuie is staiteu, we will auu the pievious
value to the new value to get an oveiall iotation angle.
The size anu the oiigin ol the laLel uoes not mattei much. Even the position ol the laLel
isn`t that impoitant, as we will only attempt to iotate the laLel aiounu its centei, no
mattei wheie on the view the laLel is positioneu. The only impoitant thing to iememLei
is that in univeisal applications, the position ol a laLel on a view contiollei useu in
uilleient taigets (uevices) must Le calculateu uynamically using the size ol its paient
view. Otheiwise, on uilleient uevices such as the iPau oi the iPhone, it might appeai
in uilleient places on the scieen.
Using the center piopeity ol the laLel, anu setting that centei location to the centei ol
the containing view, we will centei-align the contents ol the laLel. The iotation tians-
loimation that we will apply to this laLel iotates the laLel aiounu its centeianu lelt-
aligneu oi iight-aligneu laLels whose actual liame is Liggei than the minimum liame
ieguiieu to holu theii contents without tiuncation will appeai to Le iotating in an
unnatuial way anu not on the centei. Il you aie cuiious, go aheau anu lelt- oi iight-
align the contents ol the laLel anu see what happens.
As we saw in this iecipe`s Solution, the iotation gestuie iecognizei that we cieateu will
senu its events to a methou calleu handleRotations:. Heie is the implementation loi
this methou:
- (void) handleRotations:(UIRotationGestureRecognizer *)paramSender{

if (self.helloWorldLabel == nil){
return;
}

/* Take the previous rotation and add the current rotation to it */
self.helloWorldLabel.transform =
CGAffineTransformMakeRotation(self.rotationAngleInRadians +
paramSender.rotation);

/* At the end of the rotation, keep the angle for later use */
if (paramSender.state == UIGestureRecognizerStateEnded){
self.rotationAngleInRadians += paramSender.rotation;
}

}
The way a iotation gestuie iecognizei senus us the iotation angles is veiy inteiesting.
This gestuie iecognizei is continuous, which means it staits linuing the angles as soon
as the usei Legins hei iotation gestuie, anu senus upuates to the hanulei methou at
lieguent inteivals until the usei is uone. Each message tieats the staiting angle as zeio
8.2 Detecting Rotation Gestures | 459
www.it-ebooks.info
anu iepoits the uilleience Letween the message`s staiting point (which is the angle
wheie the pievious message lelt oll) anu its enuing point. Thus, the complete ellect ol
the gestuie can Le uiscoveieu only Ly auuing up the angles iepoiteu Ly the uilleient
events. Clockwise movement piouuces a positive angulai value, wheieas counteiclock-
wise movement piouuces a negative value.
Il you aie using iPhone Simulatoi insteau ol a ieal uevice, you can still
simulate the iotation gestuie Ly holuing uown the Option key in the
simulatoi. You will see two ciicles appeai on the simulatoi at the same
uistance liom the centei ol the scieen, iepiesenting two lingeis. Il you
want to shilt these lingeis liom the centei to anothei location while
holuing uown the Alt key, piess the Shilt key anu point somewheie else
on the scieen. Vheie you leave youi pointei will Lecome the new centei
loi these two lingeis.
Now we will simply assign this angle to the iotation angle ol the laLel. But can you
imagine what will happen once the iotation is linisheu anu anothei one staits? The
seconu iotation gestuie`s angle will ieplace that ol the liist iotation in the rotation
value iepoiteu to the hanulei. Foi this ieason, whenevei a iotation gestuie is linisheu,
we must keep the cuiient iotation ol the laLel. The value in each iotation gestuie`s
angle must Le auueu in tuin, anu we must assign the iesult to the laLel`s iotation
tiansloimation as we saw Leloie.
As we saw eailiei, we useu the CGAffineTransformMakeRotation lunction to cieate an
alline tiansloimation. Functions in the iOS SDK that stait with CG ielei to the Coie
Giaphics liamewoik. Foi piogiams that use Coie Giaphics to compile anu link suc-
cesslully, you must make suie the Coie Giaphics liamewoik is auueu to the list ol
liamewoiks. New veisions ol Xcoue link a uelault pioject against the CoieGiaphics
liamewoik automatically, so you uon`t ieally have to woiiy aLout that.
Now that we aie suie Coie Giaphics is auueu to the taiget, we can compile anu iun
the app.
See Also
Recipe S.6
8.3 Detecting Panning and Dragging Gestures
Problem
You want the useis ol youi application to Le aLle to move GUI elements aiounu using
theii lingeis.
460 | Chapter 8: Implementing Gesture Recognizers
www.it-ebooks.info
Pan gestuies aie continuous movements ol lingeis on the scieen; iecall
that swipe gestuies weie uisciete gestuies. This means the methou set
as the taiget methou ol a pan gestuie iecognizei gets calleu iepeateuly
liom the Leginning to the enu ol the iecognition piocess.
Solution
Use the UIPanGestureRecognizer class:
- (void)viewDidLoad {
[super viewDidLoad];

self.view.backgroundColor = [UIColor whiteColor];

/* Let's first create a label */
CGRect labelFrame = CGRectMake(0.0f, /* X */
0.0f, /* Y */
150.0f, /* Width */
100.0f); /* Height */

self.helloWorldLabel = [[UILabel alloc] initWithFrame:labelFrame];
self.helloWorldLabel.text = @"Hello World";
self.helloWorldLabel.backgroundColor = [UIColor blackColor];
self.helloWorldLabel.textColor = [UIColor whiteColor];
self.helloWorldLabel.textAlignment = UITextAlignmentCenter;

/* Make sure to enable user interaction; otherwise, tap events
won't be caught on this label */
self.helloWorldLabel.userInteractionEnabled = YES;

/* And now make sure this label gets displayed on the view */
[self.view addSubview:self.helloWorldLabel];

/* Create the Pan Gesture Recognizer */
self.panGestureRecognizer = [[UIPanGestureRecognizer alloc]
initWithTarget:self
action:@selector(handlePanGestures:)];

/* At least and at most we need only one finger to activate
the pan gesture recognizer */
self.panGestureRecognizer.minimumNumberOfTouches = 1;
self.panGestureRecognizer.maximumNumberOfTouches = 1;

/* Add it to the view */
[self.helloWorldLabel addGestureRecognizer:self.panGestureRecognizer];

}
The pan gestuie iecognizei will call the handlePanGestures: methou as its taiget meth-
ou. This methou is uesciiLeu in this iecipe`s Discussion.
8.3 Detecting Panning and Dragging Gestures | 461
www.it-ebooks.info
Discussion
The UIPanGestureRecognizer, as its name implies, can uetect pan gcsturcs. The pan
gestuie iecognizei will go thiough the lollowing states while iecognizing the pan ges-
tuie:
1. UIGestureRecognizerStateBegan
2. UIGestureRecognizerStateChanged
3. UIGestureRecognizerStateEnded
Ve can implement the gestuie iecognizei taiget methou as lollows. The coue will
continuously move the centei ol the laLel along with the usei`s lingei as UIGestureRe
cognizerStateChanged events aie iepoiteu:
- (void) handlePanGestures:(UIPanGestureRecognizer*)paramSender{

if (paramSender.state != UIGestureRecognizerStateEnded &&
paramSender.state != UIGestureRecognizerStateFailed){
CGPoint location = [paramSender locationInView:paramSender.view.superview];
paramSender.view.center = location;
}

}
To Le aLle to move the laLel on the view ol the view contiollei, we neeu
the position ol the lingei on the view, not the laLel. Foi this ieason, we
aie calling the locationInView: methou ol the pan gestuie iecognizei
anu passing the supeiview ol the laLel as the taiget view.
Use the locationInView: methou ol the pan gestuie iecognizei to linu the point ol the
cuiient panning lingei(s). To uetect multiple lingei locations, use the location
OfTouch:inView: methou. Using the minimumNumberOfTouches anu maximumNumberOf
Touches piopeities ol the UIPanGestureRecognizer, you can uetect moie than one pan-
ning touch at a time. In the example, loi the sake ol simplicity, we aie tiying to uetect
only one lingei.
Duiing the UIGestureRecognizerStateEnded state, the iepoiteu x anu y
values might not Le a numLei; in othei woius, they coulu Le egual to
NAN. That is why we neeu to avoiu using the iepoiteu values uuiing this
paiticulai state.
462 | Chapter 8: Implementing Gesture Recognizers
www.it-ebooks.info
8.4 Detecting Long Press Gestures
Problem
You want to Le aLle to uetect when the usei taps anu holus his lingei on a view loi a
ceitain peiiou ol time.
Solution
Cieate an instance ol the UILongPressGestureRecognizer class anu auu it to the view
that has to uetect long tap gestuies. The .h lile ol the view contiollei is uelineu in this
way:
#import <UIKit/UIKit.h>
@interface Detecting_Long_Press_GesturesViewController : UIViewController
@property (nonatomic, strong)
UILongPressGestureRecognizer *longPressGestureRecognizer;
@property (nonatomic, strong) UIButton *dummyButton;
@end
Heie is the viewDidLoad instance methou ol the view contiollei that uses the long piess
gestuie iecognizei that we uelineu in the .n lile:
- (void)viewDidLoad {
[super viewDidLoad];

self.view.backgroundColor = [UIColor whiteColor];

self.dummyButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.dummyButton.frame = CGRectMake(0.0f,
0.0f,
72.0f,
37.0f);
self.dummyButton.center = self.view.center;
[self.view addSubview:self.dummyButton];

/* First create the gesture recognizer */
self.longPressGestureRecognizer =
[[UILongPressGestureRecognizer alloc]
initWithTarget:self
action:@selector(handleLongPressGestures:)];

/* The number of fingers that must be present on the screen */
self.longPressGestureRecognizer.numberOfTouchesRequired = 2;

/* Maximum 100 points of movement allowed before the gesture
is recognized */
self.longPressGestureRecognizer.allowableMovement = 100.0f;

8.4 Detecting Long Press Gestures | 463
www.it-ebooks.info
/* The user must press two fingers (numberOfTouchesRequired) for
at least one second for the gesture to be recognized */
self.longPressGestureRecognizer.minimumPressDuration = 1.0;

/* Add this gesture recognizer to the view */
[self.view addGestureRecognizer:self.longPressGestureRecognizer];

}
Il the long-piess gestuie iecognizei is liiing events to the ieceivei oLject
while the gestuie is continuing on the usei`s enu, anu a phone call oi
any othei inteiiuption comes in, the state ol the gestuie iecognizei will
Le changeu to UIGestureRecognizerStateCancelled. No luithei messag-
es will Le sent to the ieceivei oLject liom that gestuie iecognizei until
the usei initiates the actions ieguiieu to stait the iecognition piocess
again; in this example, holuing two lingeis loi at least one seconu on
the view ol oui view contiollei.
Oui coue iuns on a view contiollei with a piopeity nameu longPress
GestureRecognizer ol type UILongPressGestureRecognizer. Foi moie in-
loimation, ielei to this iecipe`s Discussion.
Discussion
The iOS SDK comes with a long tap gestuie iecognizei class nameu UILongTapGes
tureRecognizer. A long tap gestuie is tiiggeieu when the usei piesses one oi moie
lingeis (conliguiaLle Ly the piogiammei) on a UIView anu holus the lingei(s) loi a
specilic amount ol time. Fuitheimoie, you can naiiow the uetection ol gestuies uown
to only those long tap gestuies that aie peiloimeu altei a ceitain numLei ol lingeis aie
tappeu on a view loi a ceitain numLei ol times anu aie then kept on the view loi a
specilieu numLei ol seconus. Beai in minu that long taps aie continuous events.
Foui impoitant piopeities can change the way the long tap gestuie iecognizei peiloims.
These aie:
numberOfTapsRequired
This is the numLei ol taps the usei has to peiloim on the taiget view, Leloie the
gestuie can Le tiiggeieu. Beai in minu that a tap is not meiely a lingei positioneu
on a scieen. A tap is the movement ol putting a lingei uown on the scieen anu
lilting the lingei oll. The uelault value ol this piopeity is 0.
numberOfTouchesRequired
This piopeity specilies the numLei ol lingeis that must Le touching the scieen
Leloie the gestuie can Le iecognizeu. You must specily the same numLei ol lingeis
to uetect the taps, il the numberOfTapsRequired piopeity is set to a value laigei than
0.
464 | Chapter 8: Implementing Gesture Recognizers
www.it-ebooks.info
allowableMovement
This is the maximum numLei ol pixels that the lingeis on the scieen can Le moveu
Leloie the gestuie iecognition is aLoiteu.
minimumPressDuration
This piopeity uictates how long, measuieu in seconus, the usei must piess his
lingei(s) on the scieen Leloie the gestuie event can Le uetecteu.
In the example, these piopeities aie set as lollows:
numberOfTapsRequired: Delault (we aie not changing this value)
numberOfTouchesRequired: 2
allowableMovement: 100
minimumPressDuration: 1
Vith these values, the long tap gestuie will Le iecognizeu only il the usei piesses on
the scieen anu holus Loth lingeis loi one seconu (minimumPressDuration) without mov-
ing hei lingeis moie than 100 pixels aiounu (allowableMovement).
Now when the gestuie is iecognizeu, it will call the handleLongPressGestures: methou,
which we can implement in this way:
- (void) handleLongPressGestures:(UILongPressGestureRecognizer *)paramSender{

/* Here we want to find the midpoint of the two fingers
that caused the long press gesture to be recognized. We configured
this number using the numberOfTouchesRequired property of the
UILongPressGestureRecognizer that we instantiated in the
viewDidLoad instance method of this View Controller. If we
find that another long press gesture recognizer is using this
method as its target, we will ignore it */

if ([paramSender isEqual:self.longPressGestureRecognizer]){

if (paramSender.numberOfTouchesRequired == 2){

CGPoint touchPoint1 =
[paramSender locationOfTouch:0
inView:paramSender.view];

CGPoint touchPoint2 =
[paramSender locationOfTouch:1
inView:paramSender.view];

CGFloat midPointX = (touchPoint1.x + touchPoint2.x) / 2.0f;
CGFloat midPointY = (touchPoint1.y + touchPoint2.y) / 2.0f;

CGPoint midPoint = CGPointMake(midPointX, midPointY);

self.dummyButton.center = midPoint;

8.4 Detecting Long Press Gestures | 465
www.it-ebooks.info
} else {
/* This is a long press gesture recognizer with more
or less than 2 fingers */

}
}

}
One ol the applications in iOS that uses long tap gestuie iecognizeis is
the Maps application. In this application, when you aie looking at uil-
leient locations, piess youi lingei on a specilic location anu holu it loi
a while without lilting it oll the scieen. This will uiop a pin on that
specilic location.
8.5 Detecting Tap Gestures
Problem
You want to Le aLle to uetect when useis tap on a view.
Solution
Cieate an instance ol the UITapGestureRecognizer class anu auu it to the taiget view,
using the addGestureRecognizer: instance methou ol the UIView class. Let`s have a look
at the uelinition ol the view contiollei (the .h lile):
#import <UIKit/UIKit.h>
@interface Detecting_Tap_GesturesViewController : UIViewController
@property (nonatomic, strong)
UITapGestureRecognizer *tapGestureRecognizer;
@end
The implementation ol the viewDidLoad instance methou ol the view contiollei is as
lollows:
- (void)viewDidLoad {
[super viewDidLoad];

self.view.backgroundColor = [UIColor whiteColor];

/* Create the Tap Gesture Recognizer */
self.tapGestureRecognizer = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:@selector(handleTaps:)];

/* The number of fingers that must be on the screen */
466 | Chapter 8: Implementing Gesture Recognizers
www.it-ebooks.info
self.tapGestureRecognizer.numberOfTouchesRequired = 2;

/* The total number of taps to be performed before the
gesture is recognized */
self.tapGestureRecognizer.numberOfTapsRequired = 3;

/* Add this gesture recognizer to the view */
[self.view addGestureRecognizer:self.tapGestureRecognizer];

}
Discussion
The tap gestuie iecognizei is the Lest canuiuate among gestuie iecognizeis to uetect
plain tap gestuies. A tap event is the event tiiggeieu Ly the usei touching anu lilting his
lingei(s) oll the scieen. A tap gestuie is a uisciete gestuie.
The locationInView: methou ol the UITapGestureRecognizer class can Le useu to uetect
the location ol the tap event. Il the tap gestuie ieguiies moie than one touch, the
locationOfTouch:inView: methou ol the UITapGestureRecognizer class can Le calleu to
ueteimine inuiviuual touch points. In the coue, we have set the numberOf
TouchesRequired piopeity ol the tap gestuie iecognizei to 2. Vith this value set, the
gestuie iecognizei will ieguiie two lingeis to Le on the scieen on each tap event. The
numLei ol taps that aie ieguiieu loi the gestuie iecognizei to iecognize this gestuie is
set to 3, using the numberOfTapsRequired piopeity. Ve have pioviueu the handleTaps:
methou as the taiget methou ol the tap gestuie iecognizei:
- (void) handleTaps:(UITapGestureRecognizer*)paramSender{

NSUInteger touchCounter = 0;
for (touchCounter = 0;
touchCounter < paramSender.numberOfTouchesRequired;
touchCounter++){
CGPoint touchPoint =
[paramSender locationOfTouch:touchCounter
inView:paramSender.view];
NSLog(@"Touch #%lu: %@",
(unsigned long)touchCounter+1,
NSStringFromCGPoint(touchPoint));
}

}
In this coue, we aie going thiough the numLei ol touches that the tap gestuie iecognizei
was askeu to look loi. Baseu on that numLei, we aie linuing the location ol each tap.
Depenuing on wheie you tap on the view on youi simulatoi, you will get iesults similai
to this in the console winuow:
Touch #1: {107, 186}
Touch #2: {213, 254}
8.5 Detecting Tap Gestures | 467
www.it-ebooks.info
Il you aie using the simulatoi, you can simulate two touches at the same
time Ly holuing uown the Option key anu moving youi mouse on the
simulatoi`s scieen. You will now have two concentiic touch points on
the scieen.
One lunction woith noting is the NSStringFromCGPoint methou, which, as its name
implies, can conveit a CGPoint stiuctuie to NSString. Ve use this lunction to conveit
the CGPoint ol each touch on the scieen to an NSString, so that we can log it to the
console winuow using NSLog. You can Liing up the console winuow with Run Con-
sole.
8.6 Detecting Pinch Gestures
Problem
You want youi useis to Le aLle to peiloim a pinch gestuie on a view.
Solution
Cieate an instance ol the UIPinchGestureRecognizer class anu auu it to youi taiget view,
using the addGestureRecognizer: instance methou ol the UIView class:
- (void)viewDidLoad {
[super viewDidLoad];

self.view.backgroundColor = [UIColor whiteColor];

CGRect labelRect = CGRectMake(0.0f, /* X */
0.0f, /* Y */
200.0f, /* Width */
200.0f); /* Height */

self.myBlackLabel = [[UILabel alloc] initWithFrame:labelRect];
self.myBlackLabel.center = self.view.center;
self.myBlackLabel.backgroundColor = [UIColor blackColor];

/* Without this line, the pinch gesture recognizer will not work */
self.myBlackLabel.userInteractionEnabled = YES;
[self.view addSubview:self.myBlackLabel];

/* Create the Pinch Gesture Recognizer */
self.pinchGestureRecognizer = [[UIPinchGestureRecognizer alloc]
initWithTarget:self
action:@selector(handlePinches:)];

/* Add this gesture recognizer to the view */
[self.myBlackLabel
addGestureRecognizer:self.pinchGestureRecognizer];

}
468 | Chapter 8: Implementing Gesture Recognizers
www.it-ebooks.info
The .h lile ol the view contiollei is uelineu in this way:
#import <UIKit/UIKit.h>
@interface Detecting_Pinch_GesturesViewController : UIViewController
@property (nonatomic, strong)
UIPinchGestureRecognizer *pinchGestureRecognizer;
@property (nonatomic, strong) UILabel *myBlackLabel;
@property (nonatomic, unsafe_unretained) CGFloat currentScale;
@end
Discussion
Pinching allows useis to scale GUI elements up anu uown easily. Foi instance, the Salaii
weL Liowsei on iOS allows useis to pinch on a weL page in oiuei to zoom into the
contents Leing uisplayeu. Pinching woiks in two ways: scaling up anu scaling uown. It
is a continuous gestuie that must always Le peiloimeu using two lingeis on the scieen.
The state ol this gestuie iecognizei changes in this oiuei:
1. UIGestureRecognizerStateBegan
2. UIGestureRecognizerStateChanged
3. UIGestureRecognizerStateEnded
Once the pinch gestuie is iecognizeu, the action methou in the taiget oLject will Le
calleu (anu will continue to Le calleu until the pinch gestuie enus). Insiue the action
methou you can access two veiy impoitant piopeities ol the pinch gestuie iecognizei:
scale anu velocity. scale is the lactoi Ly which you shoulu scale the x- anu y-axes ol
a GUI element to iellect the size ol the usei`s gestuie. velocity is the velocity ol the
pinch in pixels pei seconu. The velocity is a negative value il the touch points aie getting
closei to each othei, anu a positive value il they aie getting laithei away liom each othei.
The value ol the scale piopeity can Le pioviueu to the CGAffineTransformMakeScale
Coie Giaphics lunction in oiuei to ietiieve an alline tiansloimation. This alline tians-
loimation can Le applieu to the tiansloim piopeity ol any instance ol the UIView class
in oiuei to change its tiansloimation. Ve aie using this lunction in this way:
- (void) handlePinches:(UIPinchGestureRecognizer*)paramSender{

if (paramSender.state == UIGestureRecognizerStateEnded){
self.currentScale = paramSender.scale;
} else if (paramSender.state == UIGestureRecognizerStateBegan &&
self.currentScale != 0.0f){
paramSender.scale = self.currentScale;
}

if (paramSender.scale != NAN &&
paramSender.scale != 0.0){
8.6 Detecting Pinch Gestures | 469
www.it-ebooks.info
paramSender.view.transform =
CGAffineTransformMakeScale(paramSender.scale,
paramSender.scale);
}

}
Since the scale piopeity ol a pinch gestuie iecognizei is ieset eveiy time a new pinch
gestuie is iecognizeu, we aie stoiing the last value ol this piopeity in an instance
piopeity ol the view contiollei calleu currentScale. The next time a new gestuie is
iecognizeu, we stait the scale lactoi liom the pieviously iepoiteu scale lactoi, as
uemonstiateu in the coue.
470 | Chapter 8: Implementing Gesture Recognizers
www.it-ebooks.info
CHAPTER 9
Networking, JSON, XML, and Twitter
9.0 Introduction
iOS apps, when connecteu to the Inteinet, Lecome moie lively. Foi example, imagine
an app that Liings high-guality wallpapeis to its useis. The usei can pick liom a Lig list
ol wallpapeis anu assign any ol those images as his iOS Lackgiounu. Now consiuei an
app that uoes the same thing, Lut auus to its list ol wallpapeis eveiy uay, week, oi
month. The usei comes Lack to the app, anu voila! Tons ol new wallpapeis aie uy-
namically auueu to the app. That is the magic ol weL seivices anu the Inteinet. This
can easily Le achieveu with Lasic knowleuge ol netwoiking, XML, ]SON, anu Twittei
connectivity along with some cieativity on the app uevelopei`s pait.
The iOS SDK allows us to connect to the Inteinet anu ietiieve anu senu uata using the
NSURLConnection class. ]SON seiialization anu ueseiialization will all Le uone using the
NSJSONSerialization class. XML paising will Le uone using NSXMLParser, anu the Twit-
tei connectivity will Le uone using the Twittei liamewoik.
9.1 Downloading Asynchronously with NSURLConnection
Problem
You want to uownloau a lile liom a URL, asynchionously.
Solution
Use the NSURLConnection class with an asynchionous ieguest.
Discussion
Theie aie two ways ol using the NSURLConnection class. One is asynchionous anu the
othei is synchionous. Asynchionous connection will cieate a new thieau anu uoes its
uownloauing piocess on the new thieau. Synchionous connection will Llock the ca||ing
thrcad while uownloauing content anu uoing its communication.
471
www.it-ebooks.info
Many uevelopeis think that a synchionous connection Llocks the nain thrcad, Lut that
is incoiiect. A synchionous connection will always Llock the thieau liom which it is
liieu. Il you liie a synchionous connection liom the main thieau, yes, the main thieau
will Le Llockeu. But il you liie a synchionous connection liom a thieau othei than the
main thieau, it will Le like an asynchionous connection in that it won`t Llock youi
main thieau. In lact, the only uilleience Letween a synchionous anu an asynchionous
connection is that the iuntime will cieate a thieau loi the asynchionous connection,
while it won`t uo such thing loi a synchionous connection.
In oiuei to cieate an asynchionous connection, we neeu to:
1. Have oui URL in an instance ol NSString.
2. Conveit oui stiing to an instance ol NSURL.
3. Place oui URL in a URL Reguest ol type NSURLRequest, oi in case ol mutaLle URLs,
in an instance ol NSMutableURLRequest.
+. Cieate an instance ol NSURLConnection anu pass the URL ieguest to it.
Ve can cieate an asynchionous URL connection using the sendAsynchronousRe
quest:queue:completionHandler: class methou ol NSURLConnection. The paiameteis to
this methou aie:
sendAsynchronousRequest
A ieguest ol type NSURLRequest, as we alieauy uiscusseu.
queue
An opeiation gueue. Ve can simply allocate anu initialize a new opeiation gueue
anu pass it to this methou, il we wish.
completionHandler
A Llock oLject to Le executeu when the asynchionous connection linishes its woik
eithei successlully oi unsuccesslully. This Llock oLject shoulu accept thiee pa-
iameteis:
1. An oLject ol type NSURLResponse which encapsulates the iesponse that the
seivei sent us, il any.
2. Data ol type NSData il any. This uata will Le the uata that the connection letcheu
liom the URL.
3. Eiioi ol type NSError il an eiioi occuis.
The sendAsynchronousRequest:queue:completionHandler: methou uoesn`t
get calleu on the main thieau, so make suie that il you want to peiloim
a UI-ielateu task, that you aie Lack on the main thieau.
Enough talk anu let`s have a look at an example. In this example, we will tiy to letch
the HTML contents ol Apple`s home page anu then piint the contents as a stiing to the
console winuow:
472 | Chapter 9: Networking, JSON, XML, and Twitter
www.it-ebooks.info
NSString *urlAsString = @"http://www.apple.com";
NSURL *url = [NSURL URLWithString:urlAsString];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection
sendAsynchronousRequest:urlRequest
queue:queue
completionHandler:^(NSURLResponse *response,
NSData *data,
NSError *error) {
if ([data length] >0 &&
error == nil){
NSString *html = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
NSLog(@"HTML = %@", html);
}
else if ([data length] == 0 &&
error == nil){
NSLog(@"Nothing was downloaded.");
}
else if (error != nil){
NSLog(@"Error happened = %@", error);
}
}];
It`s as simple as that. Il you wanteu to save the uata that the connection uownloaueu
loi us to the uisk, you coulu simply uo so using the appiopiiate methous ol the
NSData that we get liom the completion Llock:
NSString *urlAsString = @"http://www.apple.com";
NSURL *url = [NSURL URLWithString:urlAsString];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection
sendAsynchronousRequest:urlRequest
queue:queue
completionHandler:^(NSURLResponse *response,
NSData *data,
NSError *error) {
if ([data length] >0 &&
error == nil){
/* Get the documents directory */
NSString *documentsDir =
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES) objectAtIndex:0];
/* Append the file name to the documents directory */
NSString *filePath = [documentsDir
stringByAppendingPathComponent:@"apple.html"];
9.1 Downloading Asynchronously with NSURLConnection | 473
www.it-ebooks.info
/* Write the data to the file */
[data writeToFile:filePath
atomically:YES];
NSLog(@"Successfully saved the file to %@", filePath);
}
else if ([data length] == 0 &&
error == nil){
NSLog(@"Nothing was downloaded.");
}
else if (error != nil){
NSLog(@"Error happened = %@", error);
}
}];
It`s that simple, ieally. In oluei veisions ol iOS SDK, URL connections useu the uele-
gation mouel, Lut now it`s all simply Llock-Laseu anu you no longei have to woiiy
aLout implementing uelegate methous.
9.2 Handling Timeouts in Asynchronous Connections
Problem
You want to set a wait limitin othei woius, a timeouton an asynchionous con-
nection.
Solution
Set the timeout on the URL ieguest that you pass to the NSURLConnection class.
Discussion
Vhen instantiating an oLject ol type NSURLRequest to pass to youi URL connection,
you can use its requestWithURL:cachePolicy:timeoutInterval: class methou anu pass
the uesiieu numLei ol seconus ol youi timeout as the timeoutInterval paiametei.
Foi instance, il you want to wait a maximum ol 30 seconus to uownloau the contents
ol Apple`s home page using a synchionous connection, cieate youi URL ieguest like so:
NSString *urlAsString = @"http://www.apple.com";
NSURL *url = [NSURL URLWithString:urlAsString];
NSURLRequest *urlRequest =
[NSURLRequest
requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
timeoutInterval:30.0f];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
474 | Chapter 9: Networking, JSON, XML, and Twitter
www.it-ebooks.info
[NSURLConnection
sendAsynchronousRequest:urlRequest
queue:queue
completionHandler:^(NSURLResponse *response,
NSData *data,
NSError *error) {
if ([data length] >0 &&
error == nil){
NSString *html = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
NSLog(@"HTML = %@", html);
}
else if ([data length] == 0 &&
error == nil){
NSLog(@"Nothing was downloaded.");
}
else if (error != nil){
NSLog(@"Error happened = %@", error);
}
}];
Vhat will happen heie is that the iuntime will tiy to ietiieve the contents ol the pio-
viueu URL. Il this can Le uone Leloie 30 seconus have elapseu anu the connection is
estaLlisheu Leloie the timeout occuis, then line. Il not, the iuntime will pioviue you
with a timeout error in the eiioi paiametei ol the completion Llock.
9.3 Downloading Synchronously with NSURLConnection
Problem
You want to uownloau the contents ol a URL, synchionously.
Solution
Use the sendSynchronousRequest:returningResponse:error: class methou ol NSURLCon
nection. The ietuin value ol this methou is uata ol type NSData.
Discussion
Using the sendSynchronousRequest:returningResponse:error: class methou ol NSURL
Connection, we can senu a synchionous ieguest to a URL. Now, iememLei: synchio-
nous connections uo not necessaiily Llock the main thieau! Synchionous connections
Llock the currcnt thrcad anu il the cuiient thieau is the main thieau, then the main
thieau will Le Llockeu. Il you go on a gloLal concuiient gueue with GCD anu then
initiate a synchionous connection, then you aie not Llocking the main thieau.
Let`s go aheau anu initiate oui liist synchionous connection anu see what happens. In
this example, we will tiy to ietiieve the home page ol Yahoo!`s US weLsite:
9.3 Downloading Synchronously with NSURLConnection | 475
www.it-ebooks.info
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
NSLog(@"We are here...");
NSString *urlAsString = @"http://www.yahoo.com";
NSURL *url = [NSURL URLWithString:urlAsString];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
NSURLResponse *response = nil;
NSError *error = nil;
NSLog(@"Firing synchronous url connection...");
NSData *data = [NSURLConnection sendSynchronousRequest:urlRequest
returningResponse:&response
error:&error];
if ([data length] > 0 &&
error == nil){
NSLog(@"%lu bytes of data was returned.", (unsigned long)[data length]);
}
else if ([data length] == 0 &&
error == nil){
NSLog(@"No data was returned.");
}
else if (error != nil){
NSLog(@"Error happened = %@", error);
}
NSLog(@"We are done.");
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Il you iun this app anu then look at the console winuow, you will see something similai
to this piinteu out:
We are here...
Firing synchronous url connection...
194472 bytes of data was returned.
We are done.
So it`s oLvious that the cuiient thieau piinteu the stiing We are here... to the console
winuow, waiteu loi the connection to linish (as it was a synchionous connection that
Llocks the cuiient thieau), anu then piinteu the We are done. text to the console win-
uow. Now let`s uo an expeiiment. Let`s place the same exact synchionous connection
insiue a gloLal concuiient gueue in GCD, which guaiantees concuiiency, anu see what
happens:
476 | Chapter 9: Networking, JSON, XML, and Twitter
www.it-ebooks.info
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
NSLog(@"We are here...");
NSString *urlAsString = @"http://www.yahoo.com";
NSLog(@"Firing synchronous url connection...");
dispatch_queue_t dispatchQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(dispatchQueue, ^(void) {
NSURL *url = [NSURL URLWithString:urlAsString];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
NSURLResponse *response = nil;
NSError *error = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:urlRequest
returningResponse:&response
error:&error];
if ([data length] > 0 &&
error == nil){
NSLog(@"%lu bytes of data was returned.", (unsigned long)[data length]);
}
else if ([data length] == 0 &&
error == nil){
NSLog(@"No data was returned.");
}
else if (error != nil){
NSLog(@"Error happened = %@", error);
}
});
NSLog(@"We are done.");
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
The output will Le similai to this:
We are here...
Firing synchronous url connection...
We are done.
194326 bytes of data was returned.
9.3 Downloading Synchronously with NSURLConnection | 477
www.it-ebooks.info
So in this example, the cuiient thieau caiiieu on to piint the We are done. text to the
console winuow without having to wait loi the synchionous connection to linish ieau-
ing liom its URL. That is inteiesting, isn`t it? So this pioves that a synchionous URL
connection won`t necessaiily Llock the main thieau, il manageu piopeily. Synchionous
connections aie guaianteeu to Llock the currcnt thrcad, though.
9.4 Modifying a URL Request with NSMutableURLRequest
Problem
You want to aujust vaiious HTTP heaueis anu settings ol a URL ieguest Leloie passing
it to a URL connection.
Solution
This technigue is the Lasis ol many uselul iecipes shown latei in this chaptei. Use
NSMutableURLRequest insteau ol NSURLRequest.
Discussion
A URL ieguest can Le eithei nutab|c oi innutab|c. A mutaLle URL ieguest can Le
changeu altei it has Leen allocateu anu initializeu, wheieas an immutaLle URL ieguest
cannot. MutaLle URL ieguests aie the taiget ol this iecipe. You can cieate them using
the NSMutableURLRequest class.
Let`s have a look at an example wheie we will change the timeout inteival ol a URL
ieguest ajtcr we have allocateu anu initializeu it:
NSString *urlAsString = @"http://www.apple.com";
NSURL *url = [NSURL URLWithString:urlAsString];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
[urlRequest setTimeoutInterval:30.0f];
Now let`s have a look at anothei example wheie we set the URL anu the timeout ol a
URL ieguest altei it has Leen allocateu anu initializeu:
NSString *urlAsString = @"http://www.apple.com";
NSURL *url = [NSURL URLWithString:urlAsString];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest new];
[urlRequest setTimeoutInterval:30.0f];
[urlRequest setURL:url];
In othei iecipes in this chaptei, we will have a look at some ol the ieally neat tiicks that
we can peiloim using mutaLle URL ieguests.
478 | Chapter 9: Networking, JSON, XML, and Twitter
www.it-ebooks.info
9.5 Sending HTTP GET Requests with NSURLConnection
Problem
You want to senu a GET ieguest ovei the HTTP piotocol anu peihaps pass paiameteis
along youi ieguest to the ieceivei.
Solution
By convention, GET ieguests allow paiameteis thiough gueiy stiings ol the lamiliai
loim:
http://example.com/?param1=value1&param2=value2...
You can use stiings to pioviue the paiameteis in the conventional loimat.
Discussion
A GET ieguest is a ieguest to a weL seivei to ietiieve uata. The ieguest usually caiiies
some paiameteis, which aie sent in a gueiy stiing as pait ol the URL.
To let you test paiametei passing, I have piepaieu a simple GET weL seivice at the
lollowing auuiess: http://pixo|ity.con/gct.php. Il you open this URL in youi Liowsei,
you will see something similai to Figuie 9-1.
Iigurc 9-1. Thc cxanp|c GET wcb scrvicc opcncd in a wcb browscr
9.5 Sending HTTP GET Requests with NSURLConnection | 479
www.it-ebooks.info
So oui weL Liowsei is aLle to open this URL just line, anu you can see that the weL
seivice is aLle to uetect gueiy stiing paiameteis anu GET paiameteis. Now il you open
the lollowing URL (http://pixo|ity.con/gct.php?paran1=Iirstcparan2=Sccond) in
youi Liowsei, you will see iesults similai to those shown in Figuie 9-2.
Iigurc 9-2. Qucry string paranctcrs scnt to thc GET wcb scrvicc
To simulate senuing gueiy stiing paiameteis in a GET ieguest to the same weL seivice
using NSURLConnection, use a mutaLle URL ieguest anu explicitly specily youi HTTP
methou to GET using the setHTTPMethod: methou ol NSMutableURLRequest anu put youi
paiameteis as pait ol the URL, like so:
/* URL = http://pixolity.com/get.php?param1=First&param2=Second */
NSString *urlAsString = @"http://pixolity.com/get.php";
urlAsString = [urlAsString stringByAppendingString:@"?param1=First"];
urlAsString = [urlAsString stringByAppendingString:@"&param2=Second"];
NSURL *url = [NSURL URLWithString:urlAsString];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
[urlRequest setTimeoutInterval:30.0f];
[urlRequest setHTTPMethod:@"GET"];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection
sendAsynchronousRequest:urlRequest
queue:queue
completionHandler:^(NSURLResponse *response,
480 | Chapter 9: Networking, JSON, XML, and Twitter
www.it-ebooks.info
NSData *data,
NSError *error) {
if ([data length] >0 &&
error == nil){
NSString *html = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
NSLog(@"HTML = %@", html);
}
else if ([data length] == 0 &&
error == nil){
NSLog(@"Nothing was downloaded.");
}
else if (error != nil){
NSLog(@"Error happened = %@", error);
}
}];
Vhat gets piinteu to the console winuow now is the uata that comes Lack liom the
weL seivice:
HTML =
<html>
<head>
<title>iOS 6 Programming Cookbook GET Example</title>
</head>
<body>
<b>HTTP Method</b> = GET<br/><br/><b>Query String</b> = Array
(
[param1] => First
[param2] => Second
)
</body>
</html>
The only thing that you have to Leai in minu is that the liist paiametei is pielixeu with
a guestion maik anu any suLseguent paiametei is pielixeu with an ampeisanu. That`s
ieally aLout it! Now you aie using the HTTP GET methou anu you know how to senu
paiameteis as a gueiy stiing.
9.6 Sending HTTP POST Requests with NSURLConnection
Problem
You want to call a weL seivice using HTTP POST methou, anu peihaps pass paiameteis
(as pait ol the HTTP Louy oi in the gueiy stiing) to the weL seivice.
9.6 Sending HTTP POST Requests with NSURLConnection | 481
www.it-ebooks.info
Solution
]ust as with the GET methou, we can use the POST methou using NSURLConnection.Ve
must explicitly set oui URL`s methou to POST.
Discussion
I have set up a uummy weL seivice at the lollowing auuiess: http://pixo|ity.con/post
.php. Il you open this URL in youi Liowsei, you will see something similai to the scieen
shown in Figuie 9-3.
Iigurc 9-3. Thc POST wcb scrvicc opcncd in a wcb browscr
This weL seivice expects POST ieguests anu is aLle to piint out paiameteis that aie
sent as pait ol the gueiy stiing anu as pait ol the HTTP Louy. You can senu Loth, il
you want to. Let`s wiite a simple app that can cieate an asynchionous connection anu
senu a lew paiameteis as a gueiy stiing anu a lew paiameteis in the HTTP Louy to the
aloiementioneu URL:
NSString *urlAsString = @"http://pixolity.com/post.php";
urlAsString = [urlAsString stringByAppendingString:@"?param1=First"];
urlAsString = [urlAsString stringByAppendingString:@"&param2=Second"];
NSURL *url = [NSURL URLWithString:urlAsString];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
[urlRequest setTimeoutInterval:30.0f];
[urlRequest setHTTPMethod:@"POST"];
482 | Chapter 9: Networking, JSON, XML, and Twitter
www.it-ebooks.info
NSString *body = @"bodyParam1=BodyValue1&bodyParam2=BodyValue2";
[urlRequest setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection
sendAsynchronousRequest:urlRequest
queue:queue
completionHandler:^(NSURLResponse *response,
NSData *data,
NSError *error) {
if ([data length] >0 &&
error == nil){
NSString *html = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
NSLog(@"HTML = %@", html);
}
else if ([data length] == 0 &&
error == nil){
NSLog(@"Nothing was downloaded.");
}
else if (error != nil){
NSLog(@"Error happened = %@", erro