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 = %@", error);
}
}];
The liist paiametei sent in the HTTP Louy uoes not have to Le pielixeu
with a guestion maik, unlike the liist paiametei in a gueiy stiing.
Il you now look at the output piinteu to the console winuow, you will see something
similai to this:
HTML =
<html>
<head>
<title>iOS 6 Programming Cookbook POST Example</title>
</head>
<body>
<b>HTTP Method</b> = POST<br/><br/><b>Query String</b> = Array
(
[param1] => First
[param2] => Second
)
<br/><br/><b>Body Parameters</b> = Array
(
[bodyParam1] => BodyValue1
[bodyParam2] => BodyValue2
)
9.6 Sending HTTP POST Requests with NSURLConnection | 483
www.it-ebooks.info
</body>
</html>
9.7 Sending HTTP DELETE Requests with NSURLConnection
Problem
You want to call a weL seivice using the HTTP DELETE methou to uelete a iesouice
liom a URL, anu peihaps pass paiameteis, as pait ol the HTTP Louy oi in the gueiy
stiing, to the weL seivice.
Solution
]ust as with the GET anu POST methous, you can use the DELETE methou using
NSURLConnection. You must explicitly set youi URL`s methou to DELETE.
Discussion
I have set up a uummy weL seivice at the lollowing auuiess: http://pixo|ity.con/dc|ctc
.php. Il you open this URL in youi Liowsei, you will see something similai to the scieen
shown in Figuie 9-+.
Iigurc 9-1. Thc DELETE wcb scrvicc opcncd in a wcb browscr
This weL seivice expects DELETE ieguests (Lut it`s just a uummy seivice, so it uoesn`t
uelete any iesouices). It can piint out paiameteis that aie sent as pait ol the gueiy stiing
484 | Chapter 9: Networking, JSON, XML, and Twitter
www.it-ebooks.info
anu as pait ol the HTTP Louy, so you can senu Loth types in the same ieguest. Let`s
wiite a simple app that can cieate an asynchionous connection anu senu a lew paiam-
eteis as a gueiy stiing anu a lew paiameteis in the HTTP Louy to the aloiementioneu
URL, using the DELETE HTTP methou:
NSString *urlAsString = @"http://pixolity.com/delete.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:@"DELETE"];
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 = %@", error);
}
}];
Anu il you now look at the output piinteu to the console winuow, you will see some-
thing similai to this:
HTML =
<html>
<head>
<title>iOS 6 Programming Cookbook DELETE Example</title>
</head>
<body>
<b>HTTP Method</b> = DELETE<br/><br/><b>Query String</b> = Array
(
9.7 Sending HTTP DELETE Requests with NSURLConnection | 485
www.it-ebooks.info
[param1] => First
[param2] => Second
)
<br/><br/><b>Body Parameters</b> = Array
(
[bodyParam1] => BodyValue1
[bodyParam2] => BodyValue2
)
</body>
</html>
9.8 Sending HTTP PUT Requests with NSURLConnection
Problem
You want to call a weL seivice using the HTTP PUT methou to place a iesouice into
the weL seivei, anu peihaps pass paiameteis as pait ol the HTTP Louy oi in the gueiy
stiing, to the weL seivice.
Solution
]ust as with the GET, POST, anu DELETE methous, we can use the PUT methou using
NSURLConnection. Ve must explicitly set oui URL`s methou to PUT.
Discussion
I have set up a uummy weL seivice at the lollowing auuiess: http://pixo|ity.con/put
.php. Il you open this URL in youi Liowsei, you will see something similai to the scieen
shown in Figuie 9-5:
This weL seivice expects PUT ieguests anu is aLle to piint out paiameteis that aie sent
as pait ol the gueiy stiing anu as pait ol the HTTP Louy. So you can senu Loth types
ol paiameteis in the same ieguest. Let`s wiite a simple app that can cieate an asyn-
chionous connection anu senu a lew paiameteis as a gueiy stiing, anu a lew paiameteis
in the HTTP Louy to the aloiementioneu URL using the PUT methou:
NSString *urlAsString = @"http://pixolity.com/put.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:@"PUT"];
NSString *body = @"bodyParam1=BodyValue1&bodyParam2=BodyValue2";
[urlRequest setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
486 | 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);
}
}];
The liist paiametei sent in the HTTP Louy uoes not have to Le pielixeu
with a guestion maik, unlike the liist paiametei in a gueiy stiing.
Iigurc 9-5. Thc PUT wcb scrvicc opcncd in a wcb browscr
9.8 Sending HTTP PUT Requests with NSURLConnection | 487
www.it-ebooks.info
Anu il you now look at the output piinteu to the console winuow, you will see some-
thing similai to this:
HTML =
<html>
<head>
<title>iOS 6 Programming Cookbook PUT Example</title>
</head>
<body>
<b>HTTP Method</b> = PUT<br/><br/><b>Query String</b> = Array
(
[param1] => First
[param2] => Second
)
<br/><br/><b>Body Parameters</b> = Array
(
[bodyParam1] => BodyValue1
[bodyParam2] => BodyValue2
)
</body>
</html>
9.9 Serializing Arrays and Dictionaries into JSON
Problem
You want to seiialize a uictionaiy oi an aiiay into a ]SON oLject that you can tianslei
ovei the netwoik oi simply save to uisk.
Solution
Use the dataWithJSONObject:options:error: methou ol the NSJSONSerialization class.
Discussion
The dataWithJSONObject:options:error: methou ol the NSJSONSerialization class can
seiialize uictionaiies anu aiiays that contain only instances ol NSString, NSNumber,
NSArray, NSDictionary vaiiaLles, oi NSNull loi nil values. As mentioneu, the oLject that
you pass to this methou shoulu eithei Le an aiiay oi a uictionaiy.
Now let`s go aheau anu cieate a simple uictionaiy with a lew keys anu values:
NSMutableDictionary *dictionary =
[NSMutableDictionary dictionaryWithDictionary:@{
@"First Name" : @"Anthony",
@"Last Name" : @"Robbins",
@"Age" : @51
}];
488 | Chapter 9: Networking, JSON, XML, and Twitter
www.it-ebooks.info
NSArray *arrayOfAnthonysChildren = @[
@"Anthony's Son 1",
@"Anthony's Daughter 1",
@"Anthony's Son 2",
@"Anthony's Son 3",
@"Anthony's Daughter 2"
];
[dictionary setValue:arrayOfAnthonysChildren forKey:@"children"];
As you can see, this uictionaiy contains the liist name, last name, anu age ol Anthony
RoLLins. A key in the uictionaiy nameu children contains the names ol Anthony`s
chiluien. This is an aiiay ol stiings with each stiing iepiesenting one chilu. So Ly this
time, the dictionary vaiiaLle contains all the values that we want it to contain. It is now
time to seiialize it into a ]SON oLject:
NSError *error = nil;
NSData *jsonData = [NSJSONSerialization
dataWithJSONObject:dictionary
options:NSJSONWritingPrettyPrinted
error:&error];
if ([jsonData length] > 0 &&
error == nil){

NSLog(@"Successfully serialized the dictionary into data = %@",
jsonData);

}
else if ([jsonData length] == 0 &&
error == nil){

NSLog(@"No data was returned after serialization.");

}
else if (error != nil){

NSLog(@"An error happened = %@", error);

}
The ietuin value ol the dataWithJSONObject:options:error: methou is uata ol type
NSData. Howevei, you can simply tuin this uata into a stiing anu piint it to the console
using the initWithData:encoding: initializei ol NSString. Heie is the complete example
that seiializes a uictionaiy into a ]SON oLject, conveits that oLject into a stiing, anu
piints the stiing out to the console winuow:
NSMutableDictionary *dictionary =
[NSMutableDictionary dictionaryWithDictionary:@{
@"First Name" : @"Anthony",
@"Last Name" : @"Robbins",
@"Age" : @51
}];
9.9 Serializing Arrays and Dictionaries into JSON | 489
www.it-ebooks.info
NSArray *arrayOfAnthonysChildren = @[
@"Anthony's Son 1",
@"Anthony's Daughter 1",
@"Anthony's Son 2",
@"Anthony's Son 3",
@"Anthony's Daughter 2"
];
[dictionary setValue:arrayOfAnthonysChildren forKey:@"children"];
NSError *error = nil;
NSData *jsonData = [NSJSONSerialization
dataWithJSONObject:dictionary
options:NSJSONWritingPrettyPrinted
error:&error];
if ([jsonData length] > 0 &&
error == nil){

NSLog(@"Successfully serialized the dictionary into data.");
NSString *jsonString =
[[NSString alloc] initWithData:jsonData
encoding:NSUTF8StringEncoding];
NSLog(@"JSON String = %@", jsonString);

}
else if ([jsonData length] == 0 &&
error == nil){

NSLog(@"No data was returned after serialization.");

}
else if (error != nil){

NSLog(@"An error happened = %@", error);

}
Vhen you iun this app, the lollowing iesults will get piinteu to the console winuow:
Successfully serialized the dictionary into data.
JSON String = {
"Last Name" : "Robbins",
"First Name" : "Anthony",
"children" : [
"Anthony's Son 1",
"Anthony's Daughter 1", "Anthony's Son 2",
"Anthony's Son 3",
"Anthony's Daughter 2"
],
"Age" : 51
}
490 | Chapter 9: Networking, JSON, XML, and Twitter
www.it-ebooks.info
9.10 Deserializing JSON into Arrays and Dictionaries
Problem
You have ]SON uata anu you want to ueseiialize it into a uictionaiy oi an aiiay.
Solution
Use the JSONObjectWithData:options:error: methou ol the NSJSONSerialization class.
Discussion
Il you alieauy have seiializeu youi uictionaiy oi aiiay into a ]SON oLject (encapsulateu
insiue an instance ol NSData, see Recipe 9.9), you shoulu Le aLle to ueseiialize them
Lack into a uictionaiy oi an aiiay, using the JSONObjectWithData:options:error: meth-
ou ol the NSJSONSerialization class. The oLject that is ietuineu Lack Ly this methou
will eithei Le a uictionaiy oi an aiiay, uepenuing on the uata that we pass to it. Heie
is an example:
/* Now try to deserialize the JSON object into a dictionary */
error = nil;
id jsonObject = [NSJSONSerialization
JSONObjectWithData:jsonData
options:NSJSONReadingAllowFragments
error:&error];
if (jsonObject != nil &&
error == nil){
NSLog(@"Successfully deserialized...");
if ([jsonObject isKindOfClass:[NSDictionary class]]){
NSDictionary *deserializedDictionary = (NSDictionary *)jsonObject;
NSLog(@"Deserialized JSON Dictionary = %@", deserializedDictionary);
}
else if ([jsonObject isKindOfClass:[NSArray class]]){
NSArray *deserializedArray = (NSArray *)jsonObject;
NSLog(@"Deserialized JSON Array = %@", deserializedArray);
} else {
/* Some other object was returned. We don't know how to deal
with this situation, as the deserializer returns only dictionaries
or arrays */
}
}
else if (error != nil){
NSLog(@"An error happened while deserializing the JSON data.");
}
9.10 Deserializing JSON into Arrays and Dictionaries | 491
www.it-ebooks.info
Il now we mix this coue with the coue liom Recipe 9.9, we can liist seiialize oui uic-
tionaiy into a ]SON oLject, ueseiialize that ]SON oLject Lack into a uictionaiy, anu
piint out the iesults to make suie things went line:
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
[dictionary setValue:@"Anthony"
forKey:@"First Name"];
[dictionary setValue:@"Robbins"
forKey:@"Last Name"];
[dictionary setValue:[NSNumber numberWithUnsignedInteger:51]
forKey:@"Age"];
NSArray *arrayOfAnthonysChildren = [[NSArray alloc]
initWithObjects:
@"Anthony's Son 1",
@"Anthony's Daughter 1",
@"Anthony's Son 2",
@"Anthony's Son 3",
@"Anthony's Daughter 2",
nil];
[dictionary setValue:arrayOfAnthonysChildren
forKey:@"children"];
NSError *error = nil;
NSData *jsonData = [NSJSONSerialization
dataWithJSONObject:dictionary
options:NSJSONWritingPrettyPrinted
error:&error];
if ([jsonData length] > 0 &&
error == nil){
NSLog(@"Successfully serialized the dictionary into data.");
/* Now try to deserialize the JSON object into a dictionary */
error = nil;
id jsonObject = [NSJSONSerialization
JSONObjectWithData:jsonData
options:NSJSONReadingAllowFragments
error:&error];
if (jsonObject != nil &&
error == nil){
NSLog(@"Successfully deserialized...");
if ([jsonObject isKindOfClass:[NSDictionary class]]){
NSDictionary *deserializedDictionary = (NSDictionary *)jsonObject;
NSLog(@"Deserialized JSON Dictionary = %@", deserializedDictionary);
492 | Chapter 9: Networking, JSON, XML, and Twitter
www.it-ebooks.info
}
else if ([jsonObject isKindOfClass:[NSArray class]]){
NSArray *deserializedArray = (NSArray *)jsonObject;
NSLog(@"Deserialized JSON Array = %@", deserializedArray);
}
else {
/* Some other object was returned. We don't know how to deal
with this situation as the deserializer only returns dictionaries
or arrays */
}
}
else if (error != nil){
NSLog(@"An error happened while deserializing the JSON data.");
}
}
else if ([jsonData length] == 0 &&
error == nil){
NSLog(@"No data was returned after serialization.");
}
else if (error != nil){
NSLog(@"An error happened = %@", error);
}
The options paiametei ol the JSONObjectWithData:options:error: methou accepts one
oi a mixtuie ol the lollowing values:
NSJSONReadingMutableContainers
The uictionaiy oi the aiiay ietuineu Ly the JSONObjectWithData:options:error:
methou will Le mutaLle. In othei woius, this methou will ietuin eithei an instance
ol NSMutableArray oi NSMutableDictionary, as opposeu to an immutaLle aiiay oi
uictionaiy.
NSJSONReadingMutableLeaves
Leal values will Le encapsulateu into instances ol NSMutableString.
NSJSONReadingAllowFragments
Allows the ueseiialization ol ]SON uata whose ioot top-level oLject is not an aiiay
oi a uictionaiy.
See Also
Recipe 9.9
9.10 Deserializing JSON into Arrays and Dictionaries | 493
www.it-ebooks.info
9.11 Integrating Twitter Functionality into Your Apps
Problem
You want to integiate Twittei lunctionality into youi iOS apps.
Solution
Use the Twittei liamewoik.
Discussion
To Le aLle to integiate Twittei lunctionality into oui iOS apps, we neeu to use the
Twittei liamewoik. So liist we neeu to auu this liamewoik to oui app. Follow these
steps to auu the Twittei liamewoik to youi app:
1. Click on youi pioject icon in Xcoue.
2. Select the taiget to which you want to auu the Twittei liamewoik.
3. On the top, select Builu Phases.
+. Expanu the Link Binaiy with LiLiaiies Lox to see all the liamewoiks that aie cui-
iently linkeu to youi taiget.
5. Click on the little - Lutton at the Lottom-lelt coinei ol the Link Binaiy with
LiLiaiies Lox.
6. Select Twittcr.jrancwor| liom the list anu then piess the Auu Lutton.
Goou! Now you have the Twittei liamewoik linkeu to youi app. The next thing you
neeu to uo is impoit the appiopiiate heauei lile into youi view contiollei`s heauei lile:
#import <UIKit/UIKit.h>
#import <Twitter/Twitter.h>
@interface Integrating_Twitter_Functionality_Into_Your_AppsViewController
: UIViewController
@end
The next step is to instantiate an oLject ol type TWTweetComposeViewController, which
will take caie ol tweeting loi you. This is just a view contiollei that you can uisplay on
top ol youi view contiollei. I have uelineu a piopeity loi oui view contiollei loi this:
#import <UIKit/UIKit.h>
#import <Twitter/Twitter.h>
@interface Integrating_Twitter_Functionality_Into_Your_AppsViewController
: UIViewController
@property (nonatomic, strong) TWTweetComposeViewController *twitterController;
@end
494 | Chapter 9: Networking, JSON, XML, and Twitter
www.it-ebooks.info
Then, in the viewDidLoad methou ol youi view contiollei, initialize youi Twittei com-
posei contiollei. You can then use the setInitialText: methou ol TWTweetComposeView
Controller to set the text that will appeai in the Twittei composei contiollei initially,
Leloie the usei enteis anything:
- (void)viewDidLoad{
[super viewDidLoad];
self.twitterController = [[TWTweetComposeViewController alloc] init];
[self.twitterController setInitialText:@"Your Tweet Goes Here"];
[self.navigationController presentModalViewController:self.twitterController
animated:YES];
}
Now il you open youi app in the simulatoi, you will notice that the Twittei composei
is uisplayeu loi a seconu (see Figuie 9-6). Next, you will pioLaLly just see the Twittei
cieuentials scieen in the Settings app, as shown in Figuie 9-7.
Iigurc 9-. Twittcr conposcr shown as a noda| contro||cr
The ieason loi the Twittei login scieen Leing uisplayeu is that the usei has not yet
loggeu into Twittei on that iOS uevice. Go aheau anu entei youi Twittei cieuentials in
the login scieen (see Figuie 9-7). Once you entei youi cieuentials anu piess the Sign In
Lutton, you will Le piesenteu with a uialog asking you whethei you want the Twittei
app on youi uevice oi not. Piess Latcr. Ve uon`t want to Le Lotheieu with installing
that app at the moment. I`ve also noticeu that tiying to install the Twittei app on the
simulatoi is pioLlematic; you will get an icon on youi simulatoi saying Waiting anu
the wait will nevei Le ovei. So we aie Lettei oll without the Twittei app on the simulatoi.
On a ieal uevice, though, this woiks just line (Figuie 9-S).
9.11 Integrating Twitter Functionality into Your Apps | 495
www.it-ebooks.info
Iigurc 9-7. Thc Twittcr |ogin scrccn is disp|aycd ij thc uscr has not yct |oggcd into Twittcr
Iigurc 9-8. |nsta||ing thc Twittcr app
Altei the usei has enteieu hei Twittei cieuentials, launching youi app again will simply
uisplay the Twittei composei (see Figuie 9-6).
Asiue liom the main text that you auu to the composei contiollei, you can also auu
images using the addImage: methou ol the composei contiollei. You can also attach a
URL to youi tweets using the addURL: methou ol the composei contiollei. Heie is an
example:
496 | Chapter 9: Networking, JSON, XML, and Twitter
www.it-ebooks.info
- (void)viewDidLoad{
[super viewDidLoad];
self.twitterController = [[TWTweetComposeViewController alloc] init];
NSString *text =
@"Anthony Robbins at Unleash the Power Within (UPW) in London";
[self.twitterController setInitialText:text];
UIImage *anthonyRobbins = [UIImage imageNamed:@"Anthony Robbins.jpg"];
[self.twitterController addImage:anthonyRobbins];
NSURL *url = [NSURL URLWithString:@"http://www.tonyrobbins.com"];
[self.twitterController addURL:url];
[self.navigationController presentModalViewController:self.twitterController
animated:YES];
}
The URL that you auu to a tweet will not Le uisplayeu as pait ol youi
tweet in the Twittei contiollei, although it will Le sent as pait ol youi
tweet to youi Twittei timeline.
The iesults that youi useis will now see on theii uevices will Le similai to Figuie 9-9.
Iigurc 9-9. A sinp|c twcct with inagc and URL
9.11 Integrating Twitter Functionality into Your Apps | 497
www.it-ebooks.info
The Twittei composei contiollei uoes not woik with uelegates. It woiks with comple-
tion hanulei Llocks, like all mouein components in the iOS SDK. So il you want to get
upuates liom this contiollei altei you have uisplayeu it to the usei, auu a completion
hanulei Llock oLject to the composei, using its setCompletionHandler: methou. This
methou ieguiies a Llock oLject that shoulu have not a ietuin value anu must accept a
paiametei ol type TWTweetComposeViewControllerResult that will have one ol the lol-
lowing values:
TWTweetComposeViewControllerResultCancelled
The iesult that gets sent to oui completion Llock when the usei cancels the Twittei
composei contiollei. In this case, we must uismiss the Twittei composei contiollei.
TWTweetComposeViewControllerResultDone
The iesult that gets sent to oui completion Llock when the Twittei composei con-
tiollei has successlully sent the tweet to the usei`s timeline. Il you get this iesult,
you uon`t have to uismiss the contiollei, Lecause it gets uismisseu automatically.
Heie is an example:
- (void)viewDidLoad{
[super viewDidLoad];
self.twitterController = [[TWTweetComposeViewController alloc] init];
__weak
Integrating_Twitter_Functionality_Into_Your_AppsViewController
*weakSelf = self;
[self.twitterController setCompletionHandler:
^(TWTweetComposeViewControllerResult result){
Integrating_Twitter_Functionality_Into_Your_AppsViewController
*strongSelf = weakSelf;
switch (result){
case TWTweetComposeViewControllerResultDone:{
/* The tweet was submitted successfully.
Will be dismissed automatically */
break;
}
case TWTweetComposeViewControllerResultCancelled:{
if (strongSelf != nil){
[strongSelf.twitterController
dismissModalViewControllerAnimated:YES];
}
break;
}
}
}];
NSString *text =
@"Anthony Robbins at Unleash the Power Within (UPW) in London";
498 | Chapter 9: Networking, JSON, XML, and Twitter
www.it-ebooks.info
[self.twitterController setInitialText:text];
UIImage *anthonyRobbins = [UIImage imageNamed:@"Anthony Robbins.jpg"];
[self.twitterController addImage:anthonyRobbins];
NSURL *url = [NSURL URLWithString:@"http://www.tonyrobbins.com"];
[self.twitterController addURL:url];
[self.navigationController presentModalViewController:self.twitterController
animated:YES];
}
9.12 Parsing XML with NSXMLParser
Problem
You want to paise an XML snippet oi uocument.
Solution
Use the NSXMLParser class.
Discussion
The NSXMLParser uses a uelegate mouel to paise XML content. Let`s go aheau anu cieate
a simple XML lile that contains the lollowing uata (save this lile as MyXML.xn| in youi
pioject):
<?xml version="1.0" encoding="UTF-8"?>
<root>
<person id="1">
<firstName>Anthony</firstName>
<lastName>Robbins</lastName>
<age>51</age>
</person>
<person id="2">
<firstName>Richard</firstName>
<lastName>Branson</lastName>
<age>61</age>
</person>
</root>
Now ueline a piopeity ol type NSXMLParser:
#import <UIKit/UIKit.h>
@interface Parsing_XML_with_NSXMLParserAppDelegate
9.12 Parsing XML with NSXMLParser | 499
www.it-ebooks.info
: UIResponder <UIApplicationDelegate, NSXMLParserDelegate>
@property (nonatomic, strong) UIWindow *window;
@property (nonatomic, strong) NSXMLParser *xmlParser;
@end
You can also see that I have uelineu my app uelegate as an XML paisei uelegate Ly
conloiming to the NSXMLParserDelegate piotocol, which is ieguiieu loi a uelegate oLject
ol an XML paisei ol type NSXMLParser. Now let`s ieau the MyXML.xn| lile liom the
uisk anu pass it to youi XML paisei:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
NSString *xmlFilePath = [[NSBundle mainBundle] pathForResource:@"MyXML"
ofType:@"xml"];
NSData *xml = [[NSData alloc] initWithContentsOfFile:xmlFilePath];
self.xmlParser = [[NSXMLParser alloc] initWithData:xml];
self.xmlParser.delegate = self;
if ([self.xmlParser parse]){
NSLog(@"The XML is parsed.");
} else{
NSLog(@"Failed to parse the XML");
}
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Ve liist ieau the contents ol oui lile into an instance ol NSData anu then initialize oui
XML paisei with the initWithData:, using the uata that we ieau liom the XML lile. Ve
then call the parse methou ol the XML paisei to stait the paising piocess. This methou
will Llock the cuiient thieau until the paising piocess is linisheu. Il you have Lig XML
liles to paise, it is highly iecommenueu that you use a gloLal uispatch gueue to uo the
paising.
To paise the XML lile, we neeu to know the uelegate methous uelineu in the
NSXMLParserDelegate piotocol anu theii iesponsiLilities:
parserDidStartDocument:
Calleu when the paising staits.
parserDidEndDocument:
Calleu when the paising enus.
500 | Chapter 9: Networking, JSON, XML, and Twitter
www.it-ebooks.info
parser:didStartElement:namespaceURI:qualifiedName:attributes:
Calleu when the paisei encounteis anu paises a new element in the XML uocu-
ment.
parser:didEndElement:namespaceURI:qualifiedName:
Calleu when the paisei has linisheu paising the cuiient element.
parser:foundCharacters:
Calleu when the paisei paises stiing contents ol elements.
Using these uelegate methous, we can go aheau anu ueline an oLject mouel loi oui
XML oLjects. Let`s liist ueline an oLject to iepiesent an XML element, in a class calleu
XMLElement:
#import <Foundation/Foundation.h>
@interface XMLElement : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *text;
@property (nonatomic, strong) NSDictionary *attributes;
@property (nonatomic, strong) NSMutableArray *subElements;
@property (nonatomic, weak) XMLElement *parent;
@end
Now let`s implement oui XMLElement class:
#import "XMLElement.h"
@implementation XMLElement
- (NSMutableArray *) subElements{
if (_subElements == nil){
_subElements = [[NSMutableArray alloc] init];
}
return _subElements;
}
@end
Ve want the subElements mutaLle aiiay to Le cieateu only il it is nil when it is accesseu,
so we place oui allocation anu initialization coue loi the subElements piopeity ol the
XMLElement class in its own gettei methou. Il an XML element uoesn`t have suLelements
anu we nevei use that piopeity, theie is no point allocating anu initializing a mutaLle
aiiay loi that element. This technigue is known as lazy allocation.
So now let`s go aheau anu ueline an instance ol XMLElement anu call it rootElement. Oui
plan is to stait the paising piocess anu uiill uown the XML lile as we paise it with oui
uelegate methous, until we have successlully paiseu the whole lile:
#import <UIKit/UIKit.h>
@class XMLElement;
9.12 Parsing XML with NSXMLParser | 501
www.it-ebooks.info
@interface Parsing_XML_with_NSXMLParserAppDelegate
: UIResponder <UIApplicationDelegate, NSXMLParserDelegate>
@property (nonatomic, strong) UIWindow *window;
@property (nonatomic, strong) NSXMLParser *xmlParser;
@property (nonatomic, strong) XMLElement *rootElement;
@property (nonatomic, strong) XMLElement *currentElementPointer;
@end
The currentElementPointer will Le the XML element that we aie paising at the moment
in oui XML stiuctuie, so it can move up anu uown the stiuctuie as we paise the lile.
Unlike the constantly changing currentElementPointer pointei, the rootElementpointei
will always Le the ioot element ol oui XML anu its value will not change uuiing the
couise ol paising the XML lile.
Let`s stait the paising piocess. The liist methou we want to take caie ol is the parser
DidStartDocument: methou. In this methou, we will simply ieset eveiything:
- (void)parserDidStartDocument:(NSXMLParser *)parser{
self.rootElement = nil;
self.currentElementPointer = nil;
}
The next methou is the parser:didStartElement:namespaceURI:qualifiedName:
attributes: methou. In this methou, we will cieate the ioot element (il it has not Leen
cieateu alieauy). Il any new element in the XML lile is getting paiseu, we will calculate
wheie in the stiuctuie ol the XML we aie anu then auu a new element oLject to oui
cuiient element oLject:
- (void) parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict{
if (self.rootElement == nil){
/* We don't have a root element. Create it and point to it */
self.rootElement = [[XMLElement alloc] init];
self.currentElementPointer = self.rootElement;
} else {
/* Already have root. Create new element and add it as one of
the subelements of the current element */
XMLElement *newElement = [[XMLElement alloc] init];
newElement.parent = self.currentElementPointer;
[self.currentElementPointer.subElements addObject:newElement];
self.currentElementPointer = newElement;
}
self.currentElementPointer.name = elementName;
self.currentElementPointer.attributes = attributeDict;
}
502 | Chapter 9: Networking, JSON, XML, and Twitter
www.it-ebooks.info
Next up is the parser:foundCharacters: methou. This methou can get calleu multiple
times loi the cuiient element, so you neeu to make suie we aie ieauy loi multiple entiies
into this methou. Foi instance, il the text ol an element is +000 chaiacteis long, the
paisei might paise a maximum ol 1000 chaiacteis in the liist go, then the next 1000,
anu so on. In that case, the paisei woulu call youi parser:foundCharacters: methou
loi the cuiient element loui times. You pioLaLly want to just accumulate the iesults
that get ietuineu into a stiing:
- (void) parser:(NSXMLParser *)parser
foundCharacters:(NSString *)string{
if ([self.currentElementPointer.text length] > 0){
self.currentElementPointer.text =
[self.currentElementPointer.text stringByAppendingString:string];
} else {
self.currentElementPointer.text = string;
}
}
The next methou to take caie ol is the parser:didEndElement:namespaceURI:qualified
Name: methou, which gets calleu when the paisei encounteis the enu ol an element.
Heie you just neeu to point oui XML element pointei Lack one level to the paient ol
the cuiient elementit`s as simple as this:
- (void) parser:(NSXMLParser *)parser
didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName{
self.currentElementPointer = self.currentElementPointer.parent;
}
Last Lut not least, you neeu to hanule the parserDidEndDocument: methou anu uispose
ol youi currentElementPointer piopeity:
- (void)parserDidEndDocument:(NSXMLParser *)parser{
self.currentElementPointer = nil;
}
That is all. Now let`s go aheau anu paise oui uocument:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
NSString *xmlFilePath = [[NSBundle mainBundle] pathForResource:@"MyXML"
ofType:@"xml"];
NSData *xml = [[NSData alloc] initWithContentsOfFile:xmlFilePath];
self.xmlParser = [[NSXMLParser alloc] initWithData:xml];
self.xmlParser.delegate = self;
if ([self.xmlParser parse]){
NSLog(@"The XML is parsed.");
9.12 Parsing XML with NSXMLParser | 503
www.it-ebooks.info
/* self.rootElement is now the root element in the XML */
} else{
NSLog(@"Failed to parse the XML");
}
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Now you can use the rootElement piopeity to tiaveise the stiuctuie ol oui XML.
504 | Chapter 9: Networking, JSON, XML, and Twitter
www.it-ebooks.info
CHAPTER 10
Audio and Video
10.0 Introduction
The AV Founuation liamewoik in the iOS SDK allows uevelopeis to play anu/oi iecoiu
auuio anu viueo with ease. In auuition, the Meuia Playei liamewoik allows uevelopeis
to play auuio anu viueo liles.
Beloie you can iun the coue in this chaptei, you must auu the A\Ioundation.jranc-
wor| anu McdiaP|aycr.jrancwor| liamewoiks to youi Xcoue pioject. You can uo this
Ly lollowing these steps:
1. In Xcoue, click on youi pioject`s icon (a Llue icon).
2. Select the taiget to which you want to auu the liamewoik.
3. On the top, select Builu Phases.
+. Select the - Lutton in the Lottom-lelt coinei ol the Link Binaiies with LiLiaiies Lox.
5. Holu uown the Commanu key anu choose A\Ioundation.jrancwor| anu Mcdia-
P|aycr.jrancwor| liom the list.
6. Select Auu.
10.1 Playing Audio Files
Problem
You want to Le aLle to play an auuio lile in youi application.
Solution
Use the AV Founuation (Auuio anu Viueo Founuation) liamewoik`s AVAudioPlayer
class.
505
www.it-ebooks.info
Discussion
The AVAudioPlayer class in the AV Founuation liamewoik can play Lack all auuio loi-
mats suppoiteu Ly iOS. The delegate piopeity ol an instance ol AVAudioPlayer allows
you to get notilieu Ly events, such as when the auuio playLack is inteiiupteu oi an
eiioi occuis as a iesult ol playing an auuio lile. Let`s have a look at a simple example
that uemonstiates how we can play an auuio lile liom the application`s Lunule:
- (void)viewDidLoad {
[super viewDidLoad];

self.view.backgroundColor = [UIColor whiteColor];

dispatch_queue_t dispatchQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_async(dispatchQueue, ^(void) {
NSBundle *mainBundle = [NSBundle mainBundle];

NSString *filePath = [mainBundle pathForResource:@"MySong"
ofType:@"mp3"];

NSData *fileData = [NSData dataWithContentsOfFile:filePath];

NSError *error = nil;

/* Start the audio player */
self.audioPlayer = [[AVAudioPlayer alloc] initWithData:fileData
error:&error];

/* Did we get an instance of AVAudioPlayer? */
if (self.audioPlayer != nil){
/* Set the delegate and start playing */
self.audioPlayer.delegate = self;
if ([self.audioPlayer prepareToPlay] &&
[self.audioPlayer play]){
/* Successfully started playing */
} else {
/* Failed to play */
}
} else {
/* Failed to instantiate AVAudioPlayer */
}
});

}
As you can see, the lile`s uata is loaueu into an instance ol NSData anu then passeu on
to AVAudioPlayer `s initWithData:error: methou. Because we neeu the actual, aLsolute
path ol the MP3 lile to extiact the uata liom that lile, we invoke the mainBundle class
methou ol NSBundle to ietiieve the inloimation liom the application`s conliguiation.
The pathForResource:ofType: instance methou ol NSBundle can then Le useu to ietiieve
the aLsolute path to a iesouice ol a specilic type, as uemonstiateu in the example coue.
506 | Chapter 10: Audio and Video
www.it-ebooks.info
In the viewDidLoad methou, we aie using GCD to asynchionously loau the song`s uata
into an instance ol NSData anu use that as a leeu to the auuio playei. Ve uo this Lecause
loauing the uata ol an auuio lile can take a long time (uepenuing on the length ol the
auuio lile), anu il we uo this on the main thieau, we iun the iisk ol stalling the UI
expeiience. Because ol this, we aie using a gloLal concuiient gueue to ensuie that the
coue uoes not iun on the main thieau.
Since we aie assigning the instance ol AVAudioPlayer to a piopeity nameu audio
Player, we must also see how this piopeity is uelineu:
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
@interface Playing_Audio_FilesViewController
: UIViewController <AVAudioPlayerDelegate>
@property (nonatomic, strong) AVAudioPlayer *audioPlayer;
@end
As you can see, we have maue the view contiollei the uelegate ol the auuio playei. This
way, we can ieceive messages liom the system whenevei the auuio playei, loi instance,
is inteiiupteu oi has linisheu playing the song. Vith this inloimation in hanu, we can
make appiopiiate uecisions in the application, such as staiting to play anothei auuio
lile.
See Also
Recipe 10.2; Recipe 10.5; Chaptei 6
10.2 Handling Interruptions while Playing Audio
Problem
You want youi AVAudioPlayer instance to iesume playing altei an inteiiuption on an
iOS uevice, such as an incoming call.
Solution
Implement the audioPlayerBeginInterruption: anu audioPlayerEndInterruption:with
Flags: methous ol the AVAudioPlayerDelegate piotocol in the uelegate oLject ol youi
AVAudioPlayer instance:
- (void)audioPlayerBeginInterruption:(AVAudioPlayer *)player{

/* Audio Session is interrupted. The player will be paused here */

}- (void)audioPlayerEndInterruption:(AVAudioPlayer *)player
withFlags:(NSUInteger)flags{

10.2 Handling Interruptions while Playing Audio | 507
www.it-ebooks.info
if (flags == AVAudioSessionInterruptionFlags_ShouldResume &&
player != nil){
[player play];
}

}
Discussion
On an iOS uevice, such as an iPhone, a phone call coulu inteiiupt the execution ol the
loiegiounu application. In that case, the auuio session(s) associateu with the applica-
tion will Le ueactivateu, anu auuio liles will not Le playeu until the inteiiuption has
enueu. At the Leginning anu the enu ol an inteiiuption, we ieceive uelegate messages
liom the AVAudioPlayer inloiming us ol the uilleient states the auuio session is passing
thiough. Altei the enu ol an inteiiuption, we can simply iesume the playLack ol auuio.
Incoming phone calls cannot Le simulateu with iPhone Simulatoi. You
must always test youi applications on a ieal uevice.
Vhen an inteiiuption occuis, the audioPlayerBeginInterruption: uelegate methou ol
an AVAudioPlayer instance will Le calleu. Heie, youi auuio session has Leen ueactivateu.
In case ol a phone call, the usei can just heai his iingtone. Vhen the inteiiuption enus
(the phone call is linisheu oi the usei iejects the call), the audioPlayerEndInterrup
tion:withFlags: uelegate methou ol youi AVAudioPlayer will Le invokeu. Il the with
Flags paiametei contains the value AVAudioSessionInterruptionFlags_ShouldResume,
you can immeuiately iesume the playLack ol youi auuio playei using the play instance
methou ol AVAudioPlayer.
The playLack ol auuio liles using AVAudioPlayer might show memoiy
leaks in Instiuments when the application is Leing iun on iPhone Sim-
ulatoi. Testing the same application on an iOS uevice pioves that the
memoiy leaks aie unigue to the simulatoi, not the uevice. I stiongly
suggest that you iun, test, ueLug, anu optimize youi applications on ieal
uevices Leloie ieleasing them to the App Stoie.
10.3 Recording Audio
Problem
You want to Le aLle to iecoiu auuio liles on an iOS uevice.
508 | Chapter 10: Audio and Video
www.it-ebooks.info
Solution
Make suie you have auueu the CoieAuuio.liamewoik liamewoik to youi taiget lile,
anu use the AVAudioRecorder class in the AV Founuation liamewoik:
NSError *error = nil;
NSString *pathAsString = [self audioRecordingPath];
NSURL *audioRecordingURL = [NSURL fileURLWithPath:pathAsString];
self.audioRecorder = [[AVAudioRecorder alloc]
initWithURL:audioRecordingURL
settings:[self audioRecordingSettings]
error:&error];
Foi inloimation aLout the audioRecordingSettings anu audioRecordingPath methous
useu in this example, ielei to this iecipe`s Discussion.
Discussion
The AVAudioRecorder class in the AV Founuation liamewoik lacilitates auuio iecoiuing
in iOS applications. To stait a iecoiuing, you neeu to pass vaiious pieces ol inloimation
to the initWithURL:settings:error: instance methou ol AVAudioRecorder:
Thc URL oj thc ji|c whcrc thc rccording shou|d bc savcd
This is a local URL. The AV Founuation liamewoik will ueciue which auuio loimat
shoulu Le useu loi the iecoiuing Laseu on the lile extension pioviueu in this URL,
so choose the extension caielully.
Thc scttings that nust bc uscd bcjorc and whi|c rccording
Examples incluue the sampling iate, channels, anu othei inloimation that will help
the auuio iecoiuei stait the iecoiuing. This is a uictionaiy oLject.
Thc addrcss oj an instancc oj NSError whcrc any initia|ization crrors shou|d bc savcd to
The eiioi inloimation coulu Le valuaLle latei, anu you can ietiieve it liom this
instance methou in case something goes wiong.
The settings paiametei ol the initWithURL:settings:error: methou is paiticulaily
inteiesting. Theie aie many keys that coulu Le saveu in the settings uictionaiy, Lut we
will uiscuss only some ol the most impoitant ones in this iecipe:
AVFormatIDKey
The loimat ol the iecoiueu auuio. Some ol the values that can Le specilieu loi this
key aie:
kAudioFormatLinearPCM
kAudioFormatAppleLossless
AVSampleRateKey
The sample iate that neeus to Le useu loi the iecoiuing.
10.3 Recording Audio | 509
www.it-ebooks.info
AVNumberOfChannelsKey
The numLei ol channels that must Le useu loi the iecoiuing.
AVEncoderAudioQualityKey
The guality with which the iecoiuing must Le maue. Some ol the values that can
Le specilieu loi this key aie:
AVAudioQualityMin
AVAudioQualityLow
AVAudioQualityMedium
AVAudioQualityHigh
AVAudioQualityMax
Vith all this inloimation in hanu, we can go on anu wiite an application that can iecoiu
auuio input into a lile anu then play it using AVAudioPlayer. Vhat we want to uo,
specilically, is:
1. Stait iecoiuing auuio in Apple Lossless loimat.
2. Save the iecoiuing into a lile nameu Rccording.n1a in the application`s Docu-
ncnts uiiectoiy.
3. Five seconus altei the iecoiuing staits, linish the iecoiuing piocess anu immeui-
ately stait playing the lile into which we iecoiueu the auuio input.
Ve will stait Ly ueclaiing the ieguiieu piopeities in the .h lile ol a simple view con-
tiollei:
#import <UIKit/UIKit.h>
#import <CoreAudio/CoreAudioTypes.h>
#import <AVFoundation/AVFoundation.h>
@interface Recording_AudioViewController : UIViewController
<AVAudioPlayerDelegate, AVAudioRecorderDelegate>
@property (nonatomic, strong) AVAudioRecorder *audioRecorder;
@property (nonatomic, strong) AVAudioPlayer *audioPlayer;
- (NSString *) audioRecordingPath;
- (NSDictionary *) audioRecordingSettings;
@end
Vhen the view insiue the view contiollei is loaueu loi the liist time, we will attempt
to stait the iecoiuing piocess anu then stop the piocess, il successlully staiteu, altei
live seconus:
- (void)viewDidLoad {
[super viewDidLoad];

NSError *error = nil;

NSString *pathAsString = [self audioRecordingPath];
510 | Chapter 10: Audio and Video
www.it-ebooks.info

NSURL *audioRecordingURL = [NSURL fileURLWithPath:pathAsString];

self.audioRecorder = [[AVAudioRecorder alloc]
initWithURL:audioRecordingURL
settings:[self audioRecordingSettings]
error:&error];

if (self.audioRecorder != nil){

self.audioRecorder.delegate = self;
/* Prepare the recorder and then start the recording */

if ([self.audioRecorder prepareToRecord] &&
[self.audioRecorder record]){
NSLog(@"Successfully started to record.");

/* After five seconds, let's stop the recording process */
[self performSelector:@selector(stopRecordingOnAudioRecorder:)
withObject:self.audioRecorder
afterDelay:5.0f];

} else {
NSLog(@"Failed to record.");
self.audioRecorder = nil;
}

} else {
NSLog(@"Failed to create an instance of the audio recorder.");
}

}
In the viewDidLoad methou ol the view contiollei, we attempt to instantiate an oLject
ol type AVAudioRecorder anu assign it to the audioRecorder piopeity that we ueclaieu
in the .h lile ol the same view contiollei eailiei.
Ve aie using an instance methou calleu audioRecordingPath to ueteimine the
NSString iepiesentation ol the local URL wheie we want to stoie the iecoiuing. This
methou is implementeu like so:
- (NSString *) audioRecordingPath{

NSString *result = nil;

NSArray *folders =
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES);

NSString *documentsFolder = [folders objectAtIndex:0];

result = [documentsFolder
stringByAppendingPathComponent:@"Recording.m4a"];

10.3 Recording Audio | 511
www.it-ebooks.info
return result;

}
The ietuin value ol this lunction is the uocument path ol youi application with the
name ol the uestination lile appenueu to it. Foi instance, il the uocument path ol youi
application is:
/var/mobile/Applications/ApplicationID/Documents/
the uestination auuio iecoiuing path will Le:
/var/mobile/Applications/ApplicationID/Documents/Recording.m4a
Vhen instantiating the AVAudioRecorder, we aie using a uictionaiy loi the settings pa-
iametei ol the initialization methou ol the auuio iecoiuei, as explaineu Leloie. This
uictionaiy is constiucteu using the audioRecordingSettings instance methou, imple-
menteu in this way:
- (NSDictionary *) audioRecordingSettings{

NSDictionary *result = nil;

/* Let's prepare the audio recorder options in the dictionary.
Later we will use this dictionary to instantiate an audio
recorder of type AVAudioRecorder */

NSMutableDictionary *settings = [[NSMutableDictionary alloc] init];

[settings
setValue:[NSNumber numberWithInteger:kAudioFormatAppleLossless]
forKey:AVFormatIDKey];

[settings
setValue:[NSNumber numberWithFloat:44100.0f]
forKey:AVSampleRateKey];

[settings
setValue:[NSNumber numberWithInteger:1]
forKey:AVNumberOfChannelsKey];

[settings
setValue:[NSNumber numberWithInteger:AVAudioQualityLow]
forKey:AVEncoderAudioQualityKey];

result = [NSDictionary dictionaryWithDictionary:settings];

return result;

}
You can see that live seconus altei the iecoiuing successlully staits in the viewDid
Load methou ol the view contiollei, we call the stopRecordingOnAudioRecorder methou,
implementeu like so:
512 | Chapter 10: Audio and Video
www.it-ebooks.info
- (void) stopRecordingOnAudioRecorder
:(AVAudioRecorder *)paramRecorder{

/* Just stop the audio recorder here */
[paramRecorder stop];

}
Now that we have askeu the auuio iecoiuei to stop iecoiuing, we will wait loi its
uelegate messages to tell us when the iecoiuing has actually stoppeu. You shoulun`t
assume that the stop instance methou ol AVAudioRecorder instantly stops the iecoiuing.
Insteau, I iecommenu that you wait loi the audioRecorderDidFinishRecording:success
fully: uelegate methou (ueclaieu in the AVAudioRecorderDelegate piotocol) Leloie
pioceeuing.
Vhen the auuio iecoiuing has actually stoppeu, we will attempt to play what was
iecoiueu:
- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder
successfully:(BOOL)flag{

if (flag){

NSLog(@"Successfully stopped the audio recording process.");

/* Let's try to retrieve the data for the recorded file */
NSError *playbackError = nil;

NSError *readingError = nil;
NSData *fileData =
[NSData dataWithContentsOfFile:[self audioRecordingPath]
options:NSDataReadingMapped
error:&readingError];

/* Form an audio player and make it play the recorded data */
self.audioPlayer = [[AVAudioPlayer alloc] initWithData:fileData
error:&playbackError];

/* Could we instantiate the audio player? */
if (self.audioPlayer != nil){
self.audioPlayer.delegate = self;

/* Prepare to play and start playing */
if ([self.audioPlayer prepareToPlay] &&
[self.audioPlayer play]){
NSLog(@"Started playing the recorded audio.");
} else {
NSLog(@"Could not play the audio.");
}

} else {
NSLog(@"Failed to create an audio player.");
}

10.3 Recording Audio | 513
www.it-ebooks.info
} else {
NSLog(@"Stopping the audio recording failed.");
}

/* Here we don't need the audio recorder anymore */
self.audioRecorder = nil;

}
Altei the auuio playei is linisheu playing the song (il it uoes so successlully), the audio
PlayerDidFinishPlaying:successfully: uelegate methou will Le calleu in the uelegate
oLject ol the auuio playei. Ve will implement this methou like so (this methou is
uelineu in the AVAudioPlayerDelegate piotocol):
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player
successfully:(BOOL)flag{

if (flag){
NSLog(@"Audio player stopped correctly.");
} else {
NSLog(@"Audio player did not stop correctly.");
}

if ([player isEqual:self.audioPlayer]){
self.audioPlayer = nil;
} else {
/* This is not the player */
}

}
As explaineu in Recipe 10.2, when playing auuio liles using AVAudioPlayer, we also
neeu to hanule inteiiuptions (such as incoming phone calls) when ueploying the ap-
plication on an iOS uevice anu Leloie ieleasing the application to the App Stoie:
- (void)audioPlayerBeginInterruption:(AVAudioPlayer *)player{

/* The audio session has been deactivated here */

}
- (void)audioPlayerEndInterruption:(AVAudioPlayer *)player
withFlags:(NSUInteger)flags{

if (flags == AVAudioSessionInterruptionFlags_ShouldResume){
[player play];
}

}
Instances ol AVAudioRecorder must also hanule inteiiuptions, just like instances ol
AVAudioPlayer. These inteiiuptions can Le hanuleu as explaineu in Recipe 10.+.
514 | Chapter 10: Audio and Video
www.it-ebooks.info
See Also
Recipe 10.2; Recipe 10.+
10.4 Handling Interruptions while Recording Audio
Problem
You want youi AVAudioRecorder instance to Le aLle to iesume iecoiuing altei an intei-
iuption, such as an incoming phone call.
Solution
Implement the audioRecorderBeginInterruption: anu audioRecorderEndInterrup
tion:withFlags: methous ol the AVAudioRecorderDelegate piotocol in the uelegate oL-
ject ol youi auuio iecoiuei, anu iesume the iecoiuing piocess Ly invoking the record
instance methou ol youi AVAudioRecorder when the inteiiuption has enueu:
- (void)audioRecorderBeginInterruption:(AVAudioRecorder *)recorder{

NSLog(@"Recording process is interrupted");

}
- (void)audioRecorderEndInterruption:(AVAudioRecorder *)recorder
withFlags:(NSUInteger)flags{

if (flags == AVAudioSessionInterruptionFlags_ShouldResume){
NSLog(@"Resuming the recording...");
[recorder record];
}

}
Discussion
]ust like auuio playeis (instances ol AVAudioPlayer), auuio iecoiueis ol type AVAu
dioRecorder also ieceive uelegate messages whenevei the auuio session associateu with
them is ueactivateu Lecause ol an inteiiuption. The two methous mentioneu in this
iecipe`s Solution aie the Lest places to hanule such inteiiuptions. In the case ol an
inteiiuption to the auuio iecoiuei, you can invoke the record instance methou ol
AVAudioRecorder altei the inteiiuption to continue the iecoiuing piocess. Howevei, the
iecoiuing will oveiwiite the pievious iecoiuing, anu all uata iecoiueu Leloie the intei-
iuption will Le lost.
10.4 Handling Interruptions while Recording Audio | 515
www.it-ebooks.info
It is veiy impoitant to Leai in minu that when the uelegate ol youi auuio
iecoiuei ieceives the audioRecorderBeginInterruption: methou, the
auuio session has alieauy Leen ueactivateu, anu invoking the resume
instance methou will not woik on youi auuio iecoiuei. Altei the intei-
iuption has enueu, you must invoke the record instance methou ol youi
AVAudioRecorder to iesume iecoiuing.
10.5 Playing Audio over Other Active Sounds
Problem
You eithei want to put othei applications in silent moue while you play auuio oi play
auuio on top ol othei applications` auuio playLack (il any).
Solution
Use auuio sessions to set the type ol auuio categoiy youi application uses.
Discussion
The AVAudioSession class was intiouuceu in the AV Founuation liamewoik. Eveiy iOS
application has one auuio session. This auuio session can Le accesseu using the share
dInstance class methou ol the AVAudioSession class, like so:
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
Altei ietiieving an instance ol the AVAudioSession class, you can invoke the setCate
gory:error: instance methou ol the auuio session oLject to choose among the uilleient
categoiies availaLle to iOS applications. Dilleient values that can Le set as the auuio
session categoiy ol an application aie listeu heie:
AVAudioSessionCategoryAmbient
This categoiy will not stop the auuio liom othei applications, Lut it will allow you
to play auuio ovei the auuio Leing playeu Ly othei applications, such as the Music
app. The main UI thieau ol youi application will lunction noimally. The prepare
ToPlay anu play instance methous ol AVAudioPlayer will ietuin with the value
YES. The auuio Leing playeu Ly youi application will stop when the usei locks the
scieen. The silent moue silences the auuio playLack ol youi application only il youi
application is the only application playing an auuio lile. Il you stait playing auuio
while the Music app is playing a song, putting the uevice in silent moue uoes not
stop youi auuio playLack.
AVAudioSessionCategorySoloAmbient
This categoiy is exactly like the AVAudioSessionCategoryAmbient categoiy, except
that this categoiy will stop the auuio playLack ol all othei applications, such as the
Music app. Vhen the uevice is put into silent moue, youi auuio playLack will Le
516 | Chapter 10: Audio and Video
www.it-ebooks.info
pauseu. This also happens when the scieen is lockeu. This is the uelault categoiy
that iOS chooses loi an application.
AVAudioSessionCategoryRecord
This stops othei applications` auuio (e.g., the music) anu also will not allow youi
application to initiate an auuio playLack (e.g., using AVAudioPlayer). You can only
iecoiu auuio in this moue. Using this categoiy, calling the prepareToPlay instance
methou ol AVAudioPlayer will ietuin YES anu the play instance methou will ietuin
NO. The main UI inteilace will lunction as usual. The iecoiuing ol youi application
will continue even il the iOS uevice`s scieen is lockeu Ly the usei.
AVAudioSessionCategoryPlayback
This categoiy will silence othei applications` auuio playLack (such as the auuio
playLack ol music applications). You can then use the prepareToPlay anu play
instance methous ol AVAudioPlayer to play a sounu in youi application. The main
UI thieau will lunction as noimal. The auuio playLack will continue even il the
scieen is lockeu Ly the usei oi il the uevice is in silent moue.
AVAudioSessionCategoryPlayAndRecord
This categoiy allows auuio to Le playeu anu iecoiueu at the same time in youi
application. This will stop the auuio playLack ol othei applications when youi
auuio iecoiuing oi playLack Legins. The main UI thieau ol youi application will
lunction as noimal. The playLack anu the iecoiuing will continue even il the scieen
is lockeu oi the uevice is in silent moue.
AVAudioSessionCategoryAudioProcessing
This categoiy can Le useu loi applications that uo auuio piocessing, Lut not auuio
playLack oi iecoiuing. By setting this categoiy, you cannot play oi iecoiu any
auuio in youi application. Calling the prepareToPlay anu play instance methous ol
AVAudioPlayer will ietuin NO. Auuio playLack ol othei applications, such as the
Music app, will also stop il this categoiy is set.
To give you an example ol using AVAudioSession, let`s stait an auuio playei that will
play its auuio lile ovei othei applications` auuio playLack. Ve will Legin with the .h
lile ol a view contiollei:
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
@interface Playing_Audio_over_Other_Active_SoundsViewController
: UIViewController <AVAudioPlayerDelegate>
@property (nonatomic, strong) AVAudioPlayer *audioPlayer;
@end
Heie is how we will altei the auuio session anu then loau a song into the memoiy anu
into an auuio playei loi playing. Ve will uo this in the viewDidLoad methou ol the view
contiollei:
10.5 Playing Audio over Other Active Sounds | 517
www.it-ebooks.info
- (void)viewDidLoad {
[super viewDidLoad];

NSError *audioSessionError = nil;
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
if ([audioSession setCategory:AVAudioSessionCategoryAmbient
error:&audioSessionError]){
NSLog(@"Successfully set the audio session.");
} else {
NSLog(@"Could not set the audio session");
}

dispatch_queue_t dispatchQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_async(dispatchQueue, ^(void) {
NSBundle *mainBundle = [NSBundle mainBundle];

NSString *filePath = [mainBundle pathForResource:@"MySong"
ofType:@"mp3"];

NSData *fileData = [NSData dataWithContentsOfFile:filePath];

NSError *audioPlayerError = nil;

self.audioPlayer = [[AVAudioPlayer alloc] initWithData:fileData
error:&audioPlayerError];

if (self.audioPlayer != nil){

self.audioPlayer.delegate = self;

if ([self.audioPlayer prepareToPlay] &&
[self.audioPlayer play]){
NSLog(@"Successfully started playing.");

} else {
NSLog(@"Failed to play the audio file.");
self.audioPlayer = nil;
} } else {
NSLog(@"Could not instantiate the audio player.");
}
});
}
Next, we will move on to hanuling the AVAudioPlayerDelegate piotocol`s methous:
- (void)audioPlayerBeginInterruption:(AVAudioPlayer *)player{
/* The audio session has been deactivated here */
}
- (void)audioPlayerEndInterruption:(AVAudioPlayer *)player
withFlags:(NSUInteger)flags{
if (flags == AVAudioSessionInterruptionFlags_ShouldResume){
[player play];
518 | Chapter 10: Audio and Video
www.it-ebooks.info
}
}
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player
successfully:(BOOL)flag{

if (flag){
NSLog(@"Audio player stopped correctly.");
} else {
NSLog(@"Audio player did not stop correctly.");
}

if ([player isEqual:self.audioPlayer]){
self.audioPlayer = nil;
} else {
/* This is not the audio player */
}

}
You can see that we aie using the shaieu instance ol the AVAudioSession class in the
viewDidLoad instance methou ol the view contiollei to set the auuio categoiy ol the
application to AVAudioSessionCategoryAmbient in oiuei to allow the application to play
auuio liles ovei othei applications` auuio playLack.
10.6 Playing Video Files
Problem
You woulu like to Le aLle to play viueo liles in youi iOS application.
Solution
Use an instance ol the MPMoviePlayerController class.
Il you simply want to uisplay a lull-scieen movie playei, you can use the
MPMoviePlayerViewController class anu push youi movie playei view
contiollei into the stack ol view contiolleis ol a navigation contiollei
(loi instance), oi simply piesent youi movie playei view contiollei as a
moual contiollei on anothei view contiollei using the presentMovie
PlayerViewControllerAnimated: instance methou ol UIViewController.
In this iecipe, we will use MPMoviePlayerController insteau ol MPMovie
PlayerViewController in oiuei to get lull access to vaiious settings that
a movie playei view contiollei uoes not ollei, such as winuoweu-moue
viueo playLack (not lull-scieen).
10.6 Playing Video Files | 519
www.it-ebooks.info
Discussion
The Meuia Playei liamewoik in the iOS SDK allows piogiammeis to play auuio anu
viueo liles, among othei inteiesting things. To Le aLle to play a viueo lile, we will
instantiate an oLject ol type MPMoviePlayerController like so:
self.moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:url];
In this coue, moviePlayer is a piopeity ol type MPMoviePlayerController uelineu loi the
cuiient view contiollei. In oluei iOS SDKs, piogiammeis hau veiy little contiol ovei
how movies weie playeu using the Meuia Playei liamewoik. Vith the intiouuction ol
the iPau, the whole liamewoik changeu uiastically to give moie contiol to piogiammeis
anu allow them to piesent theii contents with moie llexiLility than Leloie.
An instance ol MPMoviePlayerController has a piopeity calleu view. This view is ol type
UIView anu is the view in which the meuia, such as viueo, will Le playeu. As a pio-
giammei, you aie iesponsiLle loi inseiting this view into youi application`s view hiei-
aichy to piesent youi useis with the content Leing playeu. Since you get a ieleience to
an oLject ol type UIView, you can shape this view howevei you want. Foi instance, you
can simply change the Lackgiounu coloi ol this view to a custom coloi.
Many multimeuia opeiations uepenu on the notilication system. Foi instance, MPMovie
PlayerController uoes not woik with uelegates; insteau, it ielies on notilications. This
allows loi a veiy llexiLle uecoupling Letween the system liLiaiies anu the applications
that iOS piogiammeis wiite. Foi classes such as MPMoviePlayerController, we stait
listening loi notilications that get sent Ly instances ol that class. Ve use the uelault
notilication centei anu auu themselves as an oLseivei loi a notilication.
To Le aLle to test the iecipe, we neeu a sample .nov lile to play with the movie playei.
You can uownloau an Apple-pioviueu sample lile liom http://bit.|y/TtjcP7. Make suie
you uownloau the H.26+ lile loimat. Il this lile is zippeu, unzip it anu iename it to
Sanp|c.n1v. Now uiag anu uiop this lile into youi application Lunule in Xcoue.
Altei uoing this, we can go aheau anu wiite a simple piogiam that attempts to play the
viueo lile loi us. Heie is the .h lile:
#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
@interface Playing_Video_FilesViewController : UIViewController
@property (nonatomic, strong) MPMoviePlayerController *moviePlayer;
@property (nonatomic, strong) UIButton *playButton;
@end
Heie is the implementation ol the startPlayingVideo: methou that we uelineu in
the .h lile:
- (void) startPlayingVideo:(id)paramSender{

/* First let's construct the URL of the file in the application bundle
520 | Chapter 10: Audio and Video
www.it-ebooks.info
that needs to get played by the movie player */
NSBundle *mainBundle = [NSBundle mainBundle];

NSString *urlAsString = [mainBundle pathForResource:@"Sample"
ofType:@"m4v"];

NSURL *url = [NSURL fileURLWithPath:urlAsString];

/* If we have already created a movie player before,
let's try to stop it */
if (self.moviePlayer != nil){
[self stopPlayingVideo:nil];
}

/* Now create a new movie player using the URL */
self.moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:url];

if (self.moviePlayer != nil){

/* Listen for the notification that the movie player sends us
whenever it finishes playing an audio file */
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(videoHasFinishedPlaying:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.moviePlayer];

NSLog(@"Successfully instantiated the movie player.");

/* Scale the movie player to fit the aspect ratio */
self.moviePlayer.scalingMode = MPMovieScalingModeAspectFit;

/* Let's start playing the video in full screen mode */
[self.moviePlayer play];

[self.view addSubview:self.moviePlayer.view];

[self.moviePlayer setFullscreen:YES
animated:YES];

} else {
NSLog(@"Failed to instantiate the movie player.");
}

}
As you can see, we manage the movie playei`s view ouiselves. Il we auu the view ol the
movie playei to the view contiollei`s view, we have to iemove the view manually. This
view will not get iemoveu liom the view contiollei`s view even il we ielease the movie
playei. The lollowing methou stops the viueo anu then iemoves the associateu view:
- (void) stopPlayingVideo:(id)paramSender {

if (self.moviePlayer != nil){

10.6 Playing Video Files | 521
www.it-ebooks.info
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.moviePlayer];

[self.moviePlayer stop];

if ([self.moviePlayer.view.superview isEqual:self.view]){
[self.moviePlayer.view removeFromSuperview];
}
}

}
In the startPlayingVideo: instance methou ol the view contiollei we aie listening loi
the MPMoviePlayerPlaybackDidFinishNotification notilication that MKMoviePlayerView
Controller will senu to the uelault notilication centei. Ve listen to this notilication on
the videoHasFinishedPlaying: instance methou ol the view contiollei. Heie, we can get
notilieu when the movie playLack has linisheu anu peihaps uispose ol the movie playei
oLject:
- (void) videoHasFinishedPlaying:(NSNotification *)paramNotification{

/* Find out what the reason was for the player to stop */
NSNumber *reason =
[paramNotification.userInfo
valueForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey];

if (reason != nil){
NSInteger reasonAsInteger = [reason integerValue];

switch (reasonAsInteger){
case MPMovieFinishReasonPlaybackEnded:{
/* The movie ended normally */
break;
}
case MPMovieFinishReasonPlaybackError:{
/* An error happened and the movie ended */
break;
}
case MPMovieFinishReasonUserExited:{
/* The user exited the player */
break;
}
}

NSLog(@"Finish Reason = %ld", (long)reasonAsInteger);
[self stopPlayingVideo:nil];
} /* if (reason != nil){ */

}
You might have alieauy noticeu that we aie invoking the stopPlayingVideo: instance
methou that we implementeu in the videoHasFinishedPlaying: notilication hanulei.
522 | Chapter 10: Audio and Video
www.it-ebooks.info
Ve uo this Lecause the stopPlayingVideo: instance methou takes caie ol uniegisteiing
the oLject liom the notilications ieceiveu Ly the meuia playei, anu iemoves the meuia
playei liom the supeiview. In othei woius, when the viueo stops playing, it uoes not
necessaiily mean the iesouices we allocateu loi that playei have Leen ueallocateu. Ve
neeu to take caie ol that manually. Beai in minu that the MPMoviePlayerController class
uoes not woik in iPhone Simulatoi. You neeu to iun this coue on a ieal uevice anu
check the iesults loi youisell.
See Also
Recipe 10.7
10.7 Capturing Thumbnails from a Video File
Problem
You aie playing a viueo lile using an instance ol the MPMoviePlayerController class anu
woulu like to captuie a scieenshot liom the movie at a ceitain time.
Solution
Use the requestThumbnailImagesAtTimes:timeOption: instance methou ol MPMovie
PlayerController like so:
/* Capture the frame at the third second into the movie */
NSNumber *thirdSecondThumbnail = [NSNumber numberWithFloat:3.0f];
/* We can ask to capture as many frames as we
want. But for now, we are just asking to capture one frame */
NSArray *requestedThumbnails =
[NSArray arrayWithObject:thirdSecondThumbnail];
/* Ask the movie player to capture this frame for us */
[self.moviePlayer
requestThumbnailImagesAtTimes:requestedThumbnails
timeOption:MPMovieTimeOptionExact];
Discussion
An instance ol MPMoviePlayerController is aLle to captuie thumLnails liom the cui-
iently playing movie, synchionously anu asynchionously. In this iecipe, we aie going
to locus on asynchionous image captuie loi this class.
Ve can use the requestThumbnailImagesAtTimes:timeOption: instance methou ol
MPMoviePlayerController to asynchionously access thumLnails. Vhen I say asyn-
chionously, I mean that uuiing the time the thumLnail is Leing captuieu anu iepoiteu
to youi uesignateu oLject (as we will soon see), the movie playei will continue its woik
anu will not Llock the playLack. Ve must oLseive the MPMoviePlayerThumbnail
10.7 Capturing Thumbnails from a Video File | 523
www.it-ebooks.info
ImageRequestDidFinishNotification notilication message the movie playei senus to the
uelault notilication centei in oiuei to linu out when the thumLnails aie availaLle:
- (void) startPlayingVideo:(id)paramSender{

/* First let's construct the URL of the file in the application bundle
that needs to get played by the movie player */
NSBundle *mainBundle = [NSBundle mainBundle];

NSString *urlAsString = [mainBundle pathForResource:@"Sample"
ofType:@"m4v"];

NSURL *url = [NSURL fileURLWithPath:urlAsString];

/* If we have already created a movie player before,
let's try to stop it */
if (self.moviePlayer != nil){
[self stopPlayingVideo:nil];
}

/* Now create a new movie player using the URL */
self.moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:url];

if (self.moviePlayer != nil){

/* Listen for the notification that the movie player sends us
whenever it finishes playing an audio file */
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(videoHasFinishedPlaying:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.moviePlayer];

[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(videoThumbnailIsAvailable:)
name:MPMoviePlayerThumbnailImageRequestDidFinishNotification
object:self.moviePlayer];

NSLog(@"Successfully instantiated the movie player.");

/* Scale the movie player to fit the aspect ratio */
self.moviePlayer.scalingMode = MPMovieScalingModeAspectFit;

/* Let's start playing the video in full screen mode */
[self.moviePlayer play];

[self.view addSubview:self.moviePlayer.view];

[self.moviePlayer setFullscreen:YES
animated:YES];

/* Capture the frame at the third second into the movie */
NSNumber *thirdSecondThumbnail = [NSNumber numberWithFloat:3.0f];
524 | Chapter 10: Audio and Video
www.it-ebooks.info
/* We can ask to capture as many frames as we
want. But for now, we are just asking to capture one frame */
NSArray *requestedThumbnails =
[NSArray arrayWithObject:thirdSecondThumbnail];

/* Ask the movie player to capture this frame for us */
[self.moviePlayer
requestThumbnailImagesAtTimes:requestedThumbnails
timeOption:MPMovieTimeOptionExact];

} else {
NSLog(@"Failed to instantiate the movie player.");
}

}
You can see that we aie asking the movie playei to captuie the liame at the thiiu seconu
into the movie. Once this task is completeu, the videoThumbnailIsAvailable: instance
methou ol the view contiollei will Le calleu. Heie is how we can access the captuieu
image:
- (void) videoThumbnailIsAvailable:(NSNotification *)paramNotification{

MPMoviePlayerController *controller = [paramNotification object];

if (controller != nil &&
[controller isEqual:self.moviePlayer]){
NSLog(@"Thumbnail is available");

/* Now get the thumbnail out of the user info dictionary */
UIImage *thumbnail =
[paramNotification.userInfo
objectForKey:MPMoviePlayerThumbnailImageKey];

if (thumbnail != nil){
/* We got the thumbnail image. You can now use it here */
}
}

}
Since we staiteu listening to the MPMoviePlayerThumbnailImageRequestDidFinishNotifi
cation notilications when we instantiateu the movie playei oLject in the startPlaying
Video: methou, we must also stop listening loi this notilication whenevei we stop the
movie playei (oi whenevei you Lelieve is appiopiiate uepenuing on youi application
aichitectuie):
- (void) stopPlayingVideo:(id)paramSender {

if (self.moviePlayer != nil){

[[NSNotificationCenter defaultCenter]
removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.moviePlayer];
10.7 Capturing Thumbnails from a Video File | 525
www.it-ebooks.info

[[NSNotificationCenter defaultCenter]
removeObserver:self
name:MPMoviePlayerThumbnailImageRequestDidFinishNotification
object:self.moviePlayer];

[self.moviePlayer stop];

if ([self.moviePlayer.view.superview isEqual:self.view]){
[self.moviePlayer.view removeFromSuperview];
}
}

}
Vhen calling the requestThumbnailImagesAtTimes:timeOption: instance methou ol
MPMoviePlayerController, we can specily one ol two values loi timeOption: MPMo
vieTimeOptionExact oi MPMovieTimeOptionNearestKeyFrame. The loimei gives us the
liame playing at the exact point we ieguesteu in the timeline ol the viueo, wheieas the
lattei is less exact, Lut uses lewei system iesouices anu olleis Lettei peiloimance when
captuiing thumLnails liom a viueo. MPMovieTimeOptionNearestKeyFrame is usually aue-
guate in teims ol piecision Lecause it is just a couple ol liames oll.
10.8 Accessing the Music Library
Problem
You want to access an item that youi usei picks liom hei music liLiaiy.
Solution
Use the MPMediaPickerController class:
MPMediaPickerController *mediaPicker = [[MPMediaPickerController alloc]
initWithMediaTypes:MPMediaTypeAny];
Discussion
MPMediaPickerController is a view contiollei that the Music app uisplays to the usei.
By instantiating MPMediaPickerController, you can piesent a stanuaiu view contiollei
to youi useis to allow them to select whatevei item they want liom theii liLiaiy anu
then tianslei the contiol to youi application. This is paiticulaily uselul in games, loi
instance, wheie the usei plays the game anu can have youi application play his lavoiite
tiacks in the Lackgiounu.
You can get inloimation liom the meuia pickei contiollei Ly Lecoming its uelegate
(conloiming to MPMediaPickerControllerDelegate):
#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
526 | Chapter 10: Audio and Video
www.it-ebooks.info
@interface Accessing_the_Music_LibraryViewController
: UIViewController <MPMediaPickerControllerDelegate>
@end
Insiue youi displayMediaPicker: selectoi, implement the coue ieguiieu to uisplay an
instance ol the meuia pickei contiollei anu piesent it to the usei as a moual view
contiollei:
- (void) displayMediaPicker{

MPMediaPickerController *mediaPicker = [[MPMediaPickerController alloc]
initWithMediaTypes:MPMediaTypeAny];

if (mediaPicker != nil){

NSLog(@"Successfully instantiated a media picker.");
mediaPicker.delegate = self;
mediaPicker.allowsPickingMultipleItems = NO;

[self.navigationController presentModalViewController:mediaPicker
animated:YES];

} else {
NSLog(@"Could not instantiate a media picker.");
}

}
The allowsPickingMultipleItems piopeity ol the meuia pickei contiollei lets you spec-
ily whethei useis can pick moie than one item liom theii liLiaiy Leloie uismissing the
meuia pickei contiollei. This takes a BOOL value, so loi now we just set it to NO; we will
latei see what this looks like. Now let`s implement the vaiious uelegate messages ue-
lineu in the MPMediaPickerControllerDelegate piotocol:
- (void) mediaPicker:(MPMediaPickerController *)mediaPicker
didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection{

NSLog(@"Media Picker returned");

for (MPMediaItem *thisItem in mediaItemCollection.items){

NSURL *itemURL =
[thisItem valueForProperty:MPMediaItemPropertyAssetURL];

NSString *itemTitle =
[thisItem valueForProperty:MPMediaItemPropertyTitle];

NSString *itemArtist =
[thisItem valueForProperty:MPMediaItemPropertyArtist];

MPMediaItemArtwork *itemArtwork =
[thisItem valueForProperty:MPMediaItemPropertyArtwork];

10.8 Accessing the Music Library | 527
www.it-ebooks.info
NSLog(@"Item URL = %@", itemURL);
NSLog(@"Item Title = %@", itemTitle);
NSLog(@"Item Artist = %@", itemArtist);
NSLog(@"Item Artwork = %@", itemArtwork);
}

[mediaPicker dismissModalViewControllerAnimated:YES];

}
You can access uilleient piopeities ol each selecteu item using the valueForProperty:
instance methou ol MPMediaItem. Instances ol this class will Le ietuineu to youi appli-
cation thiough the mediaItemCollection paiametei ol the mediaPicker:didPickMediaI
tems: uelegate message.
Now let`s wiite a piogiam with a veiy simple GUI that allows us to ask the usei to pick
one music item liom his Music liLiaiy. Altei he picks the music lile, we will attempt
to play it using an MPMusicPlayerController instance. The GUI has two simple Luttons:
Pick anu Play, anu Stop Playing. The liist Lutton will ask the usei to pick an item liom
his Music liLiaiy to play, anu the seconu Lutton will stop the auuio playLack (il we aie
alieauy playing the song). Ve will stait with the uesign ol the UI ol the application.
Let`s cieate it in a simple way, as shown in Figuie 10-1.
Iigurc 10-1. A vcry sinp|c U| jor thc ncdia pic|cr and A\ Audio P|aycr
Now let`s go aheau anu ueline these two Luttons in the .h ol the view contiollei:
@interface Accessing_the_Music_LibraryViewController : UIViewController
<MPMediaPickerControllerDelegate, AVAudioPlayerDelegate>
@property (nonatomic, strong) MPMusicPlayerController *myMusicPlayer;
@property (nonatomic, strong) UIButton *buttonPickAndPlay;
528 | Chapter 10: Audio and Video
www.it-ebooks.info
@property (nonatomic, strong) UIButton *buttonStopPlaying;
@end
Vhen the view loaus up, we will then instantiate these two Luttons anu place them on
the view:
- (void)viewDidLoad {
[super viewDidLoad];

self.view.backgroundColor = [UIColor whiteColor];

self.buttonPickAndPlay = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.buttonPickAndPlay.frame = CGRectMake(0.0f,
0.0f,
200,
37.0f);
self.buttonPickAndPlay.center = CGPointMake(self.view.center.x,
self.view.center.y - 50);
[self.buttonPickAndPlay setTitle:@"Pick and Play"
forState:UIControlStateNormal];
[self.buttonPickAndPlay addTarget:self
action:@selector(displayMediaPickerAndPlayItem)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.buttonPickAndPlay];

self.buttonStopPlaying = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.buttonStopPlaying.frame = CGRectMake(0.0f,
0.0f,
200,
37.0f);
self.buttonStopPlaying.center = CGPointMake(self.view.center.x,
self.view.center.y + 50);
[self.buttonStopPlaying setTitle:@"Stop Playing"
forState:UIControlStateNormal];
[self.buttonStopPlaying addTarget:self
action:@selector(stopPlayingAudio)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.buttonStopPlaying];

[self.navigationController setNavigationBarHidden:YES
animated:NO];
}
The two most impoitant methous in the view contiollei aie the displayMediaPicker
AndPlayItem anu stopPlayingAudio:
- (void) stopPlayingAudio{

if (self.myMusicPlayer != nil){

[[NSNotificationCenter defaultCenter]
removeObserver:self
name:MPMusicPlayerControllerPlaybackStateDidChangeNotification
object:self.myMusicPlayer];

10.8 Accessing the Music Library | 529
www.it-ebooks.info
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:MPMusicPlayerControllerNowPlayingItemDidChangeNotification
object:self.myMusicPlayer];

[[NSNotificationCenter defaultCenter]
removeObserver:self
name:MPMusicPlayerControllerVolumeDidChangeNotification
object:self.myMusicPlayer];

[self.myMusicPlayer stop];
}

}
- (void) displayMediaPickerAndPlayItem{

MPMediaPickerController *mediaPicker =
[[MPMediaPickerController alloc]
initWithMediaTypes:MPMediaTypeMusic];

if (mediaPicker != nil){

NSLog(@"Successfully instantiated a media picker.");
mediaPicker.delegate = self;
mediaPicker.allowsPickingMultipleItems = YES;

[self.navigationController presentModalViewController:mediaPicker
animated:YES];

} else {
NSLog(@"Could not instantiate a media picker.");
}

}
Vhen the meuia pickei contiollei succeeus, the mediaPicker:didPickMediaItems mes-
sage will Le calleu in the uelegate oLject (in this case, the view contiollei). On the othei
hanu, il the usei cancels the meuia playei, we`ll get the mediaPicker:mediaPickerDid
Cancel message. The lollowing coue implements the methou that will Le calleu in each
case:
- (void) mediaPicker:(MPMediaPickerController *)mediaPicker
didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection{

NSLog(@"Media Picker returned");

/* First, if we have already created a music player, let's
deallocate it */
self.myMusicPlayer = nil;

self.myMusicPlayer = [[MPMusicPlayerController alloc] init];

[self.myMusicPlayer beginGeneratingPlaybackNotifications];

530 | Chapter 10: Audio and Video
www.it-ebooks.info
/* Get notified when the state of the playback changes */
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(musicPlayerStateChanged:)
name:MPMusicPlayerControllerPlaybackStateDidChangeNotification
object:self.myMusicPlayer];

/* Get notified when the playback moves from one item
to the other. In this recipe, we are only going to allow
the user to pick one music file */
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(nowPlayingItemIsChanged:)
name:MPMusicPlayerControllerNowPlayingItemDidChangeNotification
object:self.myMusicPlayer];

/* And also get notified when the volume of the
music player is changed */
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(volumeIsChanged:)
name:MPMusicPlayerControllerVolumeDidChangeNotification
object:self.myMusicPlayer];

/* Start playing the items in the collection */
[self.myMusicPlayer setQueueWithItemCollection:mediaItemCollection];
[self.myMusicPlayer play];

/* Finally dismiss the media picker controller */
[mediaPicker dismissModalViewControllerAnimated:YES];

}
- (void) mediaPickerDidCancel:(MPMediaPickerController *)mediaPicker{

/* The media picker was cancelled */
NSLog(@"Media Picker was cancelled");
[mediaPicker dismissModalViewControllerAnimated:YES];

}
Ve aie listening loi the events the music playei geneiates thiough the notilications that
it senus. Heie aie the thiee methous that aie going to Le iesponsiLle loi hanuling the
notilications we aie listening to loi the music playei:
- (void) musicPlayerStateChanged:(NSNotification *)paramNotification{

NSLog(@"Player State Changed");

/* Let's get the state of the player */
NSNumber *stateAsObject =
[paramNotification.userInfo
objectForKey:@"MPMusicPlayerControllerPlaybackStateKey"];

NSInteger state = [stateAsObject integerValue];
10.8 Accessing the Music Library | 531
www.it-ebooks.info

/* Make your decision based on the state of the player */
switch (state){
case MPMusicPlaybackStateStopped:{
/* Here the media player has stopped playing the queue. */
break;
}
case MPMusicPlaybackStatePlaying:{
/* The media player is playing the queue. Perhaps you
can reduce some processing that your application
that is using to give more processing power
to the media player */
break;
}
case MPMusicPlaybackStatePaused:{
/* The media playback is paused here. You might want
to indicate this by showing graphics to the user */
break;
}
case MPMusicPlaybackStateInterrupted:{
/* An interruption stopped the playback of the media queue */
break;
}
case MPMusicPlaybackStateSeekingForward:{
/* The user is seeking forward in the queue */
break;
}
case MPMusicPlaybackStateSeekingBackward:{
/* The user is seeking backward in the queue */
break;
}
} /* switch (State){ */

}
- (void) nowPlayingItemIsChanged:(NSNotification *)paramNotification{

NSLog(@"Playing Item Is Changed"); NSString *persistentID =
[paramNotification.userInfo
objectForKey:@"MPMusicPlayerControllerNowPlayingItemPersistentIDKey"];

/* Do something with Persistent ID */
NSLog(@"Persistent ID = %@", persistentID);

}
- (void) volumeIsChanged:(NSNotification *)paramNotification{
NSLog(@"Volume Is Changed");
/* The userInfo dictionary of this notification is normally empty */
}
By iunning the application anu piessing the Pick anu Play Lutton on the view contiollei,
we will Le piesenteu with the meuia pickei contiollei. Once the pickei view contiollei
is uisplayeu, the same Music UI will Le piesenteu to the usei. Altei the usei picks an
item (oi cancels the whole uialog), we will get appiopiiate uelegate messages calleu in
532 | Chapter 10: Audio and Video
www.it-ebooks.info
the view contiollei (since the view contiollei is the uelegate ol the meuia pickei). Altei
the items aie pickeu (we only allow one item in this iecipe, though), we will stait the
music playei anu stait playing the whole collection.
Il you want to allow youi useis to pick moie than one item at a time, simply set the
allowsPickingMultipleItems piopeity ol youi meuia pickei contiollei to YES:
mediaPicker.allowsPickingMultipleItems = YES;
Sometimes when woiking with the meuia pickei contiollei (MPMedia
PickerController), the MPMeuiaPickei: Lost connection to iPou li-
Liaiy message will Le piinteu to the console scieen. This is Lecause the
meuia pickei has Leen inteiiupteu Ly an event, such as syncing with
iTunes while the pickei was Leing uisplayeu to the usei. Immeuiately,
youi mediaPickerDidCancel: uelegate message will Le calleu as well.
10.8 Accessing the Music Library | 533
www.it-ebooks.info
www.it-ebooks.info
CHAPTER 11
Address Book
11.0 Introduction
On an iOS uevice, the Contacts application allows useis to auu contacts to, iemove
contacts liom, anu manipulate theii auuiess Look. The auuiess Look can Le a collection
ol people anu gioups. Each peison can have piopeities such as liist name, last name,
phone numLei, anu email auuiess. Some piopeities can have a single value anu some
can have multiple values. Foi instance, the liist name ol a peison is one value, Lut the
phone numLei can Le multiple values (e.g., il the usei has two home phone numLeis).
The AuuiessBook.liamewoik liamewoik in the iOS SDK allows you to inteiact with
the auuiess Look uataLase on the uevice. You can get the aiiay ol all entities in the
usei`s auuiess Look, inseit anu change values, anu much moie.
To use the auuiess-Look-ielateu lunctions in youi application, lollow these steps to
liist auu AuuiessBook.liamewoik to youi application:
1. Click on youi pioject`s icon in Xcoue.
2. Select the taiget to which you want to auu the AuuiessBook liamewoik.
3. On the top ol the scieen, select the Builu Phases taL.
+. In the Builu Phases taL, linu anu expanu the Link Binaiy with LiLiaiies Lox anu
piess the - Lutton, locateu at the Lottom-lelt coinei ol that Lox.
5. In the list that gets uisplayeu, select AddrcssBoo|.jrancwor| anu piess the Auu
Lutton (see Figuie 11-1).
Altei you`ve auueu the liamewoik to youi application, whenevei you want to use
auuiess-Look-ielateu lunctions, you must incluue the main heauei lile ol the liame-
woik in youi heauei (.h) oi implementation (.n) lile, like so:
#import <UIKit/UIKit.h>
#import <AddressBook/AddressBook.h>
@interface RootViewController : UIViewController
535
www.it-ebooks.info
@end
You can use the Auuiess Book liamewoik on iOS Simulatoi, Lut the
Contacts uataLase on the simulatoi is empty Ly uelault. Il you want to
iun the examples in this chaptei on iOS Simulatoi, liist populate youi
auuiess Look (on the simulatoi) using the Contacts application.
I have populateu my iOS Simulatoi`s contacts uataLase with thiee entiies, as shown in
Figuie 11-2.
I also suggest that you populate the auuiess Look ol youi iOS Simulatoi with as many
values as possiLle: multiple phone numLeis loi woik anu home, uilleient auuiesses,
anu so loith. Only thiough such uiveisity can you coiiectly test the Auuiess Book
liamewoik`s lunctions.
The examples in this chaptei uon`t tiy to hanule all the uilleient types
ol eiiois that an Auuiess Book API coulu thiow. Ve simply check
whethei an API succeeus oi lails. In youi app, howevei, you might neeu
to check these eiiois; loi this ieason, the coue examples ietiieve the
ieleiences to eiiois that might happen uuiing calls to each ol the Au-
uiess Book methous, just loi youi ieleience.
Iigurc 11-1. Adding thc AddrcssBoo| jrancwor| to your app
536 | Chapter 11: Address Book
www.it-ebooks.info
11.1 Requesting Access to the Address Book
Problem
You want to stait accessing the usei`s auuiess Look, which ieguiies the usei to have
gianteu youi app access to the usei`s auuiess Look uataLase. You want to check
whethei you have access so that you uon`t ieceive a iuntime eiioi when you attempt
access.
Solution
In oiuei to linu the cuiient authoiization state ol youi app, call the lunction ABAddress
BookGetAuthorizationStatus in the Auuiess Book liamewoik. This lunction can ietuin
any ol the lollowing values:
kABAuthorizationStatusNotDetermined
The usei has not yet ueciueu whethei she woulu like to giant access to youi
application.
kABAuthorizationStatusDenied
The usei has explicitly uenieu youi application liom having access to the auuiess
Look.
kABAuthorizationStatusAuthorized
The usei has authoiizeu youi application to have access to the auuiess Look on
hei uevice.
Iigurc 11-2. Contacts addcd to iOS Sinu|ator
11.1 Requesting Access to the Address Book | 537
www.it-ebooks.info
kABAuthorizationStatusRestricted
Paiental contiols oi othei peimissions conliguieu on the iOS uevice pievent youi
app liom accessing anu inteiacting with the auuiess Look uataLase on the uevice.
Il you linu out that the status that you ieceiveu liom the ABAddressBookGetAuthoriza
tionStatus lunction is kABAuthorizationStatusNotDetermined, you can use the ABAd
dressBookRequestAccessWithCompletion lunction to ask loi peimission to access the
usei`s auuiess Look uataLase. You have to pass two paiameteis to this lunction:
An Addrcss Boo| rcjcrcncc oj typc ABAddressBookRef
The instance ol the auuiess Look that you want to access.
A conp|ction b|oc| oj typc ABAddressBookRequestAccessCompletionHandler
Altei you call this lunction, iOS will ask the usei il she wants to giant access to
youi application. Regaiuless ol whethei the usei says Yes oi No, this Llock oLject
will Le calleu anu you will then, thiough a Boolean paiametei, get to know whethei
the answei was Yes oi No.
Discussion
Staiting with iOS 6, Apple is guite iightly putting iestiictions on how apps can access
useis` peisonal uata, such as theii contact inloimation. This is uone thiough a usei
inteilace uesigneu Ly Apple that asks the useis explicitly whethei they allow these apps
to access ceitain paits ol theii uevice anu uata, such as theii auuiess Look uataLase.
Since we aie all goou iOS-lanu citizens, we will auheie to these iules anu make suie
that we access the usei`s auuiess Look only il we have Leen gianteu peimission to uo so.
Regaiuless ol what you want to uo with the auuiess Look, whethei to ieau liom it oi
wiite to it, you neeu to make suie that you have Leen gianteu sullicient piivileges. Il
you aie not suie aLout whethei you can access the auuiess Look, simply call the ABAd
dressBookGetAuthorizationStatus lunction as uemonstiateu in this iecipe.
Heie is a little example ol what to uo uepenuing on what the ABAddressBookGetAuthor
izationStatus lunction ietuins to youi application. In this example, we will call the
aloiementioneu lunction anu just gueiy the system aLout the authoiization status ol
oui app with iegaius to the auuiess Look uataLase. Il we aie authoiizeu to access it,
line. Il we have Leen uenieu access, oi theie is a systemwiue iestiiction on auuiess Look
access, we will uisplay an aleit view on the scieen. Il we have not yet Leen given access,
we will ask the usei loi hei peimission to access the auuiess Look:
#import "AppDelegate.h"
#import <AddressBook/AddressBook.h>
NSString *const kDenied = @"Access to address book is denied";
NSString *const kRestricted = @"Access to address book is restricted";
ABAddressBookRef addressBook;
@implementation AppDelegate
538 | Chapter 11: Address Book
www.it-ebooks.info
- (void) displayMessage:(NSString *)paramMessage{
[[[UIAlertView alloc] initWithTitle:nil
message:paramMessage
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil] show];
}
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
CFErrorRef error = NULL;
switch (ABAddressBookGetAuthorizationStatus()){
case kABAuthorizationStatusAuthorized:{
addressBook = ABAddressBookCreateWithOptions(NULL, &error);
/* Do your work and once you are finished ... */
if (addressBook != NULL){
CFRelease(addressBook);
}
break;
}
case kABAuthorizationStatusDenied:{
[self displayMessage:kDenied];
break;
}
case kABAuthorizationStatusNotDetermined:{
addressBook = ABAddressBookCreateWithOptions(NULL, &error);
ABAddressBookRequestAccessWithCompletion
(addressBook, ^(bool granted, CFErrorRef error) {
if (granted){
NSLog(@"Access was granted");
} else {
NSLog(@"Access was not granted");
}
if (addressBook != NULL){
CFRelease(addressBook);
}
});
break;
}
case kABAuthorizationStatusRestricted:{
[self displayMessage:kRestricted];
break;
}
}
self.window = [[UIWindow alloc]
initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
11.1 Requesting Access to the Address Book | 539
www.it-ebooks.info
11.2 Retrieving a Reference to an Address Book
Problem
You woulu like to woik with a usei`s contacts. To uo this, liist you neeu to get a
ieleience to the usei`s auuiess Look uataLase. This ieleience is what you use to ietiieve
entiies, as well as to make anu save changes.
Solution
Use the ABAddressBookCreateWithOptions lunction in the Auuiess Book liamewoik. As
the option, pass NULL anu pass a ieleience to an eiioi oLject to get any eiiois that
may happen uuiing the piocess:
addressBook = ABAddressBookCreateWithOptions(NULL, &error);
Discussion
To get a ieleience to the usei`s auuiess Look uataLase you must liist check whethei
you have peimission, as uiscusseu in Recipe 11.1. Altei peimission is gianteu to youi
app, you can caiiy on to use the ABAddressBookCreateWithOptions lunction. This lunc-
tion ietuins a value ol type ABAddressBookRef that will Le nil il the auuiess Look cannot
Le accesseu. You must check loi nil values Leloie accessing the auuiess Look ieleience
ietuineu Ly this lunction. Attempting to mouily a nil auuiess Look will teiminate youi
application with a iuntime eiioi.
Altei ietiieving a ieleience to the usei`s auuiess Look, you can stait making changes
to the contacts, ieauing the entiies, anu so on. Il you have maue any changes to the
auuiess Look, the ABAddressBookHasUnsavedChanges lunction will tell you Ly ietuining
the value YES.
An instance ol the auuiess Look uataLase ietuineu Ly the ABAddress
BookCreate lunction must Le ieleaseu when you aie linisheu woiking
with it, using the CFRelease Coie Founuation methou, as uemonstiateu
in oui example coue.
Altei ueteimining whethei changes weie maue to the auuiess Look uataLase, you can
eithei save oi uiscaiu these changes using the ABAddressBookSave oi ABAddressBook
Revert pioceuuie, iespectively.
Heie is a little example that will uemonstiate this. In the implementation lile ol youi
app uelegate, ueline an instance vaiiaLle ol type ABAddressBookRef along with the eiioi
stiings that you want to uisplay to the usei shoulu youi app not Le gianteu peimission
to the auuiess Look:
#import "AppDelegate.h"
#import <AddressBook/AddressBook.h>
540 | Chapter 11: Address Book
www.it-ebooks.info
NSString *const kDenied = @"Access to address book is denied";
NSString *const kRestricted = @"Access to address book is restricted";
ABAddressBookRef addressBook;
@implementation AppDelegate
...
Now we go stiaight into the application:didFinishLaunchingWithOptions: instance
methou ol oui app uelegate anu stait checking loi the status ol oui app to see whethei
we can access the auuiess Look:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
CFErrorRef error = NULL;
switch (ABAddressBookGetAuthorizationStatus()){
case kABAuthorizationStatusAuthorized:{
addressBook = ABAddressBookCreateWithOptions(NULL, &error);
[self useAddressBook:addressBook];
if (addressBook != NULL){
CFRelease(addressBook);
}
break;
}
case kABAuthorizationStatusDenied:{
[self displayMessage:kDenied];
break;
}
case kABAuthorizationStatusNotDetermined:{
addressBook = ABAddressBookCreateWithOptions(NULL, &error);
ABAddressBookRequestAccessWithCompletion
(addressBook, ^(bool granted, CFErrorRef error) {
if (granted){
NSLog(@"Access was granted");
[self useAddressBook:addressBook];
} else {
NSLog(@"Access was not granted");
}
if (addressBook != NULL){
CFRelease(addressBook);
}
});
break;
}
case kABAuthorizationStatusRestricted:{
[self displayMessage:kRestricted];
break;
}
}
self.window = [[UIWindow alloc]
11.2 Retrieving a Reference to an Address Book | 541
www.it-ebooks.info
initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
You can see that il we aie alieauy oi have just Leen gianteu peimission to access the
usei`s auuiess Look uataLase, we aie calling a methou calleu useAddressBook:. In this
methou, il we have maue any changes to the auuiess Look, we will save them:
- (void) useAddressBook:(ABAddressBookRef)paramAddressBook{
/* Work with the address book here */
/* Let's see whether we have made any changes to the
address book or not, before attempting to save it */
if (ABAddressBookHasUnsavedChanges(paramAddressBook)){
/* Now decide if you want to save the changes to
the address book */
NSLog(@"Changes were found in the address book.");
BOOL doYouWantToSaveChanges = YES;
/* We can make a decision to save or revert the
address book back to how it was before */
if (doYouWantToSaveChanges){
CFErrorRef saveError = NULL;
if (ABAddressBookSave(paramAddressBook, &saveError)){
/* We successfully saved our changes to the
address book */
} else {
/* We failed to save the changes. You can now
access the [saveError] variable to find out
what the error is */
}
} else {
/* We did NOT want to save the changes to the address
book so let's revert it to how it was before */
ABAddressBookRevert(paramAddressBook);
}
} else {
/* We have not made any changes to the address book */
NSLog(@"No changes to the address book.");
}
}
542 | Chapter 11: Address Book
www.it-ebooks.info
Ve cieateu the doYouWantToSaveChanges local vaiiaLle anu set it to YES
just to uemonstiate that we can, il necessaiy, ieveit an auuiess Look
whose contents have Leen changeu (ieveision is uone thiough the ABAd
dressBookRevert pioceuuie). You can auu coue, loi instance, asking the
usei il he wants the changes to Le saveu oi not, anu il not, you can ieveit
the auuiess Look to its oiiginal state.
Foi moie inloimation aLout impoiting the Auuiess Book liamewoik into youi appli-
cation, please ielei to this chaptei`s Intiouuction.
11.3 Retrieving All the People in the Address Book
Problem
You want to ietiieve all the contacts in the usei`s auuiess Look.
Solution
Use the ABAddressBookCopyArrayOfAllPeople lunction to ietiieve an aiiay ol all contacts:
- (void) readFromAddressBook:(ABAddressBookRef)paramAddressBook{
NSArray *arrayOfAllPeople = (__bridge_transfer NSArray *)
ABAddressBookCopyArrayOfAllPeople(paramAddressBook);
NSUInteger peopleCounter = 0;
for (peopleCounter = 0;
peopleCounter < [arrayOfAllPeople count];
peopleCounter++){
ABRecordRef thisPerson =
(__bridge ABRecordRef)
[arrayOfAllPeople objectAtIndex:peopleCounter];
NSLog(@"%@", thisPerson);
/* Use the [thisPerson] address book record */
}
}
Discussion
Altei accessing the usei`s auuiess Look uataLase, we can call the ABAddressBook
CopyArrayOfAllPeople lunction to ietiieve an aiiay ol all the contacts in that auuiess
Look. The ietuin value ol this lunction is an immutaLle aiiay ol type CFArrayRef. You
can`t woik with this type ol aiiay as you woulu woik with instances ol NSArray, Lut
you have two ways to tiaveise a CFArrayRef aiiay. Fiist, it natively suppoits two lunc-
tions:
11.3 Retrieving All the People in the Address Book | 543
www.it-ebooks.info
CFArrayGetCount
Gets the numLei ol items in an instance ol CFArrayRef. This is similai to the
count instance methou ol an NSArray.
CFArrayGetValueAtIndex
Retiieves an item at a specilic location ol an instance ol CFArrayRef. This is similai
to the objectAtIndex: instance methou ol an NSArray.
Seconu, the CFArrayRef Coie Founuation oLject is one ol the oLjects that suppoits Toll-
Fiee Biiuging to its NS counteipait, NSArray. This means that we can simply Liiuge this
Coie Founuation aiiay anu type-cast it to an instance ol NSArray. This woiks peilectly
unuei ARC, using the __bridge_transfer keywoiu. That keywoiu uecieases the ielei-
ence count on the Coie Founuation oLject, since oui local aiiay is a stiong vaiiaLle Ly
uelault anu will ietain its contents without us having to uo anything else. ]ust as a
ieminuei, all local vaiiaLles aie stiong vaiiaLles, meaning that they will ietain theii
contents. In this case, the ABAddressBookCopyArrayOfAllPeople lunction ietuins a Coie
Founuation aiiay ol all people in an auuiess Look. Altei we place the Coie Founuation
aiiay into a local aiiay (which will ietain oui Coie Founuation aiiay), we aie going to
have to uispose ol the oiiginal Coie Founuation oLject, Leloie it was ietaineu Ly the
local vaiiaLle (Lecause ol the strong local vaiiaLle). Because ol this, we aie using
__bridge_transfer to ueciease the ietain count on the Coie Founuation aiiay anu let
the stiong local vaiiaLle ietain the toll-liee aiiay into an oLject ol type NSArray.
The items that aie put in an aiiay ol all people, ietiieveu Ly calling the ABAddressBook
CopyArrayOfAllPeople lunction, aie ol type ABRecordRef. In Recipe 11.+, you will see
how to access uilleient piopeities ol the entiies, such as a peison`s entiy, in the auuiess
Look uataLase.
See Also
Recipe 11.2
11.4 Retrieving Properties of Address Book Entries
Problem
You have ietiieveu a ieleience to an item in the auuiess Look, such as a peison`s entiy,
anu you want to ietiieve that peison`s piopeities, such as liist anu last names.
Solution
Use the ABRecordCopyValue lunction on the peison`s Auuiess Book iecoiu.
544 | Chapter 11: Address Book
www.it-ebooks.info
Discussion
The iecoius in the auuiess Look uataLase aie ol type ABRecordRef. Each iecoiu coulu
Le eithei a gioup oi a peison. Ve have not uiscusseu gioups yet, so let`s locus on people.
Each peison coulu have vaiious types ol inloimation assigneu to him, such as his liist
name, last name, email auuiess, anu so on. Beai in minu that many ol these values aie
optional, anu at the time ol cieating a new contact in the auuiess Look uataLase, the
usei can simply leave out lielus such as phone numLei, miuule name, email auuiess,
URL, anu so loith.
ABRecordCopyValue accepts an auuiess Look iecoiu anu the piopeity that has to Le
ietiieveu as its two paiameteis. The seconu paiametei is the piopeity ol the iecoiu that
we want to ietiieve. Heie aie some ol the common piopeities (all ol these piopeities
aie uelineu as constant values in the ABPcrson.h heauei lile):
kABPersonFirstNameProperty
This value will ietiieve the liist name ol the given peison. The ietuin value is ol
type CFStringRef, which can Le cast to NSString with a Liiuge cast, so you can uo
just aLout anything you want with the iesults.
kABPersonLastNameProperty
This value will ietiieve the last name ol the given peison. Like the liist name piop-
eity, the ietuin value will Le ol type CFStringRef, which again can Le cast to
NSString.
kABPersonMiddleNameProperty
This value will ietiieve the miuule name ol the given peison. Like the liist name
anu the last name, the ietuin value will Le ol type CFStringRef.
kABPersonEmailProperty
This will ietiieve the given peison`s email auuiess. The ietuin value in this case
will Le ol type ABMultiValueRef. This is a uata type that can contain multiple values
insiue it, like an aiiay, Lut not cxact|y like an aiiay. This type ol uata will Le uis-
cusseu next.
Some ol the values that we ietiieve liom the ABRecordCopyValue lunction aie stiaight-
loiwaiu, geneiic types, such as CFStringRef. But this lunction can also ietuin moie
complicateu values, such as the email ol a contact. The email coulu Le luithei Lioken
uown into home email auuiess, woik email auuiess, anu so on. Values that can Le
luithei Lioken uown like this aie calleu nu|tiva|ucs in the Auuiess Book liamewoik.
Vaiious lunctions allow us to woik with multiple values (which aie ol type
ABMultiValueRef):
ABMultiValueGetCount
Retuins the numLei ol value/laLel paiis that aie insiue the multivalue.
11.4 Retrieving Properties of Address Book Entries | 545
www.it-ebooks.info
ABMultiValueCopyLabelAtIndex
Retuins the laLel associateu with a multivalue item at a specilic inuex (inuexes aie
zeio-Laseu). Foi instance, il the usei has thiee email auuiesses, such as woik, home,
anu test auuiesses, the inuex ol the liist (woik) email auuiess in the email multi-
value woulu Le 0. This lunction will then ietiieve the laLel associateu with that
auuiess (in this example, wor|). Please Leai in minu that multivalues uo not nec-
essaiily have to have laLels. Make suie you check loi NULL values.
ABMultiValueCopyValueAtIndex
Retuins the stiing value associateu with a multivalue item at a specilic inuex (in-
uexes aie zeio-Laseu). Suppose the usei has woik, home, anu test email auuiesses.
Il we pioviue the inuex 0 to this lunction, it will ietiieve the given contact`s woik
email auuiess.
All Coie Founuation aiiay inuexes aie zeio-Laseu, just like theii Cocoa
counteipait aiiay inuexes.
Now let`s go aheau anu wiite a simple methou that can ietiieve all the people in the
auuiess Look anu piint out theii liist name, last name, anu email auuiess oLjects, anu
place it in oui app uelegate:
- (void) readFromAddressBook:(ABAddressBookRef)paramAddressBook{
NSArray *allPeople = (__bridge_transfer NSArray *)
ABAddressBookCopyArrayOfAllPeople(paramAddressBook);
NSUInteger peopleCounter = 0;
for (peopleCounter = 0;
peopleCounter < [allPeople count];
peopleCounter++){
ABRecordRef thisPerson = (__bridge ABRecordRef)
[allPeople objectAtIndex:peopleCounter];
NSString *firstName = (__bridge_transfer NSString *)
ABRecordCopyValue(thisPerson, kABPersonFirstNameProperty);
NSString *lastName = (__bridge_transfer NSString *)
ABRecordCopyValue(thisPerson, kABPersonLastNameProperty);
NSString *email = (__bridge_transfer NSString *)
ABRecordCopyValue(thisPerson, kABPersonEmailProperty);
NSLog(@"First Name = %@", firstName);
NSLog(@"Last Name = %@", lastName);
NSLog(@"Address = %@", email);
}
}
546 | Chapter 11: Address Book
www.it-ebooks.info
Ve will oLviously liist ask loi peimission liom the usei whethei oi not we can access
the uevice`s auuiess Look uataLase. Once peimission is gianteu, we will call this meth-
ou. I will not Le iepeating the coue that ieguests loi peimission again, since we have
alieauy seen this coue a lew times in this chaptei. Please ielei to the Recipe 11.1 iecipe
loi moie inloimation.
Il you iun this app in the iOS Simulatoi loi iOS SDK 6, which has pieuelineu contacts
in the Contacts app, you will get the lollowing piinteu to the console winuow:
First Name = Kate
Last Name = Bell
Address = ABMultiValueRef 0x73948f0 with 2 value(s)
0: _$!<Work>!$_ (0x8d498c0) - kate-bell@mac.com (0x8d498e0)
1: _$!<Work>!$_ (0x8d49130) - www.creative-consulting-inc.com (0x8d49920)
First Name = Daniel
Last Name = Higgins
Address = ABMultiValueRef 0x8d4a4a0 with 1 value(s)
0: _$!<Home>!$_ (0x8d4a460) - d-higgins@mac.com (0x8d4a480)
First Name = John
Last Name = Appleseed
Address = ABMultiValueRef 0x8856180 with 1 value(s)
0: _$!<Work>!$_ (0x884a5b0) - John-Appleseed@mac.com (0x8856160)
First Name = Anna
Last Name = Haro
Address = ABMultiValueRef 0x8d4a0f0 with 1 value(s)
0: _$!<Home>!$_ (0x8d4a0b0) - anna-haro@mac.com (0x8d4a0d0)
First Name = Hank
Last Name = Zakroff
Address = ABMultiValueRef 0x8d4a3c0 with 1 value(s)
0: _$!<Work>!$_ (0x8d4a380) - hank-zakroff@mac.com (0x8d4a3a0)
First Name = David
Last Name = Taylor
Address = ABMultiValueRef 0x8d4a5b0 with 0 value(s)
It`s immeuiately visiLle that the multivalue lielu (email) cannot Le ieau as a plain stiing
oLject. So, using the lunctions that we just leaineu, let`s go aheau anu implement a
methou to accept an oLject ol type ABRecordRef, ieau that iecoiu`s multivalue email
lielu, anu piint the values out to the console:
- (void) logPersonEmails:(ABRecordRef)paramPerson{
if (paramPerson == NULL){
NSLog(@"The given person is NULL.");
return;
}
ABMultiValueRef emails =
ABRecordCopyValue(paramPerson, kABPersonEmailProperty);
if (emails == NULL){
NSLog(@"This contact does not have any emails.");
return;
}
11.4 Retrieving Properties of Address Book Entries | 547
www.it-ebooks.info
/* Go through all the emails */
NSUInteger emailCounter = 0;
for (emailCounter = 0;
emailCounter < ABMultiValueGetCount(emails);
emailCounter++){
/* Get the label of the email (if any) */
NSString *emailLabel = (__bridge_transfer NSString *)
ABMultiValueCopyLabelAtIndex(emails, emailCounter);
NSString *localizedEmailLabel = (__bridge_transfer NSString *)
ABAddressBookCopyLocalizedLabel((__bridge CFStringRef)emailLabel);
/* And then get the email address itself */
NSString *email = (__bridge_transfer NSString *)
ABMultiValueCopyValueAtIndex(emails, emailCounter);
NSLog(@"Label = %@, Localized Label = %@, Email = %@",
emailLabel,
localizedEmailLabel,
email);
}
CFRelease(emails);
}
- (void) readFromAddressBook:(ABAddressBookRef)paramAddressBook{
NSArray *allPeople = (__bridge_transfer NSArray *)
ABAddressBookCopyArrayOfAllPeople(paramAddressBook);
NSUInteger peopleCounter = 0;
for (peopleCounter = 0;
peopleCounter < [allPeople count];
peopleCounter++){
ABRecordRef thisPerson = (__bridge ABRecordRef)
[allPeople objectAtIndex:peopleCounter];
NSString *firstName = (__bridge_transfer NSString *)
ABRecordCopyValue(thisPerson, kABPersonFirstNameProperty);
NSString *lastName = (__bridge_transfer NSString *)
ABRecordCopyValue(thisPerson, kABPersonLastNameProperty);
NSLog(@"First Name = %@", firstName);
NSLog(@"Last Name = %@", lastName);
[self logPersonEmails:thisPerson];
}
}
548 | Chapter 11: Address Book
www.it-ebooks.info
Calling the CFRelease pioceuuie on a NULL value will ciash youi appli-
cation. Make suie you check loi NULL values Leloie calling this Coie
Founuation pioceuuie.
LaLel values ietuineu Ly the ABMultiValueCopyLabelAtIndex lunction aie iathei ciyptic
anu haiu to ieau. Examples aie _$!<Other>!$_ anu _$!<Home>!$_, which might Le set
loi email auuiesses with laLels ol Othei anu Home. Howevei, il you want to ietiieve a
plain anu ieauaLle veision ol these laLels, you can liist copy the laLel using the ABMul
tiValueCopyLabelAtIndex lunction anu pass the ietuin value ol this lunction to the
ABAddressBookCopyLocalizedLabel lunction.
See Also
Recipe 11.2; Recipe 11.3
11.5 Inserting a Person Entry into the Address Book
Problem
You want to cieate a new peison contact anu inseit it into the usei`s auuiess Look.
Solution
Use the ABPersonCreate lunction to cieate a new peison. Set the peison`s piopeities
using the ABRecordSetValue lunction anu auu the peison to the auuiess Look using the
ABAddressBookAddRecord lunction.
Discussion
Altei accessing the auuiess Look uataLase using the ABAddressBookCreate lunction, you
can stait inseiting new gioup anu peison iecoius into the uataLase. In this iecipe, we
will concentiate on inseiting new peison iecoius. Foi inloimation aLout inseiting new
gioups into the auuiess Look, please ielei to Recipe 11.6.
Use the ABPersonCreate lunction to cieate a new peison iecoiu. Beai in minu that calling
this lunction is not enough to auu the peison iecoiu to the auuiess Look. You must
save the auuiess Look loi youi iecoiu to appeai in the uataLase.
By calling the ABPersonCreate lunction, you get a Coie Founuation ieleience to a value
ol type ABRecordRef. Now you can call the ABRecordSetValue lunction to set the vaiious
piopeities ol a new peison entiy. Once you aie uone, you must auu the new peison
iecoiu to the uataLase. You can uo this using the ABAddressBookAddRecord lunction.
Altei uoing this, you must also save any unsaveu changes to the auuiess Look uataLase
in oiuei to tiuly pieseive youi new peison iecoiu. Do this Ly using the ABAddressBook
Save lunction.
11.5 Inserting a Person Entry into the Address Book | 549
www.it-ebooks.info
So let`s comLine all this into a methou that allows us to inseit a new peison entiy into
the auuiess Look:
- (ABRecordRef) newPersonWithFirstName:(NSString *)paramFirstName
lastName:(NSString *)paramLastName
inAddressBook:(ABAddressBookRef)paramAddressBook{
ABRecordRef result = NULL;
if (paramAddressBook == NULL){
NSLog(@"The address book is NULL.");
return NULL;
}
if ([paramFirstName length] == 0 &&
[paramLastName length] == 0){
NSLog(@"First name and last name are both empty.");
return NULL;
}
result = ABPersonCreate();
if (result == NULL){
NSLog(@"Failed to create a new person.");
return NULL;
}
BOOL couldSetFirstName = NO;
BOOL couldSetLastName = NO;
CFErrorRef setFirstNameError = NULL;
CFErrorRef setLastNameError = NULL;
couldSetFirstName = ABRecordSetValue(result,
kABPersonFirstNameProperty,
(__bridge CFTypeRef)paramFirstName,
&setFirstNameError);
couldSetLastName = ABRecordSetValue(result,
kABPersonLastNameProperty,
(__bridge CFTypeRef)paramLastName,
&setLastNameError);
CFErrorRef couldAddPersonError = NULL;
BOOL couldAddPerson = ABAddressBookAddRecord(paramAddressBook,
result,
&couldAddPersonError);
if (couldAddPerson){
NSLog(@"Successfully added the person.");
} else {
NSLog(@"Failed to add the person.");
CFRelease(result);
result = NULL;
return result;
}
550 | Chapter 11: Address Book
www.it-ebooks.info
if (ABAddressBookHasUnsavedChanges(paramAddressBook)){
CFErrorRef couldSaveAddressBookError = NULL;
BOOL couldSaveAddressBook = ABAddressBookSave(paramAddressBook,
&couldSaveAddressBookError);
if (couldSaveAddressBook){
NSLog(@"Successfully saved the address book.");
} else {
NSLog(@"Failed to save the address book.");
}
}
if (couldSetFirstName &&
couldSetLastName){
NSLog(@"Successfully set the first name and the last name of the person.");
} else {
NSLog(@"Failed to set the first name and/or last name of the person.");
}
return result;
}
- (void) createNewPersonInAddressBook:(ABAddressBookRef)paramAddressBook{
ABRecordRef anthonyRobbins = [self newPersonWithFirstName:@"Anthony"
lastName:@"Robbins"
inAddressBook:paramAddressBook];
if (anthonyRobbins != NULL){
NSLog(@"Anthony Robbins' record is inserted into the Address Book.");
CFRelease(anthonyRobbins);
}
}
In oui app uelegate, we will liist check il we have peimission to access the usei`s auuiess
Look uataLase. Ve have alieauy seen this coue in Recipe 11.1, so we won`t Le iepeating
it heie. Once you have access, you can then call the createNewPersonInAddressBook:
methou that we have wiitten anu pass the instance ol the auuiess Look oLject to this
methou.
The newPersonWithFirstName:lastName:inAddressBook: methou that we implementeu
cieates a new peison entiy in the auuiess Look uataLase. Altei invoking this lunction,
you will see the iesults (as shown in Figuie 11-3) in the Contacts application on the
iOS Simulatoi.
11.5 Inserting a Person Entry into the Address Book | 551
www.it-ebooks.info
Memoiy management on Coie Founuation is guite uilleient liom what
you might Le useu to when wiiting applications loi Cocoa Touch. As
this topic is Leyonu the scope ol this Look, please make suie you ieau
the Memoiy Management Piogiamming Guiue loi Coie Founuation
uocumentation on Apple`s weLsite.
11.6 Inserting a Group Entry into the Address Book
Problem
You want to categoiize youi contacts into gioups.
Solution
Use the ABGroupCreate lunction.
Beai in minu that, as mentioneu Leloie, Coie Founuation memoiy management is moie
complex than what Xcoue`s static analyzei coulu piocess. Theieloie, attempting to use
the LLVM compilei to compile Coie Founuation coue with static analysis tuineu on
might give you a lot ol wainings. You can ignoie these anu test the coue with Instiu-
ments to make suie youi coue uoes not leak, Lut I encouiage you to lamiliaiize youisell
with memoiy management in Coie Founuation Ly ieauing Apple`s Memoiy Manage-
ment Piogiamming Guiue loi Coie Founuation uocument, as mentioneu in the pie-
vious section.
Discussion
Altei ietiieving the ieleience to the auuiess Look uataLase, you can call the ABGroup
Create lunction to cieate a new gioup entiy. Howevei, you must peiloim a lew moie
opeiations Leloie you can inseit this gioup into the auuiess Look opeiation. The liist
Iigurc 11-3. A ncw pcrson rccord is addcd to thc addrcss boo|
552 | Chapter 11: Address Book
www.it-ebooks.info
thing you have to uo is set the name ol this gioup using the ABRecordSetValue lunction
with the kABGroupNameProperty piopeity, as shown in the example coue.
Altei the name ol the gioup is set, auu it to the auuiess Look uataLase just like you auu
a new peison`s entiyusing the ABAddressBookAddRecord lunction. Foi moie inloima-
tion aLout auuing a new peison`s entiy to the auuiess Look uataLase, please ieau
Recipe 11.5.
Inseiting a new gioup with a name that alieauy exists in the auuiess
Look uataLase will cieate a new gioup with the same name Lut with no
gioup memLeis. In latei iecipes, we will leain how to avoiu uoing this
Ly liist linuing the gioups in the uataLase anu making suie a gioup with
that name uoesn`t alieauy exist.
Altei auuing the gioup to the auuiess Look, you also neeu to save the auuiess Look`s
contents using the ABAddressBookSave lunction.
So, with all this in minu, let`s go aheau anu implement a methou that allows us to cieate
a new gioup with any uesiieu name in the Auuiess Book uataLase:
- (ABRecordRef) newGroupWithName:(NSString *)paramGroupName
inAddressBook:(ABAddressBookRef)paramAddressBook{
ABRecordRef result = NULL;
if (paramAddressBook == NULL){
NSLog(@"The address book is nil.");
return NULL;
}
result = ABGroupCreate();
if (result == NULL){
NSLog(@"Failed to create a new group.");
return NULL;
}
BOOL couldSetGroupName = NO;
CFErrorRef error = NULL;
couldSetGroupName = ABRecordSetValue(result,
kABGroupNameProperty,
(__bridge CFTypeRef)paramGroupName,
&error);
if (couldSetGroupName){
BOOL couldAddRecord = NO;
CFErrorRef couldAddRecordError = NULL;
11.6 Inserting a Group Entry into the Address Book | 553
www.it-ebooks.info
couldAddRecord = ABAddressBookAddRecord(paramAddressBook,
result,
&couldAddRecordError);
if (couldAddRecord){
NSLog(@"Successfully added the new group.");
if (ABAddressBookHasUnsavedChanges(paramAddressBook)){
BOOL couldSaveAddressBook = NO;
CFErrorRef couldSaveAddressBookError = NULL;
couldSaveAddressBook = ABAddressBookSave(paramAddressBook,
&couldSaveAddressBookError);
if (couldSaveAddressBook){
NSLog(@"Successfully saved the address book.");
} else {
CFRelease(result);
result = NULL;
NSLog(@"Failed to save the address book.");
}
} else {
CFRelease(result);
result = NULL;
NSLog(@"No unsaved changes.");
}
} else {
CFRelease(result);
result = NULL;
NSLog(@"Could not add a new group.");
}
} else {
CFRelease(result);
result = NULL;
NSLog(@"Failed to set the name of the group.");
}
return result;
}
- (void) createNewGroupInAddressBook:(ABAddressBookRef)paramAddressBook{
ABRecordRef personalCoachesGroup =
[self newGroupWithName:@"Personal Coaches"
inAddressBook:paramAddressBook];
if (personalCoachesGroup != NULL){
NSLog(@"Successfully created the group.");
CFRelease(personalCoachesGroup);
} else {
NSLog(@"Could not create the group.");
}
}
554 | Chapter 11: Address Book
www.it-ebooks.info
All we have to uo now is to call the createNewGroupInAddressBook: methou when oui
app uelegate staits, to make suie that it woiks as expecteu. Beloie you attempt to call
this methou though, uo make suie that youi app has the ieguiieu peimission to access
the usei`s auuiess Look uataLase. To ieau moie aLout this, please have a look at
Recipe 11.1.
Altei iunning youi coue, you will see iesults like those shown in Figuie 11-+ (you might
have cieateu othei gioups alieauy, so youi auuiess Look might not look exactly like
that shown in the liguie).
Iigurc 11-1. A ncw group crcatcd in thc addrcss boo| databasc
11.7 Adding Persons to Groups
Problem
You want to assign a peison entiy in the auuiess Look to a gioup.
Solution
Use the ABGroupAddMember lunction.
Discussion
Ve leaineu to inseit Loth peison entiies (in Recipe 11.5) anu gioup entiies (in
Recipe 11.6) into the auuiess Look uataLase. In those iecipes we implementeu two
custom methous nameu newPersonWithFirstName:lastName:inAddressBook: anu new
GroupWithName:inAddressBook:. Now we want to auu the peison entiy to the gioup we
11.7 Adding Persons to Groups | 555
www.it-ebooks.info
cieateu anu save the inloimation to the auuiess Look uataLase. ComLining these thiee
iecipes, we can use the lollowing coue to achieve oui goal:
- (BOOL) addPerson:(ABRecordRef)paramPerson
toGroup:(ABRecordRef)paramGroup
saveToAddressBook:(ABAddressBookRef)paramAddressBook{
BOOL result = NO;
if (paramPerson == NULL ||
paramGroup == NULL ||
paramAddressBook == NULL){
NSLog(@"Invalid parameters are given.");
return NO;
}
CFErrorRef error = NULL;
/* Now attempt to add the person entry to the group */
result = ABGroupAddMember(paramGroup,
paramPerson,
&error);
if (result == NO){
NSLog(@"Could not add the person to the group.");
return result;
}
/* Make sure we save any unsaved changes */
if (ABAddressBookHasUnsavedChanges(paramAddressBook)){
BOOL couldSaveAddressBook = NO;
CFErrorRef couldSaveAddressBookError = NULL;
couldSaveAddressBook = ABAddressBookSave(paramAddressBook,
&couldSaveAddressBookError);
if (couldSaveAddressBook){
NSLog(@"Successfully added the person to the group.");
result = YES;
} else {
NSLog(@"Failed to save the address book.");
}
} else {
NSLog(@"No changes were saved.");
}
return result;
}
- (void) addPersonsAndGroupsToAddressBook:(ABAddressBookRef)paramAddressBook{
ABRecordRef richardBranson = [self
newPersonWithFirstName:@"Richard"
lastName:@"Branson"
inAddressBook:paramAddressBook];
556 | Chapter 11: Address Book
www.it-ebooks.info
if (richardBranson != NULL){
ABRecordRef entrepreneursGroup = [self
newGroupWithName:@"Entrepreneurs"
inAddressBook:paramAddressBook];
if (entrepreneursGroup != NULL){
if ([self addPerson:richardBranson
toGroup:entrepreneursGroup
saveToAddressBook:paramAddressBook]){
NSLog(@"Successfully added Richard Branson \
to the Entrepreneurs Group");
} else {
NSLog(@"Failed to add Richard Branson to the \
Entrepreneurs group.");
}
CFRelease(entrepreneursGroup);
} else {
NSLog(@"Failed to create the Entrepreneurs group.");
}
CFRelease(richardBranson);
} else {
NSLog(@"Failed to create an entity for Richard Branson.");
}
}
Once youi app staits, you neeu to make suie youi app has peimission to access anu
upuate the usei`s auuiess Look. Foi moie inloimation aLout this, please see
Recipe 11.1. Once you aie suie that you have peimission, you can call the addPerson
sAndGroupsToAddressBook: methou anu pass the instance ol auuiess Look that you ie-
tiieveu liom the system as a paiametei to this methou. Once that is uone, Ve can see
that the peison entiy we auueu to the Entiepieneuis gioup anu to the uataLase is,
in lact, now insiue this auuiess Look gioup, as shown in Figuie 11-5.
See Also
Recipe 11.6
11.8 Searching the Address Book
Problem
You want to linu a specilic peison oi gioup in the auuiess Look uataLase.
11.8 Searching the Address Book | 557
www.it-ebooks.info
Solution
Use the ABAddressBookCopyArrayOfAllPeople anu ABAddressBookCopyArrayOfAllGroups
lunctions to linu all people anu gioups in the auuiess Look. Tiaveise the ietuineu aiiays
to linu the inloimation you aie looking loi. Alteinatively, you can use the ABAddress
BookCopyPeopleWithName lunction to linu an entiy aLout a peison with a specilic name.
Discussion
Up to this point, we have Leen inseiting gioup anu peison entiies into the auuiess Look
without checking whethei such a gioup oi peison alieauy exists. Ve can use the AB
AddressBookCopyArrayOfAllPeople anu ABAddressBookCopyArrayOfAllGroups lunctions
to get the aiiay ol all people anu gioups in the auuiess Look anu seaich in the aiiay to
see whethei the peison oi gioup entiies we aie aLout to inseit into the auuiess Look
alieauy exist. Vhen we check whethei stiings match, we also have to check loi null
stiings (which we assume mean that the contacts match). Heie aie two methous that
will make use ol these lunctions anu that can also Le useu in othei iecipes:
- (BOOL) doesPersonExistWithFirstName:(NSString *)paramFirstName
lastName:(NSString *)paramLastName
inAddressBook:(ABRecordRef)paramAddressBook{
BOOL result = NO;
if (paramAddressBook == NULL){
NSLog(@"The address book is null.");
return NO;
}
NSArray *allPeople = (__bridge_transfer NSArray *)
Iigurc 11-5. Adding a pcrson to a group
558 | Chapter 11: Address Book
www.it-ebooks.info
ABAddressBookCopyArrayOfAllPeople(paramAddressBook);
NSUInteger peopleCounter = 0;
for (peopleCounter = 0;
peopleCounter < [allPeople count];
peopleCounter++){
ABRecordRef person = (__bridge ABRecordRef)
[allPeople objectAtIndex:peopleCounter];
NSString *firstName = (__bridge_transfer NSString *)
ABRecordCopyValue(person, kABPersonFirstNameProperty);
NSString *lastName = (__bridge_transfer NSString *)
ABRecordCopyValue(person, kABPersonLastNameProperty);
BOOL firstNameIsEqual = NO;
BOOL lastNameIsEqual = NO;
if ([firstName length] == 0 &&
[paramFirstName length] == 0){
firstNameIsEqual = YES;
}
else if ([firstName isEqualToString:paramFirstName]){
firstNameIsEqual = YES;
}
if ([lastName length] == 0 &&
[paramLastName length] == 0){
lastNameIsEqual = YES;
}
else if ([lastName isEqualToString:paramLastName]){
lastNameIsEqual = YES;
}
if (firstNameIsEqual &&
lastNameIsEqual){
return YES;
}
}
return result;
}
Similaily, we can check the existence ol a gioup Ly liist ietiieving the aiiay ol all the
gioups in the auuiess Look uataLase, using the ABAddressBookCopyArrayOfAllGroups
lunction:
- (BOOL) doesGroupExistWithGroupName:(NSString *)paramGroupName
inAddressBook:(ABAddressBookRef)paramAddressBook{
BOOL result = NO;
11.8 Searching the Address Book | 559
www.it-ebooks.info
if (paramAddressBook == NULL){
NSLog(@"The address book is null.");
return NO;
}
NSArray *allGroups = (__bridge_transfer NSArray *)
ABAddressBookCopyArrayOfAllGroups(paramAddressBook);
NSUInteger groupCounter = 0;
for (groupCounter = 0;
groupCounter < [allGroups count];
groupCounter++){
ABRecordRef group = (__bridge ABRecordRef)
[allGroups objectAtIndex:groupCounter];
NSString *groupName = (__bridge_transfer NSString *)
ABRecordCopyValue(group, kABGroupNameProperty);
if ([groupName length] == 0 &&
[paramGroupName length] == 0){
return YES;
}
else if ([groupName isEqualToString:paramGroupName]){
return YES;
}
}
return result;
}
Attempting to cieate a gioup with the name egual to @"" (an empty
stiing), nil, oi NULL will cieate a new gioup with the name Contacts
in the auuiess Look uataLase. Please tiy to avoiu cieating gioups with
empty names oi names egual to nil oi NULL.
Ve can use the doesGroupExistWithGroupName:inAddressBook: methou in this way:
- (void) createGroupInAddressBook:(ABAddressBookRef)paramAddressBook{
if ([self doesGroupExistWithGroupName:@"O'Reilly"
inAddressBook:addressBook]){
NSLog(@"The O'Reilly group already exists in the address book.");
} else {
ABRecordRef oreillyGroup = [self newGroupWithName:@"O'Reilly"
inAddressBook:addressBook];
if (oreillyGroup != NULL){
NSLog(@"Successfully created a group for O'Reilly.");
560 | Chapter 11: Address Book
www.it-ebooks.info
CFRelease(oreillyGroup);
} else {
NSLog(@"Failed to create a group for O'Reilly.");
}
}
}
Foi the implementation ol the createNewGroupWithName:inAddressBook: methou, please
ielei to Recipe 11.6.
As we saw eailiei, we have two ways ol linuing a peison in the auuiess Look uataLase:
Retiieve the aiiay ol all people in the auuiess Look, using the ABAddressBookCopy
ArrayOfAllPeople lunction. Next, get each iecoiu insiue the aiiay anu compaie the
liist anu last name piopeities ol each peison with the stiings you aie looking loi.
You can seaich in any ol the piopeities assigneu to that peison in the auuiess Look,
incluuing liist name, last name, email, phone numLei, anu so on.
Ask the Auuiess Book liamewoik to peiloim the seaich Laseu on a composite
name. This is uone using the ABAddressBookCopyPeopleWithName lunction.
Heie is an example ol using the ABAddressBookCopyPeopleWithName lunction to seaich
loi a contact with a specilic name:
- (BOOL) doesPersonExistWithFullName:(NSString *)paramFullName
inAddressBook:(ABAddressBookRef)paramAddressBook{
BOOL result = NO;
if (paramAddressBook == NULL){
NSLog(@"Address book is null.");
return NO;
}
NSArray *allPeopleWithThisName = (__bridge_transfer NSArray *)
ABAddressBookCopyPeopleWithName(paramAddressBook,
(__bridge CFStringRef)paramFullName);
if ([allPeopleWithThisName count] > 0){
result = YES;
}
return result;
}
Heie is how we can use the methou that we just implementeu:
- (void) createPersonInAddressBook:(ABAddressBookRef)paramAddressBook{
if ([self doesPersonExistWithFullName:@"Anthony Robbins"
inAddressBook:addressBook]){
NSLog(@"Anthony Robbins exists in the address book.");
11.8 Searching the Address Book | 561
www.it-ebooks.info
} else {
NSLog(@"Anthony Robbins does not exist in the address book.");
ABRecordRef anthonyRobbins = [self newPersonWithFirstName:@"Anthony"
lastName:@"Robbins"
inAddressBook:addressBook];
if (anthonyRobbins != NULL){
NSLog(@"Successfully created a record for Anthony Robbins");
CFRelease(anthonyRobbins);
} else {
NSLog(@"Failed to create a record for Anthony Robbins");
}
}
}
Using this lunction, you won`t have to know the lull name to Le aLle to linu a contact
in the auuiess Look. You can just pass a pait ol the nameloi instance, just the liist
namein oiuei to linu all the contacts with that specilic liist name.
The seaich peiloimeu Ly the ABAddressBookCopyPeopleWithName lunc-
tion is case-insensitive.
11.9 Retrieving and Setting a Persons Address Book Image
Problem
You want to Le aLle to ietiieve anu set the images ol auuiess Look people entiies.
Solution
Use one ol the lollowing lunctions:
ABPersonHasImageData
Use this lunction to linu out il an auuiess Look entiy has an image set.
ABPersonCopyImageData
Use this lunction to ietiieve the image uata (il any).
ABPersonSetImageData
Use this lunction to set the image uata loi an entiy.
Discussion
As mentioneu in this iecipe`s Solution, we can use the ABPersonCopyImageData lunction
to ietiieve the uata associateu with an image ol a peison entiy in the auuiess Look. Ve
can use this lunction in a methou ol oui own to make it moie convenient to use:
562 | Chapter 11: Address Book
www.it-ebooks.info
- (UIImage *) getPersonImage:(ABRecordRef)paramPerson{
UIImage *result = nil;
if (paramPerson == NULL){
NSLog(@"The person is nil.");
return NULL;
}
NSData *imageData = (__bridge_transfer NSData *)
ABPersonCopyImageData(paramPerson);
if (imageData != nil){
UIImage *image = [UIImage imageWithData:imageData];
result = image;
}
return result;
}
The ABPersonSetImageData lunction sets the image uata loi a peison entiy in the auuiess
Look. Since this lunction uses uata, not the image itsell, we neeu to get NSData liom
UIImage. Il we want the uata peitaining to a PNG image, we can use the UIIma
gePNGRepresentation lunction to ietiieve the PNG NSData iepiesentation ol the image
ol type UIImage. To ietiieve ]PEG image uata liom an instance ol UIImage, use the
UIImageJPEGRepresentation lunction. Heie is the methou that will allow you to set the
image ol a peison entiy in the auuiess Look uataLase:
- (BOOL) setPersonImage:(ABRecordRef)paramPerson
inAddressBook:(ABAddressBookRef)paramAddressBook
withImageData:(NSData *)paramImageData{
BOOL result = NO;
if (paramAddressBook == NULL){
NSLog(@"The address book is nil.");
return NO;
}
if (paramPerson == NULL){
NSLog(@"The person is nil.");
return NO;
}
CFErrorRef couldSetPersonImageError = NULL;
BOOL couldSetPersonImage =
ABPersonSetImageData(paramPerson,
(__bridge CFDataRef)paramImageData,
&couldSetPersonImageError);
if (couldSetPersonImage){
NSLog(@"Successfully set the person's image. Saving...");
11.9 Retrieving and Setting a Persons Address Book Image | 563
www.it-ebooks.info
if (ABAddressBookHasUnsavedChanges(paramAddressBook)){
BOOL couldSaveAddressBook = NO;
CFErrorRef couldSaveAddressBookError = NULL;
couldSaveAddressBook =
ABAddressBookSave(paramAddressBook,
&couldSaveAddressBookError);
if (couldSaveAddressBook){
NSLog(@"Successfully saved the address book.");
result = YES;
} else {
NSLog(@"Failed to save the address book.");
}
} else {
NSLog(@"There are no changes to be saved!");
}
} else {
NSLog(@"Failed to set the person's image.");
}
return result;
}
Now let`s wiite a simple application to uemonstiate the use ol these methous. In this
example coue, we want to achieve the lollowing:
Cieate a simple view contiollei with two laLels anu two image views.
Attempt to ietiieve a contact with the liist name Anthony anu the last name
RoLLins liom oui auuiess Look. Il this contact uoesn`t exist, we will cieate it.
Retiieve the pievious image (il any) ol the contact anu uisplay it in the liist image
view (the top image view).
Set a new image loi the contact, ietiieveu liom oui application Lunule, anu uisplay
the new image in the seconu image view (the Lottom image view).
Let`s get staiteu. Heie is the .h lile ol oui view contiollei:
#import <UIKit/UIKit.h>
#import <AddressBook/AddressBook.h>
@interface ViewController : UIViewController
@property (nonatomic, strong) UILabel *labelOldImage;
@property (nonatomic, strong) UIImageView *imageViewOld;
@property (nonatomic, strong) UILabel *labelNewImage;
@property (nonatomic, strong) UIImageView *imageViewNew;
@end
The next stop is the viewDidLoad methou ol oui view contiollei, wheie we will instan-
tiate oui laLels anu image views anu place them on oui view contiollei`s view. Ve neeu
564 | Chapter 11: Address Book
www.it-ebooks.info
to wiite oui viewDidLoad methou in a way that we can ieau a peison`s image liom the
auuiess Look anu then set his image anu uisplay the new one, using the lunctions we`ve
leaineu aLout in this anu othei iecipes in this chaptei:
- (void) changeYPositionOfView:(UIView *)paramView
to:(CGFloat)paramY{
CGRect viewFrame = paramView.frame;
viewFrame.origin.y = paramY;
paramView.frame = viewFrame;
}
- (void) createLabelAndImageViewForOldImage{
self.labelOldImage = [[UILabel alloc] initWithFrame:CGRectZero];
self.labelOldImage.text = @"Old Image";
self.labelOldImage.font = [UIFont systemFontOfSize:16.0f];
[self.labelOldImage sizeToFit];
self.labelOldImage.center = self.view.center;
[self.view addSubview:self.labelOldImage];
[self changeYPositionOfView:self.labelOldImage
to:80.0f];
self.imageViewOld = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f,
0.0f,
100.0f,
100.0f)];
self.imageViewOld.center = self.view.center;
self.imageViewOld.contentMode = UIViewContentModeScaleAspectFit;
[self.view addSubview:self.imageViewOld];
[self changeYPositionOfView:self.imageViewOld
to:105.0f];
}
- (void) createLabelAndImageViewForNewImage{
self.labelNewImage = [[UILabel alloc] initWithFrame:CGRectZero];
self.labelNewImage.text = @"New Image";
self.labelNewImage.font = [UIFont systemFontOfSize:16.0f];
[self.labelNewImage sizeToFit];
self.labelNewImage.center = self.view.center;
[self.view addSubview:self.labelNewImage];
[self changeYPositionOfView:self.labelNewImage
to:210.0f];
self.imageViewNew = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f,
0.0f,
100.0f,
100.0f)];
self.imageViewNew.center = self.view.center;
self.imageViewNew.contentMode = UIViewContentModeScaleAspectFit;
[self.view addSubview:self.imageViewNew];
[self changeYPositionOfView:self.imageViewNew
11.9 Retrieving and Setting a Persons Address Book Image | 565
www.it-ebooks.info
to:235.0f];
}
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
[self createLabelAndImageViewForOldImage];
[self createLabelAndImageViewForNewImage];
}
The next stop woulu Le to ask the usei loi peimission to access the uevice`s auuiess
Look uataLase. The Lest place to uo this is when we know oui view has appeaieu on
the scieen anu that woulu Le insiue the viewDidAppear: instance methou ol oui view
contiollei. In that methou, we will simply gueiy the system to see il oui app has alieauy
Leen authoiizeu to access the usei`s auuiess Look:
- (ABRecordRef) getPersonWithFirstName:(NSString *)paramFirstName
lastName:(NSString *)paramLastName
inAddressBook:(ABRecordRef)paramAddressBook{
ABRecordRef result = NULL;
if (paramAddressBook == NULL){
NSLog(@"The address book is null.");
return NULL;
}
NSArray *allPeople = (__bridge_transfer NSArray *)
ABAddressBookCopyArrayOfAllPeople(paramAddressBook);
NSUInteger peopleCounter = 0;
for (peopleCounter = 0;
peopleCounter < [allPeople count];
peopleCounter++){
ABRecordRef person = (__bridge ABRecordRef)
[allPeople objectAtIndex:peopleCounter];
NSString *firstName = (__bridge_transfer NSString *)
ABRecordCopyValue(person, kABPersonFirstNameProperty);
NSString *lastName = (__bridge_transfer NSString *)
ABRecordCopyValue(person, kABPersonLastNameProperty);
BOOL firstNameIsEqual = NO;
BOOL lastNameIsEqual = NO;
if ([firstName length] == 0 &&
[paramFirstName length] == 0){
firstNameIsEqual = YES;
}
else if ([firstName isEqualToString:paramFirstName]){
566 | Chapter 11: Address Book
www.it-ebooks.info
firstNameIsEqual = YES;
}
if ([lastName length] == 0 &&
[paramLastName length] == 0){
lastNameIsEqual = YES;
}
else if ([lastName isEqualToString:paramLastName]){
lastNameIsEqual = YES;
}
if (firstNameIsEqual &&
lastNameIsEqual){
return person;
}
}
return result;
}
- (void) updateImagesInAddressBook:(ABAddressBookRef)paramAddressBook{
ABRecordRef anthonyRobbins = [self getPersonWithFirstName:@"Anthony"
lastName:@"Robbins"
inAddressBook:paramAddressBook];
if (anthonyRobbins == NULL){
NSLog(@"Couldn't find record. Creating one...");
anthonyRobbins = [self newPersonWithFirstName:@"Anthony"
lastName:@"Robbins"
inAddressBook:paramAddressBook];
if (anthonyRobbins == NULL){
NSLog(@"Failed to create a new record for this person.");
return;
}
}
self.imageViewOld.image = [self getPersonImage:anthonyRobbins];
NSString *newImageFilePath =
[[NSBundle mainBundle] pathForResource:@"Anthony Robbins"
ofType:@"jpg"];
UIImage *newImage = [[UIImage alloc]
initWithContentsOfFile:newImageFilePath];
NSData *newImageData = UIImagePNGRepresentation(newImage);
if ([self setPersonImage:anthonyRobbins
inAddressBook:paramAddressBook
withImageData:newImageData]){
NSLog(@"Successfully set this person's new image.");
self.imageViewNew.image = [self getPersonImage:anthonyRobbins];
11.9 Retrieving and Setting a Persons Address Book Image | 567
www.it-ebooks.info
} else {
NSLog(@"Failed to set this person's new image.");
}
CFRelease(anthonyRobbins);
}
- (void) viewDidAppear:(BOOL)paramAnimated{
[super viewDidAppear:paramAnimated];
CFErrorRef error = NULL;
switch (ABAddressBookGetAuthorizationStatus()){
case kABAuthorizationStatusAuthorized:{
addressBook = ABAddressBookCreateWithOptions(NULL, &error);
[self updateImagesInAddressBook:addressBook];
if (addressBook != NULL){
CFRelease(addressBook);
}
break;
}
case kABAuthorizationStatusDenied:{
[self displayMessage:kDenied];
break;
}
case kABAuthorizationStatusNotDetermined:{
addressBook = ABAddressBookCreateWithOptions(NULL, &error);
ABAddressBookRequestAccessWithCompletion
(addressBook, ^(bool granted, CFErrorRef error) {
if (granted){
[self updateImagesInAddressBook:addressBook];
} else {
NSLog(@"Access was not granted");
}
if (addressBook != NULL){
CFRelease(addressBook);
}
});
break;
}
case kABAuthorizationStatusRestricted:{
[self displayMessage:kRestricted];
break;
}
}
}
The iesults aie shown in Figuie 11-6.
568 | Chapter 11: Address Book
www.it-ebooks.info
Iigurc 11-. Thc o|d inagc jor a contact is rcp|accd by a ncw onc
11.9 Retrieving and Setting a Persons Address Book Image | 569
www.it-ebooks.info
www.it-ebooks.info
CHAPTER 12
Files and Folder Management
12.0 Introduction
iOS is Laseu on Mac OS X, which itsell is Laseu on the UNIX opeiating system. In iOS,
the opeiating system`s lull uiiectoiy stiuctuie is not visiLle to an app Lecause each app,
wiitten Ly an iOS app uevelopei, lives in its own sanuLox. A sanuLox enviionment is
exactly what it sounus like: a sanctioneu aiea wheie only the app that owns the sanuLox
can access the contents ol the loluei. Eveiy app has its own sanuLox loluei anu the
sanuLox lolueis Ly uelault have suLlolueis that apps can access.
Vhen an iOS app is installeu on the uevice, the loluei stiuctuie shown in Fig-
uie 12-1 will Le cieateu loi that app Ly the system.
The ioot loluei ol eveiy application contains vaiious othei lolueis, which I will explain
heie:
Name.app
Despite the ouu name with the .app extension, this is a loluei. The contents ol youi
main Lunule will all go in heie. Foi instance, all youi app icons, youi app Linaiy,
youi uilleient Lianuing images, lonts, sounus, etc., will all Le placeu in this loluei
automatically when iOS installs youi app on a uevice. The name is the piouuct name
that you have set loi youi app. So il youi app is calleu MyApp, the .app loluei will
Le calleu MyApp.app.
Docuncnts/
This loluei is the uestination loi all usei-cieateu content. Content that youi app
has populateu, uownloaueu, oi cieateu shoulu not Le stoieu in this loluei.
Library/
You use this uiiectoiy to stoie cacheu liles, usei pieleiences, anu so on. Usually,
this loluei on its own will not have any liles sitting in it. It contains othei lolueis
that will contain liles.
571
www.it-ebooks.info
Library/Cachcs/
The loluei wheie you stoie uata that youi app can latei ie-cieate, il neeu Le. The
contents ol this loluei aie not Lackeu up Ly iOS. Also, iOS may iemove the contents
ol this loluei il the uevice is iunning out ol uisk space while youi app is not iunning!
So uo not allow youi app to iely on the contents ol this loluei too much; Le piepaieu
to ie-cieate this content. Once again: the contents ol this loluei will not Le Lackeu
up Ly iOS anu can Le ueleteu while youi app is suspenueu.
Foi instance, il youi app is ielying on liles anu lolueis that aie to Le cieateu on
uisk, this loluei woulu not Le the Lest place to stoie this uata. You aie Lettei oll
stoiing such liles anu lolueis in the /tnp loluei.
Iigurc 12-1. Dcpiction oj thc iOS ji|c systcn
572 | Chapter 12: Files and Folder Management
www.it-ebooks.info
Library/Prcjcrcnccs/
As the name inuicates, this loluei contains the pieleiences that youi app wants to
iememLei Letween launches. Ve will talk aLout this in uetail latei. iOS uoes Lack
up the contents ol this loluei.
Library/App|ication Support/
The uata that youi app cieates, not incluuing the uata cieateu Ly the usei, must
Le stoieu in this loluei. It is goou to know that iOS Lacks up the contents ol this
loluei. This loluei may not Le cieateu loi you automatically anu you`ll have to
cieate it youisell il it uoesn`t exist. Ve will talk aLout loluei cieation latei in this
chaptei.
tnp/
These aie tempoiaiy liles that youi app may cieate, uownloau, anu so on. The
contents ol this loluei aie not Lackeu up Ly iOS. Foi instance, you may uownloau
a lew photos liom the Inteinet anu stoie them in this loluei in oiuei to inciease
the peiloimance ol youi application, so that you won`t have to uownloau the liles
eveiy time the usei opens youi app. This loluei seives exactly this puipose. Make
suie that you aie not stoiing any usei-cieateu uocuments oi liles in this loluei.
Now you know the lolueis that iOS cieates loi you when youi app is installeu on an
iOS uevice. The next thing you want to uo is linu the path ol the iest ol the uselul
lolueis that we just talkeu aLout, using the APIs that Apple has exposeu to you (these
will Le explaineu in this chaptei).
12.1 Finding the Paths of the Most Useful Folders on Disk
Problem
You want to Le aLle to linu the path ol some ol the most uselul lolueis that youi app
has access to (e.g., the lolueis that we talkeu aLout in Recipe 12.0), so that you can
access theii content oi cieate new content in those lolueis.
Piogiammeis neeu to use APIs that aie exposeu in the iOS SDK to linu
the path ol lolueis anu/oi liles. In othei woius, you shoulu nevei assume
the path ol a loluei oi a lile. You shoulu always make suie that you use
the appiopiiate APIs to, loi instance, linu the paths that you aie looking
loi, such as the Docuncnts loluei. Nevei, evei assume that this loluei
will Le calleu Docuncnts in youi app`s Lunule. Simply use the appio-
piiate APIs to linu this path anu, il you want to auu oi access liles in the
loluei, attach youi lilenames to the enu ol this path.
Solution
Use the URLsForDirectory:inDomains: instance methou ol the NSFileManager class.
12.1 Finding the Paths of the Most Useful Folders on Disk | 573
www.it-ebooks.info
Discussion
The NSFileManager class olleis a lot ol lile anu loluei ielateu opeiations that you can
uo with iOS, iight insiue youi apps, simply Ly making an instance ol the class. I auvise
against using the shaieu lile managei pioviueu Ly this class thiough the defaultMan
ager class methou Lecause it is not thieau-sale. It is Lest to cieate anu manage an
instance ol the NSFileManager class loi youisell.
The URLsForDirectory:inDomains: instance methou ol the NSFileManager class allows
you to seaich loi specilic uiiectoiies on the iOS lile system, mostly in youi app`s sanu-
Lox. Theie aie two paiameteis to this methou:
URLsForDirectory:
This is the uiiectoiy that you want to seaich loi. Pass a value ol type NSSearchPath
Directory enumeiation to this paiametei. I will talk moie aLout this soon.
inDomains
This is whcrc you look loi the given uiiectoiy. The value to this paiametei must
Le ol type NSSearchPathDomainMask enumeiation.
Suppose you want to linu the path to youi app`s Docuncnts loluei. This is how easily
you can linu it:
NSFileManager *fileManager = [[NSFileManager alloc] init];
NSArray *urls = [fileManager URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask];
if ([urls count] > 0){
NSURL *documentsFolder = urls[0];
NSLog(@"%@", documentsFolder);
} else {
NSLog(@"Could not find the Documents folder.");
}
As you can see, altei cieating oui own instance ol NSFileManager, we passeu the NSDo
cumentDirectory value as the loluei we aie looking loi anu NSUserDomainMask as the
uomain. Let`s go thiough some ol the most impoitant values that you can pass to each
one ol the paiameteis to the URLsForDirectory:inDomains: instance methou ol the
NSFileManager class:
URLsForDirectory
NSLibraryDirectory
The liLiaiy loluei loi the app.
NSCachesDirectory
The caches loluei, as explaineu Leloie.
NSDocumentDirectory
The uocuments loluei.
574 | Chapter 12: Files and Folder Management
www.it-ebooks.info
inDomains
NSUserDomainMask
Specilies that the seaich Le peiloimeu in the cuiient usei`s loluei. On OS X,
this loluei woulu Le -/.
Using this methou, you can then linu othei lolueis such as the cachcs loluei, as shown
heie:
NSFileManager *fileManager = [[NSFileManager alloc] init];
NSArray *urls = [fileManager URLsForDirectory:NSCachesDirectory
inDomains:NSUserDomainMask];
if ([urls count] > 0){
NSURL *cachesFolder = urls[0];
NSLog(@"%@", cachesFolder);
} else {
NSLog(@"Could not find the Caches folder.");
}
Il you want to linu the tnp loluei, use the NSTemporaryDirectory() C lunction like so:
NSString *tempDirectory = NSTemporaryDirectory();
NSLog(@"Temp Directory = %@", tempDirectory);
Vhen you execute this commanu on a uevice, the output will Le similai to that shown
heie:
Temp Directory = /private/var/mobile/Applications/19E19C60-8A3A-41BF-
AFCA-B1AB9746A4CB/tmp/
See Also
Recipe 12.0
12.2 Writing to and Reading from Files
Problem
You want to Le aLle to save inloimation to uisk (e.g., text, uata, images, etc.).
Solution
Cocoa classes that allow you to stoie inloimation, such as NSString, UIImage, anu
NSData, all expose instance methous that allow you to stoie theii uata to uisk unuei a
given path.
Discussion
In oiuei to stoie text to uisk, assuming that youi text is stoieu in an instance ol
NSString (oi the immutaLle veision ol this class), you can use the writeToFile:
12.2 Writing to and Reading from Files | 575
www.it-ebooks.info
atomically:encoding:error: instance methou ol this class. This methou woiks with
stiings that iepiesent the uestination path. Heie aie the uilleient paiameteis:
writeToFile
The path ol the lile to wiite to, as a stiing.
atomically
A Boolean that, il set to YES, will liist wiite the lile to a tempoiaiy space anu will
then move the tempoiaiy lile to the uestination that you chose. This will ensuie
that the contents ol the lile will Le saveu to uisk liist anu then saveu to its uesti-
nation, so that il iOS ciashes Leloie the lile is saveu to the linal uestination, youi
contents will still Le saveu latei when the OS is Lack up again. It is iecommenueu
to set this value to YES when stoiing inloimation that you uon`t want to lose unuei
any ciicumstance while youi app is iunning.
encoding
Encouing ol the text that you want to wiite to the path. Piogiammeis usually use
UTFS loi the encouing, using the NSUTF8StringEncoding constant value.
error
Takes a pointei to an NSError oLject so that il the saving opeiation lails, you will
Le aLle to linu the eiioi that happeneu uuiing the piocess. You can pass nil to this
paiametei il you aie not inteiesteu in knowing aLout the eiiois that may occui
uuiing the saving piocess. Beai in minu that this lunction ietuins a Boolean value
anu you can simply use this value to linu out whethei an eiioi has occuiieu.
Foi instance, il you have some text that you want to tempoiaiily stoie in youi app, anu
you uon`t want it to Le Lackeu up Ly iOS, you can uo the lollowing:
NSString *someText = @"Random string that won't be backed up.";
NSString *destinationPath = [NSTemporaryDirectory()
stringByAppendingPathComponent:@"MyFile.txt"];
NSError *error = nil;
BOOL succeeded = [someText writeToFile:destinationPath
atomically:YES
encoding:NSUTF8StringEncoding
error:&error];
if (succeeded) {
NSLog(@"Successfully stored the file at: %@", destinationPath);
} else {
NSLog(@"Failed to store the file. Error = %@", error);
}
Also, altei you aie uone, to make suie things went line, you can attempt to ieau the
same stiing Lack into memoiy liom the uestination lile, using the stringWithContent
sOfFile:encoding:error: class methou ol the NSString class. This will ietuin Lack the
autoielease stiing that is the contents ol the specilieu lile. Il you want to explicitly
instantiate an oLject ol type NSString with the contents ol the lile, simply use the
initWithContentsOfFile:encoding:error: instance methou ol the NSString class like so:
576 | Chapter 12: Files and Folder Management
www.it-ebooks.info
- (BOOL) writeText:(NSString *)paramText toPath:(NSString *)paramPath{
return [paramText writeToFile:paramPath
atomically:YES
encoding:NSUTF8StringEncoding
error:nil];
}
- (NSString *) readTextFromPath:(NSString *)paramPath{
return [[NSString alloc] initWithContentsOfFile:paramPath
encoding:NSUTF8StringEncoding
error:nil];
}
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
NSString *filePath = [NSTemporaryDirectory()
stringByAppendingPathComponent:@"MyFile.txt"];
if ([self writeText:@"Hello, World!" toPath:filePath]){
NSString *readText = [self readTextFromPath:filePath];
if ([readText length] > 0){
NSLog(@"Text read from disk = %@", readText);
} else {
NSLog(@"Failed to read the text from disk.");
}
} else {
NSLog(@"Failed to write the file.");
}
self.window = [[UIWindow alloc]
initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Vhat we have uone is cieateu two convenient methous that allow us to wiite text to
anu ieau text liom a specilieu location. In oui app uelegate, then, we use these two
methous to wiite some text to the tcnp loluei anu then ieau the same text Lack to
memoiy in oiuei to make suie oui methous aie woiking line.
Il you want to woik with URLs encapsulateu in instances ol NSURL (oi the mutaLle
veision ol it), you can use the writeToURL:atomically:encoding:error: instance methou
insteau.
Instances ol NSURL can point to iesouices (liles, uiiectoiies, etc.) locally
oi iemotely. Foi instance, an instance ol NSURL can iepiesent a local lile
in the Docuncnts loluei ol youi app as easily as it can iepiesent the
weLsite URL loi www.apple.com. This class simply gives you lunctionality
to access anu woik with URLs, iegaiuless ol which type ol URL they aie.
12.2 Writing to and Reading from Files | 577
www.it-ebooks.info
Othei classes in lounuation have methous similai to those ol NSString. Let`s take
NSArray as an example. You can save the contents ol an aiiay using the writeTo
File:atomically: instance methou ol NSArray. In oiuei to ieau the contents ol an aiiay
liom uisk, you can simply allocate an instance ol the aiiay anu then initialize it using
the initWithContentsOfFile: initializei ol the aiiay. Heie is an example ol Loth these:
NSString *filePath = [NSTemporaryDirectory()
stringByAppendingPathComponent:@"MyFile.txt"];
NSArray *arrayOfNames = @[@"Steve", @"John", @"Edward"];
if ([arrayOfNames writeToFile:filePath atomically:YES]){
NSArray *readArray = [[NSArray alloc] initWithContentsOfFile:filePath];
if ([readArray count] == [arrayOfNames count]){
NSLog(@"Read the array back from disk just fine.");
} else {
NSLog(@"Failed to read the array back from disk.");
}
} else {
NSLog(@"Failed to save the array to disk.");
}
The writeToFile:atomically: instance methou ol NSArray class can save
only an aiiay that contains oLjects ol the lollowing type:
NSString
NSDictionary
NSArray
NSData
NSNumber
NSDate
Il you attempt to inseit any othei oLjects in the aiiay, youi uata will not
Le saveu to uisk, Lecause this methou liist makes suie all the oLjects in
the aiiay aie ol one ol the aloiementioneu types. This is simply Lecause
the OLjective-C iuntime will not, otheiwise, have any iuea how to stoie
youi uata to uisk. Foi instance, suppose you cieate a class calleu Per
son anu cieate a liist name anu last name piopeity loi the class, then
instantiate an instance anu auu it to an aiiay. How can an aiiay then
save youi peison to uisk? It simply cannot uo that, as it won`t know
what it has to save to uisk. This is a pioLlem known as narsha||ing, anu
is solveu Ly iOS only loi the uata types just listeu.
Dictionaiies aie also veiy similai to aiiays anu have the same way ol saving theii uata
to uisk anu ieauing uata Lack into the uictionaiy. The methou names aie exactly the
same, anu the iules ol saving an aiiay also apply to uictionaiies. Heie is an example:
NSString *filePath = [NSTemporaryDirectory()
stringByAppendingPathComponent:@"MyFile.txt"];
578 | Chapter 12: Files and Folder Management
www.it-ebooks.info
NSDictionary *dict = @{
@"first name" : @"Steven",
@"middle name" : @"Paul",
@"last name" : @"Jobs",
};
if ([dict writeToFile:filePath atomically:YES]){
NSDictionary *readDictionary = [[NSDictionary alloc]
initWithContentsOfFile:filePath];
/* Now compare the dictionaries and see if the one we read from disk
is the same as the one we saved to disk */
if ([readDictionary isEqualToDictionary:dict]){
NSLog(@"The file we read is the same one as the one we saved.");
} else {
NSLog(@"Failed to read the dictionary from disk.");
}
} else {
NSLog(@"Failed to write the dictionary to disk.");
}
As you can see, this example wiites the uictionaiy to uisk anu then ieaus it Lack liom
the same location. Altei ieauing, we compaie the ieau uictionaiy to the one we saveu
to uisk in oiuei to make suie they Loth contain the same uata.
Up to now, we have Leen using high-level classes such as NSString anu NSArray to save
oui contents to uisk. Now, what il we want to stoie iaw aiiay ol Lytes to uisk? That`s
easy too. Suppose we have an aiiay ol loui unsigneu chaiacteis anu we want to save
that to uisk:
unsigned char *bytes = {0x22, 0xA0, 0x41, 0x10};
The easiest way ol saving this iaw aiiay ol Lytes to uisk is to encapsulate it in anothei
high-level uata stiuctuie like NSData anu then use the ielevant methous ol NSData to
wiite to anu ieau liom the uisk. The saving anu loauing methous loi an NSData aie
viitually the same as those loi NSArray anu NSDictionary. Heie is an example ol saving
iaw uata to uisk anu ieauing it Lack liom the uisk:
NSString *filePath = [NSTemporaryDirectory()
stringByAppendingPathComponent:@"MyFile.txt"];
char bytes[4] = {'a', 'b', 'c', 'd'};
NSData *dataFromBytes = [[NSData alloc] initWithBytes:bytes
length:sizeof(bytes)];
if ([dataFromBytes writeToFile:filePath atomically:YES]){
NSData *readData = [[NSData alloc] initWithContentsOfFile:filePath];
if ([readData isEqualToData:dataFromBytes]){
NSLog(@"The data read is the same data as was written to disk.");
} else {
NSLog(@"Failed to read the data from disk.");
12.2 Writing to and Reading from Files | 579
www.it-ebooks.info
}
} else {
NSLog(@"Failed to save the data to disk.");
}
See Also
Recipe 12.0
12.3 Creating Folders on Disk
Problem
You want to Le aLle to cieate lolueis on uisk to save some ol youi app`s liles in them.
Solution
Use the createDirectoryAtPath:withIntermediateDirectories:attributes:error: in-
stance methou ol the NSFileManager class, as shown heie:
NSFileManager *fileManager = [[NSFileManager alloc] init];
NSString *tempDir = NSTemporaryDirectory();
NSString *imagesDir = [tempDir stringByAppendingPathComponent:@"images"];
NSError *error = nil;
if ([fileManager createDirectoryAtPath:imagesDir
withIntermediateDirectories:YES
attributes:nil
error:&error]){
NSLog(@"Successfully created the directory.");
} else {
NSLog(@"Failed to create the directory. Error = %@", error);
}
Discussion
The APIs exposeu Ly NSFileManager aie veiy easy to use, anu it`s no suipiise that you
can use them to cieate lolueis on uisk in a lew lines. The createDirectoryAtPath:with
IntermediateDirectories:attributes:error: methou may look scaiy at liist, Lut it`s
not that Lau. I will explain the uilleient paiameteis that you can pass to it:
createDirectoryAtPath
The path to the loluei that has to Le cieateu.
withIntermediateDirectories
A Boolean paiametei that, il set to YES, will cieate all the lolueis in the miuule
Leloie it cieates the linal loluei. Foi instance, il you want to cieate a loluei nameu
inagcs in anothei loluei nameu data insiue the tnp loluei ol youi app, Lut the
580 | Chapter 12: Files and Folder Management
www.it-ebooks.info
data loluei uoesn`t exist yet, you coulu easily ask to cieate the tnp/data/inagcs/
loluei anu set the withIntermediateDirectories paiametei to YES. This will make
the system cieate the data loi you as well as the inagcs loluei.
attributes
A uictionaiy ol attiiLutes that you can pass to the system in oiuei to allect how
youi loluei will Le cieateu. Ve won`t Le using these heie, to keep things simple,
Lut you can change things such as the mouilication uate anu time, the cieation
uate anu time, anu othei attiiLutes ol the cieateu loluei il you want to.
error
This paiametei accepts a pointei to an eiioi oLject ol type NSObject, which will Le
populateu with any eiiois that may happen while the loluei is Leing cieateu. It`s
geneially a goou iuea to pass an eiioi oLject to this paiametei,so that il the methou
lails (ietuins NO), you can access the eiioi anu ueteimine what went wiong.
See Also
Recipe 12.1
12.4 Enumerating Files and Folders
Problem
You eithei want to enumeiate lolueis within a loluei oi you want to enumeiate the list
ol liles insiue a loluei. The act ol enumeiating means that you simply want to linu all
the lolueis anu/oi liles within anothei loluei.
Solution
Use the contentsOfDirectoryAtPath:error: instance methou ol the NSFileManager class
as shown heie. In this example, we aie enumeiating all the liles, lolueis, anu symlinks
unuei oui app`s Lunule loluei:
NSFileManager *fileManager = [[NSFileManager alloc] init];
NSString *bundleDir = [[NSBundle mainBundle] bundlePath];
NSError *error = nil;
NSArray *bundleContents = [fileManager contentsOfDirectoryAtPath:bundleDir
error:&error];
if ([bundleContents count] > 0 &&
error == nil){
NSLog(@"Contents of the app bundle = %@", bundleContents);
}
else if ([bundleContents count] == 0 &&
error == nil){
NSLog(@"Call the police! The app bundle is empty.");
}
12.4 Enumerating Files and Folders | 581
www.it-ebooks.info
else {
NSLog(@"An error happened = %@", error);
}
Discussion
In some ol youi iOS apps, you may neeu to enumeiate the contents ol a loluei. Let me
give you an example, in case this neeu is a Lit vague iight now. Imagine that the usei
askeu you to uownloau 10 images liom the Inteinet anu cache them in youi app. You
go aheau anu save them, let`s say, in the tnp/inagcs/ loluei that you manually cieateu.
Now the usei closes youi app anu ieopens it, anu in youi UI, you want to uisplay the
list ol alieauy-uownloaueu-liles in a taLle view. How can you achieve this? Vell, it`s
easy. All you have to uo is to enumeiate the contents ol the aloiementioneu loluei using
the NSFileManager class. As you saw in the Solution section ol this iecipe, the content
sOfDirectoryAtPath:error: instance methou ol the NSFileManager class ietuins an aiiay
ol NSString oLjects that will iepiesent the liles, lolueis, anu symlinks within the given
loluei. Howevei, it is not easy to say which one is a loluei, which one is a lile, anu so
on. To get moie line-giaineu uetail liom the lile managei, invoke the contentsOfDirec
toryAtURL:includingPropertiesForKeys:options:error:. Let`s go thiough the uilleient
paiameteis that you neeu to pass to this methou:
contentsOfDirectoryAtURL
The path ol the loluei that you want to inspect. This path shoulu Le pioviueu as
an instance ol NSURL. Don`t woiiy aLout it il you uon`t know how to constiuct this
instance. Ve will talk aLout it soon.
includingPropertiesForKeys
This is an aiiay ol piopeities that you woulu like iOS to letch loi eveiy lile, loluei,
oi item that it linus in the given uiiectoiy. Foi instance, you can specily that you
want the cieation uate ol the items to Le ietuineu in the iesults, as pait ol the URL
instance that is ietuineu to you (in instances ol NSURL that you get Lack liom the
liamewoik). Heie is the list ol some ol the most impoitant values that you can
place in this aiiay:
NSURLIsDirectoryKey
Allows you to ueteimine latei whethei one ol the URLs ietuineu aie uiiecto-
iies.
NSURLIsReadableKey
Allows you to ueteimine latei whethei the ietuineu URL is ieauaLle Ly youi
app`s piocess.
NSURLCreationDateKey
Retuins the cieation uate ol the item in the ietuineu URL.
NSURLContentAccessDateKey
Retuins the last content access uate in the ietuineu iesults.
582 | Chapter 12: Files and Folder Management
www.it-ebooks.info
NSURLContentModificationDateKey
As its name inuicates, this allows you to ueteimine the last-mouilieu-uate loi
the ietuineu URLs.
options
Only 0 oi NSDirectoryEnumerationSkipsHiddenFiles may Le enteieu loi this pa-
iametei. Il the lattei value is enteieu, as the name ol the value shows, all hiuuen
items will Le skippeu uuiing the enumeiation.
error
A ieleience to an oLject that will Le lilleu with an eiioi shoulu this methou lail to
execute its joL. It`s usually a goou iuea to pioviue eiioi oLjects to these methous
il you can. You get moie contiol ovei why things lail, shoulu they evei lail.
Now that we have moie contiol ovei how the items aie enumeiateu, let`s enumeiate
all the items in the .app loluei anu piint out the cieation, last mouilieu, anu last accesseu
uates. Ve will also piint out whethei the items aie hiuuen oi not, anu whethei we have
ieau access to the liles oi not. The last thing we`ll piint out will Le whethei the items
aie uiiectoiies oi not. Let`s go:
- (NSArray *) contentsOfAppBundle{
NSFileManager *manager = [[NSFileManager alloc] init];
NSURL *bundleDir = [[NSBundle mainBundle] bundleURL];
NSArray *propertiesToGet = @[
NSURLIsDirectoryKey,
NSURLIsReadableKey,
NSURLCreationDateKey,
NSURLContentAccessDateKey,
NSURLContentModificationDateKey
];
NSError *error = nil;
NSArray *result = [manager contentsOfDirectoryAtURL:bundleDir
includingPropertiesForKeys:propertiesToGet
options:0
error:&error];
if (error != nil){
NSLog(@"An error happened = %@", error);
}
return result;
}
- (NSString *) stringValueOfBOOLProperty:(NSString *)paramProperty
ofURL:(NSURL *)paramURL{
NSNumber *boolValue = nil;
NSError *error = nil;
[paramURL getResourceValue:&boolValue
forKey:paramProperty
error:&error];
12.4 Enumerating Files and Folders | 583
www.it-ebooks.info
if (error != nil){
NSLog(@"Failed to get property of URL. Error = %@", error);
}
return [boolValue isEqualToNumber:@YES] ? @"Yes" : @"No";
}
- (NSString *) isURLDirectory:(NSURL *)paramURL{
return [self stringValueOfBOOLProperty:NSURLIsDirectoryKey ofURL:paramURL];
}
- (NSString *) isURLReadable:(NSURL *)paramURL{
return [self stringValueOfBOOLProperty:NSURLIsReadableKey ofURL:paramURL];
}
- (NSDate *) dateOfType:(NSString *)paramType inURL:(NSURL *)paramURL{
NSDate *result = nil;
NSError *error = nil;
[paramURL getResourceValue:&result
forKey:paramType
error:&error];
if (error != nil){
NSLog(@"Failed to get property of URL. Error = %@", error);
}
return result;
}
- (void) printURLPropertiesToConsole:(NSURL *)paramURL{
NSLog(@"Item name = %@", [paramURL lastPathComponent]);
NSLog(@"Is a Directory? %@", [self isURLDirectory:paramURL]);
NSLog(@"Is Readable? %@", [self isURLReadable:paramURL]);
NSLog(@"Creation Date = %@",
[self dateOfType:NSURLCreationDateKey inURL:paramURL]);
NSLog(@"Access Date = %@",
[self dateOfType:NSURLContentAccessDateKey inURL:paramURL]);
NSLog(@"Modification Date = %@",
[self dateOfType:NSURLContentModificationDateKey inURL:paramURL]);
NSLog(@"-----------------------------------");
}
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
NSArray *itemsInAppBundle = [self contentsOfAppBundle];
for (NSURL *item in itemsInAppBundle){
[self printURLPropertiesToConsole:item];
}
584 | Chapter 12: Files and Folder Management
www.it-ebooks.info
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;
}
The output ol this piogiam will Le something similai to that shown heie:
Item name = en.lproj
Is a Directory? Yes
Is Readable? Yes
Creation Date = 2012-08-11 20:07:49 +0000
Access Date = 2012-08-12 12:31:33 +0000
Modification Date = 2012-08-11 20:07:49 +0000
-----------------------------------
Item name = Enumerating Files and Folders
Is a Directory? No
Is Readable? Yes
Creation Date = 2012-08-12 12:31:30 +0000
Access Date = 2012-08-12 12:31:33 +0000
Modification Date = 2012-08-12 12:31:30 +0000
-----------------------------------
Item name = Info.plist
Is a Directory? No
Is Readable? Yes
Creation Date = 2012-08-11 20:07:48 +0000
Access Date = 2012-08-12 12:31:33 +0000
Modification Date = 2012-08-11 20:07:48 +0000
-----------------------------------
Item name = PkgInfo
Is a Directory? No
Is Readable? Yes
Creation Date = 2012-08-11 20:07:48 +0000
Access Date = 2012-08-11 20:07:48 +0000
Modification Date = 2012-08-11 20:07:48 +0000
-----------------------------------
The impoitant thing to note aLout this app is that we aie using the
getResourceValue:forKey:error: instance methou ol the NSURL class to
get the value ol each one ol the keys that we aie gueiying liom the lile
managei, such as the cieation anu mouilication uate. Ve pass these
ieguiiements to the lile managei, asking it to letch this inloimation loi
us. Anu then, once we have oui URLs, we use the aloiementioneu
methou to ietiieve the uilleient piopeities liom the iesulting URLs.
So let`s have a look at the uilleient paits ol this app. I will simply explain what each
one ol these methous that we have wiitten uoes:
12.4 Enumerating Files and Folders | 585
www.it-ebooks.info
contcntsOjAppBund|c
This methou seaiches the .app loluei loi all items (liles, lolueis, symlinks, etc.) anu
ietuins the iesult as an aiiay. All items in the aiiay will Le ol type NSURL anu contain
theii cieation uate, last mouilication uate, anu othei attiiLutes that we talkeu aLout
Leloie.
string\a|ucOjBOOLPropcrty:ojURL:
This methou will letch the stiing eguivalent (Yes oi No) ol a Boolean piopeity ol a
URL. Foi instance, inloimation aLout whethei a URL is a uiiectoiy oi not is stoieu
as a Linaiy, Boolean value. Howevei, il we want to piint this Boolean value out to
the console, we neeu to conveit it to stiing. Ve have two gueiy items loi each URL
that will ietuin instances ol NSNumber containing a Boolean value: NSURLIsDirector
yKey anu NSURLIsReadableKey. So insteau ol wiiting this conveision coue twice,
methous aie availaLle to uo the conveision ol NSNumber to a stiing ol Yes oi No loi us.
isURLDircctory:
Takes in a URL anu inspects it to see whethei it is a uiiectoiy. This methou intei-
nally uses the stringValueOfBOOLProperty:ofURL: methou anu passes the NSURLIs
DirectoryKey key to it.
isURLRcadab|c:
Deteimines whethei youi app has ieau access to a given URL. This methou also
inteinally uses the stringValueOfBOOLProperty:ofURL: methou anu passes the NSUR
LIsReadableKey key to it.
datcOjTypc:inURL:
Since we aie going to inspect thiee types ol piopeities in each URL that will Le ol
type NSDate, we have simply encapsulateu the ielevant coue in this methou, which
will take the key anu will ietuin the uate associateu with that key in a given URL.
OK, that`s aLout it, ieally. You now know how to enumeiate lolueis anu ietiieve all
items within the loluei. You even know how to ietiieve uilleient attiiLutes loi uilleient
items.
See Also
Recipe 12.1; Recipe 12.2
12.5 Deleting Files and Folders
Problem
You have cieateu some liles anu/oi lolueis on uisk anu no longei neeu them, so you
woulu like to uelete them.
586 | Chapter 12: Files and Folder Management
www.it-ebooks.info
Solution
Use the removeItemAtPath:error: oi the removeItemAtURL:error: instance methou ol
the NSFileManager class. The loimei methou takes the path as a stiing anu the lattei
takes the path as a URL.
Discussion
Deleting liles anu lolueis is peihaps one ol the easiest opeiations that you can peiloim
using a lile managei. In iOS, you neeu to Le minulul ol wheie you stoie youi liles anu
lolueis in the liist place, anu once you have uone the stoiage, you neeu to get iiu ol
liles anu lolueis when you no longei neeu them. Foi instance, let`s cieate live text liles
in the tnp/tcxt loluei anu then uelete them once we aie uone. In the meantime, we can
enumeiate the contents ol the loluei Leloie anu altei the ueletion just to make suie
things aie woiking line. Also, as you know, the tnp/ loluei exists when youi app is
installeu, Lut the tnp/tcxt uoesn`t. So we neeu to cieate it liist. Once we aie uone with
the liles, we will uelete the loluei as well:
/* Creates a folder at a given path */
- (void) createFolder:(NSString *)paramPath{
NSError *error = nil;
if ([self.fileManager createDirectoryAtPath:paramPath
withIntermediateDirectories:YES
attributes:nil
error:&error] == NO){
NSLog(@"Failed to create folder %@. Error = %@",
paramPath,
error);
}
}
/* Creates 5 .txt files in the given folder, named 1.txt, 2.txt, etc */
- (void) createFilesInFolder:(NSString *)paramPath{
/* Create 10 files */
for (NSUInteger counter = 0; counter < 5; counter++){
NSString *fileName = [NSString stringWithFormat:@"%lu.txt",
(unsigned long)counter+1];
NSString *path = [paramPath stringByAppendingPathComponent:fileName];
NSString *fileContents = [NSString stringWithFormat:@"Some text"];
NSError *error = nil;
if ([fileContents writeToFile:path
atomically:YES
encoding:NSUTF8StringEncoding
error:&error] == NO){
NSLog(@"Failed to save file to %@. Error = %@", path, error);
}
}
}
/* Enumerates all files/folders at a given path */
- (void) enumerateFilesInFolder:(NSString *)paramPath{
12.5 Deleting Files and Folders | 587
www.it-ebooks.info
NSError *error = nil;
NSArray *contents = [self.fileManager contentsOfDirectoryAtPath:paramPath
error:&error];
if ([contents count] > 0 &&
error == nil){
NSLog(@"Contents of path %@ = \n%@", paramPath, contents);
}
else if ([contents count] == 0 &&
error == nil){
NSLog(@"Contents of path %@ is empty!", paramPath);
}
else {
NSLog(@"Failed to enumerate path %@. Error = %@", paramPath, error);
}
}
/* Deletes all files/folders in a given path */
- (void) deleteFilesInFolder:(NSString *)paramPath{
NSError *error = nil;
NSArray *contents = [self.fileManager contentsOfDirectoryAtPath:paramPath
error:&error];
if (error == nil){
error = nil;
for (NSString *fileName in contents){
/* We have the filename, to delete it,
we have to have the full path */
NSString *filePath = [paramPath
stringByAppendingPathComponent:fileName];
if ([self.fileManager removeItemAtPath:filePath
error:&error] == NO){
NSLog(@"Failed to remove item at path %@. Error = %@",
fileName,
error);
}
}
} else {
NSLog(@"Failed to enumerate path %@. Error = %@", paramPath, error);
}
}
/* Deletes a folder with a given path */
- (void) deleteFolder:(NSString *)paramPath{
NSError *error = nil;
if ([self.fileManager removeItemAtPath:paramPath error:&error] == NO){
NSLog(@"Failed to remove path %@. Error = %@", paramPath, error);
}
}
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
588 | Chapter 12: Files and Folder Management
www.it-ebooks.info
self.fileManager = [[NSFileManager alloc] init];
NSString *txtFolder = [NSTemporaryDirectory()
stringByAppendingPathComponent:@"txt"];
[self createFolder:txtFolder];
[self createFilesInFolder:txtFolder];
[self enumerateFilesInFolder:txtFolder];
[self deleteFilesInFolder:txtFolder];
[self enumerateFilesInFolder:txtFolder];
[self deleteFolder:txtFolder];
self.window = [[UIWindow alloc]
initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Beai in minu that the fileManager piopeity, which we aie using in vaiious methous ol
oui app uelegate, is a piopeity ol the app uelegate itsell anu is uelineu in this way in
the app uelegate`s heauei lile:
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (nonatomic, strong) UIWindow *window;
@property (nonatomic, strong) NSFileManager *fileManager;
@end
This example coue comLines a lot ol the things that you have leaineu in this chaptei,
liom enumeiating to cieating to ueleting liles. It`s all in this example. As you can see
liom the app`s staiting point, we aie peiloiming six main tasks, all ol which have theii
associateu methous to take caie ol them:
1. Cieating the tnp/txt loluei. Ve know the tnp loluei will Le cieateu Ly iOS loi
eveiy app, Lut the txt uoesn`t come alieauy cieateu Ly iOS when youi app is in-
stalleu on the uevice.
2. Cieating live text liles in the tnp/txt loluei.
3. Enumeiating all the liles in the tnp/txt loluei just to piove that we successlully
cieateu all live liles in that loluei.
+. Deleting the liles that we cieateu to piove the point ol this iecipe.
5. Enumeiating the liles again in the tnp/txt loluei to uemonstiate that the ueletion
mechanism woikeu just line.
6. Deleting the tnp/txt loluei, as we no longei neeu it. Again, as I mentioneu Leloie,
Le minulul ol what lolueis anu liles you cieate on uisk. Disk space uoesn`t giow
on tiees! So il you uon`t neeu youi liles anu lolueis any longei, uelete them.
12.5 Deleting Files and Folders | 589
www.it-ebooks.info
Now you not only know how to cieate liles anu lolueis, Lut how to get iiu ol them
when you longei neeu them.
See Also
Recipe 12.2
12.6 Securing Files on Disk
Problem
You want to make suie that the liles that you aie woiking with on uisk aie lockeu anu
enciypteu when the iOS uevice is lockeu, anu not accessiLle Ly an attackei.
Solution
Cieate youi lile using the createFileAtPath:contents:attributes: instance methou oi
youi lolueis using the createDirectoryAtPath:withIntermediateDirectories:attributes:
error: instance methou ol the NSFileManager anu use the NSFileProtectionKey key in
the attiiLutes uictionaiy with one ol the lollowing values:
NSFileProtectionCompleteUnlessOpen
The lile will Le enciypteu on uisk anu will Le accessiLle Ly youi app only altei the
usei has unlockeu the uevice. The usei can then lock the uevice Lack, Lut while
you have the hanule to the lile, you can continue to ieau liom anu wiite to the lile.
NSFileProtectionComplete
The lile is enciypteu on uisk anu is not accessiLle Ly youi app unless the usei
unlocks the uevice. Il you have a hanule to the lile when the uevice is unlockeu,
you will not Le aLle to ieau liom oi wiite to the lile il the usei ueciues to lock the
uevice again.
NSFileProtectionCompleteUntilFirstUserAuthentication
The lile is enciypteu on uisk anu you can ieau liom it oi wiite to it only altei the
usei has at least unlockeu the uevice once. Altei that one-time unlocking, you can
ieau liom anu wiite to the lile. The usei can lock the uevice, Lut that won`t allect
you anu youi lile hanule.
iOS uses the passcoue that the usei sets loi hei uevice as a seeu to the enciyption applieu
to sensitive uata on the uevice. Il you aie stoiing sensitive liles oi lolueis on uisk, you
can use this mechanism, thiough NSFileManager, to ensuie youi uata is secuiely stoieu
on uisk.
Discussion
Il you noticeu, I talkeu aLout a ji|c hand|c in the NSFileProtectionCompleteUntilFirst
UserAuthentication item ol the list. Vhat uiu I mean Ly that? Up to now, we have Leen
590 | Chapter 12: Files and Folder Management
www.it-ebooks.info
saving complete uata to uisk anu ieauing complete uata Lack liom uisk. That`s gieat,
Lut sometimes you may want to open a lile anu keep wiiting to it anu ieauing liom it,
appenuing uata to it, anu so on. Foi this puipose, the iOS SDK pioviues piogiammeis
with the NSFileHandle class. This is a high-level iepiesentation ol a lile anu allows you
to peiloim almost eveiy opeiation possiLle to a lile.
Let`s have a look at a simple example. Say we want to wiite a simple text to a lile unuei
tnp/ji|c.txt. This is how simple it is to uo so:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
NSFileManager *fileManager = [[NSFileManager alloc] init];
NSString *filePath = [NSTemporaryDirectory()
stringByAppendingPathComponent:@"file.txt"];
BOOL fileIsCreated = NO;
if ([fileManager fileExistsAtPath:filePath] == NO){
fileIsCreated = [fileManager createFileAtPath:filePath
contents:nil
attributes:nil];
}
if (fileIsCreated == YES){
/* Open the file handle */
NSFileHandle *fileHandle = [NSFileHandle
fileHandleForUpdatingAtPath:filePath];
if (fileHandle != nil){
NSString *stringToWrite = @"Hello, World!";
/* Write the data */
[fileHandle writeData:
[stringToWrite dataUsingEncoding:NSUTF8StringEncoding]];
NSLog(@"Wrote to the file.");
} else {
NSLog(@"Failed to create the file handle.");
}
/* Close the file handle */
[fileHandle closeFile];
/* Delete the file now that we no longer need it */
[fileManager removeItemAtPath:filePath error:nil];
} else {
NSLog(@"Failed to create the file on disk.");
}
self.window = [[UIWindow alloc]
12.6 Securing Files on Disk | 591
www.it-ebooks.info
initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
As you can see, we aie using the help ol the NSFileManager to cieate the lile il it uoesn`t
exist anu also to uelete the lile once we aie uone with it. Once the lile is cieateu, we
can use the fileHandleForUpdatingAtPath: class methou ol the NSFileHandle class in
oiuei to open oui lile with ieau anu wiite access. Heie aie the uilleient impoitant class
methous on NSFileHandle that you can use to open liles loi vaiious puiposes:
fileHandleForUpdatingAtPath:
Opens the lile with ieau anu wiite access. This will place the pointei ol the lile at
the Leginning ol the lile.
fileHandleForReadingAtPath:
Opens the lile with ieau access only.
fileHandleForWritingAtPath:
Opens the lile with wiite access only.
None ol these methous cieate the lile at the given path il the lile uoesn`t
exist alieauy.
Once the lile is open, you can use one ol the lollowing instance methous ol the NSFile
Handle class to ieau liom oi wiite to the lile, uepenuing on what methou you useu to
open the lile:
readDataOfLength:
Retuins n numLei ol Lytes liom the lile as an instance ol NSData.
writeData:
Viites the given NSData to the lile.
You can always linu out how many Lytes aie alieauy wiitten to the lile Ly getting the
ietuin value ol the availableData instance methou ol the NSFileHandle.
Now that we know the Lasics ol lile hanules, let`s get on with the main puipose ol this
iecipe, which is secuie lile stoiage.
Let`s say you aie captuiing inloimation aLout youi usei that you will use while youi
app is iunning. Next time youi app iuns, you will attempt to ieau liom the lile. Il it
uoesn`t exist, you will cieate it again. As we ieau in Recipe 12.0, the Library/Cachcs/
loluei is the Lest place to stoie this type ol uata, since it is uata that oui app is cieating
anu the contents ol this loluei will not Le Lackeu up Ly iOS into Lackup stoiage uevice,
such as iClouu oi iTunes. So let`s get staiteu. In this example, we will use the NSFile
ProtectionCompleteUnlessOpen piotection loi oui lile, which we will name uscrdata.txt.
592 | Chapter 12: Files and Folder Management
www.it-ebooks.info
Theie aie two little things that we have to consiuei in this example coue. Ve neeu to
make suie:
That we have set a passcoue on the uevice wheie we aie planning to iun this app.
That once the app is iunning on the uevice, we lock the uevice so the lile Lecomes
piotecteu again.
In this example coue, I am using technigues that aie coveieu in Chaptei 1+, so uon`t
leel Lau il it seems a Lit stiange. The only thing stiange that you may linu in this example
coue is that we aie waiting loi the app to Lecome inactive, which is what happens when
the usei locks hei uevice while oui app is iunning. This can also happen il the usei
senus the app to the Lackgiounu, Lut loi the sake ol simplicity, we won`t consiuei that
scenaiio. So make suie that when the app is executeu on the uevice, you piess the lock
Lutton to senu the app to the inactive moue:
- (NSString *) cachesDirectory{
NSArray *caches = [self.fileManager URLsForDirectory:NSCachesDirectory
inDomains:NSUserDomainMask];
if ([caches count] > 0){
NSURL *result = caches[0];
return [result path];
} else {
return nil;
}
}
- (void) createFileIfDoesntExist:(NSString *)paramPath{
NSDictionary *attributes = @{
NSFileProtectionKey : NSFileProtectionComplete
};
if ([self.fileManager fileExistsAtPath:paramPath] == NO){
[self.fileManager createFileAtPath:paramPath
contents:nil
attributes:attributes];
}
}
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
self.fileManager = [[NSFileManager alloc] init];
NSString *filePath = [[self cachesDirectory]
stringByAppendingPathComponent:@"file.txt"];
[self createFileIfDoesntExist:filePath];
self.fileHandle = [NSFileHandle fileHandleForUpdatingAtPath:filePath];
12.6 Securing Files on Disk | 593
www.it-ebooks.info
self.window = [[UIWindow alloc]
initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
- (void) writeToFile{
@try {
NSLog(@"Attempting to write to the file...");
[self.fileHandle writeData:
[@"Hello World" dataUsingEncoding:NSUTF8StringEncoding]];
NSLog(@"Successfully wrote to the file. Make sure you have a passcode\
set on your device. This method should have failed!");
}
@catch (NSException *exception) {
NSLog(@"Failed to write to file. Is it locked?");
}
@finally {
NSLog(@"Finishing our background task...");
[[UIApplication sharedApplication]
endBackgroundTask:self.backgroundTask];
}
}
- (void)applicationWillResignActive:(UIApplication *)application{
if (self.fileHandle == nil){
NSLog(@"The file wasn't opened. No point trying to write to it!");
return;
}
NSLog(@"Scheduling writing to file in 10 seconds...");
self.backgroundTask = [[UIApplication sharedApplication]
beginBackgroundTaskWithExpirationHandler:^{
self.backgroundTask = UIBackgroundTaskInvalid;
}];
[self performSelector:@selector(writeToFile)
withObject:nil
afterDelay:10.0f];
}
Theie aie a lew methous in this example, all ol which aie explaineu heie:
cachesDirectory
Retuins the path ol the Library/Cachcs/ uiiectoiy in youi app`s Lunule.
594 | Chapter 12: Files and Folder Management
www.it-ebooks.info
createFileIfDoesntExist:
Takes the path ol a lile anu cieates it il it uoesn`t exist. The cieation happens using
the NSFileProtectionComplete value loi the NSFileProtectionKey attiiLute so that
the lile will Le lockeu, even il we have alieauy openeu it, when the uevice is lockeu.
application:didFinishLaunchingWithOptions:
Gets the hanule to the lile Ly utilizing the pieviously uesciiLeu methous.
applicationWillResignActive:
Scheuules a wiite seguence to the lile altei 10 seconus. This methou gets calleu in
vaiious situations, one ol which Leing when the usei piesses the lock Lutton on
the uevice. So we aie assuming this is the case.
writeToFile
Does the actual wiiting to the lile.
As you can see liom the coue, the writeData: instance methou ol the
NSFileHandle class iaises an exception il it cannot wiite to the lile suc-
cesslully. The readDataOfLength: instance methou ol this class uoes the
same thing il it cannot ieau liom the lile.
Il you iun this app on a uevice that has a passcoue, anu then lock the uevice, you will
see something similai to this showing up in the Console scieen altei 10 seconus:
Scheduling writing to file in 10 seconds...
Attempting to write to the file...
Failed to write to file. Is it locked?
Finishing our background task...
See Also
Recipe 12.5; Recipe 12.2
12.7 Saving Objects to Files
Problem
You have auueu a new class to youi pioject anu you woulu like to Le aLle to save this
oLject to uisk as a lile anu then ieau it Lack liom uisk whenevei ieguiieu.
Solution
Make suie that youi class conloims to the NSCoding piotocol anu implement all the
ieguiieu methous ol this methou. Don`t woiiy; I will walk you thiough this in the
Discussion section ol this iecipe.
12.7 Saving Objects to Files | 595
www.it-ebooks.info
Discussion
Theie aie two ieally hanuy classes in iOS SDK loi this specilic puipose, which in the
piogiamming woilu is known as narsha||ing. They aie calleu:
NSKeyedArchiver
A class that can aichive oi save the contents ol an oLject oi oLject tiee Ly keys.
Each value in the class, let`s say each piopeity, can Le saveu to the aichive, using
a key that the piogiammei chooses. You will Le given an aichive lile (we will talk
moie aLout this) anu you will just save youi values using keys that you choose.
]ust like a uictionaiy!
NSKeyedUnarchiver
This class uoes the ieveise ol the aichivei class. It simply gives you the unaichiveu
uictionaiy anu asks you to ieau the values into youi oLject`s piopeities.
In oiuei loi the aichivei anu the unaichivei to woik, you neeu to make suie that the
oLjects you aie asking them to aichive oi unaichive conloim to the NSCoding piotocol.
Let`s stait with a simple Person class. Heie is the heauei lile ol oui class:
@interface Person : NSObject <NSCoding>
@property (nonatomic, copy) NSString *firstName;
@property (nonatomic, copy) NSString *lastName;
@end
Now il you uon`t wiite any coue loi the implementation ol this class anu tiy to compile
youi coue, you will see that the compilei will stait to thiow wainings at you saying you
have not conloimeu to the NSCoding piotocol anu have not implementeu its ieguiieu
methous. The methous that we have to implement aie as lollows:
- (void)encodeWithCoder:(NSCoder *)aCoder
This methou will give you a couei. You will use the couei just like you woulu use
a uictionaiy. Simply stoie youi values in it using keys that you choose.
- (id)initWithCoder:(NSCoder *)aDecoder;
This methou gets calleu on youi class when you tiy to unaichive youi class using
NSKeyedUnarchiver. Simply ieau youi values Lack liom the NSCoder instance passeu
to this methou.
Now, using this inloimation, let`s implement oui class:
#import "Person.h"
NSString *const kFirstNameKey = @"FirstNameKey";
NSString *const kLastNameKey = @"LastNameKey";
@implementation Person
- (void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:self.firstName forKey:kFirstNameKey];
596 | Chapter 12: Files and Folder Management
www.it-ebooks.info
[aCoder encodeObject:self.lastName forKey:kLastNameKey];
}
- (id)initWithCoder:(NSCoder *)aDecoder{
self = [super init];
if (self != nil){
_firstName = [aDecoder decodeObjectForKey:kFirstNameKey];
_lastName = [aDecoder decodeObjectForKey:kLastNameKey];
}
return self;
}
@end
You can see that the way we aie using the instance ol the NSCoder class is ieally similai
to that ol a uictionaiy except that, insteau ol setValue:forKey: in a uictionaiy, we aie
using encodeObject:forKey:, anu insteau ol objectForKey: in a uictionaiy, we aie using
decodeObjectForKey:. All in all, veiy similai to the way we use uictionaiies.
Ve aie uone with this class. So let`s implement the aichiving anu unaichiving mecha-
nism using the two aloiementioneu classes. Oui plan is to liist instantiate an oLject ol
type Person, aichive it, get iiu ol it in memoiy, ieau it Lack liom lile, anu see whethei
the unaichiveu value matches the value that we oiiginally put in the class. Ve will Le
implementing this in oui app uelegate, Lecause it`s the easiest place to uo this:
#import "AppDelegate.h"
#import "Person.h"
@implementation AppDelegate
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
/* Define the name and the last name we are going to set in the object */
NSString *const kFirstName = @"Steven";
NSString *const kLastName = @"Jobs";
/* Determine where we want to archive the object */
NSString *filePath = [NSTemporaryDirectory()
stringByAppendingPathComponent:@"steveJobs.txt"];
/* Instantiate the object */
Person *steveJobs = [[Person alloc] init];
steveJobs.firstName = kFirstName;
steveJobs.lastName = kLastName;
/* Archive the object to the file */
[NSKeyedArchiver archiveRootObject:steveJobs toFile:filePath];
/* Now unarchive the same class into another object */
Person *cloneOfSteveJobs =
[NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
12.7 Saving Objects to Files | 597
www.it-ebooks.info
/* Check if the unarchived object has the same first name and last name
as the previously archived object */
if ([cloneOfSteveJobs.firstName isEqualToString:kFirstName] &&
[cloneOfSteveJobs.lastName isEqualToString:kLastName]){
NSLog(@"Unarchiving worked");
} else {
NSLog(@"Could not read the same values back. Oh no!");
}
/* We no longer need the temp file, delete it */
NSFileManager *fileManager = [[NSFileManager alloc] init];
[fileManager removeItemAtPath:filePath error:nil];
self.window = [[UIWindow alloc]
initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
So the aichiving simply uses the archiveRootObject:toFile class methou ol the NSKeyed
Archiver class, which takes an oLject anu a lile on which the content ol the lile has to
Le saveu. Simple anu easy. How aLout unaichiving? That is as easy as the aichiving
piocess. All you have to uo is just pass the aichiveu lile path to the unarchiveObject
WithFile: class methou ol the NSKeyedUnarchiver class anu that class will uo the iest
loi you.
See Also
Recipe 12.1
598 | Chapter 12: Files and Folder Management
www.it-ebooks.info
CHAPTER 13
Camera and the Photo Library
13.0 Introduction
Devices iunning iOS, such as the iPhone, aie eguippeu with cameiasloi instance,
the iPhone 5 has two cameias anu the iPhone 3G anu 3GS each have one. Some iOS
uevices, such as the liist geneiation ol the iPau, uo not have cameias. The
UIImagePickerController class allows piogiammeis to uisplay the lamiliai Cameia in-
teilace to theii useis anu ask them to take a photo oi shoot a viueo. The photos taken
oi the viueos shot Ly the usei with the UIImagePickerController class then Lecome
accessiLle to the piogiammei.
In this chaptei, you will leain how to let useis take photos anu shoot viueos liom insiue
applications, access these photos anu viueos, anu access the photos anu viueos that aie
placeu insiue the Photo LiLiaiy on an iOS uevice, such as the iPou touch anu iPau.
iOS Simulatoi uoes not suppoit the Cameia inteilace. Please test anu
ueLug all youi applications that ieguiie a Cameia inteilace on a ieal iOS
uevice with a cameia.
In this chaptei, we will liist attempt to ueteimine il a cameia is availaLle on the iOS
uevice iunning the application. You can also ueteimine whethei the cameia allows you
(the piogiammei) to captuie viueos, images, oi Loth. To uo this, make suie you have
auueu the Mobi|cCorcScrviccs.jrancwor| liamewoik to youi taiget Ly lollowing these
steps:
1. Click on youi pioject`s icon in Xcoue.
2. Select the taiget to which you want to auu the liamewoik.
3. On the top ol the scieen, select the Builu Phases taL.
+. In the Builu Phases scieen, expanu the Link Binaiy with LiLiaiies Lox anu piess
the little - Lutton on the Lottom-lelt coinei ol that Lox.
599
www.it-ebooks.info
5. Choose Mobi|cCorcScrviccs.jrancwor| liom the list.
6. Click the Auu Lutton.
Ve will then move to othei topics, such as accessing viueos anu photos liom uilleient
alLums on an iOS uevice. These aie the same alLums that aie accessiLle thiough the
Photos application Luilt into iOS.
Accessing photos insiue alLums is moie stiaightloiwaiu than accessing viueos, how-
evei. Foi photos, we will Le given the auuiess ol the photo anu we can simply loau the
uata ol the image eithei in an instance ol NSData oi uiiectly into an instance ol
UIImage. Foi viueos, we won`t Le given a lile auuiess on the lilesystem liom which to
loau the uata ol the viueo. Insteau, we will Le given an auuiess such as this:
assets-library://asset/asset.MOV?id=1000000004&ext=MOV
Foi auuiesses such as this, we neeu to use the Assets LiLiaiy liamewoik. The Assets
LiLiaiy liamewoik allows us to access the contents accessiLle thiough the Photos ap-
plication, such as viueos anu photos shot Ly the usei. You can also use the Assets LiLiaiy
liamewoik to save images anu viueos on the uevice. These photos anu viueos will then
Lecome accessiLle Ly the Photo LiLiaiy as well as othei applications that wish to access
these contents.
To make suie the iecipes in this chaptei compile coiiectly, lollow these steps to auu
the Assets LiLiaiy liamewoik to youi taiget:
1. Click on youi pioject`s icon in Xcoue.
2. Select the taiget to which you want to auu the liamewoik.
3. On the top ol the scieen, select the Builu Phases taL.
+. In the Builu Phases scieen, expanu the Link Binaiy with LiLiaiies Lox anu piess
the little - Lutton on the Lottom-lelt coinei ol that Lox.
5. Choose AssctsLibrary.jrancwor| liom the list.
6. Click the Auu Lutton.
To access the uata ol an asset given the URL to the asset, lollow these steps:
1. Allocate anu initialize an oLject ol type ALAssetsLibrary. The Assets LiLiaiy oLject
lacilitates the Liiuge that you neeu in oiuei to access the viueos anu photos acces-
siLle Ly the Photos application.
2. Use the assetForURL:resultBlock:failureBlock instance methou ol the Assets Li-
Liaiy oLject (allocateu anu initializeu in step 1) to access the asset. An asset coulu
Le an image, a viueo, oi any othei iesouice that Apple might latei ueciue to auu to
the Photo LiLiaiy. This methou woiks with Llock oLjects. Foi moie inloimation
aLout Llock oLjects anu GCD, please ielei to Chaptei 6.
3. Release the Assets LiLiaiy oLject allocateu anu initializeu in step 1.
600 | Chapter 13: Camera and the Photo Library
www.it-ebooks.info
At this point, you might Le wonueiing: how uo I access the uata loi the asset? The
resultBlock paiametei ol the assetForURL:resultBlock:failureBlock instance methou
ol the Assets LiLiaiy oLject will neeu to point to a Llock oLject that accepts a single
paiametei ol type ALAsset. ALAsset is a class pioviueu Ly the Assets LiLiaiy that en-
capsulates an asset availaLle to Photos anu any othei iOS application that wishes to
use these assets. Foi moie inloimation aLout stoiing photos anu viueos in the Photo
LiLiaiy, please ielei to Recipes 13.+ anu 13.5. Il you want to leain moie aLout ietiieving
photos anu viueos liom the Photo LiLiaiy anu the Assets LiLiaiy, please ielei to Recipes
13.6 anu 13.7.
13.1 Detecting and Probing the Camera
Problem
You want to know whethei the iOS uevice iunning youi application has a cameia that
you can access. This is an impoitant check to make Leloie attempting to use the cameia,
unless you aie suie youi application will nevei iun on a uevice that lacks one.
Solution
Use the isSourceTypeAvailable: class methou ol UIImagePickerController with the
UIImagePickerControllerSourceTypeCamera value, like so:
- (BOOL) isCameraAvailable{

return [UIImagePickerController isSourceTypeAvailable:
UIImagePickerControllerSourceTypeCamera];

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

if ([self isCameraAvailable]){
NSLog(@"Camera is available.");
} else {
NSLog(@"Camera is not available.");
}

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

self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
13.1 Detecting and Probing the Camera | 601
www.it-ebooks.info
Discussion
Beloie attempting to uisplay an instance ol UIImagePickerController to youi usei loi
taking photos oi shooting viueos, you must uetect whethei the uevice suppoits that
inteilace. The isSourceTypeAvailable: class methou allows you to ueteimine thiee
souices ol uata:
The cameia, Ly passing the UIImagePickerControllerSourceTypeCamera value to
this methou.
The Photo LiLiaiy, Ly passing the value UIImagePickerControllerSourceType
PhotoLibrary to this methou. This Liowses the ioot loluei ol the Photos uiiectoiy
on the uevice.
The cameia ioll loluei in the Photos uiiectoiy, Ly passing the UIImagePickerCon
trollerSourceTypeSavedPhotosAlbum value to this methou.
Il you want to check the availaLility ol any ol these lacilities on an iOS uevice, you must
pass these values to the isSourceTypeAvailable: class methou ol UIImagePicker
Controller Leloie attempting to piesent the inteilaces to the usei.
Now in the .h oi the .n lile ol youi oLject(s) (uepenuing on youi ieguiiements), impoit
the main heauei lile ol the liamewoik we just auueu. Heie I will impoit these liamewoik
into the .h lile ol my app uelegate:
#import <UIKit/UIKit.h>
#import <AssetsLibrary/AssetsLibrary.h>
#import <MobileCoreServices/MobileCoreServices.h>
@interface Detecting_and_Probing_the_CameraAppDelegate
: UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
Now we can use the isSourceTypeAvailable: anu availableMediaTypesForSource
Type: class methous ol UIImagePickerController to ueteimine liist il a meuia souice is
availaLle (cameia, Photo LiLiaiy, etc.), anu il so, whethei meuia types such as image
anu viueo aie availaLle on that meuia souice:
- (BOOL) cameraSupportsMedia:(NSString *)paramMediaType
sourceType:(UIImagePickerControllerSourceType)paramSourceType{

__block BOOL result = NO;

if ([paramMediaType length] == 0){
NSLog(@"Media type is empty.");
return NO;
}

602 | Chapter 13: Camera and the Photo Library
www.it-ebooks.info
NSArray *availableMediaTypes =
[UIImagePickerController availableMediaTypesForSourceType:paramSourceType];

[availableMediaTypes enumerateObjectsUsingBlock:
^(id obj, NSUInteger idx, BOOL *stop) {

NSString *mediaType = (NSString *)obj;
if ([mediaType isEqualToString:paramMediaType]){
result = YES;
*stop= YES;
}

}];

return result;

}
- (BOOL) doesCameraSupportShootingVideos{

return [self cameraSupportsMedia:(__bridge NSString *)kUTTypeMovie
sourceType:UIImagePickerControllerSourceTypeCamera];

}
- (BOOL) doesCameraSupportTakingPhotos{

return [self cameraSupportsMedia:(__bridge NSString *)kUTTypeImage
sourceType:UIImagePickerControllerSourceTypeCamera];

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

if ([self doesCameraSupportTakingPhotos]){
NSLog(@"The camera supports taking photos.");
} else {
NSLog(@"The camera does not support taking photos");
}

if ([self doesCameraSupportShootingVideos]){
NSLog(@"The camera supports shooting videos.");
} else {
NSLog(@"The camera does not support shooting videos.");
}

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

self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
13.1 Detecting and Probing the Camera | 603
www.it-ebooks.info
Ve aie typecasting the kUTTypeMovie anu the kUTTypeImage values to
NSString using __bridge (as explaineu in Recipe 1.1S). The ieason Le-
hinu this is that the two aloiementioneu values aie ol type CFString
Ref anu we neeu to ietiieve theii NSString iepiesentation. To help the
static analyzei anu the compilei anu to avoiu getting wainings liom the
compilei, it is Lest to uo this typecasting.
Some iOS uevices can have moie than one cameia. The two cameias might Le calleu
the liont anu the ieai cameias. To ueteimine whethei these cameias aie availaLle, use
the isCameraDeviceAvailable: class methou ol UIImagePickerController, like so:
- (BOOL) isFrontCameraAvailable{

return [UIImagePickerController
isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceFront];

}
- (BOOL) isRearCameraAvailable{

return [UIImagePickerController
isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceRear];

}
By calling these methous on an oluei iPhone with no ieai cameia, you will see that the
isFrontCameraAvailable methou ietuins NO anu the isRearCameraAvailable methou ie-
tuins YES. Running the coue on an iPhone with Loth liont anu ieai cameias will piove
that Loth methous will ietuin YES, as iPhone 5 uevices aie eguippeu with Loth liont-
anu ieai-lacing cameias.
Il uetecting which cameia is piesent on a uevice isn`t enough loi youi application, you
can ietiieve othei settings using the UIImagePickerController class. One such setting
is whethei llash capaLility is availaLle loi a cameia on the uevice. You can use the
isFlashAvailableForCameraDevice: class methou ol UIImagePickerController to uetei-
mine the availaLility ol a llash capaLility on the ieai oi liont cameia. Please Leai in
minu that the isFlashAvailableForCameraDevice: class methou ol UIImagePickerCon
troller checks the availaLility ol the given cameia uevice liist, Leloie checking the
availaLility ol a llash capaLility on that cameia. Theieloie, you can iun the methous
we will implement on uevices that uo not have liont oi ieai cameias, without a neeu
to liist check il the cameia is availaLle.
- (BOOL) isFlashAvailableOnFrontCamera{

return [UIImagePickerController isFlashAvailableForCameraDevice:
UIImagePickerControllerCameraDeviceFront];

}- (BOOL) isFlashAvailableOnRearCamera{

604 | Chapter 13: Camera and the Photo Library
www.it-ebooks.info
return [UIImagePickerController isFlashAvailableForCameraDevice:
UIImagePickerControllerCameraDeviceRear];

}
Now il we take auvantage ol all the methous that we wiote in this iecipe anu test them
in youi app uelegate (loi example), we can see the iesults on uilleient uevices:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

if ([self isFrontCameraAvailable]){
NSLog(@"The front camera is available.");
if ([self isFlashAvailableOnFrontCamera]){
NSLog(@"The front camera is equipped with a flash");
} else {
NSLog(@"The front camera is not equipped with a flash");
}
} else {
NSLog(@"The front camera is not available.");
}

if ([self isRearCameraAvailable]){
NSLog(@"The rear camera is available.");
if ([self isFlashAvailableOnRearCamera]){
NSLog(@"The rear camera is equipped with a flash");
} else {
NSLog(@"The rear camera is not equipped with a flash");
}
} else {
NSLog(@"The rear camera is not available.");
}

if ([self doesCameraSupportTakingPhotos]){
NSLog(@"The camera supports taking photos.");
} else {
NSLog(@"The camera does not support taking photos");
}

if ([self doesCameraSupportShootingVideos]){
NSLog(@"The camera supports shooting videos.");
} else {
NSLog(@"The camera does not support shooting videos.");
}

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

self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Heie aie the iesults when we iun the application on an iPhone +:
13.1 Detecting and Probing the Camera | 605
www.it-ebooks.info
The front camera is available.
The front camera is not equipped with a flash
The rear camera is available.
The rear camera is equipped with a flash
The camera supports taking photos.
The camera supports shooting videos.
Heie is the output ol the same coue when iun on an iPhone 3GS:
The front camera is not available.
The rear camera is available.
The rear camera is not equipped with a flash
The camera supports taking photos.
The camera supports shooting videos.
Running the same coue on the liist geneiation iPau will iesult in this output in the
console winuow:
The front camera is not available.
The rear camera is not available.
The camera does not support taking photos
The camera does not support shooting videos
Running the same coue on the iPau 2 will iesult in this output in the console winuow:
The front camera is available.
The front camera is not equipped with a flash
The rear camera is available.
The rear camera is not equipped with a flash
The camera supports taking photos.
The camera supports shooting videos.
13.2 Taking Photos with the Camera
Problem
You want to ask the usei to take a photo with the cameia on his iOS uevice, anu you
want to access that photo once the usei is uone.
Solution
Instantiate an oLject ol type UIImagePickerController anu piesent it as a moual view
contiollei on youi cuiient view contiollei. Heie is the .h lile ol the view contiollei:
#import <UIKit/UIKit.h>
#import <AssetsLibrary/AssetsLibrary.h>
#import <MobileCoreServices/MobileCoreServices.h>
@interface Taking_Photos_with_the_CameraViewController
: UIViewController <UINavigationControllerDelegate,
UIImagePickerControllerDelegate>
@end
606 | Chapter 13: Camera and the Photo Library
www.it-ebooks.info
The uelegate ol an instance ol UIImagePickerController must conloim to the
UINavigationControllerDelegate anu UIImagePickerControllerDelegate piotocols. Il
you loiget to incluue them in the .h lile ol youi uelegate oLject, you`ll get wainings
liom the compilei when assigning a value to the uelegate piopeity ol youi image pickei
contiollei. Please Leai in minu that you can still assign an oLject to the uelegate piopeity
ol an instance ol UIImagePickerController wheie that oLject uoes not explicitly con-
loim to the UIImagePickerControllerDelegate anu UINavigationControllerDelegate
piotocols, Lut implements the ieguiieu methous in these piotocols. I, howevei, suggest
that you give a hint to the compilei that the uelegate oLject uoes, in lact, conloim to
the aloiementioneu piotocols in oiuei to avoiu getting compilei wainings.
In the implementation ol the view contiollei (.n lile), we will attempt to uisplay an
image pickei contiollei as a moual view contiollei, like so:
- (void)viewDidLoad{
[super viewDidLoad];

if ([self isCameraAvailable] &&
[self doesCameraSupportTakingPhotos]){

UIImagePickerController *controller =
[[UIImagePickerController alloc] init];

controller.sourceType = UIImagePickerControllerSourceTypeCamera;

NSString *requiredMediaType = (__bridge NSString *)kUTTypeImage;
controller.mediaTypes = [[NSArray alloc]
initWithObjects:requiredMediaType, nil];

controller.allowsEditing = YES;
controller.delegate = self;

[self.navigationController presentModalViewController:controller
animated:YES];

} else {
NSLog(@"Camera is not available.");
}

}
Ve aie using the isCameraAvailable anu doesCameraSupportTakingPho
tos methous in this example. These methous aie implementeu anu ex-
plaineu in Recipe 13.1.
In this example, we aie allowing the usei to take photos using the image pickei. You
must have noticeu that we aie setting the uelegate piopeity ol the image pickei to
self, which ieleis to the view contiollei. Foi this, we have to make suie we have
13.2 Taking Photos with the Camera | 607
www.it-ebooks.info
implementeu the methous uelineu in the UIImagePickerControllerDelegate piotocol,
like so:
- (void) imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info{

NSLog(@"Picker returned successfully.");

NSString *mediaType = [info objectForKey:
UIImagePickerControllerMediaType];

if ([mediaType isEqualToString:(__bridge NSString *)kUTTypeMovie]){

NSURL *urlOfVideo =
[info objectForKey:UIImagePickerControllerMediaURL];

NSLog(@"Video URL = %@", urlOfVideo);

}

else if ([mediaType isEqualToString:(__bridge NSString *)kUTTypeImage]){

/* Let's get the metadata. This is only for
images. Not videos */

NSDictionary *metadata =
[info objectForKey:
UIImagePickerControllerMediaMetadata];

UIImage *theImage =
[info objectForKey:
UIImagePickerControllerOriginalImage];

NSLog(@"Image Metadata = %@", metadata);
NSLog(@"Image = %@", theImage);


}

[picker dismissModalViewControllerAnimated:YES];

}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{

NSLog(@"Picker was cancelled");
[picker dismissModalViewControllerAnimated:YES];

}
Discussion
Theie aie a couple ol impoitant things that you must keep in minu aLout the image
pickei contiollei`s uelegate. Fiist, two uelegate messages aie calleu on the uelegate
608 | Chapter 13: Camera and the Photo Library
www.it-ebooks.info
oLject ol the image pickei contiollei. The imagePickerController:didFinishPick
ingMediaWithInfo: methou gets calleu when the usei linishes execution ol the image
pickei (e.g., takes a photo anu piesses a Lutton at the enu), wheieas the imagePicker
ControllerDidCancel: methou gets calleu when the image pickei`s opeiation is cancel-
leu.
Also, the imagePickerController:didFinishPickingMediaWithInfo: uelegate methou
contains inloimation aLout the item that was captuieu Ly the usei, Le it an image oi a
viueo. The didFinishPickingMediaWithInfo paiametei is a uictionaiy ol values that tell
you what the image pickei has captuieu anu the metauata ol that item, along with othei
uselul inloimation. The liist thing you have to uo in this methou is to ieau the value
ol the UIImagePickerControllerMediaType key in this uictionaiy. The oLject loi this key
is an instance ol NSString that coulu Le one ol these values:
kUTTypeImage
Foi a photo that was shot Ly the cameia
kUTTypeMovie
Foi a movie/viueo that was shot Ly the cameia
The kUTTypeImage anu kUTTypeMovie values aie availaLle in the MoLile
Coie Seivices liamewoik anu aie ol type CFStringRef. You can simply
typecast these values to NSString il neeueu.
Altei ueteimining the type ol iesouice cieateu Ly the cameia (viueo oi photo), you can
access that iesouice`s piopeities using the didFinishPickingMediaWithInfo uictionaiy
paiametei again.
Foi images (kUTTypeImage), you can access these keys:
UIImagePickerControllerMediaMetadata
This key`s value is an oLject ol type NSDictionary. This uictionaiy contains a lot ol
uselul inloimation aLout the image that was shot Ly the usei. A complete uiscus-
sion ol the values insiue this uictionaiy is Leyonu the scope ol this chaptei.
UIImagePickerControllerOriginalImage
This key`s value is an oLject ol type UIImage containing the image that was shot Ly
the usei.
UIImagePickerControllerCropRect
Il euiting is enaLleu (using the allowsEditing piopeity ol UIImagePicker
Controller), the oLject ol this key will contain the iectangle ol the cioppeu aiea.
UIImagePickerControllerEditedImage
Il euiting is enaLleu (using the allowsEditing piopeity ol UIImagePicker
Controller), this key`s value will contain the euiteu (iesizeu anu scaleu) image.
13.2 Taking Photos with the Camera | 609
www.it-ebooks.info
Foi viueos (kUTTypeMovie) that aie shot Ly the usei, you can access the UIImagePicker
ControllerMediaURL key in the didFinishPickingMediaWithInfo uictionaiy paiametei ol
the imagePickerController:didFinishPickingMediaWithInfo: methou. The value ol this
key is an oLject ol type NSURL containing the URL ol the viueo that was shot Ly the usei.
Altei you get a ieleience to the UIImage instance that the usei took with the cameia,
you can simply use that instance within youi application.
The images shot Ly the image pickei contiollei within youi application
aie not saveu to the cameia ioll Ly uelault.
See Also
Recipe 13.1
13.3 Taking Videos with the Camera
Problem
You want to allow youi useis to shoot a viueo using theii iOS uevice, anu you woulu
like to Le aLle to use that viueo liom insiue youi application.
Solution
Use UIImagePickerController with the UIImagePickerControllerSourceTypeCamera
souice type anu the kUTTypeMovie meuia type:
- (void)viewDidLoad{
[super viewDidLoad];

if ([self isCameraAvailable] &&
[self doesCameraSupportTakingPhotos]){

UIImagePickerController *controller =
[[UIImagePickerController alloc] init];

controller.sourceType = UIImagePickerControllerSourceTypeCamera;

NSString *requiredMediaType = (__bridge NSString *)kUTTypeMovie;
controller.mediaTypes = [[NSArray alloc]
initWithObjects:requiredMediaType, nil];
controller.allowsEditing = YES;
controller.delegate = self;

[self.navigationController presentModalViewController:controller
animated:YES];

610 | Chapter 13: Camera and the Photo Library
www.it-ebooks.info
} else {
NSLog(@"Camera is not available.");
}

}
The isCameraAvailable anu doesCameraSupportShootingVideos methous
useu in this sample coue aie implementeu anu uiscusseu in Recipe 13.1.
Ve will implement the uelegate methous ol the image pickei contiollei like so:
- (void) imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info{

NSLog(@"Picker returned successfully.");

NSLog(@"%@", info);

NSString *mediaType = [info objectForKey:
UIImagePickerControllerMediaType];

if ([mediaType isEqualToString:(__bridge NSString *)kUTTypeMovie]){

NSURL *urlOfVideo =
[info objectForKey:UIImagePickerControllerMediaURL];

NSLog(@"Video URL = %@", urlOfVideo);

NSError *dataReadingError = nil;

NSData *videoData =
[NSData dataWithContentsOfURL:urlOfVideo
options:NSDataReadingMapped
error:&dataReadingError];

if (videoData != nil){
/* We were able to read the data */
NSLog(@"Successfully loaded the data.");
} else {
/* We failed to read the data. Use the dataReadingError
variable to determine what the error is */
NSLog(@"Failed to load the data with error = %@",
dataReadingError);
}

}

[picker dismissModalViewControllerAnimated:YES];
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{
13.3 Taking Videos with the Camera | 611
www.it-ebooks.info

NSLog(@"Picker was cancelled");
[picker dismissModalViewControllerAnimated:YES];

}
Discussion
Once you uetect that the iOS uevice youi application is iunning on suppoits viueo
iecoiuing, you can Liing up the image pickei contiollei with the UIImagePickerControl
lerSourceTypeCamera souice type anu kUTTypeMovie meuia type to allow the useis ol
youi application to shoot viueos. Once they aie uone, the imagePickerController:did
FinishPickingMediaWithInfo: uelegate methou will get calleu anu you can use the did
FinishPickingMediaWithInfo uictionaiy paiametei to linu out moie aLout the captuieu
viueo (the values that can Le placeu insiue this uictionaiy aie thoioughly explaineu in
Recipe 13.2).
Vhen the usei shoots a viueo using the image pickei contiollei, the viueo will Le saveu
in a tempoiaiy loluei insiue youi application`s Lunule, not insiue the cameia ioll. An
example ol such a URL is:
ji|c://|oca|host/privatc/var/nobi|c/App|ications/< APPID >/tnp/capturc-T0x101c20.
tnp.TQ9UTr/capturcdvidco.MO\
The value APPID in the URL iepiesents youi application`s unigue iuen-
tiliei, anu will cleaily Le uilleient uepenuing on youi application.
As the piogiammei, not only can you allow youi useis to shoot viueos liom insiue youi
application, Lut also you can mouily how the viueos aie captuieu. You can change two
impoitant piopeities ol the UIImagePickerController class in oiuei to mouily the ue-
lault Lehavioi ol viueo iecoiuing:
videoQuality
This piopeity specilies the guality ol the viueo. You can choose a value such as
UIImagePickerControllerQualityTypeHigh oi UIImagePickerControllerQualityType
Medium loi the value ol this piopeity.
videoMaximumDuration
This piopeity specilies the maximum uuiation ol the viueo. This value is measuieu
in seconus.
Foi instance, il we weie to allow the useis to iecoiu high-guality viueos loi up to 30
seconus, we coulu simply mouily the values ol the aloiementioneu piopeities ol the
instance ol UIImagePickerController like so:
- (void)viewDidLoad{
[super viewDidLoad];
612 | Chapter 13: Camera and the Photo Library
www.it-ebooks.info

if ([self isCameraAvailable] &&
[self doesCameraSupportTakingPhotos]){

UIImagePickerController *controller =
[[UIImagePickerController alloc] init];

controller.sourceType = UIImagePickerControllerSourceTypeCamera;

NSString *requiredMediaType = (__bridge NSString *)kUTTypeMovie;
controller.mediaTypes = [[NSArray alloc]
initWithObjects:requiredMediaType, nil];

controller.allowsEditing = YES;
controller.delegate = self;

/* Record in high quality */
controller.videoQuality = UIImagePickerControllerQualityTypeHigh;

/* Only allow 30 seconds of recording */
controller.videoMaximumDuration = 30.0f;

[self.navigationController presentModalViewController:controller
animated:YES];

} else {
NSLog(@"Camera is not available.");
}

}
See Also
Recipe 13.1
13.4 Storing Photos in the Photo Library
Problem
You want to Le aLle to stoie a photo in the usei`s photo liLiaiy.
Solution
Use the UIImageWriteToSavedPhotosAlbum pioceuuie:
- (void) imageWasSavedSuccessfully:(UIImage *)paramImage
didFinishSavingWithError:(NSError *)paramError
contextInfo:(void *)paramContextInfo{

if (paramError == nil){
NSLog(@"Image was saved successfully.");
} else {
NSLog(@"An error happened while saving the image.");
13.4 Storing Photos in the Photo Library | 613
www.it-ebooks.info
NSLog(@"Error = %@", paramError);
}

}
- (void) imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info{

NSLog(@"Picker returned successfully.");

NSLog(@"%@", info);

NSString *mediaType = [info objectForKey:
UIImagePickerControllerMediaType];

if ([mediaType isEqualToString:(__bridge NSString *)kUTTypeImage]){
UIImage *theImage = nil;

if ([picker allowsEditing]){
theImage = [info objectForKey:UIImagePickerControllerEditedImage];
} else {
theImage = [info objectForKey:UIImagePickerControllerOriginalImage];
}

SEL selectorToCall =
@selector(imageWasSavedSuccessfully:didFinishSavingWithError:contextInfo:);

UIImageWriteToSavedPhotosAlbum(theImage,
self,
selectorToCall,
NULL);

}

[picker dismissModalViewControllerAnimated:YES];

}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{

NSLog(@"Picker was cancelled");
[picker dismissModalViewControllerAnimated:YES];

}- (void)viewDidLoad{
[super viewDidLoad];

if ([self isCameraAvailable] &&
[self doesCameraSupportTakingPhotos]){

UIImagePickerController *controller =
[[UIImagePickerController alloc] init];

controller.sourceType = UIImagePickerControllerSourceTypeCamera;

614 | Chapter 13: Camera and the Photo Library
www.it-ebooks.info
NSString *requiredMediaType = (__bridge NSString *)kUTTypeImage;
controller.mediaTypes = [[NSArray alloc]
initWithObjects:requiredMediaType, nil];

controller.allowsEditing = YES;
controller.delegate = self;

[self.navigationController presentModalViewController:controller
animated:YES];

} else {
NSLog(@"Camera is not available.");
}

}
The isCameraAvailable anu doesCameraSupportTakingPhotos methous
useu in this example aie thoioughly explaineu in Recipe 13.1.
Discussion
Usually altei a usei is uone taking a photo with hei iOS uevice, she expects the photo
to Le saveu into hei photo liLiaiy. Howevei, applications that aie not oiiginally shippeu
with iOS can ask the usei to take a photo, using the UIImagePickerController class, anu
then piocess that image. In this case, the usei will unueistanu that the application we
pioviueu might not save the photo to hei photo liLiaiyit might simply use it intei-
nally. Foi instance, il an instant messaging application allows useis to tianslei theii
photos to each othei`s uevices, the usei will unueistanu that a photo he takes insiue
the application will not Le saveu to his photo liLiaiy, Lut will insteau Le tiansleiieu
ovei the Inteinet to the othei usei.
Howevei, il you ueciue you want to stoie an instance ol UIImage to the photo liLiaiy
on the usei`s uevice, you can use the UIImageWriteToSavedPhotosAlbum lunction. This
lunction accepts loui paiameteis:
1. The image
2. The oLject that will Le notilieu whenevei the image is lully saveu
3. A paiametei that specilies the selectoi that has to Le calleu on the taiget oLject
(specilieu Ly the seconu paiametei) when the save opeiation linishes
+. A context value that will get passeu to the specilieu selectoi once the opeiation is
uone
Pioviuing the seconu, thiiu, anu louith paiameteis to this pioceuuie is optional. Il you
uo pioviue the seconu anu thiiu paiameteis, the louith paiametei still iemains op-
tional. Foi instance, this is the selectoi we have chosen in the example:
13.4 Storing Photos in the Photo Library | 615
www.it-ebooks.info
- (void) imageWasSavedSuccessfully:(UIImage *)paramImage
didFinishSavingWithError:(NSError *)paramError
contextInfo:(void *)paramContextInfo{

if (paramError == nil){
NSLog(@"Image was saved successfully.");
} else {
NSLog(@"An error happened while saving the image.");
NSLog(@"Error = %@", paramError);
}

}
Il the error paiametei that you ieceive in this selectoi is egual to nil,
that means the image was saveu in the usei`s photo liLiaiy successlully.
Otheiwise, you can ietiieve the value ol this paiametei to ueteimine
what the issue was.
13.5 Storing Videos in the Photo Library
Problem
You want to stoie a viueo accessiLle thiough a URL, such as a viueo in youi application
Lunule, to the Photo LiLiaiy.
Solution
Use the writeVideoAtPathToSavedPhotosAlbum:completionBlock: instance methou ol
ALAssetsLibrary:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

self.assetsLibrary = [[ALAssetsLibrary alloc] init];

NSURL *videoURL = [[NSBundle mainBundle] URLForResource:@"MyVideo"
withExtension:@"MOV"];

if (videoURL != nil){
[self.assetsLibrary
writeVideoAtPathToSavedPhotosAlbum:videoURL
completionBlock:^(NSURL *assetURL, NSError *error) {

if (error == nil){
NSLog(@"no errors happened");
} else {
NSLog(@"Error happened while saving the video.");
NSLog(@"The error is = %@", error);
}

}];
616 | Chapter 13: Camera and the Photo Library
www.it-ebooks.info
} else {
NSLog(@"Could not find the video in the app bundle.");
}

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

self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
In the example, assetsLibrary is a piopeity ol type ALAssetsLibrary. Although this
example allocates anu initializes this piopeity in the app uelegate, you uo not neces-
saiily have to use Assets LiLiaiy oLjects in youi app uelegate. You can allocate, initialize,
anu use them anywheie in youi application that you linu most appiopiiate.
Discussion
The Assets LiLiaiy liamewoik is a convenient Liiuge Letween uevelopeis anu the Photo
LiLiaiy. As mentioneu in Recipe 13.6, the iOS SDK pioviues you with Luilt-in GUI
components that you can use to access the contents ol the Photo LiLiaiy. Howevei,
you might sometimes ieguiie uiiect access to these contents. In such instances, you can
use the Assets LiLiaiy liamewoik.
Altei allocating anu initializing the Assets LiLiaiy oLject ol type ALAssetsLibrary, you
can use the writeVideoAtPathToSavedPhotosAlbum:completionBlock: instance methou
ol this oLject to wiite a viueo liom a URL to the Photo LiLiaiy. All you have to uo is
pioviue the URL ol the viueo in NSURL loim anu a Llock oLject whose coue will Le calleu
when the viueo is saveu. The Llock oLject must accept two paiameteis ol type NSURL
anu NSError, iespectively.
Il the error paiametei is nil, the save piocess went well anu you uon`t have to woiiy
aLout anything. One ol the common eiiois that iOS coulu ietuin to you is similai to
this:
Error Domain=ALAssetsLibraryErrorDomain Code=-3302 "Invalid data"
UserInfo=0x7923590 {NSLocalizedFailureReason=
There was a problem writing this asset because
the data is invalid and cannot be viewed or played.,
NSLocalizedRecoverySuggestion=Try with different data,
NSLocalizedDescription=Invalid data}
You will get this eiioi message il you attempt to pass a URL that is not insiue youi
application Lunule. Il you aie testing youi application on iPhone Simulatoi, you might
occasionally also get this eiioi message:
Error Domain=ALAssetsLibraryErrorDomain Code=-3310 "Data unavailable"
UserInfo=0x6456810 {NSLocalizedRecoverySuggestion=
Launch the Photos application, NSLocalizedDescription=Data unavailable}
13.5 Storing Videos in the Photo Library | 617
www.it-ebooks.info
Il so, please open the Photos application in iOS Simulatoi once, anu then launch youi
application again. This will loice the simulatoi to ieLuilu the necessaiy uataLase loi
the photos that aie availaLle on the simulatoithis will solve this issue, shoulu you
encountei it while ueveloping iOS apps.
The liist paiametei passeu to the Llock oLject pioviueu to the writeVideoAt
PathToSavedPhotosAlbum:completionBlock: methou will point to the Assets LiLiaiy
URL ol the stoieu viueo. A sample URL ol this kinu will look like this:
assets-library://asset/asset.MOV?id=1000000002&ext=MOV
In Recipe 13.7, we will leain how to use such a URL to loau the uata loi the viueo lile
into memoiy.
13.6 Retrieving Photos and Videos from the Photo Library
Problem
You want useis to Le aLle to pick a photo oi a viueo liom theii photo liLiaiy anu use
it in youi application.
Solution
Use the UIImagePickerControllerSourceTypePhotoLibrary value loi the souice type ol
youi UIImagePickerController anu the kUTTypeImage oi kUTTypeMovie value, oi Loth,
loi the meuia type, like so:
- (BOOL) isPhotoLibraryAvailable{

return [UIImagePickerController isSourceTypeAvailable:
UIImagePickerControllerSourceTypePhotoLibrary];

}
- (BOOL) canUserPickVideosFromPhotoLibrary{

return [self
cameraSupportsMedia:(__bridge NSString *)kUTTypeMovie
sourceType:UIImagePickerControllerSourceTypePhotoLibrary];

}
- (BOOL) canUserPickPhotosFromPhotoLibrary{

return [self
cameraSupportsMedia:(__bridge NSString *)kUTTypeImage
sourceType:UIImagePickerControllerSourceTypePhotoLibrary];

}
- (void)viewDidLoad{
618 | Chapter 13: Camera and the Photo Library
www.it-ebooks.info
[super viewDidLoad];
if ([self isPhotoLibraryAvailable]){

UIImagePickerController *controller =
[[UIImagePickerController alloc] init];

controller.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;

NSMutableArray *mediaTypes = [[NSMutableArray alloc] init];

if ([self canUserPickPhotosFromPhotoLibrary]){
[mediaTypes addObject:(__bridge NSString *)kUTTypeImage];
}

if ([self canUserPickVideosFromPhotoLibrary]){
[mediaTypes addObject:(__bridge NSString *)kUTTypeMovie];
}

controller.mediaTypes = mediaTypes;

controller.delegate = self;

[self.navigationController presentModalViewController:controller
animated:YES];

}

}
Foi the implementation ol the cameraSupportsMedia:sourceType: methou we aie using
in this example, please ielei to Recipe 13.1.
Discussion
To allow youi useis to pick photos oi viueos liom theii photo liLiaiy, you must set the
sourceType piopeity ol an instance ol UIImagePickerController to UIImagePickerCon
trollerSourceTypePhotoLibrary Leloie piesenting them with the image pickei. In au-
uition, il you want to liltei the viueos oi photos out ol the items piesenteu to youi useis
once the image pickei is shown, excluue the kUTTypeMovie oi kUTTypeImage value (ie-
spectively) liom the aiiay ol meuia types ol the image pickei (in the mediaTypes piop-
eity).
Beai in minu that setting the mediaTypes piopeity ol an image pickei contiollei to nil
oi an empty aiiay will iesult in a iuntime eiioi.
Altei the usei is uone picking the image, you will get the usual uelegate messages
thiough the UIImagePickerControllerDelegate piotocol. Foi moie inloimation on how
you can implement the methous uelineu in this piotocol loi piocessing images, please
ielei to Recipe 13.2.
13.6 Retrieving Photos and Videos from the Photo Library | 619
www.it-ebooks.info
See Also
Recipe 13.7
13.7 Retrieving Assets from the Assets Library
Problem
You want to uiiectly ietiieve photos oi viueos liom the Photo LiLiaiy without the help
ol any Luilt-in GUI components.
Solution
Use the Assets LiLiaiy liamewoik. Follow these steps:
1. Allocate anu initialize an oLject ol type ALAssetsLibrary.
2. Pioviue two Llock oLjects to the enumerateGroupsWithTypes:usingBlock:failure
Block: instance methou ol the Assets LiLiaiy oLject. The liist Llock will ietiieve
all the gioups associateu with the type that we passeu to this methou. The gioups
will Le ol type ALAssetsGroup. The seconu Llock ietuins an eiioi in case ol lailuie.
3. Use the enumerateAssetsUsingBlock: instance methou ol each gioup oLject to
enumeiate the assets availaLle in each gioup. This methou takes a single paiametei,
a Llock that ietiieves inloimation on a single asset. The Llock that you pass as a
paiametei must accept thiee paiameteis, ol which the liist must Le ol type ALAsset.
+. Altei ietiieving the ALAsset oLjects availaLle in each gioup, you can ietiieve vaiious
piopeities ol each asset, such as theii type, availaLle URLs, anu so on. Retiieve
these piopeities using the valueForProperty: instance methou ol each asset ol type
ALAsset. The ietuin value ol this methou, uepenuing on the piopeity passeu to it,
coulu Le NSDictionary, NSString, oi any othei oLject type. Ve will see a lew com-
mon piopeities that we can ietiieve liom each asset soon.
5. Invoke the defaultRepresentation instance methou ol each oLject ol type ALAs
set to ietiieve its iepiesentation oLject ol type ALAssetRepresentation. Each asset
in the Assets LiLiaiy can have moie than one iepiesentation. Foi instance, a photo
might have a PNG iepiesentation Ly uelault, Lut a ]PEG iepiesentation as well.
Using the defaultRepresentation methou ol each asset ol type ALAsset, you can
ietiieve the ALAssetRepresentation oLject, anu then use that to ietiieve uilleient
iepiesentations (il availaLle) ol each asset.
6. Use the size anu the getBytes:fromOffset:length:error: instance methous ol each
asset iepiesentation to loau the asset`s iepiesentation uata. You can then wiite the
ieau Lytes into an NSData oLject oi uo whatevei else you neeu to uo in youi appli-
cation. Auuitionally, loi photos, you can use the fullResolutionImage, fullScreen
Image, anu CGImageWithOptions: instance methous ol each iepiesentation to ie-
620 | Chapter 13: Camera and the Photo Library
www.it-ebooks.info
tiieve images ol type CGImageRef. You can then constiuct a UIImage liom CGImage
Ref using the imageWithCGImage: class methou ol UIImage:
- (void)viewDidLoad{
[super viewDidLoad];
self.assetsLibrary = [[ALAssetsLibrary alloc] init];

[self.assetsLibrary
enumerateGroupsWithTypes:ALAssetsGroupAll
usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
[group enumerateAssetsUsingBlock:^(ALAsset *result,
NSUInteger index,
BOOL *stop) {

/* Get the asset type */
NSString *assetType = [result valueForProperty:ALAssetPropertyType];

if ([assetType isEqualToString:ALAssetTypePhoto]){
NSLog(@"This is a photo asset");
}

else if ([assetType isEqualToString:ALAssetTypeVideo]){
NSLog(@"This is a video asset");
}

else if ([assetType isEqualToString:ALAssetTypeUnknown]){
NSLog(@"This is an unknown asset");
}

/* Get the URLs for the asset */
NSDictionary *assetURLs = [result valueForProperty:ALAssetPropertyURLs];

NSUInteger assetCounter = 0;
for (NSString *assetURLKey in assetURLs){
assetCounter++;
NSLog(@"Asset URL %lu = %@",
(unsigned long)assetCounter,
[assetURLs valueForKey:assetURLKey]);
}

/* Get the asset's representation object */
ALAssetRepresentation *assetRepresentation =
[result defaultRepresentation];

NSLog(@"Representation Size = %lld", [assetRepresentation size]);

}]; }
failureBlock:^(NSError *error) {
NSLog(@"Failed to enumerate the asset groups.");
}];

}
13.7 Retrieving Assets from the Assets Library | 621
www.it-ebooks.info
Discussion
The Assets LiLiaiy is Lioken uown into gioups. Each gioup contains assets, anu each
asset has piopeities, such as URLs anu iepiesentation oLjects.
You can ietiieve all assets ol all types liom the Assets LiLiaiy using the ALAssetsGrou
pAll constant passeu to the enumerateGroupsWithTypes paiametei ol the enumerate
GroupsWithTypes:usingBlock:failureBlock: instance methou ol the Assets LiLiaiy oL-
ject. Heie is a list ol values you can pass to this paiametei to enumeiate uilleient gioups
ol assets:
ALAssetsGroupAlbum
Gioups iepiesenting alLums that have Leen stoieu on an iOS uevice thiough
iTunes.
ALAssetsGroupFaces
Gioups iepiesenting alLums that contain lace assets that weie stoieu on an iOS
uevice thiough iTunes.
ALAssetsGroupSavedPhotos
Gioups iepiesenting the saveu photos in the Photo LiLiaiy. These aie accessiLle
to an iOS uevice thiough the Photos application as well.
ALAssetsGroupAll
All availaLle gioups in the Assets LiLiaiy.
Now let`s wiite a simple application that ietiieves the uata loi the liist image lounu in
the Assets LiLiaiy, cieates a UIImageView out ol it, anu auus the image view to the view
ol the cuiient view contiollei. This way, we will leain how to ieau the contents ol an
asset using its iepiesentation.
Let`s stait with the ueclaiation ol the view contiollei anu ueline an image view in theie,
which we will use to uisplay the liist image that we can linu in the assets liLiaiy:
#import <UIKit/UIKit.h>
#import <AssetsLibrary/AssetsLibrary.h>
#import <MobileCoreServices/MobileCoreServices.h>
@interface Retrieving_Assets_from_the_Assets_LibraryViewController
: UIViewController <UIImagePickerControllerDelegate,
UINavigationControllerDelegate>
@property (nonatomic, strong) ALAssetsLibrary *assetsLibrary;
@property (nonatomic, strong) UIImageView *imageView;
@end
Now when the view contiollei loaus its view, we will initialize the assets liLiaiy oLject
anu then stait enumeiating the assets liLiaiy until we linu the liist photo. At that time,
we will use the iepiesentation ol that asset (photo) to uisplay the photo on the image
view:
622 | Chapter 13: Camera and the Photo Library
www.it-ebooks.info
- (void)viewDidLoad{
[super viewDidLoad];

self.view.backgroundColor = [UIColor whiteColor];
self.assetsLibrary = [[ALAssetsLibrary alloc] init];

dispatch_queue_t dispatchQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_async(dispatchQueue, ^(void) {

[self.assetsLibrary
enumerateGroupsWithTypes:ALAssetsGroupAll
usingBlock:^(ALAssetsGroup *group, BOOL *stop) {

[group enumerateAssetsUsingBlock:^(ALAsset *result,
NSUInteger index,
BOOL *stop) {

__block BOOL foundThePhoto = NO;

if (foundThePhoto){
*stop = YES;
}

/* Get the asset type */
NSString *assetType = [result valueForProperty:ALAssetPropertyType];

if ([assetType isEqualToString:ALAssetTypePhoto]){
NSLog(@"This is a photo asset");

foundThePhoto = YES;
*stop = YES;

/* Get the asset's representation object */
ALAssetRepresentation *assetRepresentation =
[result defaultRepresentation];

/* We need the scale and orientation to be able to construct a
properly oriented and scaled UIImage out of the
representation object */
CGFloat imageScale = [assetRepresentation scale];

UIImageOrientation imageOrientation =
(UIImageOrientation)[assetRepresentation orientation];

dispatch_async(dispatch_get_main_queue(), ^(void) {

CGImageRef imageReference =
[assetRepresentation fullResolutionImage];

/* Construct the image now */
UIImage *image =
[[UIImage alloc] initWithCGImage:imageReference
scale:imageScale
13.7 Retrieving Assets from the Assets Library | 623
www.it-ebooks.info
orientation:imageOrientation];

if (image != nil){
self.imageView = [[UIImageView alloc]
initWithFrame:self.view.bounds];
self.imageView.contentMode = UIViewContentModeScaleAspectFit;
self.imageView.image = image;
[self.view addSubview:self.imageView];

} else {
NSLog(@"Failed to create the image.");
}
});

}

}];
}
failureBlock:^(NSError *error) {
NSLog(@"Failed to enumerate the asset groups.");
}];

});

}
Ve enumeiate the gioups anu eveiy asset in the gioups. Then we linu the liist photo
asset anu ietiieve its iepiesentation. Using the iepiesentation, we constiuct a
UIImage, anu liom the UIImage, we constiuct a UIImageView to uisplay that image on the
view. Quite simple, isn`t it?
Foi viueo liles, we aie uealing with a slightly uilleient issue, as the ALAsset
Representation class uoes not have any methous that coulu ietuin an oLject that en-
capsulates the viueo liles. Foi this ieason, we have to ieau the contents ol a viueo asset
into a Lullei anu peihaps save it to the Docuncnts loluei wheie it is easiei loi us to
access latei. Ol couise, the ieguiiements uepenu on youi application, Lut in this ex-
ample coue, we will go aheau anu linu the liist viueo in the Assets LiLiaiy anu stoie it
in the application`s Docuncnts loluei unuei the name Tcnp.MO\:
- (void)viewDidLoad{
[super viewDidLoad];

self.view.backgroundColor = [UIColor whiteColor];
self.assetsLibrary = [[ALAssetsLibrary alloc] init];

dispatch_queue_t dispatchQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_async(dispatchQueue, ^(void) {

[self.assetsLibrary
enumerateGroupsWithTypes:ALAssetsGroupAll
usingBlock:^(ALAssetsGroup *group, BOOL *stop) {

624 | Chapter 13: Camera and the Photo Library
www.it-ebooks.info
__block BOOL foundTheVideo = NO;

[group enumerateAssetsUsingBlock:^(ALAsset *result,
NSUInteger index,
BOOL *stop) {

/* Get the asset type */
NSString *assetType = [result valueForProperty:ALAssetPropertyType];

if ([assetType isEqualToString:ALAssetTypeVideo]){
NSLog(@"This is a video asset");

foundTheVideo = YES;
*stop = YES;

/* Get the asset's representation object */
ALAssetRepresentation *assetRepresentation =
[result defaultRepresentation];

const NSUInteger BufferSize = 1024;
uint8_t buffer[BufferSize];
NSUInteger bytesRead = 0;
long long currentOffset = 0;
NSError *readingError = nil;

/* Find the documents folder (an array) */
NSArray *documents =
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES);

/* Retrieve the one documents folder that we need */
NSString *documentsFolder = [documents objectAtIndex:0];

/* Construct the path where the video has to be saved */
NSString *videoPath = [documentsFolder
stringByAppendingPathComponent:@"Temp.MOV"];

NSFileManager *fileManager = [[NSFileManager alloc] init];

/* Create the file if it doesn't exist already */
if ([fileManager fileExistsAtPath:videoPath] == NO){
[fileManager createFileAtPath:videoPath
contents:nil
attributes:nil];
}

/* We will use this file handle to write the contents
of the media assets to the disk */
NSFileHandle *fileHandle = [NSFileHandle
fileHandleForWritingAtPath:videoPath];

do{

/* Read as many bytes as we can put in the buffer */
13.7 Retrieving Assets from the Assets Library | 625
www.it-ebooks.info
bytesRead = [assetRepresentation getBytes:(uint8_t *)&buffer
fromOffset:currentOffset
length:BufferSize
error:&readingError];

/* If we couldn't read anything, we will exit this loop */
if (bytesRead == 0){
break;
}

/* Keep the offset up to date */
currentOffset += bytesRead;

/* Put the buffer into an NSData */
NSData *readData = [[NSData alloc]
initWithBytes:(const void *)buffer
length:bytesRead];

/* And write the data to file */
[fileHandle writeData:readData];

} while (bytesRead > 0);
NSLog(@"Finished reading and storing the \
video in the documents folder");

}

}];

if (foundTheVideo){
*stop = YES;
}

}
failureBlock:^(NSError *error) {
NSLog(@"Failed to enumerate the asset groups.");
}];

});

}
This is what`s happening in the sample coue:
Ve get the uelault iepiesentation ol the liist viueo asset that we linu in the Assets
LiLiaiy.
Ve cieate a lile calleu Tcnp.MO\ in the application`s Docuncnts loluei to save
the contents ol the viueo asset.
Ve cieate a loop that iuns as long as theie is still uata in the asset iepiesentation
waiting to Le ieau. The getBytes:fromOffset:length:error: instance methou ol
the asset iepiesentation oLject ieaus as many Lytes as we can lit into the Lullei loi
as many times as necessaiy until we get to the enu ol the iepiesentation uata.
626 | Chapter 13: Camera and the Photo Library
www.it-ebooks.info
Altei ieauing the uata into the Lullei, we encapsulate the uata into an oLject ol
type NSData using the initWithBytes:length: initialization methou ol NSData. Ve
then wiite this uata to the lile we cieateu pieviously using the writeData: instance
methou ol NSFileHandle.
13.8 Editing Videos on an iOS Device
Problem
You want the usei ol youi application to Le aLle to euit viueos stiaight liom youi
application.
Solution
Use the UIVideoEditorController class. In this example, we will use this class in con-
junction with an image pickei contiollei. Fiist we will ask the usei to pick a viueo liom
hei photo liLiaiy. Altei she uoes, we will uisplay an instance ol the viueo euitoi con-
tiollei anu allow the usei to euit the viueo she pickeu.
Discussion
The UIVideoEditorController in the iOS SDK allows piogiammeis to uisplay a viueo
euitoi inteilace to the useis ol theii applications. All you have to uo is to pioviue the
URL ol the viueo that neeus to Le euiteu anu then piesent the viueo euitoi contiollei
as a moual view. You shoulu not oveilay the view ol this contiollei with any othei
views, anu you shoulu not mouily this view.
Calling the presentModalViewController:animated: methou immeuiate-
ly altei calling the dismissModalViewControllerAnimated: methou ol a
view contiollei will teiminate youi application with a iuntime eiioi.
You must wait loi the liist view contiollei to Le uismisseu anu then
piesent the seconu view contiollei. You can take auvantage ol the view
DidAppear: instance methou ol youi view contiolleis to uetect when
youi view is uisplayeu. You know at this point that any moual view
contiolleis must have uisappeaieu.
So let`s go aheau anu ueclaie the view contiollei anu any necessaiy piopeities:
#import <UIKit/UIKit.h>
#import <AssetsLibrary/AssetsLibrary.h>
#import <MobileCoreServices/MobileCoreServices.h>
@interface Editing_Videos_on_an_iOS_DeviceViewController
: UIViewController <UINavigationControllerDelegate,
UIVideoEditorControllerDelegate,
UIImagePickerControllerDelegate>
13.8 Editing Videos on an iOS Device | 627
www.it-ebooks.info
@property (nonatomic, strong) NSURL *videoURLToEdit;
@end
The UIVideoEditorController is not uesigneu to woik in lanuscape
moue. Even il the view contiollei that uisplays an instance ol the viueo
euitoi suppoits all oiientations, the viueo euitoi will Le shown in poi-
tiait moue only.
The next thing to uo is to hanule uilleient viueo euitoi uelegate messages in the view
contiollei:
- (void)videoEditorController:(UIVideoEditorController *)editor
didSaveEditedVideoToPath:(NSString *)editedVideoPath{
NSLog(@"The video editor finished saving video");
NSLog(@"The edited video path is at = %@", editedVideoPath);
[editor dismissModalViewControllerAnimated:YES];
}
- (void)videoEditorController:(UIVideoEditorController *)editor
didFailWithError:(NSError *)error{
NSLog(@"Video editor error occurred = %@", error);
[editor dismissModalViewControllerAnimated:YES];
}
- (void)videoEditorControllerDidCancel:(UIVideoEditorController *)editor{
NSLog(@"The video editor was cancelled");
[editor dismissModalViewControllerAnimated:YES];
}
Vhen the view loaus, we neeu to uisplay a viueo pickei to the usei. She will then Le
aLle to pick a viueo liom hei liLiaiy, anu we will then pioceeu to allow hei to euit that
viueo:
- (BOOL) cameraSupportsMedia:(NSString *)paramMediaType
sourceType:(UIImagePickerControllerSourceType)paramSourceType{

__block BOOL result = NO;

if ([paramMediaType length] == 0){
NSLog(@"Media type is empty.");
return NO;
}

NSArray *availableMediaTypes =
[UIImagePickerController availableMediaTypesForSourceType:paramSourceType];

[availableMediaTypes enumerateObjectsUsingBlock:
^(id obj, NSUInteger idx, BOOL *stop) {

NSString *mediaType = (NSString *)obj;
if ([mediaType isEqualToString:paramMediaType]){
result = YES;
628 | Chapter 13: Camera and the Photo Library
www.it-ebooks.info
*stop= YES;
}

}];

return result;

}
- (BOOL) canUserPickVideosFromPhotoLibrary{

return [self cameraSupportsMedia:(__bridge NSString *)kUTTypeMovie
sourceType:UIImagePickerControllerSourceTypePhotoLibrary];

}
- (BOOL) isPhotoLibraryAvailable{

return [UIImagePickerController
isSourceTypeAvailable:
UIImagePickerControllerSourceTypePhotoLibrary];

}
- (void)viewDidLoad {
[super viewDidLoad];

if ([self isPhotoLibraryAvailable] &&
[self canUserPickVideosFromPhotoLibrary]){

UIImagePickerController *imagePicker =
[[UIImagePickerController alloc] init];

/* Set the source type to photo library */
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;

/* And we want the user to be able to pick movies from the library */
NSArray *mediaTypes = [[NSArray alloc] initWithObjects:
(__bridge NSString *)kUTTypeMovie, nil];

imagePicker.mediaTypes = mediaTypes;

/* Set the delegate to the current view controller */
imagePicker.delegate = self;

/* Present the image picker */
[self.navigationController presentModalViewController:imagePicker
animated:YES];

}

}
Ve now neeu to know when the usei is uone picking a viueo, so let`s hanule vaiious
uelegate methous ol the image pickei contiol:
13.8 Editing Videos on an iOS Device | 629
www.it-ebooks.info
- (void) imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info{

NSLog(@"Picker returned successfully.");

NSString *mediaType = [info objectForKey:
UIImagePickerControllerMediaType];

if ([mediaType isEqualToString:(NSString *)kUTTypeMovie]){
self.videoURLToEdit = [info objectForKey:UIImagePickerControllerMediaURL];
}

[picker dismissModalViewControllerAnimated:YES];

}
- (void) imagePickerControllerDidCancel:(UIImagePickerController *)picker{

NSLog(@"Picker was cancelled");
self.videoURLToEdit = nil;
[picker dismissModalViewControllerAnimated:YES];

}
Vhen the view appeais to the usei altei she has selecteu a viueo liom the assets liLiaiy
on hei uevice, we can pioceeu to uisplay the viueo euitoi:
- (void) viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];

if (self.videoURLToEdit != nil){

NSString *videoPath = [self.videoURLToEdit path];

/* First let's make sure the video editor is able to edit the
video at the path in the documents folder */
if ([UIVideoEditorController canEditVideoAtPath:videoPath]){

/* Instantiate the video editor */
UIVideoEditorController *videoEditor =
[[UIVideoEditorController alloc] init];

/* We become the delegate of the video editor */
videoEditor.delegate = self;

/* Make sure to set the path of the video */
videoEditor.videoPath = videoPath;

/* And present the video editor */
[self.navigationController presentModalViewController:videoEditor
animated:YES];

self.videoURLToEdit = nil;

630 | Chapter 13: Camera and the Photo Library
www.it-ebooks.info
} else {
NSLog(@"Cannot edit the video at this path");
}

}

}
In the example, the usei is alloweu to pick any viueo liom the photo liLiaiy. Once she
uoes, we will uisplay the viueo euitoi contiollei Ly pioviuing the path ol the viueo that
the viueo pickei passes to us in a uelegate methou.
The viueo euitoi contiollei`s uelegate gets impoitant messages aLout the state ol the
viueo euitoi. This uelegate oLject must conloim to the UIVideoEditorControllerDele
gate anu UINavigationControllerDelegate piotocols. In the example, we chose the view
contiollei to Lecome the uelegate ol the viueo euitoi. Once the euiting is uone, the
uelegate oLject ieceives the videoEditorController:didSaveEditedVideoToPath: uele-
gate methou liom the viueo euitoi contiollei. The path ol the euiteu viueo will Le passeu
thiough the didSaveEditedVideoToPath paiametei.
Beloie attempting to uisplay the inteilace ol the viueo euitoi to youi useis, you must
call the canEditVideoAtPath: class methou ol UIVideoEditorController to make suie
the path you aie tiying to euit is euitaLle Ly the contiollei. Il the ietuin value ol this
class methou is YES, pioceeu to conliguiing anu uisplaying the viueo euitoi`s inteilace.
Il not, take a sepaiate path, peihaps uisplaying an aleit to youi usei.
See Also
Recipe 13.6; Recipe 13.7
13.8 Editing Videos on an iOS Device | 631
www.it-ebooks.info
www.it-ebooks.info
CHAPTER 14
Multitasking
14.0 Introduction
Multitasking enaLles bac|ground cxccution, which means the application can keep
woiking as usualiunning tasks, spawning new thieaus, listening loi notilications,
anu ieacting to eventsLut simply uoes not uisplay anything on the scieen oi have any
way to inteiact with the usei. Vhen the usei piesses the Home Lutton on his uevice,
which in pievious veisions ol the iPhone anu iPau woulu teiminate the application, the
application is now sent into the Lackgiounu.
An application iunning on an iOS veision that suppoits multitasking is, Ly uelault,
opteu into Lackgiounu execution. Il you link youi application against iOS SDK +.0 anu
latei, you can opt out ol Lackgiounu execution, as you will see in Recipe 1+.10. Il you
uo, youi application will Le teiminateu when the usei piesses the Home Lutton, as
Leloie.
Vhen oui application moves to the Lackgiounu (such as when the usei piesses the
Home Lutton) anu then Lack to the loiegiounu (when the usei selects the application
again), vaiious messages aie sent Ly the system anu aie expecteu to Le ieceiveu Ly an
oLject we uesignate as oui application uelegate. Foi instance, when oui application is
sent to the Lackgiounu, oui application uelegate will ieceive the applicationDidEnter
Background: methou, anu as the application comes Lack to the loiegiounu loi the usei,
the application uelegate will ieceive the applicationWillEnterForeground: uelegate
message.
In auuition to these uelegate messages, iOS also senus notilications to the iunning
application when it tiansitions the application to the Lackgiounu anu liom the Lack-
giounu to the loiegiounu. The notilication that gets sent when the application is moveu
to the Lackgiounu is UIApplicationDidEnterBackgroundNotification, anu the notilica-
tion that gets sent when an application tiansitions liom the Lackgiounu to the loie-
giounu is UIApplicationWillEnterForegroundNotification. You can use the uelault
notilication centei to iegistei loi these notilications.
633
www.it-ebooks.info
14.1 Detecting the Availability of Multitasking
Problem
You want to linu out whethei the iOS uevice iunning youi application suppoits mul-
titasking.
Solution
Call the isMultitaskingSupported instance methou ol UIDevice, like so:
- (BOOL) isMultitaskingSupported{

BOOL result = NO;
if ([[UIDevice currentDevice]
respondsToSelector:@selector(isMultitaskingSupported)]){
result = [[UIDevice currentDevice] isMultitaskingSupported];
}
return result;

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

if ([self isMultitaskingSupported]){
NSLog(@"Multitasking is supported.");
} else {
NSLog(@"Multitasking is not supported.");
}

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

self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Discussion
Youi application, uepenuing on the iOS uevices it taigets, can Le iun anu executeu on
a vaiiety ol uevices on uilleient veisions ol iOS. Foi instance, il you compile youi
application with iOS SDK 6 anu youi ueployment taiget OS is 5.0, youi application
can Le iun on the iPhone 3G, iPhone 3GS, iPhone +, iPhone +S anu iPou touch (seconu
anu thiiu geneiations), pioviueu that the iOS on these uevices has Leen upuateu to iOS
+.0 oi Lettei. Fuitheimoie, a uevice coulu have iOS 6.0 oi latei installeu on it, Lut the
unueilying haiuwaie might not Le stiong enough loi multitasking to Le suppoiteu.
Because ol this, youi application must Le awaie ol whethei multitasking is enaLleu on
that specilic haiuwaie (anu on that specilic iOS) Leloie attempting to act like a multi-
tasking application.
634 | Chapter 14: Multitasking
www.it-ebooks.info
14.2 Completing a Long-Running Task in the Background
Problem
You want to Loiiow some time liom iOS to complete a long-iunning task when youi
application is Leing sent to the Lackgiounu.
Solution
Use the beginBackgroundTaskWithExpirationHandler: instance methou ol UIApplica
tion. Altei you have linisheu the task, call the endBackgroundTask: instance methou ol
UIApplication.
Discussion
Vhen an iOS application is sent to the Lackgiounu, its main thieau is pauseu. The
thieaus you cieate within youi application using the detachNewThreadSelector:toTar
get:withObject: class methou ol NSThread aie also suspenueu. Il you aie attempting to
linish a long-iunning task when youi application is Leing sent to the Lackgiounu, you
must call the beginBackgroundTaskWithExpirationHandler: instance methou ol UIAppli
cation to Loiiow some time liom iOS. The backgroundTimeRemaining piopeity ol UIAp
plication contains the numLei ol seconus the application has to linish its joL. Il the
application uoesn`t linish the long-iunning task Leloie this time expiies, iOS will tei-
minate the application. Eveiy call to the beginBackgroundTaskWithExpirationHandler:
methou must have a coiiesponuing call to endBackgroundTask: (anothei instance meth-
ou ol UIApplication). In othei woius, il you ask loi moie time liom iOS to complete a
task, you must tell iOS when you aie uone with that task. Once this is uone anu no
moie tasks aie ieguesteu to Le iunning in the Lackgiounu, youi application will Le
lully put into the Lackgiounu with all thieaus pauseu.
Vhen youi application is in the loiegiounu, the backgroundTimeRemaining piopeity ol
UIApplication is egual to the DBL_MAX constant, which is the laigest value a value ol type
double can contain (the integei eguivalent ol this value is noimally egual to 1 in this
case). Altei iOS is askeu loi moie time Leloie the application is lully suspenueu, this
piopeity will inuicate the numLei ol seconus the application has Leloie it linishes iun-
ning its task(s).
You can call the beginBackgroundTaskWithExpirationHandler: methou as many times
as you wish insiue youi application. The impoitant thing to keep in minu is that when-
evei iOS ietuins a token oi a task iuentiliei to youi application with this methou, you
must call the endBackgroundTask: methou to maik the enu ol that task once you aie
linisheu iunning the task. Failing to uo so might cause iOS to teiminate youi applica-
tion.
Vhile in the Lackgiounu, applications aie not supposeu to Le lully lunctioning anu
piocessing heavy uata. They aie inueeu only supposeu to jinish a long-iunning task.
14.2 Completing a Long-Running Task in the Background | 635
www.it-ebooks.info
An example coulu Le an application that is calling a weL seivice API anu has not yet
ieceiveu the iesponse ol that API liom the seivei. Duiing this time, il the application
is sent to the Lackgiounu, the application can ieguest moie time until it ieceives a
iesponse liom the seivei. Once the iesponse is ieceiveu, the application must save its
state anu maik that task as linisheu Ly calling the endBackgroundTask: instance methou
ol UIApplication.
Let`s have a look at an example. I will stait Ly uelining a piopeity ol type UIBackground
TaskIdentifier in the app uelegate. Also, let`s ueline a timei ol type NSTimer, which we
will use to piint a message to the console winuow eveiy seconu when oui app is sent
to the Lackgiounu:
#import <UIKit/UIKit.h>
@interface Completing_a_Long_Running_Task_in_the_BackgroundAppDelegate
: UIResponder <UIApplicationDelegate>
@property (nonatomic, strong) UIWindow *window;
@property (nonatomic, unsafe_unretained)
UIBackgroundTaskIdentifier backgroundTaskIdentifier;
@property (nonatomic, strong) NSTimer *myTimer;
@end
Now let`s move on to cieating anu scheuuling oui timei when the app gets sent to the
Lackgiounu:
- (BOOL) isMultitaskingSupported{

BOOL result = NO;
if ([[UIDevice currentDevice]
respondsToSelector:@selector(isMultitaskingSupported)]){
result = [[UIDevice currentDevice] isMultitaskingSupported];
}
return result;

}
- (void) timerMethod:(NSTimer *)paramSender{

NSTimeInterval backgroundTimeRemaining =
[[UIApplication sharedApplication] backgroundTimeRemaining];

if (backgroundTimeRemaining == DBL_MAX){
NSLog(@"Background Time Remaining = Undetermined");
} else {
NSLog(@"Background Time Remaining = %.02f Seconds",
backgroundTimeRemaining);
}

}
636 | Chapter 14: Multitasking
www.it-ebooks.info
- (void)applicationDidEnterBackground:(UIApplication *)application{

if ([self isMultitaskingSupported] == NO){
return;
}

self.myTimer =
[NSTimer scheduledTimerWithTimeInterval:1.0f
target:self
selector:@selector(timerMethod:)
userInfo:nil
repeats:YES];
self.backgroundTaskIdentifier =
[application beginBackgroundTaskWithExpirationHandler:^(void) {
[self endBackgroundTask];
}];

}
You can see that in the completion hanulei loi oui Lackgiounu task, we aie calling the
endBackgroundTask methou ol oui app uelegate. This is a methou which we have wiitten
anu it looks like this:
- (void) endBackgroundTask{

dispatch_queue_t mainQueue = dispatch_get_main_queue();

__weak Completing_a_Long_Running_Task_in_the_BackgroundAppDelegate
*weakSelf = self;

dispatch_async(mainQueue, ^(void) {

Completing_a_Long_Running_Task_in_the_BackgroundAppDelegate
*strongSelf = weakSelf;

if (strongSelf != nil){
[strongSelf.myTimer invalidate];
[[UIApplication sharedApplication]
endBackgroundTask:self.backgroundTaskIdentifier];
strongSelf.backgroundTaskIdentifier = UIBackgroundTaskInvalid;
}

});

}
Theie aie a couple ol things we neeu to uo to clean up altei a long-iunning task:
1. Enu any thieaus oi timeis, whethei they aie lounuation timeis oi they aie cieateu
with GCD.
2. Enu the Lackgiounu task Ly calling the endBackgroundTask: methou ol UIApplica
tion.
14.2 Completing a Long-Running Task in the Background | 637
www.it-ebooks.info
3. Maik oui task as enueu Ly assigning the value ol UIBackgroundTaskInvalid to oui
task iuentilieis.
Last Lut not least, when oui app is Liought to the loiegiounu, il we still have oui
Lackgiounu task iunning, we neeu to ensuie that we get iiu ol it:
- (void)applicationWillEnterForeground:(UIApplication *)application{

if (self.backgroundTaskIdentifier != UIBackgroundTaskInvalid){
[self endBackgroundTask];
}

}
In oui example, whenevei the application is put into the Lackgiounu, we ask loi moie
time to linish a long-iunning task (in this case, loi instance, oui timei`s coue). In oui
time, we constantly ieau the value ol the backgroundTimeRemaining piopeity ol UIAppli
cation `s instance anu piint that value out to the console. In the beginBackgroundTask
WithExpirationHandler: instance methou ol UIApplication, we pioviueu the coue that
will Le executeu just Leloie oui application`s extia time to execute a long-iunning task
linishes (usually aLout 5 to 10 seconus Leloie the expiiation ol the task). In heie, we
can simply enu the task Ly calling the endBackgroundTask: instance methou ol UIAppli
cation.
Vhen an application is sent to the Lackgiounu anu the application has
ieguesteu moie execution time liom iOS, Leloie the execution time is
linisheu, the application coulu Le ieviveu anu Liought to the loiegiounu
Ly the usei again. Il you hau pieviously askeu loi a long-iunning task
to Le executeu in the Lackgiounu when the application was Leing sent
to the Lackgiounu, you must enu the long-iunning task using the end
BackgroundTask: instance methou ol UIApplication.
See Also
Recipe 1+.1
14.3 Receiving Local Notifications in the Background
Problem
You want to piesent an aleit to youi usei even when youi application is not iunning.
You want to cieate this aleit locally insiue youi application without using push notili-
cations.
638 | Chapter 14: Multitasking
www.it-ebooks.info
Solution
Instantiate an oLject ol type UILocalNotification anu scheuule it using the schedule
LocalNotification: instance methou ol UIApplication:
- (BOOL) localNotificationWithMessage:(NSString *)paramMessage
actionButtonTitle:(NSString *)paramActionButtonTitle
launchImage:(NSString *)paramLaunchImage
applicationBadge:(NSInteger)paramApplicationBadge
secondsFromNow:(NSTimeInterval)paramSecondsFromNow
userInfo:(NSDictionary *)paramUserInfo{

if ([paramMessage length] == 0){
return NO;
}

UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody = paramMessage;
notification.alertAction = paramActionButtonTitle;

if ([paramActionButtonTitle length]> 0){
/* Make sure we have the action button for the user to press
to open our application */
notification.hasAction = YES;
} else {
notification.hasAction = NO;
}

/* Here you have a chance to change the launch image of your application
when the notification's action is viewed by the user */
notification.alertLaunchImage = paramLaunchImage;

/* Change the badge number of the application once the notification is
presented to the user. Even if the user dismisses the notification,
the badge number of the application will change */
notification.applicationIconBadgeNumber = paramApplicationBadge;

/* This dictionary will get passed to your application
later if and when the user decides to view this notification */
notification.userInfo = paramUserInfo;

/* We need to get the system time zone so that the alert view
will adjust its fire date if the user's time zone changes */
NSTimeZone *timeZone = [NSTimeZone systemTimeZone];
notification.timeZone = timeZone;

/* Schedule the delivery of this notification x seconds from now */
NSDate *today = [NSDate date];

NSDate *fireDate = [today dateByAddingTimeInterval:paramSecondsFromNow];

NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];

NSUInteger dateComponents =
NSYearCalendarUnit |
14.3 Receiving Local Notifications in the Background | 639
www.it-ebooks.info
NSMonthCalendarUnit |
NSDayCalendarUnit |
NSHourCalendarUnit |
NSMinuteCalendarUnit |
NSSecondCalendarUnit;

NSDateComponents *components = [calendar components:dateComponents
fromDate:fireDate];

/* Here you have a chance to change these components. That's why we
retrieved the components of the date in the first place. */
fireDate = [calendar dateFromComponents:components];

/* Finally set the schedule date for this notification */
notification.fireDate = fireDate;

[[UIApplication sharedApplication] cancelAllLocalNotifications];

[[UIApplication sharedApplication] scheduleLocalNotification:notification];

return YES;

}
Discussion
A |oca| notijication is an aleit view (an oLject ol type UIAlertView) that gets piesenteu
to the usei il youi application is iunning in the Lackgiounu oi not iunning at all. You
can scheuule the ueliveiy ol a local notilication using the scheduleLocalNotifica
tion: instance methou ol UIApplication. The cancelAllLocalNotifications instance
methou cancels the ueliveiy ol all penuing local notilications.
You can ask iOS to uelivei a local notilication to the usei in the lutuie when youi
application is not even iunning. These notilications coulu also Le iecuiiingloi in-
stance, eveiy week at a ceitain time. Howevei, extia caie must Le taken when you aie
specilying the jirc datc loi youi notilications.
Foi instance, let`s say the time is now 13:00 in Lonuon, the time zone is GMT-0, anu
youi application is cuiiently iunning on a usei`s uevice. You want to Le aLle to uelivei
a notilication at 1+:00 to youi usei, even il youi application is not iunning at that time.
Now youi usei is on a plane at Lonuon`s Gatwick Aiipoit anu plans to lly to Stockholm
wheie the time zone is GMT-1. Il the llight takes 30 minutes, the usei will Le in
Stockholm at 13:30 GMT-0. Howevei, when he lanus, the iOS uevice will uetect the
change in the time zone anu will change the usei`s uevice time to 1+:30. Youi notili-
cation was supposeu to occui at 1+:00 (GMT-0), so as soon as the time zone is changeu,
iOS uetects that the notilication is uue to Le uisplayeu (30 minutes late, in lact, with
the new time zone) anu will uisplay youi notilication.
The issue is that youi notilication was supposeu to Le uisplayeu at 1+:00 GMT-0 oi
15:00 GMT-1, anu not 1+:30 GMT-1. To ueal with occasions such as this (which may
Le moie common than you think, with mouein tiavel haLits), when specilying a uate
640 | Chapter 14: Multitasking
www.it-ebooks.info
anu time loi youi local notilications to Le liieu, you shoulu also specily the time zone
ol the uate anu time you aie specilying.
The pievious coue uiu not incluue the aleit view that you`u neeu to wiite in oiuei to
have something to uisplay to the usei. Let`s go aheau anu auu that coue in oui appli-
cation anu see what happens on iPhone Simulatoi in uilleient scenaiios. Heie is
the .h lile ol oui application uelegate:
#import <UIKit/UIKit.h>
@interface Receiving_Local_Notifications_in_the_BackgroundAppDelegate
: UIResponder <UIApplicationDelegate>
@property (nonatomic, strong) UIWindow *window;
@end
Peilect! Now we will go to the application:didReceiveLocalNotification: methou anu
see il a local notilication has woken oui app up. Il not, we will scheuule one:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

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

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

id scheduledLocalNotification =
[launchOptions valueForKey:
UIApplicationLaunchOptionsLocalNotificationKey];

if (scheduledLocalNotification != nil){

/* We received a local notification while
our application wasn't running. You can now typecase the
ScheduledLocalNotification variable to UILocalNotification and
use it in your application */

NSString *message = @"Local Notification Woke Us Up";
[[[UIAlertView alloc] initWithTitle:@"Notification"
message:message
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil, nil] show];

} else {

NSString *message =@"A new instant message is available. \
Would you like to read this message?";

/* If a local notification didn't start our application,
then we start a new local notification */

14.3 Receiving Local Notifications in the Background | 641
www.it-ebooks.info
[self localNotificationWithMessage:message
actionButtonTitle:@"Yes"
launchImage:nil
applicationBadge:1
secondsFromNow:10.0f
userInfo:nil];

message = @"A new Local Notification is set up \
to be displayed 10 seconds from now";

[[[UIAlertView alloc] initWithTitle:@"Set Up"
message:message
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil, nil] show];

}

return YES;
}
Last Lut not least, we will hanule the application:didReceiveLocalNotification:
methou ol oui UIApplicationDelegate in oui app uelegate to make suie we uisplay a
message to the usei il she opens oui app Lecause ol a local notilication:
- (void) application:(UIApplication *)application
didReceiveLocalNotification:(UILocalNotification *)notification{

NSString *message = @"The Local Notification is delivered.";

[[[UIAlertView alloc] initWithTitle:@"Local Notification"
message:message
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil, nil] show];

}
Now let`s test the coue. Heie is Scenaiio 1: the usei has just installeu oui application
anu will launch it loi the liist time. Figuie 1+-1 shows what he will see.
The usei taps the OK Lutton anu stays in the application. Figuie 1+-2 uepicts the mes-
sage that will Le shown to the usei altei the notilication is ueliveieu to oui application.
Vhen the application is iunning oi even in the Lackgiounu (that is, it hasn`t Leen
teiminateu yet), iOS will call the application:didReceiveLocalNotification: methou
ol oui application uelegate to let oui application know a local notilication has Leen
ueliveieu to us. Il the usei is insiue the application, iOS will not uo anything special
anu will not uisplay a message. Howevei, iOS uoes uisplay a notilication message au-
tomatically when oui application is iunning in the Lackgiounu.
In Scenaiio 2, the usei opens oui application loi the liist time (as shown eailiei in
Figuie 1+-1) anu immeuiately altei piessing the OK Lutton, piesses the Home Lutton
642 | Chapter 14: Multitasking
www.it-ebooks.info
on his iOS uevice, senuing oui application to the Lackgiounu. Now when the notili-
cation is ueliveieu, oui usei will see a message similai to Figuie 1+-3.
Because we set the application Lauge numLei piopeity ol oui local notilication to 1
when we cieateu the notilication, oui application`s Lauge numLei is immeuiately set
to 1 when the notilication is ueliveieu. The usei uoesn`t have to close oi accept the
notilication loi the Lauge numLei to Le changeu. Now il the usei piesses the Yes Lutton,
iOS will launch the application associateu with this local notilication anu the usei will
Iigurc 11-1. An indication oj |oca| notijications bcing sct up
Iigurc 11-2. A |oca| notijication dc|ivcrcd whi|c our app is running (Sccnario 1)
14.3 Receiving Local Notifications in the Background | 643
www.it-ebooks.info
see a scieen similai to Figuie 1+-2. Please note that in this scenaiio, oui application has
not Leen teiminateu Lut sent to the Lackgiounu.
Scenaiio 3 is when oui application iuns loi the liist time (as shown eailiei in Fig-
uie 1+-1) anu the usei senus oui application to the Lackgiounu. Then the usei teimi-
nates oui application manually Ly uouLle-tapping the Home Lutton anu closing the
application with the Close Lutton that appeais on the application icon when the usei
piesses anu holus hei lingei on the icon loi a lew seconus, as shown in Figuie 1+-+.
Once oui application is teiminateu, the local notilication will Le uisplayeu to the usei
altei a lew seconus (10 seconus liom the time we scheuuleu the notilication). Once the
notilication is ueliveieu, the usei will see a scieen similai to Figuie 1+-3. Altei the usei
piesses the Yes Lutton, iOS will ielaunch oui application anu the usei will see a scieen
similai to Figuie 1+-5.
So, you can visually see how local notilications woik. Vhen oui application is iunning
in the loiegiounu oi the Lackgiounu, iOS will uelivei the local notilication thiough the
application:didReceiveLocalNotification: uelegate methou. Howevei, il oui appli-
cation has Leen teiminateu eithei Ly the usei oi Ly iOS, we will ieceive the local noti-
lication (that is, il the usei ueciues to view it) thiough the application`s didFinishLaun
chingWithOptions: methou. Ve can ietiieve the notilication using the UIApplication
LaunchOptionsLocalNotificationKey key ol the didFinishLaunchingWithOptions paiam-
etei.
A local notilication uoes not necessaiily have to Le an action notilication. Action no-
tilications have two Luttons. You can change the title ol one Lutton thiough the aler
tAction piopeity ol UILocalNotification. The othei Lutton is an OK Lutton that simply
Iigurc 11-3. A |oca| notijication dc|ivcrcd to an app in thc bac|ground (Sccnario 2)
644 | Chapter 14: Multitasking
www.it-ebooks.info
uismisses the aleit; you cannot change the title oi action. Il a notilication is not an
action notilication (when the hasAction piopeity ol UILocalNotification is set to NO),
the notilication will simply have an OK Lutton, anu piessing this Lutton will not ie-
launch youi application.
Iigurc 11-1. Thc uscr attcnpting to tcrninatc our app|ication bcjorc thc |oca| notijication is dc|ivcrcd
(Sccnario 3)
Iigurc 11-5. A |oca| notijication wa|ing up thc tcrninatcd app
14.3 Receiving Local Notifications in the Background | 645
www.it-ebooks.info
14.4 Playing Audio in the Background
Problem
You aie wiiting an application that plays auuio liles (such as a music playei) anu you
woulu like the auuio liles to Le playeu even il youi application is iunning in the Lack-
giounu.
Solution
Cieate a new aiiay key in youi application`s main .p|ist lile. Set the name ol the key to
UIBackgroundModes. Auu the value audio to this new key. Heie is an example ol the
contents ol a .p|ist lile with the aloiementioneu key anu value auueu:
<dict>
...
...
...
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
</array>
...
...
...
</dict>
Now you can use the AV Founuation to play auuio liles, anu youi auuio liles will Le
playeu even il youi application is in the Lackgiounu.
Discussion
In iOS, applications can ieguest that theii auuio liles continue playing even il the ap-
plication is sent to the Lackgiounu. AV Founuation`s AVAudioPlayer is an easy-to-use
auuio playei that we will use in this iecipe. Oui mission is to stait an auuio playei anu
play a simple song, anu while the song is playing, senu the application to the Lack-
giounu Ly piessing the Home Lutton. Il we have incluueu the UIBackgroundModes key
in oui application`s .p|ist lile, iOS will continue playing the music liom oui app`s auuio
playei, even in the Lackgiounu. Vhile in the Lackgiounu, we shoulu only play music
anu pioviue oui music playei with the uata that is necessaiy loi it to iun. Ve shoulu
not Le peiloiming any othei tasks, such as uisplaying new scieens.
Heie is the .h lile ol a simple app uelegate that staits an AVAudioPlayer:
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
@interface Playing_Audio_in_the_BackgroundAppDelegate
: UIResponder <UIApplicationDelegate, AVAudioPlayerDelegate>
@property (nonatomic, strong) UIWindow *window;
646 | Chapter 14: Multitasking
www.it-ebooks.info
@property (nonatomic, strong) AVAudioPlayer *audioPlayer;
@end
Vhen oui app opens, we will allocate anu initialize oui auuio playei, ieau the contents
ol a lile nameu MySong.mp4 into an instance ol NSData anu use that uata in the initiali-
zation piocess ol oui auuio playei:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

dispatch_queue_t dispatchQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_async(dispatchQueue, ^(void) {
NSError *audioSessionError = nil;
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
if ([audioSession setCategory:AVAudioSessionCategoryPlayback
error:&audioSessionError]){
NSLog(@"Successfully set the audio session.");
} else {
NSLog(@"Could not set the audio session");
}

NSBundle *mainBundle = [NSBundle mainBundle];

NSString *filePath = [mainBundle pathForResource:@"MySong"
ofType:@"mp3"];

NSData *fileData = [NSData dataWithContentsOfFile:filePath];

NSError *error = nil;

/* Start the audio player */
self.audioPlayer = [[AVAudioPlayer alloc] initWithData:fileData
error:&error];

/* Did we get an instance of AVAudioPlayer? */
if (self.audioPlayer != nil){
/* Set the delegate and start playing */

self.audioPlayer.delegate = self;

if ([self.audioPlayer prepareToPlay] &&
[self.audioPlayer play]){
NSLog(@"Successfully started playing..."); } else {
NSLog(@"Failed to play.");
}

} else {
/* Failed to instantiate AVAudioPlayer */
}
});

self.window = [[UIWindow alloc] initWithFrame:
14.4 Playing Audio in the Background | 647
www.it-ebooks.info
[[UIScreen mainScreen] bounds]];

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

return YES;
}
Please Leai in minu that playing auuio in the Lackgiounu might not
woik in iPhone Simulatoi. You neeu to test this iecipe on a ieal uevice.
On the simulatoi, chances aie that the auuio will stop playing once youi
application is sent to the Lackgiounu.
In this example coue, we aie using AV auuio sessions to silence music playLack liom
othei applications (such as the iPou application) Leloie staiting to play the auuio. Foi
moie inloimation aLout auuio sessions, please ielei to Recipe 10.5. Vhen in the Lack-
giounu, you aie not limiteu to playing only the cuiient auuio lile. Il the cuiiently playing
auuio lile (in the Lackgiounu) linishes playing, you can stait anothei instance ol
AVAudioPlayer anu play a completely new auuio lile. iOS will aujust the piocessing
ieguiieu loi this, Lut theie is no guaiantee that while in the Lackgiounu, youi appli-
cation will Le given peimission to allocate enough memoiy to accommouate the uata
ol the new sounu lile.
Anothei impoitant thing to keep in minu is that while youi application is iunning an
auuio lile in the Lackgiounu, the value ietuineu Ly the backgroundTimeRemaining piop-
eity ol UIApplication will not Le changeu. In othei woius, an application that ieguests
to play auuio liles in the Lackgiounu is not implicitly oi explicitly asking iOS loi extia
execution time.
14.5 Handling Location Changes in the Background
Problem
You aie wiiting an application whose main lunctionality is piocessing location changes,
using Coie Location. You want the application to ietiieve the iOS uevice location
changes even il the application is sent to the Lackgiounu.
Solution
Auu the location value to the UIBackgroundModes key ol youi main application .p|ist
lile, like so:
<dict>
...
...
...
<key>UIBackgroundModes</key>
648 | Chapter 14: Multitasking
www.it-ebooks.info
<array>
<string>location</string>
</array>
...
...
...
</dict>
Discussion
Vhen youi application is iunning in the loiegiounu, you can ieceive uelegate messages
liom an instance ol CLLocationManager telling you when iOS uetects that the uevice is
at a new location. Howevei, il youi application is sent to the Lackgiounu anu is no
longei active, the location uelegate messages will not Le ueliveieu noimally to youi
application. They will insteau Le ueliveieu in a Latch when youi application again
Lecomes the loiegiounu application.
Il you still want to Le aLle to ieceive changes in the location ol the usei`s uevice while
iunning in the Lackgiounu, you must auu the location value to the UIBack
groundModes key ol youi application`s main .p|ist lile, as shown in this iecipe`s Solu-
tion. Once in the Lackgiounu, youi application will continue to ieceive the changes in
the uevice`s location. Let`s test this in a simple app with just the app uelegate.
Vhat I intenu to uo in this app is to keep a Loolean value in the app uelegate, calleu
executingInBackground. Vhen the app goes to the Lackgiounu, I will set this value to
YES; when the app comes Lack to the loiegiounu, I will set this value to NO. Vhen we
get location upuates liom CoieLocation, we will check this llag. Il this llag is set to
YES, then we won`t uo any heavy calculations oi any UI upuate Lecause, well, oui app
is in the Lackgiounu, anu as a iesponsiLle piogiammei we shoulu not uo heavy pio-
cessing while oui app is in the Lackgiounu. Il oui app is in the loiegiounu, howevei,
we have all the uevice`s piocessing powei loi the noimal piocessing that we wish to
uo. Ve also will attempt to get the Lest location change accuiacy when oui app is in
the loiegiounu; when the app is sent to the Lackgiounu, we will Le suie to ask loi less
accuiacy in location upuates to ease the stiain on the location sensois. So let`s go aheau
anu ueline oui app uelegate:
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
@interface Handling_Location_Changes_in_the_BackgroundAppDelegate
: UIResponder <UIApplicationDelegate, CLLocationManagerDelegate>
@property (nonatomic, strong) UIWindow *window;
@property (nonatomic, strong) CLLocationManager *myLocationManager;
@property (nonatomic, unsafe_unretained, getter=isExecutingInBackground)
BOOL executingInBackground;
@end
Now let`s go aheau anu cieate anu stait oui location managei when oui app staits:
14.5 Handling Location Changes in the Background | 649
www.it-ebooks.info
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

self.myLocationManager = [[CLLocationManager alloc] init];
self.myLocationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.myLocationManager.delegate = self;
[self.myLocationManager startUpdatingLocation];

self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
You can see that we have set the uesiieu accuiacy ol oui location managei to a high
level. Howevei, when we go to the Lackgiounu, we want to lowei this accuiacy to give
iOS a Lit ol a iest:
- (void)applicationDidEnterBackground:(UIApplication *)application{
self.executingInBackground = YES;

/* Reduce the accuracy to ease the strain on
iOS while we are in the background */
self.myLocationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
}
Vhen oui app is awakeneu liom the Lackgiounu, we can change this accuiacy Lack
to a high level:
- (void)applicationWillEnterForeground:(UIApplication *)application{
self.executingInBackground = NO;

/* Now that our app is in the foreground again, let's increase the location
detection accuracy */
self.myLocationManager.desiredAccuracy = kCLLocationAccuracyBest;
}
Auuitionally, we woulu like to avoiu uoing any intense piocessing when we get a new
location liom the location managei while oui app is in the Lackgiounu, so we neeu to
hanule the locationManager:didUpdateToLocation:fromLocation: uelegate methou ol
oui location managei in this way:
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation{

if ([self isExecutingInBackground]){
/* We are in the background. Do not do any heavy processing */
} else {
/* We are in the foreground. Do any processing that you wish */
}

}
650 | Chapter 14: Multitasking
www.it-ebooks.info
The simple iule heie is that il we aie in the Lackgiounu, we shoulu Le using the smallest
amount ol memoiy anu piocessing powei to satisly oui application`s neeus. So, Ly
uecieasing the accuiacy ol the location managei while in the Lackgiounu, we aie ue-
cieasing the amount ol piocessing iOS has to uo to uelivei new locations to oui appli-
cation.
Depenuing on the veision ol iOS Simulatoi you aie testing youi appli-
cations with, as well as the settings ol youi netwoik connection anu
many othei lactois that allect this piocess, Lackgiounu location pio-
cessing might not woik loi you. Please test youi applications, incluuing
the souice coue in this iecipe, on a ieal uevice.
14.6 Saving and Loading the State of Multitasking iOS Apps
Problem
You want the state ol youi iOS app to Le saveu when it is sent to the Lackgiounu, anu
loi the same state to iesume when the application is Liought to the loiegiounu.
Solution
Use a comLination ol the UIApplicationDelegate piotocol`s messages sent to youi ap-
plication uelegate anu the notilications sent Ly iOS to pieseive the state ol youi mul-
titasking apps.
Discussion
Vhen an empty iOS application (an application with just one winuow anu no coue
wiitten loi it) is iun on an iOS uevice with suppoit loi multitasking loi the liist time
(not liom the Lackgiounu), the lollowing UIApplicationDelegate messages will Le sent
to youi app uelegate, in this oiuei:
1. application:didFinishLaunchingWithOptions:
2. applicationDidBecomeActive:
Il the usei piesses the Home Lutton on hei iOS uevice, youi app uelegate will ieceive
these messages, in this oiuei:
1. applicationWillResignActive:
2. applicationDidEnterBackground:
Once the application is in the Lackgiounu, the usei can piess the Home Lutton twice
anu select oui application liom the list ol Lackgiounu applications. (The way oui app
is Liought to the loiegiounu uoesn`t ieally mattei. Foi all we know, anothei app might
launch oui app thiough URI schemes that we can expose in oui app.) Once oui
14.6 Saving and Loading the State of Multitasking iOS Apps | 651
www.it-ebooks.info
application is Liought to the loiegiounu again, we will ieceive these messages in the
application uelegate, in this oiuei:
1. applicationWillEnterForeground:
2. applicationDidBecomeActive:
In auuition to these messages, we will also ieceive vaiious notilication messages liom
iOS when oui application is sent to the Lackgiounu oi Liought to the loiegiounu again.
To save anu loau Lack the state ol youi apps, you neeu to think caielully aLout the
tasks you neeu to pause when going into the Lackgiounu, anu then iesume when the
application is Liought to the loiegiounu. Let me give you an example. As will Le men-
tioneu in Recipe 1+.7, netwoik connections can Le easily iesumeu Ly the system itsell,
so we might not neeu to uo anything special il we`ie uownloauing a lile liom the net-
woik. Howevei, il you aie wiiting a game, loi instance, it is Lest to listen loi the noti-
lications iOS senus when youi application is Leing sent to the Lackgiounu, anu to act
accoiuingly. In such a scenaiio, you can simply put the game engine into a pauseu state.
You can also put the state ol the sounu engine into a pauseu state il necessaiy.
Altei an application is sent to the Lackgiounu, it has aLout 10 seconus to save any
unsaveu uata anu piepaie itsell to Le Liought to the loiegiounu at any moment Ly the
usei. You can optionally ask loi extia execution time il ieguiieu (luithei inloimation
aLout this is availaLle in Recipe 1+.2).
Let`s uemonstiate saving youi state with an example. Suppose we aie wiiting a game
loi iOS. Vhen oui game is sent to the Lackgiounu, we want to:
1. Put the game engine into a pauseu state.
2. Save the usei`s scoie to uisk.
3. Save the cuiient level`s uata to uisk. This incluues wheie the usei is in the level,
the physical aspects ol the level, the cameia position, anu so on.
Vhen the usei opens the application again, Liinging the application to the loiegiounu,
we want to:
1. Loau the usei`s scoie liom uisk.
2. Loau the level the usei was playing the last time liom uisk.
3. Resume the game engine.
Now let`s say oui app uelegate is oui game engine. Let`s ueline a lew methous in the
app uelegate`s heauei lile:
#import <UIKit/UIKit.h>
@interface Saving_and_Loading_the_State_of_Multitasking_iOS_AppsAppDelegate
: UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
652 | Chapter 14: Multitasking
www.it-ebooks.info
/* Saving the state of our app */
- (void) saveUserScore;
- (void) saveLevelToDisk;
- (void) pauseGameEngine;
/* Loading the state of our app */
- (void) loadUserScore;
- (void) loadLevelFromDisk;
- (void) resumeGameEngine;
@end
Ve will pioceeu to place stuL implementations ol these methous in the implementation
lile ol oui app uelegate:
#import "Saving_and_Loading_the_State_of_Multitasking_iOS_AppsAppDelegate.h"
@implementation
Saving_and_Loading_the_State_of_Multitasking_iOS_AppsAppDelegate
- (void) saveUserScore{
/* Save the user score here */
}
- (void) saveLevelToDisk{
/* Save the current level and the user's location on map to disk */
}
- (void) pauseGameEngine{
/* Pause the game engine here */
}
- (void) loadUserScore{
/* Load the user's location back to memory */
}
- (void) loadLevelFromDisk{
/* Load the user's previous location on the map */
}
- (void) resumeGameEngine{
/* Resume the game engine here */
}
...
Now we neeu to make suie that oui app is aLle to hanule inteiiuptions, such as in-
coming calls on an iPhone. On such occasions, oui app won`t Le sent to the Lack-
giounu, Lut will Lecome inactive. Vhen the usei linishes a phone call, loi instance,
iOS will Liing oui app to the active state. So when oui app Lecomes inactive, we neeu
to make suie we aie pausing oui game engine; when the app Lecomes active again, we
can iesume oui game engine. Ve uon`t neeu to save anything to the uisk when oui app
Lecomes inactive ieally (at least in this example), Lecause iOS will Liing oui app to its
pievious state once it Lecomes active again:
14.6 Saving and Loading the State of Multitasking iOS Apps | 653
www.it-ebooks.info
- (void)applicationWillResignActive:(UIApplication *)application{
[self pauseGameEngine];
}
- (void)applicationDidBecomeActive:(UIApplication *)application{
[self resumeGameEngine];
}
Anu now, simply, when oui app is sent to the Lackgiounu, we will save the state ol oui
game anu when oui app is Lack in the loiegiounu, we will loau the state Lack:
- (void)applicationDidEnterBackground:(UIApplication *)application{
[self saveUserScore];
[self saveLevelToDisk];
[self pauseGameEngine];
}
- (void)applicationWillEnterForeground:(UIApplication *)application{
[self loadUserScore];
[self loadLevelFromDisk];
[self resumeGameEngine];
}
Not eveiy application is a game. Howevei, you can use this technigue to loau anu save
the state ol youi application in the multitasking enviionment ol iOS.
See Also
Recipe 1+.2
14.7 Handling Network Connections in the Background
Problem
You aie using instances ol NSURLConnection to senu anu ieceive uata to anu liom a weL
seivei anu aie wonueiing how you can allow youi application to woik in the multi-
tasking enviionment ol iOS without connection lailuies.
Solution
Make suie you suppoit connection lailuies in the Llock oLjects that you suLmit to youi
connection oLjects.
Discussion
Foi applications that use NSURLConnection Lut uo not Loiiow extia time liom iOS when
they aie sent to the Lackgiounu, connection hanuling is tiuly simple. Let`s go thiough
an example to see how an asynchionous connection will act il the application is sent
to the Lackgiounu anu Liought to the loiegiounu again. Foi this, let`s senu an
654 | Chapter 14: Multitasking
www.it-ebooks.info
asynchionous connection ieguest to ietiieve the contents ol a URL (say, Apple`s home
page):
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

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){
/* Date did come back */
}
else if ([data length] == 0 &&
error != nil){
/* No data came back */
}
else if (error != nil){
/* Error happened. Make sure you handle this properly */
}

}];

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

self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
I auvise you to ieplace the Apple home page URL in this example with
the URL to a iathei laige lile on the Inteinet. The ieason is that il youi
app is uownloauing a laige lile, you will have moie time to play with the
app anu senu it to the Lackgiounu anu Liing it to the loiegiounu.
Vheieas, il you aie on a iathei last Inteinet connection anu you aie just
uownloauing Apple`s home page, chances aie that the connection is
going to ietiieve the uata loi you in a seconu oi two.
In the loiegiounu, oui application will continue uownloauing the lile. Vhile uown-
loauing, the usei can piess the Home Lutton anu senu the application to the Lack-
giounu. Vhat you will oLseive is tiue magic! iOS will automatically put the uownloau
piocess into a pauseu state loi you. Vhen the usei Liings youi application to the
14.7 Handling Network Connections in the Background | 655
www.it-ebooks.info
loiegiounu again, the uownloauing will iesume without you wiiting a single line ol
coue to hanule multitasking.
Now let`s see what happens with synchionous connections. Ve aie going to uownloau
a veiy Lig lile on the main thieau (a veiy Lau piacticeuo not uo this in a piouuction
application!) as soon as oui application launches:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

/* Replace this URL with the URL of a file that is rather big in size */
NSString *urlAsString = @"http://www.apple.com";
NSURL *url = [NSURL URLWithString:urlAsString];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
NSError *error = nil;

NSData *connectionData = [NSURLConnection sendSynchronousRequest:urlRequest
returningResponse:nil
error:&error];

if ([connectionData length] > 0 &&
error == nil){ }
else if ([connectionData length] == 0 &&
error == nil){

}
else if (error != nil){

}

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

self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Il you iun this application anu senu it to the Lackgiounu, you will notice that the
application`s GUI is sent to the Lackgiounu, Lut the application`s coie is nevei sent to
the Lackgiounu anu the appiopiiate uelegate messages applicationWillRe
signActive: anu applicationDidEnterBackground: will nevei Le ieceiveu. I have con-
uucteu this test on an iPhone.
The pioLlem with this appioach is that we aie consuming the main thieau`s time slice
Ly uownloauing liles synchionously. Ve can lix this Ly eithei uownloauing the liles
asynchionously on the main thieau, as mentioneu Leloie, oi uownloauing them syn-
chionously on sepaiate thieaus.
Take the pievious sample coue, loi example. Il we uownloau the same Lig lile syn-
chionously on a gloLal concuiient gueue, the connection will Le pauseu when the
application is sent to the Lackgiounu, anu will iesume once it is Liought to the loie-
giounu again:
656 | Chapter 14: Multitasking
www.it-ebooks.info
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

dispatch_queue_t dispatchQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_async(dispatchQueue, ^(void) {

/* Replace this URL with the URL of a file that is rather big in size */
NSString *urlAsString = @"http://www.apple.com";
NSURL *url = [NSURL URLWithString:urlAsString];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
NSError *error = nil;

NSData *connectionData = [NSURLConnection sendSynchronousRequest:urlRequest
returningResponse:nil
error:&error];

if ([connectionData length] > 0 &&
error == nil){

}
else if ([connectionData length] == 0 &&
error == nil){

}
else if (error != nil){

}
});

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

self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
See Also
Recipe 1+.2
14.8 Handling Notifications Delivered to a Waking App
Problem
Vhen youi application is Liought to the loiegiounu, you want to Le aLle to get noti-
lications aLout impoitant system changes, such as the usei`s locale changes.
14.8 Handling Notifications Delivered to a Waking App | 657
www.it-ebooks.info
Solution
Simply listen to one ol the many system notilications that iOS senus to waking appli-
cations. Some ol these notilications aie listeu heie:
NSCurrentLocaleDidChangeNotification
This notilication is ueliveieu to applications when the usei changes hei locale: loi
instance, il the usei switches his iOS uevice`s language liom English to Spanish in
the Settings page ol the uevice.
NSUserDefaultsDidChangeNotification
This notilication is liieu when the usei changes the application`s settings in the
Settings page ol the iOS uevice (il any settings aie pioviueu to the usei).
UIDeviceBatteryStateDidChangeNotification
This notilication gets sent whenevei the state ol the Latteiy ol the iOS uevice is
changeu. Foi instance, il the uevice is pluggeu into a computei when the applica-
tion is in the loiegiounu anu then unpluggeu when in the Lackgiounu, the appli-
cation will ieceive this notilication (il the application has iegisteieu loi this noti-
lication). The state can then Le ieau using the batteryState piopeity ol an instance
ol UIDevice.
UIDeviceProximityStateDidChangeNotification
This notilication gets sent whenevei the state ol the pioximity sensoi changes. The
last state is availaLle thiough the proximityState piopeity ol an instance ol UIDe
vice.
Discussion
Vhen youi application is in the Lackgiounu, a lot ol things coulu happen! Foi instance,
the usei might suuuenly change the locale ol hei iOS uevice thiough the Settings page
liom English to Spanish. Applications can iegistei themselves loi such notilications.
These notilications will Le coalesceu anu then ueliveieu to a waking application. Let
me explain what I mean Ly the teim coa|csccd. Suppose youi application is in the loie-
giounu anu you have iegisteieu loi UIDeviceOrientationDidChangeNotification noti-
lications. Now the usei piesses the Home Lutton anu youi application gets sent to the
Lackgiounu. The usei then iotates the uevice liom poitiait, to lanuscape iight, to poi-
tiait, anu then to lanuscape lelt. Vhen the usei Liings youi application to the loie-
giounu, you will ieceive only one notilication ol type UIDeviceOrientationDidChange
Notification. This is coalescing. All the othei oiientations that happeneu along the
way Leloie youi application opens aie not impoitant (since youi application isn`t on
the scieen) anu the system will not uelivei them to youi application. Howevei, the
system will uelivei you at least one notilication loi each aspect ol the system, such as
oiientation, anu you can then uetect the most up-to-uate oiientation ol the uevice.
Heie is the implementation ol a simple view contiollei that takes auvantage ol this
technigue to ueteimine changes in oiientation:
658 | Chapter 14: Multitasking
www.it-ebooks.info
#import "Handling_Notifications_Delivered_to_a_Waking_AppViewController.h"
@implementation Handling_Notifications_Delivered_to_a_Waking_AppViewController
- (void) orientationChanged:(NSNotification *)paramNotification{
NSLog(@"Orientation Changed");
}
- (void)viewDidLoad{
[super viewDidLoad];

[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(orientationChanged:)
name:UIDeviceOrientationDidChangeNotification
object:nil];

}
- (void)viewDidUnload{
[super viewDidUnload];

[[NSNotificationCenter defaultCenter] removeObserver:self];

}
- (BOOL)shouldAutorotateToInterfaceOrientation
:(UIInterfaceOrientation)interfaceOrientation{
return YES;
}
@end
Run the application on the uevice now. Altei the view contiollei is uisplayeu on the
scieen, piess the Home Lutton to senu the application to the Lackgiounu. Now tiy
changing the oiientation ol the uevice a couple ol times, anu then ielaunch the appli-
cation. OLseive the iesults, anu you will see that initially when youi application opens,
at most one notilication will Le sent to the orientationChanged: methou. You might
get a seconu call, though, il youi view hieiaichy suppoits oiientation changes.
14.9 Responding to Changes in App Settings
Problem
Youi application exposes a settings Lunule to the usei. You want to get notilieu ol the
changes the usei has maue to youi application`s settings (while the application was in
the Lackgiounu) as soon as youi application is Liought to the loiegiounu.
Solution
Registei loi the NSUserDefaultsDidChangeNotification notilication.
14.9 Responding to Changes in App Settings | 659
www.it-ebooks.info
Discussion
Applications wiitten loi iOS can expose a Lunule lile loi theii settings. These settings
will Le availaLle to useis thiough the Settings application on theii uevice. To get a Lettei
unueistanuing ol how this woiks, let`s cieate a settings Lunule:
1. In Xcoue, choose File New File.
2. Make suie the iOS categoiy is selecteu on the lelt.
3. Choose the Resouices suLcategoiy.
+. Choose Settings Bunule as the lile type anu click Next.
5. Set the lilename as Scttings.bund|c.
6. Click Save.
Now you have a lile in Xcoue nameu Scttings.bund|c. Leave this lile as it is, without
mouilying it. Put the coue in this iecipe`s Solution into youi ioot view contiollei anu
iun the application. Piess the Home Lutton on the uevice anu go to the uevice`s Settings
application. Il you have nameu youi application loo you will see Foo in the Settings
application, as shown in Figuie 1+-6 (the name ol the sample application I cieateu is
Responuing to Changes in App Settings).
Iigurc 11-. Our Scttings.bund|c disp|aycd in thc Scttings app on iOS Sinu|ator
Tap on youi application`s name to see the settings youi application exposes to the usei,
as shown in Figuie 1+-7.
Let`s go aheau anu stait listening loi NSUserDefaultsDidChangeNotification notilica-
tions in oui app uelegate. Vhen oui app teiminates, oLviously, we will iemove oui app
uelegate liom the notilication chain:
660 | Chapter 14: Multitasking
www.it-ebooks.info
#import "Responding_to_Changes_in_App_SettingsAppDelegate.h"
@implementation Responding_to_Changes_in_App_SettingsAppDelegate
- (void) settingsChanged:(NSNotification *)paramNotification{
NSLog(@"Settings changed");
NSLog(@"Notification Object = %@", [paramNotification object]);

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

[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(settingsChanged:)
name:NSUserDefaultsDidChangeNotification
object:nil];

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

self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillTerminate:(UIApplication *)application{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
@end
Now tiy to change some ol these settings while youi application is iunning in the
Lackgiounu. Altei you aie uone, Liing the application to the loiegiounu anu you will
Iigurc 11-7. Thc contcnts oj thc dcjau|t Scttings.bund|c
14.9 Responding to Changes in App Settings | 661
www.it-ebooks.info
see that only one NSUserDefaultsDidChangeNotification notilication will Le ueliveieu
to youi application. The oLject attacheu to this notilication will Le ol type NSUser
Defaults anu will contain youi application`s settings user defaults.
14.10 Opting Out of Multitasking
Problem
You uo not want youi application to paiticipate in multitasking.
Solution
Auu the UIApplicationExitsOnSuspend key to youi application`s main .p|ist lile anu set
the value to true:
<dict>
...
...
...
<key>UIApplicationExitsOnSuspend</key>
<true/>
...
...
...
</dict>
Discussion
In some ciicumstances, you might ieguiie youi iOS applications not to Le multitasking
(although I stiongly encouiage you to uevelop youi applications to Le multitasking-
awaie). In such cases, you can auu the UIApplicationExitsOnSuspend key to youi ap-
plication`s main .p|ist lile. Devices on the latest iOS veisions that suppoit multitasking
unueistanu this value anu the OS will teiminate an application with this key set to
true in the application`s .p|ist lile. On eailiei iOS veisions without suppoit loi multi-
tasking, this value will have no meaning to the opeiating system anu will Le ignoieu.
Vhen such an application iuns on the latest iOS, the lollowing application uelegate
messages will Le posteu to youi application:
1. application:didFinishLaunchingWithOptions:
2. applicationDidBecomeActive:
Il the usei piesses the Home Lutton on the uevice, the lollowing messages will Le sent
to youi application uelegate:
1. applicationDidEnterBackground:
2. applicationWillTerminate:
662 | Chapter 14: Multitasking
www.it-ebooks.info
CHAPTER 15
Core Data
15.0 Introduction
Coie Data is a poweilul liamewoik on the iOS SDK that allows piogiammeis to stoie
anu manage uata in an oLject-oiienteu way. Tiauitionally, piogiammeis hau to stoie
theii uata on uisk using the aichiving capaLilities ol OLjective-C, oi wiite theii uata to
liles anu manage them manually. Vith the intiouuction ol Coie Data, piogiammeis
can simply inteiact with its oLject-oiienteu inteilace to manage theii uata elliciently.
In this chaptei, you will leain how to use Coie Data to cieate the mouel ol youi appli-
cation (in the Mouel-View-Contiollei soltwaie aichitectuie).
Coie Data inteiacts with a peisistent stoie at a lowei level that is not visiLle to the
piogiammei. iOS ueciues how the low-level uata management is implementeu. All the
piogiammei must know is the high-level API she is pioviueu with. But unueistanuing
the stiuctuie ol Coie Data anu how it woiks inteinally is veiy impoitant. Let`s cieate
a Coie Data application to unueistanu this a Lit Lettei.
Coie Data in an iOS application neeus a Lit ol setting up. Foitunately, with Xcoue, this
piocess is veiy easy. You can simply cieate a Coie Data application anu leave the iest
up to Xcoue.
Follow these instiuctions to cieate a pioject in Xcoue that uses Coie Data:
1. Open Xcoue, il it`s not open alieauy.
2. Fiom the File menu, select New New Pioject...
3. In the New Pioject uialog, make suie iOS is the main categoiy on the lelt anu
Application is the suLcategoiy unuei it. Then on the iighthanu siue ol the uialog,
choose Empty Application anu piess Next, as shown in Figuie 15-1.
+. Now, loi youi piouuct name, choose Intiouuction to Coie Data anu make suie
the Usei Coie Data checkLox is checkeu, as shown in Figuie 15-2. Once uone,
piess the Next Lutton.
663
www.it-ebooks.info
Iigurc 15-1. Crcating an cnpty app|ication jor Corc Data
Iigurc 15-2. Sctting up a projcct to usc Corc Data
5. Now you must choose wheie to save youi pioject. Once you aie uone selecting the
uestination loluei, piess the Cieate Lutton, as shown in Figuie 15-3.
664 | Chapter 15: Core Data
www.it-ebooks.info
Iigurc 15-3. Sc|ccting whcrc to savc our Corc Data projcct
Now in Xcoue, linu the lile nameu |ntroduction_to_Corc_DataAppDc|cgatc.h. This is
the shaieu uelegate ol oui application, since oui application is univeisal. Both the iPau
anu iPhone application uelegates will use this uelegate as theii supeiclass. Il you have
a look at the contents ol this lile, you will linu that thiee piopeities weie auueu to the
ueclaiation ol the application uelegate loi you. These piopeities aie:
managedObjectContext (ol type NSManagedObjectContext)
managedObjectModel (ol type NSManagedObjectModel)
persistentStoreCoordinator (ol type NSPersistentStoreCoordinator)
I know this is new anu pioLaLly conlusing to you, Lut Ly compaiing these new concepts
to existing uataLase concepts, it will Lecome easiei loi you to uigest:
Pcrsistcnt storc coordinator
This is the Liiuge oi the connection Letween the physical lile that stoies oui uata
anu oui application. This Liiuge will Le iesponsiLle loi managing uilleient oLject
contexts.
Managcd objcct nodc|
This is the same concept as a schema in a uataLase. This coulu iepiesent the taLles
in a uataLase oi the uilleient types ol manageu oLjects we can cieate in oui uata-
Lase.
15.0 Introduction | 665
www.it-ebooks.info
Managcd objcct contcxt
This is the Liiuge Letween the piogiammei anu the manageu oLject mouel. Using
the manageu oLject context, you can inseit a new iow into a new taLle, ieau iows
liom a ceitain taLle, anu so on. (Actually, Coie Data uoesn`t use the concept ol a
taLle, Lut I`m using the teim heie Lecause it`s lamiliai anu will help you unuei-
stanu how Coie Data woiks.)
Managcd objcct
This is similai to a iow in a taLle. Ve inseit manageu oLjects into the manageu
oLject context anu save the context. This way, we cieate a new iow in a taLle in
oui uataLase.
In Recipe 15.1, you will leain how to cieate a Coie Data mouel using Xcoue. This is
the liist step towaiu cieating a uataLase schcna.
15.1 Creating a Core Data Model with Xcode
Problem
You want to visually uesign the uata mouel ol youi iOS application using Xcoue.
Solution
Follow the instiuctions in this chaptei`s Intiouuction to cieate a Coie Data pioject.
Then linu the lile with the extension ol xcdatanodc| in youi application Lunule in
Xcoue anu click on it to open the visual uata euitoi, as shown in Figuie 15-+.
Iigurc 15-1. \isua| data cditor in Xcodc
666 | Chapter 15: Core Data
www.it-ebooks.info
Discussion
Xcoue`s visual uata euitoi is a lantastic tool that allows piogiammeis to uesign the uata
mouel ol theii applications with ease. Theie aie two impoitant uelinitions you neeu to
leain Leloie you can woik with this tool:
Entity
Coiiesponus to a taLle in a uataLase.
Attributc
Coiiesponus to a column in a taLle.
Entities will latei Lecome oLjects (manageu oLjects) when we geneiate the coue Laseu
on oui oLject mouel. This is explaineu in Recipe 15.2. Foi now, in this iecipe, we will
concentiate on cieating the uata mouel in this tool.
In the euitoi, linu the - Lutton at the Lottom. Piess anu holu youi mouse Lutton on
this Lutton anu then select Auu Entity liom the menu that will appeai, as shown in
Figuie 15-5.
Iigurc 15-5. Adding a ncw cntity to our data nodc|
Youi new entity will Le cieateu anu will Le in a state wheie you can immeuiately iename
it altei cieation. Change the name ol this entity to Peison, as shown in Figuie 15-6.
Select the Person entity, then select the - Lutton in the AttiiLutes pane (see Fig-
uie 15-7) anu cieate the lollowing thiee attiiLutes loi it (the iesults aie shown in
Figuie 15-S:
firstName (ol type String).
lastName (ol type String).
age (ol type Integer 32).
15.1 Creating a Core Data Model with Xcode | 667
www.it-ebooks.info
Iigurc 15-7. Thc Attributcs box
Iigurc 15-8. Wc havc addcd thrcc attributcs to thc Pcrson cntity
Vhile you aie in the uata mouel euitoi, liom the View menu in Xcoue, choose Utilit-
ies Show Utilities. The utilities pane will open on the iighthanu siue ol Xcoue. On
top, choose the Data Mouel Inspectoi Lutton anu make suie that you have clickeu on
the Peison entity that we just cieateu. At this point, the Data Mouel inspectoi will Le
populateu with items ielevant to the Peison entity, as shown in Figuie 15-9.
Now click on the firstName, lastName, anu the age attiiLutes ol the Peison entity. Make
suie the firstName anu the lastName attiiLutes aie not optiona| Ly unticking the
Optional checkLox anu make suie the age lielu is optional Ly ticking the Optional
checkLox.
Now youi uata mouel in the euitoi shoulu look similai to that uepicteu in Figuie 15-10.
Iigurc 15-. Changing thc nanc oj thc ncw cntity to Pcrson
668 | Chapter 15: Core Data
www.it-ebooks.info
Iigurc 15-10. Thc Pcrson Entity with thrcc attributcs
OK, we aie uone cieating the mouel. Choose File Save to make suie youi changes
aie saveu. To leain how to geneiate coue Laseu on the manageu oLject you just cieateu,
ielei to Recipe 15.2.
Iigurc 15-9. Thc Data Modc| |nspcctor shown on thc right sidc oj thc Xcodc window
15.1 Creating a Core Data Model with Xcode | 669
www.it-ebooks.info
15.2 Generating Class Files for Core Data Entities
Problem
You lolloweu the instiuctions inRecipe 15.1 anu you want to know how to cieate coue
Laseu on youi oLject mouel.
Solution
Follow these steps:
1. In Xcoue, linu the lile with the xcdatanodc| extension that was cieateu loi youi
application when you cieateu the application itsell in Xcoue. Click on the lile, anu
you shoulu see the euitoi on the iighthanu siue ol the Xcoue winuow.
2. Select the Peison entity that we cieateu eailiei (see Recipe 15.1).
3. Select File New File in Xcoue.
+. In the New File uialog, make suie you have selecteu iOS as the main categoiy anu
Coie Data as the suLcategoiy. Then choose the NSManagedObject subclass item
liom the iighthanu siue ol the uialog anu piess Next, as shown in Figuie 15-11.
Iigurc 15-11. Crcating a nanagcd objcct subc|ass in Xcodc
5. Now choose wheie to save youi liles in youi pioject anu piess Cieate, as shown in
Figuie 15-12.
670 | Chapter 15: Core Data
www.it-ebooks.info
Iigurc 15-12. Sc|ccting thc dcstination jo|dcr jor thc nanagcd objcct
Now you will see two new liles in youi pioject, calleu Pcrson.h anu Pcrson.n. Open
the contents ol the Pcrson.h lile. It will look like the lollowing:
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@interface Person : NSManagedObject {
@private
}
@property (nonatomic, retain) NSString * firstName;
@property (nonatomic, retain) NSString * lastName;
@property (nonatomic, retain) NSNumber * age;
@end
The Pcrson.n lile is implementeu loi you in this way:
#import "Person.h"
@implementation Person
@dynamic firstName;
@dynamic lastName;
@dynamic age;
@end
15.2 Generating Class Files for Core Data Entities | 671
www.it-ebooks.info
Theie you go! Ve tuineu oui manageu oLject into a ieal uelinition anu implementation.
In Recipe 15.3, you will leain how to instantiate anu save a manageu oLject ol type
Person into the manageu oLject context ol youi application.
Discussion
Vhen you cieate youi uata mouel using the euitoi in Xcoue, you aie cieating the uata
ielationships, entities, attiiLutes, anu so loith. Howevei, to Le aLle to use youi mouel
in youi app, you must geneiate the coue loi youi mouel. Il you view the .h anu .n liles
loi youi entities, you will iealize that all the attiiLutes aie assigneu uynamically. You
can even see the @dynamic uiiective in the .n lile ol youi entities to tell the compilei
that you will lullill the ieguest ol each attiiLute at iuntime using uynamic methou
iesolution.
None ol the coue that Coie Data iuns on youi entities is visiLle to you, anu theie is no
neeu loi it to Le visiLle to the piogiammei in the liist place. All you have to know is
that a Person entity has thiee attiiLutes nameu firstName, lastName, anu age. You can
assign values to these attiiLutes (il they aie ieau/wiite piopeities) anu you can save to
anu loau them liom the context, as we`ll see in Recipe 15.3.
15.3 Creating and Saving Data Using Core Data
Problem
You have alieauy cieateu a manageu oLject anu you want to instantiate it anu inseit
that instance into youi app`s Coie Data context.
Solution
Follow the instiuctions in Recipe 15.1 anu Recipe 15.2. Now you can use the insert
NewObjectForEntityForName:inManagedObjectContext: class methou ol NSEntityDe
scription to cieate a new oLject ol a type specilieu Ly the liist paiametei ol this methou.
Once the new entity (the manageu oLject) is cieateu, you can mouily it Ly changing its
piopeities. Altei you aie uone, save youi manageu oLject context using the save: in-
stance methou ol the manageu oLject context.
I`ll assume that you have cieateu a univeisal application in Xcoue with the name Cie-
ating anu Saving Data Using Coie Data; now, lollow these steps to inseit a new manageu
oLject into the context:
1. Finu the lile nameu Crcating_and_Saving_Data_Using_Corc_DataAppDc|cgatc.n.
2. Impoit the Pcrson.h lile into the app uelegate`s implementation lile:
672 | Chapter 15: Core Data
www.it-ebooks.info
Person is the entity we cieateu in Recipe 15.1.
#import "Creating_and_Saving_Data_Using_Core_DataAppDelegate.h"
#import "Person.h"
@implementation Creating_and_Saving_Data_Using_Core_DataAppDelegate
@synthesize managedObjectContext = _managedObjectContext;
@synthesize managedObjectModel = _managedObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
...
3. In the application:didFinishLaunchingWithOptions: methou ol youi shaieu ap-
plication uelegate, wiite this coue:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
Person *newPerson = [NSEntityDescription
insertNewObjectForEntityForName:@"Person"
inManagedObjectContext:self.managedObjectContext];
if (newPerson != nil){
newPerson.firstName = @"Anthony";
newPerson.lastName = @"Robbins";
newPerson.age = [NSNumber numberWithUnsignedInteger:51];
NSError *savingError = nil;
if ([self.managedObjectContext save:&savingError]){
NSLog(@"Successfully saved the context.");
} else {
NSLog(@"Failed to save the context. Error = %@", savingError);
}
} else {
NSLog(@"Failed to create the new person.");
}
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
15.3 Creating and Saving Data Using Core Data | 673
www.it-ebooks.info
Discussion
Pievious iecipes showeu how to cieate entities anu geneiate coue Laseu on them using
the euitoi in Xcoue. The next thing we neeu to uo is stait using those entities anu
instantiate them. Foi this, we use NSEntityDescription anu call its insertNewObjectFor
EntityForName:inManagedObjectContext: class methou. This will look up the given en-
tity (specilieu Ly its name as NSString) in the given manageu oLject context. Il the entity
is lounu, the methou will ietuin a new instance ol that entity. This is similai to cieating
a new iow (manageu oLject) in a taLle (entity) in a uataLase (manageu oLject context).
Attempting to inseit an unknown entity into a manageu oLject context
will iaise an exception ol type NSInternalInconsistencyException.
Altei inseiting a new entity into the context, we must save the context. This will llush
all the unsaveu uata ol the context to the peisistent stoie. Ve can uo this using the
save: instance methou ol oui manageu oLject context. Il the BOOL ietuin value ol this
methou is YES, we can Le suie that oui context is saveu. In Recipe 15.+, you will leain
how to ieau the uata Lack to memoiy.
15.4 Reading Data from Core Data
Problem
You want to Le aLle to ieau the contents ol youi entities (taLles) using Coie Data.
Solution
Use an instance ol NSFetchRequest:
- (BOOL) createNewPersonWithFirstName:(NSString *)paramFirstName
lastName:(NSString *)paramLastName
age:(NSUInteger)paramAge{
BOOL result = NO;
if ([paramFirstName length] == 0 ||
[paramLastName length] == 0){
NSLog(@"First and Last names are mandatory.");
return NO;
}
Person *newPerson = [NSEntityDescription
insertNewObjectForEntityForName:@"Person"
inManagedObjectContext:self.managedObjectContext];
if (newPerson == nil){
674 | Chapter 15: Core Data
www.it-ebooks.info
NSLog(@"Failed to create the new person.");
return NO;
}
newPerson.firstName = paramFirstName;
newPerson.lastName = paramLastName;
newPerson.age = [NSNumber numberWithUnsignedInteger:paramAge];
NSError *savingError = nil;
if ([self.managedObjectContext save:&savingError]){
return YES;
} else {
NSLog(@"Failed to save the new person. Error = %@", savingError);
}
return result;
}
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
[self createNewPersonWithFirstName:@"Anthony"
lastName:@"Robbins"
age:51];
[self createNewPersonWithFirstName:@"Richard"
lastName:@"Branson"
age:61];
/* Create the fetch request first */
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
/* Here is the entity whose contents we want to read */
NSEntityDescription *entity =
[NSEntityDescription
entityForName:@"Person"
inManagedObjectContext:self.managedObjectContext];
/* Tell the request that we want to read the
contents of the Person entity */
[fetchRequest setEntity:entity];
NSError *requestError = nil;
/* And execute the fetch request on the context */
NSArray *persons =
[self.managedObjectContext executeFetchRequest:fetchRequest
error:&requestError];
/* Make sure we get the array */
if ([persons count] > 0){
/* Go through the persons array one by one */
15.4 Reading Data from Core Data | 675
www.it-ebooks.info
NSUInteger counter = 1;
for (Person *thisPerson in persons){
NSLog(@"Person %lu First Name = %@",
(unsigned long)counter,
thisPerson.firstName);
NSLog(@"Person %lu Last Name = %@",
(unsigned long)counter,
thisPerson.lastName);
NSLog(@"Person %lu Age = %ld",
(unsigned long)counter,
(unsigned long)[thisPerson.age unsignedIntegerValue]);
counter++;
}
} else {
NSLog(@"Could not find any Person entities in the context.");
}
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
In this coue, we aie using a countei vaiiaLle insiue a last-enumeiation
Llock. The ieason we neeu the countei in this last-enumeiation is loi
use in NSLog ueLugging messages that we aie piinting in oiuei to see the
inuex ol the cuiient enumeiateu peison oLject in the aiiay. An alteina-
tive to this solution woulu have Leen to use a classic loi-loop with a
countei vaiiaLle.
Foi moie inloimation aLout letch ieguests, please ielei to this iecipe`s Discussion.
Discussion
Foi those ol you who aie lamiliai with uataLase teiminology, a jctch rcqucst is similai
to a SELECT statement. In the SELECT statement, you specily which iows, with which
conuitions, have to Le ietuineu liom which taLle. Vith a letch ieguest, we uo the same
thing. Ve specily the entity (taLle) anu the manageu oLject context (the uataLase layei).
Ve can also specily soit uesciiptois loi soiting the uata we ieau. But liist we`ll locus
on ieauing the uata to make it simplei.
To Le aLle to ieau the contents ol the Person entity (we cieateu this entity in
Recipe 15.1 anu tuineu it into coue in Recipe 15.2), we must liist ask the NSEntity
676 | Chapter 15: Core Data
www.it-ebooks.info
Description class to seaich in oui manageu oLject context loi an entity nameu Per
son. Once it is lounu, we will tell oui letch ieguest what entity we want to ieau liom.
Altei this, all that`s lelt to uo is to execute the letch ieguest as we saw in this iecipe`s
Solution.
The ietuin value ol the executeFetchRequest:error: instance methou ol NSMan
agedObjectContext is eithei nil (in case ol an eiioi) oi an aiiay ol Person manageu
oLjects. Il no iesults aie lounu loi the given entity, the ietuineu aiiay will Le empty.
See Also
Recipe 15.1; Recipe 15.2
15.5 Deleting Data from Core Data
Problem
You want to uelete a manageu oLject (a iow in a taLle) liom a manageu oLject context
(youi uataLase).
Solution
Use the deleteObject: instance methou ol NSManagedObjectContext:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
[self createNewPersonWithFirstName:@"Anthony"
lastName:@"Robbins"
age:51];
[self createNewPersonWithFirstName:@"Richard"
lastName:@"Branson"
age:61];
/* Create the fetch request first */
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
/* Here is the entity whose contents we want to read */
NSEntityDescription *entity =
[NSEntityDescription entityForName:@"Person"
inManagedObjectContext:self.managedObjectContext];
NSSortDescriptor *ageSort =
[[NSSortDescriptor alloc] initWithKey:@"age"
ascending:YES];
/* Tell the request that we want to read the
contents of the Person entity */
[fetchRequest setEntity:entity];
NSError *requestError = nil;
15.5 Deleting Data from Core Data | 677
www.it-ebooks.info
/* And execute the fetch request on the context */
NSArray *persons =
[self.managedObjectContext executeFetchRequest:fetchRequest
error:&requestError];
/* Make sure we get the array */
if ([persons count] > 0){
/* Delete the last person in the array */
Person *lastPerson = [persons lastObject];
[self.managedObjectContext deleteObject:lastPerson];
NSError *savingError = nil;
if ([self.managedObjectContext save:&savingError]){
NSLog(@"Successfully deleted the last person in the array.");
} else {
NSLog(@"Failed to delete the last person in the array.");
}
} else {
NSLog(@"Could not find any Person entities in the context.");
}
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
In this example coue, we aie using the createNewPersonWithFirst
Name:lastName:age: methou that we coueu in Recipe 15.+.
Discussion
You can uelete manageu oLjects (iecoius ol a taLle in a uataLase) using the deleteOb
ject: instance methou ol NSManagedObjectContext.
This methou uoesn`t ietuin an eiioi to you in any ol its paiameteis, noi uoes it ietuin
a BOOL value, so you ieally have no goou way ol knowing whethei an oLject was suc-
cesslully ueleteu using the manageu oLject context. The Lest way to ueteimine this to
use that manageu oLject`s isDeleted methou.
Vith this inloimation, let`s change the coue that we wiote pieviously in this iecipe:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
[self createNewPersonWithFirstName:@"Anthony"
678 | Chapter 15: Core Data
www.it-ebooks.info
lastName:@"Robbins"
age:51];
[self createNewPersonWithFirstName:@"Richard"
lastName:@"Branson"
age:61];
/* Create the fetch request first */
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
/* Here is the entity whose contents we want to read */
NSEntityDescription *entity =
[NSEntityDescription entityForName:@"Person"
inManagedObjectContext:self.managedObjectContext];
/* Tell the request that we want to read the
contents of the Person entity */
[fetchRequest setEntity:entity];
NSError *requestError = nil;
/* And execute the fetch request on the context */
NSArray *persons =
[self.managedObjectContext executeFetchRequest:fetchRequest
error:&requestError];
/* Make sure we get the array */
if ([persons count] > 0){
/* Delete the last person in the array */
Person *lastPerson = [persons lastObject];
[self.managedObjectContext deleteObject:lastPerson];
if ([lastPerson isDeleted]){
NSLog(@"Successfully deleted the last person...");
NSError *savingError = nil;
if ([self.managedObjectContext save:&savingError]){
NSLog(@"Successfully saved the context.");
} else {
NSLog(@"Failed to save the context.");
}
} else {
NSLog(@"Failed to delete the last person.");
}
} else {
NSLog(@"Could not find any Person entities in the context.");
}
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
15.5 Deleting Data from Core Data | 679
www.it-ebooks.info
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Once you iun the app, you will get iesults similai to this, piinteu to the console winuow:
Successfully deleted the last person...
Successfully saved the context.
15.6 Sorting Data in Core Data
Problem
You want to soit the manageu oLjects (iecoius) that you letch liom a manageu oLject
context (uataLase).
Solution
Cieate instances ol NSSortDescriptor loi each attiiLute (column, in the uataLase woilu)
ol an entity that has to Le soiteu. Auu the soit uesciiptois to an aiiay anu assign the
aiiay to an instance ol NSFetchRequest using the setSortDescriptors: instance methou.
In this example coue, Sorting_Data_in_Core_DataAppDelegate is the class that iepie-
sents the app uelegate in a univeisal app. To unueistanu how the Person entity is cie-
ateu, please ielei to Recipes 15.1 anu 15.2:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
[self createNewPersonWithFirstName:@"Richard"
lastName:@"Branson"
age:61];
[self createNewPersonWithFirstName:@"Anthony"
lastName:@"Robbins"
age:51];
/* Create the fetch request first */
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
/* Here is the entity whose contents we want to read */
NSEntityDescription *entity =
[NSEntityDescription entityForName:@"Person"
inManagedObjectContext:self.managedObjectContext];
NSSortDescriptor *ageSort =
[[NSSortDescriptor alloc] initWithKey:@"age"
ascending:YES];
NSSortDescriptor *firstNameSort =
[[NSSortDescriptor alloc] initWithKey:@"firstName"
ascending:YES];
680 | Chapter 15: Core Data
www.it-ebooks.info
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:
ageSort,
firstNameSort, nil];
fetchRequest.sortDescriptors = sortDescriptors;
/* Tell the request that we want to read the
contents of the Person entity */
[fetchRequest setEntity:entity];
NSError *requestError = nil;
/* And execute the fetch request on the context */
NSArray *persons =
[self.managedObjectContext executeFetchRequest:fetchRequest
error:&requestError];
for (Person *person in persons){
NSLog(@"First Name = %@", person.firstName);
NSLog(@"Last Name = %@", person.lastName);
NSLog(@"Age = %lu", (unsigned long)[person.age unsignedIntegerValue]);
}
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Discussion
An instance ol NSFetchRequest can caiiy with itsell an aiiay ol NSSortDescriptor in-
stances. Each soit uesciiptoi uelines the attiiLute (column) on the cuiient entity that
has to Le soiteu anu whethei the soiting has to Le ascenuing oi uescenuing. Foi in-
stance, the Person entity we cieateu in Recipe 15.1 has firstName, lastName, anu age
attiiLutes. Il we want to ieau all the peisons in a manageu oLject context anu soit them
liom youngest to oluest, we woulu cieate an instance ol NSSortDescriptor with the
age key anu set it to Le ascending:
NSSortDescriptor *ageSortDescriptor =
[[NSSortDescriptor alloc] initWithKey:@"age"
ascending:YES];
You can assign moie than one soit uesciiptoi to one letch ieguest. The
oiuei in the aiiay ueteimines the oiuei in which uesciiptois aie pio-
viueu. In othei woius, The output is soiteu accoiuing to the liist ue-
sciiptoi ol the aiiay, anu within that oiuei, entiies aie soiteu accoiuing
to the seconu uesciiptoi ol the aiiay, etc.
15.6 Sorting Data in Core Data | 681
www.it-ebooks.info
See Also
Recipe 15.+
15.7 Boosting Data Access in Table Views
Problem
In an application that uses taLle views to piesent manageu oLjects to the usei, you want
to Le aLle to letch anu piesent the uata in a moie lluiu anu natuial way than managing
youi uata manually.
Solution
Use letcheu iesults contiolleis, which aie instances ol NSFetchedResultsController.
Discussion
Fetcheu iesults contiolleis woik in the same way as taLle views. Both have sections anu
iows. A letcheu iesults contiollei can ieau manageu oLjects liom a manageu oLject
context anu sepaiate them into sections anu iows. Each section is a gioup (il you specily
it) anu each iow in a section is a manageu oLject. You can then easily map this uata to
a taLle view anu uisplay it to the usei. Theie aie a lew veiy impoitant ieasons why you
might want to mouily youi application to use letcheu iesults contiolleis:
Altei a letcheu iesults contiollei is cieateu on a manageu oLject context, any change
(inseition, ueletion, mouilication, etc.) will immeuiately Le iellecteu on the letcheu
iesults contiollei as well. Foi instance, you coulu cieate youi letcheu iesults con-
tiollei to ieau the manageu oLjects ol the Person entity. Then in some othei place
in youi application, you might inseit a new Person manageu oLject into the context
(the same context the letcheu iesults contiollei was cieateu on). Immeuiately, the
new manageu oLject will Lecome availaLle in the letcheu iesults contiollei. This
is just magical!
Vith a letcheu iesults contiollei, you can manage cache moie elliciently. Foi in-
stance, you can ask youi letcheu iesults contiollei to keep only N numLei ol man-
ageu oLjects in memoiy pei contiollei instance.
Fetcheu iesults contiolleis aie exactly like taLle views in the sense that they have
sections anu iows, as explaineu Leloie. You can use a letcheu iesults contiollei to
piesent manageu oLjects in the GUI ol youi application with taLle views with ease.
Heie aie some ol the impoitant piopeities anu instance methous ol letcheu iesults
contiolleis (all aie oLjects ol type NSFetchedResultsController):
682 | Chapter 15: Core Data
www.it-ebooks.info
sections (propcrty, oj typc NSArray)
A letcheu iesults contiollei can gioup uata togethei using a key path. The uesig-
nateu initializei ol the NSFetchedResultsController class accepts this giouping
liltei thiough the sectionNameKeyPath paiametei. The sections aiiay will then
contain each gioupeu section. Each oLject in this aiiay conloims to the NSFetche
dResultsSectionInfo piotocol.
objectAtIndexPath: (instancc ncthod, rcturns a nanagcd objcct)
OLjects letcheu with a letcheu iesults contiollei can Le ietiieveu using theii section
anu iow inuex. Each section`s iows aie numLeieu 0 thiough N-1, wheie N is the
total numLei ol items in that section. An inuex path oLject compiises a section anu
iow inuex, anu peilectly matches the inloimation neeueu to ietiieve oLjects liom
a letcheu iesults contiollei. The objectAtIndexPath: instance methou accepts in-
uex paths. Each inuex path is ol type NSIndexPath. Il you neeu to constiuct a taLle
view cell using a manageu oLject in a letcheu iesults contiollei, simply pass the
inuex path oLject in the cellForRowAtIndexPath paiametei ol the tableView:cell
ForRowAtIndexPath: uelegate methou ol a taLle view. Il you want to constiuct an
inuex path youisell anywheie else in youi application, use the indexPathFor
Row:inSection: class methou ol NSIndexPath.
fetchRequest (propcrty, oj typc NSFetchRequest)
Il at any point in youi application, you Lelieve you have to change the letch ieguest
oLject loi youi letcheu iesults contiolleis, you can uo so using the fetchRequest
piopeity ol an instance ol NSFetchedResultsController. This is uselul, loi example,
il you want to change the soit uesciiptois (ielei to Recipe 15.6 loi inloimation
aLout this) ol the letch ieguest oLject altei you have allocateu anu initializeu youi
letcheu iesults contiolleis.
To uemonstiate the uselulness ol letch iesults contiolleis, we neeu to cieate an app
that lets us auu new manageu oLjects to anu uelete manageu oLjects liom oui manageu
oLjects context with a usei inteilace. Foi this, we will neeu two view contiolleis:
Pcrsons List \icw Contro||cr
This will Le oui ioot view contiollei. In it we will uisplay a taLle view; insiue the
taLle view we will list all the Peison manageu oLjects that we have in oui manageu
oLjects context. Please ielei to Recipe 15.1 to see how we cieateu the Peison man-
ageu oLject. The taLle view on this view contiollei must allow the usei to uelete
Peison oLjects Ly swiping oi piessing the Euit Lutton on the navigation Lai. Ve
will uisplay a - Lutton on the navigation Lai as well, to allow the usei to auu new
Peison oLjects to the manageu oLject context.
Add Ncw Pcrson \icw Contro||cr
Ve will use this view contiollei to allow the usei to auu new Peison oLjects to the
manageu oLject context.
To uo this, simply lollow these instiuctions:
15.7 Boosting Data Access in Table Views | 683
www.it-ebooks.info
1. Let`s stait with an empty application. Go to Xcoue, select File New New
Pioject..., anu choose an Empty Application univeisal iOS pioject. (You shoulu
also enaLle Coie Data; see Recipe 15.1 loi moie inloimation.) Name the pioject
Boosting Data Access in Table Views. Next, select the Boosting_Da-
ta_Acccss_in_Tab|c_\icws.xcdatanodc|d in Xcoue anu cieate the same exact Pei-
son entity that we cieateu in Recipe 15.1 anu save it as Peison.
2. In youi pioject, cieate two view contiolleis, Loth suLclassing UIViewController.
Name one PersonListViewController anu the othei AddPersonViewController. Cie-
ate Loth these view contiolleis without an xib lile (we won`t neeu Inteilace Builuei
as oui UI is veiy simple inueeu).
3. Now open the ueclaiation ol youi app uelegate anu ueline a new piopeity ol type
PersonListViewController anu call it personListViewController. This will Le the
ioot view contiollei that we will uisplay to oui useis. RememLei that you also neeu
a navigation contiollei, so ueline that as a piopeity too:
#import <UIKit/UIKit.h>
@class PersonListViewController;
@interface Boosting_Data_Access_in_Table_ViewsAppDelegate
: UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (nonatomic, strong)
PersonListViewController *personListViewController;
@property (nonatomic, strong) UINavigationController *navigationController;
@property (readonly, strong, nonatomic)
NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic)
NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic)
NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
@end
+. Vhen youi app loaus up, you want to uisplay the Peison List View Contiollei to
the usei, so uo that now in the application:didFinishLaunchingWithOptions:
methou ol youi app uelegate:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
self.personListViewController =
684 | Chapter 15: Core Data
www.it-ebooks.info
[[PersonListViewController alloc]
initWithNibName:nil
bundle:nil];
self.navigationController =
[[UINavigationController alloc]
initWithRootViewController:self.personListViewController];
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
self.window.rootViewController = self.navigationController;
return YES;
}
5. Vhen the Peison List view contiollei is uisplayeu, place a taLle view on it to list
all the peison entities in youi manageu oLject context. Let`s cieate the taLle now
anu set up oui view contiollei as that taLle view`s uelegate anu uata souice. You
also neeu an Auu Lutton on the navigation Lai with a - sign on it, so when the usei
taps on that Lutton, it will take him to the Auu Peison view contiollei. In auuition
to these two piopeities, you also neeu to have youi letcheu iesults contiollei in the
ioot view contiollei. So let`s ueline all these in oui view contiollei`s uelinition:
#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
@interface PersonListViewController : UIViewController
<UITableViewDelegate,
UITableViewDataSource,
NSFetchedResultsControllerDelegate>
@property (nonatomic, strong) UITableView *tableViewPersons;
@property (nonatomic, strong) UIBarButtonItem *barButtonAddPerson;
@property (nonatomic, strong) NSFetchedResultsController *personsFRC;
@end
6. Next, you neeu to stait implementing oui view contiollei. In the viewDidLoad
methou, instantiate youi Auu navigation Lai Lutton. Also, instantiate youi taLle
view anu set up the euit Lutton on the navigation Lai:
- (void)viewDidLoad{
[super viewDidLoad];
self.title = @"Persons";
self.tableViewPersons =
[[UITableView alloc] initWithFrame:self.view.bounds
style:UITableViewStylePlain];
self.tableViewPersons.delegate = self;
15.7 Boosting Data Access in Table Views | 685
www.it-ebooks.info
self.tableViewPersons.dataSource = self;
[self.view addSubview:self.tableViewPersons];
self.barButtonAddPerson = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
target:self
action:@selector(addNewPerson:)];
[self.navigationItem setLeftBarButtonItem:[self editButtonItem]
animated:NO];
[self.navigationItem setRightBarButtonItem:self.barButtonAddPerson
animated:NO];
}
7. OLviously, now that you`ve electeu the ioot view contiollei to Lecome the uelegate
anu the uata souice ol the taLle view, you neeu to implement the ieguiieu methous
loi the uelegate anu the uata souice. Foi now, we will ietuin 0 cells to the taLle
view. Latei, when we piopeily ieau Peison entities liom the manageu oLject con-
text using the letcheu iesults contiollei, we can ietuin the appiopiiate count ol
Peison oLjects:
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section{
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath{
return nil;
}
S. Now it`s time to hook the - Lutton to the Auu Peison view contiollei, so make
suie you have impoiteu the AddPcrson\icwContro||cr.h heauei lile into the im-
plementation lile ol the Peison List view contiollei:
- (void) addNewPerson:(id)paramSender{
AddPersonViewController *controller = [[AddPersonViewController alloc]
initWithNibName:nil
bundle:nil];
[self.navigationController pushViewController:controller
animated:YES];
}
9. In the Auu Peison view contiollei, you neeu loui piopeities. Thiee aie text lielus:
liist name, last name, anu age. The louith piopeity is loi an Auu navigation Lutton,
which you will place on the navigation Lai. The usei will piess this Lutton once
she is uone, to auu the new peison to the list:
#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
686 | Chapter 15: Core Data
www.it-ebooks.info
@interface AddPersonViewController : UIViewController
@property (nonatomic, strong) UITextField *textFieldFirstName;
@property (nonatomic, strong) UITextField *textFieldLastName;
@property (nonatomic, strong) UITextField *textFieldAge;
@property (nonatomic, strong) UIBarButtonItem *barButtonAdd;
@end
10. Now in the viewDidLoad methou ol youi Auu Peison view contiollei, instantiate
these piopeities anu place them on the view anu put the Lai Lutton on the navi-
gation Lai:
- (void)viewDidLoad{
[super viewDidLoad];
self.title = @"New Person";
CGRect textFieldRect = CGRectMake(20.0f,
20.0f,
self.view.bounds.size.width - 40.0f,
31.0f);
self.textFieldFirstName = [[UITextField alloc] initWithFrame:textFieldRect];
self.textFieldFirstName.placeholder = @"First Name";
self.textFieldFirstName.borderStyle = UITextBorderStyleRoundedRect;
self.textFieldFirstName.autoresizingMask = UIViewAutoresizingFlexibleWidth;
self.textFieldFirstName.contentVerticalAlignment =
UIControlContentVerticalAlignmentCenter;
[self.view addSubview:self.textFieldFirstName];
textFieldRect.origin.y += 37.0f;
self.textFieldLastName = [[UITextField alloc] initWithFrame:textFieldRect];
self.textFieldLastName.placeholder = @"Last Name";
self.textFieldLastName.borderStyle = UITextBorderStyleRoundedRect;
self.textFieldLastName.autoresizingMask = UIViewAutoresizingFlexibleWidth;
self.textFieldLastName.contentVerticalAlignment =
UIControlContentVerticalAlignmentCenter;
[self.view addSubview:self.textFieldLastName];
textFieldRect.origin.y += 37.0f;
self.textFieldAge = [[UITextField alloc] initWithFrame:textFieldRect];
self.textFieldAge.placeholder = @"Age";
self.textFieldAge.borderStyle = UITextBorderStyleRoundedRect;
self.textFieldAge.autoresizingMask = UIViewAutoresizingFlexibleWidth;
self.textFieldAge.keyboardType = UIKeyboardTypeNumberPad;
self.textFieldAge.contentVerticalAlignment =
UIControlContentVerticalAlignmentCenter;
[self.view addSubview:self.textFieldAge]; self.barButtonAdd =
[[UIBarButtonItem alloc] initWithTitle:@"Add"
style:UIBarButtonItemStylePlain
target:self
action:@selector(createNewPerson:)];
15.7 Boosting Data Access in Table Views | 687
www.it-ebooks.info
[self.navigationItem setRightBarButtonItem:self.barButtonAdd
animated:NO];
}
11. As you can see, the Auu Lutton is now linkeu to the createNewPerson: methou ol
youi Auu Peison view contiollei, so all you have to uo is to implement this methou,
get the values in youi text lielus, anu place them in a new Peison oLject. Then you
will neeu to save this oLject into the manageu oLject context anu pop the view
contiollei to go Lack to the Peison List view contiollei (at which time the Peison
view contiollei will neeu to uisplay the new peison in the list). To uo all this, you
liist neeu to make suie we have impoiteu the Pcrson.h anu the Boosting_Da-
ta_Acccss_in_Tab|c_\icwsAppDc|cgatc.h heauei liles into the Auu Peison view
contiollei`s implementation lile so that you can cieate a new peison anu use the
manageu oLject context in the app uelegate to inseit that peison into the uataLase:
12. Now let`s implement the createNewPerson: methou in the Auu Peison view con-
tiollei:
- (void) createNewPerson:(id)paramSender{
Boosting_Data_Access_in_Table_ViewsAppDelegate *appDelegate =
(Boosting_Data_Access_in_Table_ViewsAppDelegate *)
[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *managedObjectContext =
appDelegate.managedObjectContext;
Person *newPerson =
[NSEntityDescription insertNewObjectForEntityForName:@"Person"
inManagedObjectContext:managedObjectContext];
if (newPerson != nil){
newPerson.firstName = self.textFieldFirstName.text;
newPerson.lastName = self.textFieldLastName.text;
newPerson.age = [NSNumber numberWithInteger:
[self.textFieldAge.text integerValue]];
NSError *savingError = nil;
if ([managedObjectContext save:&savingError]){
[self.navigationController popViewControllerAnimated:YES];
} else {
NSLog(@"Failed to save the managed object context.");
}
} else {
NSLog(@"Failed to create the new person object.");
}
}
688 | Chapter 15: Core Data
www.it-ebooks.info
13. To ollei a Lettei usei expeiience, when youi view appeais on the scieen, you can
automatically uisplay the keyLoaiu on the liist name text lielu:
- (void) viewDidAppear:(BOOL)paramAnimated{
[super viewDidAppear:paramAnimated];
[self.textFieldFirstName becomeFirstResponder];
}
1+. You aie uone with the Auu Peison view contiollei. You can actually now go aheau
anu tiy it out loi youisell. Let`s now go to the Peison List view contiollei anu uuiing
its initialization, instantiate oui letcheu iesults contiollei:
#import "PersonListViewController.h"
#import "AddPersonViewController.h"
#import "Boosting_Data_Access_in_Table_ViewsAppDelegate.h"
#import "Person.h"
@implementation PersonListViewController
- (NSManagedObjectContext *) managedObjectContext{
Boosting_Data_Access_in_Table_ViewsAppDelegate *appDelegate =
(Boosting_Data_Access_in_Table_ViewsAppDelegate *)
[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *managedObjectContext =
appDelegate.managedObjectContext;
return managedObjectContext;
}
- (id) initWithNibName:(NSString *)nibNameOrNil
bundle:(NSBundle *)nibBundleOrNil{
self = [super initWithNibName:nibNameOrNil
bundle:nibBundleOrNil];
if (self != nil){
/* Create the fetch request first */
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
/* Here is the entity whose contents we want to read */
NSEntityDescription *entity =
[NSEntityDescription entityForName:@"Person"
inManagedObjectContext:[self managedObjectContext]];
NSSortDescriptor *ageSort =
[[NSSortDescriptor alloc] initWithKey:@"age"
ascending:YES];
NSSortDescriptor *firstNameSort =
[[NSSortDescriptor alloc] initWithKey:@"firstName"
ascending:YES];
15.7 Boosting Data Access in Table Views | 689
www.it-ebooks.info
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:
ageSort,
firstNameSort, nil];
fetchRequest.sortDescriptors = sortDescriptors;
/* Tell the request that we want to read the
contents of the Person entity */
[fetchRequest setEntity:entity];
self.personsFRC =
[[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest
managedObjectContext:[self managedObjectContext]
sectionNameKeyPath:nil
cacheName:nil];
self.personsFRC.delegate = self;
NSError *fetchingError = nil;
if ([self.personsFRC performFetch:&fetchingError]){
NSLog(@"Successfully fetched.");
} else {
NSLog(@"Failed to fetch.");
}
}
return self;
}
15. Now go aheau anu implement vaiious methous ol youi taLle view uelegate (we lelt
them to theii minimum ieguiieu implementation Leloie). You can ieau the letcheu
manageu oLjects liom the letcheu iesults contiollei anu uisplay the Peison man-
ageu oLjects in the taLle view:
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section{
id <NSFetchedResultsSectionInfo> sectionInfo = [self.personsFRC.sections
objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *result = nil;
static NSString *PersonTableViewCell = @"PersonTableViewCell";
result = [tableView dequeueReusableCellWithIdentifier:PersonTableViewCell];
690 | Chapter 15: Core Data
www.it-ebooks.info
if (result == nil){
result =
[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:PersonTableViewCell];
result.selectionStyle = UITableViewCellSelectionStyleNone;
}
Person *person = [self.personsFRC objectAtIndexPath:indexPath];
result.textLabel.text =
[person.firstName stringByAppendingFormat:@" %@", person.lastName];
result.detailTextLabel.text =
[NSString stringWithFormat:@"Age: %lu",
(unsigned long)[person.age unsignedIntegerValue]];
return result;
}
16. You can now iun the app anu test it loi youisell. One ol the issues in oui app at
the moment is that il the usei goes to the Auu Peison view contiollei anu auus a
new peison to the manageu oLject context, when she is sent Lack to the Peison
List view contiollei, the new peison she just inseiteu into the context will not
appeai in the list. That is Lecause oui view contiollei uoesn`t know aLout the new
oLject in the manageu oLject context. The way to solve this is to implement the
controllerDidChangeContent: uelegate methou ol oui letcheu iesults contiollei
oLject in the Peison List view contiollei. Vhen we cieateu oui letcheu iesults
contiollei, we nominateu this view contiollei to Lecome the uelegate ol the letcheu
iesults contiollei, so let`s implement this methou. This methou gets calleu when
the letcheu iesults contiollei uetects a change in the oLjects in the manageu oLject
context, so once this methou gets calleu, we can go aheau anu ieloau oui taLle view:
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller{
[self.tableViewPersons reloadData];
}
17. The next thing we have to uo in oui Peison List view contiollei is to hanule euiting:
- (void) tableView:(UITableView *)tableView
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath{
Person *personToDelete = [self.personsFRC objectAtIndexPath:indexPath];
/* Very important: we need to make sure we are not reloading the table view
while deleting the managed object */
self.personsFRC.delegate = nil;
[[self managedObjectContext] deleteObject:personToDelete];
if ([personToDelete isDeleted]){
15.7 Boosting Data Access in Table Views | 691
www.it-ebooks.info
NSError *savingError = nil;
if ([[self managedObjectContext] save:&savingError]){
NSError *fetchingError = nil;
if ([self.personsFRC performFetch:&fetchingError]){
NSLog(@"Successfully fetched.");
NSArray *rowsToDelete = [[NSArray alloc]
initWithObjects:indexPath, nil];
[tableViewPersons
deleteRowsAtIndexPaths:rowsToDelete
withRowAnimation:UITableViewRowAnimationAutomatic];
} else {
NSLog(@"Failed to fetch with error = %@", fetchingError);
}
} else {
NSLog(@"Failed to save the context with error = %@", savingError);
}
}
self.personsFRC.delegate = self;
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView
editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
return UITableViewCellEditingStyleDelete;
}
- (void) setEditing:(BOOL)paramEditing
animated:(BOOL)paramAnimated{
[super setEditing:paramEditing
animated:paramAnimated];
if (paramEditing){
[self.navigationItem setRightBarButtonItem:nil
animated:YES];
} else {
[self.navigationItem setRightBarButtonItem:self.barButtonAddPerson
animated:YES];
}
[self.tableViewPersons setEditing:paramEditing
animated:YES];
}
Ve aie all uone. Go aheau anu tiy it out loi youisell.
692 | Chapter 15: Core Data
www.it-ebooks.info
15.8 Implementing Relationships in Core Data
Problem
You want to Le aLle to link youi manageu oLjects to each othei: loi instance, linking
a Person to the Home he lives in.
Solution
Use inveise ielationships in the mouel euitoi.
Discussion
Relationships in Coie Data can Le one-to-one, inveise one-to-many, oi inveise many-
to-many. Heie is an example ol each type ol ielationship:
Onc-to-onc rc|ationship
An example is the ielationship Letween a peison anu hei nose. Each peison can
have only one nose, anu each nose can Lelong to only one peison.
|nvcrsc onc-to-nany rc|ationship
An example is the ielationship Letween an employee anu his managei. The em-
ployee can have only one uiiect managei, Lut his managei can have multiple em-
ployees woiking loi hei. Heie, the ielationship ol the employee with the managei
is one-to-one, Lut liom the managei`s peispective, the ielationship is one (man-
agei) to many (employees); hence the woiu invcrsc.
|nvcrsc nany-to-nany rc|ationship
An example is the ielationship Letween a peison anu a cai. One cai can Le useu
Ly moie than one peison, anu one peison can have moie than one cai.
In Coie Data, you can cieate one-to-one ielationships, Lut I highly iecommenu that
you avoiu uoing so Lecause, going Lack to the example in the pieceuing list, the peison
will know what nose she has Lut the nose will not know who it Lelongs to. Please note
that this is a uilleient one-to-one mouel than what you might have seen in othei uata-
Lase management systems wheie OLject A anu B will Le linkeu togethei when they
have a one-to-one ielationship. In a Coie Data one-to-one ielationship, OLject A will
know aLout OLject B, Lut not the othei way aiounu. In an oLject-oiienteu piogiam-
ming language such as OLjective-C, it is always Lest to cieate inveise ielationships so
that chilu elements can ielei to paient elements ol that ielationship. In a one-to-many
ielationship, the oLject that can have association with many othei oLjects will ietain a
set ol those oLjects. The set will Le ol type NSSet. Howevei, in a one-to-one ielationship,
oLjects on Loth siues ol the lence keep a ieleience to one anothei using the piopei class
names ol one anothei since, well, the ielationship is one-to-one anu an instance ol one
oLject in anothei oLject can easily Le iepiesenteu with the class name ol that oLject.
15.8 Implementing Relationships in Core Data | 693
www.it-ebooks.info
Let`s go aheau anu cieate a uata mouel that takes auvantage ol an inveise one-to-many
ielationship:
1. In Xcoue, linu the xcdatanodc| lile that was cieateu loi you when you staiteu youi
Coie Data pioject, as shown eailiei in Figuie 15-1 (ielei to Recipe 15.1 to cieate
such a pioject).
2. Open the uata mouel lile in the euitoi Ly clicking on it.
3. Remove any entities that weie cieateu loi you pieviously Ly selecting them anu
piessing the Delete key on youi keyLoaiu.
+. Cieate a new entity anu name it Employee. Cieate thiee attiiLutes loi this entity,
nameu firstName (ol type String), lastName (ol type String), anu age (ol type
Integer 32), as shown in Figuie 15-13.
5. Cieate anothei entity nameu Manager with the same attiiLutes you cieateu loi the
Employee entity (firstName ol type String, lastName ol type String, anu age ol type
Integer 32). See Figuie 15-1+.
Iigurc 15-13. Thc Enp|oycc cntity with thrcc attributcs
6. Cieate a new ielationship loi the Manager entity Ly liist selecting the Managei entity
in the list anu then piessing the - Lutton in the Lottom ol the Relationships Lox
(see Figuie 15-15).
694 | Chapter 15: Core Data
www.it-ebooks.info
Iigurc 15-15. Wc havc addcd a ncw rc|ationship to thc Managcr cntity
7. Set the name ol the new ielationship to FKManagerToEmployees (see Figuie 15-16).
Iigurc 15-11. Thc Managcr cntity with thrcc attributcs
15.8 Implementing Relationships in Core Data | 695
www.it-ebooks.info
Iigurc 15-1. Changing thc nanc oj thc ncw Managcr-to-Enp|oyccs rc|ationship
S. Select the Employee entity anu cieate a new ielationship loi it. Name the ielationship
FKEmployeeToManager (see Figuie 15-17).
Iigurc 15-17. Changing thc nanc oj thc ncw Enp|oycc-to-Managcr rc|ationship
9. Choose the Manager entity, anu then select the FKManagerToEmployees ielationship
loi the Manager. In the Relationships Lox, choose Employee in the Destination
uiop-uown menu (Lecause we want to connect a Manager to an Employee entity
thiough this ielationship), set the Inveise Lox`s value to FKEmployeeToManager (Le-
cause the FKEmployeeToManager ielationship ol the Employee will link an employee
to hei Manager), anu tick the To-Many Relationship Lox in Data Mouel inspectoi
(see Recipe 15.1). The iesults aie shown in Figuie 15-1S.
696 | Chapter 15: Core Data
www.it-ebooks.info
Iigurc 15-18. Thc Managcr invcrsc rc|ationship cstab|ishcd with cnp|oyccs
10. Select Loth youi Employee anu Manager entities, select File New File, anu cieate
the manageu oLject classes loi youi mouel, as uesciiLeu in Recipe 15.2.
Altei cieating the inveise one-to-many ielationship, open the .h lile ol youi Employee
entity:
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@class Manager;
@interface Employee : NSManagedObject {
@private
}
@property (nonatomic, retain) NSString * firstName;
@property (nonatomic, retain) NSString * lastName;
@property (nonatomic, retain) NSNumber * age;
@property (nonatomic, retain) Manager *FKEmployeeToManager;
@end
You can see that a new piopeity has Leen auueu to this lile. The piopeity is nameu
FKEmployeeToManager anu its type is Manager, meaning that liom now on, il we have a
ieleience to any oLject ol type Employee, we can access its FKEmployeeToManager piopeity
to access that specilic employee`s Manager oLject (il any). Let`s have a look at the .h lile
ol the Manager entity:
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@class Employee;
15.8 Implementing Relationships in Core Data | 697
www.it-ebooks.info
@interface Manager : NSManagedObject {
@private
}
@property (nonatomic, retain) NSNumber * age;
@property (nonatomic, retain) NSString * firstName;
@property (nonatomic, retain) NSString * lastName;
@property (nonatomic, retain) NSSet *FKManagerToEmployees;
@end
@interface Manager (CoreDataGeneratedAccessors)
- (void)addFKManagerToEmployeesObject:(Employee *)value;
- (void)removeFKManagerToEmployeesObject:(Employee *)value;
- (void)addFKManagerToEmployees:(NSSet *)values;
- (void)removeFKManagerToEmployees:(NSSet *)values;
@end
The FKManagerToEmployees piopeity is also cieateu loi the Manager entity. The uata type
ol this oLject is NSSet. This simply means the FKManagerToEmployees piopeity ol any
instance ol the Manager entity can contain 1 to N numLei ol Employee entities (a one-
to-many ielationship: one managei, many employees).
Anothei type ol ielationship that you might want to cieate is a many-to-many iela-
tionship. Going Lack to the Manager to Employee ielationship, with a many-to-many
ielationship, any managei coulu have N numLei ol employees anu one employee coulu
have N numLei ol manageis. To uo this, lollow the same instiuctions loi cieating a
one-to-many ielationship, Lut select the Employee entity anu then the FKEm
ployeeToManager ielationship. Change this name to FKEmployeeToManagers anu tick the
To-Many Relationship Lox, as shown in Figuie 15-19. Now the aiiow has uouLle ai-
iowheaus on Loth siues.
Iigurc 15-19. Crcating a Many-to-Many rc|ationship bctwccn thc Managcr and Enp|oycc cntitics
698 | Chapter 15: Core Data
www.it-ebooks.info
In youi coue, loi a one-to-many ielationship, you can simply cieate a new Manager
manageu oLject (ieau how you can inseit oLjects to a manageu oLject context in
Recipe 15.3), save it to the manageu oLject context, anu then cieate a couple ol
Employee manageu oLjects anu save them to the context as well. Now, to associate the
managei with an employee, set the value ol the FKEmployeeToManager piopeity ol an
instance ol Employee to an instance ol the Manager manageu oLject. Coie Data will then
cieate the ielationship loi you.
Il you woulu like to ietiieve all employees (ol type Employee) that aie associateu to a
managei oLject (ol type Manager), all you have to uo is to use the allObjects instance
methou ol the FKManagerToEmployees piopeity ol oui managei oLject. This oLject is ol
type NSSet, so you can use its allObjects instance methou to ietiieve the aiiay ol all
employee oLjects associateu with a paiticulai managei oLject.
15.8 Implementing Relationships in Core Data | 699
www.it-ebooks.info
www.it-ebooks.info
CHAPTER 16
Dates, Calendars, and Events
16.0 Introduction
The Event Kit anu Event Kit UI liamewoiks allow iOS uevelopeis to access the Calenuai
uataLase on an iOS uevice. You can inseit, ieau, anu mouily events using the Event Kit
liamewoik. The Event Kit UI liamewoik allows you to piesent Luilt-in SDK GUI ele-
ments that allow the usei to manipulate the Calenuai uataLase manually. In this chap-
tei, we will locus on the Event Kit liamewoik liist, anu then leain aLout the Event Kit
UI liamewoik.
Vith the Event Kit liamewoik, a piogiammei can mouily the usei`s Calenuai uataLase
without him knowing. Howevei, this is not a veiy goou piactice. In lact, Apple piohiLits
piogiammeis liom uoing so anu asks us to always notily useis aLout any changes that
the piogiam might make to the Calenuai uataLase. Heie is a guote liom Apple:
Il youi application mouilies a usei`s Calenuai uataLase piogiammatically, it must get
conliimation liom the usei Leloie uoing so. An application shoulu nevei mouily the
Calenuai uataLase without specilic instiuction liom the usei.
iOS comes with a Luilt-in Calenuai app. The Calenuai app can woik with uilleient
types ol calenuais, such as local, CalDAV, anu so loith. In this chaptei, we will Le
woiking with uilleient types ol calenuais as well. To make suie you aie piepaieu to
iun the coue in some ol the iecipes in this chaptei, please cieate a Google account anu
associate it with Google Calenuai. To get staiteu, heau ovei to http://www.goog|c.con/
ca|cndar/.
Once theie, cieate a Google account. Altei you aie uone, auu Google Calenuai to youi
iOS uevice Ly lollowing these steps:
1. Go to the home scieen ol youi iOS uevice.
2. Go to Settings.
3. Select Mail, Contacts, Calenuais.
+. Select Auu Account...
5. Select Othei.
701
www.it-ebooks.info
6. Unuei the Calenuais gioup, select the Auu CalDAV Account Lutton.
7. On the CalDAV scieen, entei the lollowing (see Figuie 16-1):
a. www.google.com loi the Seivei
L. Youi Google useiname loi Usei Name
c. Youi Google passwoiu loi Passwoiu
u. A uesciiption ol youi choice loi Desciiption
S. Tap Next.
Iigurc 1-1. Adding a Goog|c ca|cndar to an iOS dcvicc
Once you auu the new Google account with Calenuai access to youi iOS uevice, you
can see this calenuai appeai in the Calenuais list in the Calenuai application, as shown
in Figuie 16-2.
CalDAV is a piotocol that allows access to the stanuaiu Calenuai loimat useu Ly Goo-
gle Calenuai anu is suppoiteu Ly iOS. Foi moie inloimation aLout CalDAV, please
ielei to RFC +791 at http://too|s.ictj.org/htn|/rjc1791.
Almost all the iecipes in this chaptei uemonstiate the use ol the Event Kit anu Event
Kit UI liamewoiks using a CalDAV calenuai. Beloie ieauing the iecipes, please take a
lew minutes anu lollow the instiuctions pioviueu heie to cieate a new CalDAV calenuai
anu link it to youi iOS uevice. Heie aie some ol the Lenelits ol using a CalDAV calenuai:
702 | Chapter 16: Dates, Calendars, and Events
www.it-ebooks.info
It`s easy to set up.
It can Le shaieu among uilleient platloims, so changes to a local instance ol a
CalDAV calenuai oLject will Le iellecteuautomatically Ly iOSto the CalDAV
seivei. This will give you a Lettei unueistanuing ol how calenuais woik in iOS,
anu you can simply check youi Google Calenuai online anu make suie the local
changes aie iellecteu theie.
You can auu paiticipants to an event using a CalDAV calenuai. This is explaineu
in Recipe 16.6.
You can auu a CalDAV calenuai to iCal on youi Mac, as well as youi iOS uevices,
syncing events acioss all machines.
To iun the example coue in this chaptei, you must auu the Event Kit liamewoik, anu
in some cases the Event Kit UI liamewoik, to youi application Ly lollowing these steps:
1. Click on youi pioject`s icon in Xcoue
2. Select the taiget to which you want to auu the liamewoiks.
3. Select the Builu Phases taL liom the top ol the scieen.
+. Expanu the Link Binaiy with LiLiaiies Lox unuei the Builu Phases taL anu piess
the little - Lutton locateu on the Lottom-lelt coinei ol this Lox.
5. Choose the Event Kit anu Event Kit UI liamewoiks anu click Auu.
Iigurc 1-2. Thc ncw Goog|c Ca|cndar addcd to thc |ist oj ca|cndars on an iOS dcvicc
16.0 Introduction | 703
www.it-ebooks.info
The iOS Simulatoi on Mac OS X uoes not simulate the Calenuai app
on an iOS uevice. To test the iecipes in this chaptei, you must iun anu
ueLug youi piogiam on a ieal iOS uevice. All examples in this chaptei
have Leen testeu on the iPhone + anu iPau 2.
In most ol the example coue in this chaptei, we will locus on manually ieauing anu
manipulating events in a calenuai. Il you want to use the Luilt-in iOS capaLilities to
allow youi useis to guickly access theii calenuai events, please ielei to Recipes 16.9
anu 16.10.
16.1 Retrieving the List of Calendars
Problem
You want to ietiieve the list ol calenuais availaLle on the usei`s uevice Leloie you
attempt to inseit new events into them.
Solution
Access the calendars aiiay piopeity ol an instance ol EKEventStore. Each calenuai is ol
type EKCalendar:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

EKEventStore *eventStore = [[EKEventStore alloc] init];

/* These are the calendar types an iOS Device can have. Please note
that the "type" property of an object of type EKCalendar
is of type EKCalendarType. The values in the "CalendarTypes"
array reflect the exact same values in the EKCalendarType
enumeration, but as NSString values */
NSArray *calendarTypes = @[
@"Local",
@"CalDAV",
@"Exchange",
@"Subscription",
@"Birthday"
];

/* Go through the calendars one by one */
NSUInteger counter = 1;
for (EKCalendar *thisCalendar in eventStore.calendars){

/* The title of the calendar */
NSLog(@"Calendar %lu Title = %@",
(unsigned long)counter, thisCalendar.title);

/* The type of the calendar */
NSLog(@"Calendar %lu Type = %@",
704 | Chapter 16: Dates, Calendars, and Events
www.it-ebooks.info
(unsigned long)counter,
[calendarTypes objectAtIndex:thisCalendar.type]);

/* The color that is associated with the calendar */
NSLog(@"Calendar %lu Color = %@",
(unsigned long)counter,
[UIColor colorWithCGColor:thisCalendar.CGColor]);

/* And whether the calendar can be modified or not */
if ([thisCalendar allowsContentModifications]){
NSLog(@"Calendar %lu can be modified.",
(unsigned long)counter);
} else {
NSLog(@"Calendar %lu cannot be modified.",
(unsigned long)counter);
}

counter++;
}

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

self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Running this coue on an iOS uevice with six calenuais (see Figuie 16-2) will piint iesults
similai to this in the console winuow:
Calendar 1 Title = Birthdays
Calendar 1 Type = Birthday
Calendar 1 Color = UIDeviceRGBColorSpace 0.509804 0.584314 0.686275 1
Calendar 1 cannot be modified.
Calendar 2 Title = Calendar
Calendar 2 Type = Local
Calendar 2 Color = UIDeviceRGBColorSpace 0.054902 0.380392 0.72549 1
Calendar 2 can be modified.
Calendar 3 Title = Calendar
Calendar 3 Type = CalDAV
Calendar 3 Color = UIDeviceRGBColorSpace 0.054902 0.380392 0.72549 1
Calendar 3 can be modified.
Calendar 4 Title = Home
Calendar 4 Type = CalDAV
Calendar 4 Color = UIDeviceRGBColorSpace 0.443137 0.101961 0.462745 1
Calendar 4 can be modified.Calendar 5 Title = Work
Calendar 5 Type = CalDAV
Calendar 5 Color = UIDeviceRGBColorSpace 0.964706 0.309804 0 1
Calendar 5 can be modified.
Calendar 6 Title = vandad.np@gmail.com
Calendar 6 Type = CalDAV
Calendar 6 Color = UIDeviceRGBColorSpace 0.160784 0.321569 0.639216 1
Calendar 6 can be modified.
16.1 Retrieving the List of Calendars | 705
www.it-ebooks.info
Discussion
By allocating anu initializing an oLject ol type EKEventStore, you can access uilleient
types ol calenuais that aie availaLle on an iOS uevice. iOS suppoits common calenuai
loimats such as CalDAV anu Exchange. The calendars piopeity ol an instance ol
EKEventStore is ol type NSArray anu contains the aiiay ol calenuais that aie on an iOS
uevice. Each oLject in this aiiay is ol type EKCalendar anu each calenuai has piopeities
that allow us to ueteimine whethei, loi instance, we can inseit new events into that
calenuai.
As we`ll see in Recipe 16.2, a calenuai oLject allows mouilications only il its allows
ContentModifications piopeity has a YES value.
You can use the colorWithCGColor: instance methou ol UIColor to ie-
tiieve an oLject ol type UIColor liom CGColorRef.
See Also
Recipe 16.2
16.2 Adding Events to Calendars
Problem
You woulu like to Le aLle to cieate new events in useis` calenuais.
Solution
Finu the calenuai you want to inseit youi event into (please ielei to Recipe 16.1). Cieate
an oLject ol type EKEvent using the eventWithEventStore: class methou ol EKEvent anu
save the event into the usei`s calenuai using the saveEvent:span:error: instance meth-
ou ol EKEventStore:
- (BOOL) createEventWithTitle:(NSString *)paramTitle
startDate:(NSDate *)paramStartDate
endDate:(NSDate *)paramEndDate
inCalendarWithTitle:(NSString *)paramCalendarTitle
inCalendarWithType:(EKCalendarType)paramCalendarType
notes:(NSString *)paramNotes{
BOOL result = NO;
EKEventStore *eventStore = [[EKEventStore alloc] init];
/* Are there any calendars available to the event store? */
if ([eventStore.calendars count] == 0){
706 | Chapter 16: Dates, Calendars, and Events
www.it-ebooks.info
NSLog(@"No calendars are found.");
return NO;
}
EKCalendar *targetCalendar = nil;
/* Try to find the calendar that the user asked for */
for (EKCalendar *thisCalendar in eventStore.calendars){
if ([thisCalendar.title isEqualToString:paramCalendarTitle] &&
thisCalendar.type == paramCalendarType){
targetCalendar = thisCalendar;
break;
}
}
/* Make sure we found the calendar that we were asked to find */
if (targetCalendar == nil){
NSLog(@"Could not find the requested calendar.");
return NO;
}
/* If a calendar does not allow modification of its contents
then we cannot insert an event into it */
if (targetCalendar.allowsContentModifications == NO){
NSLog(@"The selected calendar does not allow modifications.");
return NO;
}
/* Create an event */
EKEvent *event = [EKEvent eventWithEventStore:eventStore];
event.calendar = targetCalendar;
/* Set the properties of the event such as its title,
start date/time, end date/time, etc. */
event.title = paramTitle;
event.notes = paramNotes;
event.startDate = paramStartDate;
event.endDate = paramEndDate;
/* Finally, save the event into the calendar */
NSError *saveError = nil;
result = [eventStore saveEvent:event
span:EKSpanThisEvent
error:&saveError];
if (result == NO){
NSLog(@"An error occurred = %@", saveError);
}
return result;
}
You can use the methou we just implementeu to inseit new events into a usei`s calenuai:
16.2 Adding Events to Calendars | 707
www.it-ebooks.info
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

/* The event starts from today, right now */
NSDate *startDate = [NSDate date];

/* And the event ends this time tomorrow.
24 hours, 60 minutes per hour and 60 seconds per minute
hence 24 * 60 * 60 */
NSDate *endDate = [startDate
dateByAddingTimeInterval:24 * 60 * 60];

/* Create the new event */
BOOL createdSuccessfully = [self createEventWithTitle:@"My event"
startDate:startDate
endDate:endDate
inCalendarWithTitle:@"Calendar"
inCalendarWithType:EKCalendarTypeLocal
notes:nil];

if (createdSuccessfully){
NSLog(@"Successfully created the event.");
} else {
NSLog(@"Failed to create the event.");
}

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

self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Discussion
To piogiammatically cieate a new event in a calenuai on an iOS uevice, we must:
1. Allocate anu initialize an instance ol EKEventStore.
2. Finu the calenuai we want to save the event to (please ielei to Recipe 16.1). Ve
must make suie the taiget calenuai suppoits mouilications Ly checking that the
calenuai oLject`s allowsContentModifications piopeity is YES. Il it is not, you must
choose a uilleient calenuai oi loiego saving the event.
3. Once you linu youi taiget calenuai, cieate an event ol type EKEvent using the
eventWithEventStore: class methou ol EKEvent.
+. Set the piopeities ol the new event such as its title, startDate, anu endDate.
5. Associate youi event with the calenuai that you lounu in step 2 using the calen
dars piopeity ol an instance ol EKEvent.
6. Once you aie uone setting the piopeities ol youi event, auu that event to the
calenuai using the saveEvent:span:error: instance methou ol EKEventStore. The
708 | Chapter 16: Dates, Calendars, and Events
www.it-ebooks.info
ietuin value ol this methou (a BOOL value) inuicates whethei the event was suc-
cesslully inseiteu into the Calenuai uataLase. Il the opeiation lails, the NSError
oLject passeu to the error paiametei ol this methou will contain the eiioi that has
occuiieu in the system while inseiting this event.
Il you attempt to inseit an event without specilying a taiget calenuai, oi il you inseit
an event into a calenuai that cannot Le mouilieu, the saveEvent:span:error: instance
methou ol EKEventStore will lail with an eiioi similai to this:
Error Domain=EKErrorDomain Code=1 "No calendar has been set."
UserInfo=0x15d860 {NSLocalizedDescription=No calendar has been set.}
Running oui coue on an iOS uevice, we will see an event cieateu in the Calenuai ua-
taLase, as shown in Figuie 16-3.
Iigurc 1-3. Progrannatica||y adding an cvcnt to a ca|cndar
iOS syncs online calenuais with the iOS calenuai. These calenuais coulu Le Exchange,
CalDAV, anu othei common loimats. Cieating an event on a CalDAV calenuai on an
iOS uevice will cieate the same event on the seivei. The seivei changes aie also iellecteu
in the iOS Calenuai uataLase when the Calenuai uataLase is synceu with the seivei.
See Also
Recipe 16.1
16.2 Adding Events to Calendars | 709
www.it-ebooks.info
16.3 Accessing the Contents of Calendars
Problem
You want to ietiieve events ol type EKEvent liom a calenuai ol type EKCalendar on an
iOS uevice.
Solution
Follow these steps:
1. Instantiate an oLject ol type EKEventStore.
2. Using the calendars piopeity ol the event stoie (instantiateu in step 1), linu the
calenuai you want to ieau liom.
3. Deteimine the time anu uate wheie you want to stait the seaich in the calenuai
anu the time anu uate wheie the seaich must stop.
+. Pass the calenuai oLject (lounu in step 2), along with the two uates you lounu in
step 3, to the predicateForEventsWithStartDate:endDate:calendars: instance
methou ol EKEventStore.
5. Pass the pieuicate cieateu in step + to the eventsMatchingPredicate: instance
methou ol EKEventStore. The iesult ol this methou is an aiiay ol EKEvent oLjects
(il any) that lell Letween the given uates (step 3) in the specilieu calenuai (step 2).
This coue illustiates the aLove steps:
- (EKCalendar *) calDAVCalendarWithTitleContaining
:(NSString *)paramDescription{

EKCalendar *result = nil;

EKEventStore *eventStore = [[EKEventStore alloc] init];

for (EKCalendar *thisCalendar in eventStore.calendars){
if (thisCalendar.type == EKCalendarTypeCalDAV){
if ([thisCalendar.title
rangeOfString:paramDescription].location != NSNotFound){
return thisCalendar;
}
}
}

return result;

}
- (void) readEvents{

/* Find a calendar to base our search on */
EKCalendar *targetCalendar =
[self calDAVCalendarWithTitleContaining:@"gmail.com"];
710 | Chapter 16: Dates, Calendars, and Events
www.it-ebooks.info

/* If we could not find a CalDAV calendar that we were looking for,
then we will abort the operation */
if (targetCalendar == nil){
NSLog(@"No CalDAV calendars were found.");
return;
}

/* We have to pass an array of calendars to the event store to search */
NSArray *targetCalendars = [[NSArray alloc] initWithObjects:
targetCalendar, nil];

/* Instantiate the event store */
EKEventStore *eventStore = [[EKEventStore alloc] init];

/* The start date will be today */
NSDate *startDate = [NSDate date];

/* The end date will be one day from today */
NSDate *endDate = [startDate dateByAddingTimeInterval:24 * 60 * 60];

/* Create the predicate that we can later pass to the
event store in order to fetch the events */
NSPredicate *searchPredicate =
[eventStore predicateForEventsWithStartDate:startDate
endDate:endDate
calendars:targetCalendars];

/* Make sure we succeeded in creating the predicate */
if (searchPredicate == nil){
NSLog(@"Could not create the search predicate.");
return;
}

/* Fetch all the events that fall between
the starting and the ending dates */
NSArray *events = [eventStore eventsMatchingPredicate:searchPredicate];

/* Go through all the events and print their information
out to the console */
if (events != nil){

NSUInteger counter = 1;
for (EKEvent *event in events){

NSLog(@"Event %lu Start Date = %@",
(unsigned long)counter,
event.startDate);

NSLog(@"Event %lu End Date = %@",
(unsigned long)counter,
event.endDate);

NSLog(@"Event %lu Title = %@",
(unsigned long)counter,
16.3 Accessing the Contents of Calendars | 711
www.it-ebooks.info
event.title);

counter++;
}

} else {
NSLog(@"The array of events for this start/end time is nil.");
}

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

[self readEvents];

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

self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Vhen we iun this coue on an iOS uevice with six calenuais set up (one ol which is a
Google CalDAV calenuai), as shown in Figuie 16-2, we will see the events that aie
availaLle Letween the uay that we iun the app anu the next uay.
The Calenuai app in iOS uisplays the same events in the loimat shown in Fig-
uie 16-+. Please Leai in minu that you will not see iesults similai to this unless you
cieate the events in youi Google Calenuai just as I have cieateu them, at the exact same
uate anu time. Howevei, il you uo ueciue to cieate events in othei calenuais, such as
the local calenuai, on uilleient uates, make suie you change the staiting anu enuing
uates ol the event pieuicate anu the calenuai in which you aie peiloiming the seaich.
Foi moie inloimation, please ielei to this iecipe`s Discussion.
Discussion
As mentioneu in this chaptei`s Intiouuction, an iOS uevice can Le conliguieu with
uilleient types ol calenuais using CalDAV, Exchange, anu so on. Each calenuai that is
accessiLle Ly the Event Kit liamewoik is encompasseu within an EKCalendar oLject that
can Le accesseu using the calendars aiiay piopeity ol an instance ol EKEventStore. You
can letch events insiue a calenuai in uilleient ways, Lut the easiest way is to cieate anu
execute a specially loimatteu specilication ol uates anu times, calleu a prcdicatc, insiue
an event stoie.
A pieuicate ol type NSPredicate that we can use in the Event Kit liamewoik can Le
cieateu using the predicateForEventsWithStartDate:endDate:calendars: instance
methou ol an EKEventStore. The paiameteis to this methou aie:
712 | Chapter 16: Dates, Calendars, and Events
www.it-ebooks.info
predicateForEventsWithStartDate
The staiting uate anu time liom when the events have to Le letcheu.
endDate
The enuing uate up until which the events will Le letcheu.
calendars
The aiiay ol calenuais to seaich loi events Letween the staiting anu enuing uates.
See Also
Recipe 16.1
16.4 Removing Events from Calendars
Problem
You want to Le aLle to uelete a specilic event oi seiies ol events liom useis` calenuais.
Solution
Use the removeEvent:span:commit:error: instance methou ol EKEventStore.
Iigurc 1-1. Thc Ca|cndar app on an iOS dcvicc
16.4 Removing Events from Calendars | 713
www.it-ebooks.info
Discussion
The removeEvent:span:commit:error: instance methou ol EKEventStore can iemove an
instance ol an event oi all instances ol a iecuiiing event. Foi moie inloimation aLout
iecuiiing events, please ielei to Recipe 16.5. In this iecipe, we will only iemove an
instance ol the event anu not the othei instances ol the same event in the calenuai.
The paiameteis that we can pass to this methou aie:
removeEvent
This is the EKEvent instance to Le iemoveu liom the calenuai.
span
This is the paiametei that tells the event stoie whethei we want to iemove only
this event oi all the occuiiences ol this event in the calenuai. To iemove only the
cuiient event, specily the EKSpanThisEvent value loi the removeEvent paiametei. To
iemove all occuiiences ol the same event liom the calenuai, pass the
EKSpanFutureEvents value loi the paiametei.
commit
A Loolean value that tells the event stoie il the changes have to Le saveu on the
iemote/local calenuai immeuiately oi not.
error
This paiametei can Le given a ieleience to an NSError oLject that will Le lilleu with
the eiioi (il any), when the ietuin value ol this methou is NO.
To uemonstiate this, let`s use the event cieation methou that we implementeu in
Recipe 16.2. Vhat we can uo then is to cieate an event in oui Google CalDAV calenuai
anu altei it has Leen cieateu, attempt to uelete it liom the event stoie:
- (BOOL) createEventWithTitle:(NSString *)paramTitle
startDate:(NSDate *)paramStartDate
endDate:(NSDate *)paramEndDate
inCalendarWithTitle:(NSString *)paramCalendarTitle
inCalendarWithType:(EKCalendarType)paramCalendarType
notes:(NSString *)paramNotes{

BOOL result = NO;

EKEventStore *eventStore = [[EKEventStore alloc] init];

/* Are there any calendars available to the event store? */
if ([eventStore.calendars count] == 0){
NSLog(@"No calendars are found.");
return NO;
}

EKCalendar *targetCalendar = nil;

/* Try to find the calendar that the user asked for */
for (EKCalendar *thisCalendar in eventStore.calendars){
if ([thisCalendar.title isEqualToString:paramCalendarTitle] &&
714 | Chapter 16: Dates, Calendars, and Events
www.it-ebooks.info
thisCalendar.type == paramCalendarType){
targetCalendar = thisCalendar;
break;
}
}

/* Make sure we found the calendar that we were asked to find */
if (targetCalendar == nil){
NSLog(@"Could not find the requested calendar.");
return NO;
}

/* If a calendar does not allow modification of its contents
then we cannot insert an event into it */
if (targetCalendar.allowsContentModifications == NO){
NSLog(@"The selected calendar does not allow modifications.");
return NO;
}

/* Create an event */
EKEvent *event = [EKEvent eventWithEventStore:eventStore];
event.calendar = targetCalendar;

/* Set the properties of the event such as its title,
start date/time, end date/time, etc. */
event.title = paramTitle;
event.notes = paramNotes;
event.startDate = paramStartDate;
event.endDate = paramEndDate;

/* Finally, save the event into the calendar */
NSError *saveError = nil;

result = [eventStore saveEvent:event
span:EKSpanThisEvent
error:&saveError];

if (result == NO){
NSLog(@"An error occurred = %@", saveError);
}

return result;

}
- (BOOL) removeEventWithTitle:(NSString *)paramTitle
startDate:(NSDate *)paramStartDate
endDate:(NSDate *)paramEndDate
inCalendarWithTitle:(NSString *)paramCalendarTitle
inCalendarWithType:(EKCalendarType)paramCalendarType
notes:(NSString *)paramNotes{

BOOL result = NO;

EKEventStore *eventStore = [[EKEventStore alloc] init];
16.4 Removing Events from Calendars | 715
www.it-ebooks.info

/* Are there any calendars available to the event store? */
if ([eventStore.calendars count] == 0){
NSLog(@"No calendars are found.");
return NO;
}

EKCalendar *targetCalendar = nil;

/* Try to find the calendar that the user asked for */
for (EKCalendar *thisCalendar in eventStore.calendars){
if ([thisCalendar.title isEqualToString:paramCalendarTitle] &&
thisCalendar.type == paramCalendarType){
targetCalendar = thisCalendar;
break;
}
}

/* Make sure we found the calendar that we were asked to find */
if (targetCalendar == nil){
NSLog(@"Could not find the requested calendar.");
return NO;
}

/* If a calendar does not allow modification of its contents
then we cannot insert an event into it */
if (targetCalendar.allowsContentModifications == NO){
NSLog(@"The selected calendar does not allow modifications.");
return NO;
}

NSArray *calendars = [[NSArray alloc] initWithObjects:targetCalendar, nil];

NSPredicate *predicate =
[eventStore predicateForEventsWithStartDate:paramStartDate
endDate:paramEndDate
calendars:calendars];

/* Get all the events that match the parameters */
NSArray *events = [eventStore eventsMatchingPredicate:predicate];

if ([events count] > 0){

/* Delete them all */
for (EKEvent *event in events){
NSError *removeError = nil;
/* Do not commit here, we will commit in batch after we have
removed all the events that matched our criteria */
if ([eventStore removeEvent:event
span:EKSpanThisEvent
commit:NO
error:&removeError] == NO){
NSLog(@"Failed to remove event %@ with error = %@",
event,
removeError);
716 | Chapter 16: Dates, Calendars, and Events
www.it-ebooks.info
}
}

NSError *commitError = nil;
if ([eventStore commit:&commitError]){
result = YES;
} else {
NSLog(@"Failed to commit the event store.");
}

} else {
NSLog(@"No events matched your input.");
}

return result;

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


NSDate *startDate = [NSDate date]; /* Now */

const NSTimeInterval NSOneHour = 60 * 60; /* 60 minutes, each 60 seconds */
NSDate *endDate = [startDate dateByAddingTimeInterval:NSOneHour];

BOOL createdSuccessfully = [self createEventWithTitle:@"Shopping"
startDate:startDate
endDate:endDate
inCalendarWithTitle:@"vandad.np@gmail.com"
inCalendarWithType:EKCalendarTypeCalDAV
notes:@"Get bread"];

if (createdSuccessfully){

NSLog(@"Successfully created the event.");

BOOL removedSuccessfully =
[self removeEventWithTitle:@"Shopping"
startDate:startDate
endDate:endDate
inCalendarWithTitle:@"vandad.np@gmail.com"
inCalendarWithType:EKCalendarTypeCalDAV
notes:@"Get bread"];


if (removedSuccessfully){
NSLog(@"Successfully removed the event.");
} else {
NSLog(@"Failed to remove the event.");
}

} else {
NSLog(@"Failed to create the event.");
16.4 Removing Events from Calendars | 717
www.it-ebooks.info
}

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

self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
In this example, we aie not committing the ueletion ol eveiy event one Ly one. Ve aie
simply setting the commit paiametei ol the removeEvent:span:commit:error: methou to
NO. Altei we aie uone, we aie invoking the commit: methou ol the event stoie explicitly.
The ieason loi this is that we uon`t ieally want to commit eveiy single ueletion. That
woulu cieate a lot ol oveiheau. Ve can uelete as many events as we neeu to, anu then
commit them all in one Latch.
See Also
Recipe 16.1; Recipe 16.3
16.5 Adding Recurring Events to Calendars
Problem
You want to auu a iecuiiing event to a calenuai.
Solution
In this example, we aie cieating an event that occuis on the same uay, eveiy month,
loi an entiie yeai. The steps aie as lollows:
1. Cieate an instance ol EKEventStore.
2. Finu a mouiliaLle calenuai insiue the calendars aiiay ol the event stoie (loi moie
inloimation, ielei to Recipe 16.1).
3. Cieate an oLject ol type EKEvent (loi moie inloimation, ielei to Recipe 16.2).
+. Set the appiopiiate values loi the event, such as its startDate anu endDate (loi moie
inloimation, ielei to Recipe 16.2).
5. Instantiate an oLject ol type NSDate that contains the exact uate when the iecuiience
ol this event enus. In this example, this uate is one yeai liom touay`s uate.
6. Use the recurrenceEndWithEndDate: class methou ol EKRecurrenceEnd anu pass the
NSDate you cieateu in step 5 to cieate an oLject ol type EKRecurrenceEnd.
7. Allocate anu then instantiate an oLject ol type EKRecurrenceRule using the initRe
currenceWithFrequency:interval:end: methou ol EKRecurrenceRule. Pass the
718 | Chapter 16: Dates, Calendars, and Events
www.it-ebooks.info
iecuiience enu uate that you cieateu in step 6 to the end paiametei ol this methou.
Foi moie inloimation aLout this methou, please ielei to this iecipe`s Discussion.
S. Assign the iecuiiing event that you cieateu in step 7 to the recurringRule piopeity
ol the EKEvent oLject that was cieateu in step 3.
9. Invoke the saveEvent:span:error: instance methou with the event (cieateu in step
3) as the saveEvent paiametei anu the value EKSpanFutureEvents loi the span pa-
iametei. This will cieate oui iecuiiing event loi us.
The lollowing coue illustiates these steps:
- (void) createRecurringEventInLocalCalendar{

/* Step 1: And now the event store */
EKEventStore *eventStore = [[EKEventStore alloc] init];

/* Step 2: Find the first local calendar that is modifiable */
EKCalendar *targetCalendar = nil;

for (EKCalendar *thisCalendar in eventStore.calendars){
if (thisCalendar.type == EKCalendarTypeLocal &&
[thisCalendar allowsContentModifications]){
targetCalendar = thisCalendar;
}
}

/* The target calendar wasn't found? */
if (targetCalendar == nil){
NSLog(@"The target calendar is nil.");
return;
}

/* Step 3: Create an event */
EKEvent *event = [EKEvent eventWithEventStore:eventStore];

/* Step 4: Create an event that happens today and happens
every month for a year from now */

NSDate *eventStartDate = [NSDate date];

/* Step 5: The event's end date is one hour from the moment it is created */
NSTimeInterval NSOneHour = 1 * 60 * 60;
NSDate *eventEndDate = [eventStartDate dateByAddingTimeInterval:NSOneHour];

/* Assign the required properties, especially
the target calendar */
event.calendar = targetCalendar;
event.title = @"My Event";
event.startDate = eventStartDate;
event.endDate = eventEndDate;

/* The end date of the recurring rule
is one year from now */
NSTimeInterval NSOneYear = 365 * 24 * 60 * 60;
16.5 Adding Recurring Events to Calendars | 719
www.it-ebooks.info
NSDate *oneYearFromNow = [eventStartDate dateByAddingTimeInterval:NSOneYear];

/* Step 6: Create an Event Kit date from this date */
EKRecurrenceEnd *recurringEnd =
[EKRecurrenceEnd recurrenceEndWithEndDate:oneYearFromNow];

/* Step 7: And the recurring rule. This event happens every
month (EKRecurrenceFrequencyMonthly), once a month (interval:1)
and the recurring rule ends a year from now (end:RecurringEnd) */

EKRecurrenceRule *recurringRule =
[[EKRecurrenceRule alloc]
initRecurrenceWithFrequency:EKRecurrenceFrequencyMonthly
interval:1
end:recurringEnd];

/* Step 8: Set the recurring rule for the event */
event.recurrenceRules = [[NSArray alloc] initWithObjects:recurringRule, nil];

NSError *saveError = nil;

/* Step 9: Save the event */
if ([eventStore saveEvent:event
span:EKSpanFutureEvents
error:&saveError]){
NSLog(@"Successfully created the recurring event.");
} else {
NSLog(@"Failed to create the recurring event %@", saveError);
}

}
Discussion
A iecuiiing event is an event that happens moie than once. Ve can cieate a iecuiiing
event just like a noimal event. Please ielei to Recipe 16.2 loi moie inloimation aLout
inseiting noimal events into the Calenuai uataLase. The only uilleience Letween a
iecuiiing event anu a noimal event is that you apply a iecuiiing iule to a iecuiiing
event. A iecuiiing iule tells the Event Kit liamewoik how the event has to occui in the
lutuie.
Ve cieate a iecuiiing iule Ly instantiating an oLject ol type EKRecurrenceRule using the
initRecurrenceWithFrequency:interval:end: initialization methou. The paiameteis loi
this methou aie:
initRecurrenceWithFrequency
Specilies whethei you want the event to Le iepeateu uaily (EKRecurrenceFre
quencyDaily), weekly (EKRecurrenceFrequencyWeekly), monthly (EKRecurrenceFre
quencyMonthly), oi yeaily (EKRecurrenceFrequencyYearly).
720 | Chapter 16: Dates, Calendars, and Events
www.it-ebooks.info
interval
A value gieatei than zeio that specilies the inteival Letween each occuiience`s stait
anu enu peiiou. Foi instance, il you want to cieate an event that happens eveiy
week, specily the EKRecurrenceFrequencyWeekly value with an interval ol 1. Il you
want this event to happen eveiy othei week, specily EKRecurrenceFrequency
Weekly with an interval ol 2.
end
A uate ol type EKRecurrenceEnd that specilies the uate when the iecuiiing event
enus in the specilieu calenuai. This paiametei is not the same as the event`s enu
uate (the endDate piopeity ol EKEvent). The enu uate ol an event specilies when
that specilic event enus in the calenuai, wheieas the end paiametei ol the initRe
currenceWithFrequency:interval:end: methou specilies the linal occuiience ol the
event in the uataLase.
Figuie 16-5 uepicts how oui iecuiiing event appeais in the Calenuai app on the uevice.
Iigurc 1-5. Ca|cndar app showing thc rccurring cvcnt wc crcatcd (My Evcnt)
By euiting this event (see Figuie 16-6) in the Calenuai application on an iOS uevice,
you can see that the event is tiuly a iecuiiing event that happens eveiy month, on the
same uay the event was cieateu, loi a whole yeai.
16.5 Adding Recurring Events to Calendars | 721
www.it-ebooks.info
See Also
Recipe 16.2
16.6 Retrieving the Attendees of an Event
Problem
You want to ietiieve the list ol attenuees loi a specilic event.
Solution
Use the attendees piopeity ol an instance ol EKEvent. This piopeity is ol type NSArray
anu incluues oLjects ol type EKParticipant.
The example coue that lollows will ietiieve all the events that happen touay (whatevei
the uay may Le) anu piint out uselul event inloimation, incluuing the attenuees ol that
event, to the console winuow:
- (EKCalendar *) calDAVCalendarWithTitleContaining
:(NSString *)paramDescription{

EKCalendar *result = nil;

Iigurc 1-. Editing a rccurring cvcnt in thc Ca|cndar app on an iOS dcvicc
722 | Chapter 16: Dates, Calendars, and Events
www.it-ebooks.info
EKEventStore *eventStore = [[EKEventStore alloc] init];

for (EKCalendar *thisCalendar in eventStore.calendars){
if (thisCalendar.type == EKCalendarTypeCalDAV){
if ([thisCalendar.title
rangeOfString:paramDescription].location != NSNotFound){
return thisCalendar;
}
}
}

return result;

}
- (void) enumerateTodayEvents{

/* Find a calendar to base our search on */
EKCalendar *targetCalendar =
[self calDAVCalendarWithTitleContaining:@"vandad.np@gmail.com"];

/* If we could not find a CalDAV calendar that
we were looking for, then we will abort the operation */
if (targetCalendar == nil){
NSLog(@"No CalDAV calendars were found.");
return;
}

/* We have to pass an array of calendars
to the event store to search */
NSArray *targetCalendars = [[NSArray alloc]
initWithObjects:targetCalendar, nil];

/* Instantiate the event store */
EKEventStore *eventStore = [[EKEventStore alloc] init];

/* Construct the starting date for today */
NSDate *startDate = [NSDate date];

/* The end date will be 1a day from now */
NSTimeInterval NSOneDay = 1 * 24 * 60 * 60;
NSDate *endDate = [startDate dateByAddingTimeInterval:NSOneDay];

/* Create the predicate that we can later pass to
the event store in order to fetch the events */
NSPredicate *searchPredicate =
[eventStore predicateForEventsWithStartDate:startDate
endDate:endDate
calendars:targetCalendars];

/* Make sure we succeeded in creating the predicate */
if (searchPredicate == nil){
NSLog(@"Could not create the search predicate.");
return;
}
16.6 Retrieving the Attendees of an Event | 723
www.it-ebooks.info

/* Fetch all the events that fall between the
starting and the ending dates */
NSArray *events = [eventStore eventsMatchingPredicate:searchPredicate];

/* Array of NSString equivalents of the values
in the EKParticipantRole enumeration */
NSArray *attendeeRole = [NSArray arrayWithObjects:
@"Unknown",
@"Required",
@"Optional",
@"Chair",
@"Non Participant",
nil];

/* Array of NSString equivalents of the values
in the EKParticipantStatus enumeration */
NSArray *attendeeStatus = [NSArray arrayWithObjects:
@"Unknown",
@"Pending",
@"Accepted",
@"Declined",
@"Tentative",
@"Delegated",
@"Completed",
@"In Process",
nil];

/* Array of NSString equivalents of the values
in the EKParticipantType enumeration */
NSArray *attendeeType = [NSArray arrayWithObjects:
@"Unknown",
@"Person",
@"Room",
@"Resource",
@"Group",
nil];

/* Go through all the events and print their information
out to the console */
if (events != nil){

NSUInteger eventCounter = 0;
for (EKEvent *thisEvent in events){

eventCounter++;

NSLog(@"Event %lu Start Date = %@",
(unsigned long)eventCounter,
thisEvent.startDate);

NSLog(@"Event %lu End Date = %@",
(unsigned long)eventCounter,
thisEvent.endDate);

724 | Chapter 16: Dates, Calendars, and Events
www.it-ebooks.info
NSLog(@"Event %lu Title = %@",
(unsigned long)eventCounter,
thisEvent.title);

if (thisEvent.attendees == nil ||
[thisEvent.attendees count] == 0){
NSLog(@"Event %lu has no attendees",
(unsigned long)eventCounter);
continue;
}

NSUInteger attendeeCounter = 1;
for (EKParticipant *participant in thisEvent.attendees){

NSLog(@"Event %lu Attendee %lu Name = %@",
(unsigned long)eventCounter,
(unsigned long)attendeeCounter,
participant.name);

NSLog(@"Event %lu Attendee %lu Role = %@",
(unsigned long)eventCounter,
(unsigned long)attendeeCounter,
[attendeeRole objectAtIndex:
participant.participantRole]);

NSLog(@"Event %lu Attendee %lu Status = %@",
(unsigned long)eventCounter,
(unsigned long)attendeeCounter,
[attendeeStatus objectAtIndex:
participant.participantStatus]);

NSLog(@"Event %lu Attendee %lu Type = %@",
(unsigned long)eventCounter,
(unsigned long)attendeeCounter,
[attendeeType objectAtIndex:
participant.participantType]);

NSLog(@"Event %lu Attendee %lu URL = %@",
(unsigned long)eventCounter,
(unsigned long)attendeeCounter,
participant.URL);

attendeeCounter++;

}

} /* for (EKEvent *Event in Events){ */

} else {
NSLog(@"The array of events is nil.");
}

}
- (BOOL) application:(UIApplication *)application
16.6 Retrieving the Attendees of an Event | 725
www.it-ebooks.info
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

[self enumerateTodayEvents];

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

self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Vhen we iun this coue on an iOS uevice with a couple ol events set up on a CalDAV
calenuai nameu vandad.np@gmail.com (ielei to this chaptei`s Intiouuction loi moie in-
loimation aLout CalDAV calenuais anu how you can set one up on youi iOS uevice),
we get iesults similai to these in the console winuow.
Discussion
Dilleient types ol calenuais, such as CalDAV, can incluue paiticipants in an event. iOS
allows useis to auu paiticipants to a calenuai on the seivei, although not to the calenuai
on the iOS uevice. You can uo this using Google Calenuai, loi instance.
Once the usei auus paiticipants to an event, you can use the attendees piopeity ol an
instance ol EKEvent to access the paiticipant oLjects ol type EKParticipant. Each pai-
ticipant has piopeities such as:
name
This is the name ol the paiticipant. Il you just specilieu the email auuiess ol a
peison to auu him to an event, this lielu will Le that email auuiess.
URL
This is usually the mailto URL loi the attenuee.
participantRole
This is the iole the attenuee plays in the event. Dilleient values that can Le applieu
to this piopeity aie listeu in the EKParticipantRole enumeiation.
participantStatus
This tells us whethei this paiticipant has accepteu oi ueclineu the event ieguest.
This piopeity coulu have othei values, all specilieu in the EKParticipantStatus
enumeiation.
participantType
This is ol type EKParticipantType, which is an enumeiation anu, as its name im-
plies, specilies the type ol paiticipant, such as gioup (EKParticipantTypeGroup) oi
inuiviuual peison (EKParticipantTypePerson).
See Also
Recipe 16.2; Recipe 16.3
726 | Chapter 16: Dates, Calendars, and Events
www.it-ebooks.info
16.7 Adding Alarms to Calendars
Problem
You want to auu alaims to the events in a calenuai.
Solution
Use the alarmWithRelativeOffset: class methou ol EKAlarm to cieate an instance ol
EKAlarm. Auu the alaim to an event using the addAlarm: instance methou ol EKEvent,
like so:
- (EKCalendar *) getFirstModifiableLocalCalendar{

EKCalendar *result = nil;

EKEventStore *eventStore = [[EKEventStore alloc] init];

for (EKCalendar *thisCalendar in eventStore.calendars){
if (thisCalendar.type == EKCalendarTypeLocal &&
[thisCalendar allowsContentModifications]){
return thisCalendar;
}
}

return result;

}
- (void) addAlarmToCalendar{

EKCalendar *targetCalendar = [self getFirstModifiableLocalCalendar];

if (targetCalendar == nil){
NSLog(@"Could not find the target calendar.");
return;
}

EKEventStore *eventStore = [[EKEventStore alloc] init];

/* The event starts 60 seconds from now */
NSDate *startDate = [NSDate dateWithTimeIntervalSinceNow:60.0f];

/* And end the event 20 seconds after its start date */
NSDate *endDate = [startDate dateByAddingTimeInterval:20.0f];

EKEvent *eventWithAlarm = [EKEvent eventWithEventStore:eventStore];

eventWithAlarm.calendar = targetCalendar;
eventWithAlarm.startDate = startDate;
eventWithAlarm.endDate = endDate;

/* The alarm goes off two seconds before the event happens */
16.7 Adding Alarms to Calendars | 727
www.it-ebooks.info
EKAlarm *alarm = [EKAlarm alarmWithRelativeOffset:-2.0f];

eventWithAlarm.title = @"Event with Alarm";
[eventWithAlarm addAlarm:alarm];

NSError *saveError = nil;

if ([eventStore saveEvent:eventWithAlarm
span:EKSpanThisEvent
error:&saveError]){
NSLog(@"Saved an event that fires 60 seconds from now.");
} else {
NSLog(@"Failed to save the event. Error = %@", saveError);
}


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

[self addAlarmToCalendar];

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

self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Discussion
An event ol type EKEvent can have multiple alaims. Simply cieate the alaim using eithei
the alarmWithAbsoluteDate: oi alarmWithRelativeOffset: class methou ol EKAlarm. The
loimei methou ieguiies an aLsolute uate anu time (you can use the CFAbsoluteTimeGet
Current lunction to get the cuiient aLsolute time), wheieas the lattei methou ieguiies
a numLei ol seconus ielative to the stait uate ol the event when the alaim must Le liieu.
Foi instance, il the event is scheuuleu loi touay at 6:00 a.m., anu we go aheau anu
cieate an alaim with the ielative ollset ol -60 (which is counteu in units ol seconus),
oui alaim will Le liieu at 5:59 a.m. the same uay. Only zeio anu negative numLeis aie
alloweu loi this ollset. Positive numLeis will automatically Le changeu to zeio Ly iOS.
Once an alaim is liieu, iOS will uisplay the alaim to the usei, as shown in Figuie 16-7.
You can use the removeAlarm: instance methou ol EKEvent to iemove an alaim associateu
with that event instance.
See Also
Recipe 16.1
728 | Chapter 16: Dates, Calendars, and Events
www.it-ebooks.info
16.8 Handling Event Changed Notifications
Problem
You want to get notilieu in youi application when the usei changes the contents ol the
Calenuai uataLase.
Solution
Registei loi the EKEventStoreChangedNotification notilication:
- (EKCalendar *)
calDAVCalendarWithTitleContaining:(NSString *)paramDescription
inEventStore:(EKEventStore *)paramEventStore{

EKCalendar *result = nil;

for (EKCalendar *thisCalendar in paramEventStore.calendars){
if (thisCalendar.type == EKCalendarTypeCalDAV){
if ([thisCalendar.title
rangeOfString:paramDescription].location != NSNotFound){
return thisCalendar;
}
}
}

Iigurc 1-7. iOS disp|aying an a|crt on thc scrccn whcn an a|arn is jircd
16.8 Handling Event Changed Notifications | 729
www.it-ebooks.info
return result;

}
- (void) eventsChanged:(NSNotification *)paramNotification{

NSMutableArray *invalidatedEvents = [[NSMutableArray alloc] init];

NSLog(@"Refreshing array of events...");

for (EKEvent *event in self.eventsForOneYear){
if ([event refresh] == NO){
[invalidatedEvents addObject:event];
}
}

if ([invalidatedEvents count] > 0){
[self.eventsForOneYear removeObjectsInArray:invalidatedEvents];
}

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

self.eventStore = [[EKEventStore alloc] init];

EKCalendar *calendar =
[self calDAVCalendarWithTitleContaining:@"vandad.np@gmail.com"
inEventStore:self.eventStore];

NSTimeInterval NSOneYear = 1 * 365 * 24 * 60 * 60;

NSDate *startDate = [NSDate date];
NSDate *endDate = [startDate dateByAddingTimeInterval:NSOneYear];

NSArray *calendars = [[NSArray alloc] initWithObjects:calendar, nil];

NSPredicate *predicate =
[self.eventStore predicateForEventsWithStartDate:startDate
endDate:endDate
calendars:calendars];

NSArray *events = [self.eventStore eventsMatchingPredicate:predicate];

self.eventsForOneYear = [[NSMutableArray alloc] initWithArray:events];

[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(eventsChanged:)
name:EKEventStoreChangedNotification
object:nil];

self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
730 | Chapter 16: Dates, Calendars, and Events
www.it-ebooks.info

self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Discussion
Multitasking is possiLle on iOS. Imagine you have letcheu a seiies ol events liom
EKEventStore into an aiiay anu you allow youi usei to woik with them (euit them, auu
to them, anu iemove liom them). The usei coulu simply switch liom youi applica-
tion to the Calenuai application anu uelete the same event she is tiying to uelete in youi
application. Such a seguence ol activities will geneiate an EKEventStoreChangedNotifi
cation notilication that you can choose to ieceive.
The EKEventStoreChangedNotification notilication will Le sent to youi application (at
least, il you suLsciiLe to this notilication) even il youi application is in the loiegiounu.
Because ol this, you must make suie you tieat this notilication uilleiently uepenuing
on whethei youi application is in the Lackgiounu oi the loiegiounu. Heie aie a couple
ol things to consiuei:
Il you ieceive the EKEventStoreChangedNotification notilication while youi appli-
cation is in the loiegiounu, it is Lest to implement a mechanism to linu out whethei
the changes to the event stoie oiiginateu insiue youi own application oi came liom
someone else outsiue the application. Il they came liom outsiue the application,
you must make suie you aie ietaining the latest veision ol the events in the stoie,
anu not the olu events. Il loi any ieason you copieu one ol the events in the event
stoie anu kept the copy somewheie, you must call the refresh instance methou ol
that event ol type EKEvent. Il the ietuin value ol this methou is YES, you can keep
the oLject in memoiy. Il the ietuin value is NO, you must uispose ol the oLject,
Lecause someone outsiue youi application has ueleteu oi somehow invaliuateu the
event.
Il you ieceive the EKEventStoreChangedNotification notilication while youi appli-
cation is in the Lackgiounu, accoiuing to uocumentation liom Apple, youi appli-
cation shoulu not attempt to uo any GUI-ielateu piocessing anu shoulu, in lact,
use as little piocessing powei as possiLle. You must theieloie ieliain liom auuing
new scieens to, oi mouilying in any way, the GUI ol youi application.
Il you ieceive the EKEventStoreChangedNotification notilication while youi appli-
cation is in the Lackgiounu, you must make note ol it insiue the application
(peihaps stoie this in a piopeity ol type BOOL) anu ieact to this change when the
application is Liought to the loiegiounu again. Noimally, il you ieceive any noti-
lication aLout a change to an event while you aie in the Lackgiounu, you shoulu
ietiieve all events stoieu in the application when you ietuin to the loiegiounu.
16.8 Handling Event Changed Notifications | 731
www.it-ebooks.info
Coalescing is not enaLleu on the EKEventStoreChangedNotification
event stoie notilication. In othei woius, you can ieceive multiple noti-
lications ol the same type il a single event changes in the Calenuai
uataLase. It is up to you to ueteimine how anu when you neeu to ieletch
youi ietaineu events.
16.9 Presenting Event View Controllers
Problem
You want to use the Luilt-in iOS SDK view contiolleis to uisplay the piopeities ol an
event in the Calenuai uataLase.
Solution
Cieate an instance ol EKEventViewController anu push it into a navigation contiollei
oi piesent it as a moual view contiollei on anothei view contiollei.
Discussion
Useis ol iOS uevices aie alieauy lamiliai with the inteilace they see on the Calenuai
application. Vhen they select an event, they can see that event`s piopeities anu they
might Le alloweu to mouily the event. To piesent a view to a usei using Luilt-in iOS
SDK event view contiolleis, we can instantiate an oLject ol type EKEventView
Controller anu assign an event ol type EKEvent to its event piopeity. Once that`s uone,
we can push the event view contiollei into oui navigation contiollei anu let iOS take
caie ol the iest.
Ve want to linu an event (any event) in any ol the calenuais availaLle on an iOS uevice,
liom one yeai ago to now. Ve will use EKEventViewController to piesent that event to
the usei. Heie is the .h lile ol oui view contiollei:
#import <UIKit/UIKit.h>
#import <EventKit/EventKit.h>
#import <EventKitUI/EventKitUI.h>
@interface Presenting_Event_View_ControllersViewController
: UIViewController <EKEventViewDelegate>
@property (nonatomic, strong) EKEventStore *eventStore;
@end
Now in the viewDidLoad methou ol oui view contiollei, let`s go aheau anu uisplay the
instance ol EKEventViewController on the liist event we linu in any ol the calenuais on
the uevice, liom a yeai ago:
- (void)viewDidLoad{
[super viewDidLoad];
732 | Chapter 16: Dates, Calendars, and Events
www.it-ebooks.info
self.eventStore = [[EKEventStore alloc] init];

NSTimeInterval NSOneYear = 1 * 365 * 24.0f * 60.0f * 60.0f;
NSDate *startDate = [[NSDate date] dateByAddingTimeInterval:-NSOneYear];
NSDate *endDate = [NSDate date];

NSPredicate *predicate =
[self.eventStore predicateForEventsWithStartDate:startDate
endDate:endDate
calendars:self.eventStore.calendars];

NSArray *events = [self.eventStore eventsMatchingPredicate:predicate];

if ([events count] > 0){
EKEvent *event = [events objectAtIndex:0];
EKEventViewController *controller = [[EKEventViewController alloc] init];
controller.event = event;
controller.allowsEditing = NO;
controller.allowsCalendarPreview = YES;
controller.delegate = self;

[self.navigationController pushViewController:controller
animated:YES];
}

}
Last Lut not least, as you can see in the coue, we have Lecome the uelegate oLject ol
the event view contiollei, so let`s make suie we aie hanuling the uelegate methous il
ieguiieu:
- (void)eventViewController:(EKEventViewController *)controller
didCompleteWithAction:(EKEventViewAction)action{

switch (action){

case EKEventViewActionDeleted:{
NSLog(@"User deleted the event.");
break;
}
case EKEventViewActionDone:{
NSLog(@"User finished viewing the event.");
break;
}
case EKEventViewActionResponded:{
NSLog(@"User responsed to the invitation in the event.");
break;
}

}

}
Once we iun this application on an iOS uevice, we can see the Luilt-in event view
contiollei uisplaying the contents ol the event that we have lounu (see Figuie 16-S).
16.9 Presenting Event View Controllers | 733
www.it-ebooks.info
Dilleient piopeities ol an instance ol EKEventViewController that we can use to change
the Lehavioi ol this oLject aie as lollows:
allowsEditing
Il this piopeity`s value is set to YES, the Euit Lutton will appeai on the navigation
Lai ol the event view contiollei, allowing the usei to euit the event. This happens
only on mouiliaLle calenuais anu only loi events that have Leen cieateu Ly the usei
on this uevice. Foi instance, il you cieate an event on the VeL using Google Cal-
enuai anu the event appeais in youi iOS uevice, you aie not alloweu to euit that
event.
allowsCalendarPreview
Il this piopeity`s value is set to YES anu the event the usei is viewing is an invitation,
the usei will Le given the option to view this cuiient event in a calenuai with othei
events that have Leen scheuuleu on the same uate.
event
This piopeity must Le set Leloie piesenting the event view contiollei. This will Le
the event that the event view contiollei will uisplay to the usei.
Vhen you push the event view contiollei, the Back Lutton will appeai with the title
Back Ly uelault, so you uo not have to change it manually. Howevei, il you ueciue
to change the Back Lutton, you can uo so Ly assigning a new oLject ol type
UIBarButtonItem to the backBarButtonItem piopeity ol youi navigation item. In oui
Iigurc 1-8. Thc bui|t-in iOS cvcnt vicw contro||cr
734 | Chapter 16: Dates, Calendars, and Events
www.it-ebooks.info
example coue, we can mouily the pushController: methou to give oui ioot view con-
tiollei a custom Back Lutton Leloie pushing the event view contiollei.
- (void)viewDidLoad{
[super viewDidLoad];

self.eventStore = [[EKEventStore alloc] init];

NSTimeInterval NSOneYear = 1 * 365 * 24.0f * 60.0f * 60.0f;
NSDate *startDate = [[NSDate date] dateByAddingTimeInterval:-NSOneYear];
NSDate *endDate = [NSDate date];

NSPredicate *predicate =
[self.eventStore predicateForEventsWithStartDate:startDate
endDate:endDate
calendars:self.eventStore.calendars];

NSArray *events = [self.eventStore eventsMatchingPredicate:predicate];

if ([events count] > 0){
EKEvent *event = [events objectAtIndex:0];
EKEventViewController *controller = [[EKEventViewController alloc] init];
controller.event = event;
controller.allowsEditing = YES;
controller.allowsCalendarPreview = YES;
controller.delegate = self; self.navigationItem.backBarButtonItem =
[[UIBarButtonItem alloc] initWithTitle:@"Go Back"
style:UIBarButtonItemStylePlain
target:nil
action:nil];

[self.navigationController pushViewController:controller
animated:YES];
}

}
The iesults ol this mouilication aie uepicteu in Figuie 16-9 (please note that in this
example, euiting is enaLleu loi the event view contiollei).
See Also
Recipe 16.10
16.10 Presenting Event Edit View Controllers
Problem
You want to allow youi useis to euit (inseit, uelete, anu mouily) events in the Calenuai
uataLase liom insiue youi application, using Luilt-in SDK view contiolleis.
16.10 Presenting Event Edit View Controllers | 735
www.it-ebooks.info
Solution
Instantiate an oLject ol type EKEventEditViewController anu piesent it on a navigation
contiollei using the presentModalViewController:animated: instance methou ol
UINavigationController.
Discussion
An instance ol the EKEventEditViewController class allows us to piesent an event euit
view contiollei to the usei. This view contiollei, uepenuing on how we set it up, can
allow the usei to eithei euit an existing event oi cieate a new event. Il you want this
view contiollei to euit an event, set the event piopeity ol this instance to an event oLject.
Il you want the usei to Le aLle to inseit a new event into the system, set the event
piopeity ol this instance to nil.
The editViewDelegate piopeity ol an instance ol EKEventEditViewController is the oL-
ject that will ieceive uelegate messages liom this view contiollei telling the piogiammei
aLout the action the usei has taken. One ol the most impoitant uelegate messages youi
uelegate oLject must hanule (a ieguiieu uelegate selectoi) is the eventEditViewControl
ler:didCompleteWithAction: methou. This uelegate methou will Le calleu whenevei the
usei uismisses the event euit view contiollei in one ol the possiLle ways inuicateu Ly
the didCompleteWithAction paiametei. This paiametei can have values such as the
lollowing:
EKEventEditViewActionCanceled
The usei piesseu the Cancel Lutton on the view contiollei.
Iigurc 1-9. An cdit vicw contro||cr with cditing cnab|cd and a custon bac| button
736 | Chapter 16: Dates, Calendars, and Events
www.it-ebooks.info
EKEventEditViewActionSaved
The usei saveu (auueu/mouilieu) an event in the Calenuai uataLase.
EKEventEditViewActionDeleted
The usei ueleteu an event liom the Calenuai uataLase.
Please make suie to uismiss the event euit view contiollei altei ieceiving this uelegate
message, il you aie uisplaying the euit view contiollei as a moual view contiollei.
So let`s go aheau anu ueline oui view contiollei:
#import <UIKit/UIKit.h>
#import <EventKit/EventKit.h>
#import <EventKitUI/EventKitUI.h>
@interface Presenting_Event_Edit_View_ControllersViewController
: UIViewController <EKEventEditViewDelegate>
@property (nonatomic, strong) EKEventStore *eventStore;
@end
Now let`s tiy to linu the liist event liom a yeai ago (whatevei event that might Le) anu
allow the usei to euit that event Ly uisplaying an euit event view contiollei:
- (void)eventEditViewController:(EKEventEditViewController *)controller
didCompleteWithAction:(EKEventEditViewAction)action{

switch (action){

case EKEventEditViewActionCanceled:{
NSLog(@"Cancelled");
break;
}
case EKEventEditViewActionSaved:{
NSLog(@"Saved");
break;
}
case EKEventEditViewActionDeleted:{
NSLog(@"Deleted");
break;
}

}

}
- (void)viewDidLoad{
[super viewDidLoad];

self.eventStore = [[EKEventStore alloc] init];

NSTimeInterval NSOneYear = 1 * 365 * 24.0f * 60.0f * 60.0f;
NSDate *startDate = [[NSDate date] dateByAddingTimeInterval:-NSOneYear];
NSDate *endDate = [NSDate date];

16.10 Presenting Event Edit View Controllers | 737
www.it-ebooks.info
NSPredicate *predicate =
[self.eventStore predicateForEventsWithStartDate:startDate
endDate:endDate
calendars:self.eventStore.calendars];

NSArray *events = [self.eventStore eventsMatchingPredicate:predicate];

if ([events count] > 0){
EKEvent *event = [events objectAtIndex:0];
EKEventEditViewController *controller =
[[EKEventEditViewController alloc] init];

controller.event = event;
controller.editViewDelegate = self;

[self.navigationController presentModalViewController:controller
animated:YES];
}

}
Depenuing on the event that is lounu on the uevice, the usei will see something similai
to Figuie 16-10.
Iigurc 1-10. An cdit cvcnt vicw contro||cr disp|aying an cvcnt
See Also
Recipe 16.9
738 | Chapter 16: Dates, Calendars, and Events
www.it-ebooks.info
CHAPTER 17
Graphics and Animations
17.0 Introduction
You`ve ceitainly seen applications with Leautilul giaphics ellects on iPhones oi iPaus.
Anu you`ve pioLaLly also encounteieu impiessive animations in games anu othei apps.
Voiking togethei, the iOS iuntime anu Cocoa piogiamming liamewoiks make pos-
siLle an amazing vaiiety ol giaphics anu animation ellects with ielatively simple couing.
The guality ol these giaphics anu animations uepenus paitly, ol couise, on the aesthetic
sensitivities ol the piogiammei anu aitistic collaLoiatois. But in this chaptei, you`ll see
how much you can accomplish with mouest piogiamming skills.
I`ll uispense with conceptual Lackgiounu, pieleiiing to intiouuce iueas such as coloi
spaces, tiansloimation, anu the giaphics context as we go along. I`ll just mention a lew
Lasics Leloie leaping into coue.
In Cocoa Touch, an app is maue up ol windows anu vicws. An app with a UI has at
least one winuow that contains, in tuin, one oi moie views. In Cocoa Touch, a winuow
is an instance ol UIWindow. Usually, an app will open to the main winuow anu the
piogiammei will then auu views to the winuow to iepiesent uilleient paits ol the UI:
paits such as Luttons, laLels, images, anu custom contiols. All these UI-ielateu com-
ponents aie hanuleu anu uiawn Ly UIKit.
Some ol these things might sounu ielatively uillicult to unueistanu, Lut I piomise you
that as we pioceeu thiough this chaptei, you will unueistanu them step-Ly-step with
the many examples I will give.
Apple has pioviueu uevelopeis with poweilul liamewoiks that hanule giaphics anu
animations in iOS anu OS X. Some ol these liamewoiks anu technologies aie:
U|Kit
The high-level liamewoik that allows uevelopeis to cieate views, winuows, Lut-
tons, anu othei UI ielateu components. It also incoipoiates some ol the low-level
APIs into an easiei-to-use high-level API.
739
www.it-ebooks.info
Quartz 2D
The main engine iunning unuei the hoou to lacilitate uiawing in iOS; UIKit uses
Quaitz.
Corc Graphics
A liamewoik that suppoits the giaphics context (moie on this latei), loauing im-
ages, uiawing images, anu so on.
Corc Anination
A liamewoik that, as its name implies, lacilitates animations in iOS.
Vhen uiawing on a scieen, one ol the most impoitant concepts to giasp is the ielation
Letween points anu pixels. I`m suie you`ie lamiliai with pixels, Lut what aie points?
They`ie the uevice-inuepenuent counteipait ol pixels. Foi instance, compaie the
iPhone 3GS to the iPhone +. Both uevices have 3.5-inch uisplays. Howevei, the numLei
ol pixels that iPhone 3GS can uiaw in poitiait moue is 320+S0. The same scieen size
on the iPhone + is capaLle ol uiawing twice as many, oi 6+0960, pixels in poitiait
moue.
Now imagine you aie wiiting an iPhone app that has only one scieen, anu that you aie
simply lilling the whole scieen with the coloi gieen. Imagine that you navely specily a
iectangulai aiea ol 320+S0 pixels. Vhen iPhone 3GS useis iun youi app, they will Le
guite happy Lecause it uoes what it says it uoes: lill the entiie scieen with the coloi
gieen. iPhone + useis, on the othei hanu, will Le guite unhappy: what they will see is
guite uilleient, as shown in Figuie 17-1.
Iigurc 17-1. Dcvicc-dcpcndcnt pixc| rcndcring yic|ds dijjcrcnt rcsu|ts on dijjcrcnt dcviccs
740 | Chapter 17: Graphics and Animations
www.it-ebooks.info
To iemeuy this pioLlem, Apple intiouuceu uevice-inuepenuent uiawing methous to
help uevelopeis locus on how theii shapes anu giaphics have to appeai on a uevice
insteau ol woiiying aLout the scieen sizes anu iesolutions ol uilleient uevices that iun
the same coue. To lix the issue we saw in Figuie 17-1, the uevelopei ol the app can
simply use the ielevant APIs to specily the gieen iectangle in points insteau ol pixels.
That will allow the same coue to iun on the iPhone 3GS anu the iPhone +, ensuiing
that the scieen on the iPhone + will Le lilleu with the iectangle. Foi this ieason, many
ol the methous that you will see in this chaptei will iely on points (oi as Apple calls
them, |ogica| points) insteau ol pixels.
The oiigin point ol the scieen on an iOS uevice is the top-lelt coinei.
Scieens whose uiawing oiigin is on the top-lelt coinei aie also ieleiieu
to as Uppei Lelt Oiigin, oi ULO, scieens. This means that point (0, 0)
is the topmost anu the leltmost point on the scieen, anu that positive
values ol the x axis extenu towaius the iight, while positive values ol
the y axis extenu towaius the Lottom. In othei woius, an x position ol
20 is luithei iight on the scieen than a position ol 10 is. On the y axis,
point 20 is luithei uown than point 10.
In this chaptei, we will Le using view oLjects ol type UIView to uiaw shapes, stiings,
anu eveiything else that`s visiLle on the scieen.
I assume you have the latest Xcoue liom Apple. Il not, please heau to
Xcoue`s weLsite anu uownloau it.
In oiuei to Le aLle to incoipoiate some ol these coue snippets in an application, I will
liist show you the ieguiieu steps to cieate a new pioject in Xcoue anu suLclass
UIView, wheie we can place the coue:
1. Open Xcoue.
2. Fiom the File menu, select New Pioject.
3. On the lelt siue ol the scieen, make suie the iOS categoiy is selecteu. Select Ap-
plication unuei that categoiy (see Figuie 17-2).
+. On the iight siue ol the scieen, select Single View Application, anu piess Next (see
Figuie 17-2).
17.0 Introduction | 741
www.it-ebooks.info
Iigurc 17-2. Crcating a Sing|c \icw App|ication jor iOS in Xcodc
5. In the Piouuct Name Lox (Figuie 17-3), select a name loi youi pioject. I`ve enteieu
Graphics, anu I suggest you choose the same name to avoiu conlusion latei on.
Iigurc 17-3. Sctting thc options jor a ncw projcct in Xcodc
742 | Chapter 17: Graphics and Animations
www.it-ebooks.info
6. In the Company Iuentiliei Lox, entei a Lunule iuentiliei pielix, which will Le pie-
penueu to the Piouuct Name you chose. This is usually com.company. I have chosen
com.pixolity. Xcoue usually will pick this up automatically loi you.
7. In the Device Family, select iPhone, anu then piess Next.
S. On the next scieen (Figuie 17-+), select wheie you want to save youi pioject anu
piess Cieate.
Iigurc 17-1. Saving thc Xcodc projcct on dis|
Now youi Xcoue pioject is open. On the lelt siue ol Xcoue, expanu the Giaphics gioup
to ieveal all the liles that Xcoue cieateu when you cieateu the pioject. Now we shall
cieate a view oLject loi the view contiollei. Please lollow these steps to uo so:
1. Select the Giaphics gioup liom the lelthanu siue in Xcoue.
2. Right-click on the Giaphics gioup anu select New File..
3. In the New File uialog Lox, make suie iOS is selecteu as the categoiy on the lelt
siue, anu select Cocoa Touch as the suLcategoiy (see Figuie 17-5).
+. On the iight siue, select OLjective-C class, anu then piess Next (see Figuie 17-5).
17.0 Introduction | 743
www.it-ebooks.info
Iigurc 17-5. Crcating a ncw Objcctivc-C c|ass in Xcodc
5. In the next scieen (Figuie 17-6), make suie that the SuLclass Lox has UIView wiitten
insiue it, anu then piess Next.
Iigurc 17-. Crcating a subc|ass oj U|\icw
744 | Chapter 17: Graphics and Animations
www.it-ebooks.info
6. In the Save As uialog, set the lile name to Graphics\icwContro||cr\icw.n.
7. Select Giaphics in the Gioup uiop-uown Lox (see Figuie 17-7).
S. Make suie the Auu to taigets checkLox is selecteu loi the pioject that we cieateu
eailiei, anu then piess Save (see Figuie 17-7).
Iigurc 17-7. Saving a subc|ass oj U|\icw to dis|
9. On the lelt siue ol Xcoue`s main winuow, click on the Graphics\icwContro|-
|cr.xib lile. Inteilace Builuei will Le uisplayeu on the iight siue ol Xcoue`s scieen,
as shown in Figuie 17-S. Ve will not Le using the .xib lile at this point.
10. Fiom the Xcoue menu, select View Utilities File Inspectoi. The lile inspectoi
will Le uisplayeu, Ly uelault, on the iight siue ol Xcoue`s winuow.
11. Click somewheie insiue the giay view that is cieateu loi you in Inteilace Builuei.
The contents uisplayeu in File Inspectoi (on the iight) will change to iellect youi
selection (see Figuie 17-9).
17.0 Introduction | 745
www.it-ebooks.info
Iigurc 17-8. Sc|ccting thc xib ji|c oj thc vicw contro||cr
Iigurc 17-9. Thc ji|c inspcctor in |ntcrjacc Bui|dcr
12. In File Inspectoi, choose the Iuentity Inspectoi taL on top (see Figuie 17-10).
746 | Chapter 17: Graphics and Animations
www.it-ebooks.info
Iigurc 17-10. Thc |dcntity |nspcctor shows injornation jor thc vicw objcct
13. In the Class Lox, unuei the Custom Class section, entei GraphicsViewController
View (the view oLject we cieateu Leloie), anu piess Retuin on youi keyLoaiu.
Now we aie ieauy to stait couing. Vhat we uiu was simply cieate a view class ol type
UIView so that latei in this chaptei, we can change the coue in that class. Then we useu
Inteilace Builuei to set the view contiollei`s view class to the same view oLject that we
cieateu. This means that the view contiollei`s view will now Le an instance ol the
GraphicsViewControllerView class that we cieateu.
You have pioLaLly alieauy lookeu at the contents ol the view oLject that Xcoue gen-
eiateu. One ol the most impoitant methous insiue this oLject is drawRect:. Cocoa
Touch automatically calls this methou whenevei it is time to uiaw the view, anu uses
it to ask the view oLject to uiaw its contents on the giaphical context that Cocoa Touch
automatically piepaies loi the view. A giaphical context can Le thought ol as a canvas,
olleiing an enoimous numLei ol piopeities such as pen coloi, pen thickness, etc. Given
the context, you can stait painting stiaight away insiue the drawRect: methou, anu
Cocoa Touch will make suie that the attiiLutes anu piopeities ol the context aie applieu
to youi uiawings. Ve will talk aLout this moie latei, Lut loi now, let`s move on to moie
inteiesting suLjects.
17.1 Enumerating and Loading Fonts
Problem
You want to use lonts which come pie-installeu on an iOS uevice, in oiuei to ienuei
some text on the scieen.
Solution
Use the UIFont class.
17.1 Enumerating and Loading Fonts | 747
www.it-ebooks.info
Discussion
Fonts aie lunuamental to uisplaying text on a giaphical usei inteilace. The UIKit
liamewoik pioviues piogiammeis with high-level APIs that lacilitate the enumeiating,
loauing, anu use ol lonts. Fonts aie encapsulateu in the UIFont class in Cocoa Touch.
Each iOS uevice comes with Luilt-in system lonts. Fonts aie oiganizeu into jani|ics,
anu each lamily contains jaccs. Foi instance, Helvetica is a lont lamily, anu Helvetica
Bo|d is one ol the laces ol the Helvetica lamily. To Le aLle to loau a lont, you must
know the lont`s lace (that is, its name)anu to know the lace, you have to know the
lamily. So liist, let`s enumeiate all the lont lamilies that aie installeu on the uevice,
using the familyNames class methou ol the UIFont class:
- (void) enumerateFonts{
for (NSString *familyName in [UIFont familyNames]){
NSLog(@"Font Family = %@", familyName);
}
}
Running this piogiam in iOS Simulatoi, I get iesults similai to this:
Font Family = Heiti TC
Font Family = Sinhala Sangam MN
Font Family = Kannada Sangam MN
Font Family = Georgia
Font Family = Heiti J
Font Family = Times New Roman
Font Family = Snell Roundhand
Font Family = Geeza Pro
Font Family = Helvetica Neue
...
Altei getting the lont lamilies, we can enumeiate the lont names insiue each lamily.
Ve`ll use the fontNamesForFamilyName: class methou ol the UIFont class, anu get Lack
an aiiay ol lont names loi the lamily name that we pass as a paiametei:
- (void) enumerateFonts{
for (NSString *familyName in [UIFont familyNames]){
NSLog(@"Font Family = %@", familyName);
for (NSString *fontName in
[UIFont fontNamesForFamilyName:familyName]){
NSLog(@"\t%@", fontName);
}
}
}
Running this coue in iOS Simulatoi gives me the lollowing iesults:
...
Font Family = Geeza Pro
748 | Chapter 17: Graphics and Animations
www.it-ebooks.info
GeezaPro
GeezaPro-Bold
Font Family = Helvetica Neue
HelveticaNeue-Italic
HelveticaNeue-Bold
HelveticaNeue-BoldItalic
HelveticaNeue
...
So as you can see, Hc|vctica Ncuc is the lont lamily anu Hc|vcticaNcuc-Bo|d is one ol
the lont names in this lamily. Now that we know the lont name, we can loau the lonts
into oLjects ol type UIFont using the fontWithName:size: class methou ol the UIFont
class:
UIFont *helveticaBold = [UIFont fontWithName:@"HelveticaNeue-Bold"
size:12.0f];
Il the iesult ol the fontWithName:size: class methou ol the UIFont class
is nil, the given lont name coulu not Le lounu. Make suie that the lont
name you have pioviueu is availaLle in the system Ly liist enumeiating
all the lont lamilies anu then all lont names availaLle in each lamily.
You can also use the systemFontOfSize: instance methou ol the UIFont class (oi its Lolu
alteinative, boldSystemFontOfSize:) to loau local system lonts, whatevei they might Le,
liom the uevice that is iunning youi coue. The uelault system lont loi iOS uevices is
Helvetica.
Altei you have loaueu lonts, you can pioceeu to Recipe 17.2, wheie we will use the
lonts that we loaueu heie in oiuei to uiaw text on a giaphical context.
See Also
Recipe 17.2
17.2 Drawing Text
Problem
You want to Le aLle to uiaw text on the scieen ol an iOS uevice.
Solution
Use the drawAtPoint:withFont: methou ol NSString.
Discussion
To uiaw text, we can use some ieally hanuy methous Luilt into the NSString class, such
as drawAtPoint:withFont:. Beloie we pioceeu luithei, make suie that you have lolloweu
17.2 Drawing Text | 749
www.it-ebooks.info
the instiuctions in Recipe 17.0. You shoulu now have a view oLject, suLclasseu liom
UIView, nameu GraphicsViewControllerView. Open that lile. Il the drawRect: instance
methou ol the view oLject is commenteu out, iemove the comments until you have that
methou in youi view oLject:
#import "GraphicsViewControllerView.h"
@implementation GraphicsViewControllerView
- (id)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
- (void)drawRect:(CGRect)rect{
}
@end
The drawRect: methou is wheie we`ll uo the uiawing, as mentioneu Leloie. Heie, we
can stait loauing the lont, anu then uiaw a simple stiing on the scieen at point +0 on
the x axis anu 1S0 on the y axis (Figuie 17-11):
- (void)drawRect:(CGRect)rect{
UIFont *helveticaBold = [UIFont fontWithName:@"HelveticaNeue-Bold"
size:40.0f];
NSString *myString = @"Some String";
[myString drawAtPoint:CGPointMake(40, 180)
withFont:helveticaBold];
}
In this coue, we aie simply loauing a Lolu Helvetica lont at size +0, anu using it to uiaw
the text Some String at point (+0, 1S0).
17.3 Constructing, Setting, and Using Colors
Problem
You want to Le aLle to oLtain ieleiences to coloi oLjects in oiuei to use them while
you aie uiawing vaiious loims on a view, such as text, iectangles, tiiangles, anu line
segments.
750 | Chapter 17: Graphics and Animations
www.it-ebooks.info
Solution
Use the UIColor class.
Discussion
UIKit pioviues piogiammeis with a high-level aLstiaction ol colois, encapsulateu in
the UIColor oLject. This class has a lew ieally hanuy class methous such as redColor,
blueColor, brownColor, anu yellowColor. Howevei, il the coloi you aie looking loi isn`t
one ol the explicitly nameu UIColor methous, you can always use the color
WithRed:green:blue:alpha: class methou ol UIColor class to loau the coloi that you aie
looking loi. The ietuin value ol this class methou is a value ol type UIColor. The pa-
iameteis ol this methou aie:
red
The amount ol ieu to use in the coloi. This value can Le anything Letween 0.0f to
1.0f, wheie 0.0f omits all ieu anu 1.0f makes the ieu component as uaik as
possiLle.
green
The amount ol gieen to mix with the ieu in the coloi. This value also ianges liom
0.0f to 1.0f.
blue
The amount ol Llue to mix with the ieu anu gieen in the coloi. This value also
ianges liom 0.0f to 1.0f.
Iigurc 17-11. A randon string drawn on thc graphica| contcxt oj a vicw
17.3 Constructing, Setting, and Using Colors | 751
www.it-ebooks.info
alpha
The opagueness ol the coloi. This value can iange liom 0.0f to 1.0f, with 1.0f
making the coloi completely opague anu 0.0f making the coloi completely tians-
paient (in othei woius, invisiLle).
Altei you have an oLject ol type UIColor, you can use its set instance methou to make
the cuiient giaphics context use that coloi loi suLseguent uiawing.
You can use the colorWithRed:green:blue:alpha: class methou ol the
UIColor class to loau piimaiy colois like ieu Ly simply passing 1.0f as
the red paiametei, anu 0.0f loi the green anu blue paiameteis. The
alpha is up to you.
Il you look at Figuie 17-11, you will notice that the Lackgiounu coloi ol the view oLject
we have cieateu Ly uelault is an ugly giay coloi. Let`s change that, shall we? Simply
linu the viewDidLoad instance methou ol youi view contiollei, GraphicsViewControl
ler, anu set the Lackgiounu coloi ol youi view to white, as shown heie:
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
}
Ve will Le using instance methous ol the NSString class to uiaw text on
the cuiient giaphics context, as we shall soon uiscuss.
Now let`s loau a magenta coloi into an oLject ol type UIColor anu then uiaw the text
I Learn Really Fast on the view`s giaphical context using a Lolu Helvetica lont ol size
30 (see Recipe 17.1 loi loauing lonts):
- (void)drawRect:(CGRect)rect{
// Drawing code
/* Load the color */
UIColor *magentaColor =[UIColor colorWithRed:0.5f
green:0.0f
blue:0.5f
alpha:1.0f];
/* Set the color in the graphical context */
[magentaColor set];
/* Load the font */
UIFont *helveticaBold = [UIFont fontWithName:@"HelveticaNeue-Bold"
size:30.0f];
/* the string to be drawn */
752 | Chapter 17: Graphics and Animations
www.it-ebooks.info
NSString *myString = @"I Learn Really Fast";
/* Draw the string using the font. The color has
already been set */
[myString drawAtPoint:CGPointMake(25, 190)
withFont:helveticaBold];
}
The iesults aie shown in Figuie 17-12.
Iigurc 17-12. String drawn with a co|or on a graphica| contcxt
Ve can also use the drawInRect:withFont: instance methou ol the NSString class to
uiaw text insiue a iectangulai space. The text will get stietcheu to lit into that iectangle.
UIKit will even wiap the text il it uoesn`t lit hoiizontally within the given iectangle.
Rectangulai Lounus aie encapsulateu in CGRect stiuctuies. You can use the CGRect
Make lunction to cieate the Lounus ol a iectangle:
- (void)drawRect:(CGRect)rect{
// Drawing code
/* Load the color */
UIColor *magentaColor = [UIColor colorWithRed:0.5f
green:0.0f
blue:0.5f
alpha:1.0f];
/* Set the color in the graphical context */
[magentaColor set];
/* Load the font */
UIFont *helveticaBold = [UIFont boldSystemFontOfSize:30];
17.3 Constructing, Setting, and Using Colors | 753
www.it-ebooks.info
/* the string to be drawn */
NSString *myString = @"I Learn Really Fast";
/* Draw the string using the font. The color has
already been set */
[myString drawInRect:CGRectMake(100, /* x */
120, /* y */
100, /* width */
200) /* height */
withFont:helveticaBold];
}
This lunction takes loui paiameteis:
x
The x position ol the oiigin point ol the iectangle in ielation to the giaphics context.
In iOS, this is the numLei ol points heauing iight, staiting liom the lelt siue ol the
iectangle.
y
The y position ol the oiigin point ol the iectangle in ielation to the giaphics context.
In iOS, this is the numLei ol points heauing uown, staiting liom the top ol the
iectangle.
width
The wiuth ol the iectangle in points.
height
The height ol the iectangle in points.
The output is shown in Figuie 17-13.
UIColor is ieally a UIKit wiappei aiounu the Coie Giaphics class CGColor. Vhen we
get as low-level as Coie Giaphics, we suuuenly gain moie contiol ovei how we use the
coloi oLjects, anu we can even ueteimine the components liom which the coloi is maue.
Let`s say some othei coue passeu you an oLject ol type UIColor, anu you want to uetect
its red, green, blue, anu alpha components. To get the components that make up a
UIColor oLject, lollow these steps:
1. Use the CGColor instance methou ol the instance ol the UIColor class. This will give
us a coloi oLject ol type CGColorRef, which is a Coie Giaphics Coloi Releience
oLject.
2. Use the CGColorGetComponents lunction to get the components that constiuct the
coloi oLject.
3. Use the CGColorGetNumberOfComponents lunction to ueteimine the numLei ol com-
ponents that weie useu to constiuct the coloi (ieu - gieen - etc.) il neeu Le.
Heie is an example:
754 | Chapter 17: Graphics and Animations
www.it-ebooks.info
/* Load the color */
UIColor *steelBlueColor = [UIColor colorWithRed:0.3f
green:0.4f
blue:0.6f
alpha:1.0f];
CGColorRef colorRef = [steelBlueColor CGColor];
const CGFloat *components = CGColorGetComponents(colorRef);
NSUInteger componentsCount = CGColorGetNumberOfComponents(colorRef);
NSUInteger counter = 0;
for (counter = 0;
counter < componentsCount;
counter++){
NSLog(@"Component %lu = %.02f",
(unsigned long)counter + 1,
components[counter]);
}
The output that we get in the console winuow altei iunning this coue is:
Component 1 = 0.30
Component 2 = 0.40
Component 3 = 0.60
Component 4 = 1.00
See Also
Recipe 17.1
Iigurc 17-13. Drawing a string in a rcctangu|ar spacc
17.3 Constructing, Setting, and Using Colors | 755
www.it-ebooks.info
17.4 Drawing Images
Problem
You want to Le aLle to uiaw images on the scieen ol an iOS uevice.
Solution
Use the UIImage class to loau an image anu then use the drawInRect: methou ol the
image to uiaw it on a giaphics context.
Discussion
UIKit helps you uiaw images with ease. All you have to uo is to loau youi images in
instances ol type UIImage. The UIImage class pioviues vaiious class anu instance meth-
ous to loau youi images. Heie aie some ol the impoitant ones in iOS:
imageNamed: c|ass ncthod
Loaus the image (anu caches the image il it can loau it piopeily). The paiametei
to this methou is the name ol the image in the Lunule, such as Trcc Tcxturc.png.
imageWithData: c|ass ncthod
Loaus an image liom the uata encapsulateu in an instance ol an NSData oLject that
was passeu as the paiametei to this methou.
initWithContentsOfFile: instancc ncthod (jor initia|ization)
Uses the given paiametei as the path to an image that has to Le loaueu anu useu
to initialize the image oLject.
This path shoulu Le the lull path to the image in the app Lunule.
initWithData: instancc ncthod (jor initia|ization)
Uses the given paiametei ol type NSData to initialize the image. This uata shoulu
Lelong to a valiu image.
Please lollow these steps to auu an image to youi Xcoue pioject:
1. Finu wheie the image is locateu in youi computei.
2. Diag anu uiop the image into Xcoue (onto the lelthanu siue, wheie the iest ol youi
pioject liles aie stoieu).
3. A new uialog Lox will appeai on the scieen. Check the Copy items into uestination
gioup`s loluei (il neeueu) checkLox only il you want the image lile to Le copieu
into youi pioject`s stiuctuie. Uncheck this Lox il you uon`t intenu to copy the
756 | Chapter 17: Graphics and Animations
www.it-ebooks.info
image into youi pioject lile, insteau allowing Xcoue to ieau it liom the oiiginal lile
that you uiaggeu anu uioppeu.
+. In the Folueis section, make suie that the Cieate gioups loi any auueu lolueis
iauio Lutton is selecteu.
5. In the Auu to taigets section, make suie that you check the taigets to which you
want to auu youi image.
You can ietiieve Xcoue`s icon Ly lollowing these steps:
1. Finu the Xcoue app in the linuei.
2. Piess Commanu-I on Xcoue in Finuei to get inloimation on it.
3. Click on the icon in the uppei lelt ol the Xcoue Inlo winuow.
+. Piess Commanu-C to copy it.
5. Open the Pieview app.
6. Hit Commanu-V to paste the Xcoue icon into a new image.
7. You will now have an ICNS lile with live sepaiate pages. Save it as
a PDF, then uelete all Lut the highest-iesolution icon (page 1).
Ve will Le uiawing this image on a giaphics context to uemonstiate
how to uiaw images in this section ol the Look. I`ve alieauy lounu the
lile, anu uiaggeu anu uioppeu that image into my iOS app. Now I have
an image calleu xcodc.png in my app Lunule. The image is shown in
Figuie 17-1+.
Iigurc 17-11. Xcodc`s icon, jound in your Xcodc app
17.4 Drawing Images | 757
www.it-ebooks.info
Heie is the coue loi uiawing an image:
- (void)drawRect:(CGRect)rect{
UIImage *image = [UIImage imageNamed:@"Xcode.png"];
if (image != nil){
NSLog(@"Successfully loaded the image.");
} else {
NSLog(@"Failed to load the image.");
}
}
Il you have the Xcodc.png image in youi app Lunule, iunning this coue will piint
Successfully loaded the image. in the console. Il you uon`t have the image, Failed to
load the image. will get piinteu. Foi the iemainuei ol this section, I assume you have
this image in youi app Lunule. Feel liee to place othei images in youi app Lunule anu
ielei to those images insteau ol Xcodc.png, which I will Le using in example coue.
The two easiest ways to uiaw an image ol type UIImage on a giaphics context aie:
drawAtPoint: instancc ncthod oj UIImage c|ass
Diaws the image at its oiiginal size at the given point. Constiuct the point using
the CGPointMake lunction.
drawInRect: instancc ncthod oj UIImage c|ass
Diaws the image in the given iectangulai space. To constiuct this iectangulai
space, use the CGRectMake lunction:
- (void)drawRect:(CGRect)rect{
/* Assuming the image is in your app bundle and we can load it */
UIImage *xcodeIcon = [UIImage imageNamed:@"Xcode.png"];
[xcodeIcon drawAtPoint:CGPointMake(0.0f,
20.0f)];
[xcodeIcon drawInRect:CGRectMake(50.0f,
10.0f,
40.0f,
35.0f)];
}
The drawAtPoint: call shown aLove will uiaw the image at its lull size at point (0, 20),
anu the drawInRect: call will uiaw the image at point (50, 10) at +035 points, as shown
in Figuie 17-15.
758 | Chapter 17: Graphics and Animations
www.it-ebooks.info
Iigurc 17-15. Drawing an inagc on a graphics contcxt can bc acconp|ishcd with two dijjcrcnt
ncthods
Aspect iatio is the iatio Letween the wiuth anu the height ol an image
(oi a computei scieen). Let`s assume you have an image that is 100100
pixels. Il you uiaw this image at point (0, 0) with a size ol (100, 200),
you can immeuiately see on the scieen that the image is stietcheu in
height (200 pixels insteau ol 100). The drawInRect: instance methou ol
UIImage leaves it up to you how you want to uiaw youi images. In othei
woius, it is you who has to specily the x, y, wiuth, anu height ol youi
image as it appeais on the scieen.
See Also
Recipe 13.6
17.5 Constructing Resizable Images
Problem
You want to Le aLle to save some memoiy anu uisk space Ly cieating iesizaLle images
loi youi UI components. You may also want to Le aLle to cieate uilleient sizes ol the
same UI component, such as a Lutton, using only a single Lackgiounu image.
17.5 Constructing Resizable Images | 759
www.it-ebooks.info
ResizaLle images ielei to simple PNG oi ]PG images that can Le loaueu
into an instance ol UIImage.
Solution
Cieate a iesizaLle image using the resizableImageWithCapInsets: instance methou ol
the UIImage class.
Discussion
ResizaLle images may sounu a Lit stiange at liist, Lut they make sense when you un-
ueistanu the uilleient uisplay neeus ol youi app. Foi instance, you may Le woiking on
an iOS app wheie you want to pioviue a Lackgiounu image loi youi Luttons. The Liggei
the text in the Lutton, the wiuei the Lutton. So you now have two options on how you
want to pioviue the Lackgiounu images ol youi Luttons:
Cieate one image pei size ol Lutton. This will auu to the size ol youi Lunule,
consumes moie memoiy, anu ieguiies much moie woik liom you. In auuition,
any change to the text ieguiies a new image to make the Lutton lit.
Cieate one iesizaLle image anu use that thioughout the app loi all the Luttons.
Vithout a uouLt, the seconu option is much moie appealing. So what aie iesizaLle
images? They aie simply images that aie uiviueu into two viitual aieas:
An aiea that will not Le stietcheu.
An aiea that will Le stietcheu to lit any size.
As you can see in Figuie 17-16, we have cieateu an image loi a Lutton. Altei a Lettei
look at the image, you can cleaily see that it is maue out ol a giauient. The aiea that I
have uiawn a iectangle aiounu is the aiea that can Le cut out ol the image. You might
Le wonueiing why. Have a closei look! Il I cut that aiea anu maue it only 1 pixel wiue
anu as tall as it is now, I coulu, in my app, put as many ol those veitical slices that I cut
togethei to loim the same aiea that is highlighteu in this photo. See Figuie 17-17.
Iigurc 17-1. An inagc with a rcdundant arca is a grcat candidatc jor a rcsizab|c inagc
760 | Chapter 17: Graphics and Animations
www.it-ebooks.info
Iigurc 17-17. |ndividua| s|iccs oj thc ccntcr scction oj thc inagc arc a|| thc sanc
So how can one make this image smallei anu still Le aLle to constiuct a Lutton out ol
it? The answei is simple. In this case, wheie the image is consistently the same acioss
the length ol the image, we will simply cut the centei ol it into a slice that is 1 point
wiue while keeping it as tall as it is iight now. Figuie 17-1S shows what oui image will
look like altei this opeiation.
Iigurc 17-18. Thc rcsizab|c arca oj thc inagc is nadc into a onc-point widc arca
Now comes the inteiesting pait! How can we tell the iOS SDK which pait ol the image
to keep intact anu which pait to stietch? It tuins out that iOS SDK has alieauy taken
caie ol this. Fiist, loau youi image into memoiy using the UIImage APIs that you leaineu
in this chaptei. Altei constiucting an instance ol UIImage with an image that you know
you can stietch, tiansloim the image instance into a iesizaLle image using the resiza
bleImageWithCapInsets: instance methou ol the same instance. The paiametei that this
methou takes is ol type UIEdgeInsets, which is itsell uelineu in this way:
typedef struct UIEdgeInsets {
CGFloat top, left, bottom, right;
} UIEdgeInsets;
Euge insets aie theie to allow us to cieate what Apple calls ninc-part inagcs. A nine-
pait image is an image that has the lollowing nine components:
Uppei lelt coinei
Top euge
Uppei iight coinei
17.5 Constructing Resizable Images | 761
www.it-ebooks.info
Right euge
Lowei iight coinei
Bottom euge
Lowei lelt coinei
Lelt euge
Centei
Figuie 17-19 illustiates this concept much Lettei than woius can.
Iigurc 17-19. |||ustration oj a ninc-part inagc
The puipose ol stoiing an image as a nine-pait image is that piogiammeis can iesize it
veitically anu hoiizontally to pietty much any size they want. Vhen the piogiammei
ieguiies the image to Le iesizeu, some ol these components will stay unchangeu anu
some will Le iesizeu. The paits that stay unchangeu aie the coineis, which aien`t iesizeu
at all. The othei paits ol the image will Le iesizeu as lollows:
Top cdgc
This pait ol the image will Le iesizeu in its wiuth Lut not in its height.
Right cdgc
This pait ol the image will Le iesizeu in its height Lut not in its wiuth.
Botton cdgc
This pait ol the image, just like the top euge, will Le iesizeu in its wiuth, Lut not
in its height.
762 | Chapter 17: Graphics and Animations
www.it-ebooks.info
Lcjt cdgc
]ust like the iight euge, this pait ol the image will Le iesizeu in its height, Lut not
in its wiuth.
Ccntcr
Vill Le iesizeu in Loth its wiuth anu its height.
The top, lelt, Lottom, anu iight values ol the inset maik the aiea that you uon`t want
to stietch. Foi instance, il you specilieu the value ol 10 loi the lelt, 11 loi the top, 1+
loi the iight, anu 5 loi the Lottom, you aie telling iOS to put a veitical |inc on the image
at 10 points liom the lelt, a hoiizontal line at 11 points liom the top, anothei veitical
line at 1+ points liom the iight, anu a linal hoiizontal line at 5 points liom the Lottom.
The iectangulai aiea trappcd Letween these viitual lines is the iesizaLle aiea ol the image
anu the aiea outsiue this iectangle is not stietcheu. This may sounu a Lit conlusing,
Lut imagine a iectangle (youi image) anu then you uiaw anothei iectangle insiue it.
The innei iectangle is iesizaLle Lut the outei iectangle stays intact. I think looking at
a pictuie uemonstiating these values will claiily this (Figuie 17-20).
Iigurc 17-20. Thc strctchab|c portion oj thc inagc is dcjincd by thc cdgc inscts
The lelt anu iight uistances aie ieally the same in Figuie 17-20. So aie
the top anu the Lottom uistances. I have just set them to uilleient values
to make the euge inset constiuction a Lit moie stiaightloiwaiu anu eas-
iei to unueistanu. Il all the values weie the same, when we constiuct
the euge insets latei you may ask: which one is which?!
Foi an image like this (Figuie 17-20), we shoulu constiuct the euge inset like so:
UIEdgeInsets edgeInsets;
edgeInsets.left = 20.0f;
edgeInsets.top = 10.0f;
edgeInsets.right = 24.0f;
edgeInsets.bottom = 14.0f;
17.5 Constructing Resizable Images | 763
www.it-ebooks.info
OK, now let`s go Lack to oui example coue. Vhat we aie tiying to uo heie is use the
stietchaLle image that we cieateu in Figuie 17-1S loi a ieal application. Ve will cieate
a Lutton anu place it at the centei ol oui only view contiollei`s view. The Lutton`s text
will ieau Stietcheu Image on Button anu its size will Le 200 points wiue anu ++ points
tall. Heie is oui coue:
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong) UIButton *button;
@end
@implementation ViewController
- (void)viewDidLoad{
[super viewDidLoad];
/* Instantiate the button */
self.button = [UIButton buttonWithType:UIButtonTypeCustom];
[self.button setFrame:CGRectMake(0.0f, 0.0f, 200.0f, 44.0f)];
/* Set the title of the button */
[self.button setTitle:@"Stretched Image on Button"
forState:UIControlStateNormal];
/* Adjust the font for our text */
self.button.titleLabel.font = [UIFont systemFontOfSize:15.0f];
/* Construct the stretchable image */
UIImage *image = [UIImage imageNamed:@"Button"];
UIEdgeInsets edgeInsets;
edgeInsets.left = 14.0f;
edgeInsets.top = 0.0f;
edgeInsets.right = 14.0f;
edgeInsets.bottom = 0.0f;
image = [image resizableImageWithCapInsets:edgeInsets];
/* Set the background image of the button */
[self.button setBackgroundImage:image forState:UIControlStateNormal];
[self.view addSubview:self.button];
self.button.center = self.view.center;
}
- (void)didReceiveMemoryWarning{
[super didReceiveMemoryWarning];
}
@end
Now il you iun the app, you will see something similai to Figuie 17-21.
764 | Chapter 17: Graphics and Animations
www.it-ebooks.info
Iigurc 17-21. A button is disp|aycd on thc scrccn with a strctchab|c bac|ground inagc
See Also
Recipe 17.+
17.6 Drawing Lines
Problem
You simply want to Le aLle to uiaw lines on a giaphics context.
Solution
Retiieve the hanule to youi giaphics context anu then use the CGContextMoveToPoint
anu the CGContextAddLineToPoint lunctions to uiaw youi line.
Discussion
Vhen we talk aLout uiawing shapes in iOS oi OS X, we aie implicitly talking aLout
paths. Vhat aie paths, you may ask? A path is constiucteu liom one oi moie seiies ol
points uiawn on a scieen. Theie is a Lig uilleience Letween paths anu lines. A path can
contain many lines, Lut a line cannot contain many paths. Think ol paths as seiies ol
pointsit`s as simple as that.
17.6 Drawing Lines | 765
www.it-ebooks.info
Lines have to Le uiawn using paths. Specily the stait anu enu points, anu then ask Coie
Giaphics to lill that path loi you. Coie Giaphics iealizes that you have cieateu a line
on that path, anu will paint that path loi you using the coloi that you specilieu (see
Recipe 17.3).
Ve will Le talking aLout paths in moie uepth latei (see Recipe 17.7), Lut loi now let`s
locus on using paths to cieate stiaight lines. To uo this, lollow these steps:
1. Choose a coloi on youi giaphics context (see Recipe 17.3).
2. Retiieve the hanule to the giaphics context, using the UIGraphicsGetCurrentCon
text lunction.
3. Set the staiting point loi youi line using the CGContextMoveToPoint pioceuuie.
+. Move youi pen on the giaphics context using the CGContextAddLineToPoint pioce-
uuie to specily the enuing point ol youi line.
5. Cieate the path that you have laiu out using the CGContextStrokePath pioceuuie.
This pioceuuie will uiaw the path using the cuiient coloi that has Leen set on the
giaphics context.
Optionally, you can use the CGContextSetLineWidth pioceuuie to set the wiuth ol the
lines that you aie uiawing on a given giaphics context. The liist paiametei to this
pioceuuie is the giaphics context that you aie uiawing on, anu the seconu paiametei
is the wiuth ol the line, expiesseu as a lloating-point numLei (CGFloat).
In iOS, the line wiuth is measuieu in logical points.
Heie is an example:
- (void)drawRect:(CGRect)rect{

/* Set the color that we want to use to draw the line */
[[UIColor brownColor] set];
/* Get the current graphics context */
CGContextRef currentContext = UIGraphicsGetCurrentContext();
/* Set the width for the line */
CGContextSetLineWidth(currentContext,
5.0f);
/* Start the line at this point */
CGContextMoveToPoint(currentContext,
50.0f,
10.0f);
/* And end it at this point */
766 | Chapter 17: Graphics and Animations
www.it-ebooks.info
CGContextAddLineToPoint(currentContext,
100.0f,
200.0f);
/* Use the context's current color to draw the line */
CGContextStrokePath(currentContext);
}
Running this coue in iOS Simulatoi will show you iesults similai to Figuie 17-22.
Iigurc 17-22. Drawing a |inc on a currcnt graphics contcxt
Let me show you anothei example. As mentioneu eailiei, the CGContextAddLineTo
Point pioceuuie specilies the enu point ol the cuiient line. Now what il we have alieauy
uiawn a line liom point (20, 20) to point (100, 100), anu want to uiaw a line liom (100,
100) to (300, 100)? You might think that altei uiawing the liist line, we have to move
the pen to point (100, 100) using the CGContextMoveToPoint pioceuuie, anu then uiaw
the line to point (300, 100) using the CGContextAddLineToPoint pioceuuie. Vhile that
will woik, theie is a moie ellicient way to uo this. Altei you call the CGContextAddLine
ToPoint pioceuuie to specily the enuing point ol youi cuiient line, youi pen`s position
will change to what you pass to this methou. In othei woius, altei you issue a methou
using the pen, it leaves the pen`s position at the enuing point ol whatevei it uiew. So
to uiaw anothei line liom the cuiient enuing point to anothei point, all you have to uo
is to call the CGContextAddLineToPoint pioceuuie again with anothei enuing point. Heie
is an example:
- (void)drawRect:(CGRect)rect{
// Drawing code
/* Set the color that we want to use to draw the line */
17.6 Drawing Lines | 767
www.it-ebooks.info
[[UIColor brownColor] set];
/* Get the current graphics context */
CGContextRef currentContext = UIGraphicsGetCurrentContext();
/* Set the width for the lines */
CGContextSetLineWidth(currentContext,
5.0f);
/* Start the line at this point */
CGContextMoveToPoint(currentContext,
20.0f,
20.0f);
/* And end it at this point */
CGContextAddLineToPoint(currentContext,
100.0f,
100.0f);
/* Extend the line to another point */
CGContextAddLineToPoint(currentContext,
300.0f,
100.0f);
/* Use the context's current color to draw the lines */
CGContextStrokePath(currentContext);
}
The iesults aie shown in Figuie 17-23. You can see that Loth lines aie successlully
uiawn without us having to move the pen loi the seconu line.
Iigurc 17-23. Drawing two |incs at oncc
768 | Chapter 17: Graphics and Animations
www.it-ebooks.info
The point wheie two lines meet is, not suipiisingly, calleu a join. Vith Coie Giaphics,
you can specily what type ol join you want to have Letween lines that aie connecteu to
each othei. To make youi choice, you must use the CGContextSetLineJoin pioceuuie.
It takes two paiameteis: a giaphics context on which you aie setting the join type, anu
the join type itsell, which must Le ol type CGLineJoin. CGLineJoin is an enumeiation ol
the lollowing values:
kCGLineJoinMiter
]oins will Le maue out ol shaip coineis. This is the uelault join type.
kCGLineJoinBevel
]oins will Le sguaieu oll on the coinei.
kCGLineJoinRound
As the name implies, this makes iounu joins.
Let`s have a look at an example. Let`s say we want to wiite a piogiam that can uiaw
iooltops on a giaphics context (thiee ol them, one loi each join type), anu also uiaws
text Lelow each iooltop uesciiLing the type ol join it is using. Something similai to
Figuie 17-2+ will Le the iesult.
Iigurc 17-21. Thrcc typcs oj |inc joins in Corc Graphics
To accomplish this, I`ve wiitten a methou nameu drawRooftopAtTopPointof:textToDis
play:lineJoin:, which takes thiee paiameteis:
1. A point at which the top ol the iooltop shoulu Le placeu.
2. The text to uisplay insiue the iooltop.
3. The join type to Le useu.
The coue is as lollows:
17.6 Drawing Lines | 769
www.it-ebooks.info
- (void) drawRooftopAtTopPointof:(CGPoint)paramTopPoint
textToDisplay:(NSString *)paramText
lineJoin:(CGLineJoin)paramLineJoin{
/* Set the color that we want to use to draw the line */
[[UIColor brownColor] set];
/* Get the current graphics context */
CGContextRef currentContext = UIGraphicsGetCurrentContext();
/* Set the line join */
CGContextSetLineJoin(currentContext,
paramLineJoin);
/* Set the width for the lines */
CGContextSetLineWidth(currentContext,
20.0f);
/* Start the line at this point */
CGContextMoveToPoint(currentContext,
paramTopPoint.x - 140,
paramTopPoint.y + 100);
/* And end it at this point */
CGContextAddLineToPoint(currentContext,
paramTopPoint.x,
paramTopPoint.y);
/* Extend the line to another point to
make the rooftop */
CGContextAddLineToPoint(currentContext,
paramTopPoint.x + 140,
paramTopPoint.y + 100);
/* Use the context's current color to draw the lines */
CGContextStrokePath(currentContext);
/* Draw the text in the rooftop using a black color */
[[UIColor blackColor] set];
/* Now draw the text */
CGPoint drawingPoint = CGPointMake(paramTopPoint.x - 40.0f,
paramTopPoint.y + 60.0f);
[paramText drawAtPoint:drawingPoint
withFont:[UIFont boldSystemFontOfSize:30.0f]];
}
Now let`s call this methou in the drawRect: instance methou ol the view oLject wheie
we have a giaphics context:
- (void)drawRect:(CGRect)rect{
[self drawRooftopAtTopPointof:CGPointMake(160.0f, 40.0f)
textToDisplay:@"Miter"
lineJoin:kCGLineJoinMiter];
770 | Chapter 17: Graphics and Animations
www.it-ebooks.info
[self drawRooftopAtTopPointof:CGPointMake(160.0f, 180.0f)
textToDisplay:@"Bevel"
lineJoin:kCGLineJoinBevel];
[self drawRooftopAtTopPointof:CGPointMake(160.0f, 320.0f)
textToDisplay:@"Round"
lineJoin:kCGLineJoinRound];
}
See Also
Recipe 17.3; Recipe 17.7
17.7 Constructing Paths
Problem
You want to Le aLle to uiaw any shape that you wish on a giaphics context.
Solution
Constiuct anu uiaw paths.
Discussion
A seiies ol points placeu togethei can loim a shape. A seiies ol shapes put togethei
Luilus a path. Paths can easily Le manageu Ly Coie Giaphics. In Recipe 17.6, we woikeu
inuiiectly with paths using CGContext lunctions. But Coie Giaphics also has lunctions
that woik uiiectly with paths, as we shall soon see.
Paths Lelong to whichevei giaphics context they aie uiawn on. Paths uo not have
Lounuaiies oi specilic shapes, unlike the shapes we uiaw on them. But paths uo have
Lounuing Loxes. Please Leai in minu that Lounuaiies aie not the same as Lounuing
Loxes. Bounuaiies aie limits aLove which you cannot uiaw on a canvas, while the
Lounuing Lox ol a path is the smallest iectangle that contains all the shapes, points,
anu othei oLjects that have Leen uiawn on that specilic path. Think ol paths as stamps
anu think ol youi giaphics context as the envelope. Youi envelope coulu Le the same
eveiy time you mail something to youi liienu, Lut what you put on that context (the
stamp oi the path) can Le uilleient.
Altei you linish uiawing on a path, you can then uiaw that path on the giaphics context.
Developeis lamiliai with game piogiamming know the concept ol bujjcrs, which uiaw
theii scenes anu, at appiopiiate times, j|ush the images onto the scieen. Paths aie those
Lulleis. They aie like Llank canvases that can Le uiawn on giaphics contexts when the
time is iight.
17.7 Constructing Paths | 771
www.it-ebooks.info
The liist step in uiiectly woiking with paths is to cieate them. The methou cieating the
path ietuins a hanule that you use whenevei you want to uiaw something on that path,
passing the hanule to Coie Giaphics loi ieleience. Altei you cieate the path, you can
auu uilleient points, lines, anu shapes to it anu then uiaw the path. You can eithei lill
the path oi paint it with a stioke on a giaphics context. Heie aie the methous you have
to woik with:
CGPathCreateMutable junction
Cieates a new mutaLle path ol type CGMutablePathRef anu ietuins its hanule. Ve
shoulu uispose ol this path once we aie uone with it, as you will soon see.
CGPathMoveToPoint proccdurc
Moves the cuiient pen position on the path to the point specilieu Ly a paiametei
ol type CGPoint.
CGPathAddLineToPoint proccdurc
Diaws a line segment liom the cuiient pen position to the specilieu position (again,
specilieu Ly a value ol type CGPoint).
CGContextAddPath proccdurc
Auus a given path (specilieu Ly a path hanule) to a giaphics context, ieauy loi
uiawing.
CGContextDrawPath proccdurc
Diaws a given path on the giaphics context.
CGPathRelease proccdurc
Releases the memoiy allocateu loi a path hanule.
CGPathAddRect proccdurc
Auus a iectangle to a path. The iectangle`s Lounuaiies aie specilieu Ly a CGRect
stiuctuie.
Theie aie thiee impoitant uiawing methous that you can ask the CGContextDrawPath
pioceuuie to peiloim:
kCGPathStroke
Diaws a line (stioke) to maik the Lounuaiy oi euge ol the path, using the cuiiently
selecteu stioke coloi.
kCGPathFill
Fills the aiea suiiounueu Ly the path with the cuiiently selecteu lill coloi.
kCGPathFillStroke
ComLines stioke anu lill. Uses the cuiiently selecteu lill coloi to lill the path, anu
the cuiiently selecteu stioke coloi to uiaw the euge ol the path. Ve`ll see an ex-
ample ol this methou in the lollowing section.
Let`s have a look at an example. Ve will uiaw a Llue line liom the top-lelt to the Lottom-
iight coinei, anu anothei liom the top-iight to the Lottom-lelt coinei, to cieate a gi-
gantic X acioss the scieen.
772 | Chapter 17: Graphics and Animations
www.it-ebooks.info
Foi this example, I have iemoveu the status Lai liom the application in
iOS Simulatoi. Il you uon`t want to Lothei uoing this, please continue
to the example coue. Vith a status Lai, the output ol this coue will only
Le slightly uilleient liom the scieenshot I`ll show. To hiue the status
Lai, linu the |njo.p|ist lile in youi Xcoue pioject anu auu a key to it
nameu UIStatusBarHidden with the value ol YES, as shown in Fig-
uie 17-25. This will loice youi app`s status Lai to Le hiuuen when it
opens.
Iigurc 17-25. Hiding thc status bar in an iOS app using thc |njo.p|ist ji|c
- (void)drawRect:(CGRect)rect{
/* Create the path */
CGMutablePathRef path = CGPathCreateMutable();
/* How big is the screen? We want the X to cover
the whole screen */
CGRect screenBounds = [[UIScreen mainScreen] bounds];
/* Start from top-left */
CGPathMoveToPoint(path,
NULL,
screenBounds.origin.x,
screenBounds.origin.y);
/* Draw a line from top-left to bottom-right of the screen */
CGPathAddLineToPoint(path,
NULL,
screenBounds.size.width,
screenBounds.size.height);
/* Start another line from top-right */
CGPathMoveToPoint(path,
NULL,
screenBounds.size.width,
17.7 Constructing Paths | 773
www.it-ebooks.info
screenBounds.origin.y);
/* Draw a line from top-right to bottom-left */
CGPathAddLineToPoint(path,
NULL,
screenBounds.origin.x,
screenBounds.size.height);
/* Get the context that the path has to be drawn on */
CGContextRef currentContext = UIGraphicsGetCurrentContext();
/* Add the path to the context so we can
draw it later */
CGContextAddPath(currentContext,
path);
/* Set the blue color as the stroke color */
[[UIColor blueColor] setStroke];
/* Draw the path with stroke color */
CGContextDrawPath(currentContext,
kCGPathStroke);
/* Finally release the path object */
CGPathRelease(path);
}
The NULL paiameteis getting passeu to pioceuuies such as CGPathMove
ToPoint iepiesent possiLle tiansloimations that can Le useu when uiaw-
ing the shapes anu lines on a given path. Foi inloimation aLout tians-
loimations, ielei to Recipes 17.11, 17.12, anu 17.13.
You can see how easy it is to uiaw a path on a context. All you ieally have to iememLei
is how to cieate a new mutaLle path (CGPathCreateMutable), auu that path to youi
giaphics context (CGContextAddPath), anu uiaw it on a giaphics context (CGContextDraw
Path). Il you iun this coue, you will get an output similai to that shown in Figuie 17-26.
See Also
Recipe 17.6; Recipe 17.11; Recipe 17.12; Recipe 17.13
17.8 Drawing Rectangles
Problem
You want to Le aLle to uiaw iectangles on a giaphics context.
774 | Chapter 17: Graphics and Animations
www.it-ebooks.info
Solution
Use the CGPathAddRect to auu a iectangle to a path anu then uiaw that path on a giaphics
context.
Discussion
As we leaineu in Recipe 17.7, you can constiuct anu use paths guite easily. One ol the
pioceuuies that you can use on paths in Coie Giaphics is CGPathAddRect, which lets
you uiaw iectangles as pait ol paths. Heie is an example:
- (void)drawRect:(CGRect)rect{
/* Create the path first. Just the path handle. */
CGMutablePathRef path = CGPathCreateMutable();
/* Here are the rectangle boundaries */
CGRect rectangle = CGRectMake(10.0f,
10.0f,
200.0f,
300.0f);
/* Add the rectangle to the path */
CGPathAddRect(path,
NULL,
rectangle);
/* Get the handle to the current context */
CGContextRef currentContext = UIGraphicsGetCurrentContext();
Iigurc 17-2. Drawing on a graphics contcxt using paths
17.8 Drawing Rectangles | 775
www.it-ebooks.info
/* Add the path to the context */
CGContextAddPath(currentContext,
path);
/* Set the fill color to cornflower blue */
[[UIColor colorWithRed:0.20f
green:0.60f
blue:0.80f
alpha:1.0f] setFill];
/* Set the stroke color to brown */
[[UIColor brownColor] setStroke];
/* Set the line width (for the stroke) to 5 */
CGContextSetLineWidth(currentContext,
5.0f);
/* Stroke and fill the path on the context */
CGContextDrawPath(currentContext,
kCGPathFillStroke);
/* Dispose of the path */
CGPathRelease(path);
}
Heie, we aie uiawing a iectangle on the path, lilling it with coinllowei Llue, anu stiok-
ing the euges ol the iectangle with Liown. Figuie 17-27 shows how the output will look
when we iun the piogiam.
Iigurc 17-27. Drawing a rcctang|c using paths
776 | Chapter 17: Graphics and Animations
www.it-ebooks.info
Il you have multiple iectangles to uiaw, you can pass an aiiay ol CGRect oLjects to the
CGPathAddRects pioceuuie. Heie is an example:
- (void)drawRect:(CGRect)rect{
/* Create the path first. Just the path handle. */
CGMutablePathRef path = CGPathCreateMutable();
/* Here are the first rectangle boundaries */
CGRect rectangle1 = CGRectMake(10.0f,
10.0f,
200.0f,
300.0f);
/* And the second rectangle */
CGRect rectangle2 = CGRectMake(40.0f,
100.0f,
90.0f,
300.0f);
/* Put both rectangles into an array */
CGRect rectangles[2] = {
rectangle1, rectangle2
};
/* Add the rectangles to the path */
CGPathAddRects(path,
NULL,
(const CGRect *)&rectangles,
2);
/* Get the handle to the current context */
CGContextRef currentContext = UIGraphicsGetCurrentContext();
/* Add the path to the context */
CGContextAddPath(currentContext,
path);
/* Set the fill color to cornflower blue */
[[UIColor colorWithRed:0.20f
green:0.60f
blue:0.80f
alpha:1.0f] setFill];
/* Set the stroke color to black */
[[UIColor blackColor] setStroke];
/* Set the line width (for the stroke) to 5 */
CGContextSetLineWidth(currentContext,
5.0f);
/* Stroke and fill the path on the context */
CGContextDrawPath(currentContext,
kCGPathFillStroke);
17.8 Drawing Rectangles | 777
www.it-ebooks.info
/* Dispose of the path */
CGPathRelease(path);
}
Figuie 17-2S shows how the output ol this coue will look when iun in iOS Simulatoi.
The paiameteis that we pass to the CGPathAddRects pioceuuie aie (in this oiuei):
1. The hanule to the path wheie we will auu the iectangles.
2. The tiansloimation, il any, to use on to the iectangles. (Foi inloimation aLout
tiansloimations, ielei to Recipes 17.11, 17.12, anu 17.13.)
3. A ieleience to the aiiay holuing the CGRect iectangles.
+. The numLei ol iectangles in the aiiay that we passeu in the pievious paiametei. It
is veiy impoitant that you pass exactly as many iectangles as you have in youi aiiay,
to avoiu unknown Lehavioi Ly this pioceuuie.
Iigurc 17-28. Drawing nu|tip|c rcctang|cs at oncc
See Also
Recipe 17.7; Recipe 17.11; Recipe 17.12; Recipe 17.13
17.9 Adding Shadows to Shapes
Problem
You want to Le aLle to apply shauows to shapes that you uiaw on giaphic contexts.
778 | Chapter 17: Graphics and Animations
www.it-ebooks.info
Solution
Use the CGContextSetShadow pioceuuie.
Discussion
It is easy to uiaw shauows using Coie Giaphics. The giaphics context is the element
that Leais the shauow. Vhat that means is that you neeu to apply the shauow to the
context, uiaw the shapes that neeu the shauow, anu then iemove the shauow liom the
context (oi set a new context). Ve will see an example ol this soon.
In Coie Giaphics, we can use two pioceuuies to apply a shauow to a giaphics context:
CGContextSetShadow proccdurc
This pioceuuie, which cieates Llack oi giay shauows, accepts thiee paiameteis:
The giaphics context on which the shauow has to Le applieu.
The ollset, specilieu Ly a value ol type CGSize, liom the iight anu the Lottom
pait ol each shape wheie the shauow has to Le applieu. The gieatei the x value
ol this ollset is, the laithei to the iight ol each shape the shauow will extenu.
The gieatei the y value ol this ollset is, the lowei the shauow will extenu.
The Llui value that has to Le applieu to the shauow, specilieu as a lloating-
point value (CGFloat). Specilying 0.0f will cause the shauow to Le a soliu shape.
The highei this value goes, the moie Lluiieu the shauow will get. Ve will see
an example ol this soon.
CGContextSetShadowWithColor proccdurc
This pioceuuie accepts the exact same paiameteis as CGContextSetShadow, with one
auuition. This louith paiametei, ol type CGColorRef, sets the coloi ol the shauow.
At the Leginning ol this section, I mentioneu that the giaphics context ietains its shau-
ow piopeities until we explicitly iemove the shauow. Let me make that point cleaiei
Ly showing you an example. Let us go aheau anu wiite coue that allows us to uiaw two
iectangles, the liist one with a shauow anu the seconu one without a shauow. Ve will
uiaw the liist one in this way:
- (void) drawRectAtTopOfScreen{
/* Get the handle to the current context */
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGContextSetShadowWithColor(currentContext,
CGSizeMake(10.0f, 10.0f),
20.0f,
[[UIColor grayColor] CGColor]);
/* Create the path first. Just the path handle. */
CGMutablePathRef path = CGPathCreateMutable();
/* Here are the rectangle boundaries */
CGRect firstRect = CGRectMake(55.0f,
17.9 Adding Shadows to Shapes | 779
www.it-ebooks.info
60.0f,
150.0f,
150.0f);
/* Add the rectangle to the path */
CGPathAddRect(path,
NULL,
firstRect);
/* Add the path to the context */
CGContextAddPath(currentContext,
path);
/* Set the fill color to cornflower blue */
[[UIColor colorWithRed:0.20f
green:0.60f
blue:0.80f
alpha:1.0f] setFill];
/* Fill the path on the context */
CGContextDrawPath(currentContext,
kCGPathFill);
/* Dispose of the path */
CGPathRelease(path);
}
Il we call this methou in the drawRect: instance methou ol the view oLject, we will see
the iectangle uiawn on the scieen with a nice shauow just like we wanteu it, as shown
in Figuie 17-29.
Iigurc 17-29. Shadow app|icd to a rcctang|c
780 | Chapter 17: Graphics and Animations
www.it-ebooks.info
Now let`s go aheau anu uiaw a seconu iectangle altei the liist one. Ve won`t ask loi a
shauow, Lut we`ll leave the shauow piopeity ol the giaphics context as it was loi the
liist iectangle:
- (void) drawRectAtBottomOfScreen{
/* Get the handle to the current context */
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGMutablePathRef secondPath = CGPathCreateMutable();
CGRect secondRect = CGRectMake(150.0f,
250.0f,
100.0f,
100.0f);
CGPathAddRect(secondPath,
NULL,
secondRect);
CGContextAddPath(currentContext,
secondPath);
[[UIColor purpleColor] setFill];
CGContextDrawPath(currentContext,
kCGPathFill);
CGPathRelease(secondPath);
}
- (void)drawRect:(CGRect)rect{
[self drawRectAtTopOfScreen];
[self drawRectAtBottomOfScreen];
}
The drawRect: methou liist calls the drawRectAtTopOfScreen methou, anu iight altei
that, calls the drawRectAtBottomOfScreen methou. Ve haven`t askeu loi a shauow loi
the drawRectAtBottomOfScreen iectangle, yet il you iun the app, you will see something
similai to Figuie 17-30.
It`s immeuiately oLvious that the shauow is applieu to the seconu iectangle at the
Lottom ol the scieen. To avoiu this, we will save the state ol the giaphics context
bcjorc applying the shauow ellect, anu then iestoie the state when we want to iemove
the shauow ellect.
Bioauly speaking, saving anu iestoiing the state ol a giaphics context is not limiteu to
shauows only. Restoiing the state ol a giaphics context iestoies eveiything (lill coloi,
lont, line thickness, etc.) to the values they hau Leloie you set them. So loi instance, il
you applieu lill anu stioke colois in the meantime, those colois will Le ieset.
You can save the state ol a giaphics context thiough the CGContextSaveGState pioceuuie
anu iestoie the pievious state thiough the CGContextRestoreGState pioceuuie. So il we
17.9 Adding Shadows to Shapes | 781
www.it-ebooks.info
mouily the drawRectAtTopOfScreen pioceuuie Ly saving the state ol the giaphics context
Leloie applying the shauow, anu iestoie that state altei uiawing the path, we will have
uilleient iesults, shown in Figuie 17-31:
- (void) drawRectAtTopOfScreen{
/* Get the handle to the current context */
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGContextSaveGState(currentContext);
CGContextSetShadowWithColor(currentContext,
CGSizeMake(10.0f, 10.0f),
20.0f,
[[UIColor grayColor] CGColor]);
/* Create the path first. Just the path handle. */
CGMutablePathRef path = CGPathCreateMutable();
/* Here are the rectangle boundaries */
CGRect firstRect = CGRectMake(55.0f,
60.0f,
150.0f,
150.0f);
/* Add the rectangle to the path */
CGPathAddRect(path,
NULL,
firstRect);
/* Add the path to the context */
CGContextAddPath(currentContext,
path);
Iigurc 17-30. A shadow is unintcntiona||y app|icd to thc sccond rcctang|c
782 | Chapter 17: Graphics and Animations
www.it-ebooks.info
/* Set the fill color to cornflower blue */
[[UIColor colorWithRed:0.20f
green:0.60f
blue:0.80f
alpha:1.0f] setFill];
/* Fill the path on the context */
CGContextDrawPath(currentContext,
kCGPathFill);
/* Dispose of the path */
CGPathRelease(path);
/* Restore the context to how it was
when we started */
CGContextRestoreGState(currentContext);
}
Iigurc 17-31. Saving thc statc oj thc graphics contcxt jor accuratc shadows
17.10 Drawing Gradients
Problem
You want to uiaw giauients on giaphics contexts, using uilleient colois.
Solution
Use the CGGradientCreateWithColor lunction.
17.10 Drawing Gradients | 783
www.it-ebooks.info
Discussion
Altei leaining aLout colois in Recipe 17.3, we`ie ieauy to put these skills to Lettei use
than uiawing simple iectangles anu coloilul text!
Coie Giaphics allows piogiammeis to cieate two types ol giauients: axial anu iauial.
(Ve will only uiscuss axial giauients in this Look.) Axial giauients aie giauients that
stait liom one point with one coloi anu enu at anothei point with anothei coloi (al-
though they can stait anu stop with the same coloi, which uoes not make them much
ol a giauient). Axial means ielating to an axis. The two points (stait anu enu point)
cieate a line segment, which will Le the axis on which the giauient will Le uiawn. An
example ol an axial giauient is shown in Figuie 17-32.
Iigurc 17-32. An axia| gradicnt starting jron thc co|or b|uc and cnding in thc co|or grccn
In oiuei to cieate an axial giauient, you must call the CGGradientCreateWithColorCom
ponents lunction. The ietuin value ol this lunction will Le the new giauient ol type
CGGradientRef. This is the hanule to the giauient. Once you aie uone with the giauient,
you nust call the CGGradientRelease pioceuuie, passing the hanule to the giauient that
you hau pieviously ietiieveu liom CGGradientCreateWithColorComponents.
The CGGradientCreateWithColorComponents lunction takes loui paiameteis:
A co|or spacc
This is a containei loi a iange ol colois, anu must Le ol type CGColorSpaceRef. Foi
this paiametei, we can just pass the ietuin value ol the CGColorSpaceCreateDevi
ceRGB lunction, which will give us an RGB coloi space.
An array oj co|or conponcnts (jor dctai|s, scc Rccipc 17.3)
This aiiay has to contain ieu, gieen, Llue, anu alpha values, all iepiesenteu as
CGFloat values. The numLei ol elements in the aiiay is tightly linkeu to the next
784 | Chapter 17: Graphics and Animations
www.it-ebooks.info
two paiameteis. Essentially, you have to incluue enough values in this aiiay to
specily the numLei ol locations in the louith paiametei. So il you ask loi two
locations (the stait anu enu point), you have to pioviue two colois in the aiiay
heie. Anu since each coloi is maue out ol ieu, gieen, Llue, anu alpha, this aiiay
has to have 2+ items: loui loi the liist coloi anu loui loi the seconu. Don`t woiiy
il you uiun`t get all this; you will eventually unueistanu it thiough the examples
that lollow in this section.
Locations oj co|ors in thc array oj co|ors
This paiametei contiols how guickly the giauient shilts liom one coloi to anothei.
The numLei ol elements must Le the same as the value ol the louith paiametei. Il
we ask loi loui colois, loi example, anu we want the liist coloi to Le the staiting
coloi anu the last coloi to Le the enuing coloi in the giauient, we have to pioviue
an aiiay ol two items ol type CGFloats, with the liist item set to 0.0f (as in the
jirst item in the aiiay ol colois) anu the seconu item set to 3.0f (as in the jourth
item in the aiiay ol colois). The values ol the two inteimeuiate colois ueteimine
how the giauient actually inseits colois to get liom the stait to the enu. Again,
uon`t woiiy il this is too uillicult to giasp. I will give you many examples to help
you lully unueistanu the concept.
Nunbcr oj |ocations
This specilies how many colois anu locations we want.
Let`s have a look at an example. Suppose we want to uiaw the same giauient we saw
in Figuie 17-32? Heie`s how:
1. Pick the stait anu enu points ol the giauientthe axis along which it will shilt. In
this case, I`ve chosen to move liom lelt to iight. Think ol this as changing coloi as
you move along a hypothetical hoiizontal line. Along that line, we will spieau the
colois so that eveiy peipenuiculai line to this hoiizontal line contains only one
coloi. In this case, the peipenuiculai lines woulu Le eveiy veitical line in Fig-
uie 17-32. Look at those veitical lines closely. Eveiy single one contains only one
coloi, which iuns all the way liom top to the Lottom. That`s how axial giauients
woik. OK, that`s enough theoiylet`s go to the seconu step.
2. Now we have to cieate a coloi space to pass to the liist paiametei ol the CGGra
dientCreateWithColorComponents lunction, as mentioneu Leloie:
CGColorSpaceRef colorSpace =
CGColorSpaceCreateDeviceRGB();
Ve will ielease this coloi space once we aie uone with it.
3. Select Llue as the staiting point (lelt) anu gieen as the enuing point (iight), ac-
coiuing to the colois chosen in Figuie 17-32. The names I`ve selecteu (startColor
17.10 Drawing Gradients | 785
www.it-ebooks.info
Components anu endColorComponents) aie aiLitiaiily chosen to help us iememLei
what we`ie uoing with each coloi. Ve`ll actually use aiiay positions to specily
which one is the stait anu which one is the enu:
UIColor *startColor = [UIColor blueColor];
CGFloat *startColorComponents =
(CGFloat *)CGColorGetComponents([startColor CGColor]);
UIColor *endColor = [UIColor greenColor];
CGFloat *endColorComponents =
(CGFloat *)CGColorGetComponents([endColor CGColor]);
Il you uon`t iememLei the concept Lehinu coloi components, I suggest
that you look at Recipe 17.3 Leloie you continue ieauing these instiuc-
tions.
+. Altei ietiieving the components ol each coloi, we place them all in one llat aiiay
to pass to the CGGradientCreateWithColorComponents lunction:
CGFloat colorComponents[8] = {
/* Four components of the blue color (RGBA) */
startColorComponents[0],
startColorComponents[1],
startColorComponents[2],
startColorComponents[3], /* First color = blue */
/* Four components of the green color (RGBA) */
endColorComponents[0],
endColorComponents[1],
endColorComponents[2],
endColorComponents[3], /* Second color = green */
};
5. Because we have only two colois in this aiiay, we neeu to specily that the liist is
positioneu at the veiy Leginning ol the giauient (position 0.0) anu the seconu at
the veiy enu (position 1.0). So let`s place these inuices in an aiiay to pass to the
CGGradientCreateWithColorComponents lunction:
CGFloat colorIndices[2] = {
0.0f, /* Color 0 in the colorComponents array */
1.0f, /* Color 1 in the colorComponents array */
};
6. Now all we have to uo is to actually call the CGGradientCreateWithColorCompo
nents lunction with all these values that we geneiateu:
CGGradientRef gradient =
CGGradientCreateWithColorComponents
(colorSpace,
786 | Chapter 17: Graphics and Animations
www.it-ebooks.info
(const CGFloat *)&colorComponents,
(const CGFloat *)&colorIndices,
2);
7. Fantastic! Now we have the giauient oLject in the gradient vaiiaLle. Beloie we
loiget, we have to ielease the coloi space that we cieateu using the CGColorSpace
CreateDeviceRGB lunction:
CGColorSpaceRelease(colorSpace);
Now we`ll use the CGContextDrawLinearGradient pioceuuie to uiaw the axial giauient
on a giaphics context. This pioceuuie takes live paiameteis:
Graphics contcxt
Specilies the giaphics context on which the axial giauient will Le uiawn.
Axia| gradicnt
The hanule to the axial giauient oLject. Ve cieateu this giauient oLject using the
CGGradientCreateWithColorComponents lunction.
Start point
A point on the giaphics context, specilieu Ly a CGPoint, that inuicates the stait
point ol the giauient.
End point
A point on the giaphics context, specilieu Ly a CGPoint, that inuicates the enu point
ol the giauient.
Gradicnt drawing options
Specilies what happens il youi stait oi enu point isn`t at the euge ol the giaphical
context. You can use youi stait oi enu coloi to lill the space that lies outsiue the
giauient. Specily one ol the lollowing values loi this paiametei:
kCGGradientDrawsAfterEndLocation
Extenus the giauient to all points altei the enuing point ol the giauient.
kCGGradientDrawsBeforeStartLocation
Extenus the giauient to all points Leloie the staiting point ol the giauient.
0
Does not extenu the giauient in any way.
To extenu colois on Loth siues, specily Loth the altei anu Leloie paiameteis as a
logical OR (using the | opeiatoi). Ve`ll see an example latei:
CGRect screenBounds = [[UIScreen mainScreen] bounds];
CGPoint startPoint, endPoint;
startPoint = CGPointMake(0.0f,
screenBounds.size.height / 2.0f);
endPoint = CGPointMake(screenBounds.size.width,
startPoint.y);
17.10 Drawing Gradients | 787
www.it-ebooks.info
CGContextDrawLinearGradient
(currentContext,
gradient,
startPoint,
endPoint,
0);
CGGradientRelease(gradient);
The giauient hanule we aie ieleasing at the enu ol this coue was cieateu
in anothei coue Llock in an eailiei example.
The output ol this coue will oLviously look similai to Figuie 17-32. Because we staiteu
the giauient liom the leltmost point ol the view anu stietcheu it all the way to the
iightmost point, we coulun`t take auvantage ol all the values that coulu Le passeu to
the linal Gradicnt drawing options paiametei ol the CGContextDrawLinearGradient pio-
ceuuie. Let`s iemeuy that, shall we? How aLout we uiaw a giauient that looks similai
to that shown in Figuie 17-33?
Iigurc 17-33. An axia| gradicnt with start and cnd point co|or cxtcnsions
Ve will use the same pioceuuie explaineu eailiei in this section to coue the iesult:
- (void)drawRect:(CGRect)rect{
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGContextSaveGState(currentContext); CGColorSpaceRef colorSpace =
CGColorSpaceCreateDeviceRGB();
788 | Chapter 17: Graphics and Animations
www.it-ebooks.info
UIColor *startColor = [UIColor orangeColor];
CGFloat *startColorComponents =
(CGFloat *)CGColorGetComponents([startColor CGColor]);
UIColor *endColor = [UIColor blueColor];
CGFloat *endColorComponents =
(CGFloat *)CGColorGetComponents([endColor CGColor]);
CGFloat colorComponents[8] = {
/* Four components of the orange color (RGBA) */
startColorComponents[0],
startColorComponents[1],
startColorComponents[2],
startColorComponents[3], /* First color = orange */
/* Four components of the blue color (RGBA) */
endColorComponents[0],
endColorComponents[1],
endColorComponents[2],
endColorComponents[3], /* Second color = blue */
};
CGFloat colorIndices[2] = {
0.0f, /* Color 0 in the colorComponents array */
1.0f, /* Color 1 in the colorComponents array */
};
CGGradientRef gradient = CGGradientCreateWithColorComponents
(colorSpace,
(const CGFloat *)&colorComponents,
(const CGFloat *)&colorIndices,
2);
CGColorSpaceRelease(colorSpace);
CGPoint startPoint, endPoint;
startPoint = CGPointMake(120,
260);
endPoint = CGPointMake(200.0f,
220);
CGContextDrawLinearGradient (currentContext,
gradient,
startPoint,
endPoint,
kCGGradientDrawsBeforeStartLocation |
kCGGradientDrawsAfterEndLocation);
CGGradientRelease(gradient);
17.10 Drawing Gradients | 789
www.it-ebooks.info
CGContextRestoreGState(currentContext);
}
It might Le uillicult to unueistanu how mixing kCGGradientDrawsBeforeStartLoca
tionanu kCGGradientDrawsAfterEndLocation values passeu to the CGContextDrawLin
earGradient pioceuuie is cieating a uiagonal ellect like that shown in Figuie 17-33. So
let`s iemove those values anu set the paiametei ol the CGContextDrawLinearGradient
pioceuuie to 0, as we hau it Leloie. Figuie 17-3+ shows what the iesults will Le.
Iigurc 17-31. Axia| gradicnt without strctchcd co|ors
It`s easy to concluue that the giauient in Figuie 17-3+ is the same giauient shown in
Figuie 17-33. Howevei, the giauient in Figuie 17-33 extenus the stait anu enu points`
colois all the way acioss the giaphics context, which is why you can see the whole
scieen coveieu with coloi.
See Also
Recipe 17.3
17.11 Displacing Shapes Drawn on Graphic Contexts
Problem
You want to move eveiything that is uiawn on a giaphics context to a new location,
without changing youi uiawing coueoi you woulu simply like to uisplace youi con-
text`s contents with ease.
790 | Chapter 17: Graphics and Animations
www.it-ebooks.info
Solution
Use the CGAffineTransformMakeTranslation lunction to cieate an alline tianslation
tiansloimation.
Discussion
Recipe 17.S mentioneu tiansloimations. These aie exactly what the name suggests:
changes to the way a giaphic is uisplayeu. Tiansloimations in Coie Giaphics aie oLjects
that you apply to shapes Leloie they get uiawn. Foi instance, you can cieate a tians-
lation tiansloimation. Tianslating what, you might Le asking? A tianslation tiansloi-
mation is a mechanism Ly which you can disp|acc a shape oi a giaphics context.
Othei types ol tiansloimations incluue iotation (see Recipe 17.13) anu scaling (see
Recipe 17.12). These aie all examples ol ajjinc tiansloimations, which map each point
in the oiigin to anothei point in the linal veision. All the tiansloimations we uiscuss in
this Look will Le alline tiansloimations.
A tianslation tiansloimation trans|atcs the cuiient position ol a shape on a path oi
giaphics context to anothei ielative place. Foi instance, il you uiaw a point at location
(10, 20), apply a tianslation tiansloimation ol (30, +0) to it, anu then uiaw it, the point
will Le uiawn at (+0, 60), Lecause +0 is the sum ol 10-30 anu 60 is the sum ol 20-+0.
In oiuei to cieate a new tianslation tiansloimation, we must use the CGAffineTrans
formMakeTranslation lunction, which will ietuin an alline tiansloimation ol type
CGAffineTransform. The two paiameteis to this lunction specily the x anu the y tians-
lation in points.
In Recipe 17.S, we saw that the CGPathAddRect pioceuuie accepts, as its seconu paiam-
etei, a tiansloimation oLject ol type CGAffineTransform. To uisplace a iectangle liom
its oiiginal place to anothei, you can simply cieate an alline tiansloimation specilying
the changes you want to make in the x anu y cooiuinates, anu pass the tiansloimation
to the seconu paiametei ol the CGPathAddRect pioceuuie as shown heie:
- (void)drawRect:(CGRect)rect{
/* Create the path first. Just the path handle. */
CGMutablePathRef path = CGPathCreateMutable();
/* Here are the rectangle boundaries */
CGRect rectangle = CGRectMake(10.0f,
10.0f,
200.0f,
300.0f);
/* We want to displace the rectangle to the right by
100 points but want to keep the y position
untouched */
CGAffineTransform transform = CGAffineTransformMakeTranslation(100.0f,
0.0f);
17.11 Displacing Shapes Drawn on Graphic Contexts | 791
www.it-ebooks.info
/* Add the rectangle to the path */
CGPathAddRect(path,
&transform,
rectangle);
/* Get the handle to the current context */
CGContextRef currentContext =
UIGraphicsGetCurrentContext();
/* Add the path to the context */
CGContextAddPath(currentContext,
path);
/* Set the fill color to cornflower blue */
[[UIColor colorWithRed:0.20f
green:0.60f
blue:0.80f
alpha:1.0f] setFill];
/* Set the stroke color to brown */
[[UIColor brownColor] setStroke];
/* Set the line width (for the stroke) to 5 */
CGContextSetLineWidth(currentContext,
5.0f);
/* Stroke and fill the path on the context */
CGContextDrawPath(currentContext,
kCGPathFillStroke);
/* Dispose of the path */
CGPathRelease(path);
}
Figuie 17-35 shows the output ol this Llock ol coue when placeu insiue a view oLject.
Compaie Figuie 17-35 with Figuie 17-27. Can you see the uilleience? Check the souice
coue loi Loth liguies anu you`ll see that the x anu y points specilieu loi Loth iectangles
in Loth coue Llocks aie the same. It is just that in Figuie 17-35, we have applieu an
alline tianslation tiansloimation to the iectangle when we auueu it to the path.
In auuition to applying tiansloimations to shapes that get uiawn to a path, we can
apply tiansloimations to giaphics contexts using the CGContextTranslateCTM pioce-
uuie. This applies a tianslation tiansloimation on the cuiient tiansloimation matiix
(CTM). The cuiient tiansloimation matiix, although its name might Le complex, is
guite simple to unueistanu. Think ol CTM as how youi giaphics context`s centei is set
up, anu how each point that you uiaw gets piojecteu onto the scieen. Foi instance,
when you ask Coie Giaphics to uiaw a point at (0, 0), Coie Giaphics linus the centei
ol the scieen Ly looking at the CTM. The CTM will then uo some calculations anu tell
Coie Giaphics that point (0, 0) is inueeu at the top-lelt coinei ol the scieen. Using
pioceuuies such as CGContextTranslateCTM, you can change how CTM is conliguieu
792 | Chapter 17: Graphics and Animations
www.it-ebooks.info
anu suLseguently loice eveiy shape uiawn on the giaphics context to Le shilteu to
anothei place on the canvas. Heie is an example wheie we achieve the exact same ellect
we saw in Figuie 17-35 Ly applying a tianslation tiansloimation to the CTM insteau
ol uiiectly to the iectangle:
- (void)drawRect:(CGRect)rect{
/* Create the path first. Just the path handle. */
CGMutablePathRef path = CGPathCreateMutable();
/* Here are the rectangle boundaries */
CGRect rectangle = CGRectMake(10.0f,
10.0f,
200.0f,
300.0f);
/* Add the rectangle to the path */
CGPathAddRect(path,
NULL,
rectangle);
/* Get the handle to the current context */
CGContextRef currentContext = UIGraphicsGetCurrentContext();
/* Save the state of the context to revert
back to how it was at this state, later */
CGContextSaveGState(currentContext);
/* Translate the current transformation matrix
to the right by 100 points */
CGContextTranslateCTM(currentContext,
100.0f,
Iigurc 17-35. A rcctang|c with an ajjinc trans|ation transjornation
17.11 Displacing Shapes Drawn on Graphic Contexts | 793
www.it-ebooks.info
0.0f);
/* Add the path to the context */
CGContextAddPath(currentContext,
path);
/* Set the fill color to cornflower blue */
[[UIColor colorWithRed:0.20f
green:0.60f
blue:0.80f
alpha:1.0f] setFill];
/* Set the stroke color to brown */
[[UIColor brownColor] setStroke]; /* Set the line width (for the stroke) to 5 */
CGContextSetLineWidth(currentContext,
5.0f);
/* Stroke and fill the path on the context */
CGContextDrawPath(currentContext,
kCGPathFillStroke);
/* Dispose of the path */
CGPathRelease(path);
/* Restore the state of the context */
CGContextRestoreGState(currentContext);
}
Altei iunning this piogiam, you will notice that the iesults aie exactly like those shown
in Figuie 17-35.
See Also
Recipe 17.S; Recipe 17.12; Recipe 17.13
17.12 Scaling Shapes Drawn on Graphic Contexts
Problem
You want to scale shapes on youi giaphics context up anu uown uynamically.
Solution
Cieate an alline scale tiansloimation using the CGAffineTransformMakeScale lunction.
Discussion
Recipe 17.11 explaineu what a tiansloimation is, anu how to apply it to shapes anu
giaphics contexts. One ol the tiansloimations that you can apply is scaling. You can
easily ask Coie Giaphics to scale a shape, such as a ciicle, to 100 times its oiiginal size.
794 | Chapter 17: Graphics and Animations
www.it-ebooks.info
To cieate an alline scale tiansloimation, use the CGAffineTransformMakeScale lunction,
which ietuins a tiansloimation oLject ol type CGAffineTransform. Il you want to apply
a scale tiansloimation uiiectly to a giaphics context, use the CGContextScaleCTM pio-
ceuuie to scale the Cuiient Tiansloimation Matiix (CTM). Foi moie inloimation
aLout CTM, see Recipe 17.11.
Scale tiansloimation lunctions take two paiameteis: one to scale the x axis anu the
othei to scale the y axis. Take anothei look at the iectangle in Figuie 17-27. Il we want
to scale this iectangle to hall its noimal length anu wiuth, shown in Figuie 17-27, we
can simply scale the x anu the y axis Ly 0.5 (hall theii oiiginal value), as shown heie:
/* Scale the rectangle to half its size */
CGAffineTransform transform =
CGAffineTransformMakeScale(0.5f, 0.5f);
/* Add the rectangle to the path */
CGPathAddRect(path,
&transform,
rectangle);
Figuie 17-36 shows what we will see altei applying the scale tiansloimation to the coue
we wiote in Recipe 17.S.
Iigurc 17-3. Sca|ing a rcctang|c
In auuition to the CGAffineTransformMakeScale lunction, you can use the CGCon
textScaleCTM pioceuuie to apply a scale tiansloimation to a giaphics context. The
lollowing coue will achieve the exact same ellect as the pievious example, as you can
see in Figuie 17-36:
17.12 Scaling Shapes Drawn on Graphic Contexts | 795
www.it-ebooks.info
- (void)drawRect:(CGRect)rect{
/* Create the path first. Just the path handle. */
CGMutablePathRef path = CGPathCreateMutable();
/* Here are the rectangle boundaries */
CGRect rectangle = CGRectMake(10.0f,
10.0f,
200.0f,
300.0f);
/* Add the rectangle to the path */
CGPathAddRect(path,
NULL,
rectangle);
/* Get the handle to the current context */
CGContextRef currentContext = UIGraphicsGetCurrentContext();
/* Scale everything drawn on the current
graphics context to half its size */
CGContextScaleCTM(currentContext,
0.5f,
0.5f);
/* Add the path to the context */
CGContextAddPath(currentContext,
path);
/* Set the fill color to cornflower blue */
[[UIColor colorWithRed:0.20f
green:0.60f
blue:0.80f
alpha:1.0f] setFill];
/* Set the stroke color to brown */
[[UIColor brownColor] setStroke];
/* Set the line width (for the stroke) to 5 */
CGContextSetLineWidth(currentContext,
5.0f);
/* Stroke and fill the path on the context */
CGContextDrawPath(currentContext,
kCGPathFillStroke);
/* Dispose of the path */
CGPathRelease(path);
}
See Also
Recipe 17.11
796 | Chapter 17: Graphics and Animations
www.it-ebooks.info
17.13 Rotating Shapes Drawn on Graphic Contexts
Problem
You want to Le aLle to iotate the contents that you have uiawn on a giaphics context
without changing youi uiawing coue.
Solution
Use the CGAffineTransformMakeRotation lunction to cieate an alline iotation tiansloi-
mation.
Discussion
I stiongly suggest that you ieau the mateiial in Recipes 17.11anu in
17.12Leloie pioceeuing with this section. To avoiu ieuunuancy, I have
tiieu to keep mateiial that has Leen taught in eailiei sections out ol latei
sections.
]ust like scaling anu tianslation, you can apply iotation tianslation to shapes uiawn on
paths, anu giaphics contexts. You can use the CGAffineTransformMakeRotation lunction
anu pass the iotation value in iauians to get Lack a iotation tiansloimation, ol type
CGAffineTransform. You can then apply this tiansloimation to paths anu shapes. Il you
want to iotate the whole context Ly a specilic angle, you must use the CGContextRota
teCTM pioceuuie.
Let`s iotate the same iectangle we hau in Figuie 17-27 +5 uegiees clockwise (see Fig-
uie 17-37). The values you supply loi iotation must Le in iauians. Positive values cause
clockwise iotation, while negative values cause counteiclockwise iotation:
/* Rotate the rectangle 45 degrees clockwise */
CGAffineTransform transform =
CGAffineTransformMakeRotation((45.0f * M_PI) / 180.0f);
/* Add the rectangle to the path */
CGPathAddRect(path,
&transform,
rectangle);
As we saw in Recipe 17.12, we can also apply a tiansloimation uiiectly to a giaphics
context using the CGContextRotateCTM pioceuuie.
See Also
Recipe 17.11; Recipe 17.12
17.13 Rotating Shapes Drawn on Graphic Contexts | 797
www.it-ebooks.info
Iigurc 17-37. Rotating a rcctang|c
17.14 Animating and Moving Views
Problem
You want to animate the uisplacement ol views.
Solution
Use the animation methous ol UIView while uisplacing youi views.
Discussion
Theie aie vaiious ways ol peiloiming animations in iOS: capaLilities aie pioviueu at a
ielatively low level, Lut also at a highei level. The highest level we can get is thiough
UIKit, which is what we will Le uiscussing in this section. UIKit incluues some low-
level Coie Animation lunctionalities anu piesents us with a ieally clean API to woik
with.
The staiting point loi peiloiming animations in UIKit is to call the beginAnima
tions:context: class methou ol the UIView class. Its liist paiametei is an optional name
that you choose loi youi animation, anu the seconu is an optional context that you can
ietiieve latei to pass to uelegate methous ol the animations. Ve will talk aLout these
shoitly.
798 | Chapter 17: Graphics and Animations
www.it-ebooks.info
Altei you stait an animation with the beginAnimations:context: methou, it won`t ac-
tually take place until you call the commitAnimations class methou ol UIView class. The
calculation you peiloim on a view oLject (such as moving it) Letween calling beginAni
mations:context: anu commitAnimations will Le animateu altei the commitAnimations
call. Let`s have a look at an example.
As we saw in Recipe 17.+, I incluueu in my Lunule an image calleu Xcodc.png. This is
Xcoue`s icon, which I lounu Ly seaiching in Google Images (see Figuie 17-1+). Now,
in my view contiollei (see Recipe 17.0), I want to place this image in an image view ol
type UIImageView anu then move that image view liom the top-lelt coinei ol the scieen
to the Lottom-iight coinei.
Heie aie the steps that complete this task:
1. Open the .h lile ol youi view contiollei.
2. Deline an instance ol UIImageView as a piopeity ol the view contiollei, anu call it
xcodeImageView, like so:
#import <UIKit/UIKit.h>
@interface Animating_and_Moving_ViewsViewController : UIViewController
@property (nonatomic, strong) UIImageView *xcodeImageView;
@end
3. Loau the Xcodc.png image into an instance ol UIImage when youi view is loaueu:
- (void) viewDidLoad{
[super viewDidLoad];
UIImage *xcodeImage = [UIImage imageNamed:@"Xcode.png"];
self.xcodeImageView = [[UIImageView alloc]
initWithImage:xcodeImage];
/* Just set the size to make the image smaller */
[self.xcodeImageView setFrame:CGRectMake(0.0f,
0.0f,
100.0f,
100.0f)];
self.view.backgroundColor = [UIColor whiteColor];
[self.view addSubview:self.xcodeImageView];
}
+. Figuie 17-3S shows how the view will look when we iun the piogiam in iOS
Simulatoi.
17.14 Animating and Moving Views | 799
www.it-ebooks.info
Iigurc 17-38. Adding an inagc vicw to a vicw objcct
5. Now when the view appeais on the scieen, in the viewDidAppear: instance methou
ol the view contiollei, we will stait the animation Llock loi the image view anu
stait an animation that moves the image liom its initial location at the top-lelt
coinei ol the scieen to the Lottom-iight coinei. Ve will make suie this animation
happens ovei a live-seconu time peiiou:
- (void) viewDidAppear:(BOOL)paramAnimated{
[super viewDidAppear:paramAnimated];
/* Start from top-left corner */
[self.xcodeImageView setFrame:CGRectMake(0.0f,
0.0f,
100.0f,
100.0f)];
[UIView beginAnimations:@"xcodeImageViewAnimation"
context:(__bridge void *)self.xcodeImageView];
/* Five seconds animation */
[UIView setAnimationDuration:5.0f];
/* Receive animation delegates */
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:
@selector(imageViewDidStop:finished:context:)];
/* End at the bottom-right corner */
[self.xcodeImageView setFrame:CGRectMake(200.0f,
350.0f,
800 | Chapter 17: Graphics and Animations
www.it-ebooks.info
100.0f,
100.0f)];
[UIView commitAnimations];
}
6. Pioviue the implementation loi a imageViewDidStop:finished:context: uelegate
methou loi youi view contiollei, so that it gets calleu Ly UIKit when the animation
linishes. This is optional, anu loi this example I will just log some messages to
piove that the methou was calleu. Latei examples will show how you can use the
methou to kick oll othei activity the moment the animation is linisheu:
- (void)imageViewDidStop:(NSString *)paramAnimationID
finished:(NSNumber *)paramFinished
context:(void *)paramContext{
NSLog(@"Animation finished.");
NSLog(@"Animation ID = %@", paramAnimationID);
UIImageView *contextImageView = (__bridge UIImageView *)paramContext;
NSLog(@"Image View = %@", contextImageView);
}
Now il you iun the app, you will notice that as soon as youi view gets uisplayeu, the
image shown in Figuie 17-3S will stait moving towaius the Lottom-iight coinei, as
shown in Figuie 17-39, ovei a peiiou ol live seconus.
Iigurc 17-39. Thc inagc is aninatcd to thc botton-right corncr oj thc scrccn
17.14 Animating and Moving Views | 801
www.it-ebooks.info
Also, il you look at the output piinteu to the console, you will see something similai
to this il you wait loi the animation to linish:
Animation finished.
Animation ID = xcodeImageViewAnimation
Image View = <UIImageView: 0x68221a0;
frame = (200 350; 100 100);
opaque = NO;
userInteractionEnabled = NO;
layer = <CALayer: 0x68221d0>>
Now let`s go thiough some ol the concepts anu how we actually animateu this image
view. Heie aie the impoitant class methous ol UIView that you shoulu know aLout when
peiloiming animations using UIKit:
beginAnimations:context:
Staits an animation Llock. Any animataLle piopeity change that you apply to views
altei calling this class methou will Le animateu altei the animation is committeu.
setAnimationDuration:
Sets the uuiation ol the animation in seconus.
setAnimationDelegate:
Sets the oLject that will ieceive uelegate oLjects loi vaiious events that coulu hap-
pen Leloie, uuiing, oi altei the animation. Setting a uelegate oLject will not im-
meuiately stait liiing animation uelegates. You must also use uilleient settei class
methous on the view oLject to tell UIKit which selectois in youi uelegate oLject
have to ieceive which uelegate messages.
setAnimationDidStopSelector:
Sets the methou in the uelegate oLject that has to Le calleu when the animation
linishes. This methou has to accept thiee paiameteis in this oiuei:
1. An animation iuentiliei ol type NSString: this will contain the animation iuen-
tiliei passeu to the beginAnimations:context: class methou ol UIView when the
animation was staiteu.
2. A linisheu inuicatoi, ol type NSNumber: this paiametei contains a Loolean
value insiue the NSNumber, which the iuntime sets to YES il it coulu lully linish
the animation Leloie it was stoppeu Ly the coue. Il this is value is set to NO, it
means the animation was inteiiupteu Leloie it was completeu.
3. A context ol type void *: this is the context that was passeu to the beginAni
mations:context: class methou ol UIView when the animation was staiteu.
setAnimationWillStartSelector:
Sets the selectoi that has to Le calleu in the uelegate oLject when the animation
is aLout to stait. The selectoi passeu to this class methou has to have two paiam-
eteis, in this oiuei:
802 | Chapter 17: Graphics and Animations
www.it-ebooks.info
1. An animation iuentiliei ol type NSString: the iuntime sets this to the animation
iuentiliei passeu to the beginAnimations:context: class methou ol UIView when
the animation was staiteu.
2. A context ol type void *: this is the context that was passeu to the beginAni
mations:context: class methou ol UIView when the animation was staiteu.
setAnimationDelay:
Sets a uelay (in seconus) loi the animation Leloie it staits. Il this value is set to
3.0f, loi instance, the animation will stait 3 seconus altei it has Leen committeu.
setAnimationRepeatCount:
Sets the numLei ol times an animation Llock has to iepeat its animation.
Now that we know some ol the most uselul UIView class methous that help us animate
views, let`s look at anothei animation. In this example coue, I want to have two image
views (Loth uisplaying the same image) appeai on the scieen at the same time: one at
the top-lelt coinei anu the othei at the Lottom-iight coinei, as shown in Figuie 17-+0.
Iigurc 17-10. Thc starting position oj thc anination
In this section, I will call the top-lelt image image 1 anu the Lottom-iight
image image 2.
Vhat we aie going to uo in this coue is cieate two images, as mentioneu, in the top-
lelt anu Lottom-iight coineis. Next, we want image 1 to stait moving towaius image
2 ovei a thiee-seconu peiiou, anu then laue away. Vhile image 1 is appioaching image
2, we want image 2 to stait its animation anu move towaius the top-lelt coinei ol the
17.14 Animating and Moving Views | 803
www.it-ebooks.info
scieen, wheie image 1 useu to Le. Ve also want image 2 to complete its animation ovei
a thiee-seconu time peiiou, anu laue away at the enu. This will look rca||y cool when
you iun it on a uevice oi the iOS Simulatoi. Let me show you how to coue it:
1. In the .h lile ol youi view contiollei, ueline two image views:
#import <UIKit/UIKit.h>
@interface Animating_and_Moving_ViewsViewController : UIViewController
@property (nonatomic, strong) UIImageView *xcodeImageView1;
@property (nonatomic, strong) UIImageView *xcodeImageView2;
@end
2. In the viewDidLoad instance methou ol youi view contiollei, initialize Loth ol the
image views anu place them on youi view:
- (void) viewDidLoad{
[super viewDidLoad];
UIImage *xcodeImage = [UIImage imageNamed:@"Xcode.png"];
self.xcodeImageView1 = [[UIImageView alloc]
initWithImage:xcodeImage];
self.xcodeImageView2 = [[UIImageView alloc]
initWithImage:xcodeImage];
/* Just set the size to make the images smaller */
[xcodeImageView1 setFrame:CGRectMake(0.0f,
0.0f,
100.0f,
100.0f)];
[xcodeImageView2 setFrame:CGRectMake(220.0f,
350.0f,
100.0f,
100.0f)];
self.view.backgroundColor = [UIColor whiteColor];
[self.view addSubview:self.xcodeImageView1];
[self.view addSubview:self.xcodeImageView2];
}
3. Implement an instance methou calleu startTopLeftImageViewAnimation loi youi
view contiollei. This methou, as its name suggests, will caiiy out the animation
loi image 1, moving it liom the top-lelt coinei ol the scieen to the Lottom-iight
coinei while lauing it out. Fauing is accomplisheu simply Ly setting the alpha value
to 0:
- (void) startTopLeftImageViewAnimation{
/* Start from top-left corner */
804 | Chapter 17: Graphics and Animations
www.it-ebooks.info
[self.xcodeImageView1 setFrame:CGRectMake(0.0f,
0.0f,
100.0f,
100.0f)];
[self.xcodeImageView1 setAlpha:1.0f];
[UIView beginAnimations:@"xcodeImageView1Animation"
context:(__bridge void *)self.xcodeImageView1];
/* 3 seconds animation */
[UIView setAnimationDuration:3.0f];
/* Receive animation delegates */
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:
@selector(imageViewDidStop:finished:context:)];
/* End at the bottom-right corner */
[self.xcodeImageView1 setFrame:CGRectMake(220.0f,
350.0f,
100.0f,
100.0f)];
[self.xcodeImageView1 setAlpha:0.0f];
[UIView commitAnimations];
}
+. Vhen the animation loi any ol these image views stops, we intenu to iemove those
image views liom theii paient views, as they aie not uselul anymoie. As we saw in
the startTopLeftImageViewAnimation methou, we passeu a uelegate selectoi to the
setAnimationDidStopSelector: class methou ol UIView, anu this selectoi will get
calleu when the animations loi image 1 (as we saw Leloie) anu loi image 2 (as we
will soon see) stop. Heie is the implementation loi this uelegate selectoi:
- (void)imageViewDidStop:(NSString *)paramAnimationID
finished:(NSNumber *)paramFinished
context:(void *)paramContext{
UIImageView *contextImageView = (__bridge UIImageView *)paramContext;
[contextImageView removeFromSuperview];
}
5. Ve also neeu a methou that will animate image 2. Theie is a little uilleience Le-
tween how I`ve wiitten the animation methou loi image 2 as compaieu to that loi
image 1. I want to Le aLle to stait image 2`s animation a|nost as image 1 is linishing
its animation. So il image 1 peiloims its animation in thiee seconus, I want image
2 to stait its animation at seconu 2.0 in image 1`s animation, so that I can see image
2 staiting to animate Leloie image 1 gets to the Lottom-iight coinei ol the scieen
17.14 Animating and Moving Views | 805
www.it-ebooks.info
anu laues away. To accomplish this, I am staiting Loth animations at the same
time, Lut the animation loi image 2 will incluue a two-seconu uelay at the Legin-
ning. So il I stait Loth animations at 1 p.m., image 1 will stait its animation at
13:00:00 anu linish it at 13:00:03, while image 2 staits at 13:00:02 anu linishes at
13:00:05. Heie is how we will animate image 2:
- (void) startBottomRightViewAnimationAfterDelay:(CGFloat)paramDelay{
/* Start from bottom-right corner */
[self.xcodeImageView2 setFrame:CGRectMake(220.0f,
350.0f,
100.0f,
100.0f)];
[self.xcodeImageView2 setAlpha:1.0f];
[UIView beginAnimations:@"xcodeImageView2Animation"
context:(__bridge void *)self.xcodeImageView2];
/* 3 seconds animation */
[UIView setAnimationDuration:3.0f];
[UIView setAnimationDelay:paramDelay];
/* Receive animation delegates */
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:
@selector(imageViewDidStop:finished:context:)];
/* End at the top-left corner */
[self.xcodeImageView2 setFrame:CGRectMake(0.0f,
0.0f,
100.0f,
100.0f)];
[self.xcodeImageView2 setAlpha:0.0f];
[UIView commitAnimations];
}
6. Last Lut not least, we have to liie Loth the startTopLeftImageViewAnimation anu
the startBottomRightViewAnimationAfterDelay: methous at the same time when
the view Lecomes visiLle:
- (void) viewDidAppear:(BOOL)paramAnimated{
[super viewDidAppear:paramAnimated];
[self startTopLeftImageViewAnimation];
[self startBottomRightViewAnimationAfterDelay:2.0f];
}
806 | Chapter 17: Graphics and Animations
www.it-ebooks.info
17.15 Animating and Scaling Views
Problem
You want to Le aLle to animate the scaling up oi uown ol youi views.
Solution
Cieate a scale alline tiansloimation loi youi view anu use the UIView animation meth-
ous to animate the scale tiansloimation.
Discussion
I highly iecommenu that you ieau Recipe 17.1+ Leloie pioceeuing with
this section ol the Look.
In oiuei to scale a view while animating it, you can eithei apply a scale tiansloimation
to it within an animation Llock (see Recipe 17.12), oi just inciease the view`s wiuth
anu/oi height.
Let`s have a look at scaling an image view Ly applying a scale tiansloimation to it:
- (void) viewDidAppear:(BOOL)paramAnimated{
[super viewDidAppear:paramAnimated];
/* Place the image view at the center of the view of this view controller */
self.xcodeImageView.center = self.view.center;
/* Make sure no translation is applied to this image view */
self.xcodeImageView.transform = CGAffineTransformIdentity;
/* Begin the animation */
[UIView beginAnimations:nil
context:NULL];
/* Make the animation five seconds long */
[UIView setAnimationDuration:5.0f];
/* Make the image view twice as large in
width and height */
self.xcodeImageView.transform = CGAffineTransformMakeScale(2.0f,
2.0f);
/* Commit the animation */
[UIView commitAnimations];
}
17.15 Animating and Scaling Views | 807
www.it-ebooks.info
This coue uses an alline scale tiansloimation to scale the image view to Lecome twice
as Lig as it oiiginally was. The Lest thing aLout applying scale tiansloimations to a view
is that the wiuth anu height aie scaleu using the centei ol the view as the centei ol the
scaling. Suppose that the centei ol youi view is at point (100, 100) on the scieen, anu
you scale youi view to Le twice as Lig in wiuth anu height. The iesulting view will have
its centei iemain at point (100, 100) on the scieen, while Leing twice as Lig in each
uiiection. Il you weie to scale a view Ly incieasing its liame`s wiuth anu height explic-
itly, you woulu enu up with the linal view Leing locateu somewheie else on the scieen.
That`s Lecause when changing the liame ol the image view to scale the wiuth anu
height, you aie also changing the value ol the x anu the y ol the liame, whethei you
want to oi not. Because ol that, youi image view will not Le scaleu up liom its centei.
Fixing this issue is outsiue the scope ol this Look, Lut leel liee to play with it loi a while
anu mayLe you will linu the solution. One hint that I wi|| give you is that you can iun
two animations at the same time in paiallel: one loi changing the wiuth anu height,
anu the othei loi changing the centei ol the image view!
See Also
Recipe 17.12; Recipe 17.1+
17.16 Animating and Rotating Views
Problem
You want to animate the iotation ol youi views.
Solution
Cieate a iotation alline tiansloim anu use the animation methous ol UIView to animate
the iotation.
Discussion
I highly iecommenu that you ieau Recipe 17.1+ Leloie pioceeuing with
this section ol the Look.
In oiuei to iotate a view while animating it, you must apply a iotation tiansloimation
to it while in an animation Llock (see Recipe 17.12). Let`s have a look at some sample
coue that will make this cleaiei. Let`s say we have an image nameu Xcodc.png (see
Figuie 17-1+), anu we want to uisplay it in the centei ol the scieen. Altei the image is
uisplayeu, we want to iotate it 90 uegiees ovei a live-seconu time peiiou anu then iotate
808 | Chapter 17: Graphics and Animations
www.it-ebooks.info
it Lack to its oiiginal oiientation. So when the view appeais on the scieen, let`s iotate
the image view 90 uegiees clockwise:
- (void) viewDidAppear:(BOOL)paramAnimated{
[super viewDidAppear:paramAnimated];
self.xcodeImageView.center = self.view.center;
/* Begin the animation */
[UIView beginAnimations:@"clockwiseAnimation"
context:NULL];
/* Make the animation five seconds long */
[UIView setAnimationDuration:5.0f];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:
@selector(clockwiseRotationStopped:finished:context:)];
/* Rotate the image view 90 degrees */
self.xcodeImageView.transform =
CGAffineTransformMakeRotation((90.0f * M_PI) / 180.0f);

/* Commit the animation */
[UIView commitAnimations];
}
Ve`ve chosen the clockwiseRotationStopped:finished:context: selectoi to get calleu
when the clockwise iotation animation linishes. In that methou, we will Le iotating the
image view counteiclockwise Lack to 0 uegiees (wheie it oiiginally was) ovei a live-
seconu time peiiou:
- (void)clockwiseRotationStopped:(NSString *)paramAnimationID
finished:(NSNumber *)paramFinished
context:(void *)paramContext{
[UIView beginAnimations:@"counterclockwiseAnimation"
context:NULL];
/* Five seconds long */
[UIView setAnimationDuration:5.0f];
/* Back to original rotation */
self.xcodeImageView.transform = CGAffineTransformIdentity;
[UIView commitAnimations];
}
17.16 Animating and Rotating Views | 809
www.it-ebooks.info
As you saw in Recipe 17.1+, Recipe 17.15, anu in this section, theie aie many ways to
animate views (uiiect oi inuiiect suLclasses ol UIView) anu many piopeities that you
can mouily while caiiying out youi animations. Be cieative anu inspect othei piopeities
in UIView which you might have not pieviously known aLout. You may also want to
take a look at the uocumentation loi UIView in Xcoue Oiganizei.
See Also
Recipe 17.13; Recipe 17.1+; Recipe 17.15
810 | Chapter 17: Graphics and Animations
www.it-ebooks.info
CHAPTER 18
Core Motion
18.0 Introduction
iOS uevices such as the iPhone anu iPau aie usually eguippeu with acceleiometei haiu-
waie. Some iOS uevices might also incluue a gyioscope, such as the iPhone 5 anu the
new iPau. Beloie attempting to use eithei the acceleiometei oi the gyioscope in youi
iOS applications, you must check the availaLility ol these sensois on the iOS uevice on
which youi app iuns. Recipes 1S.1 anu 1S.2 incluue technigues you can use to uetect
the availaLility ol the acceleiometei anu gyioscope. Vith a gyioscope, iOS uevices such
as the iPhone + anu iPau 2 aie aLle to uetect motion in six axes.
Let`s go thiough a situation that will show you the value ol the gyioscope. The accel-
eiometei cannot uetect the iotation ol the uevice aiounu its veitical axis il you aie
holuing the uevice peilectly still in youi hanus, sitting in a computei chaii, anu iotating
youi chaii in a clockwise oi counteiclockwise lashion. Fiom the stanupoint ol the llooi
oi the Eaith, the uevice is iotating aiounu the veitical axis, Lut it`s not iotating aiounu
its own y-axis, which is the veitical centei ol the uevice. So, the acceleiometei uoes not
uetect any motion.
Howevei, the gyioscope incluueu in some iOS uevices allows us to uetect such move-
ments. This allows moie lluiu anu llawless movement uetection ioutines. This is typ-
ically uselul in games, wheie the uevelopeis neeu to know not only whethei the uevice
is moving on the x-, y-, anu z-axes (inloimation they can get liom the acceleiometei),
Lut also whethei it is changing in ielation to the Eaith along these uiiections, which
ieguiies a gyioscope.
Piogiammeis can use the Coie Motion liamewoik to access Loth the acceleiometei
anu the gyioscope uata (il availaLle). All iecipes in this chaptei make use ol the Coie
Motion liamewoik. Please lollow these steps to auu this liamewoik to youi pioject:
1. Click on youi pioject icon in Xcoue.
2. Select the taiget to which you want to auu the Coie Motion liamewoik.
3. On the top ol the scieen, select the Builu Phases taL.
811
www.it-ebooks.info
+. Unuei Builu Phases, linu anu expanu the Link Binaiy with LiLiaiies Lox anu piess
the little - Lutton on its Lottom-lelt coinei.
5. In the list ol liamewoiks, select the CoieMotion.liamewoik anu piess the Auu
Lutton (see Figuie 1S-1).
Iigurc 18-1. Adding thc Corc Motion jrancwor| to a targct
iOS Simulatoi uoes not simulate the acceleiometei oi the gyioscope haiuwaie. How-
evei, you can geneiate a sha|c with iOS Simulatoi using Haiuwaie Shake Gestuie
(see Figuie 1S-2).
18.1 Detecting the Availability of an Accelerometer
Problem
In youi piogiam, you want to uetect whethei the acceleiometei haiuwaie is availaLle.
Solution
Use the isAccelerometerAvailable methou ol CMMotionManager to uetect the accelei-
ometei haiuwaie. The isAccelerometerActive methou can also Le useu to uetect
whethei the acceleiometei haiuwaie is cuiiently senuing upuates to the piogiam.
812 | Chapter 18: Core Motion
www.it-ebooks.info
Let`s liist make suie we have impoiteu the ieguiieu heauei liles:
#import <UIKit/UIKit.h>
#import <CoreMotion/CoreMotion.h>
@interface Detecting_the_Availability_of_an_AccelerometerAppDelegate
: UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
Next, go on to uetect the availaLility ol acceleiometei in the implementation lile ol oui
app uelegate:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
CMMotionManager *motionManager = [[CMMotionManager alloc] init];
if ([motionManager isAccelerometerAvailable]){
NSLog(@"Accelerometer is available.");
} else{
NSLog(@"Accelerometer is not available.");
}
if ([motionManager isAccelerometerActive]){
NSLog(@"Accelerometer is active.");
} else {
NSLog(@"Accelerometer is not active.");
}
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
Iigurc 18-2. Thc Sha|c Gcsturc option in iOS Sinu|ator
18.1 Detecting the Availability of an Accelerometer | 813
www.it-ebooks.info
return YES;
}
Acceleiometei haiuwaie might Le availaLle on the iOS uevice iunning youi piogiam.
This, howevei, uoes not mean the acceleiometei haiuwaie is senuing upuates to youi
piogiam. Il the acceleiometei oi gyioscope is senuing upuates to youi piogiam, we say
it is activc (which ieguiies you to ueline a uelegate oLject, as we will soon see).
Il you iun this coue on iOS Simulatoi, you will get values similai to these in the console
winuow:
Accelerometer is not available.
Accelerometer is not active.
Running the same coue on an iPhone + uevice, you will get values similai to these:
Accelerometer is available.
Accelerometer is not active.
Discussion
An iOS uevice coulu have a Luilt-in acceleiometei. As we uon`t yet know which iOS
uevices might have acceleiometei haiuwaie Luilt in anu which ones won`t, it is Lest to
test the availaLility ol the acceleiometei Leloie using it.
You can uetect the availaLility ol this haiuwaie Ly instantiating an oLject ol type
CMMotionManager anu accessing its isAccelerometerAvailable methou. This methou is
ol type BOOL anu ietuins YES il the acceleiometei haiuwaie is availaLle anu NO il not.
In auuition, you can uetect whethei the acceleiometei haiuwaie is cuiiently senuing
upuates to youi application (whethei it is active) Ly issuing the isAccelerome
terActive methou ol CMMotionManager. You will leain aLout ietiieving acceleiometei
uata in Recipe 1S.3.
See Also
Recipe 1S.3
18.2 Detecting the Availability of a Gyroscope
Problem
You want to linu out whethei the cuiient iOS uevice that is iunning youi piogiam has
gyioscope haiuwaie availaLle.
Solution
Use the isGyroAvailable methou ol an instance ol CMMotionManager to uetect the gyio-
scope haiuwaie. The isGyroActive methou is also availaLle il you want to uetect
814 | Chapter 18: Core Motion
www.it-ebooks.info
whethei the gyioscope haiuwaie is cuiiently senuing upuates to youi piogiam (in othei
woius, whethei it is active):
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
CMMotionManager *motionManager = [[CMMotionManager alloc] init];
if ([motionManager isGyroAvailable]){
NSLog(@"Gryro is available.");
} else {
NSLog(@"Gyro is not available.");
}
if ([motionManager isGyroActive]){
NSLog(@"Gryo is active.");
} else {
NSLog(@"Gryo is not active.");
}
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
iOS Simulatoi uoes not have gyioscope simulation in place. Il you iun this coue on the
simulatoi, you will ieceive iesults similai to these in the console winuow:
Gyro is not available.
Gyro is not active.
Il you iun the same coue on the oiiginal iPau, you will get the same iesults as you get
liom iOS Simulatoi. Howevei, il you iun this coue on an iOS uevice with a gyioscope,
such as the iPhone + oi iPau 2, the iesults coulu Le uilleient:
Gyro is available.
Gyro is not active.
Discussion
Il you plan to ielease an application that makes use ol the gyioscope, you must make
suie othei iOS uevices without this haiuwaie can iun youi application. Il you aie using
the gyioscope as pait ol a game, loi instance, you must make suie othei iOS uevices
that aie capaLle ol iunning youi application can play the game, although they might
not have a gyioscope installeu. Not all iOS uevices have a gyioscope. This iecipe shows
you how to ueteimine whethei a uevice has a gyioscope.
To achieve this, you must liist instantiate an oLject ol type CMMotionManager. Altei this,
you must access the isGyroAvailable methou (ol type BOOL) anu see whethei the gy-
ioscope is availaLle on the uevice iunning youi coue. You can also use the isGyro
18.2 Detecting the Availability of a Gyroscope | 815
www.it-ebooks.info
Active methou ol the CMMotionManager instance to linu out whethei the gyioscope is
cuiiently senuing youi application any upuates. Foi moie inloimation aLout this,
please ielei to Recipe 1S.5.
See Also
Recipe 1S.5
18.3 Retrieving Accelerometer Data
Problem
You want to ask iOS to senu acceleiometei uata to youi application.
Solution
Use the startAccelerometerUpdatesToQueue:withHandler: instance methou ol CMMotion
Manager. Heie is the heauei lile ol a view contiollei that utilizes CMMotionManager to get
acceleiometei upuates:
#import <UIKit/UIKit.h>
#import <CoreMotion/CoreMotion.h>
@interface Retrieving_Accelerometer_DataViewController : UIViewController
@property (nonatomic, strong) CMMotionManager *motionManager;
@end
Ve will now implement oui view contiollei anu take auvantage ol the startAccelero
meterUpdatesToQueue:withHandler: methou ol the CMMotionManager class:
#import "Retrieving_Accelerometer_DataViewController.h"
@implementation Retrieving_Accelerometer_DataViewController
- (void)viewDidLoad{
[super viewDidLoad];
self.motionManager = [[CMMotionManager alloc] init];
if ([self.motionManager isAccelerometerAvailable]){
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[self.motionManager
startAccelerometerUpdatesToQueue:queue
withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {
NSLog(@"X = %.04f, Y = %.04f, Z = %.04f",
accelerometerData.acceleration.x,
accelerometerData.acceleration.y,
accelerometerData.acceleration.z);
}];
} else {
816 | Chapter 18: Core Motion
www.it-ebooks.info
NSLog(@"Accelerometer is not available.");
}
}
- (BOOL)shouldAutorotateToInterfaceOrientation
:(UIInterfaceOrientation)interfaceOrientation{
return YES;
}
@end
Discussion
The acceleiometei iepoits thiee-uimensional uata (thiee axes) that iOS iepoits to youi
piogiam as x, y, anu z values. These values aie encapsulateu in a CMAccelerationstiuc-
tuie:
typedef struct {
double x;
double y;
double z;
} CMAcceleration;
Il you holu youi iOS uevice in liont ol youi lace with the scieen lacing you in poitiait
moue:
The x-axis iuns liom lelt to iight at the hoiizontal centei ol the uevice, with values
ianging liom 1 to -1 liom lelt to iight.
The y-axis iuns liom Lottom to top at the veitical centei ol the uevice, with values
ianging liom 1 to -1 liom Lottom to top.
The z-axis iuns liom the Lack ol the uevice, thiough the uevice towaiu you, with
values ianging liom 1 to -1 liom Lack to liont.
The Lest way to unueistanu the values iepoiteu liom the acceleiometei haiuwaie is Ly
taking a look at a lew examples. Heie is one: let`s assume you have youi iOS uevice
lacing you with the Lottom ol the uevice pointing to the giounu anu the top pointing
up. Il you holu it peilectly still without tilting it in any specilic uiiection, the values you
have loi the x-, y-, anu z-axes at this moment will Le (x: 0.0, y: -1.0, z: 0.0). Now tiy
the lollowing while the scieen is lacing you anu the Lottom ol the uevice is pointing to
the giounu:
1. Tuin the uevice 90 uegiees clockwise. The values you have at this moment aie (x:
-1.0, y: 0.0, z: 0.0).
2. Tuin the uevice a luithei 90 uegiees clockwise. Now the top ol the uevice must Le
pointing to the giounu. The values you have at this moment aie (x: 0.0, y: -1.0,
z: 0.0).
18.3 Retrieving Accelerometer Data | 817
www.it-ebooks.info
3. Tuin the uevice a luithei 90 uegiees clockwise. Now the top ol the uevice must Le
pointing to the lelt. The values you have iight now aie (x: 1.0, y: 0.0, z: 0.0).
+. Finally, il you iotate the uevice a luithei 90 uegiees clockwise, wheie the top ol
the uevice once again points to the sky anu the Lottom ol the uevice points to the
giounu, the values will Le as they weie oiiginally (x: 0.0, y: 1.0, z: 0.0).
So, liom these values, we can concluue that iotating the uevice aiounu the z-axis
changes the x anu y values iepoiteu Ly the acceleiometei, Lut not the z value.
Let`s conuuct anothei expeiiment. Holu the uevice again so it`s lacing you with its
Lottom pointing to the giounu anu its top pointing to the sky. The values that a piogiam
will get liom the acceleiometei, as you alieauy know, aie (x: 0.0, y: 1.0, z: 0.0). Now
tiy these movements:
1. Tilt the uevice Lackwaiu 90 uegiees aiounu the x-axis so that its top will Le pointing
Lackwaiu. In othei woius, holu it as though it is sitting lace up on a taLle. The
values you get at this moment will Le (x: 0.0, y: 0.0, z: 1.0).
2. Now tilt the uevice Lackwaiu 90 uegiees again so that its Lack is lacing you, its top
is lacing the giounu, anu its Lottom is lacing the sky. The values you get at this
moment will Le (x: 0.0, y: 1.0, z: 0.0).
3. Tilt the uevice Lackwaiu 90 uegiees so that it`s lacing the giounu with its Lack
lacing the sky anu its top pointing towaiu you. The iepoiteu values at this moment
will Le (x: 0.0, y: 0.0, z: 1.0).
+. Anu linally, il you tilt the uevice one moie time in the same uiiection, so the uevice
is lacing you anu its top is lacing the sky, the values you get will Le the same values
you staiteu with.
Theieloie, we can oLseive that iotating the uevice aiounu the x-axis changes the values
ol the y- anu z-axes, Lut not x. I encouiage you to tiy the thiiu type ol iotationaiounu
the y-axis (pointing liom top to Lottom)anu oLseive the changes in the values ie-
poiteu loi the x- anu the z-axes.
To Le aLle to ieceive acceleiometei upuates, you have two options:
The startAccelerometerUpdatesToQueue:withHandler: instance methou ol
CMMotionManager.
This methou will uelivei acceleiometei upuates on an opeiation gueue (ol type
NSOperationQueue) anu will ieguiie a Lasic knowleuge ol Llocks that aie useu ex-
tensively in Gianu Cential Dispatch (GCD). Foi moie inloimation aLout Llocks,
please ielei to Chaptei 6.
The startAccelerometerUpdates instance methou ol CMMotionManager.
Once you call this methou, the acceleiometei (il availaLle) will stait upuating ac-
celeiometei uata in the motion managei oLject. You neeu to set up youi own thieau
to continuously ieau the value ol the accelerometerData piopeity (ol type
CMAccelerometerData) ol CMMotionManager.
818 | Chapter 18: Core Motion
www.it-ebooks.info
In this iecipe, we aie using the liist methou (with Llocks). I highly iecommenu that
you liist ieauChaptei 6 Leloie pioceeuing with this iecipe. The Llock we pioviue to
the startAccelerometerUpdatesToQueue:withHandler: instance methou ol CMMotionMan
ager must Le ol type CMAccelerometerHandler:
typedef void (^CMAccelerometerHandler)
(CMAccelerometerData *accelerometerData, NSError *error);
In othei woius, we must accept two paiameteis on the Llock. The liist one must Le ol
type CMAccelerometerData anu the seconu must Le ol type NSError, as implementeu in
oui example coue.
See Also
Recipe 1S.1
18.4 Detecting Shakes on an iOS Device
Problem
You want to know when the usei shakes an iOS uevice.
Solution
Use the motionEnded:withEvent: methou ol youi app`s winuow oLject.
Discussion
The motionEnded:withEvent: methou ol youi app`s winuow will get calleu whenevei a
motion has Leen captuieu Ly iOS. The simplest implementation ol this methou is this:
- (void) motionEnded:(UIEventSubtype)motion
withEvent:(UIEvent *)event{
/* Do something with the motion */
}
The motion paiametei, as you can see, is ol type UIEventSubtype. One ol the values ol
type UIEventSubtype is UIEventSubtypeMotionShake, which is what we aie inteiesteu in.
As soon as we uetect this event, we know that the usei has shaken hei iOS uevice. In
oiuei to get to oui app`s winuow, though, we neeu to suLclass UIWindow. To uo so,
lollow these steps:
1. In Xcoue, while you have youi pioject openeu, go to File New File.
2. Fiom the lelthanu siue, make suie iOS is the main categoiy anu Cocoa Touch is
the suLcategoiy.
18.4 Detecting Shakes on an iOS Device | 819
www.it-ebooks.info
3. In the list on the iighthanu siue, select OLjective-C class anu then piess Next, as
shown in Figuie 1S-3.
Iigurc 18-3. Crcating a ncw Objcctivc-C c|ass jor our window
+. Now make suie that you aie suLclassing UIWindow anu then piess Next, as shown
in Figuie 1S-+.
Iigurc 18-1. Subc|assing U|Window
820 | Chapter 18: Core Motion
www.it-ebooks.info
5. In this scieen, set the lile name to MyWindow anu piess the Save Lutton, as shown
in Figuie 1S-5.
Iigurc 18-5. Saving thc c|ass ji|c
Now that you have youi winuow class, go to oui app uelegate anu make suie that the
app uelegate`s winuow oLject is an instance ol the class, MyWindow:
#import "Detecting_Shakes_on_an_iOS_DeviceAppDelegate.h"
#import "Detecting_Shakes_on_an_iOS_DeviceViewController.h"
#import "MyWindow.h"
@implementation Detecting_Shakes_on_an_iOS_DeviceAppDelegate
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
self.window = [[MyWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
UIUserInterfaceIdiom device = [[UIDevice currentDevice] userInterfaceIdiom];
if (device == UIUserInterfaceIdiomPhone) {
self.viewController =
[[Detecting_Shakes_on_an_iOS_DeviceViewController alloc]
initWithNibName:@"Detecting_Shakes_on_an_iOS_DeviceViewController_iPhone"
bundle:nil];
18.4 Detecting Shakes on an iOS Device | 821
www.it-ebooks.info
} else {
self.viewController =
[[Detecting_Shakes_on_an_iOS_DeviceViewController alloc]
initWithNibName:@"Detecting_Shakes_on_an_iOS_DeviceViewController_iPad"
bundle:nil];
}
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
Now go to the implementation ol the MyWindow class anu hanule the motionEnded:with
Event: methou:
#import "MyWindow.h"
@implementation MyWindow
- (void) motionEnded:(UIEventSubtype)motion
withEvent:(UIEvent *)event{
if (motion == UIEventSubtypeMotionShake){
NSLog(@"Detected a shake");
}
}
@end
Il you now simulate a shake event even il you aie on iOS Simulatoi (see Recipe 1S.0),
you will see that oui winuow piints the text Detected a shake to the console winuow.
18.5 Retrieving Gyroscope Data
Problem
You want to Le aLle to ietiieve inloimation aLout the uevice`s motion liom the gyio-
scope haiuwaie on an iOS uevice.
Solution
Follow these steps:
1. Finu out whethei the gyioscope haiuwaie is availaLle on the iOS uevice. Please
ielei to Recipe 1S.2 loi uiiections on how to uo this.
2. Il the gyioscope haiuwaie is availaLle, make suie it is not alieauy senuing you
upuates. Please ielei to Recipe 1S.2 loi uiiections.
822 | Chapter 18: Core Motion
www.it-ebooks.info
3. Use the setGyroUpdateInterval: instance methou ol CMMotionManager to set the
numLei ol upuates you want to ieceive pei seconu. Foi instance, loi 20 upuates
pei seconu (one seconu), set this value to 1.0/20.0.
+. Invoke the startGyroUpdatesToQueue:withHandler: instance methou ol CMMotion
Manager. The gueue oLject coulu simply Le the main opeiation gueue (as we will
see latei) anu the hanulei Llock must lollow the CMGyroHandler loimat.
The lollowing coue implements these steps:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
CMMotionManager *manager = [[CMMotionManager alloc] init];
if ([manager isGyroAvailable]){
if ([manager isGyroActive] == NO){
[manager setGyroUpdateInterval:1.0f / 40.0f];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[manager
startGyroUpdatesToQueue:queue
withHandler:^(CMGyroData *gyroData, NSError *error) {
NSLog(@"Gyro Rotation x = %.04f", gyroData.rotationRate.x);
NSLog(@"Gyro Rotation y = %.04f", gyroData.rotationRate.y);
NSLog(@"Gyro Rotation z = %.04f", gyroData.rotationRate.z);
}];
} else {
NSLog(@"Gyro is already active.");
}
} else {
NSLog(@"Gyro isn't available.");
}
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Discussion
Vith CMMotionManager, application piogiammeis can attempt to ietiieve gyioscope
upuates liom iOS. You must liist make suie the gyioscope haiuwaie is availaLle on the
iOS uevice on which youi application is iunning (please ielei to Recipe 1S.2).
Altei uoing so, you can call the setGyroUpdateInterval: instance methou ol CMMotion
18.5 Retrieving Gyroscope Data | 823
www.it-ebooks.info
Manager to set the numLei ol upuates you woulu like to ieceive pei seconu on upuates
liom the gyioscope haiuwaie. Foi instance, il you want to Le upuateu N times pei
seconu, set this value to 1.0/N.
Altei you set the upuate inteival, you can call the startGyroUpdatesToQueue:withHan
dler: instance methou ol CMMotionManager to set up a hanulei Llock loi the upuates.
Foi moie inloimation aLout Llocks, please ielei to Chaptei 6. Youi Llock oLject must
Le ol type CMGyroHandler, which accepts two paiameteis:
gyroData
The uata that comes liom the gyioscope haiuwaie, encompasseu in an oLject ol
type CMGyroData. You can use the rotationRate piopeity ol CMGyroData (a stiuctuie)
to get access to the x, y, anu z values ol the uata, which iepiesent all thiee Eulei
angles known as ioll, pitch, anu yaw, iespectively. You can leain moie aLout these
Ly ieauing aLout llight uynamics.
error
An eiioi ol type NSError that might occui when the gyioscope is senuing us up-
uates.
Il you uo not wish to use Llock oLjects, you must call the startGyroUpdates instance
methou ol CMMotionManager insteau ol the startGyroUpdatesToQueue:withHandler: in-
stance methou, anu set up youi own thieau to ieau the gyioscope haiuwaie upuates
posteu to the gyroData piopeity ol the instance ol CMMotionManager you aie using.
See Also
Recipe 1S.2
824 | Chapter 18: Core Motion
www.it-ebooks.info
CHAPTER 19
iCloud
19.0 Introduction
iClouu is Apple`s clouu inliastiuctuie. A clouu is a name given to a seivice that stoies
inloimation on a centializeu location, wheie the usei cannot physically access the uisk/
memoiy that stoies the inloimation. Foi instance, an iClouu stoiage space coulu Le
allocateu Ly Apple in Caliloinia, anu all iPhone uevices in New Yoik coulu have all
theii iClouu tiallic go to the Caliloinia iClouu uata centei.
The puipose ol using iClouu, liom a piogiammei`s peispective, is to give theii useis
the aLility to seamlessly have theii apps` uata tiansleiieu liom one machine to the othei.
Let`s have a look at a ieal lile example ol when iClouu woulu come in veiy hanuy:
imagine that you have uevelopeu an app calleu Game XYZ. Saiah is a hypothetical usei
ol youi game anu she has puichaseu it thiough the App Stoie. Youi game is a univeisal
app, anu hence can Le iun on Loth the iPhone anu the iPau. It just so happens that
Saiah has an iPau anu an iPhone, anu has installeu youi game on Loth hei uevices. She
is playing youi game at the ollice, anu is at level 12. She goes Lack home anu picks up
hei iPau to play some moie, only to uiscovei that the game staits liom level 1 on hei
iPau Lecause she was playing on hei iPhone all along. This is uelinitely not a pietty
situation. Vhat is Lettei is loi youi game to Le intelligent enough to save its state anu
iesume that state when youi useis stait the game, iegaiuless ol which uevice they have
Leen iunning the game. To hanule this situation, you coulu use iClouu to stoie Saiah`s
game state on hei iPhone anu let iClouu synchionize this uata to the uata centeis that
aie maintaineu Ly Apple. Vhen she picks hei iPau up, you coulu use youi app to contact
iClouu anu linu out il theie is a iecent game state saveu loi Saiah. Il yes, then you can
loau that state loi hei to give hei the leeling that she ieally uiun`t even leave youi game.
She just switcheu uevices. This is a Lit moie woik loi you, Lut in the enu you will get
ieally happy customeis.
Beloie Leing aLle to use iClouu seivices, you liist neeu to enaLle youi app loi iClouu.
This ieguiies cieating the coiiect piovisioning pioliles in iOS Piovisioning Poital anu
then enaLling the coiiect entitlements in youi pioject. You can ieau moie aLout this
in Recipe 19.1.
825
www.it-ebooks.info
I use the teims loluei anu uiiectoiy inteichangeaLly thioughout this
chaptei.
19.1 Setting Up Your App for iCloud
Problem
You want to stait using iClouu in youi apps anu you woulu like to know how you
shoulu set up youi Xcoue pioject.
Solution
Follow these steps to enaLle iClouu stoiage in youi app:
1. Cieate an app in Xcoue anu set its Lunule iuentiliei using a ieveise-uomain style.
Foi instance, com.pixolity.Setting-Up Your-App-For-iCloud.
2. Using the iOS Piovisioning Poital, cieate a new App ID loi youi app. EnaLle iClouu
loi that App ID Ly selecting it in the poital, enaLling the checkLox loi iClouu, anu
saving youi changes.
3. In iOS Piovisioning Poital, cieate new Au Hoc App Stoie anu Development pio-
visioning pioliles, anu make suie they aie linkeu to youi new App ID.
+. Select youi taiget in Xcoue anu set the appiopiiate piovisioning pioliles loi uil-
leient schemes, such as DeLug, Release, etc.
5. In Xcoue, select youi taiget anu in the Summaiy taL, scioll uown to the Entitle-
ments section anu enaLle entitlements loi youi taiget. This will piepopulate the
ielevant iClouu stoiage entitlements loi you.
Discussion
To enaLle iClouu loi an app, you neeu to uo a Lit ol setting up. The high level ieguiie-
ment was uesciiLeu in the Solution section, Lut let`s now go into uetails aLout what
we ieally neeu to uo:
1. Open Xcoue anu liom the File menu select New New Pioject...
2. On the lelthanu siue ol the New Pioject uialog, make suie iOS is the main categoiy
anu Application is the suLcategoiy. Fiom the list that now appeais on the iighthanu
siue ol the New Pioject uialog, choose Empty Application anu piess the Next Lut-
ton (see Figuie 19-1).
826 | Chapter 19: iCloud
www.it-ebooks.info
Iigurc 19-1. Crcating an Enpty App|ication to usc with iC|oud storagc
3. In this scieen (see Figuie 19-2), set the Piouuct Name to Setting Up Your App For
iCloud anu set the Company Iuentiliei to the ieveise uomain name ol youi com-
pany name. Foi instance, I have set this value to com.pixolity. Il youi company
name is XYZ, then you set this value to com.XYZ. Once you aie uone anu youi
settings look like those shown in Figuie 19-2, piess the Next Lutton.
+. Now you aie askeu to save youi pioject. Simply save the pioject on uisk oi wheievei
you wish. Once uone, piess the Cieate Lutton.
5. Ve now neeu to cieate the App ID in iOS Piovisioning Poital. Log in to the iOS
Dev Centei anu liom the menus, select the iOS Piovisioning Poital.
6. In the piovisioning poital, select the App IDs option anu then piess the New App
ID Lutton.
7. In the Desciiption lielu (see Figuie 19-3), entei Setting Up Your App For iCloud.
In the Bunule Seeu ID (App ID Pielix), select the Use Team ID option. In the Bunule
Iuentiliei (App ID Sullix) Lox, choose con. TEAM ID.Sctting-Up-Your-App-Ior-
iC|oud, wheie TEAM ID is youi company name. Foi my example, this woulu Le
com.pixolity.Setting-Up-Your-App-For-iCloud. Once you aie uone, piess the SuL-
mit Lutton.
19.1 Setting Up Your App for iCloud | 827
www.it-ebooks.info
Iigurc 19-2. Sctting thc product nanc and conpany idcntijicr jor a ncw iC|oud app
Iigurc 19-3. Sctting up a ncw App |D jor thc iC|oud app
S. You aie now Lack in the piovisioning poital. Select the Piovisioning item liom the
menu anu then unuei the Development taL, select the New Piolile Lutton.
9. In the Piolile Name lielu, entei Setting Up Your App For iCloud Development. In
the Ceitilicates lielu, check the Lox loi the youi Development Ceitilicate. In the
App ID uiop-uown, select the Sctting Up Your App Ior iC|oud ID that we cieateu
eailiei. In the Devices section, select the uevices you woulu like to allow the
828 | Chapter 19: iCloud
www.it-ebooks.info
uevelopment veision ol youi app to iun. Altei you aie uone, select the SuLmit
Lutton (see Figuie 19-+).
Iigurc 19-1. Crcating a ncw Dcvc|opncnt provision proji|c jor iC|oud
10. Once the app goes thiough the uevelopment anu testing piocess, we aie going to
want to suLmit it to the App Stoie, so let`s go aheau anu cieate the App Stoie
piovisioning piolile as well. In the Piovisioning section ol the iOS Piovisioning
Poital, select the DistiiLution taL anu then piess the New Piolile Lutton.
11. Set the DistiiLution Methou to App Stoie. Set the Piolile Name to Setting Up Your
App For iCloud App Store. In the App ID uiop-uown, select the Sctting Up Your
App Ior iC|oud ID that we cieateu eailiei. Once you aie uone, piess the SuLmit
Lutton (see Figuie 19-5).
12. Navigate to the Development anu then the DistiiLution taLs ol the Piovisioning
section ol the iOS Piovisioning Poital scieen anu piess the Downloau Lutton on
the Development anu the App Stoie piovisioning pioliles that you just cieateu.
13. Once you have uownloaueu the two piovision pioliles, uiag anu uiop them into
iTunes. iTunes will then automatically install these piovision pioliles loi you.
1+. In Xcoue, select youi pioject lile (with the Llue icon), select youi taiget, anu then
choose the Builu Settings taL. Fiom the Lai menu, make suie the All anu the Com-
Lineu options aie selecteu, as shown in Figuie 19-6.
19.1 Setting Up Your App for iCloud | 829
www.it-ebooks.info
Iigurc 19-. Thc Conbincd and A|| bar itcns shou|d bc sc|cctcd in thc Bui|d Scttings tab
15. Scioll uown the Builu Settings list until you get to the Coue Signing section. In that
section, loi DeLug, select the Development piovision piolile anu loi Release, select
the App Stoie piovision piolile we cieateu eailiei (see Figuie 19-7).
Iigurc 19-7. Sctting thc appropriatc provisioning proji|cs jor thc Dcbug and Rc|casc schcncs
Iigurc 19-5. Crcating a ncw Distribution provision proji|c jor iC|oud
830 | Chapter 19: iCloud
www.it-ebooks.info
Il you cannot see these pioliles in youi list, it coulu Le Lecause you have
not yet installeu them. Downloauing the pioliles is not sullicient. You
neeu to uiag anu uiop the uownloaueu piovision pioliles into iTunes.
iTunes will then install those pioliles loi you.
16. Vhile you have youi taiget selecteu, move liom the Builu Settings taL to the Sum-
maiy taL (see Figuie 19-S).
Iigurc 19-8. Thc Sunnary tab oj thc targct
17. Scioll uown in the Summaiy taL until you get to the Entitlements section. In that
section, tick the EnaLle Entitlements checkLox anu Xcoue will automatically set
the ieguiieu entitlements values loi iClouu loi you.
Fantastic. Ve aie now uone. The app is now set up loi iClouu Lecause ol the entitle-
ments anu the piovision pioliles that we cieateu eailiei anu useu in the Builu Settings
ol the taiget. Now it`s time to stait using iClouu in the apps.
19.2 Storing and Synchronizing Dictionaries in iCloud
Problem
You want to stoie key-value uata in uictionaiy loim in iClouu, anu seamlessly ieau anu
wiite to this centializeu anu synchionizeu uictionaiy liom vaiious uevices anu liom
vaiious iClouu accounts.
Solution
Use the NSUbiquitousKeyValueStore class.
The uata that you stoie in iClouu using the NSUbiquitousKeyValueStore is uniguely
cieateu in iClouu using the piovision piolile with which you sign the app anu the enu-
usei`s iClouu account. In othei woiu, you simply stoie values in iClouu using the
NSUbiquitousKeyValueStore class, not woiiying il one usei`s uata is going to clash with
anothei usei`s uata. iClouu uoes that sepaiation loi you.
Discussion
The NSUbiquitousKeyValueStore class woiks veiy similai to the NSUserDefaults class. It
can stoie stiings, Loolean, integei, lloat anu othei values. Each one ol the values has
to have a key associateu with it. You will then Le aLle to ieau the values Ly passing the
keys to this class. The uilleience Letween the NSUbiquitousKeyValueStore anu the
19.2 Storing and Synchronizing Dictionaries in iCloud | 831
www.it-ebooks.info
NSUserDefaults class is that the loimei synchionizes its uictionaiy uata with iClouu,
wheieas the lattei only stoies the uictionaiy locally to a .p|ist lilethis uata will Le
ueleteu once the app gets ueleteu liom the usei`s uevice.
Beloie you can use the NSUbiquitousKeyValueStore class to stoie key-
value uata in iClouu, you must set up the appiopiiate entitlements loi
youi pioject. Please ielei to Recipe 19.1 to leain how to uo this.
An instance ol youi application uses a unigue iuentiliei to stoie uata in the iClouu.
This unigue iuentiliei is maue up ol thiee key pieces:
Tcan |D
This is the unigue iuentiliei loi youi iOS Developei Piogiam. Vhen you sign up
loi iOS Developei Piogiam, Apple will automatically geneiate a unigue iuentiliei
loi youi account. To ietiieve this iuentiliei, simply log into Developei Centei anu
then select Youi Account liom the top menu items. Then choose Oiganization
Piolile liom the menus on the lelt. On the scieen to the iight, youi Team ID is
uisplayeu unuei the Conpany/Organization |D section. No two iOS Developei
accounts can have the same Team ID.
Rcvcrsc donain-sty|c oj conpany idcntijicr
This stiing is usually in the loim ol com.COMPANYNAME, wheie COMPANYNAME is the name
ol youi company anu APPNAME is the name ol youi app. Foi instance, my company
name is Pixolity, so my ieveise uomain style ol company iuentiliei will Le
com.pixolity.
App idcntijicr and optiona| sujjix
This is the stiing that gets attacheu as the sullix to the Reveise uomain-style ol
company iuentiliei. Foi instance Storing and Synchronizing Dictionaries in
iCloud is the name ol the piouuct that I have cieateu loi this iecipe. Once I leu this
value to Xcoue`s pioject uialog when cieating the pioject itsell, the iesulting stiing
Lecame Storing-and-Synchronizing-Dictionaries-in-iCloud, since spaces aie not
alloweu in the app iuentiliei.
The Team ID is always Lounu to the piovision piolile with which you
will sign youi app. You uo not have to entei this value into youi pioject
settings. Foi instance, il my company name is Pixolity anu I set the
ieveise uomain style name loi my app to com.pixolity anu my app ID
to Storing-and-Synchronizing-Dictionaries-in-iCloud, the name that
iClouu will use in the entitlements will Le $(TeamIdentifierPrefix)
com.pixolity.Storing-and-Synchronizing-Dictionaries-in-iCloud.
The $(TeamIdentifierPrefix) value is the Team ID, which will Le ie-
solveu to my actual Team ID when Xcoue compiles my application anu
signs it with a piovision piolile.
832 | Chapter 19: iCloud
www.it-ebooks.info
Now that we aie suie we have set up the pioject piopeily anu entitlements aie set up
as well, then we can move on to using the NSUbiquitousKeyValueStore class to stoie
keys anu values in iClouu. Theie aie vaiious methous that NSUbiquitousKey
ValueStore class exposes to us in oiuei loi us to save the values in iClouu. Some ol these
methous aie listeu anu explaineu heie:
setString:forKey:
Sets a stiing value loi the given key. The stiing must Le ol type NSString. OLviously,
classes that suLclass NSString, such as NSMutableString can also Le stoieu in iClouu
using this methou.
setArray:forKey:
Sets an aiiay value loi the given key. The aiiay can Le eithei a mutaLle oi an
immutaLle aiiay.
setDictionary:forKey:
Sets a mutaLle oi an immutaLle uictionaiy loi the given key.
setBool:forKey:
Sets a Loolean value ol type BOOL loi the given key.
setData:forKey:
Sets a mutaLle oi an immutaLle uata loi the given key.
None ol these methous will actually uo the saving loi you. Il you aie uone setting the
values, then you must call the synchronize methou ol NSUbiquitousKeyValueStore loi
youi settings to Le llusheu liist to iOS anu then synchionizeu with iClouu.
All the woik that we uo with the NSUbiquitousKeyValueStore is uone
thiough the defaultStore class methou ol this class. This class methou
will ietuin an instance ol the NSUbiquitousKeyValueStore class, which is
ieauy loi us to use.
OLviously, altei setting the values loi keys, we aie going to want to ietiieve those values
at some point uuiing the iuntime ol the app. Ve can uo this using some ol the methous
that the NSUbiquitousKeyValueStore pioviues us with. Some ol these methous aie listeu
heie:
stringForKey:
Retuins the stiing associateu with the given key, oi nil il that key cannot Le lounu.
This will Le an immutaLle stiing even il you useu this key to stoie a mutaLle stiing
in iClouu.
arrayForKey:
Retuins the aiiay associateu with the given key, oi nil il that key cannot Le lounu.
This will Le an immutaLle aiiay even il the oiiginal aiiay you stoieu in iClouu loi
this key was mutaLle.
19.2 Storing and Synchronizing Dictionaries in iCloud | 833
www.it-ebooks.info
dictionaryForKey:
Retuins the uictionaiy associateu with the given key, oi nil il that key cannot Le
lounu. The uictionaiy ietuineu Ly this methou will Le immutaLle even il the oiig-
inal uictionaiy you stoieu into iClouu loi this key was mutaLle.
boolForKey:
Retuins the Loolean value ol type BOOL associateu with the given key, oi nil il that
key cannot Le lounu.
dataForKey:
Retuins the uata ol type NSData associateu with the given key, oi nil il that key
cannot Le lounu. The uata ietuineu Ly this methou will Le immutaLle even il the
oiiginal uata stoieu in iClouu loi this key was mutaLle.
So let`s have a look at how we can peihaps use this class in the apps. As you alieauy
know, iClouu`s powei ieally pioves hanuy when you aie shaiing uata Letween two oi
moie uevices loi the same usei. Foi instance, il the usei picks up his iPhone anu ieaus
a Look up to page +0, anu then picks up his iPau, the app that piesents the Look can
see the last page the usei was at, anu opens the Look iight theie. In ellect, we have two
uevices pietenuing to Le one, loi the sake ol usaLility loi the enu-usei. Foi this example,
we will stoie a stiing anu a Loolean value into iClouu using the NSUbiquitousKeyValue
Store class. Ve will place a check to see il those values hau alieauy Leen stoieu in
iClouu; il yes, we will ieau theii value. I can then Luilu this app, iun it on my iPhone
anu then on my iPau, anu see what happens:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

NSUbiquitousKeyValueStore *kvoStore =
[NSUbiquitousKeyValueStore defaultStore];

NSString *stringValue = @"My String";
NSString *stringValueKey = @"MyStringKey";

BOOL boolValue = YES;
NSString *boolValueKey = @"MyBoolKey";

BOOL mustSynchronize = NO;

if ([[kvoStore stringForKey:stringValueKey] length] == 0){
NSLog(@"Could not find the string value in iCloud. Setting...");
[kvoStore setString:stringValue
forKey:stringValueKey];
mustSynchronize = YES;
} else {
NSLog(@"Found the string in iCloud, getting...");
stringValue = [kvoStore stringForKey:stringValueKey];
}

834 | Chapter 19: iCloud
www.it-ebooks.info
if ([kvoStore boolForKey:boolValueKey] == NO){
NSLog(@"Could not find the boolean value in iCloud. Setting...");
[kvoStore setBool:boolValue
forKey:boolValueKey];
mustSynchronize = YES;
} else {
NSLog(@"Found the boolean in iCloud, getting...");
boolValue = [kvoStore boolForKey:boolValueKey];
}

if (mustSynchronize){
if ([kvoStore synchronize]){
NSLog(@"Successfully synchronized with iCloud.");
} else {
NSLog(@"Failed to synchronize with iCloud.");
}
}

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

self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Altei setting up the coiiect piovision pioliles, enaLling entitlements loi this pioject,
anu iunning this app on an iPhone that has alieauy Leen set up with an iClouu account,
we can oLseive these iesults piinteu to the console scieen:
Could not find the string value in iCloud. Setting...
Could not find the boolean value in iCloud. Setting...
Successfully synchronized with iCloud.
Now, I will leave my iPhone sitting heie loi a minute oi two just to make suie that
iClouu has enough time to synchionize my uata with the clouu. I will then iun the same
coue on an iPau to see what happens:
Found the string in iCloud, getting...
Found the boolean in iCloud, getting...
Fantastic. This uemonstiates that iClouu is inueeu synchionizing the uata loi multiple
iOS uevices that aie hookeu to the same iClouu account.
19.3 Creating and Managing Folders for Apps in iCloud
Problem
You want to stoie specilic liles into specilic lolueis within the usei`s iClouu stoiage loi
youi app.
19.3 Creating and Managing Folders for Apps in iCloud | 835
www.it-ebooks.info
Solution
Follow these steps:
1. Make suie youi app is set up to use iClouu (see Recipe 19.1)
2. Select youi pioject lile (with the Llue icon) in Xcoue anu select the Summaiy taL.
3. In the Summaiy taL, scioll uown until you get to the Entitlements section. Finu
the iClouu Containeis list anu copy the liist value in that list. The value loi the
pioject that I have set up loi this iecipe is com.pixolity.Creating-and-Managing-
Folders-for-Apps-in-iCloud. This value will Le uilleient loi youi app.
+. In youi app uelegate, place the stiing that you copieu liom iClouu Containeis list,
into a stiing. Pielix this stiing with youi Team ID (see Recipe 19.2 on how to linu
youi Team ID).
5. Now instantiate an oLject ol type NSFileManager anu pass the path that you cieateu
in the pievious two steps, to the URLForUbiquityContainerIdentifier: methou ol
this class. The value ol this methou will Le the |oca| auuiess loi iClouu stoiage on
the uevice that is iunning youi app. Let`s call this path Root iC|oud Path.
6. Appenu the loluei name that you want to cieate to the Root iClouu Path (see
pievious step). Keep the iesulting path in a stiing oi an instance ol NSURL.
7. Invoke the fileExistsAtPath:isDirectory: methou ol youi lile managei. Il this
methou ietuins NO, then go on to cieate the loluei using the createDirectoryAt
Path:withIntermediateDirectories:attributes:error:methou ol the lile manag-
ei. Il the ietuin value ol the fileExistsAtPath:isDirectory: methou is YES, check
whethei the Loolean value that comes out ol the isDirectory paiametei is NO. Il it
is NO, then you must cieate youi loluei again as instiucteu, Lecause the path that
was lounu Ly the fileExistsAtPath:isDirectory: methou was not a uiiectoiy, Lut
iathei a lile.
Discussion
One ol the things that can make iClouu sound complicateu to uevelopeis is that they
assume, since it is a clouu stoiage, that they have to ueal with URLs outsiue theii apps
oi URLs on the Inteinet. Vell, this is not tiue. Vith iClouu, the URLs that you ueal
with aie actually iOS-ielateu. By that, I mean that the URLs aie local to the uevice
connecteu to iClouu. iClouu will then synchionize these local URLs anu theii uata with
the iClouu stoiage hosteu Ly Apple in the clouu. The uevelopei uoesn`t ieally have to
woiiy aLout this pait, unless theie aie conllicts that neeu to Le iesolveu Lecause two
uevices iunning youi app anu using the same iClouu account simultaneously mouilieu
a iesouice that cannot automatically Le meigeu. Ve will talk aLout this latei; let`s just
locus on cieating lolueis in iClouu loi now.
So let`s now implement what we leaineu in the Solution section ol this chaptei:
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
836 | Chapter 19: iCloud
www.it-ebooks.info

NSFileManager *fileManager = [[NSFileManager alloc] init];

/* Place your team ID here */
NSString *teamID = @"TEAM ID";

NSString *rootFolderIdentifier = [NSString stringWithFormat:
@"%@.com.pixolity.Creating-and-Managing-Folders-for-Apps-in-iCloud",
teamID];

NSURL *containerURL =
[fileManager URLForUbiquityContainerIdentifier:rootFolderIdentifier];

NSString *documentsDirectory = [[containerURL path]
stringByAppendingPathComponent:@"Documents"];
BOOL isDirectory = NO;
BOOL mustCreateDocumentsDirectory = NO;

if ([fileManager fileExistsAtPath:documentsDirectory
isDirectory:&isDirectory]){
if (isDirectory == NO){
mustCreateDocumentsDirectory = YES;
}
} else {
mustCreateDocumentsDirectory = YES;
}

if (mustCreateDocumentsDirectory){
NSLog(@"Must create the directory.");

NSError *directoryCreationError = nil;

if ([fileManager createDirectoryAtPath:documentsDirectory
withIntermediateDirectories:YES
attributes:nil
error:&directoryCreationError]){
NSLog(@"Successfully created the folder.");
} else {
NSLog(@"Failed to create the folder with error = %@",
directoryCreationError);
}

} else {
NSLog(@"This folder already exists.");
}

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

self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
19.3 Creating and Managing Folders for Apps in iCloud | 837
www.it-ebooks.info
The Containei Iuentiliei that Xcoue sets up Ly uelault loi youi appli-
cation is maue out ol a Team ID anu a Bunule Iuentiliei. Il you want,
you can simply change this. One ol the gieat leatuies ol iClouu loi ue-
velopeis is that the containei iuentilieis that you specily loi youi app`s
iClouu stoiage uon`t have to necessaiily Le linkeu in any way to youi
app oi youi app`s Lunule iuentiliei. Il you Lelieve the uelault iuentiliei
is conlusing, just change it to something that makes moie sense to you
anu youi team.
Vhat we can uo now is to wiap the coue into a methou loi ie-use:
- (BOOL) createiCloudDirectory:(NSString *)paramDirectory
recursiveCreation:(BOOL)paramRecursiveCreation
teamID:(NSString *)paramTeamID
iCloudContainer:(NSString *)paramContainer
finalPath:(NSString **)paramFinalPath{

BOOL result = NO;

NSFileManager *fileManager = [[NSFileManager alloc] init];

NSString *rootFolderIdentifier = [NSString stringWithFormat:
@"%@.%@", paramTeamID, paramContainer];

NSURL *containerURL =
[fileManager URLForUbiquityContainerIdentifier:rootFolderIdentifier];

NSString *documentsDirectory = [[containerURL path]
stringByAppendingPathComponent:@"Documents"];

if (paramFinalPath != nil){
*paramFinalPath = documentsDirectory;
} BOOL isDirectory = NO;
BOOL mustCreateDocumentsDirectory = NO;

if ([fileManager fileExistsAtPath:documentsDirectory
isDirectory:&isDirectory]){
if (isDirectory == NO){
mustCreateDocumentsDirectory = YES;
}
} else {
mustCreateDocumentsDirectory = YES;
}

if (mustCreateDocumentsDirectory){
NSLog(@"Must create the directory.");

NSError *directoryCreationError = nil;

if ([fileManager createDirectoryAtPath:documentsDirectory
withIntermediateDirectories:paramRecursiveCreation
attributes:nil
error:&directoryCreationError]){
838 | Chapter 19: iCloud
www.it-ebooks.info
result = YES;
NSLog(@"Successfully created the folder.");
} else {
NSLog(@"Failed to create the folder with error = %@",
directoryCreationError);
}

} else {
NSLog(@"This folder already exists.");
result = YES;
}

return result;

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


/* Place your Team ID here */
NSString *teamID = @"TEAM ID";

NSString *containerID =
@"com.pixolity.Creating-and-Managing-Folders-for-Apps-in-iCloud";

NSString *documentsDirectory = nil;

if ([self createiCloudDirectory:@"Documents"
recursiveCreation:YES
teamID:teamID
iCloudContainer:containerID
finalPath:&documentsDirectory]){
NSLog(@"Successfully created the directory in %@", documentsDirectory);
} else {
NSLog(@"Failed to create the directory.");
}

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

self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
The finalPath paiametei in the new methou is an out paiametei, mean-
ing that it can stoie the linal path ol the uiiectoiy that you cieateu into
an output stiing, shoulu you neeu it loi any othei methou (oi anywheie
in youi app).
OK, now that we have this methou, we can go aheau anu save a iesouice into the
Documents loluei loi the cuiient usei`s iClouu stoiage loi the app:
19.3 Creating and Managing Folders for Apps in iCloud | 839
www.it-ebooks.info
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

/* Place your Team ID here */
NSString *teamID = @"TEAM ID";

NSString *containerID =
@"com.pixolity.Creating-and-Managing-Folders-for-Apps-in-iCloud";

NSString *documentsDirectory = nil;

if ([self createiCloudDirectory:@"Documents"
recursiveCreation:YES
teamID:teamID
iCloudContainer:containerID
finalPath:&documentsDirectory]){
NSLog(@"Successfully created the directory in %@", documentsDirectory);

NSString *stringToSave = @"My String";

NSString *pathToSave = [documentsDirectory
stringByAppendingPathComponent:@"MyString.txt"];

NSError *savingError = nil;

if ([stringToSave writeToFile:pathToSave
atomically:YES
encoding:NSUTF8StringEncoding
error:&savingError]){
NSLog(@"Successfully saved the string in iCloud.");
} else {
NSLog(@"Failed to save the string with error = %@", savingError);
}


} else {
NSLog(@"Failed to create the directory.");
}

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

self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Saving a lile in a clouu URL uoes not explicitly tell iOS that the lile has
to Le placeu in clouu stoiage. Ve will leain aLout saving liles in clouu
stoiage in Recipe 19.5.
840 | Chapter 19: iCloud
www.it-ebooks.info
Il I iun this app on an iPau that has Leen set up to Lackup uata anu liles to an iClouu
account, I can go to the Settings app anu then select the iClouu option in the list. In
the iClouu scieen, I woulu then select Stoiage e Backup. Once in the Stoiage e Backup
scieen, select Manage Stoiage, anu you will Le piesenteu with a scieen similai to that
shown in Figuie 19-9.
Iigurc 19-9. Thc Docuncnts and Data oj thc app arc |istcd in thc Scttings app on thc iPad
Now il you select youi app liom the list (oui app is listeu as Unknown, loi ieasons we
will go thiough latei in this chaptei), you can see a scieen similai to Figuie 19-10).
See Also
Recipe 19.1; Recipe 19.2; Recipe 19.5
19.4 Searching for Files and Folders in iCloud
Problem
You want to seaich loi liles anu/oi lolueis insiue the cuiient iClouu usei`s clouu space
allocateu loi youi app.
19.4 Searching for Files and Folders in iCloud | 841
www.it-ebooks.info
Solution
Use the NSMetadataQuery class.
Discussion
OS X Developeis aie pioLaLly lamiliai with the NSMetadataQuery class. This class allows
uevelopeis to gueiy Spotlight items, whethei they aie liles oi lolueis. In iOS, we will
use this class to seaich loi liles anu lolueis in the iClouu space assigneu to the app loi
the cuiient usei, il she has set up iClouu loi the iOS uevice on which the app is iunning.
To set up a metauata gueiy, theie aie thiee veiy impoitant things that we neeu to uo:
1. Ve neeu to set the pieuicate ol the metauata gueiy. The pieuicate is the scarch
critcria ol the gueiy. This pieuicate will tell the gueiy what items we aie seaiching
loi.
2. Ve also neeu to set the gueiy`s seaich scope. In oiuei to seaich in the usei`s iClouu
Documents loluei, we set this scope to NSMetadataQueryUbiquitousDocuments
Scope. Otheiwise, you can use the NSMetadataQueryUbiquitousDataScope, which
iepiesents the Data loluei in iClouu, a loluei youi app can use to stoie uata ielateu
to the usei-cieateu uocuments. RememLei that the liles you stoie in the usei`s
iClouu shoulu not Le youi app`s tempoiaiy liles oi any othei liles that youi app
Iigurc 19-10. Our string savcd into thc dis| is indccd syncing with iC|oud
842 | Chapter 19: iCloud
www.it-ebooks.info
can ietiieve in some othei way il those liles weien`t piesent in the usei`s iClouu
stoiage. Things that you stoie in the usei`s iClouu stoiage shoulu Le his oi hei
cieations.
3. Altei we stait the gueiy, we shall stait listening loi the NSMetadataQueryDidFinish
GatheringNotification notilication. This notilication gets calleu when the gueiy
has linisheu its seaich. In the methou that hanules this notilication, we can then
look thiough the iesults the gueiy gatheieu loi us anu ueteimine il any ol those
liles/lolueis aie the ones we`ie looking loi.
The setPredicate: instance methou ol NSMetadataQuery class allows us to set the pieu-
icate ol the gueiy. The pieuicate must Le ol type NSPredicate. Ve will use the predica
teWithFormat: class methou ol NSPredicate class to initialize the pieuicate. RememLei,
the pieuicate will tell the gueiy what to seaich loi. The predicateWithFormat: accepts
a loimat stiing in the lollowing loimat:
QUERY_ITEM COMPARISON_CRITERIA PATTERN
The QUERY_ITEM pait ol the loimat ol the pieuicate can Le any ol the NSMetadataItem
constant values. Foi instance, we can use the NSMetadataItemFSNameKey constant value
to tell the pieuicate that the seaich pattein taigets the lile-system name ol the items in
the clouu. Since the loimat pioviueu to the predicateWithFormat: methou can Le a
vaiiaLle numLei ol aiguments, with the liist aigument uictating the loimat ol the iest
ol the aiguments, you can pass %K as the QUERY_ITEM. Foi instance, the lollowing two
pieuicates aie Lasically the same in teims ol how they will supply an input to the
meta uata gueiy:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K like %@",
NSMetadataItemFSNameKey,
@"*"];
NSPredicate *samePredicate = [NSPredicate predicateWithFormat:
@"NSMetadataItemFSNameKey like %@",
@"*"];
The COMPARISON_CRITERIA pait ol the loimat ol the pieuicate can Le any ol the lollowing
values:
>
To inuicate that you aie seaiching loi gueiy items that aie, in value, Liggei than
youi ciiteiia patteins. Foi instance, you can seaich in the uocuments loluei in the
iClouu containei ol an app loi all liles whose size is Liggei than X kiloLytes, wheie
X is uelineu Ly you.
<
This compaiison ciiteiia is similai to the pievious ciiteiia. This ciiteiia looks loi
items in the iClouu containei ol an app whose size (as an example) is smallei than
the lile size that you have specilieu in the pattein.
19.4 Searching for Files and Folders in iCloud | 843
www.it-ebooks.info
|i|c
This compaiison ciiteiia is useu loi seaiching loi lile names anu uisplay names ol
liles. You can even use wilucaius with this ciiteiia; loi instance, looking loi all liles
whose names stait with a specilic chaiactei.
Ve can go on anu on aLout this, Lut I suggest we uive into the uevelopment piece to
get a Lettei unueistanuing ol how metauata gueiies woik. Foi this example, heie is
what we will uo:
1. Vhen the app loaus (in the app uelegate), we will simply seaich loi a|| liles in the
app`s iClouu containei.
2. Ve will then log the names ol all the liles that we lounu to the console, using NSLog.
3. At the enu ol eveiy seaich, we will cieate a new lile whose name is geneiateu ian-
uomly using a ianuom integei. Ve will then make suie that lile uoesn`t alieauy
exist in the iClouu containei loi the app. Il it uoesn`t, we will save it to the iClouu
containei. Simple, isn`t it? This way, whenevei the app opens up, we aie cieating
a new lile to the usei`s iClouu stoiage.
Stoiing unnecessaiy liles in useis` iClouu stoiage is a ieally Lau piactice.
Make suie, as stateu Leloie, that you only use iClouu to stoie liles that
have Leen uiiectly cieateu Ly youi usei, such as uocuments oi cieative
images. Foi this example, since we neeu to linu liles/lolueis in the usei`s
iClouu containei to piove that the solution woiks, we neeu to at least
have something stoieu in the iClouu containei loi the app.
Although we aie going to leain aLout stoiing liles in the iClouu in Recipe 19.5, loi the
sake ol this iecipe, we will use anothei, easiei methou to stoie liles into iClouu. Ve
will accomplish this using the setUbiquitous:itemAtURL:destinationURL:error: in-
stance methou ol NSFileManager. The paiameteis that we will pass to this methou aie:
setUbiquitous
This is a Loolean value that you set to YES il you want to move a lile to the iClouu.
itemAtURL
The paiametei passeu to this methou is the NSURL pointing to the lile in youi app`s
Lunule that neeus to Le moveu to iClouu.
destinationURL
This is the URL ol wheie the souice lile has to Le copieu in the usei`s iClouu stoiage.
This URL must Le an iClouu URL.
error
A pointei to an NSError oLject that will get set to an eiioi, il one occuis uuiing
piocess.
844 | Chapter 19: iCloud
www.it-ebooks.info
So let`s go aheau anu cieate a Single View Application, anu then ueline the view con-
tiollei with a metauata gueiy piopeity that we will use loi seaiching in the app`s iClouu
containei:
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@property (nonatomic, strong) NSMetadataQuery *metadataQuery;
@end
Vhen the view contiollei is loaueu, in the viewDidLoad methou, we shall stait the gueiy
anu seaich loi all liles in the Documents uiiectoiy ol the app`s iClouu containei:
- (void)viewDidLoad{

[super viewDidLoad];

/* Listen for a notification that gets fired when the metadata query
has finished finding the items we were looking for */
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(handleMetadataQueryFinished:)
name:NSMetadataQueryDidFinishGatheringNotification
object:nil];

// Do any additional setup after loading the view, typically from a nib.
self.metadataQuery = [[NSMetadataQuery alloc] init];
NSArray *searchScopes = [[NSArray alloc] initWithObjects:
NSMetadataQueryUbiquitousDocumentsScope, nil];
[self.metadataQuery setSearchScopes:searchScopes];
NSPredicate *predicate = [NSPredicate predicateWithFormat:
@"%K like %@",
NSMetadataItemFSNameKey,
@"*"];
[self.metadataQuery setPredicate:predicate];
if ([self.metadataQuery startQuery]){
NSLog(@"Successfully started the query.");
} else {
NSLog(@"Failed to start the query.");
}
}
In this coue, we have electeu the handleMetadataQueryFinished: instance methou ol
the view contiollei (yet to Le implementeu) as the methou that the gueiy will call
whenevei it has linisheu seaiching insiue the Documents loluei ol the app`s iClouu
containei. Let`s go anu implement this methou. Vhat we want to uo in this methou is
to look loi all the liles that the metauata gueiy lounu (il any), anu then list them Ly
piinting them out to the console. Altei this, we will cieate a new ianuom lile anu place
it in the app`s iClouu containei. Heie aie the steps that we have to take in oiuei to
achieve this:
19.4 Searching for Files and Folders in iCloud | 845
www.it-ebooks.info
1. Geneiate a URL loi a new ianuom lile in the app`s iClouu containei. Foi this, we
liist neeu to linu the app`s iClouu containei URL.
2. Il the URL loi this new ianuom lile alieauy exists in the iesults ietuineu Ly the
metauata gueiy, we will ignoie the whole opeiation.
3. Il a lile with the exact same name as the new ianuom lile has not Leen cieateu in
the Documents uiiectoiy ol the app`s iClouu containei, we will save a lile with the
same name to the app`s Documents uiiectoiy in the app`s sanuLox on the uevice.
+. Altei the lile has Leen cieateu in the app`s sanuLox, we will set it to uLiguitous,
wheie the lile will Le moveu to iClouu anu will automatically Le ueleteu liom the
app`s sanuLox.
As uesciiLeu Leloie, we aie going to have to stoie a lile into the app`s Documents loluei,
on the app`s sanuLox, anu in iClouu. Theieloie, we neeu to have some methous that
give us these URLs. Fiist we will stait with a methou that will ietuin the URL loi the
app`s Documents loluei in iClouu:
- (NSURL *) urlForDocumentsFolderIniCloud{

NSURL *result = nil;

#error Put your TEAM ID here
const NSString *TeamID = @"YOUR TEAM ID";

NSString *containerID = [[NSBundle mainBundle] bundleIdentifier];

NSString *teamIDAndContainerID = [[NSString alloc] initWithFormat:@"%@.%@",
TeamID,
containerID];

NSFileManager *fileManager = [[NSFileManager alloc] init];

NSURL *appiCloudContainerURL =
[fileManager URLForUbiquityContainerIdentifier:teamIDAndContainerID];

result = [appiCloudContainerURL URLByAppendingPathComponent:@"Documents"
isDirectory:YES];

if ([fileManager fileExistsAtPath:[result path]] == NO){

/* The Documents directory does NOT exist in the app's iCloud container;
attempt to create it now */

NSError *creationError = nil;
BOOL created = [fileManager createDirectoryAtURL:result
withIntermediateDirectories:YES
attributes:nil
error:&creationError];

if (created){
NSLog(@"Successfully created the Documents folder in iCloud.");
} else {
846 | Chapter 19: iCloud
www.it-ebooks.info
NSLog(@"Failed to create the Documents folder in iCloud. Error = %@",
creationError);
result = nil;
}

} else {
/* the Documents directory already exists in the app's iCloud container;
we don't have to do anything */
}

return result;

}
Now we will use this methou to ueteimine the URL ol the ianuom lile in the Documents
loluei in the iClouu containei loi the app:
- (NSURL *) urlForRandomFileInDocumentsFolderIniCloud{

NSURL *result = nil;

NSUInteger randomNumber = arc4random() % NSUIntegerMax;

NSString *randomFileName = [[NSString alloc] initWithFormat:@"%llu.txt",
(unsigned long)randomNumber];

/* Check in the metadata query if this file already exists */
__block BOOL fileExistsAlready = NO;
[self.metadataQuery.results enumerateObjectsUsingBlock:
^(NSMetadataItem *item, NSUInteger idx, BOOL *stop) {
NSString *itemFileName = [item valueForAttribute:NSMetadataItemFSNameKey];
if ([itemFileName isEqualToString:randomFileName]){
NSLog(@"This file already exists. Aborting...");
fileExistsAlready = YES;
*stop = YES;
}
}];

if (fileExistsAlready){
return nil;
}

result = [[self urlForDocumentsFolderIniCloud]
URLByAppendingPathComponent:randomFileName];

return result;

}
Now that we have the URL loi the ianuom lile (yet to Le cieateu) in iClouu, we also
neeu to wiite a methou that we can use to get the URL loi the same lile in the app
Lunule. Since we cieateu this ianuom lile name in the urlForRandomFileInDocuments
FolderIniCloud methou, the new methou won`t know aLout this name anu thus we
neeu to pass the lile name to the methou as a paiametei:
19.4 Searching for Files and Folders in iCloud | 847
www.it-ebooks.info
- (NSURL *) urlForRandomFileInDocumentsFolderInAppSandbox
:(NSString *)paramFileName{

NSURL *result = nil;

NSString *documentsFolderInAppSandbox =
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES) objectAtIndex:0];

NSString *filePath = [documentsFolderInAppSandbox
stringByAppendingPathComponent:paramFileName];

result = [NSURL fileURLWithPath:filePath];

return result;

}
Next, we have to implement a methou that we will soon use to enumeiate thiough the
metauata items ietuineu Ly the metauata gueiy:
- (void) enumerateMetadataResults:(NSArray *)paramResults{

[paramResults enumerateObjectsUsingBlock:
^(NSMetadataItem *item, NSUInteger index, BOOL *stop) {

NSString *itemName = [item valueForAttribute:NSMetadataItemFSNameKey];
NSURL *itemURL = [item valueForAttribute:NSMetadataItemURLKey];
NSNumber *itemSize = [item valueForAttribute:NSMetadataItemFSSizeKey];

NSLog(@"Item name = %@", itemName);
NSLog(@"Item URL = %@", itemURL);
NSLog(@"Item Size = %llu",
(unsigned long long)[itemSize unsignedLongLongValue]);

}];

}
Last Lut not least, we will implement the handleMetadataQueryFinished: methou, which
will get calleu Ly the notilication centei when the metauata gueiy linishes seaiching
loi the gueiy:
- (void) handleMetadataQueryFinished:(id)paramSender{

NSLog(@"Search finished");

if ([[paramSender object] isEqual:self.metadataQuery] == NO){
NSLog(@"An unknown object called this method. Not safe to proceed.");
return;
}

/* Stop listening for notifications as we are not expecting anything more */
[[NSNotificationCenter defaultCenter] removeObserver:self];

848 | Chapter 19: iCloud
www.it-ebooks.info
/* We are done with the query, let's stop the process now */
[self.metadataQuery disableUpdates];
[self.metadataQuery stopQuery];

[self enumerateMetadataResults:self.metadataQuery.results];

if ([self.metadataQuery.results count] == 0){
NSLog(@"No files were found.");
}

NSURL *urlForFileIniCloud = [self urlForRandomFileInDocumentsFolderIniCloud];

if (urlForFileIniCloud == nil){
NSLog(@"Cannot create a file with this URL. URL is empty.");
return;
}

NSString *fileName = [[[urlForFileIniCloud path]
componentsSeparatedByString:@"/"] lastObject];

NSURL *urlForFileInAppSandbox =
[self urlForRandomFileInDocumentsFolderInAppSandbox:fileName];

NSString *fileContent =
[[NSString alloc] initWithFormat:@"Content of %@",
[[self urlForRandomFileInDocumentsFolderIniCloud] path]];

/* Save the file temporarily in the app bundle and then move
it to the cloud */
NSError *writingError = nil;
BOOL couldWriteToAppSandbox =
[fileContent writeToFile:[urlForFileInAppSandbox path]
atomically:YES
encoding:NSUTF8StringEncoding
error:&writingError];

/* If we cannot save the file, just return from method because it won't make
any sense to continue as we, ideally, should have stored the file in iCloud
from the app sandbox but here, if an error has occurred,
we cannot continue */
if (couldWriteToAppSandbox == NO){
NSLog(@"Failed to save the file to app sandbox. Error = %@", writingError);
return;
}

NSFileManager *fileManager = [[NSFileManager alloc] init];

/* Now move the file to the cloud */
NSError *ubiquitousError = nil;
BOOL setUbiquitousSucceeded =
[fileManager setUbiquitous:YES
itemAtURL:urlForFileInAppSandbox
destinationURL:urlForFileIniCloud
error:&ubiquitousError];

19.4 Searching for Files and Folders in iCloud | 849
www.it-ebooks.info
if (setUbiquitousSucceeded){
NSLog(@"Successfully moved the file to iCloud.");
/* The file has been moved from App Sandbox to iCloud */
} else {
NSLog(@"Failed to move the file to iCloud with error = %@",
ubiquitousError);
}

}
You can now go aheau anu iun the app anu see loi youisell. Once you open anu close
the app a lew times, you will Le aLle to see something similai to Figuie 19-11 in the
Settings app on youi iOS uevice.
Oui app only cieates a new lile when the metauata gueiy linishes. The metauata gueiy
gets liieu in the viewDidLoad methou ol the view contiollei, which itsell gets liieu when
the only view gets loaueu. Theieloie, il you simply open the app anu piess the Home
Lutton on youi iOS uevice, anu then open the app again, the app might not cieate a
new lilethe app was simply sent to the Lackgiounu insteau ol Leing teiminateu anu
ieopeneu. To make suie the app cieates a new lile eveiy time you open it, Leloie opening
the app, close it manually liom the apps Lai in iOS Ly uouLle-piessing the Home Lutton
anu closing the app liom the list ol iunning apps.
Iigurc 19-11. Thc |ist oj randon ji|cs that thc app has crcatcd in iC|oud
850 | Chapter 19: iCloud
www.it-ebooks.info
See Also
Recipe 19.5
19.5 Storing User Documents in iCloud
Problem
You want to allow the useis ol youi app to cieate uocuments in youi app anu you want
to have those uocuments piesent on all uevices that the usei owns.
Solution
Use UIDocument.
Discussion
Although a usei can have many liles ol uilleient types stoieu on hei uevice Ly uilleient
apps, each app has to Le consiueiate ol the amount ol uata that it puts in the usei`s
iClouu stoiage. Theieloie, only the uata that the usei geneiates while using youi app
might neeu to Le saveu to the usei`s iClouu stoiage space. Foi instance, il you aie
cieating a weL-Liowsei app, the uata that youi Liowsei app caches on uisk on the
uevice shoulu not Le stoieu in the clouu. Vhy? Because that uata was not geneiateu
Ly the usei. Youi app simply was tiying to give a Lettei usei expeiience Ly caching the
uata so that the next time it accesseu the same seiies ol weL pages, the pages woulu
loau lastei. Il you look at it liom the usei`s peispective, she uiun`t ieally ask you to
cache the uata. Vhat`s even woise is that youi app is now using the usei`s iClouu
stoiage (loi which she might have pioLaLly paiu) to stoie cacheu uata. That is simply
wiong. You must tell the usei what uata youi app is stoiing in the clouu, anu il she
uoesn`t allow you to use hei clouu stoiage space, you shoulu avoiu using that space
anu just stoie the uata locally in youi app`s sanuLox.
One ol the most conlusing lacts aLout iClouu is how you, as the piogiammei, will neeu
to manage the uata stoieu in the clouu. Beloie iClouu, as piogiammeis, we weie only
conceineu aLout the uata we stoieu in the app`s sanuLox. Now we neeu to leain aLout
a seconuaiy stoiage space calleu iClouu stoiage. A lot ol piogiammeis tenu to get
conluseu when it comes to iClouu stoiage, anu I peisonally think that Apple might
have maue it a Lit complicateu in theii uocumentation. Peihaps this is something that
will Le solveu at a latei stage ol iOS uevelopment, Lut loi now, heie aie a lew key points
you will neeu to leain aLout in oiuei to integiate iClouu stoiage into youi apps anu
allow the loauing anu saving ol useis` uocuments liom anu to iClouu:
19.5 Storing User Documents in iCloud | 851
www.it-ebooks.info
1. A lile that is piesent on the usei`s clouu stoiage is uLiguitous. ULiguitous liles aie
liles that aie stoieu outsiue an app`s sanuLox. Ve will talk aLout these moie, Lut
loi now, iememLei that a uLiguitous lile is a lile that is no longei piesent in the
app`s sanuLox, Lut iathei in the clouu.
2. Ve have to suLclass the UIDocument class in oiuei to manage useis` uocuments.
Each uocument will Le given a uLiguitous URL to loau its contents liom. In the
suLclass, all we ieally have to uo is to implement two veiy impoitant methous that
will allow iOS to pass uata to us (when iOS ieaus the uata liom iClouu) anu loi us
to Le aLle to pass uata to iOS to stoie on iClouu.
3. Youi uLiguitous liles uo not necessaiily have to Le in youi app sanuLox. Il you
want to stoie a lile in iClouu, you will simply ietiieve a uiiect URL to the iClouu
loluei (moie on this latei) anu place youi liles theie.
+. Beloie you go anu cieate liles in the usei`s iClouu stoiage, you must liist gueiy the
iClouu stoiage to see il that lile alieauy exists oi not.
5. Each app has an iuentiliei; iClouu uses that iuentiliei to sepaiate the iClouu liles
loi that app liom liles liom othei apps piesent on useis` iOS uevices. Il you use
the same app iuentiliei acioss multiple apps, all those apps will Le aLle to shaie
each othei`s iClouu stoiage space. This can Le goou il you aie ueveloping a lite
veision ol youi app anu you want the lull veision to Le aLle to access the iClouu
stoiage ol the lite veision ol youi app, anu vice veisa.
6. You can seaich loi liles in youi app`s iClouu stoiage loi the cuiient usei, using the
NSMetadataQuery class (ielei to Recipe 19.+ loi moie inloimation).
In this iecipe, we woulu like to wiite an app that simply cieates a uocument loi the
usei (text lile) anu allows him to euit that uocument. In the Lackgiounu, we will save
that uocument to iClouu so that il he has anothei iOS uevice set up with the same
iClouu cieuentials (useiname anu passwoiu), he can see the most up-to-uate veision
ol the lile, iegaiuless ol which iOS uevice he is euiting it on. Heie is the checklist loi
this app:
1. Ve neeu to set up the appiopiiate piovision pioliles loi the app, as well as enti-
tlements (see Recipe 19.1 loi moie inloimation).
2. Now we have to give the uocument a name (loi now, let`s call the uocument lile
UscrDocuncnt.txt).
3. Vhen the app opens (whethei it is loi the liist time oi not), we will liie up a
metauata gueiy anu tiy to linu the lile in the usei`s iClouu stoiage. Il that lile alieauy
exists, we will ietiieve its URL. Il that lile uoesn`t exist, we will cieate an empty/
uummy lile in that URL.
+. Now that we have the URL loi the uocument lile in the usei`s iClouu stoiage, we
will open that uocument into the instance ol the suLclass ol UIDocument. Ve will
leain aLout this in a minute.
852 | Chapter 19: iCloud
www.it-ebooks.info
Something that can conluse any piogiammei is using the UIDocument classLut to Le
peilectly honest, il you want to stait with the Lasics, theie aie only loui things you neeu
to leain aLout this class:
1. You must always suLclass this class. This class itsell uoesn`t know how to loau its
contents oi how to pass its contents as uata to iOS to stoie in the clouu.
2. You must initialize this class with the URL ol a lile. In this iecipe, we will pass the
URL ol a lile in the usei`s clouu stoiage to the uesignateu initializei ol this class.
3. In youi suLclass, you must oveiiiue the contentsForType:error: instance methou
ol UIDocument. The ietuin value ol this methou can Le an NSData snapshot ol the
uocument you aie managing. Foi instance, il it is a text lile whose URL you passeu
to the initializei ol youi uocument class, then you must simply conveit that text
(piesumaLly in the loim ol NSString) to NSData anu ietuin that uata as the ietuin
value ol this methou. iOS calls this methou in youi uocument whenevei it neeus
to stoie that uata to the clouu oi neeus to ieau that content to piesent it to the usei.
+. You must oveiiiue the loadFromContents:ofType:error: instance methou ol youi
UIDocument suLclass. In this methou, iOS passes you the uata (that peihaps was
ieau liom the clouu stoiage), anu you must ieau that uata into text (il text is what
youi uocument manages).
So, assuming that we have alieauy set up the app with iClouu (see Recipe 19.1), we
will go aheau anu stait suLclassing UIDocument. In this iecipe, we want to cieate a
Documents loluei in the usei`s iClouu stoiage loi the app (il this loluei uoesn`t exist
yet). Ve will then ieau liom/stoie a lile nameu UscrDocuncnt.txt in this loluei. Follow
these steps to suLclass the UIDocument class:
1. In Xcoue, select File New New File... liom the menus.
2. In the New File uialog, make suie the Cocoa Touch suLcategoiy ol the iOS categoiy
is selecteu on the lelthanu siue. Then select the OLjective-C class item on the
iighthanu siue ol the uialog anu piess the Next Lutton (see Figuie 19-12).
3. In the next scieen, name youi new class CloudDocument anu make suie you aie
suLclassing UIDocument, as shown in Figuie 19-13. Once you aie uone, piess the
Next Lutton.
+. In the next uialog, select wheie you wish to save the new class anu piess the Cieate
Lutton (see Figuie 19-1+).
19.5 Storing User Documents in iCloud | 853
www.it-ebooks.info
Iigurc 19-12. Bcginning to crcatc a ncw docuncnt c|ass
Iigurc 19-13. Subc|assing U|Docuncnt
854 | Chapter 19: iCloud
www.it-ebooks.info
Iigurc 19-11. Saving thc subc|ass to dis|
Now that we have the UIDocument suLclass, we neeu to see how we can initialize it. The
uesignateu initializei ol UIDocument class is the initWithFileURL: methou. Howevei, we
neeu to change this a Lit, as we aie going to neeu a uelegate oLject as well. Vhy uo we
neeu a uelegate oLject, you might Le asking? Ve want to let the uelegate oLject know
whenevei iOS uownloaus a newei veision ol the uocument liom iClouu. Imagine this
scenaiio: the usei has two iOS uevices iunning youi app anu she has alieauy set up
those uevices with hei iClouu cieuentials. Now she opens youi app on hei iPhone anu
staits wiiting some text into the text view. She leaves the app anu goes to iun some
eiianus. She comes Lack anu picks up hei iPad (as opposeu to hei iPhone, which she
oiiginally useu to wiite content in the app), anu sees that the app pickeu up the latest
veision ol the uocument anu shows that content. RememLei that the app is still piesent
in the Lackgiounu on hei iPhone. She auus some text to the uocument on the iPau anu
goes Lack to the iPhone. At this point, iClouu has pioLaLly alieauy pickeu up the
veision that hei iPau synceu to the clouu anu has uownloaueu that uocument into hei
iPhone. At this point, the uocument oLject has to Le intelligent enough to piesent the
new content to a uelegate oLject. In this case, we can nominate the view contiollei (the
ownei ol the text view) as the uelegate oLject ol the uocument. The whole point is that
we neeu to cieate a uelegate oLject that will Le notilieu whenevei iClouu gives a new
19.5 Storing User Documents in iCloud | 855
www.it-ebooks.info
veision ol uata, which we neeu to initialize the uocument. Let`s ueline this piotocol in
the heauei lile ol the uocument anu ueline a new uesignateu initializei loi the class:
#import <UIKit/UIKit.h>
@class CloudDocument;
@protocol CloudDocumentProtocol<NSObject>
- (void) cloudDocumentChanged:(CloudDocument *)paramSender;
@end
@interface CloudDocument : UIDocument
@property (nonatomic, strong) NSString *documentText;
@property (nonatomic, weak) id<CloudDocumentProtocol> delegate;
/* Designated Initializer */
- (id) initWithFileURL:(NSURL *)paramURL
delegate:(id<CloudDocumentProtocol>)paramDelegate;
@end
Heie is a Liiel uesciiption ol what is going on in this heauei lile:
Thc CloudDocumentProtocol protoco|
This is the piotocol that this uocument`s uelegate oLject has to auapt in oiuei to
stay up-to-uate aLout the changes to the cuiient uocument that aie Liought into
the usei`s cuiient uevice via iClouu.
Thc documentText string
This is a simple stiing that we will use to house the content ol the uocument. The
usei will pass the URL ol the lile that we neeu to initialize the uocument to the
class`s uesignateu initializei. The UIDocument class will then ieau the contents ol
that URL loi us (we uon`t have to uo it manually) anu will pass the uata ol that lile
to the class. All we have to uo is conveit that uata to the loimat we aie managing
in the uocument (in this case, NSString).
Thc initWithFileURL:delegate: dcsignatcd initia|izcr
This is the class`s uesignateu initializei, anu veiy similai to the uesignateu initializei
ol the supeiclass. The uilleience is that we aie asking loi a seconu paiametei that
will Le the uelegate ol an instance ol the class. Ve will keep the uelegate oLject
upuateu whenevei new content is uownloaueu Ly iOS liom iClouu loi the uocu-
ment we aie managing.
Ve will lollow that with the implementation ol the class`s uesignateu initializei:
- (id) initWithFileURL:(NSURL *)paramURL
delegate:(id<CloudDocumentProtocol>)paramDelegate{

self = [super initWithFileURL:paramURL];

if (self != nil){

856 | Chapter 19: iCloud
www.it-ebooks.info
if (paramDelegate == nil){
NSLog(@"Warning: no delegate is given.");
}

_delegate = paramDelegate;
}

return self;

}
- (id) initWithFileURL:(NSURL *)paramURL{
return [self initWithFileURL:paramURL
delegate:nil];
}
As uesciiLeu Leloie, we shall now implement the contentsForType:error: instance
methou ol the class. This methou gets calleu whenevei iOS ueciues to ieau the contents
ol the uocument that the instance ol the class is managing. Foi instance, iOS might ask
the instance to say what contents it is managing so that iOS can stoie that content on
iClouu. In this methou, we will simply conveit the stiing to an instance ol NSData anu
ietuin it:
- (id) contentsForType:(NSString *)typeName
error:(NSError *__autoreleasing *)outError{

if ([self.documentText length] == 0){
self.documentText = @"New Document";
}

return [self.documentText dataUsingEncoding:NSUTF8StringEncoding];
}
Ve aie setting a uelault text loi the uocument il the text that we aie
managing at the moment is empty, so that when the usei liist cieates a
new uocument (oui app cieates the uocument loi the usei), the text
won`t Le empty anu the usei at least sees something on the scieen.
Moving on to the implementation ol the loadFromContents:ofType:error: instance
methou ol the uocument class now, we shall simply ieau the content that is passeu to
us as the liist paiametei ol this methou anu tuin it into the text that the uocument
instance is managing. This methou gets calleu when iOS ieaus the contents ol the URL
with which the instance ol the class gets initializeu. So we will take the uata anu tuin
it into a stiing in this example. In auuition to that, we also let the uelegate oLject know
(il one is set) that the text the instance is managing has changeu:
- (BOOL) loadFromContents:(id)contents
ofType:(NSString *)typeName
error:(NSError *__autoreleasing *)outError{

NSData *data = (NSData *)contents;
19.5 Storing User Documents in iCloud | 857
www.it-ebooks.info

if ([data length] == 0){
self.documentText = @"New Document";
} else {
self.documentText = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
}

if ([_delegate respondsToSelector:@selector(cloudDocumentChanged:)]){
[_delegate cloudDocumentChanged:self];
}

return YES;

}
In this methou, we will notily the uelegate oLject that the contents ol
the uocument have changeu, to give the uelegate oLject a chance to
upuate things, such as the UI.
That was ieally all we hau to implement in the uocument class. The iest ol the heavy
lilting has to happen in the view contiollei. The liist thing that we neeu to uo in the
view contiollei is to linu the iClouu path ol the UscrDocuncnt.txt lile we aie cieating
loi the usei. Foi this, as we leaineu in Recipe 19.3, we will use the URLForUbiq
uityContainerIdentifier: instance methou ol NSFileManager. Also, as we leaineu in
Recipe 19.3, we will cieate a Documents uiiectoiy in the app`s ioot iClouu uiiectoiy il
one uoesn`t exist. Let`s Legin with a methou that ietuins the URL loi the Documents
uiiectoiy in iClouu loi the app anu cieates the uiiectoiy il it uoesn`t exist alieauy:
- (NSURL *) urlForDocumentsDirectoryIniCloud{

NSURL *result = nil;

#error Replace this with your own Team ID
NSString *teamID = @"TEAM ID";

NSString *containerID = @"com.pixolity.Storing-User-Documents-in-iCloud";

NSString *teamIDAndContainerID = [NSString stringWithFormat:@"%@.%@",
teamID,
containerID];

NSFileManager *fileManager = [[NSFileManager alloc] init];

NSURL *iCloudURL = [fileManager
URLForUbiquityContainerIdentifier:teamIDAndContainerID];

NSURL *documentsFolderURLIniCloud =
[iCloudURL URLByAppendingPathComponent:@"Documents"
isDirectory:YES];

858 | Chapter 19: iCloud
www.it-ebooks.info
/* If it doesn't exist, create it */
if ([fileManager fileExistsAtPath:[documentsFolderURLIniCloud path]] == NO){
NSLog(@"The documents folder does NOT exist in iCloud. Creating...");
NSError *folderCreationError = nil;
BOOL created = [fileManager createDirectoryAtURL:documentsFolderURLIniCloud
withIntermediateDirectories:YES
attributes:nil
error:&folderCreationError];

if (created){
NSLog(@"Successfully created the Documents folder in iCloud.");
result = documentsFolderURLIniCloud;
} else {
NSLog(@"Failed to create the Documents folder in iCloud. Error = %@",
folderCreationError);
}
} else {
NSLog(@"The Documents folder already exists in iCloud.");
result = documentsFolderURLIniCloud;
}

return result;

}
Ve will use the URL ietuineu Ly the urlForDocumentsDirectoryIniCloud methou to
cieate the URL loi the UscrDocuncnt.txt that the app wants to cieate/euit/manage:
- (NSURL *) urlForFileInDocumentsDirectoryIniCloud{

return [[self urlForDocumentsDirectoryIniCloud]
URLByAppendingPathComponent:@"UserDocument.txt"];

}
Now let`s go to the heauei lile ol the view contiollei anu ueline the appiopiiate instance
vaiiaLles. Ve neeu:
1. An instance ol the CloudDocument class that will manage the uocument in the clouu.
2. An instance ol the UITextView class that we will use to allow the usei to entei his
text, which we will sync to iClouu as he types.
3. An instance ol the NSMetadataQuery class that we will use to linu the existing uocu-
ment in the clouu, il one exists.
#import <UIKit/UIKit.h>
#import "CloudDocument.h"
@interface ViewController : UIViewController
<CloudDocumentProtocol, UITextViewDelegate>
@property (nonatomic, strong) CloudDocument *cloudDocument;
@property (nonatomic, strong) UITextView *textViewCloudDocumentText;
19.5 Storing User Documents in iCloud | 859
www.it-ebooks.info
@property (nonatomic, strong) NSMetadataQuery *metadataQuery;
@end
Now that we have the text view ueclaieu in the heauei lile ol the view contiollei, let`s
go instantiate it in the implementation ol the view contiollei:
- (void) setupTextView{
/* Create the text view */

CGRect textViewRect = CGRectMake(20.0f,
20.0f,
self.view.bounds.size.width - 40.0f,
self.view.bounds.size.height - 40.0f);

self.textViewCloudDocumentText = [[UITextView alloc] initWithFrame:
textViewRect];
self.textViewCloudDocumentText.delegate = self;
self.textViewCloudDocumentText.font = [UIFont systemFontOfSize:20.0f];
[self.view addSubview:self.textViewCloudDocumentText];
}
Ve will Le using this methou in the viewDidLoad methou ol the view contiollei, which
will Le uiscusseu soon. Now let`s stait implementing a methou that will allow the view
contiollei to ieact to keyLoaiu notilications. As it was uiscusseu in Recipe 2.29, when
the usei staits to change the text in the text view, the keyLoaiu will pop up (il a Blue-
tooth keyLoaiu isn`t set up) anu the keyLoaiu will covei almost hall ol the iPhone
scieen. So in this case, we neeu to change the content inset ol the text view. Ve stait
Ly listening to keyLoaiu notilications:
- (void) listenForKeyboardNotifications{
/* As we have a text view, when the keyboard shows on screen, we want to
make sure the textviews content is fully visible, so start
listening for keyboard notifications */
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(handleKeyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];

[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(handleKeyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
The next thing that we shall take caie ol is to seaich loi existing usei uocuments when
the view contiollei`s view is loaueu (in the viewDidLoad methou). Il a uocument exists
in the clouu, then we will loau that; il not, we will cieate a new uocument:
- (void) startSearchingForDocumentIniCloud{
/* Start searching for existing text documents */
self.metadataQuery = [[NSMetadataQuery alloc] init];

860 | Chapter 19: iCloud
www.it-ebooks.info
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K like %@",
NSMetadataItemFSNameKey,
@"*"];
[self.metadataQuery setPredicate:predicate];
NSArray *searchScopes = [[NSArray alloc] initWithObjects:
NSMetadataQueryUbiquitousDocumentsScope,
nil];
[self.metadataQuery setSearchScopes:searchScopes];

NSString *metadataNotification =
NSMetadataQueryDidFinishGatheringNotification;

[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(handleMetadataQueryFinished:)
name:metadataNotification
object:nil];

[self.metadataQuery startQuery];
}
Let`s utilize all these methous in the view contiollei:
- (void)viewDidLoad{
[super viewDidLoad];
[self listenForKeyboardNotifications];
self.view.backgroundColor = [UIColor brownColor];
[self setupTextView];
[self startSearchingForDocumentIniCloud];
}
In the startSearchingForDocumentIniCloud methou, we staiteu listening loi NSMeta
dataQueryDidFinishGatheringNotification notilications on the handleMetadataQuery
Finished: methou. Ve neeu to have a look at the implementation ol this methou. The
way we have to implement this methou is to liist linu out il the metauata gueiy coulu
linu any existing iClouu uocuments. Il yes, then we will look loi the specilic uocument
that the app cieates loi the usei, which is calleu UscrDocuncnt.txt. Il this lile is lounu
in the usei`s clouu space, then we will open that uocument. Il not, we will cieate it:
- (void) handleMetadataQueryFinished:(NSNotification *)paramNotification{

/* Make sure this is the metadata query that we were expecting... */
NSMetadataQuery *senderQuery = (NSMetadataQuery *)[paramNotification object];

if ([senderQuery isEqual:self.metadataQuery] == NO){
NSLog(@"Unknown metadata query sent us a message.");
return;
}

[self.metadataQuery disableUpdates];

/* Now we stop listening for these notifications because we don't really
have to, anymore */
NSString *metadataNotification =
NSMetadataQueryDidFinishGatheringNotification;
19.5 Storing User Documents in iCloud | 861
www.it-ebooks.info

[[NSNotificationCenter defaultCenter] removeObserver:self
name:metadataNotification
object:nil];
[self.metadataQuery stopQuery];

NSLog(@"Metadata query finished.");


/* Let's find out if we had previously created this document in the user's
cloud space because if yes, then we have to avoid overwriting that
document and just use the existing one */
__block BOOL documentExistsIniCloud = NO;
NSString *FileNameToLookFor = @"UserDocument.txt";

NSArray *results = self.metadataQuery.results;

[results enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSMetadataItem *item = (NSMetadataItem *)obj;
NSURL *itemURL = (NSURL *)[item valueForAttribute:NSMetadataItemURLKey];
NSString *lastComponent = (NSString *)[[itemURL pathComponents] lastObject];
if ([lastComponent isEqualToString:FileNameToLookFor]){
if ([itemURL isEqual:[self urlForFileInDocumentsDirectoryIniCloud]]){
documentExistsIniCloud = YES;
*stop = YES;
}
}
}];

NSURL *urlOfDocument = [self urlForFileInDocumentsDirectoryIniCloud];
self.cloudDocument = [[CloudDocument alloc] initWithFileURL:urlOfDocument
delegate:self];

__weak ViewController *weakSelf = self;

/* If the document exists, open it */
if (documentExistsIniCloud){
NSLog(@"Document already exists in iCloud. Loading it from there...");
[self.cloudDocument openWithCompletionHandler:^(BOOL success) {
if (success){
ViewController *strongSelf = weakSelf;
NSLog(@"Successfully loaded the document from iCloud.");
strongSelf.textViewCloudDocumentText.text =
strongSelf.cloudDocument.documentText;
} else {
NSLog(@"Failed to load the document from iCloud.");
}
}];

} else {
NSLog(@"Document does not exist in iCloud. Creating it...");

/* If the document doesn't exist, ask the CloudDocument class to
save a new file on that address for us */
[self.cloudDocument saveToURL:[self urlForFileInDocumentsDirectoryIniCloud]
862 | Chapter 19: iCloud
www.it-ebooks.info
forSaveOperation:UIDocumentSaveForCreating
completionHandler:^(BOOL success) {
if (success){
NSLog(@"Successfully created the new file in iCloud.");
ViewController *strongSelf = weakSelf;
strongSelf.textViewCloudDocumentText.text =
strongSelf.cloudDocument.documentText;

} else {
NSLog(@"Failed to create the file.");
}
}];

}

}
Vhat is lelt now is to listen loi changes in the text viewonce the changes have Leen
applieu Ly the usei, we will tiy to save them into the uocument. Ve uo this Ly imple-
menting the textViewDidChange: uelegate methou ol the UITextViewDelegate piotocol:
- (void) textViewDidChange:(UITextView *)textView{
self.cloudDocument.documentText = textView.text;
[self.cloudDocument updateChangeCount:UIDocumentChangeDone];
}
Vith this methou, we let the uocument know that the usei has upuateu the contents
ol the text in the text view. Ve call the updateChangeCount: instance methou ol UIDocu
ment to get the uocument to iellect those changes to the clouu. Ve also have to imple-
ment the cloudDocumentChanged: uelegate methou ol the CloudDocumentProtocol pio-
tocol, anu change the text insiue the text view when the text in the uocument changes.
This methou will get calleu, loi instance, when the usei opens the app in two uevices
with the same iClouu cieuentials, changes the uocument in one uevice, anu leaves the
uocument open in the othei uevice. The seconu uevice`s iClouu uaemon will then ie-
tiieve the latest veision ol the uocument liom the clouu, anu the uocument class will
call the cloudDocumentChanged: uelegate message to give us a chance to upuate the UI:
- (void) cloudDocumentChanged:(CloudDocument *)paramSender{
self.textViewCloudDocumentText.text = paramSender.documentText;
}
Beloie we loiget, we also have to implement the keyLoaiu notilication hanuleis:
- (void) handleKeyboardWillShow:(NSNotification *)paramNotification{

NSDictionary *userInfo = [paramNotification userInfo];

NSValue *animationCurveObject =
[userInfo valueForKey:UIKeyboardAnimationCurveUserInfoKey];

NSValue *animationDurationObject =
[userInfo valueForKey:UIKeyboardAnimationDurationUserInfoKey];

NSValue *keyboardEndRectObject =
19.5 Storing User Documents in iCloud | 863
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];

UIWindow *window = [[[UIApplication sharedApplication] delegate] window];

/* Convert the frame from window's coordinate system to
the view's coordinate system */
keyboardEndRect = [self.view convertRect:keyboardEndRect
fromView:window];

[UIView beginAnimations:@"changeTextViewContentInset"
context:NULL];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:(UIViewAnimationCurve)animationCurve];

CGRect intersectionOfKeyboardRectAndWindowRect =
CGRectIntersection(window.frame, keyboardEndRect);

CGFloat bottomInset = intersectionOfKeyboardRectAndWindowRect.size.height;

self.textViewCloudDocumentText.contentInset = UIEdgeInsetsMake(0.0f,
0.0f,
bottomInset,
0.0f);

[UIView commitAnimations];

}
- (void) handleKeyboardWillHide:(NSNotification *)paramNotification{

if (UIEdgeInsetsEqualToEdgeInsets(self.textViewCloudDocumentText.contentInset,
UIEdgeInsetsZero)){
/* the text 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];

NSUInteger animationCurve = 0;
double animationDuration = 0.0f;

864 | Chapter 19: iCloud
www.it-ebooks.info
[animationCurveObject getValue:&animationCurve];
[animationDurationObject getValue:&animationDuration];

[UIView beginAnimations:@"changeTextViewContentInset"
context:NULL];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:(UIViewAnimationCurve)animationCurve];

self.textViewCloudDocumentText.contentInset = UIEdgeInsetsZero;

[UIView commitAnimations];

}
Go aheau anu iun this app on a uevice. It is actually Lettei il you can iun the same app
on two iOS uevices with the same iClouu cieuentials, anu then upuate the uocument
on one uevice anu wait loi the seconu uevice to automatically upuate its contents liom
the clouu.
See Also
Recipe 2.29; Recipe 19.1; Recipe 19.3
19.6 Managing the State of Documents in iCloud
Problem
You want to Le aLle to uetect conllicts anu othei issues that coulu occui as a iesult ol
syncing uocuments to iClouu.
Solution
Stat listening to the UIDocumentStateChangedNotification notilication.
I highly iecommenu ieauing Recipe 19.5 Leloie pioceeuing with this
iecipe, as the mateiial uesciiLeu heie highly ielies on what was taught
in that section.
Discussion
The UIDocumentStateChangedNotification notilication gets sent when the state ol an
iClouu uocument (ol type UIDocument) is changeu. The oLject caiiieu Ly this notilica-
tion is the instance ol the UIDocument whose state was changeu. You can listen to this
notilication anu then analyze the documentState piopeity ol youi iClouu uocument;
this piopeity is ol type UIDocumentState anu can Le a mixtuie ol these values:
19.6 Managing the State of Documents in iCloud | 865
www.it-ebooks.info
UIDocumentStateNormal
Things aie noimal anu no conllicts have occuiieu in the uocument.
UIDocumentStateClosed
This means that the uocument has not yet Leen openeu, oi was open anu has just
Leen closeu. You might want to uisallow the usei liom euiting the uocument while
the uocument is in this state. Apple iecommenus that you uo not uisplay aleit views
to youi useis, Lut insteau, peihaps, uisplay giaphical components on the scieen to
inuicate to the usei that euiting has Leen uisaLleu.
UIDocumentStateInConflict
This state inuicates that a conllict has happeneu in the uocument. Foi instance,
the same uocument coulu hau Leen euiteu Ly two oi moie people at the same time
causing a conllict. In such cases, you will have two options. Eithei lix the conllict
piogiammatically loi the usei, oi piompt the usei to choose which veision ol that
uocument she wants to keep.
UIDocumentStateSavingError
This uocument state inuicates that an eiioi has occuiieu in saving the uocument
to iClouu. You night want to allow the usei to continue euiting the uocument
while the uocument is in this state, Lut theie is no guaiantee as to whethei the usei
changes will Le saveu to iClouu oi not. OLviously, you might want to implement
some smait mechanisms in youi apps that will tempoiaiily stoie the contents ol
the uocument in the app Lunule while the uocument is in this state, anu iellect
those changes to iClouu at a latei time. The solution is up to you. Alteinatively,
you might want to let youi useis know that an eiioi has happeneu to theii uocu-
ment, anu that theie is a possiLility ol uata loss.
UIDocumentStateEditingDisabled
This state inuicates that euiting has Leen uisaLleu on the uocument Lecause ol an
eiioi. It is Lest in this case to uisallow the usei liom euiting the uocument.
As explaineu Leloie, the documentState piopeity ol UIDocument can Le a
mixtuie ol the aloiementioneu values.
To uemonstiate how we can take auvantage ol the UIDocumentStateChangedNotifica
tion notilication, let`s Luilu on top ol the example coue in Recipe 19.5 anu change the
viewDidLoad methou ol the view contiollei to suLsciiLe to this notilication:
- (void) listenForDocumentStateChangesNotification{

/* Start listening for the Document State Changes notification */
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(handleDocumentStateChanged:)
name:UIDocumentStateChangedNotification
866 | Chapter 19: iCloud
www.it-ebooks.info
object:nil];

}
- (void)viewDidLoad{
[super viewDidLoad];

[self listenForDocumentStateChangesNotification];
[self listenForKeyboardNotifications];
self.view.backgroundColor = [UIColor brownColor];
[self setupTextView];
[self startSearchingForDocumentIniCloud];
}
Ve have electeu the handleDocumentStateChanged: methou ol the view contiollei to
listen loi the UIDocumentStateChangedNotification notilication. Now let`s go aheau anu
implement this methou:
- (void) handleDocumentStateChanged:(NSNotification *)paramNotification{
NSLog(@"Document state has changed");
NSLog(@"Notification Object = %@", [paramNotification object]);

NSLog(@"Notification Object Class = %@",
NSStringFromClass([[paramNotification object] class]));

CloudDocument *senderDocument = (CloudDocument *)paramNotification.object;
NSLog(@"Document State = %d", senderDocument.documentState);


/* Since we don't yet know how to solve conflicts, we'll disallow the user
from editing the document if an error of any sort happens. Later, when
we learn about handling conflicts, we'll handle these issues more gracefully*/

if (senderDocument.documentState & UIDocumentStateInConflict){
NSLog(@"Conflict found in the document.");
self.textViewCloudDocumentText.editable = NO;
}
if (senderDocument.documentState & UIDocumentStateClosed){
NSLog(@"Document is closed.");
self.textViewCloudDocumentText.editable = NO;
}
if (senderDocument.documentState & UIDocumentStateEditingDisabled){
NSLog(@"Editing is disabled on this document.");
self.textViewCloudDocumentText.editable = NO;
}
if (senderDocument.documentState & UIDocumentStateNormal){
NSLog(@"Things are normal. We are good to go.");
self.textViewCloudDocumentText.editable = YES;
}
if (senderDocument.documentState & UIDocumentStateSavingError){
NSLog(@"A saving error has happened.");
self.textViewCloudDocumentText.editable = NO;
}

}
19.6 Managing the State of Documents in iCloud | 867
www.it-ebooks.info
As you can see, we aie using il statements insteau ol else-il statements in this example,
simply Lecause the state ol a clouu uocument can Le moie than one ol the aloiemen-
tioneu values at the same time. Theieloie, we have to Le aLle to hanule them in con-
junction. You will also notice that we aie uisallowing the usei liom enteiing text into
the text view while an eiioi has Leen uetecteu in the state ol the uocument, Le it a saving
eiioi oi a conllict. This is not a veiy goou usei expeiience, anu I highly iecommenu
that you have a look at Recipe 19.7 to leain how to solve conllicts in iClouu uocuments
anu pioviue a Lettei usei expeiience in youi apps.
See Also
Recipe 19.5
19.7 Handling Conflicts in iCloud Documents
Problem
You want to Le aLle to solve conllicts Letween two oi moie veisions ol a uocument
(manageu thiough UIDocument) in iClouu.
Solution
Use the otherVersionsOfItemAtURL: class methou ol the NSFileVersion class to uetect
uilleient veisions ol the cuiient ievision ol the uocument you aie managing using an
instance ol UIDocument. Each veision ol a uocument is ol type NSFileVersion. The pio-
ceuuie to take is as lollows:
1. Instantiate anu open a uocument.
2. Listen loi UIDocumentStateChangedNotification notilications (see Recipe 19.6).
3. Check il the documentState piopeity ol the uocument that causeu the aloiemen-
tioneu notilication to Le liieu has the UIDocumentStateInConflict state. Il yes, then
we will pioceeu to the next step. Il not, we will hanule the issue in a uilleient way.
Vhen a conllict occuis in a uocument, iClouu will automatically at-
tempt to iesolve that conllict Ly eithei meiging two oi moie ievisions
ol that uocument togethei, oi simply taking the latest veision. Vhatevei
iClouu uoes, it will give you a ievision ol the uocument to woik with.
This ievision is calleu the currcnt vcrsion ol that uocument.
+. Ve will use the currentVersionOfItemAtURL: class methou ol the NSFileVersion
class to get the cuiient veision ol the uocument Ly passing the URL ol the uocu-
ment to this methou.
868 | Chapter 19: iCloud
www.it-ebooks.info
5. Next, we will use the otherVersionsOfItemAtURL: class methou ol the NSFileVer
sion class to get all othei veisions ol the uocument, Ly passing the URL ol the
uocument to this methou. The ietuin value ol this methou is an aiiay ol type
NSFileVersion. Now that we have all the othei veisions, as well as the cuiient
veision ol the uocument, we will put them in an aiiay loi piocessing. RememLei,
all these veision oLjects aie ol type NSFileVersion.
6. Now that we have all the veisions, we can uisplay a taLle view to the usei asking
him which veision he woulu like to use, now that a conllict has occuiieu.
7. Il he chose the cuiient veision, we will simply get iiu ol the taLle view anu uisplay
the main UI ol the app, since the cuiient veision is the one that the uocument is
cuiiently managingiClouu has manageu to solve the conllict on that veision, so
theie ieally is nothing we neeu to uo on that uocument. Since the usei chose the
cuiient veision, we will not pioceeu to the next steps.
S. Il the usei uoes not choose the cuiient veision, we will pioceeu to the steps that
lollow.
9. Ve will liist close the uocument that we aie cuiiently managing, using the close
WithCompletionHandler: instance methou ol UIDocument.
10. Then we will use the removeOtherVersionsOfItemAtURL:error: class methou ol
NSFileVersion class, anu pass the URL ol the veision that the usei pickeu as the
liist paiametei to this methou. This methou will then automatically uispose ol the
othei veisions that aie availaLle loi the cuiient uocument (in conllict, oi not in
conllict), except loi the veision to which we pass the URL in the seconu aigument
ol this methou. That veision will Le kept sale. Ve uo this in oiuei to let iClouu
know we aie hanuling the conllict manually. Il we uon`t take this step, the next
time the app opens, the uocument will go into a conllict state Lecause iClouu will
uetect all the in-conllict veisions ol the uocument we weie managing.
11. The next step is to ie-instantiate the uocument oLject using the URL to the veision
that the usei just pickeu. This will get iiu ol the pievious uocument oLject, as theie
is no goou way ol switching Letween two oi moie uocument liles using the same
instance ol UIDocument.
12. Last Lut not least, we will attempt to open the new veision ol the uocument, using
the openWithCompletionHandler: instance methou ol the uocument oLject (ol type
UIDocument).
This iecipe Luilus on top ol Recipes 19.6 anu 19.5. I highly iecommenu
that you thoioughly covei those iecipes Leloie pioceeuing with this one.
19.7 Handling Conflicts in iCloud Documents | 869
www.it-ebooks.info
Discussion
In this iecipe, we will assume that we have two iOS uevices iunning the same app, that
Loth have one uocument open, anu that the usei is shaiing hei iClouu account on Loth
uevices (in othei woius, Loth uevices Lelong to the same usei). Ve have a text view
that allows the usei to entei text, anu we will attempt to save the text in the cuiient
uocument. Ve also stait listening loi UIDocumentStateChangedNotification notilica-
tions (see Recipe 19.6) anu once we uetect a conllict, we will uisplay a moual taLle view
on the scieen anu list all availaLle veisions ol the uocument. The usei can then pick a
veision, which we will keep as the cuiient veision anu allow hei to continue euiting
the uocument.
One ol the liist things we neeu to accomplish is cieating a view contiollei with a taLle
view in it. Ve will use this taLle view to uisplay the availaLle veisions ol the uocument
that the usei is euiting, shoulu theie Le a conllict Letween veisions. So let`s go aheau
anu cieate the view contiollei Ly lollowing these steps:
1. In Xcoue, select File New New File...
2. Make suie you have selecteu the Cocoa Touch suLcategoiy unuei the iOS categoiy
on the lelthanu siue ol the New File uialog. Once that is uone, select the UIView-
Contiollei suLclass item on the iighthanu siue anu piess the Next Lutton, as shown
in Figuie 19-15.
Iigurc 19-15. Crcating a ncw vicw contro||cr to hand|c conj|icts
3. In the next scieen, set youi view contiollei`s class to Conj|ict\icwContro||cr anu
make suie Xcoue cieates a XIB lile alongsiue the view contiollei`s heauei anu
870 | Chapter 19: iCloud
www.it-ebooks.info
implementation lile, as shown in Figuie 19-16. Once you aie uone, piess the Next
Lutton.
Iigurc 19-1. Spccijying a nanc jor thc conj|ict rcso|ution vicw contro||cr
+. In the next scieen, specily wheie you woulu like to save the view contiollei anu
its .xiL lile anu then piess the Cieate Lutton.
Peilect! Now we have the view contiollei. Ve want the app`s main view contiollei to
Le in chaige ol populating uata into the taLle view insiue the conllict view contiollei
so let`s ueline the inteilace ol the conllict view contiollei with a new uesignateu ini-
tializei:
#import <UIKit/UIKit.h>
@interface ConflictViewController : UIViewController
@property (nonatomic, strong) UITableView *tableViewVersions;
/* Designated Initializer */
- (id) initWithNibName:(NSString *)nibNameOrNil
bundle:(NSBundle *)nibBundleOrNil
tableViewDelegate:(id<UITableViewDelegate>)paramTableViewDelegate
tableViewDataSource:(id<UITableViewDataSource>)paramTableViewDataSource;
@end
19.7 Handling Conflicts in iCloud Documents | 871
www.it-ebooks.info
The next step is to implement this view contiollei. Theie`s not much coue to wiite heie,
except loi implementing the uesignateu initializei anu setting up the taLle view:
#import "ConflictViewController.h"
@implementation ConflictViewController
- (id) initWithNibName:(NSString *)nibNameOrNil
bundle:(NSBundle *)nibBundleOrNil
tableViewDelegate:(id<UITableViewDelegate>)paramTableViewDelegate
tableViewDataSource:(id<UITableViewDataSource>)paramTableViewDataSource{

self = [super initWithNibName:nibNameOrNil
bundle:nibBundleOrNil];

if (self != nil){
/* No view exists at this point so let's set the table view's frame
to a zero-rectangle and then we will adjust it when the view loads */
tableViewVersions = [[UITableView alloc]
initWithFrame:CGRectZero
style:UITableViewStylePlain];
tableViewVersions.delegate = paramTableViewDelegate;
tableViewVersions.dataSource = paramTableViewDataSource;
}

return self;

}
- (id) initWithNibName:(NSString *)nibNameOrNil
bundle:(NSBundle *)nibBundleOrNil{

return [self initWithNibName:nibNameOrNil
bundle:nibBundleOrNil
tableViewDelegate:nil
tableViewDataSource:nil];

}
- (void)viewDidLoad{
[super viewDidLoad];

self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;
self.tableViewVersions.autoresizingMask = self.view.autoresizingMask;
self.tableViewVersions.frame = self.view.bounds;
[self.view addSubview:self.tableViewVersions];

}
- (BOOL)shouldAutorotateToInterfaceOrientation
:(UIInterfaceOrientation)interfaceOrientation{
872 | Chapter 19: iCloud
www.it-ebooks.info
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
@end
OK, now let`s go to the app`s main view contiollei`s heauei lile anu make suie that we
have:
1. An aiiay ol type NSArray in which we can stoie uilleient veisions ol the uocument,
shoulu theie Le a conllict.
2. An instance ol the ConflictViewController class that we will use to uisplay to the
usei when we uetect a conllict on the uocument.
#import <UIKit/UIKit.h>
#import "CloudDocument.h"
@class ConflictViewController;
@interface ViewController : UIViewController <UITextFieldDelegate,
CloudDocumentProtocol, UITextViewDelegate,
UITableViewDelegate, UITableViewDataSource>
@property (nonatomic, strong) UITextView *textViewCloudDocumentText;
@property (nonatomic, strong) CloudDocument *cloudDocument;
@property (nonatomic, strong) NSMetadataQuery *metadataQuery;
@property (nonatomic, copy) NSArray *arrayOfCloudDocumentVersions;
@property (nonatomic, strong) ConflictViewController *conflictViewController;
@end
OLviously, we will now move to the implementation ol the lile anu ueline oui piivate
methou theie:
#import "ViewController.h"
#import "ConflictViewController.h"
@interface ViewController(Private)
- (NSURL *) urlForDocumentsDirectoryIniCloud;
@end
@implementation ViewController
...
Vhat we have to uo now is to listen to anu hanule incoming UIDocumentStateChanged
Notification notilications. Once a notilication aiiives, we will:
1. Finu out il the uocument`s state now contains the UIDocumentStateInConflict llag
oi not. Il yes, we will pioceeu to the next step.
2. Once we linu a conllict, we will use the currentVersionOfItemAtURL: anu the
otherVersionsOfItemAtURL: class methous ol NSFileVersion, anu place all the avail-
aLle veisions in the arrayOfCloudDocumentVersions aiiay.
19.7 Handling Conflicts in iCloud Documents | 873
www.it-ebooks.info
3. Now that we have all the availaLle veisions ol the uocument in the arrayOfCloud
DocumentVersions aiiay, we will place the conllict view contiollei insiue a naviga-
tion contiollei anu piesent it as a moual view contiollei on top ol the cuiient view
contiollei. This will then give the usei the aLility to view all availaLle veisions anu
pick one.
So let`s uig in anu hanule the incoming UIDocumentStateChangedNotification s:
- (void) listenForDocumentStateChangesNotification{

/* Start listening for the Document State Changes notification */
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(handleDocumentStateChanged:)
name:UIDocumentStateChangedNotification
object:nil];

}
- (void) prepareFileVersionsTableView{

self.conflictViewController = [[ConflictViewController alloc]
initWithNibName:@"ConflictViewController"
bundle:nil
tableViewDelegate:self
tableViewDataSource:self];

}
- (void)viewDidLoad{
[super viewDidLoad];
[self prepareFileVersionsTableView];
[self listenForDocumentStateChangesNotification];
[self listenForKeyboardNotifications];
self.view.backgroundColor = [UIColor brownColor];
[self setupTextView];
[self startSearchingForDocumentIniCloud];
}
Heie is the implementation ol the handleDocumentStateChanged: methou that will uo
the heavy lilting ol linuing all the lile veisions anu so on:
- (void) handleDocumentStateChanged:(NSNotification *)paramNotification{
NSLog(@"Document state has changed");
NSLog(@"Notification Object = %@", [paramNotification object]);

NSLog(@"Notification Object Class = %@",
NSStringFromClass([[paramNotification object] class]));

CloudDocument *senderDocument = (CloudDocument *)paramNotification.object;
NSLog(@"Document State = %d", senderDocument.documentState);


/* Since we don't yet know how to solve conflicts, we will disallow the user
from editing the document if an error of any sort has happened. Later, when
874 | Chapter 19: iCloud
www.it-ebooks.info
we will learn about handling conflicts, we will handle these issues
more gracefully*/

if (senderDocument.documentState & UIDocumentStateInConflict){
NSLog(@"Conflict found in the document.");

NSMutableArray *versions = [[NSMutableArray alloc] init];

/* The first item in the list will be the current version */
[versions addObject:[NSFileVersion currentVersionOfItemAtURL:
self.cloudDocument.fileURL]];

/* Then add the other available versions of this document to the list */
[versions addObjectsFromArray:
[NSFileVersion otherVersionsOfItemAtURL:senderDocument.fileURL]];

self.arrayOfCloudDocumentVersions = [NSArray arrayWithArray:versions];

NSLog(@"There are %lu versions of this document available.",
(unsigned long)[self.arrayOfCloudDocumentVersions count]);

UINavigationController *tempNavController =
[[UINavigationController alloc] initWithRootViewController:
self.conflictViewController];

[self presentModalViewController:tempNavController
animated:YES];

[self.conflictViewController.tableViewVersions reloadData];

}

if (senderDocument.documentState & UIDocumentStateClosed){
NSLog(@"Document is closed.");
self.textViewCloudDocumentText.editable = NO;
}
if (senderDocument.documentState & UIDocumentStateEditingDisabled){
NSLog(@"Editing is disabled on this document.");
self.textViewCloudDocumentText.editable = NO;
}
if (senderDocument.documentState & UIDocumentStateNormal){
NSLog(@"Things are normal. We are good to go.");
}
if (senderDocument.documentState & UIDocumentStateSavingError){
NSLog(@"A saving error has happened.");
self.textViewCloudDocumentText.editable = NO;
}

}
Ve shall now leeu the taLle view insiue the conllict view contiollei, with uata ielevant
to the vaiious lile veisions ol each conllict that we can linu on the uocument we aie
cuiiently managing. Let`s go aheau anu uo that iight now:
19.7 Handling Conflicts in iCloud Documents | 875
www.it-ebooks.info
- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
- (NSInteger) tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section{

return [self.arrayOfCloudDocumentVersions count];

}
- (UITableViewCell *) tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath{

UITableViewCell *result = nil;

static NSString *FileVersionTableViewCell = @"FileVersionTableViewCell";

result = [tableView dequeueReusableCellWithIdentifier:
FileVersionTableViewCell];

if (result == nil){
result = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:FileVersionTableViewCell];
result.detailTextLabel.numberOfLines = 2;
}

NSFileVersion *version = [self.arrayOfCloudDocumentVersions objectAtIndex:
indexPath.row];

if (indexPath.row == 0){
result.textLabel.text = [NSString stringWithFormat:
@"(Current) Version at: %@",
version.modificationDate];
} else {
result.textLabel.text = [NSString stringWithFormat:@"Version at: %@",
version.modificationDate];
}


result.detailTextLabel.text = [NSString stringWithFormat:@"Modified by: %@",
version.localizedNameOfSavingComputer];

return result;

}
The liist instance ol NSFileVersion we place in the aiiay ol lile veisions
(that gets leu to the taLle view) is always the cuiient veision. Because
ol this, in the taLle view, we will laLel the liist cell Currcnt to let the usei
know that il he picks that veision, it will Le the veision he is cuiiently
woiking on altei conllicts weie hanuleu Ly iClouu automatically.
876 | Chapter 19: iCloud
www.it-ebooks.info
Vhen the usei selects one ol the veisions we have piesenteu in the taLle view on the
conllict view contiollei, we woulu like to ietiieve that veision anu piesent it to the usei.
As mentioneu in the Solution ol this iecipe, theie aie a lew steps that we have to take
in oiuei to achieve this. I stiongly suggest that you ielei to those steps Leloie having a
look at this coue:
- (void) tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath{

if (indexPath.row == 0){
[self dismissModalViewControllerAnimated:YES];
return;
}

self.textViewCloudDocumentText.text = [NSString string];

NSFileVersion *selectedFileVersion = [self.arrayOfCloudDocumentVersions
objectAtIndex:indexPath.row];

NSLog(@"Closing the document...");

/* Step 1: First close the document */
[self.cloudDocument closeWithCompletionHandler:^(BOOL success) {
if (success){
NSLog(@"Successfully closed the current document.");

/* Step 2: Remove all other versions of the selected revision */
NSLog(@"Removing all other versions of the selected revision...");
NSError *removeError = nil;
BOOL removed = [NSFileVersion
removeOtherVersionsOfItemAtURL:selectedFileVersion.URL
error:&removeError];
if (removed &&
removeError == nil){
NSLog(@"Successfully removed all other versions of selected revision.");

/* Step 3: Open the selected revision */
NSLog(@"Opening the selected revision...");
self.cloudDocument = [[CloudDocument alloc]
initWithFileURL:selectedFileVersion.URL
delegate:self];

[self.cloudDocument openWithCompletionHandler:^(BOOL success) {
if (success){
NSLog(@"Successfully opened the new file.");
self.textViewCloudDocumentText.text =
self.cloudDocument.documentText;
} else {
NSLog(@"Failed to open the new file.");
}
}];

} else {
NSLog(@"Failed to remove other versions of this revision. Error = %@",
19.7 Handling Conflicts in iCloud Documents | 877
www.it-ebooks.info
removeError);
}
} else {
NSLog(@"Failed to close the current document.");
}
}];

[self dismissModalViewControllerAnimated:YES];

}
Now il you iun this app on two uevices simultaneously using the same iClouu account,
you will see an inteilace similai to Figuie 19-17 pop up to ask you which veision ol the
uocument you woulu pielei to keep.
Iigurc 19-17. Sc|ccting a vcrsion to hand|c conj|icts
See Also
Recipe 19.5; Recipe 19.6
878 | Chapter 19: iCloud
www.it-ebooks.info
CHAPTER 20
Pass Kit
20.0 Introduction
Ve`ie all lamiliai with coupons anu tickets. Foi instance, you may go to a collee shop
that gives you a loyalty caiu that olleis you a liee cup ol collee altei you have accu-
mulateu some numLei ol stamps loi pievious collee puichases. Ve also use coupons
when we shop. You can Luy X amount ol loou anu the shop may give you a coupon to
spenu when you next shop theie.
Figuie 20-1 uepicts what a simple iailway ticket (piesenteu as a pass) looks like in
PassLook on a ieal iOS uevice.
Iigurc 20-1. A rai|way tic|ct prcscntcd as a pass in Passboo| on an iOS dcvicc
879
www.it-ebooks.info
iOS apps can use the PassLook liamewoik to inteiact with passes as well. Going Lack
to the collee shop example, the app loi this collee shop may allow the usei to top up
theii loyalty caiu with cash to allow them to take auvantage ol othei cool things that
the shop has to ollei, such as ViFi access acioss the countiy. So, when the usei opens
the app, it will uetect a pass in the usei`s PassLook uataLase ielateu to the collee shop,
allow the usei to top the pass up iight theie on hei phone, anu then contact a Laiista
to say that the pass installeu on the usei`s uevice has Leen toppeu up with cash.
Pass Kit is how Apple iepiesents this type ol tiansaction uigitally. Apple also intiouuceu
PassLook in iOS 6. So let`s get oui teiminology iight Leloie we uig any ueepei:
Pass Kit
The liamewoik Apple pioviues to uevelopeis to allow uigitally signeu passes to Le
ueliveieu to compatiLle iOS uevices iunning iOS 6 oi latei.
Passboo|
The client application on iOS 6 uevices aLle to stoie, hanule, anu manage passes
cieateu Ly uevelopeis.
Theieloie, we as uevelopeis will Le using Pass Kit to cieate uigitally signeu passes anu
uelivei them to oui useis. Oui useis will use PassLook on theii uevices to inteiact with
the passes we cieate loi them. Ol couise, this allows us uevelopeis to uelivei coupons,
iail passes, puLlic tianspoitation tickets, loyalty caius, anu so on to oui useis in the
loim ol uigitally signeu passes insteau ol the tiauitional, papei-Laseu appioach wheie
people have to caiiy multiple caius in theii wallets. PassLook on iOS uevices is the
place wheie all this content can Le stoieu in a single place, without useis having to
caiiy all these passes in theii pockets.
Beloie attempting to use new technology, you shoulu get a giasp ol the Lig pictuie: the
high-level uesign ol the technology anu how it enaLles us to achieve oui goals. Foi Pass
Kit, I have Lioken this Lig pictuie uown into small steps so that you can hopelully leain
how you can use it to uelivei uigitally signeu passes to youi useis:
1. The uevelopei cieates a ceitilicate anu its coiiesponuing piivate key using Apple`s
Piovisioning Poital.
2. The uevelopei then cieates a seiies ol liles that will iepiesent the pass that the usei
will Le given latei.
3. The uevelopei signs the cieateu pass with the ceitilicate that she cieateu at the liist
step.
+. The uevelopei ueliveis the pass to the usei thiough vaiious means ol ueliveiy.
5. The usei will see the pass anu will have the oppoitunity to auu that pass to hei
uevice.
6. Once the pass is auueu to the usei`s uevice, PassLook will ietain it loi lutuie use
until the usei ueciues to uelete the pass.
880 | Chapter 20: Pass Kit
www.it-ebooks.info
I know that it can Le uillicult to unueistanu the Lig pictuie simply Ly ieauing a lew
paiagiaphs ol text. Figuie 20-2 shows the seguence in moie uetail.
Iigurc 20-2. Crcating and distributing digita||y signcd passcs to uscrs, iOS and abovc
The iecipes in this chaptei will thoioughly explain the uetails ol this piocess. A lew Lits
anu pieces ielateu to Pass Kit as a technologykeeping youi pass up-to-uate anu
leaining how to push upuates liom a seiveiieguiie you to know a Lit aLout seivei-
siue uevelopment. Foi the sake ol simplicity, we won`t Le coveiing those paits in this
chaptei anu insteau will Le locusing on cieating passes. Once you know how to cieate
a pass, you can uistiiLute it in a vaiiety ol ways, two ol which aie explaineu in this
chaptei. Howevei, paits that aie not ielevant to iOS, such as those that ieguiie seivei-
siue uevelopment knowleuge, aie skippeu in this chaptei loi this ieason.
20.0 Introduction | 881
www.it-ebooks.info
20.1 Creating Pass Kit Certificates
Problem
You have ueciueu to uistiiLute uigitally signeu passes to youi useis anu woulu like to
Legin with the liist step, cieating ceitilicates to sign youi passes with.
Solution
Cieate youi ceitilicates in the iOS Piovisioning Poital.
Discussion
As explaineu in Recipe 20.0, in oiuei to uistiiLute passes to youi useis, you neeu to
uigitally sign them, anu Leloie uoing that, you neeu to ieguest a ceitilicate liom Apple
that will uniguely Linu all youi passes to youi uevelopei account. That way, Apple
knows which passes aie legitimate anu which ones aie not.
Follow these steps to cieate youi ceitilicate:
1. Navigate youi Liowsei to the iOS Dev Centei. I have avoiueu putting the URL to
the iOS Dev Centei heie, as this URL is suLject to change anu I uon`t want to give
you the wiong URL. Il you uon`t know wheie this is, simply type it in a seaich
engine anu I Let you will linu it in a mattei ol seconus.
2. Il you aie not loggeu in alieauy, log in now.
3. Once loggeu in, go to the iOS Piovisioning Poital page.
+. In the iOS Piovisioning Poital, navigate to the Pass Type IDs page on the lelthanu
siue ol the scieen.
5. Vhen you liist lanu theie, the page will look empty, as shown in Figuie 20-3. Finu
anu select the New Pass Type ID Lutton on the scieen.
6. Now, in the Desciiption Lox, entei text that will uesciiLe youi pass type ID.
7. In the Iuentiliei Lox, entei a ieveise-uomain-style iuentiliei ol youi pass. Foi in-
stance, il youi app ID is con.pixo|ity.tcstingpass|it, then loi passes that integiate
with that app you can use pass.pixo|ity.tcstingpass|it. The pass iuentiliei is ieally
something that shoulu make sense to you anu youi application. Howevei, the
piactice is that the whole iuentiliei name shoulu stait with pass. anu then you use
whatevei you wish loi the iest ol the iuentiliei. Figuie 20-+ uemonstiates how you
can lill in the uetails in this page.
Once you aie uone populating the uetails in this page, piess the SuLmit Lutton. Now
you have a pass type ID. Howevei, this pass type ID is not linkeu to any ceitilicate as
such. Now we have to associateu oui pass type ID to a ceitilicate. That`s also easy.
Follow these steps to cieate the ceitilicate anu associate it with youi pass type ID:
882 | Chapter 20: Pass Kit
www.it-ebooks.info
1. In the Pass Type IDs section ol the iOS Piovisioning Poital, linu the pass type ID
that you cieateu (Figuie 20-5). Unuei the Pass Ceitilicates column ol the list, you
can see that loi youi pass type ID, it will say Nonc. Unuei the Action column, select
the Conliguie link.
Iigurc 20-3. Thc Pass Typc |Ds scrccn with no pass typcs crcatcd yct
Iigurc 20-1. Ii||ing in thc dctai|s oj a sinp|c pass |D
20.1 Creating Pass Kit Certificates | 883
www.it-ebooks.info
Iigurc 20-5. A pass typc |D that has not bccn conjigurcd yct
2. In the new scieen, you can see that the status ol youi pass ceitilicate is Conjigura-
b|c anu the light next to it is amLei (see Figuie 20-6). This means the ceitilicate has
not Leen conliguieu loi youi pass type ID yet. Now select the Conliguie Lutton
again in the new scieen.
Iigurc 20-. A ccrtijicatc has not yct bccn associatcd with our pass typc |D
3. Once you piess the Conliguie Lutton, you will Le piesenteu with a moual uialog
on youi Liowsei instiucting you to cieate a ceitilicate signing ieguest using the
Keychain on youi Mac. Simply lollow the steps, cieate the ceitilicate signing ie-
guest (Figuie 20-7), anu once you aie uone, piess the Continue Lutton (Fig-
uie 20-S).
884 | Chapter 20: Pass Kit
www.it-ebooks.info
It is possiLle to cieate the Ceitilicate signing ieguest on a non-Mac ma-
chine. In oiuei to uo so, you neeu to make suie that Open SSL is installeu
on that machine. The instiuctions on how to geneiate these ceitilicates
on non-Mac machines aie outsiue the scope ol this Look, Lut il you aie
inteiesteu, a simple weL seaich will help you unueistanu the piocess on
those machines.
Iigurc 20-7. Crcating a ccrtijicatc signing rcqucst using Kcychain
The ceitilicate ieguests that you cieate on youi computei using Key-
chain Access will also cieate a piivate key that is associateu with that
ceitilicate. Apple iecommenus that you Lack up youi Keychain uataLase
eveiy now anu then so that you won`t lose youi piivate keys, as Apple
will not Le saving youi piivate keys on the iOS Piovisioning Poital. Il
you aie moving to a new computei, you neeu to move youi piivate keys
with you manually. That`s why they aie calleu piivate keys. Expoiting
piivate keys is simple: iight-click on youi piivate key anu piess the Ex-
poit menu item.
20.1 Creating Pass Kit Certificates | 885
www.it-ebooks.info
Iigurc 20-8. Io||ow thc on-scrccn instructions to crcatc a ccrtijicatc signing rcqucst
+. Now you will Le askeu on youi Liowsei to uploau the ceitilicate signing ieguest
to Apple in oiuei to ietiieve youi ceitilicate. The piivate key was cieateu on youi
computei the moment you cieateu the ceitilicate signing ieguest. The ceitilicate
that Apple will issue you at the enu ol this piocess will match youi piivate key. So
now select the Choose File Lutton in this scieen in oiuei to select the ceitilicate
signing ieguest that Keychain cieateu loi you (see Figuie 20-9) anu once uone,
piess the Geneiate Lutton.
5. Once the ceitilicate has Leen geneiateu, you will Le piesenteu with a scieen similai
to Figuie 20-10. Piess the Continue Lutton on this scieen.
886 | Chapter 20: Pass Kit
www.it-ebooks.info
Iigurc 20-9. Up|oading thc ccrtijicatc signing rcqucst to App|c to gct a ccrtijicatc bac|
6. Now you aie piesenteu with a scieen wheie you can uownloau youi ceitilicate (see
Figuie 20-11). Simply piess the Downloau Lutton anu once the ceitilicate lile is
uownloaueu to youi computei, piess the Done Lutton.
7. Now you shoulu have the uownloaueu ceitilicate on youi uisk. Locate that lile anu
uouLle-click on it in oiuei to impoit it into youi Keychain. To make suie eveiything
woikeu successlully, open Keychain Access on youi computei anu navigate to the
Login section anu then the My Ceitilicate suLsection. Now on the iighthanu siue
ol the scieen, conliim that youi ceitilicate is piesent anu that it is associateu with
a piivate key, as shown in Figuie 20-12.
20.1 Creating Pass Kit Certificates | 887
www.it-ebooks.info
Iigurc 20-10. App|c |ctting you |now that your ccrtijicatc was crcatcd succcssju||y
888 | Chapter 20: Pass Kit
www.it-ebooks.info
Iigurc 20-11. You can now down|oad your gcncratcd ccrtijicatc
20.1 Creating Pass Kit Certificates | 889
www.it-ebooks.info
Iigurc 20-12. Thc App|c gcncratcd ccrtijicatc is corrcct|y associatcd with a privatc |cy
You aie now uone cieating youi ceitilicate, anu ieauy to sign youi passes, ieauy to Le
sent to iOS uevices.
See Also
Recipe 20.0
20.2 Creating Pass Files
Problem
You want to cieate a pass lile that iepiesents the uata that you want youi useis to holu
in theii iOS uevices.
890 | Chapter 20: Pass Kit
www.it-ebooks.info
Solution
Cieate a pass.json lile anu populate it with appiopiiate keys anu values.
Discussion
Apple has chosen ]SON liles to iepiesent passes loi Pass Kit. ]SON stanus loi javaScript
Objcct Notation anu is extensively useu in weL applications anu seivices. Howevei, as
an iOS uevelopei, you uon`t necessaiily have to know aLout ]SON liles.
]SON liles aie simple key-value liles, just like a uictionaiy. A key can have a value anu
the value can iange liom a simple stiing to a uictionaiy that contains keys anu values
itsell. Heie is a simple ]SON that will pietty much uemonstiate all theie is to know
aLout ]SON liles:
{
"key 1" : "value 1",
"key 2 - dictionary" : {
"key 2.1" : "value 2.1",
"key 2.2" : "value 2.2"
},
"key 3 - array" : [
{
"array item 1, key1" : "value",
"array item 1, key2" : "value"
},
{
"array item 2, key1" : "value",
"array item 2, key2" : "value"
}
]
}
You can see that uictionaiies aie iepiesenteu with sguaie Liackets anu aiiays with cuily
Liackets. Othei values aie just simple key value paiis. Il we weie to iepiesent this same
]SON oLject with a noimal NSDictionary, this is what the iesulting coue woulu Le:
NSDictionary *json = @{
@"key1" : @"value1",
@"key 2 - dictionary" : @{
@"key 2.1" : @"value 2.1",
@"key 2.2" : @"value 2.2",
},
@"key 3 - array" : @[
@{
@"array item 1, key1" : @"value",
@"array item 1, key2" : @"value"
},
@{
@"array item 2, key1" : @"value",
@"array item 2, key2" : @"value"
}
]
};
20.2 Creating Pass Files | 891
www.it-ebooks.info
Foi moie inloimation aLout ]SON, you can ielei to ]SON.oig. Let`s move on to cie-
ating oui pass liles. A pass lile, as mentioneu Leloie, is a simple ]SON lile. Don`t conluse
pass liles with passes. A pass is a collection ol liles, incluuing the pass.json lile, that will,
as a whole, iepiesent the uigitally signeu pass that useis can install on theii uevices. A
pass lile is a lile that explains how the pass shoulu appeai on the uevice.
The pass.json lile can Le constiucteu using high- anu low-level keys. High-level keys
aie the keys that will Le immeuiately visiLle in the top hieiaichy ol the pass.json lile.
The low-level keys will appeai as chiluien ol the high-level keys. Don`t woiiy il this
sounus conlusing loi now. I know I was conluseu when I liist heaiu aLout this, Lut il
you ieau on, I piomise it will all click eventually.
Let`s stait Ly cieating a pass.json in Xcoue. I shoulu wain you that Xcoue is unloitu-
nately not the Lest euitoi loi ]SON liles; Howevei, it is oui piimaiy IDE, so we will
stick with it. Follow these steps to cieate a pass.json lile:
1. Cieate an empty iOS pioject in Xcoue Ly choosing File New Pioject...
2. On the lelthanu siue ol the New Pioject uialog, make suie you aie unuei the iOS
categoiy. Then choose Othei anu on the iighthanu siue, choose Empty, as shown
in Figuie 20-13. Once uone, piess the Next Lutton.
Iigurc 20-13. Crcating an cnpty iOS projcct
3. Now, give youi pioject a name unuei the Piouuct Name Lox anu once uone, piess
the Next Lutton. Now you get the chance to save youi lile on uisk. Once you have
892 | Chapter 20: Pass Kit
www.it-ebooks.info
successlully chosen the path to save the pioject, you aie ieauy to cieate the
pass.json lile.
+. In youi new empty pioject, in Xcoue, choose File New File...
5. In the New File uialog, make suie you aie unuei the iOS categoiy, then choose
Othei. On the iighthanu siue, choose Empty, as shown in Figuie 20-1+. Once you
aie uone, piess the Next Lutton.
Iigurc 20-11. Adding an cnpty ji|c to our projcct
6. Altei piessing the Next Lutton, you aie now askeu to save this lile on uisk. Make
suie that you save this lile as pass.json. Once you aie uone, piess the Cieate Lutton
anu youi lile is now auueu on uisk anu auueu to youi pioject.
OK, lantastic, now we have oui pass.json cieateu on uisk. Ve neeu to populate it with
some keys anu values. Beloie we go into the uetails ol the keys anu the values, let me
show you a simple pass lile populateu with keys anu values so that you can get a Lettei
iuea ol what a pass lile actually contains:
{
"formatVersion" : 1,
"passTypeIdentifier" : "",
"serialNumber" : "p69f2J",
"teamIdentifier" : "",
"description" : "Train Ticket Example",
"locations" : [
20.2 Creating Pass Files | 893
www.it-ebooks.info
{
"longitude" : -0.170867,
"latitude" : 50.834948
}
],
"barcode" : {
"message" : "1234567890",
"format" : "PKBarcodeFormatPDF417",
"messageEncoding" : "iso-8859-1"
},
"organizationName" : "O'Reilly Railways",
"logoText" : "O'Reilly Railways",
"foregroundColor" : "rgb(255, 255, 255)",
"backgroundColor" : "rgb(100, 100, 100)",
"boardingPass" : {
"transitType" : "PKTransitTypeTrain",
"primaryFields" : [
{
"key" : "departure",
"label" : "Departs From",
"value" : "Hove, 07:37",
},
{
"key" : "departurePlatform",
"label" : "Departs from Platform",
"value" : "2",
}
],
"auxiliaryFields" : [
{
"key" : "arrival",
"label" : "Arrives At",
"value" : "London Bridge, 08:41"
},
{
"key" : "arrivalPlatform",
"label" : "Arrives at Platform",
"value" : "13"
}
],
"backFields" : [
{
"key" : "oreillyRailways",
"label" : "O'Reilly Railways",
"value" : "For more information about our services, visit www.oreilly.com"
},
{
"key" : "termsAndConditions",
"label" : "Terms and Conditions",
"value" : "To be filled later"
}
]
}
}
894 | Chapter 20: Pass Kit
www.it-ebooks.info
I have intentionally lelt the teamIdentifier anu passTypeIdentifier
keys` values empty. You neeu to make suie that you populate the values
ol these keys to something that you have set up in youi piovisioning
poital as a pass type ID. It is impeiative that you lill the values ol these
keys with accuiate inloimation.
Fantastic, now we have oui pass.json ieauy to Le incluueu in oui uigitally signeu pass.
RememLei, a pass is moie than just the pass.json lile. Ve neeu to incluue a hanulul ol
images anu a manilest lile that will list all the liles incluueu in oui pass.
Heie aie some ol the most impoitant keys that you can place in the pass.json lile:
formatVersion
This key specilies the veision ol the pass loimat. Please set this value to the constant
value ol 1.
passTypeIdentifier
This is the iuentiliei ol the pass that you cieateu in the iOS Piovisioning Poital
Leloie, minus youi team ID. Foi instance, il my lull pass ID is TEAMID.pass.pixo|i-
ty.tcstingpass|it, I will set the value ol the pass iuentiliei to pass.pixo|ity.tcsting-
pass|it.
teamIdentifier
This is youi team iuentiliei. To linu this value, simply navigate to the main page
ol iOS Dev Centei, anu then navigate to MemLei Centei. Choose Youi Account
anu then Oiganization Piolile. You shoulu now Le aLle to see a lielu that ieaus
Conpany/Organization |D. That is youi Team ID. Simply copy anu paste that value
in this key in youi pass.json lile.
description
A shoit uesciiption ol what this pass is loi. AccessiLility in iOS will use this ue-
sciiption.
organizationName
This is the name ol youi company.
serialNumber
A unigue seiial numLei loi youi pass. You can make this up as you go. It shoulu
make sense to you anu youi oiganization. Note that il two oi moie passes aie using
the same pass type iuentiliei, theii seiial numLeis cannot Le the same.
barcode
A Laicoue loi youi pass. It is highly iecommenueu that you incluue Laicoue in-
loimation with youi uigital passes. The keys that you can entei in this uictionaiy
aie explaineu heie:
message
The message to Le encoueu within youi Laicoue.
20.2 Creating Pass Files | 895
www.it-ebooks.info
format
The loimat ol youi Laicoue. The value ol this key must Le PKBarcodeFormat
Text, PKBarcodeFormatQR, PKBarcodeFormatPDF417, oi PKBarcodeFormatAztec. A
uiscussion ol Laicoue loimats is outsiue the scope ol this Look so we won`t
go into uetails aLout Laicoues anu what each loimat means.
messageEncoding
The encouing that you want to use loi youi Laicoue. Leave the value ol this
key at iso-8859-1.
logoText
This text will appeai next to the logo ol youi pass in the PassLook app on the uevice.
foregroundColor
The loiegiounu coloi ol youi pass. This value is specilieu in ieu, gieen, anu Llue
values, each ianging liom 0 to 255 inclusive. Viap the value insiue an rgb() lunc-
tion. Foi instance, loi puie ieu coloi, specily rgb(255, 0, 0), oi loi white, specily
rgb(255, 255, 255).
backgroundColor
This is the Lackgiounu coloi ol youi pass, specilieu in the same loimat as the
foregroundColor.
Once you aie uone setting the values loi these keys, you can now specily what type ol
pass you aie cieating. You can uo this Ly putting one ol the lollowing keys in youi
pass`s top level keys, just like all the pieviously mentioneu keys:
The lollowing keys in youi pass.json will contain a uictionaiy ol values
(keys anu values) that will specilically uictate what the pass is loi anu
what values it contains.
eventTicket
This tells PassLook that youi pass is loi an event, such as a conceit.
coupon
This tells PassLook that youi pass is a coupon. Foi instance, the usei can use a pass
like this to get some items moie cheaply in the stoie that issueu the pass.
storeCard
This tells PassLook that youi pass is a stoie caiu (e.g., a loyalty caiu that you can
use in a stoie to collect points).
boardingPass
This tells PassLook that youi pass is a Loaiuing pass (e.g., loi plane, tiain, oi Lus
tiavel).
generic
A pass that uoesn`t lit into any ol the aloiementioneu categoiies.
896 | Chapter 20: Pass Kit
www.it-ebooks.info
Once you have incluueu one ol these pass types as a key into youi pass.json, it is now
time to specily the keys anu values loi the pass type uictionaiy (which we just talkeu
aLout). Each pass type uictionaiy can contain the lollowing keys:
transitType
This key is ieguiieu only insiue the boardingPass uictionaiy; otheiwise, you can
just ignoie this key. The possiLle values loi this key aie PKTransitTypeAir, PKTran
sitTypeBus, PKTransitTypeTrain, PKTransitTypeBoat, anu PKTransitTypeGeneric.
All these aie sell-explanatoiy.
headerFields
The visiLle pait ol the top ol the pass in PassLook on the uevice. Make suie you
uon`t put too much inloimation heie, as these values aie always visiLle to the usei
even when all passes aie stackeu on top ol each othei in the PassLook app on the
uevice.
primaryFields
The most impoitant inloimation aLout youi pass, which will Le uisplayeu on the
liont siue ol the pass. Foi instance, loi a Loaiuing pass at an aiipoit, the gate, seat
numLei, anu aiiline name may Le the most impoitant pieces ol inloimation to
uisplay. Foi anothei type ol pass, these values may Le uilleient.
secondaryFields
Less impoitant inloimation aLout the pass, also uisplayeu on the liont siue ol the
pass. Again, loi a Loaiuing pass at an aiipoit, the seconuaiy lielus might Le the
Loaiuing time, Loaiuing uate, anu aiicialt type.
auxiliaryFields
The least impoitant inloimation to Le uisplayeu on the liont siue ol the pass. Again,
going Lack to oui example ol a Loaiuing pass at an aiipoit, this might Le the
expecteu aiiival time.
backFields
The values to uisplay on the Lack ol the pass.
All the aloiementioneu keys have uictionaiies as theii values, anu those uictionaiies
can contain any ol the lollowing keys:
label
The value ol the lielu that has to Le uisplayeu on the pass (Lack oi liont ol the pass,
uepenuing on the key that it has Leen auueu to).
key
The key that youi app can use to ieau the value ol this lielu.
value
The value ol this lielu.
20.2 Creating Pass Files | 897
www.it-ebooks.info
textAlignment
An optional key that can uesciiLe the alignment ol the laLel visually on the pass.
You can specily any ol the lollowing values loi this lielu (these values aie ieally
sell-explanatoiy):
PKTextAlignmentRight
PKTextAlignmentCentei
PKTextAlignmentLelt
PKTextAlignmentNatuial
PKTextAlignment]ustilieu
Phew! Those aie a lot ol keys anu values to iememLei. Don`t woiiy, though, you`ll get
useu to them altei some time! So let`s cieate a simple pass.json now. I Lelieve il we put
oui ieguiiements uown liist anu then tackle the cieation ol the pass lile itsell, it will Le
much easiei to map what we leaineu so lai to how we cieate the pass.json lile. So heie
is what we`ll uo loi an example:
The type ol pass is a tiain Loaiuing pass.
The tiain uepaits liom a city calleu Hove in the Uniteu Kinguom at 07:37. The
platloim liom which the tiain uepaits at Hove is Platloim 2.
The tiain will aiiive into Lonuon Biiuge station in Lonuon at 0S:+1 on Platloim 13.
The ticket is valiu loi all tiains opeiateu Ly a maue-up company nameu O`Reilly
Railways.
Beloie we move on, though, we neeu to go thiough the locations aiiay in oui
pass.json lile. This key is an aiiay in which eveiy element has two keys I will uesciiLe
in a moment. But the cool thing aLout this key is that it can uesciiLe the geolocations
wheie the pass that you aie cieating Lelongs. Vhen the pass is impoiteu in the PassLook
app on the usei`s uevice, iOS will uisplay a message on the usei`s scieen with the uetails
ol youi pass, telling the usei that youi pass is ielevant at the cuiient location wheie the
usei is. Think ol it this way: in oui example, the usei has to uisplay the tiain ticket at
the ticket Laiiieis eveiy time she ieaches the tiain station at Hove (the uepaituie city).
So you can put the location ol the uepaituie tiain station in the pass (unuei the loca
tions key) so that iOS will automatically uisplay the pass on the scieen when the usei
ieaches the tiain station. You can uo the same thing loi the uestination tiain station
Lecause when the usei is coming Lack home to the Hove tiain station via Lonuon
Biiuge, Lonuon Biiuge will Le the uepaiting station. It`s just the othei way aiounu. Il
you go liom point A to B, A is the souice anu B is the uestination. Once you come Lack,
B is the souice anu A is the uestination. So you can put the location ol Loth point A
anu B, oi even some othei points wheie youi pass is ielevant, insiue the locations aiiay.
Heie aie the keys that eveiy location can contain:
898 | Chapter 20: Pass Kit
www.it-ebooks.info
longitude
The longituue ol the location. This value is ol type double. Do not put guotation
maiks aiounu this value.
latitude
The latituue ol the location. This value is ol type double. Do not put guotation
maiks aiounu this value.
See Also
Recipe 20.2; Recipe 20.0
20.3 Providing Icons and Images for Passes
Problem
You want to make suie that youi pass will Le Lianueu accoiuing to youi company`s
style, oi give youi pass a uistinct llavoi oi image.
Solution
Cieate Lackgiounus, icons, anu logos anu emLeu them insiue youi uigitally signeu pass.
Discussion
A pass can contain uilleient images:
Bac|ground (bac|ground.png and bac|ground2x.png)
The Lackgiounu image ol the pass. Not all passes can have Lackgiounu images.
Logo (|ogo.png and |ogo2x.png)
The logo that will appeai on the uppei lelt coinei ol the pass, uepenuing on which
type ol pass it is.
|con (icon.png and icon2x.png)
The icon loi the pass. Not all passes can have icons. Ve will have a look at cieating
icons loi passes in this chaptei.
Thunbnai| (thunbnai|.png and thunbnai|2x.png)
The thumLnail image that will Le visiLle when the passes aie stackeu on top ol
each othei.
All images, as you can see liom the lilenames, have to come in the non-ietina anu the
ietina llavois. Apple uoesn`t stiictly say that this is a must, Lut uon`t we all as uevelopeis
value oui customeis? Retina uisplays aie so populai now that they aie Lecoming in-
uustiy stanuaiu, so please uo pioviue the ietina images loi youi passes.
20.3 Providing Icons and Images for Passes | 899
www.it-ebooks.info
Now that we know the image lilenames, let`s move on to the image uimensions. I will
list only the ietina images, so please uiviue the image wiuth anu height that I pioviue
Lelow in hall to get the uimensions ol the non-ietina images:
bac|ground2x.png
6+0 pixels wiue anu 960 pixels tall
|ogo2x.png
60 pixels wiue anu 60 pixels tall
icon2x.png
5S pixels wiue anu 29 pixels tall
thunbnai|2x.png
200 pixels wiue anu 200 pixels tall
Foi the puiposes ol this iecipe, I have cieateu all these images in a veiy simple way.
Figuie 20-15 shows them togethei on one canvas.
The liguie is loi uemonstiation puiposes anu just to show you how
many images you have to piepaie loi one pass. You uo not have to cieate
such an image wheie all youi images appeai on one canvas.
Iigurc 20-15. A|| pass inagcs on onc canvas
Now that youi images aie ieauy, place them in the same loluei that you have placeu
youi pass.json lile. Ve will move on to the next stage now, which is piepaiing oui
manilest lile.
900 | Chapter 20: Pass Kit
www.it-ebooks.info
See Also
Recipe 20.2
20.4 Preparing Your Passes for Digital Signature
Problem
You want to piepaie youi passes loi uigital signatuie. This is the step that you have to
take Leloie you aie aLle to uigitally sign youi passes.
Solution
Cieate a lile nameu nanijcst.json in the same loluei wheie you placeu youi pass.json
anu youi pass images. The manilest lile will Le a ]SON lile. Its ioot oLject is a uictionaiy.
The keys to the uictionaiy aie the names ol the liles (all youi images, plus the
pass.json lile). The value ol each key is the SHA1 hash ol the lile.
Discussion
Simply cieate the nanijcst.json lile with the keys loi all youi images anu leave the values
empty loi now. Youi nanijcst.json lile`s contents shoulu look similai to that shown
heie:
{
"background.png" : "",
"background@2x.png" : "",
"icon.png" : "",
"icon@2x.png" : "",
"logo.png" : "",
"logo@2x.png" : "",
"pass.json" : "",
"thumbnail.png" : "",
"thumbnail@2x.png" : ""
}
Now oll to uo the inteiesting pait. Ve have to calculate the SHA1 hashes ol all these
liles. RememLei that eveiy time you change the liles liom now on (loi instance, il you
linu an issue with the pass.json lile), you will have to iecalculate the SHA1 hash anu
place the new SHA1 value in the nanijcst.json lile. In oiuei to calculate the SHA1 hash
ol any lile in OS X, simply lollow these steps:
1. Open up Teiminal anu navigate to the loluei wheie the taiget lile sits, using the
cd commanu.
2. Issue an opcnss| commanu in Teiminal. Pass sha1 as the liist aigument anu the
lilename as the seconu aigument to this commanu.
20.4 Preparing Your Passes for Digital Signature | 901
www.it-ebooks.info
Foi instance, in my pioject loluei, I have a loluei calleu pass anu I have placeu my
pass.json anu my almost-empty nanijcst.json liles in theie along the images (Lack-
giounu, logo, etc.). Now in Teiminal, I shall calculate the SHA1 hashes ol all these liles
anu place them in the manilest lile. So the lollowing listing shows my opcnss| commanu
on the liist line, anu the output with all the hashes on the iest ol the lines.
openssl sha1 *.*
SHA1(background.png)= 0744d456ce7ada02ac581d0fa5c99a5f5eb97539
SHA1(background@2x.png)= 75b5cc40951bcc18750b4230d6334f48f66e8215
SHA1(icon.png)= ed698ab24c5bd7f0e7496b2897ec054bbd426747
SHA1(icon@2x.png)= 90381c84cfea22136c951ddb3b368ade71f49eef
SHA1(logo.png)= c3bd8c5533b6c9f500bbadbdd957b9eac8a6bfe9
SHA1(logo@2x.png)= 1a56a5564dec5e8742ad65dc47aa9bd64c39222f
SHA1(manifest.json)= a7319cf48c0e34cac75001aada9d0767208bf73c
SHA1(pass.json)= af56398ccc5a0faf73667eacabf76d04c961566f
SHA1(thumbnail.png)= 58883d22196eb73f33ea556a4b7ea735f90a6213
SHA1(thumbnail@2x.png)= 0903df90165ef1a8909a15b4f652132c27368560
Ve calculateu the SHA1 ol all liles, incluuing the SHA1 ol the nani-
jcst.json. Howevei, we aie not going to neeu the SHA1 ol nani-
jcst.json Lecause it holus the hashes loi all the othei liles, anu uoesn`t
have to holu its own. So just ignoie the SHA1 ol this lile.
Vhat we have to uo now is to populate the nanijcst.json with the SHA1 values ol the
iest ol the liles that we just calculateu:
{
"background.png" : "0744d456ce7ada02ac581d0fa5c99a5f5eb97539",
"background@2x.png" : "75b5cc40951bcc18750b4230d6334f48f66e8215",
"icon.png" : "ed698ab24c5bd7f0e7496b2897ec054bbd426747",
"icon@2x.png" : "90381c84cfea22136c951ddb3b368ade71f49eef",
"logo.png" : "c3bd8c5533b6c9f500bbadbdd957b9eac8a6bfe9",
"logo@2x.png" : "1a56a5564dofec5e8742ad65dc47aa9bd64c39222f",
"pass.json" : "af56398ccc5a0faf73667eacabf76d04c961566f",
"thumbnail.png" : "58883d22196eb73f33ea556a4b7ea735f90a6213",
"thumbnail@2x.png" : "0903df90165ef1a8909a15b4f652132c27368560"
}
All is goou now. Ve can now move on to the next step, which is the signatuie ol oui
pass.
See Also
Recipe 20.1
902 | Chapter 20: Pass Kit
www.it-ebooks.info
20.5 Signing Passes Digitally
Problem
You have piepaieu youi pass loluei with the manilest anu the pass.json anu all the
images, anu now you want to Le aLle to uigitally sign the pass loluei anu its content to
cieate youi pass lile, ieauy to Le uistiiLuteu.
Solution
Use openssl to sign youi passes.
Discussion
Eveiy pass has to Le signeu using the ceitilicate that we cieateu in Recipe 20.1. Ve will
use openssl again in Teiminal in oiuei to sign oui passes. Beloie you continue ieauing,
make suie that you have cieateu a loluei nameu pass anu place youi pass.json, nani-
jcst.json anu all youi images in this loluei. The loluei name uoesn`t necessaiily have to
Le calleu pass. Howevei, to make suie you can lollow thiough the steps in this iecipe
anu the iest ol this chaptei, it`s Lest to uo what I`ve uone anu put the liles in a loluei
nameu pass so you can lollow along moie easily.
Some ol you may Le a Lit conluseu as to what keys aie which anu what
ceitilicates uo what. I hope I can make it a Lit moie cleai heie. Vhen
you ieguest a new ceitilicate in the iOS Piovisioning Poital, Keychain
cieates a piivate key on youi computei along with a Ceitilicate Reguest
lile (CSR). The ceitilicate will Le geneiateu Ly Apple. Vhen you uown-
loau the ceitilicate, its lile extension will Le .ccr. This is just the ceitili-
cate! Vhen you impoit this ceitilicate into youi Keychain, Keychain will
automatically associate the ceitilicate with the piivate key that it cieateu
Leloie. Now il you expoit the ceitilicate liom Keychain, the iesulting
lile will Le ol type .p12, which contains Loth the ceitilicate anu the
piivate key loi the ceitilicate.
Beloie we can uive into the signing piocess, we will neeu to expoit oui ceitilicate liom
Keychain Access. Keep in minu that the ceitilicate that you uownloaueu liom iOS
Piovisioning Piolile is not the same ceitilicate as you will now expoit liom Keychain
Access, so make suie that you lollow these steps to expoit youi pass ID ceitilicate liom
youi Keychain:
1. Open up Keychain Access on youi Mac.
2. On the uppei-lelt siue ol the winuow unuei Keychains, make suie that you have
selecteu the Login keychain.
3. Unuei the Categoiy section on the lelt siue, choose My Ceitilicates.
20.5 Signing Passes Digitally | 903
www.it-ebooks.info
+. Locate youi Pass Type ID ceitilicate on the iighthanu siue ol the scieen anu then
iight-click on it.
5. Now choose the Expoit option, as shown in Figuie 20-16, anu pioceeu to expoit
youi ceitilicate to uisk as a .p12 lile (as shown in Figuie 20-17). Do not save the
ceitilicate in the pass loluei. Keep the ceitilicate outsiue that loluei.
Iigurc 20-1. Exporting our pass |D ccrtijicatc jron Kcychain Acccss
6. Altei you attempt to expoit youi ceitilicate, you will Le askeu loi two pieces ol
inloimation: a passwoiu that you neeu to set on youi ceitilicate anu the passwoiu
ol youi OS X usei, who owns the Keychain Access. The liist passwoiu is on the
ceitilicate, which will make suie the ceitilicate cannot Le impoiteu into any ian-
uom machine il the usei uoesn`t have the passwoiu. The seconu passwoiu makes
suie the peison who is expoiting youi ceitilicate liom youi Keychain ieally has
peimission to uo so. Foi instance, il you leave youi computei on anu unlockeu anu
youi liienu attempts to expoit a ceitilicate liom youi Keychain, he oi she will have
to entei youi usei account`s passwoiu in oiuei to uo so. It`s always goou piactice
to make suie uilleient accounts on the system have uilleient passwoius. Foi in-
stance, il you anu youi Liothei Loth use the same Mac, you neeu to make suie that
904 | Chapter 20: Pass Kit
www.it-ebooks.info
youi account`s passwoiu is something unigue to youi account. Il you anu youi
Liothei have the same passwoiu on Loth youi accounts on the same Mac, that
uelies the whole puipose ol secuiity on youi Mac.
Make suie that you do not save the ceitilicate insiue the pass loluei. You
shoulu not ship youi ceitilicate insiue youi pass.
Now that you have expoiteu youi ceitilicate, you have enueu up with a lile that is
pioLaLly nameu Ccrtijicatcs.p12. Now it is time to split this lile into the ceitilicate pait
anu the piivate key. As you may know, when you expoit a ceitilicate liom Keychain
Access, the iesulting .p12 lile contains Loth the ceitilicate anu the piivate key. Howevei,
when you use openssl to sign youi pass, you will neeu to pass the piivate key anu the
Iigurc 20-17. Saving thc ccrtijicatc to dis| as part oj cxporting jron Kcychain Acccss
20.5 Signing Passes Digitally | 905
www.it-ebooks.info
ceitilicate sepaiately. So to ietiieve the piivate key anu the ceitilicate liom youi Ccr-
tijicatcs.p12 lile that we just expoiteu liom Keychain Access, lollow these steps:
1. Open up Teiminal il it`s not open alieauy.
2. Navigate to the loluei wheie you saveu the expoiteu ceitilicate .p12 lile.
3. In oiuei to get the ceitilicate out, issue the lollowing commanu:
openssl pkcs12 -in "NAME OF YOUR .P12 CERTIFICATE FILE" -clcerts \
-nokeys -out "NAME OF THE OUTPUT CERTIFICATE"
Foi instance, the ceitilicate anu piivate key lile expoiteu liom my Keychain is nameu
Ccrtijicatcs.p12 anu I want to expoit the ceitilicate out ol it, unuei the name cxportcd-
ccrtijicatc. To uo this, I have to issue the lollowing commanu in Teiminal:
openssl pkcs12 -in Certificates.p12 -clcerts -nokeys -out exported-certificate
Once you issue this commanu, you will Le askeu to assign youi expoiteu
ceitilicate a passwoiu. Foi this example, I am setting the passwoiu as
1231, Lut please give youis a Lettei passwoiu.
+. In oiuei to expoit the piivate key out ol the Keychain-expoiteu ceitilicate, you will
neeu to issue the lollowing commanu in Teiminal:
openssl pkcs12 -in "NAME OF YOUR .P12 CERTIFICATE FILE" \
-nocerts -out "NAME OF THE OUTPUT KEY"
I will name the expoiteu piivate key cxportcd-|cy, Lut leel liee to choose anothei name
il you want to:
openssl pkcs12 -in Certificates.p12 -nocerts -out exported-key
Again, you will Le askeu to entei passwoius loi youi key. I have set mine up with the
passwoiu ol 1231 so that I can easily iememLei it, anu it`s the same passwoiu I have
set up loi my ceitilicate. In an oiganization wheie you neeu to make suie things aie
uone in a secuie way, ol couise, you woulun`t want to choose this type ol passwoiu.
Choose something that makes sense loi you anu make suie the passwoius that you
choose loi uilleient ceitilicates/keys that you expoit aie uistinct loi maximum piotec-
tion.
Fantastic, now we have oui expoiteu ceitilicate anu piivate key liles. Ve can now move
on to signing oui pass with these liles. Follow these steps in oiuei to uo so:
1. Il you haven`t alieauy, place all the liles ielateu to the pass (pass.json, nani-
jcst.json, anu all the ielevant images) insiue a loluei calleu pass. You can name this
loluei anything you want, Lut loi the puipose ol claiity in this iecipe, it`s Lest that
the loluei name that you cieate Le the same loluei that I have heie. That way, it
will Le easiei loi all ol us to know which loluei we aie in anu what we aie uoing
in Teiminal.
906 | Chapter 20: Pass Kit
www.it-ebooks.info
2. Use the cd commanu to change the cuiient woiking uiiectoiy to the pass uiiectoiy
wheie all youi pass liles exist.
3. Execute the rn -j .DS_Storc commanu to make suie no unnecessaiy OS X hiuuen
system liles aie piesent in youi pass loluei. You neeu to make suie all the liles in
this loluei aie listeu in the nanijcst.json along with theii SHA1 hashes. Il any othei
liles, hiuuen oi not hiuuen, cieep into this loluei without Leing listeu in the man-
ilest lile, the iesulting pass will Le invaliu anu not ieauaLle Ly PassLook on iOS
uevices oi the simulatoi.
+. Issue the lollowing commanu in Teiminal in oiuei to geneiate a signaturc lile insiue
youi pass loluei:
openssl smime -binary -sign -signer "PATH TO YOUR EXPORTED CERTIFICATE" \
-inkey "PATH TO YOUR EXPORTED PRIVATE KEY" -in manifest.json \
-out signature -outform DER
This commanu has to Le issueu insiue the pass loluei wheie all youi
pass assets exist. The expoiteu ceitilicate anu piivate key aie the ceitil-
icate anu the piivate key that you extiacteu liom the Keychain-expoiteu
ceitilicate. Avoiu pioviuing the actual Keychain-expoiteu ceitilicate to
this commanu. Beloie this, we leaineu how to extiact the ieal ceitilicate
anu the piivate key out ol the Keychain-expoiteu .p12 lile, so you may
want to have a look at that again to make suie things aie going as plan-
neu.
As pait ol the last step, you will Le askeu to pioviue the passwoiu loi youi piivate key.
Do you iememLei it? That is the passwoiu that you set when you weie extiacting the
piivate key liom the Keychain-expoiteu ceitilicate. This commanu has now cieateu a
lile nameu signaturc in the pass loluei. Ve aie almost uone; all we have to uo now is
to compiess the pass uiiectoiy into a ZIP lile with the extension ol .p|pass. In oiuei to
uo that, lollow these steps:
1. Open up Teiminal anu using the cd commanu, navigate to youi pass loluei.
2. Issue the lollowing commanu in oiuei to zip youi pass loluei into a lile calleu
pass.p|pass in the cuiient loluei:
zip -r pass.pkpass . -x '.DS_Store'
This will zip up all the pass liles into the pass.p|pass anu again, makes suie that a lile
nameu .DS_Storc will not Le incluueu in the output aichive.
See Also
Recipe 20.+; Recipe 20.1
20.5 Signing Passes Digitally | 907
www.it-ebooks.info
20.6 Distributing Passes Using Email
Problem
You want to Le aLle to senu youi uigitally signeu passes to people using theii email
auuiess.
Solution
Simply senu the passes as attachments in youi email.
Discussion
The pass that you signeu anu packageu up in Recipe 20.5 is now ieauy to Le uistiiLuteu.
One ol the easiest way ol uistiiLuting passes is thiough email. Follow these steps to
uistiiLute youi pass thiough email using the Mail.app on youi installation ol OS X:
1. Open up Mail.app on youi installation ol OS X.
2. Fiom the File menu, choose New Message.
3. Entei the email auuiess ol the peison to whom you want to senu the pass.
+. Entei a title loi youi email.
5. Entei the message loi youi email anu simply uiag anu uiop the pass.p|pass lile,
which you piepaieu in Recipe 20.5, into the message ol youi email at the enu, as
shown in Figuie 20-1S.
Iigurc 20-18. Distributing digita||y signcd passcs using Mai|.app on OS X
908 | Chapter 20: Pass Kit
www.it-ebooks.info
6. Now senu the email. The usei will ieceive it in hei inLox. The email will appeai as
shown in Figuie 20-19 on the usei`s uevice.
Iigurc 20-19. A pass scnt through cnai|
Note that the icon that we specilieu loi oui pass in Recipe 20.3 is ap-
peaiing in Mail.app on iOS uevices when a pass is attacheu to an email.
Now the usei has the aLility to tap on the pass that is attacheu to the email. This will
cause PassLook to pop up anu uisplay the pass in its inteilace, allowing the usei to auu
the pass to PassLook, iight on the uevice Figuie 20-20.
Il the usei piesses the Auu Lutton on the pass, it will get auueu to PassLook iight on
the uevice. Now the usei has the aLility to see the liont (Figuie 20-21) oi the Lack
(Figuie 20-22) ol the pass.
Figuie 20-21 uilleis liom Figuie 20-20 in that when the pass is auueu
to the PassLook on the uevice (Figuie 20-21), theie is no Auu Lutton on
the top ol the scieen. This simply shows that the pass is alieauy installeu
on the uevice.
20.6 Distributing Passes Using Email | 909
www.it-ebooks.info
Iigurc 20-21. Disp|aying thc jront oj a pass in Passboo| on an iOS dcvicc
Iigurc 20-20. Opcning a pass attachcd to an cnai| wi|| disp|ay thc Passboo| intcrjacc on an iOS dcvicc
910 | Chapter 20: Pass Kit
www.it-ebooks.info
Iigurc 20-22. Disp|aying thc bac| oj a pass in Passboo| on an iOS dcvicc
See Also
Recipe 20.7
20.7 Distributing Passes Using Web Services
Problem
You want useis to Le aLle to uownloau youi uigitally signeu passes iight liom youi
weLsite.
Solution
In youi weL pages, cieate hypeilinks to youi .p|pass passes. Vhen useis view the weL
pages on theii uevices, they can simply tap on those links. Once they tap on the link,
Salaii will uetect that the link leaus to a .p|pass lile anu will hanu the link to PassLook
which will uisplay the pass on the weLsite anu allow the useis to auu youi passes to
theii PassLook.
20.7 Distributing Passes Using Web Services | 911
www.it-ebooks.info
Discussion
Salaii on iOS uoes not hanule uiiect uownloauing ol .p|pass pass liles. In oiuei to let
youi useis uownloau the .p|pass passes, you neeu to cieate weL pages with hypeilinks
in them that point to the .p|pass liles. A simple HTML coue lile that seives a
pass.p|pass to the usei is uisplayeu heie:
<html>
<header>
<title>Passbook Site</title>
</header>
<body>
<a href="http://localhost:8888/pass.pkpass">Download your pass here</a>
</body>
</html>
I have put the link as |oca|host Lecause I`m iunning an instance ol
Apache weL seivei on my installation ol OS X. You neeu to make suie
the link in this HTML lile makes sense in youi weL uevelopment envi-
ionment.
Now when the usei opens this link in Salaii on hei uevice, she will see something similai
to Figuie 20-23.
Iigurc 20-23. \icwing our wcbsitc in Sajari on iOS Sinu|ator
912 | Chapter 20: Pass Kit
www.it-ebooks.info
Vhen the usei taps on the link, PassLook will pop up anu will uisplay its lamiliai UI
to the usei, allowing hei to auu youi pass to hei uevice`s PassLook, similai to that shown
in Figuie 20-20.
See Also
Recipe 20.6
20.8 Enabling Your iOS Apps to Access Passes on iOS Devices
Problem
You want to ueploy youi PassLook-enaLleu app to iOS uevices anu you want to make
suie that youi app can ieau the uigitally signeu passes that you have pusheu into those
uevices.
Solution
Cieate an appiopiiate piovision piolile loi youi app, linkeu to an App ID that has Passes
access enaLleu loi it.
Discussion
You neeu to sign youi apps with an appiopiiate piovisioning piolile that has Leen
cieateu in the same poital that youi pass IDs weie cieateu in, in oiuei to Le aLle to ieau
oui own passes liom the PassLook app on useis` uevices. The whole piocess is uepicteu
in Figuie 20-2+.
Iigurc 20-21. Thc proccss oj cnab|ing an iOS app to acccss passcs on an iOS dcvicc
20.8 Enabling Your iOS Apps to Access Passes on iOS Devices | 913
www.it-ebooks.info
So let`s Legin! Heie I assume that you alieauy have a Dev/Dist ceitilicate. Ve`ll cieate
an app ID loi the pass ID that we cieateu in Recipe 20.1 anu then move on to cieate
the appiopiiate piovisioning piolile loi that app ID. Heie we go:
1. Navigate to iOS Dev Centei in youi Liowsei, anu log in il you aie not loggeu in
alieauy.
2. Navigate to iOS Piovisioning Poital now.
3. Navigate to the App IDs section anu piess the New App ID Lutton.
+. In the Desciiption Lox, uesciiLe youi app ID; something that is meaninglul to you
anu youi team oi oiganization.
5. Leave the Bunule Seeu ID as Use Team ID.
6. In the Bunule Iuentiliei (App ID Sullix), entei the ieveise uomain style name ol
youi Lunule ID. Foi me, loi the pass with an ID ol pass.pixo|ity.tcstingpass|it, I
have set the Lunule iuentiliei ol my app ID to con.pixo|ity.tcstingpass|it.
7. Once you aie uone, piess the SuLmit Lutton. Gieat, now you have an App ID.
S. Back in the App IDs section ol the poital, locate youi newly cieateu app ID. You
shoulu see something similai to that shown in Figuie 20-25.
Iigurc 20-25. Locating our app |D in thc iOS provisioning porta|
9. As you can see, passes aie not conliguieu loi this app ID. Piess the Conliguie link
on the iighthanu siue ol the scieen loi the app ID that you just geneiateu.
10. In the new scieen, you will see a lew conliguiation options, such as those loi iClouu
anu push notilications. Ignoie all those anu move ovei to the EnaLle loi Passes
section anu tick the Lox next to it, as shown in Figuie 20-26.
11. Once you tick that check Lox, you will Le piompteu with a scieen asking whethei
you want to enaLle passes loi this app ID. Piess the OK Lutton on that uialog anu
then piess the Done Lutton at the Lottom ol the scieen to linish youi woik with
the app ID (Figuie 20-27).
914 | Chapter 20: Pass Kit
www.it-ebooks.info
12. Now that we have enaLleu Passes loi oui app ID, it is time to cieate oui piovisioning
piolile. Heau to the Piovisioning section ol the iOS Piovisioning Piolile now.
13. Ve aie going to cieate a uevelopei piovisioning piolile as opposeu to an Au Hoc
Luilu, so in the Piovisioning section, unuei the Development taL, piess the New
Piolile Lutton.
1+. Unuei the Piolile name, give youi piolile a meaninglul name. I have set the piolile
name as Tcsting Pass|it.
15. Unuei the Ceitilicates section, choose youi uevelopei ceitilicate anu tick it.
16. Unuei the App ID section, choose the App ID that you just cieateu.
17. Unuei the Devices, choose the list ol uevices on which you aie intenuing to test
youi app. Once you aie uone, piess the SuLmit Lutton (as shown in Figuie 20-2S).
Iigurc 20-2. Enab|ing Pass acccss on our app |D
Iigurc 20-27. Prcssing OK on this dia|og wi|| jina||y cnab|c Passcs acccss on our app |D
20.8 Enabling Your iOS Apps to Access Passes on iOS Devices | 915
www.it-ebooks.info
Iigurc 20-28. Crcating a dcvc|opcr provisioning proji|c jor our pass|it app
1S. Once you aie uone, you shoulu Le aLle to uownloau youi piovisioning piolile liom
the iOS Piovisioning Poital. Altei you have uownloaueu the piolile, simply uiag
anu uiop it into iTunes in oiuei to install it.
Theie aie vaiious ways ol installing a piovisioning piolile on youi OS
X installation. The Lest anu lastest way is to uiag anu uiop the piolile
into iTunes. You can also use Xcoue to install the piolile. Vhatevei
methou you choose, make suie that you avoiu uouLle-clicking on the
piolile in oiuei to install it. DouLle-clicking will install youi piolile with
a ieally ciyptic name on youi uisk, anu latei it will Le veiy uillicult to
uistinguish which piolile is which. To keep youi uisk clean, use iTunes
oi Xcoue to install youi piovisioning pioliles. You can view all installeu
piovisioning pioliles on youi uisk in the lile -/Library/Mobi|cDcvicc/
Provisioning Proji|cs/.
19. Now open youi pioject in Xcoue. In the Builu Settings ol youi taiget app, choose
the piovisioning piolile that you just cieateu loi DeLug-only Luilus. You can uo
the same thing loi Au Hoc Luilus, Lut unuei the Release scheme in Builu Settings.
20. Now go to the Summaiy taL ol youi taiget, anu unuei the Entitlements section,
tick the EnaLle Entitlements Lox to enaLle entitlements loi youi taiget.
21. Unuei Entitlements, unuei the Passes section, choose the Use selecteu pass type
iuentilieis option anu then piess the Reliesh Lutton. This will contact the iOS
916 | Chapter 20: Pass Kit
www.it-ebooks.info
Piovisioning Poital anu will ietiieve all the pass type IDs that youi piovisioning
piolile is linkeu to. RememLei, a piovisioning piolile is linkeu to an app ID anu
you conliguieu youi app ID to enaLle access to passes. So you will enu up with
something like that shown in Figuie 20-29.
Iigurc 20-29. Choosing thc pass |Ds that wc want to acccss
Il you want to Le aLle to access all pass type IDs that youi piovision
piolile can ieau, simply leave the Passes option as Use pass type iuen-
tilieis liom piovisioning piolile.
Anu with this task, we aie all uone setting up Pass Kit! All we neeu is to wiite an app
that can access the passes that we cieateu anu impoiteu into passLook, as mentioneu
in Recipe 20.6 anu Recipe 20.7. The app will Le uesciiLeu in Recipe 20.9.
See Also
Recipe 20.6; Recipe 20.7
20.9 Interacting with Passbook Programmatically
Problem
You want to Le aLle to inteiact with the installeu passes on a usei`s uevice piogiam-
matically.
20.9 Interacting with Passbook Programmatically | 917
www.it-ebooks.info
Solution
Incluue the PassKit.liamewoik into youi pioject anu use the PKPassLibrary to linu the
passes that you aie inteiesteu in. Passes will Le ol type PKPass, so using this class you
can ietiieve inloimation aLout youi passes.
Discussion
As a pieieguisite to this iecipe, please make suie that you have ieau
Recipe 20.S anu now have an Xcoue iOS pioject that has the appiopiiate
piovisioning piolile to access youi passes in the usei`s PassLook liLiaiy.
Apple has pioviueu the PassKit.liamewoik loi iOS uevelopeis. Using this liamewoik,
you can inteiact with passes that the usei has installeu on hei uevices. To Le aLle to
use this liamewoik, you have to liist auu it to oui pioject. Follow these steps:
1. On the lelthanu siue in the Navigatoi pane, select youi pioject (with the Llue icon).
2. Choose the taiget that you aie Luiluing next to the Navigatoi pane.
3. On the top ol the scieen, choose the Builu Phases taL.
+. Move ovei to anu expanu the Link Binaiy Vith LiLiaiies section anu piess the -
Lutton loi it.
5. In the list ol liamewoiks anu liLiaiies that appeai on youi list, linu anu choose
PassKit.liamewoik anu auu it to youi pioject, as shown in Figuie 20-30.
Now that you have this liamewoik, you can get staiteu with youi pioject. Go to youi
app uelegate`s heauei lile anu impoit the PassKit/PassKit.h heauei lile liom the PassKit
liamewoik:
#import <UIKit/UIKit.h>
#import <PassKit/PassKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
The next thing that we aie going to uo is ueclaie a piivate piopeity ol type PKPassLi
brary in the implementation lile ol oui app uelegate. The aloiementioneu class in
PassKit.liamewoik will allow you to inteiact with the passes that have Leen auueu to
the uevice. Vhile you aie at it, you will also neeu to know the keys in the pass.json lile
that you cieateu in Recipe 20.2 in oiuei to Le aLle to ieau values such as the uepaituie
platloim anu uepaituie city. So ueclaie these keys as well, all in the implementation
lile ol youi app uelegate:
918 | Chapter 20: Pass Kit
www.it-ebooks.info
#import "AppDelegate.h"
@interface AppDelegate ()
@property (nonatomic, strong) PKPassLibrary *passLibrary;
@end
NSString *PassIdentifier = @"pass.pixolity.testingpasskit";
NSString *PassSerialNumber = @"p69f2J";
NSString *DepartureKey = @"departure";
NSString *DeparturePlatformKey = @"departurePlatform";
NSString *Arrival = @"arrival";
NSString *ArrivalPlatform = @"arrivalPlatform";
@implementation AppDelegate
...
Fantastic! Altei you aie uone with that, you neeu to stait accessing the PassLook liLiaiy
on the uevice. But wait a minute: what il the uevice uoesn`t have PassLook installeu on
it? You have to liist check whethei PassLook is availaLle on the uevice. Do that using
the isPassLibraryAvailable class methou ol the PKPassLibrary class.
The next thing you neeu to uo is instantiate youi passLibrary piopeity ol type PK
PassLibrary anu then use the passWithPassTypeIdentifier:serialNumber: instance
methou ol the pass liLiaiy to linu the pass that you aie looking loi. So now you know
why we have also uelineu oui pass iuentiliei anu its seiial numLei among the keys to
Iigurc 20-30. Adding thc PassKit.jrancwor| to our targct in Xcodc
20.9 Interacting with Passbook Programmatically | 919
www.it-ebooks.info
uilleient lielus within the pass. The aloiementioneu methou will ietuin an oLject ol
type PKPass that will iepiesent youi pass oLject. Once you have this pass oLject, you
can ieau the values liom its uilleient keys.
Delault keys, such as oiganization name anu seiial numLei, aie mappeu to piopeities
loi you Ly Apple in the PKPass class itsell. Howevei, il you want to access the values
within primaryFields oi othei similai places, you will neeu to use the localizedValue
ForFieldKey: instance methou ol the PKPass class anu pass youi keys to this methou to
get the values associateu with those keys. So heie is a little coue snippet that can ieau
the uepaituie anu aiiival city anu platloims liom the pass that we cieateu in
Recipe 20.2:
This is insiue the implementation lile ol oui app uelegate.
#import "AppDelegate.h"
@interface AppDelegate ()
@property (nonatomic, strong) PKPassLibrary *passLibrary;
@end
NSString *PassIdentifier = @"pass.pixolity.testingpasskit";
NSString *PassSerialNumber = @"p69f2J";
NSString *DepartureKey = @"departure";
NSString *DeparturePlatformKey = @"departurePlatform";
NSString *Arrival = @"arrival";
NSString *ArrivalPlatform = @"arrivalPlatform";
@implementation AppDelegate
- (void) displayPassInformation:(PKPass *)paramPass{
if (paramPass == nil){
NSLog(@"The given pass is nil.");
return;
}
NSLog(@"Departs From = %@",
[paramPass localizedValueForFieldKey:DepartureKey]);
NSLog(@"Departure Platform = %@",
[paramPass localizedValueForFieldKey:DeparturePlatformKey]);
NSLog(@"Arrives at = %@",
[paramPass localizedValueForFieldKey:Arrival]);
NSLog(@"Arrival Platform = %@",
[paramPass localizedValueForFieldKey:ArrivalPlatform]);
}
920 | Chapter 20: Pass Kit
www.it-ebooks.info
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
if ([PKPassLibrary isPassLibraryAvailable]){
self.passLibrary = [[PKPassLibrary alloc] init];
PKPass *pass =
[self.passLibrary passWithPassTypeIdentifier:PassIdentifier
serialNumber:PassSerialNumber];
[self displayPassInformation:pass];
} else {
/* Take another action here perhaps */
NSLog(@"The pass library is not available.");
}
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;
}
The pass iuentiliei anu seiial numLei pioviueu aie loi the pass that I
cieateu using my ceitilicate. Howevei, youi pass iuentiliei will Le uil-
leient. The seiial numLei may Le the same, Lut the pass iuentiliei will
ceitainly Le uilleient, anu will Le something that makes moie sense loi
you anu youi piovisioning poital/oiganization.
See Also
Recipe 20.2
20.9 Interacting with Passbook Programmatically | 921
www.it-ebooks.info
www.it-ebooks.info
Index
Symbols
" " (uouLle guotes), in stiings, 23
s vs. loimat speciliei, 2+
- (iu)initVithCouei:(NSCouei ')aDecouei;
methou, 596
- (voiu)encoueVithCouei:(NSCouei ')aCouei
methou, 596
.h liles, 60
.ipa liles, 19
.moLilepiovision liles, 19
.plist lile
auuing key anu setting to tiue, 662
auuing location Key to, 6+S
setting aiiay key in .plist lile, 6+66+S
.png liles
linuing path in images loluei to all, 90
loauing as image, S7
.xiL liles, 1+7
= (egual sign), setting piopeities using, +9
== (uouLle egual sign), insiue conuitional
statement, 2S
(at-sign)
as pielix to uouLle guotes, 23
in expiession Loxing, 71
collection loimat, 73
" " (an empty stiing), cieating gioup with
name egual to, 560
piopeity keywoiu, +S
synthesize keywoiu, +9
(caiet) chaiactei, maiking Llock oLject with,
77
Liiugeietaineu typecast, 5S
Llock stoiage type
pielix integeiValue vaiiaLle with, 370371
pielix outsiueVaiiaLle, 366367
Liiuge typecast, 5S
Liiugetianslei keywoiu, 5++
Liiugetianslei typecast, 5S
(cuily Liaces), in il-else statement, 29
' (pipe) chaiactei, using in constiucting swipe
gestuie, +57
A
ABAuuiessBookAuuRecoiu lunction, 5+9
551
ABAuuiessBookCopyAiiayOlAllGioups
lunction, 55S562
ABAuuiessBookCopyAiiayOlAllPeople
lunction, 5+3, 55S562
ABAuuiessBookCopyLocalizeuLaLel lunction,
5+9
ABAuuiessBookCopyPeopleVithName
lunction, 562
ABAuuiessBookCieate lunction, 5+0
ABAuuiessBookCieateVithOptions lunction,
5+05+3
ABAuuiessBookGetAuthoiizationStatus
lunction, 5375+0, 53S
ABAuuiessBookHasUnsaveuChanges
lunction, 5+0
ABAuuiessBookReveit pioceuuie, 5+3
ABAuuiessBookSave lunction, 553
ABGioupAuuMemLei lunction, 555557
ABGioupCieate lunction, 552555
ABMultiValueCopyLaLelAtInuex lunction,
5+9
ABMultiValueCopyLaLelAtInuex lunction,
laLel values, 5+9
ABMultiValueRel values, 5+5
Ve`u like to heai youi suggestions loi impioving oui inuexes. Senu email to indcxorci||y.con.
923
www.it-ebooks.info
ABPeisonCopyImageData lunction, 56256S
ABPeisonCieate lunction, 5+9551
ABPeisonHasImageData lunction, 562
ABPeisonSetImageData lunction, 56256S
ABRecoiuCopyValue lunction, 5++5+9
ABRecoiuRel uata type, 5+5, 5+7, 5+9
ABRecoiuSetValue lunction, 5+9551
acceleiometei
aLout, S11S12
uetecting availaLility ol, S12S1+
ietiieving uata ol, S16S19
accessoiies
cieating custom taLle view cell, 290293
uisplaying uilleient types in taLle view, 2SS
290
accessoiyView piopeity
assigning instance ol uiview class, 290292
Au Hoc DistiiLution piovision piolile, cieating,
161S
Auu navigation Lai Lutton, 6S5
auuAlaim: instance methou, 72772S
auuAnnotation: methou, +37
auuGestuieRecognizei: methou, +5+, +6S
auuOLject: methou, 75, S2
auuOLjectsFiomAiiay: methou, 75
auuOLseivei:selectoi:name:oLject: instance
methou, 9+95
auuOpeiation: methou, +06
auuPeisonsAnuGioupsToAuuiessBook:
methou, 557
AuuPeisonViewContiollei, 6S6692
auuiess Look
aLout, 535536
auuing peisons to gioups, 555557
inseiting gioup entiy into, 552555
Inseiting new gioup with alieauy existing
name, 553
inseiting peison entiy into, 5+9551
ieguesting access to, 5375+0
ietiieving all people in, 5+3
ietiieving anu setting image ol peison, 562
56S
ietiieving piopeities ol entiies in, 5++5+9
ietiieving ieleience to, 5+05+3
seaiching, 557562
AuuiessBook liamewoik, 535
auuiesses
conveiting longituue anu latituue to, +50
+52
linuing longituue anu latituue liom, ++S
+50
auuTaiget:action:loiContiolEvents: methou,
196, 333
auispatchkeywoiu, loi GCD methous anu
uata types, 355356
alline iotation tiansloimations, S0SS10
alline scale tiansloimations, 79+795, S07
S0S
alline tiansloimations, 790792
alaims
auuing to calenuais, 72772S
alaimVithRelativeOllset: class methou, 727
72S
ALAsset class, 601
ALAsset Repiesentation class, 62+
ALAssetsLiLiaiy class, 61661S
aleit views
cieating without Lutton, 102
uisplaying on iPhone, 229232
loi text entiies, 10+106
initialing, 100101
styles ol, 102
with Yes anu No Luttons, 10210+
aleits
uisplaying with UIAleitView, 100106
aleitView:clickeuButtonAtInuex: methou, 103
aligning UI components, 253, 265272
allKeys methou, S0
alloc methou, +6+S
allowaLleMovement piopeity, +6++65
allowsContentMouilications piopeity, 70S
allowsPickingMultipleItems piopeity, 527,
533
alpha values, 751, 7S5
animating views
moving anu, 79SS06
scaling anu, S07S0S
animations
aLout, 7397+1
peiloiming in UIKit, 79S
API (Application Piogiamming Inteilace)
exposeu Ly NSFileManagei, 5S0
online seivices loi uevelopeis exposing thiiu
paity, +52
suppoiting uevices iunning oluei iOS
veisions anu, 6669
using loi path ol lolueis anu liles
appiopiiate, 573
924 | Index
www.it-ebooks.info
using GCD in woiking with UI-ielateu, 373
377
App ID cieating, S27
app iuentiliei, S32
Apple App Stoie
causes loi iejection ol app in
aleit views without Luttons, 102
causing iejection ol app in
ciashes, S
Application Piogiamming Inteilace (API)
suppoiting uevices iunning oluei iOS
veisions anu, 6669
application setting, iesponuing to changes in,
659662
application:uiuFinishLaunchingVithOptions:
instance methou, 5+15+2
application:uiuFinishLaunchingVithOptions:
methou, 1+9, 35+, 399, 595, 6S+
application:uiuFinishLaunchingVithOptions:
methou,, +00
application:uiuReceiveLocalNotilication:
methou, 6+16+2
applicationDiuEnteiBackgiounu: methou, 633
applications
aichitectuial components ol, 99
compiling, 710
connecting to Inteinet, +71
cieating
in Xcoue, 25
tasks in, 7
enumeiating contents ol loluei in, 5S1
opting out ol multitasking, 662
packaging loi uistiiLution, 1520
ieasons loi iejection ol
aleit views without Luttons, 102
ciashes as, S
ioot lolueis ol, 571
iunning on uevices, 12
shaiing with liienus content ol, 151155
applicationVillResignActive: methou, 595
applyConstiaintsToButtonOnBottomGiayVie
w methou, 271
applyConstiaintsToButtonOnTopGiayView
methou, 269270
ARC (Automatic Releience Counting)
in LLVM compilei, 1
using typecasting unuei, 5760
aichiveu app, cieating, 1S
aichiveRootOLject:toFile class methou, 59S
aichiving contents ol oLjects, 59559S
aiiayFoiKey: methou, S3+
Aiiayol View Contiolleis, 161162
aiiayOlClouuDocumentVeisions aiiay, S73
S7+
aiiays
allocating anu using, 7277
CFAiiayRel, 5+3
collecting constiaints into, 263265
ueseiializing ]SON into uictionaiies anu,
+91+93
mutaLle, 6669
mutaLle vs. immutaLle aiiay, 73
ol coloi components, 7S5
ol ianuom numLeis saving to il anu only il,
3S+
seiializing into ]SON, +SS+91
similaiity to uictionaiies, 57S579
soiting, 7677
using NS oLject types in, 73
vs. uictionaiies, 77
vs. sets, S1
while loop tiansveising, 3+
aiiayVithOLjects class methou, 73
aspect iatio, 759
assess uata ol asset, 601
assetFoiURL:iesultBlock:lailuieBlock methou,
601
Assets LiLiaiy liamewoik
auuing to taiget, 600
uiiectly accessing content ol Photo LiLiaiy
using, 617
ietiieving photos oi viueos liom Photo
LiLiaiy using, 620627
asynchionous connection
ieguesting to ietiieve contents ol URL, 65+
656
asynchionous connections
hanuling timeouts in, +7++75
asynchionous tasks
peiloiming with GCD non-UI ielateu, 3S0
3S5
iunning with opeiations, +0++10
synchionously uownloauing URL liom
asynchionous coue, 3S0
asynchionously
uownloauing, with NSURLConnection,
+71+7+
Index | 925
www.it-ebooks.info
loauing uata ol song into instance ol NSData
using GCD, 507
at-sign ()
as pielix to uouLle guotes, 23
in expiession Loxing, 71
atomic piopeity, +9
atomically paiametei, 575
attenuees piopeity
accessing paiticipant oLjects, 726
attiiLute, uelinition ol, 667
auuio
hanuling inteiiuptions
invoking iecoiu instance methou, 516
while playing, 50750S
while iecoiuing auuio, 515
playing liles, 505507
playing in Lackgiounu, 6+66+S
playing ovei othei active sounus, 516519
iecoiuing, 50S51+
auuio PlayeiDiuFinishPlaying:successlully:
uelegate methou, 51+
auuioPlayeiBeginInteiiuption: methou, 507
50S
auuioPlayeiEnuInteiiuption:with Flags:
methou, 50750S
auuioRecoiueiBeginInteiiuption: methou,
515
auuioRecoiueiDiuFinishRecoiuing:success
lully: uelegate methou, 513
auuioRecoiueiEnuInteiiuption:withFlags:
methou, 515
auuioRecoiuingPath methou, 509, 511
auuioRecoiuingSettings methou, 509, 512
Auto Layout
aLout, 253, 255
align Lutton at centei ol scieen, 25S
conliguiing constiaints in Inteilace Builuei,
273276
UIKit tianslating autoiesizing masks to
constiaints ol, 262
Automatic Releience Counting (ARC)
in LLVM compilei, 1
moving liom Manual Releience Counting
to, 5257, 5257
using typecasting unuei, 5760
autoielease oLjects
autoielease pool insiue loops anu, 33
autoielease pool, +22+23
AV Founuation liamewoik
auuing to pioject, 505
hanuling inteiiuptions
while playing auuio liles, 50750S
while iecoiuing auuio, 515
playing auuio liles, 505507
playing auuio in Lackgiounu, 6+66+S
playing auuio ovei othei active sounus, 516
519
iecoiuing auuio using, 50S51+
availaLleData instance methou, 592
availaLleMeuiaTypesFoiSouiceType: class
methou, 60260+
AVAuuioPlayei class
hanuling inteiiuptions while playing auuio
liles, 50750S
playing auuio liles, 505507
playing auuio in Lackgiounu, 6+66+S
AVAuuioPlayeiDelegate piotocol, 50750S,
51S519
AVAuuioRecoiuei class
hanuling inteiiuptions while iecoiuing
auuio, 515
iecoiuing auuio, 50S51+
AVAuuioRecoiuei: methou, 509
AVAuuioRecoiueiDelegate piotocol, 513, 51+,
515
AVAuuioSession class, 516519
AVAuuioSessionCategoiyAmLient values, 516
AVAuuioSessionCategoiyAuuioPiocessing
values, 517
AVAuuioSessionCategoiyPlayAnuRecoiu
values, 517
AVAuuioSessionCategoiyPlayLack values, 517
AVAuuioSessionCategoiyRecoiu values, 516
AVAuuioSessionCategoiySoloAmLient values,
516
AVEncoueiAuuioQualityKey, 510
AVFoimatIDKey, 509
AVNumLeiOlChannelsKey, 510
AVSampleRateKey, 509
axial anu iauial
uiawing giauients, 7S3790
axial giauients, 7S+, 7S7
B
Lackgiounu execution, 633
(see also multitasking)
ol applications, 633
Lackgiounu methous, invoking, +23
926 | Index
www.it-ebooks.info
LackgiounuTimeRemaining piopeity, 6+S
LaiButtonAction piopeity, 31S
Base SDK, 67
LeginAnimations:context: methou, 79S, S02
LeginBackgiounuTaskVithExpiiationHanulei
: instance methou, 63563S
Litwise OR opeianu, +57
Llock oLjects
aLout, 357359
accessing vaiiaLles in, 365371
auuitional iesouices on, xv
as paiametei ol uispatchaltei lunction,
3S6
as paiametei ol uispatchasync lunction,
37+
as paiametei ol uispatchonce lunction,
3S9
constiucting, 361, 37S
uispatching tasks to GCD, 372373
enumeiating oLjects in aiiays using, 75
inuepenuent
aLout, 361363
Llock oLjects accessing ueclaieu
piopeities in, 369
inline
aLout, 363365
Llock oLjects accessing ueclaieu
piopeities in, 36S369
invoking, 371372
launching asynchionously on concuiient
gueue, 3S0
passing as paiameteis to OLjective-C
methous, 363
vs. C lunction, 361362
vs. thieaus, 35S
vs. tiauitional lunction pointeis, 35S
Llock opeiations
in Cocoa, 359
peiloim tasks synchionously using, 399
Llue values, 751, 7S5
Bluetooth keyLoaius, keyLoaiu notilications
anu, 196
LoolFoiKey: methou, S3+
Lioaucasting events
allowing oLjects to take action, 9193
Liown values, 751
Buck, Eiik M., Cocoa Design Patteins, +S
Lullei oveillows, 3+
Luilu commanus
in Xcoue loi compiling apps, 910
Bunule Piogiamming Guiue, weLsite loi, xv
Lunules, S+
(see also main Lunules)
Cocoa Touch, S3S+
cieating setting, 659662
loauing uata liom, SS
vs. lolueis, S+
LunuleVithPath: class methou, SS
ButtonItem class, 166
Luttons
aLout, 196
auuing Luttons to usei inteilace, 196202
ienueiing images, 199200
to align at centei ol scieen, 25725S
LuttonTitleAtInuex: methou, 10+
C
C lunction vs. Llock oLjects, 361362
C lunctions
as paiametei ol uispatchalteil lunction,
3S7
uispatching gioup using
uispatchgioupasyncl
lunction, 39339+
uispatching tasks to GCD, 372373
executing synchionously on uispatch
gueue, 379
linuing tmp loluei, 575
loi execution on main gueue, 375376
vs. OLjective-C coue, 361
C methou, invoking, 371372
caches loluei, linuing, 575
cachesDiiectoiy methou, 59+
CalDAV calenuai, 701, 70270+, 712
(see also Google CalDAV calenuai)
Calenuai app, 701, 732
Calenuai uataLase
accessing, 701
allowing useis to euit events in, 73573S
uisplaying piopeities ol event in, 732
calenuais
accessing contents ol, 710713
auuing alaims to, 72772S
auuing events to, 706709
auuing iecuiiing events to, 71S721
letching events in, 712
hanuling event changeu notilications, 729
731
Index | 927
www.it-ebooks.info
iemoving events liom, 71371S
ietiieving attenuees ol events, 722726
ietiieving list ol, 70+706
callIntToStiing methou, 362
callTiimBlock methou, 372
camelCase naming convention
iules loi naming, 20, 21
cameia, 609
(see also Photo LiLiaiy)
(see also viueos)
aLout, 599601
uetecting anu pioLing, 601606
uetecting Flash capaLility, 60+605
uetecting multiple cameias, 60+
taking anu using viueos with, 610613
taking photos with, 606610
cameia ioll loluei, uetecting, 602
cameia ioll loluei, saving images to, 610, 612
cameiaSuppoitsMeuia:souiceType: methou,
60260+, 619
cancel methou, +25
cancelAllLocalNotilications instance methou,
6+0
canEuitViueoAtPath: class methou, 631
caiet () chaiactei, maiking Llock oLject with,
77
cellFoiRowAtInuexPath paiametei, 6S3
centei ol scieen, placing UI component in, 256
25S
Ceitilicate Reguest lile (CSR), 903
CFAiiayGetCount lunction, 5+3
CFAiiayGetValueAtInuex lunction, 5+3
CFAiiayRel aiiay, 5+3
CFAiiayRel Coie Founuation oLject, 5+3
CFRelease Coie Founuation methou, 5+0
CFRelease pioceuuie, calling NULL value,
5+9
CFStiingRel uata type, 60+, 609
CGAllineTiansloimMakeRotation lunction,
+60, 797
CGAllineTiansloimMakeScale lunction, +69,
79+795
CGAllineTiansloimMakeTianslation
lunction, 79079+, 791792
CGColoi class, 75+
CGColoi instance methou, 75+755
CGColoiGetComponents lunction, 75+755
CGColoiGetNumLeiOlComponents lunction,
75+755
CGColoiSpaceCieateDeviceRGB lunction,
7S+, 7S7
CGContextAuuLineToPoint lunction, 765
CGContextAuuPath pioceuuie, 77277+
CGContextDiawLineaiGiauient pioceuuie,
7S7790
CGContextDiawPath pioceuuie, 772
CGContextMoveToPoint lunction, 765
CGContextRotateCTM pioceuuie, 797
CGContextSaveGState pioceuuie, 7S17S3
CGContextScaleCTM pioceuuie, 79+795,
79+795
CGContextSetLineViuth pioceuuie, 766767
CGContextSetShauow pioceuuie, 77S7S3
CGContextSetShauowVithColoi pioceuuie,
779
CGContextTianslateCTM pioceuuie, 792
79+
CGFloat values
holuing lloating-point values using, 70
in aiiay ol coloi components, 7S5
CGGiauientCieateVithColoiComponents
lunction, 7S+790
CGGiauientRelease pioceuuie, 7S+
CGImageRel, 620
CGImageVithOptions: instance methous,
620
CGPathAuuLineToPoint pioceuuie, 772
CGPathAuuRect pioceuuie, 772, 77577S
CGPathCieateMutaLle lunction, 77277+
CGPathMoveToPoint pioceuuie, 772, 77+
CGPathRelease pioceuuie, 772
CGPoint stiuctuie, conveiting touch on scieen
to NSStiing, +6S
CGRect values, conveiting to ielevant
oiientation-awaie cooiuinates, 239
CGRectInteisection lunction, 239
CGRectMake lunction, 75375+
chai ' stiing, as paiametei ol
uispatchgueuecieate lunction,
395
ciicle, scaling shape ol, 79+
class methous
ueclaiing anu implementing, +1
ueteimining availaLility ol, 6669
classes
auuing piopeities to, +S51
cieating custom, 3537
uelining lunctionality loi, 3S+3
928 | Index
www.it-ebooks.info
ueteimining availaLility at iuntime ol, 69
ienaming, 37
vs. oLjects, 1
CLGeocouei class, ++S+50
CLLocationManagei class, +3++37, 6+9
clockwiseRotationStoppeu:linisheu:context:
selectoi, S10
closuies, 35S
(see also Llock oLjects)
ClouuDocument class, S53
ClouuDocumentPiotocol, S56, S63
CMMotionManagei class
uetecting availaLility ol acceleiometei, S12
S1+
uetecting availaLility ol gyioscope, S1+
S16
ietiieving acceleiometei uata, S16S19
ietiieving gyioscope uata, S22S2+
coalesceu notilications, 65S, 732
Cocoa
GCD in, 355
main uispatch gueue anu, 357
piogiamming liamewoiks, 739
types ol opeiations in, 359
Cocoa classes, stoiing inloimation anu, 575
Cocoa Design Patteins (Buck anu Yacktman),
+S
Cocoa Funuamentals Guiue (Apple), 390
Cocoa liLiaiies, uelinition ol oLjects, 1
Cocoa Touch
accessing Lunules with, S+
altei accessoiyView piopeity is set, 292
lonts encapsulateu in UIFont class in, 7+S
GCD in, 355
main uispatch gueue anu, 357
memoiy management on Coie Founuation,
552
piotocols, 66
winuows anu views in apps in, 739
Couing Guiuelines loi Cocoa (Apple), +5
coloi components, 751755, 7S5, 7S6
colois
constiucting, setting, anu using, 751755
uiawing, 7S3790
coloiVithReu:gieen:Llue:alpha: class methou,
752
commitAnimations methou, 79S
compilei, 1
(see also LLVM compilei)
hanuling eiiois in coue, 10
ivais hanuleu Ly, 50
wainings, 329
compiling applications, 710
components, in pickei views, 115
concuiiency
aLout, 355
Llock oLjects
aLout, 357359
accessing vaiiaLles in, 365371
as paiametei ol uispatchaltei lunction,
3S6
as paiametei ol uispatchasync lunction,
37+
as paiametei ol uispatchonce lunction,
3S9
constiucting, 361, 37S
uispatching tasks to GCD, 372373
enumeiating oLjects in aiiays using, 75
inuepenuent, 361363, 369
inline, 363365, 36S369
invoking, 371372
launching asynchionously on concuiient
gueue, 3S0
passing as paiameteis to OLjective-C
methous, 363
vs. C lunction, 361362
vs. thieaus, 35S
vs. tiauitional lunction pointeis, 35S
cieating with thieaus, +1S+23
GCD
aLout, 355357
constiucting uispatch gueues with, 39+
397
uispatching tasks to, 372373
giouping tasks togethei with, 39139+
peiloiming non-UI ielateu tasks
asynchionously with, 3S0
3S5
peiloiming non-UI ielateu tasks
synchionously with, 3773S0
peiloiming task only once with, 3S9
390
peiloiming tasks altei uelay, 3S63S9
peiloiming UI-ielateu tasks with, 373
377
placing synchionous connection in, +76
+7S
woiking with Llock oLjects, 35S
Index | 929
www.it-ebooks.info
tasks
cieating uepenuency in, +10+13
cieating timeis loi, +13+1S
uispatching to GCD, 372373
giouping togethei with GCD, 39139+
in cieating applications, 7
peiloiming altei uelay with GCD, 3S6
3S9
peiloiming only once with GCD, 3S9
390
peiloiming with GCD asynchionous
non-UI ielateu, 3S03S5
peiloiming with GCD synchionous non-
UI ielateu, 3773S0
peiloiming with GCD UI-ielateu, 373
377
iunning with opeiations asynchionous,
+0++10
iunning with opeiations synchionous,
397+0+
synchionous tasks suLmitteu to a seiial
gueue, 395
concuiient uispatch gueues
aLout, 357
asynchionous execution on, 3S03S5
synchionous execution on, 3773S0
ConllictViewContiollei class, S73, S75S77
console scieen in Xcoue, uisplaying, 290
constiaints
conliguiing in Inteilace Builuei Auto
Layout, 273276
uelining hoiizontal anu veitical, 259265
loi placing UI component in centei ol
scieen, 256
iules loi cieating, 25+
UIKit tianslating autoiesizing masks to Auto
Layout, 262
utilizing cioss view, 265272
with Visual Foimat Language, 256
constiaintsVithVisualFoimat:options:metiics
:views: class methou, 256
constiaintVithItem:attiiLute:ielateuBy:toI
tem:attiiLute:multipliei:constant:
class methou, 25+256
constiuctUIComponents methou, 262
contacts
auuing peisons to gioups, 555557
categoiizing into gioups, 552555
cieate new peison, 5+9551
seaiching in auuiess Look loi, 55S562
contacts uataLase, populating on iOS
Simulatoi, 536
containei iuentiliei, Xcoue, S3S
content view, giving maigins to, 29+
contentsFoiType:eiioi: methou, S53, S57
contentsOlAppBunule, methou, 5S5
contentsOlDiiectoiyAtPath:eiioi: instance
methou, 5S15S6
contentsOlDiiectoiyAtURL:incluuing
PiopeitiesFoiKeys:options:eiioi:
methou, 5S25S3
context menus, uisplaying on taLle view cells,
306310
continuous gestuies, +5++55
contiolleiDiuChangeContent: uelegate
methou, 691
contiolleis (view contiolleis)
accessing music liLiaiy methous in, 529
530
alteiing auuio session anu loauing song into
memoiy in, 51751S
as aichitectuial component ol applications,
99
attempting to uisplay image pickei
contiollei as moual, 607
cieating, 1+7
cieating helloVoiluLaLel on, +5S
cieating to uemonstiate uselulness ol letch
iesults contiolleis, 6S+
uelining image view in, 622
uetecting pinch gestuies, +69, +70
uisplaying contents insiue popoveis, 226
229
liiing metauata gueiy when view gets
loaueu, S+5, S50
loi euiting viueos on uevices, 62762S
loi instantiating Auu navigation Lai Lutton,
6S5
implementing taLle view methous in, 2S+
in uetecting long piess gestuies, +63
in uetecting tap gestuies, +66
in MVC uivision ol laLoi, 1+7
initialize Twittei composei contiollei in,
+95
initializing image views, S0+
moving to othei, 155161
placing laLels anu image views, 56+566
piesenting euit event, 73573S
930 | Index
www.it-ebooks.info
piesenting event, 732735
piesenting multiple, 170177
piesenting two siue-Ly-siue, 213219
seaiching loi existing usei uocuments, S60
stait iecoiuings using, 510511
stop iecoiuings using, 512513
takes auvantage ol coalesceu notilications,
65S
to Le in chaige ol conllict in iClouu, S71
conveitIntToStiing: methou, 363
conveitIntToStiing:usingBlockOLject:
methou, 363365
copy/paste options, 306310
Coie Animation lunctionalities, 7+0, 79S
Coie Data
aLout, 663666
Loosting uata access in taLle views, 6S2
692
cieating anu saving uata using, 67267+
cieating mouel with Xcoue, 666669
ueleting uata liom, 6776S0
geneiating class liles loi entities ol, 670
672
implementing ielationships in, 693699
ieauing uata liom, 67+677
soiting uata in, 6S06S1
Coie Founuation
aiiays, 5++, 5+6
memoiy management, 552
oLjects
ARC anu, 57
CFAiiayRel, 5++
ieleience value ol type ABRecoiuRel, 5+9
551
Coie Founuation, GCD in, 355
Coie Giaphics, 7+0
Coie Giaphics liamewoik
contiolling coloi oLjects, 75+
uiawing shauows, 77S7S3
lunctions staiting with CG in, +60
scaling shapes using, 79+
tiansloimations in, 790
Coie Location liamewoik
aLout, +29
geocouing in, ++S+50
hanuling location changes in Lackgiounu,
6+S651
pinpointing location ol uevices, +3++37
Coie Motion liamewoik
acceleiometei
aLout, S11S12
uetecting availaLility ol, S12S1+
ietiieving uata ol, S16S19
auuing to pioject, S11
uetecting shaking ol uevice, S19
gyioscope
aLout, S11
uetecting availaLility ol, S1+S16
ietiieving uata ol, S22S2+
count methou, 7+
countuown timei, using uate pickei as, 125
ciashes
causing iejection ol app, S
CFRelease pioceuuie causing, 5+9
cieateButtons methou, 26S
cieateDiiectoiyAtPath:withInteimeuiateDiiect
oiies:attiiLutes:eiioi: instance
methou, 5S05S1
cieateFileAtPath:contents:attiiLutes: instance
methou, 590
cieateFileIlDoesntExist: methou, 595
cieateGiayViews methou, 26S
cieateNewGioupInAuuiessBook: methou,
555
cieateNewGioupVithName:inAuuiessBook:
methou, 561
cieateNewPeison: methou, 6SS6S9
cioss view constiaints, utilizing, 265272
cioss views, constiaints cieateu Ly, 25+
CSR (Ceitilicate Reguest lile), 903
cuily Liaces ( ), in il-else statement, 29
Cuiient Tiansloimation Matiix (CTM), 792,
79+
cuiient veision ol uocuments, S6S, S76
cuiientElementPointei pointei, 502
cuiientVeisionOlItemAtURL: class methou,
S69
cuiientVeisionOlItemAtURL: methou, S73
D
uataFoiKey: methou, S3+
DataViewContiollei class, 221
uataVith]SONOLject:options:eiioi: methou,
+SS+91
uate anu time, picking, 122125
uateOlType:inURL: methou, 5S6
DBLMAX constant, 635
Index | 931
www.it-ebooks.info
ueclaieu piopeities, Llock oLjects accessing,
363369
uecoupleu coue, 92
uelaultManagei class methou, 573
uelaultStoie class methou, S33
Delegate Class, 221
uelegate oLjects
assigning to instance ol MKMapView class,
+32, ++7
assigning to taLle view, 2S02S3
uelining, 66
ol instance ol CLLocationManagei, +35
+36
uelegating tasks, with piotocols, 6066
uelegation, 212
ueleteOLject: instance methou, 67767S
ueleteOuuNumLeisSection: selectoi, 321
ueleteRowsAtInuexPaths:withRowAnimation:
methou, 296, 317
ueleteSections:withRowAnimation: methou,
322
ueleting
cells anu sections liom taLle views, 317
uata liom Coie Data, 677
liles anu lolueis, 5S6590
taLle view cells enaLling swipe ueletion,
29+296
Deployment SDK/Taiget, 67
uetachNewThieauSelectoi:toTaiget:withOLje
ct: class methou, 635
DetailViewContiollei, 216, 217219
uevices
euiting viueos on, 627631
pinpointing location ol, +3++37
iotation anu movement ol, S11
using GPS seivices, +29
Xcoue uetecting, 131+
uictionaiies
allocating anu using, 77S0
constiucteu using auuioRecoiuingSettings
instance methou, 512
ueseiializing ]SON into aiiays anu, +91
+93
in keyLoaiu notilications, 19+, 23S
keys availaLle to set in, 250
seiializing into ]SON, +SS+91
similaiity to aiiays, 57S579
stoiing anu synchionizing in iClouu, S31
S35
Usei-Inlo Dictionaiy, 91
vs. aiiays, 77
uictionaiyFoiKey: methou, S3+
uictionaiyOlNumLeis piopeity, 31S
DiuAppeai: methou, 3S13S3
uiuFinishPickingMeuiaVithInlo uictionaiy
paiametei, 609
uiuSaveEuiteuViueoToPath paiametei, 631
uigital signatuies
piepaiing Pass Kit passes loi, 901902
signing Pass Kit passes uigitally, 903907
uisciete gestuies, +5++55
uismissMoualViewContiolleiAnimateu:
methou, 627
uispatch uelay, gianulaiity ol, 3S7
uispatch gueue hanule, as paiametei ol
uispatchasync lunction, 37+
uispatch gueue, as paiametei ol
uispatchalteil lunction, 3S7
uispatch gueues
aLout, 355
constiucting with GCD, 39+397
types ol, 357
uispatchaltei lunction, 3S63SS
uispatchalteil lunction, 3S63S9
uispatchasync lunction, 37+377, 3S0, 396
uispatchasyncl lunction, 37+, 375, 3S0, 396
uispatchgetgloLalgueue lunction, 379
uispatchgetmaingueue lunction, 357, 373
377
uispatchgioupasync lunction, 391393
uispatchgioupasyncl lunction, 39339+
uispatchgioupcieate lunction, 39139+,
391
uispatchgioupnotily lunction, 391
uispatchonce lunction, 3S9390
uispatchgueuecieate lunction, 357, 39+
397
uispatchielease lunction, 357, 391
uispatchsync lunction, 3773S0, 3S1, 3S+
3S5
uispatchsync methou
calling on main gueue with, 37+
uispatchsyncl lunction, 379
uispatchtime lunction, 3SS
uisplacement ol views
animating, 79SS06
uisplayAleitView lunction, 377
uisplayMeuiaPickei: selectoi, 527
932 | Index
www.it-ebooks.info
uisplayMeuiaPickeiAnuPlayItem methou,
529530
DistiiLution Methous, Au Hoc, 17
uocuments
cuiient veision ol, S6S
hanuling conllicts in iClouu ol, S6SS7S
managing in iClouu state ol, S65S67
Documents loluei, 571, 57+
saving iesouice into, S39
saving viueo asset to, 62+627
seaiching in usei`s iClouu, S+2, S+5S+7
uocumentState piopeity, S65, S6S
uoesCameiaSuppoitTakingPhotos methou,
607, 611, 615
uoesGioupExistVithGioupName:inAuuiessB
ook: methou, 560
uot notation, auuing piopeities to classes using,
+S51
uoTheConveision methou, 363
uouLle egual sign (==), insiue conuitional
statement, 2S
uouLle guotes (" "), in stiings, 23
uouLle, holuing lloating point values using, 70
uouLleValue methou, 2+, 72
uiagging anu panning gestuies, uetecting, +60
+62
uiagging vs. sciolling, 206
uiawAtPoint: instance methou ol UIImage
class, 75S
uiawAtPoint:withFont: methou, 7+9750
uiawing
giauients, 7S3
images, 756759, 756759
lines, 765770
iectangles, 77577S
shauows, 77S7S3
shapes, 77177+
text, 7+9750, 752
uiawInRect: methou, 75S
uiawRect: methou, 7+7, 7+9750, 775, 7S0
E
EKAlaim class, 72772S
EKCalenuai oLject
aLout, 706
Event Kit liamewoik within, 712
ietiieving events, 710
EKEventEuitViewContiollei, 73573S
EKEventStoie
aLout, 70+706
access uilleient types ol calenuais with,
706709
accessing calenuais using instance ol, 712
auuing alaims to calenuais, 72772S
auuing iecuiiing events to calenuais, 71S
iemoving events liom calenuais, 713
ietiieving attenuees ol events, 722726
ietiieving events, 71S
EKEventStoieChangeuNotilication, 729731
EKEventViewContiollei, 732735
EKPaiticipant, ietiieving attenuees ol events
using, 722726
EKRecuiienceRule, 71S, 721
else clause, ol il-else statement, 27
email, uistiiLuting Pass Kit passes using, 90S
911
encouing paiametei, 575
enciypting liles anu lolueis, 590595
enuBackgiounuTask: instance methou, 635
63S
entitlements, setting up, S26, S31
entity, uelinition ol, 667
enumeiateAssetsUsingBlock: instance methou,
620
enumeiateGioupsVithTypes:usingBlock:lailu
ie Block: instance methou, 620
enumeiateKeysAnuOLjectsUsingBlock:
methou, 77
enumeiateOLjectsUsingBlock: methou,
enumeiating oLjects in aiiays using,
75
enumeiating, liles anu lolueis, 5S15S6
enumeiatoi, getting numLei ol oLjects using,
7+
egual sign (=), setting piopeities using, +9
eiioi paiametei, 576
(see also NSEiioi class)
Event Kit UI liamewoik
aLout, 70170+
calenuais accessiLle Ly, 712
eventEuitViewContiollei:uiuCompleteVithA
ction: methou., 73573S
events
auuing alaims to calenuais, 72772S
auuing to calenuais, 706709
auuing to calenuais iecuiiing, 71S721
allowing useis in Calenuai uataLase to euit,
73573S
Index | 933
www.it-ebooks.info
cieating in Google CalDAV calenuai, 71+
71S
cieating on uilleient calenuais, 726
hanuling event changeu notilications, 729
731
piesenting view contiolleis ol, 732735
iemoving liom calenuais, 71371+, 71S
ietiieving, 710
ietiieving attenuees ol, 722726
eventVithEventStoie: class methou, 706709,
710712
Exchange calenuai, 706, 712
executeFetchReguest:eiioi: instance methou,
677
executingInBackgiounu value, 6+9
expiession Loxing, 71
F
FaceLook, integiation in iOS 6, 152
laces in lamilies ol lonts, 7+S
lamilies ol lonts, 7+S
lamilyNames class methou, 7+S
last enumeiation
aLout, 7+
manual without Llock oLjects, S0
ol mutaLle aiiay, 75
ol oLjects in set, S2S3
using countei vaiiaLle insiue Llock, 676
letch ieguest vs. SELECT statement, 677
letch ieguest, assign moie than one soit
uesciiptoi to one, 6S1
letcheu iesults contiolleis, 6S26S3, 6S9690
letchReguest piopeity, 6S3
lile hanule, 590
lileHanuleFoiReauingAtPath: class methou,
592
lileHanuleFoiUpuatingAtPath: class methou,
592
lileHanuleFoiViitingAtPath: class methou,
592
liles
ueleting, 5S6590
enumeiating, 5S15S6
linuing path ol, 573
saving oLjects to, 59559S
saving to lolueis cieateu on uisk, 5S05S1
seaiching in iClouu loi, S+1S50
secuiing, 590595
SHA1 hash ol lile, 901902
wiiting to anu ieauing liom, 575579
Finuei, auuing liles to lolueis manually using,
S+
liist-class oLjects, Llock oLjects as, 35S
liistOpeiationEntiy: methou, +06
llash capaLility, uetecting, 60+605
llat hieiaichy on uisk, main Lunules having,
S5
lloat vaiiaLle type, 22
lloating point values, 70
lloating point values, in piogiess views, 233
lloatValue methou, 2+, 72
lolueis
cieating on uisk, 5S05S1
ueleting, 5S6590
uetecting cameia ioll, 602
enumeiating, 5S15S6
linuing most uselul path, 573575
ioot lolueis ol applications, 571573
seaiching in iClouu loi, S+1S50
vs. Lunules, S+
lonts
enumeiating anu loauing ol, 7+S
lamilies anu laces ol, 7+S
naming, 7+9
lontVithName:size: class methou, 7+9
looteis, constiucting in taLle view, 297306
loi loops
getting numLei ol oLjects using, 7+
implementing, 3032, 33
loi statement
exit stiategy loi loops, 33
implementing loops with, 3032
lullResolutionImage instance methous, 620
lullScieenImage instance methous, 620
lunction pointeis, tiauitional, vs. Llock oLjects,
35S
lunctions vs. pioceuuies, 3S
lunctions, staiting with CG, +60
G
GCC compilei, ivais hanuleu Ly, 50
GCD (Gianu Cential Dispatch)
aLout, 355357
asynchionously loauing uata ol song into
instance ol NSData using, 507
constiucting uispatch gueues with, 39+
397
uispatching tasks to, 372373
934 | Index
www.it-ebooks.info
giouping tasks togethei with, 39139+
peiloiming non-UI ielateu tasks
asynchionously with, 3S03S5
peiloiming non-UI ielateu tasks
synchionously with, 3773S0
peiloiming task only once with, 3S9390
peiloiming tasks altei uelay, 3S63S9
peiloiming UI-ielateu tasks with, 373377
placing synchionous connection in, +76
+7S
woiking with Llock oLjects, 35S
GCDAppDelegate class, 39339+
geocoueAuuiessStiing:completionHanulei:
methou, ++S+50
geocouing
conveiting longituue anu latituue to
auuiesses, +50+52
linuing liom auuiesses longituue anu
latituue, ++S+50
gestuie iecognizeis
aLout implementing, +53+55
uetecting long piess gestuies, +63+66
uetecting panning anu uiagging gestuies,
+60+62
uetecting pinch gestuies, +6S+70
uetecting iotation gestuies, +57+60
uetecting tap gestuies, +66+70
swipe gestuies, +55+57
GET methou, senuing ieguests ovei HTTP
piotocol, +79+S1
getBytes:liomOllset:length:eiioi: instance
methous, 620
getResouiceValue:loiKey:eiioi: instance
methou, 5S5
gettei methous, +951
gloLal concuiient gueue, uownloauing laige lile
using synchionous connection on,
656657
Google CalDAV calenuai
auuing to pioject, 701702
cieating event in, 71+71S
ietiieving attenuees ol events, 726
setting up, 726
GPS seivices, iOS uevices using, +29
giauients, uiawing, 7S3790
Gianu Cential Dispatch (GCD) Releience
(Apple), 379
giaphic contexts
uisplacing shapes uiawn on, 79079+
scaling shapes uiawn on, 79+795
Giaphic Contexts, iotating shapes uiawn on,
797
giaphics
aLout, 7397+1
constiucting, setting, anu using coloi, 751
755
uisplaying text using lonts in, 7+S
uiawing
giauients, 7S3
lines, 765770
iectangles, 77577S
shauows, 77S7S3
shapes Ly constiucting paths, 77177+
images
constiucting iesizaLle, 75976+
uiawing, 756759
gieen values, 751
gioup entiy
auuing peisons to gioups, 555557
inseiting into auuiess Look, 552555
seaiching, 55S562
gyioscope
aLout, S11
uetecting availaLility ol, S1+S16
ietiieving uata ol, S22S2+
H
H: oiientation speciliei, 259
hanuleDocumentStateChangeu: methou, S67,
S7+S75
hanuleKeyLoaiuVillHiue:methou, 2++2+5
hanuleKeyLoaiuVillShow: methou, 2+22++,
2+62+7, S63S65
hanuleLongPiessGestuies: methou, +65
hanuleMetauataQueiyFinisheu: methou, S+5,
S+SS50, S61S63
hanulePanGestuies: methou, +62
hanuleReliesh: methou, 33333+
hanuleRotations: methou, +57, +59
hanuleSwipes: methou, +56
hanuleTaps: methou, +67
heaueis, constiucting in taLle view, 297306
specilying height ol, 299, 301302
helloVoiluLaLel piopeity, cieating on view
contiollei, +5S
hieiaichical uata, uisplaying in taLle view, 293
29+
HTTP
Index | 935
www.it-ebooks.info
aujusting URL settings anu heaueis, +7S
senuing GET ieguest ovei piotocol ol, +79
+S1
HTTP DELETE methou, senuing ieguests with
NSURLConnection, +S++S5
HTTP Post methou, senuing ieguest with
NSURLConnection, +S1+S3
HTTP PUT methou, senuing ieguests with
NSURLConnection, +S6+S7
I
IB (Inteilace Builuei)
conliguiing Auto Layout constiaints in,
273276
liles extension loi, 1+7
instantiating TaLle Views using, 2792S0
segue oLjects in, 351
setting view contiollei`s view class using,
7+57+7
unueistanuing, 67
iBooks, applications woiking like, 219
iClouu
aLout, S25
hanuling conllicts in uocuments in, S6S
S7S
managing state ol uocuments in, S65S67
seaiching loi liles anu lolueis in, S+1S50
setting up pioject, S32S33
setting up youi app loi, S26S31
stoiing anu synchionizing uictionaiies in,
S31S35
stoiing liles in, S++S+5
stoiing unnecessaiy liles in useis` iClouu
stoiage, S++
stoiing usei uocuments in, S51S65
IDeviceBatteiyStateDiuChangeNotilication,
657
il anu only il, saving aiiay ol ianuom numLeis
to, 3S+
il statement, using in OLjective-C, 2729
il-else statement, 27
image liles
accessing at iuntime, SS90
loauing into memoiy, S7SS
image pickei, allowing usei to take photos
using, 607
imageNameu: class methou, 756
imagePickeiContiollei:uiu
FinishPickingMeuiaVithInlo:
uelegate methou, 612
imagePickeiContiollei:uiuFinishPickingMeuia
VithInlo: uelegate methou, 609,
629630
imagePickeiContiollei:uiuFinishPickingMeuia
VithInlo: methou, 60S
imagePickeiContiolleiDiuCancel: methou,
60S609
images, 609
(see also Photo LiLiaiy)
applying new colois to segmenteu contiol
using, 1391+6
Luttons ienueiing, 199200
clipping, 203
constiucting iesizaLle, 75976+
uisplaying, 200203
uisplaying on Navigation Bais, 162163
uiawing images, 756759
getting uata peitaining to PNG, 563
in Pass Kit passes, S99900
on sliueis, 132
ieplacing uelault image in Map Kit
liamewoik, ++S
ietiieving anu setting peison`s, 56256S
ietiieving ]PEG image uata, 563
values loi taking photo with cameia in,
609
imageViewDiuStop:linisheu:context: uelegate
methou, S01
imageVithCGImage: class methou, 620
imageVithData: class methou, 756
IMainStoiyLoaiuFile~ipau key, cieating, 35+
immutaLle aiiays vs. mutaLle aiiays, 73
immutaLle sets, S1
immutaLle URL ieguests, +7S
inuentation, applying to taLle view cells, 29+
inuepenuent Llock oLjects
Llock oLjects accessing ueclaieu piopeities
in, 369
inuexPathFoiRow:inSection: methou, 317,
6S3
inuexSetVithInuexesInRange: methou, 317
inDomains paiametei, 57+
inlinite-loops, 30
init methou
calling to cieate new instance ol class, 333
in NSOLject class, +6+S
936 | Index
www.it-ebooks.info
initializei methou, ol type
CLLocationCooiuinate2D, +37
initRecuiienceVithFieguency:inteival:enu:
methou, 71S721
initVithBaiButtonSystemItem:taiget:action:
initializei methou, 166
initVithBytes:length: initialization methou,
627
initVithContentsOlFile: instance methou,
756
initVithCustomView: methou, 16S
initVithData: instance methou, 756
initVithData:encouing: initializei methou,
+S9
initVithData:eiioi: methou, 506
initVithFileURL: methou, S53
initVithNiLName:Lunule: methou, 150
initVithStiing: methou, 250
initVithURL:settings:eiioi: instance methou,
509510
inline Llock oLjects
aLout, 363365
inline Llock oLjects, Llock oLjects accessing
ueclaieu piopeities in, 36S369
inseitNewOLjectFoiEntityFoiName:
inManageuOLjectContext: class
methou, 67267+
instance methous, ueteimining availaLility ol,
6669
instance vaiiaLle, 50
instancesResponuToSelectoi: class methou,
67
integei vaiiaLles, negative numLeis anu, 21
integeiValue methou, 2+, 72
integeiValue vaiiaLle, pielix with Llock
stoiage type, 370371
integial values, using in oLjects, 7072
Inteilace Builuei (IB)
conliguiing Auto Layout constiaints in,
273276
liles extension loi, 1+7
instantiating TaLle Views using, 2792S0
segue oLjects in, 351
setting view contiollei`s view class using,
7+57+7
unueistanuing, 67
Inteinet, applications connecting to, +71
invaliuate instance methou, +1+, +25
invaliuate methou, +1S
inveise many-to-many ielationship, in Coie
Data, 693
inveise one-to-many ielationship, in Coie Data,
693, 69+697
invocation opeiations, in Cocoa, 359
iOS Application Piogiamming Guiue, weLsite
loi, xv
iOS Devices
iunning apps on, 121+
suppoiting iunning ol oluei iOS veisions
anu, 70
iOS uevices
iunning apps on, 12
using GPS seivices, +29
iOS Human Inteilace Guiuelines (Apple), 260
iOS opeiating system, 571
iOS Piovisioning Poital, SS2, 903
iOS Simulatoi
Lackgiounu location piocessing using, 651
hiuing status Lai, 773
populating contacts uataLase on, 536
iunning applications in, 2
iunning apps on, 11
simulating limiteu veisions ol apps, 12
simulating two touches at same time, +6S
suppoit loi Cameia inteilace on, 599
iPau
aLout cameia on, 599
aLout touch piogiamming, 1
cieating IMainStoiyLoaiuFile~ipau key loi,
35+
uisplaying popoveis in, 223232
giving piogiammeis contiol ovei how
movies aie playeu, 520
keyLoaiu uisplay, 235237
moual scieens on, 337
navigation contiollei in, 155
piesenting two siue-Ly-siue view contiolleis
in, 213219
piesenting UIActivityViewContiollei class
in, 151
usei splitting keyLoaiu on, 235
iPau 2, as multicoie uevice, 355
iPau Human Inteilace Guiuelines, weLsite loi,
xv
iPhone, 229232
aLout cameia on, 599
aLout touch piogiamming, 1
cieating UIMainStoiyLoaiu File loi, 35+
Index | 937
www.it-ebooks.info
keyLoaiu uisplay, 235
navigation contiollei in, 155
piesenting UIActivityViewContiollei class
in, 151
ieliesh contiol in applications ol, 332
iPhone Conliguiation Utility, 19
iPhone Human Inteilace Guiuelines, weLsite
loi, xv
iPhone Simulatoi
eiioi in testing app loi stoiing viueos in
Photo LiLiaiy, 617
memoiy leaks anu, 50S
MPMoviePlayeiContiollei class on, 522
playing auuio in Lackgiounu on, 6+S
simulating phone calls with, 50S
simulating iotation gestuie on, +60
iPou touch
aLout cameia on, 599
navigation contiollei in, 155
iPou, aLout touch piogiamming, 1
IPiogiessViewStyle values, 232
isAcceleiometeiAvailaLle methou, S12S1+
isCameiaAvailaLle methou, 607, 611, 615
isCameiaDeviceAvailaLle: class methou, 60+
isDeleteu methou, 67S6S0
isEgual instance methou, 2S
isFlashAvailaLleFoiCameiaDevice: class
methou, 60+
isGyioAvailaLle methou, S1+S16
isMultitaskingSuppoiteu instance methou,
63+
isPassLiLiaiyAvailaLle class methou, 919
isSouiceTypeAvailaLle: class methou, 601
606
isURLDiiectoiy: methou, 5S5
isURLReauaLle: methou, 5S5
iTunes Conliguiation Utility, 19
ivais, compileis hanuling ol, 50
J
]PEG image uata, ietiieving, 563
]SON
aLout, +71, S91
ueseiializing into aiiays anu uictionaiies,
+91+93
liles iepiesenting passes loi Pass Kit, S91
S9S
manilest liles in, 901902
seiializing aiiays anu uictionaiies into, +SS
+91
]SONOLjectVithData:options:eiioi: methou,
+91
K
kCGPathFill methou, 772
kCGPathFillStioke methou, 772
kCGPathStioke methou, 772
Key-value OLseiving (KVO) compliant,
opeiation oLjects as, 360
Key: methou, S0
keyLoaiu liames, oiientation ol uevice anu,
239
keyLoaiu notilication hanuleis, 2+62+7, S63
S65
keyLoaiu notilications
uictionaiy in, 19+, 23S
il keyLoaiu not on scieen continuing
listening loi, 2+2
listening anu ieacting to, 23+2+7
listening to anu stopping, 196
keyLoaiu shoitcut, iunning app in Simulatoi,
2
Keychain Access, expoiting Pass Kit ceitilicate
liom, 903905
Keychain uataLase, Lacking up, SS5
keyEnumeiatoi methou, ol mutaLle uictionaiy,
S0
kUTTypeImage meuia type, loi taking photo
with cameia in, 609, 61S619
kUTTypeMovie meuia type, loi taking movie/
viueo with cameia in, 609, 610612,
61S619
L
laLels
aLout, 177
cieating, 1771S1
customizing appeaiance ol, 1S11S3
latituue anu longituue
conveiting to auuiesses, +50+52
linuing liom auuiesses, ++S+50
LiLiaiy/ loluei, 571
LiLiaiy/Application Suppoit/ loluei, 571
LiLiaiy/Caches/ loluei, 571
LiLiaiy/Pieleiences/ loluei, 571
lines, uiawing, 765770
938 | Index
www.it-ebooks.info
list ol values, selecting liom, 115120
LLVM compilei, 1
(see also compilei)
ARC in, 1
compiling Coie Founuation coue with, 552
geneiating settei anu gettei methous, +9
ivais hanuleu Ly, 50
LLVM compliei
using ARC with, 52
loauData:MIMEType:textEncouingName:Las
eURL: methou, 209
loauFiomContents:olType:eiioi: methou, S53,
S57
loauHTMLStiing:LaseURL: methou, 209
loauReguest: methou, 209
local notilication aleit view, 6+0
localizeuValue FoiFieluKey: methou, 91S921
LocalNotilication: instance methou, 63S
location ol uevice, pinpointing, +3++37
locationInView: methou, +62, +67
locationManagei:uiuUpuateToLocation:liom
Location: methou, 651
locationOlTouch:inView: methou, +67
locations
conveiting longituue anu latituue to
auuiesses, +50+52
linuing longituue anu latituue liom
auuiesses, ++S+50
hanuling changes in Lackgiounu ol, 6+S
651
locationSeivicesEnaLleu class methou, +37
logical points, 7+0, 766
(see also points)
login anu passwoiu style, in aleit view, 106
long piess gestuies, uetecting, +63+66
longituue anu latituue
conveiting to auuiesses, +50+52
linuing liom auuiesses, ++S+50
longPiess GestuieRecognizei, +63
loops
autoielease pool insiue, 33
implementing with loi statement, 3032,
33
implementing with while statement, 323+
iun loops, 360
M
Mac OS X opeiating system, 571
main Lunules, S+
(see also Lunules)
aLout, S+
having llat hieiaichy on uisk, S5
loauing uata liom, S+SS
naming iesouices insiue, S5
main uispatch gueue
aLout, 357
uispatching tasks to, 37+
tasks suLmitteu to GCD anu, 37+
main thieau
opeiations Llocking, +00
synchionous connections anu, +72, +75
when app is sent to Lackgiounu, 635
mainBunule class methou, S+, S5, 506
manageu oLject context
uelinition ol, 665666
inseiting unknown entity into, 67+
manageu oLject mouel, uelinition ol, 665
manageu oLject, uelinition ol, 666
manual ieleience counting, moving to ARC
liom, 5257
many-to-many ielationship, 699
Map Kit liamewoik
aLout, +29
ieplacing uelault image in, ++S
map view
cieating, +30+32
uisplaying custom pins on, ++6++S
uisplaying pins on, +37+39
uisplaying pins with uilleient colois on,
+39++5
hanuling events ol, +32+3+
mapView:iegionDiuChangeAnimateu:
methou, +3+
mapView:viewFoiAnnotation: methou, +3+,
+39, ++0++1
mapViewVillStaitLoauingMap: methou, +3+
mapViewVillStaitLocatingUsei: methou, +3+
maigins, giving to content view, 29+
maishalling, 57S, 596
maximumNumLeiOlTouches piopeity, +62
Meuia Playei liamewoik
accessing music liLiaiy, 526533
captuiing thumLnails liom viueo liles, 523
526
playing auuio anu viueo liles, 519523
Meuia Playei liamewoik allows, auuing to
pioject, 505
meuiaItemCollection paiametei, 52S
Index | 939
www.it-ebooks.info
meuiaPickei:uiuPickMeuiaItems message,
530531
meuiaPickei:uiuPickMeuiaItems: uelegate
message, 52S
meuiaPickei:meuiaPickeiDiuCancel message,
530531
meuiaPickeiDiuCancel: uelegate message, 533
memoiy leaks, iPhone Simulatoi anu, 50S
Memoiy Management Piogiamming Guiue loi
Coie Founuation (Apple), 552
metauata gueiy, setting up, S+2
methou oveiloauing, +3
methous
choosing names loi, +5
cieating, 39
ueclaiing anu implementing class methous,
+1
uelining with same name, +3+6
things to look out loi in cieating anu
woiking with, +5
with exteinal names loi paiameteis ol, +1
minimumNumLeiOlTouches piopeity, +62
minimumPiessDuiation piopeity, +6++65
MKAnnotation piotocol, +37
MKAnnotationView class, ++0++1
MKMap ViewDelegate piotocol, ++7
MKMapView class, +30+32, ++6++S
MKMapViewDelegate piotocol, +3+
MKPinAnnotationView class, +39++5
MoLileCoieSeivices liamewoik
auuing to pioject, 599600
values loi taking photo oi movie with
cameia in, 609
mouel
as aichitectuial component ol applications,
99
in MVC uivision ol laLoi, 1+7
using Coie Data in MVC in cieating
application, 663
Mouel-View-Contiollei (MVC)
aLout, 99
cieate mouel ol application using Coie Data
in, 663
uivision ol laLoi, 1+7
Mouel-View-Contiollei (MVC) soltwaie
aichitectuie
cieate mouel ol application using Coie Data
in, 663
MouelContiollei class, 221
motionEnueu:withEvent: methou, S19
moveRowAtInuexPath:toInuexPath: methou,
310
moveSection1ToSection3 methou, 315
moveSection:toSection: methou, 310
movie playei, uisplay a lull-scieen, 519
movies
euiting on uevices, 627631
in lanuscape moue only with
UIViueoEuitoiContiollei, 62S
ietiieving liom Photo LiLiaiy, 61S619,
620627
stoiing in Photo LiLiaiy, 61661S
taking anu using with cameia, 610613
values in NSStiing loi taking with cameia,
609
MPMeuiaItem class, 52S
MPMeuiaPickeiContiollei class, 526533
MPMoviePlayeiContiollei class, 519526
MPMoviePlayeiPlayLackDiuFinishNotilicatio
n, 522
MPMoviePlayeiThumLnail
ImageReguestDiuFinishNotilication
notilication message, 523525
MPMoviePlayeiViewContiollei class, 519
MPMovieTimeOptionNeaiestKeyFiame value,
526
multicoie uevices, wiiting apps loi, 355
multiple inheiitances, in OLjective-C, 1
multitasking
aLout, 633
completing a long-iunning task in
Lackgiounu, 63563S
uetecting availaLility ol, 633
hanuling location changes in Lackgiounu,
6+S651
hanuling netwoik connections in
Lackgiounu, 65+657
hanuling notilications ueliveieu to waking
app, 65765S
opting out ol, 662
playing auuio in Lackgiounu, 6+66+S
ieceiving local notilications in Lackgiounu,
63S6+5
iesponuing to changes in app settings, 659
662
saving anu loauing state ol apps, 65165+
switching applications to uelete events, 731
multivalues, in auuiess Look, 5+5
940 | Index
www.it-ebooks.info
music liLiaiy, accessing, 526533
mutaLle aiiays
aLout, 6669
last enumeiation ol, 7+
vs. immutaLle aiiays, 73
mutaLle sets, S1S2
mutaLle URL ieguests, +7S
MVC (Mouel-View-Contiollei)
aLout, 99
uivision ol laLoi, 1+7
MyAnnotation class, +3S
N
Name.app loluei, 571
naming
lonts, 7+9
methous, +5
notilications, 91
iesouices insiue main Lunule, S5
vaiiaLles, 20
Navigation Bais
auuing Luttons to, 163
uisplaying images on, 162163
navigation contiolleis
cieating, 15515S
manipulating Aiiayol View Contiolleis,
161162
vs. UIViewContiollei class, 171
netwoik connections, hanuling in Lackgiounu,
65+657
niL liles, 6
nil
/NULL/zeio in loops, 32
cieating gioup with name egual to, 560
nonatomic piopeity, +9
notilication centeis, as uispatch centials, 91
notilications
Lackgiounu execution ol applications anu,
633
coalesceu, 65S
hanuling ueliveieu to waking app, 65765S
hanuling event changeu, 729731
il keyLoaiu not on scieen continuing
listening loi, 2+2
implementing uecoupleu coue using, 92
listening anu ieacting to keyLoaiu, 23+
2+7
listening loi, 9+97
multimeuia opeiations uepenuing on, 520,
522
naming, 91
senuing, 91
sullixes loi name ol, 92
notilicationVith Name:oLject:useiInlo: class
methou, 9293
NSAiiay class
aLout, 6769
in geocouing, ++9
in ieveise geocouing, +50+52
in stoiing veisions ol uocuments, S73
saving anu loauing methous loi, 57S579
stoiing lixeu oLjects into aiiays, 72
Toll-Fiee Biiuging to, 5++
vs. NSMutaLleAiiay, 73
NSAiiay uata type, 22, 6S2
NSAttiiLuteuStiing, 2+S
NSBunule class
accessing Lunule using, SS
output il iesouice is not lounu in taiget
Lunule, S7
ietiieving inloimation liom application
conliguiation, 506
ietiieving main Lunule using, S5
using il not senuing oLject loi notilication,
93
NSCaseInsensitiveSeaich value, 26
NSClassFiomStiing lunction, 69
NSCouei class, 597
NSCouing piotocol, 59559S
NSCompaiisonResult uata type, 77
NSCuiientLocaleDiuChangeNotilication, 657
NSData class
Cocoa classes anu, 575
in ietiieving viueos liom Photo LiLiaiy,
627
loauing uata into instance ol, 500, 506507
passing iesouice path to, S5
saving anu loauing methous loi, 579
using uata in initialization piocess ol auuio
playei, 6+66+S
NSData uata type, +S9, 756, S57
NSDate oLject, loi auuing iecuiiing events to
calenuais, 71S
NSDictionaiy class, 77, 57S579
NSEntityDesciiption class, 67267+, 677
NSEiioi class, ++9, +50+52, 576
Index | 941
www.it-ebooks.info
NSEiioi paiametei, in wiiting URL to Photo
LiLiaiy, 617
NSet class, S1
NSFetcheuResultsContiollei class, 6S26S3
NSFetchReguest, 67+677, 6S1
NSFileHanule class, 590595, 627
NSFileManagei class
cieating lolueis, 5S05S1
ueleting liles anu lolueis, 5S6
enumeiating liles anu lolueis, 5S15S6
linuing path ol most uselul liles, 573575
manually access main Lunule using, S5
secuiing liles anu lolueis, 590
value loi local auuiess loi iClouu stoiage,
S36S3S, S5S
NSFilePiotectionCompleteUnlessOpen
piotection, 592
NSFilePiotectionKey, 590
NSFileVeision class, S6S, S73, S75S7S
NSInuexPath class, 317, 6S3
NSInuexSet class, 317
NSIntegei class, 70
NSIntegei uata type, 22
NSInteinalInconsistencyException, 67267+
NS]SONReauingAllowFiagments, +93
NS]SONReauingMutaLleContaineis, +93
NS]SONReauingMutaLleLeaves, +93
NS]SONSeiialization class, 70, +71, +SS, +91
NSKeyeuAichivei class, 59559S
NSKeyeuUnaichivei class, 59559S
NSLayoutConstiaint class, 25+, 256
NSLog methous, +52
NSManageuOLjectContext class, 67767S
NSMeta
uataQueiyDiuFinishGatheiingNotili
cation, S61S63
NSMetauataQueiy class, S+1S+5, S52, S59
S63
NSMetauataQueiyDiuFinishGatheiingNotilic
ation, S+2
NSMetauataQueiyULiguitousDataScope, S+2
NSMetauataQueiyULiguitousDocuments
Scope, S+2
NSMutaLleAiiay class
aLout, 6769
in ueleting taLle view sections liom taLle
views, 31S
methous ol, 75
soiting a mutaLle aiiay, 366
stoiing lixeu oLjects into aiiays, 72
vs. NSAiiay, 73
NSMutaLleAttiiLuteuStiing, 2+S
NSMutaLleAttiiLuteuStiing class, 250
NSMutaLleDictionaiy class, 77
NSMutaLleSet class, S1S2
NSMutaLleStiing class, 23
NSMutaLleURLReguest class
mouilying URL ieguest with, +7S
placing URL in instance ol, +72
NSNotilicationCentei class
listening loi notilications liom, 9+97
senuing notilications with, 9193
NSNumLei class, 7072, 31S
NSNumLei class methou, S02
NSOLject class, 2S, 3S6
as OLjective-C ioot class, 1
init methou in, +S
NSOpeiation class, +00, +0+, +06+07
NSOiueieuAscenuing uata type, 77
NSOiueieuDescenuing uata type, 77
NSOiueieuSame uata type, 77
NSPieuicate class, 712, S+3
NSRange stiuctuie, 25
NSSet class, 22, 693
NSSoitDesciiptoi, 6S1
NSStiing class
Cocoa classes anu, 575
ueteimining iepiesentation ol local URL to
iecoiuing stoiage, 511
uisplaying pins on map view, +37
uiawing text using, 7+9750, 752
placing stiing insiue instance ol, 2325
piinting stiing to console using
initVithData:encouing:
initializei, +S9
ieauing stiing Lack into memoiy, 576577
saving anu loauing methous loi, 57S579
values loi taking photo oi movie with
cameia, 609
NSStiing CompaieOptions, options paiametei
type, 25
NSStiing uata type, 22, +6S
NSStiingFiomCGPoint methou, +6S
NSTaLleView class, 3S3
NSTempoiaiyDiiectoiy() lunction, 575
NSThieau class, 377, 635
NSTimei class methou, +1++1S
NSULiguitousKeyValueStoie class
942 | Index
www.it-ebooks.info
cieating anu managing lolueis loi apps in,
S35S+1
synchionize methou, S33
using with iClouu, S3+S35
vs. NSUseiDelaults class, S32
NSUIntegei class, 70
NSUIntegei uata type, 22
NSURL class
getting value ol keys that aie gueiieu liom
lile, 5S5
in viueo Leing shot Ly usei, 610
pointing to iesouices, 577
NSURL paiametei, in wiiting URL to Photo
LiLiaiy, 617
NSURLConnection
aLout, +71
allowing app to woik in Lackgiounu, 65+
uownloauing asynchionously with, +71
+7+
uownloauing synchionously with, +75+7S
senuing HTTP DELETE ieguests with, +S+
+S5
senuing HTTP GET ieguests with, +79
+S1
senuing HTTP post ieguests with, +S1
+S3
senuing HTTP PUT ieguests with, +S6
+S7
seting timeout on URL ieguest passeu to,
+7++75
NSUseiDelaults class vs.
NSULiguitousKeyValueStoie class,
S32
NSUseiDelaultsDiuChangeNotilication, 657,
659662
NSXMLPaisei class
aLout, +71
paising XML with, +9S50+
NSXMLPaiseiDelegate piotocol, 500
NULL
/zeio/nil in loops, 32
cieating gioup with name egual to, 560
passing to pioceuuies loi uiawing shapes
anu lines, 77+
numLeiOlComponentsInPickeiView: methou,
11S
numLeiOlSectionsInTaLleView: methou, 2S+,
329
numLeiOlTapsReguiieu piopeity, +6++65,
+67
numLeiOlTouchesReguiieu piopeity, +6+
+65, +67
numLeis
conveiting to stiings, 72
encapsulating in oLjects, 7072
saving to il anu only il aiiay ol ianuom,
3S+
numLeiVithDouLle: methou, 71
numLeiVithFloat: methou, 71
numLeiVithIntegei: methou, 71
numLeiVithUnsigneuIntegei: methou, 71
O
oLject-oiienteu piogiamming language, classes
in, 1
oLjectAtInuexPath: instance methou, 6S3
OLjective-C coue
Llock oLjects in, 357
classes in, 37
cieating methous, 39
ueclaiing vaiiaLles in, 2022
loimatting stiings with system-inuepenuent
loimat specilieis, 362
lunctions vs. pioceuuies in, 3S
multiple inheiitances in, 1
vs. C lunction, 361
woiking with stiings in, 2326
OLjective-C methous
accessing vaiiaLles in Llock oLjects vs., 365
passing Llock oLjects as paiameteis to, 363
OLjective-C iuntime, ivais hanuleu Ly, 50
oLjects
allocating anu initializing, +6+S
allowing to take action liom Lioaucasteu
events, 91, 9+95
compaiison methous ol, 29
uelining uelegate, 66
memoiy allocateu loi, 53
stoiing into aiiays lixeu, 73
stoiing key-value uata in, 77
stoiing seiies ol, 72
using sets loi stoiing aiiay ol, S0
vs. classes, 1
On/Oll contiol, liom UISwitch class, 10S
one-to-one ielationship, in Coie Data, 693
openssl, using to sign passes, 903, 905907
openVithCompletionHanulei: methou, S69
Index | 943
www.it-ebooks.info
opeiation gueues
types ol, 359
woiking with, 359360
opeiations
cieating uepenuency Letween, +10+13
iunning asynchionous tasks with, +0++10
iunning synchionous tasks with, +00+0+
woiking with, 359360
OR opeianu, Litwise, +57
oiigin point ol scieen, 7+1
otheiVeisionsOlItemAtURL: methou, S6S,
S73, S7+, S7S
out paiametei, S39
outsiueVaiiaLle vaiiaLle, pielix with Llock
stoiage type, 366367
P
page view contiolleis, cieating, 219
pageViewContiollei: methou, 221
paging, enaLling, 219222
panning anu uiagging gestuies, uetecting, +60
+62
paiaContext paiametei, 373
paisei DiuStaitDocument: methou, 502
paisei:uiuEnuElement:namespaceURI:gualilie
u Name: methou, 503
paisei:uiuEnuElement:namespaceURI:gualilie
uName: methou, 501
paisei:uiuStaitElement:namespaceURI:gualili
eu Name:attiiLutes: methou, 502
paisei:uiuStaitElement:namespaceURI:gualili
euName:attiiLutes: methou, 501
paisei:lounuChaiacteis: methou, 501, 503
paiseiDiuEnuDocument: methou, 500, 503
paiseiDiuStaitDocument: methou, 500
Pass Kit
aLout, S79SS1
cieating ceitilicates, SS2S90
cieating pass liles, S90S9S
uistiiLuting passes
using email, 90S911
using weL seivices, 911913
enaLling apps to access passes on uevices,
913917
passes vs. ceitilicates, 903
piepaiing passes loi uigital signatuie, 901
902
pioviuing icons anu images loi passes, S99
900
saving ceitilicates, 905
signing passes uigitally, 903907
PassLook liamewoik
aLout, S79
using, 917
PassLook liLiaiy, accessing, 919
PassLook, inteiacting piogiammatically with,
917921
passTypeIuentiliei keys, S95
passVithPassTypeIuentiliei:seiialNumLei:
methou, 91S921
paste/copy options, 306310
path ol lolueis anu liles, linuing most uselul,
573
pathFoiResouice:olType: methou, S7, SS
paths
aLout, 771
uiawing shapes Ly constiucting, 77177+
pathsFoiResouicesOlType:inDiiectoiy:
methou, 90
peiloimAuuVithAleitView: methou, 230
peiloimAuuVithPopovei: methou, 230
Peiloimance Tuning (iOS Releience LiLiaiy),
+00
peiloimExpanu: methou, 291293
peiloimSelectoi:withOLject:alteiDelay:
methou, 160, 3S6
peiloimSelectoiInBackgiounu:withOLject:
methou, +2+
peimissions, asking to access auuiess Look
uataLase, 5375+0
peisistent stoie cooiuinatoi, uelinition ol, 665
Peison class, 596
PeisonListViewContiollei, 6S+6S5, 691692
phone calls, hanuling inteiiuptions while
playing auuio liles uuiing, 50S
Photo LiLiaiy
aLout, 599601
uetecting, 602
ietiieving assets liom, 620627
ietiieving photos anu viueos liom, 61S
619
stoiing photos in, 613616
stoiing viueos in, 61661S
photos, taking with cameia, 606610
pickei views
uate anu time, 122125
iange, 126129
value, 115120
944 | Index
www.it-ebooks.info
pickeiView:numLeiOlRowsInComponent:
methou, 11S
pinch gestuies, uetecting, +6S+70
pipe (') chaiactei, using in constiucting swipe
gestuie, +57
pixels, unueistanuing points anu, 7+0
PKPass class, 917921
PKPassLiLiaiy class, 91S921
placeholueis, uisplaying, 190
placemaiks aiiays, +50+52
plain opeiations
in Cocoa, 359
iunning asynchionously, +07
iunning synchionously, 399
playing auuio
liles, 506507
hanuling inteiiuptions while, 50750S
ovei othei active sounus, 516519
playing viueo liles, 519523
PMeuiaPickeiContiolleiDelegate piotocol,
526533, 527
PNG image, getting uata peitaining to, 563
points
loiming shapes using, 771
logical, 766
scieen`s oiigin, 7+1
unueistanuing pixels anu, 7+0
popoveis
uisplaying in iPau, 223232
setting ieleience to itsell in content view
contiollei, 230
poital, iemoving uevices liom, 17
postNotilicationName:oLject: instance
methou, 93
postNotilicationName:oLject:useiInlo:
methou, 91
pieuicate, aLout, 712
pieuicateFoiEventsVithStaitDate:enuDate:ca
lenuais: instance methou, 712
pieuicateVithFoimat: methou, S+3
piepaieFoiSegue:senuei: methou, 350
piesentMoualViewContiollei:animateu:
instance methou, 73573S
piesentMoualViewContiollei:animateu:
methou, 627
piesentMoviePlayeiViewContiolleiAnimateu:
instance methou, 519
pieviousViewContiolleis: methou, 221
piimaiy colois, loauing, 752
pioceuuies vs. lunctions, 3S
piogiess Lai (piogiess view), uisplaying, 232
23+
piopeities, aLout, +9
piopeity keywoiu, +S
piotocols
aLout, 60
Cocoa Touch piotocols, 66
uelegating tasks with, 6066
piovision pioliles, cieating Au Hoc, 161S
Piovisioning Poital, SS2, 903
piovisioning piolile, installing, 916
Q
Quaitz 2D, 7+0
R
iauial giauients, 7S+
iange pickeis, implementing, 126129
ieauDataOlLength: methou, 592, 595
ieauing liom anu wiiting to liles, 575579
iecoiu instance methou, 516
iecoiuing auuio
hanuling inteiiuptions while, 515
invoking iecoiu instance methou altei
inteiiuption, 516
to iOS uevice, 50S51+
iectangles
auuing shauows to, 77S7S3
applying tiansloimations to, 79279+
uiawing, 77577S
uiawing images in, 75S759
uiawing text in, 753
iotating, 797
iecuiiing events, auuing to calenuais, 71S
iecuiiingRule piopeity, 71S
ieu values, 751, 7S5
Relactoi, selecting, 37
ieliesh contiols, uisplaying loi taLle views,
332335
iejection ol apps
ciashes causing, S
ciashes causing, aleit views without
Luttons, 102
ieloauImageView methou, 392393
ieloauSciollView methou, 392393
ieloauTaLleView methou, 392393
Index | 945
www.it-ebooks.info
iemoveEvent:span:commit:eiioi: instance
methou, 713, 71S
iemoveGestuieRecognizei: methou, +5+
iemoveItemAtPath:eiioi: methou, 5S6
iemoveItemAtURL:eiioi: methou, 5S6
iemoveOLject: methou, 75, S2
iemoveOLseivei:name:oLject: instance
methou, 9+, 97
iemoveOtheiVeisionsOlItemAtURL:eiioi:
methou, S69
ienaming, classes, 37
ieguestThumLnailImagesAtTimes:timeOption
: methou, 523526
ieguestVithURL:cachePolicy:timeoutInteival:
class methou, +7+
iesizaLle images, constiucting, 75976+
iesizaLleImageVithCapInsets: instance
methou, 75976+
ieveise DNS loimat, loi iuentilieis, 395
ieveise uomain-style ol company iuentiliei,
S32
ieveise geocouing, ++S, +50+52
ieveiseGeocoueLocation:completionHanulei:
methou, +50
RGB coloi, 7S5
ioot lolueis ol applications, 571573
iootElement piopeity, 50+
iootElementpointei, 502
RootViewContiollei, 216
RootViewContiollei class, 221
iootViewContiollei piopeity, 35+
iotation gestuies, uetecting, +57+60
iotation tiansloimations, 790, 797, S0SS10
iotationAngleInRauians piopeity, +5S+59
iotationGestuieRecognizei piopeity, +5S
iounueuValuesInRect: methou, 113
iun loops, 360
S
Salaii Liowseis, using weL views, 209
sanuLox, 571
saveEvent:span:eiioi: instance methou, 71S
scale piopeity, +69
scaling tiansloimations, 790, 79+795, S07
S0S
scaling views, animating anu, S07S0S
scheuule LocalNotilication: instance methou,
63S6+5
scheuuleuTimeiVithTimeInteival paiametei,
+1+
scheuuleuTimeiVithTimeInteival:invocation:
iepeats: class methou, +1+
Scheme LieauciumL Lutton, 1112
scopeTest methou, 370371
scieen
uiawing text on, 7+9750
oiigin point ol, 7+1
Uppei Lelt Oiigin ol, 7+1
sciollaLle content, cieating, 20+20S
sciolling view vs. taLle view, 279
sciolling vs. uiagging, 206
sciollViewDiuEnuDeceleiating: methou, 205
sciollViewDiuEnuDiagging:willDeceleiate:
methou, 205
sciollViewDiuScioll: methou, 205
sciollViewVillBeginDeceleiating: methou,
205
seconuOpeiationEntiy: methou, +06
sectionNameKeyPath paiametei, 6S2
sections piopeity, 6S2
secuie text entiy, in aleit view, 106
secuiity, enciypting liles anu lolueis, 590595
segmenteu contiols
customizing, 1391+6
giouping compact options with, 1351+0
segue oLjects, using, 350351
SELECT statement vs. letch ieguest, 677
selecteuSegmentInuex methou, 13S
selectois, 67
senuAsynchionousReguest:gueue:completion
Hanulei: class methou, +72
senuEmailTo pioceuuie, 39
Senuei OLject, 91
senuSynchionousReguest:ietuiningResponse:
eiioi: class methou, +75
seiial uispatch gueues, 357, 39+397
setAnimationDelay: methou, S03
setAnimationDelegate: methou, S02
setAnimationDiuStopSelectoi: methou, S02
setAnimationDuiation: methou, S02
setAnimationRepeatCount: methou, S03
setAnimationVillStaitSelectoi: methou, S02
S03, S02S03
setAiiay:loiKey: methou, S33
setAttiiLutes:iange: methou ol, 250
setBackgiounuImage:loiState:LaiMetiics:
methou, 1+2
946 | Index
www.it-ebooks.info
setBool:loiKey: methou, S33
setCategoiy:eiioi: instance methou, 516
setCompletionHanulei: methou, +9S
setData:loiKey: methou, S33
setDictionaiy:loiKey: methou, S33
setDiviueiImage:loiLeltSegmentState:iightSeg
mentState:LaiMetiics: methou, 1+2
setGyioUpuateInteival: instance methou, S22
S2+
setHTTPMethou: methou, +S0+S1
setLeltBaiButtonItem:animateu: methou, 170
setNetwoikActivityInuicatoiVisiLle: methou,
212
setPieuicate: instance methou, S+3
setRightBaiButtonItem:animateu: methou,
170
sets
allocating anu using, S0S3
vs. aiiays, S1
setShowsSelectionInuicatoi: methou, 120
setSoitDesciiptois: instance methou, 6S06S1
setStiing:loiKey: methou, S33
settei methous, +951
setThumLImage:loiState: methou, 129
settings Lunule, cieating, 659662
setULiguitous:itemAtURL:uestinationURL:eii
oi: instance methou, S+5
setViewContiolleis:animateu: methou, 161
162
SHA1 hash ol lile, 901902
shaking, uetecting uevice, S19
shapes
auuing shauows to, 77S7S3
uiawing, 771
uiawn on giaphics contexts
uisplacing, 79079+
iotating, 797
scaling, 79+795
Shaie Lutton, neai text lielu, 153155
shaiing options, when view contiollei is
uisplayeu on scieen, 153
A Shoit Piactical Guiue to Blocks, weLsite loi,
xv
show methou, ol aleit view, 100101
signeu integei values
negative numLeis anu, 21
using NSIntegei to holu, 70
Simulatoi
iOS
Lackgiounu location piocessing using,
651
hiuing status Lai, 773
populating contacts uataLase on, 536
iunning applications in, 2
iunning apps on, 11
simulating limiteu veisions ol apps, 12
simulating two touches at same time,
+6S
suppoit loi Cameia inteilace on, 599
iPhone
eiioi in testing app loi stoiing viueos in
Photo LiLiaiy, 617
memoiy leaks anu, 50S
MPMoviePlayeiContiollei class on, 522
playing auuio in Lackgiounu on, 6+S
simulating phone calls with, 50S
simulating iotation gestuie on, +60
iunning app in, 2
simulating limiteu veisions ol apps, 12
simulatoi, iunning apps on, 11
Single View Application
auu navigation contiollei to pioject, 3+3
cieating pioject, 107109
sliueis
cieating, 126129
customizing, 130135
images on, 132135
iange specilieis ol, 127
thumL on, 12S
sliueiValueChangeu: taiget methou, 129
soiting uata, in Coie Data, 6S06S1
soitUsingCompaiatoi: methou, 77, 366
split view contiolleis, cieating applications
with, 213219
Spotlight items, gueiying, S+2
staitAcceleiometeiUpuatesToQueue:withHan
ulei: instance methou, S16S19
staitGyioUpuatesToQueue:withHanulei:
instance methou, S22S2+
staitPlayingViueo: methou, 520521, 525
staitSeaichingFoiDocumentIniClouu
methou,, S61S63
staitUpuateLocation instance methou, +36
static text, uisplaying, 177
stopPlayingAuuio methou, 529530
stopPlayingViueo: instance methou, 522
stopRecoiuingOnAuuioRecoiuei methou,
512513
Index | 947
www.it-ebooks.info
stopThieau methou, +26
stoiyLoaius
aLout, 337
auuing navigation contiollei to, 33S
auuing to existing pioject, 352
cieating pioject with, 33S
passing uata liom one scieen to anothei,
350351
stiaight lines, uiawing, 765770
Stiing Piogiamming Guiue (Apple), 25, 362
Stiing:completionHanulei: methou, ++9
stiingFoiKey: methou, S3+
stiings
conveiting numLeis to, 72
woiking with, 2326
stiingValueOlBOOLPiopeity:olURL:,
methou, 5S5
stiingVithContentsOlFile:encouing:eiioi:
class methou, 576
stilen() lunction, 3+
stiong keywoiu, 52
styleu texts, constiucting anu uisplaying, 2+S
252
suppoiteuInteilaceOiientations methou, 272
swipe ueletion, ol taLle view cells, 29+
swipe gestuies, +55+57
as uisciete gestuies, +56
switches
cieating, 107111
customizing, 11111+
synchionize methou, ol
NSULiguitousKeyValueStoie class,
S33
synchionous connections, uownloauing laige
lile using, 656657
synchionous tasks
uownloauing URL liom asynchionous coue,
3S0
peiloiming with GCD non-UI ielateu, 377
3S0
iunning with opeiations, 397+0+
suLmitteu to a seiial gueue, 395
synchionously uownloauing, with
NSURLConnection, +71+72, +75
+7S
syncing uocuments to iClouu, S65S67
synthesize keywoiu, +9
systemFontOlSize: instance methou, 7+9
T
taL Lais
aLout, 171177
piesenting multiple view contiolleis in,
170177
taLle view cells
applying inuentation to, 29+
cieating custom accessoiy, 290293
ueleting liom taLle views, 317
uisplaying context menus on, 306310
enaLling swipe ueletion ol, 29+296
moving in taLle views, 315316
moving vs. exchanging, 310
using uilleient types ol accessoiies in, 2SS
290
taLle view contiollei, in cieation ol taLle views,
325332
taLle view events, ieceiving anu hanuling, 2S7
2SS
taLle view sections
ueleting liom taLle views, 317325
moving in taLle views, 310315
moving vs. exchanging, 310
taLle View:numLeiOlRowsInSection: methou,
329
taLle views, 279
(see also views)
aLout, 279
assigning uelegate to, 2S02S3
Loosting uata access using Coie Data in,
6S2692
constiucting heaueis anu looteis in, 297
306
cieating guick, 325332
ueleting cells anu sections liom, 317325
uisplaying hieiaichical uata in, 29329+
uisplaying ieliesh contiol loi, 332335
giving a yes/no answei to iOS, 306310
instantiating, 2792S0
moving cells anu sections in, 310315
moving vs. exchanging ol cells anu sections,
310
populating with uata, 2S32S6
taLleView:canPeiloimAction:loiRowAtInuexP
ath:withSenuei:
methouPath:withSenuei: methou,
306, 309
taLleView:cellFoiRowAtInuexPath: methou,
2S+, 6S3
948 | Index
www.it-ebooks.info
taLleView:commitEuitingStyle:loiRowAtInue
xPath: methou, 296
taLleView:euitingStyleFoiRowAtInuexPath:
methou, 29+296
taLleView:heightFoiFooteiInSection: methou,
302
taLleView:heightFoiHeaueiInSection: methou,
301
taLleView:numLeiOlRowsInSection: methou,
2S+
taLleView:peiloimAction:loiRowAtInuexPath
:withSenuei: methou, 307
taLleView:shouluShowMenuFoiRowAtInuexP
ath: methou, 306
taLleView:titleFoiFooteiInSection: methou,
305
taLleView:titleFoiHeaueiInSection: methou,
305
taLleView:viewFoiFooteiInSection: methou,
300, 30230+
taLleView:viewFoiHeaueiInSection: methou,
300, 30230+
taLleViewNumLeis piopeity, 31S
tap gestuies, uetecting, +66+70
taiget methou, +1S
tasks
cieating uepenuency in, +10+13
cieating timeis loi, +13+1S
uelegating with piotocols, 6066
uispatching to GCD, 372373
giouping togethei with GCD, 39139+
in cieating applications, 7
peiloiming altei uelay with GCD, 3S63S9
peiloiming only once with GCD, 3S9390
peiloiming with GCD asynchionous non-
UI ielateu, 3S03S5
peiloiming with GCD synchionous non-UI
ielateu, 3773S0
peiloiming with GCD UI-ielateu, 373377
iunning with opeiations asynchionous,
+0++10
iunning with opeiations synchionous, 397
+0+
synchionous tasks suLmitteu to a seiial
gueue, 395
team ID
Lounu to piovision piolile, S32
ietiieving, S31
teamIuentiliei keys, S95
tempoiaiily stoiing text in apps, 576
text
aLout static, 177
constiucting anu uisplaying styleu, 2+S
252
uisplaying long lines ol, 192196
uisplaying using lonts in giaphics, 7+S
uiawing, 7+9750, 752
stoiing to uisk, 575
tempoiaiily stoiing in apps, 576
usei inteilace accepting usei, 1S3190
textFielu:shouluChangeChaiacteisIn
Range:ieplacementStiing: methou,
1S6, 1S9
textFielu:shouluChangeChaiacteisInRange:ie
placementStiing: methou, 1S6
textFieluDiuBeginEuiting: methou, 1S6
textFieluDiuEnuEuiting: methou, 1S6
textFieluShouluBeginEuiting: methou, 1S6
textFieluShouluEnuEuiting: methou, 1S6
textFieluShouluRetuin: methou, 153, 1S6
textFieluVithPlaceholuei: methou, 262
textViewDiuChange: methou, S63
thiiuCountei methou, +21
Thieau class methou, 376
thieau management, GCD anu, 357
thieaus
aLout, 360
cieating, +23+2+
cieating concuiiency with, +1S+23
exiting timeis anu, +25+26
opeiations Llocking main, +00
vs. Llock oLjects, 35S
thumL on sliueis, 12S
thumLnails, captuiing liom viueo liles, 523
526
time anu uate, picking, 122
timeOption: MPMovieTimeOptionExact
value, 526
timeouts, hanuling asynchionous connection,
+7++75
timeis
aLout, 360
cieating, +13+1S
exiting thieaus anu, +25+26
timeiVithTimeInteival:invocation:iepeats:
class methou, +16
timeiVithTimeInteival:taiget:selectoi:useiInl
o:iepeats: class methou, +16
Index | 949
www.it-ebooks.info
tint colois
applying new colois to segmenteu contiol
using, 1391+6
mouilying sliuei, 130135
titleFoiSegmentAtInuex: methou, 13S
titleView piopeity, 162
tmp loluei, 571, 575
Toll-Fiee Biiuging, 5++
tiauitional lunction pointeis vs. Llock oLjects,
35S
tiansloimations
aLout, 790791
alline
aLout, 790791
iotation, S0SS10
scaling, 79+795, S07S0S
passing NULL to pioceuuies loi uiawing
shapes anu lines, 77+
iotation, 790, 797, S0SS10
scaling, 79+795, S07S0S
tianslation, 790791
tianslation tiansloimations, 790791
Twittei
aLout connectivity, +71
integiating into apps lunctionality ol, +9+
+99
integiation in iOS 6, 152
ieliesh contiol in application, 332
URL in tweet as pait ol Twittei timeline,
+97
Twittei liamewoik, integiating Twittei
lunctionality into apps using ol, +9+
+99
TVTweetComposeViewContiollei, +9+
TVTweetComposeViewContiolleiResult
paiametei, +9S50+
typecasting
specilieis, 57
to help static analyzei anu compilei, 60+
unuei ARC, 5760
U
UDIDs (Unigue Device Iuentilieis), 16
UI components
aLout aligning, 253
placing on centei ol scieen, 25625S
stanuaiu uistances oi spaces Letween, 260
UI-ielateu tasks, peiloiming with GCD, 373
377
UIActivityViewContiollei class
piesenting in iPhone anu iPau, 151
piesenting shaiing options with, 151155
UIAleitView class
uisplaying aleits with, 100106
local notilication aleit view, 6+0
UIAleitViewStyle, styles ol, 102
UIApplication class
in linishing task when youi application is
sent to Lackgiounu, 63563S
scheuuling ueliveiy ol local notilication
using, 63S6+5
value ietuineu while iunning auuio lile in
Lackgiounu, 6+S
UIApplicationDelegate messages, in saving anu
loauing state ol apps, 65165+
UIApplicationDiuEnteiBackgiounuNotilicatio
n, 633
UIApplicationExitsOnSuspenu key, 662
UIBackgiounuMoues key
auuing location Key to .plist lile to, 6+S
setting aiiay key in .plist lile to, 6+66+S
UIBaiButtonItem, 22+
UIBaiButtonItem class, auuing Luttons to
Navigation Bais, 163
UIButton class, auuing Luttons to usei
inteilace, 196
UIColoi class, 751755
UIDatePickei class, picking uate anu time with,
122125
UIDatePickeiMoue enumeiation, values in,
123
UIDatePickeiMoueCountDownTimei, 125
UIDevice class, 63+
UIDevicePioximityStateDiuChangeNotilicatio
n, 657
UIDocument class, S51S56, S63, S65S67,
S6S, S69
UIDocumentStateChangeuNotilication, S65
S67, S6S, S70, S7+
UIDocumentStateInConllict state, S6S
UIEventSuLtype class, S19S22
UIFont class
encapsulating lonts, 7+S
enumeiate installeu lont lamilies, 7+S
UIGestuieRecognizei class, +5+
UIGestuieRecognizeiStateBegan, +5S
UIGestuieRecognizeiStateCancelleu, +55, +63
UIGestuieRecognizeiStateEnueu, +5S, +62
950 | Index
www.it-ebooks.info
UIGestuieRecognizeiStatePossiLle, +55
UIImage class, 563
Cocoa classes anu, 575
cieating iesizaLle images, 75976+
uiawing images using, 756759
loauing .png lile as image, S7
passing iesouice path to, S5
using instance within application ol, 610
using to uisplay image on view, 62+
UIImage]PEGRepiesentation lunction, 563
UIImagePickeiContiollei class, 61S619
aLout, 599
uetecting anu pioLing cameia, 601606
ietiieving photos anu viueos liom Photo
LiLiaiy, 619
stoiing photos in Photo LiLiaiy, 615616
taking anu using viueos with cameia, 610
613
taking photos with cameia, 606610
UIImagePickeiContiolleiDelegate piotocol,
60760S
UIImagePickeiContiolleiSouiceTypeCameia
souice type, 612
UIImagePickeiContiolleiSouiceTypePhotoLiL
iaiy value, 61S619
UIImagePNGRepiesentation lunction, 563
UIImageView class, 30+
clipping images, 203
constiucting, 62+
uisplaying images with, 200203
UIImageViiteToSaveuPhotosAlLum lunction,
615616
UIImageViiteToSaveuPhotosAlLum
pioceuuie, 613616
UIKeyLoaiuAnimationCuiveUseiInloKey, 23S
UIKeyLoaiuAnimationDuiationUseiInloKey,
23S
UIKeyLoaiuDiuHiueNotilication, 193, 23S
UIKeyLoaiuDiuShowNotilication, 193, 23S
UIKeyLoaiuFiameBeginUseiInloKey, 23S
UIKeyLoaiuFiameEnuUseiInloKey, 23S
UIKeyLoaiuVillHiueNotilication, 23S
UIKeyLoaiuVillShowNotilication, 193, 237
UIKit liamewoik
aLout, 739
colois pioviueu Ly, 751
enumeiating anu loauing ol lonts lacilitateu
Ly, 7+S
peiloiming animations in, 79SS03
UILaLel class
customizing, 1S11S3
uisplaying static text with, 1771S1
UILocalNotilication, 63S6+5
UILongPiessGestuieRecognizei class, +63
+66
UILongTapGestuieRecognizei class, +6+
UIMainStoiyLoaiu File key, cieating loi
iPhone, 35+
UINavigationContiollei class
accessing anu mouilying aiiay ol view
contiolleis, 161
piesenting euit event view contiolleis using,
735
ielationship to UIView Contiollei, 171,
17+
UINavigationContiollei wiuget, implementing
navigation with, 155161
UINavigationContiolleiDelegate piotocol,
60760S
UINavigationContiolleiDelegate piotocols,
631
UIPage ViewContiolleiDelegate piotocol, 221
UIPageViewContiollei, enaLling paging with,
219222
UIPageViewContiolleiSpineLocationMiu
uisplaying, 222
UIPanGestuieRecognizei class, +60+62
UIPickeiView class, picking values with, 115
120
UIPickeiViewDelegate piotocol, 119
UIPinchGestuieRecognizei class, +6S
UIPopoveiContiollei class, uisplaying
popoveis with, 223232
UIPiogiessView class, uisplaying piogiess with,
23223+
UIRelieshContiol, 333
UIRotationGestuieRecognizei class, +5S
UISciollView class, cieating sciollaLle content
with, 20+20S
UISciollViewDelegate piotocol, 206
UISegmenteuContiol class
customizing, 1391+6
giouping compact options with, 1351+0
UISliuei class
customizing, 130135
implementing iange pickeis with, 126129
UISplitViewContiollei class, piesenting
mastei-uetail views with, 213219
Index | 951
www.it-ebooks.info
UIStatusBaiHiuuen key, 773
UIStoiyLoaiuSegue class, 350351
UISwipeGestuieRecognizei class, +55+57
UISwitch class
cieating anu using switches with, 107111
customizing, 11111+
UITaLBaiContiollei class, piesenting multiple
view contiolleis with, 170177
UITaLleView class, 66, 2S1, 317, 3S3
UITaLleViewCell class, 279, 2SS290292
UITaLleViewContiollei class, utilizing loi easy
cieation ol taLle views, 325332
UITaLleViewDataSouice piotocol, 2S3, 312
31+, 331
UITaLleViewDelegate piotocol, 2S1, 2SS, 299,
301, 306, 331
UITaLleViewRowAnimationAutomatic
animation type, 322
UITapGestuieRecognizei class, +66
UITextFielu class, accepting usei text input
with, 1S3190
UITextFieluDelegate piotocol, 153
UITextView class
uisplaying long lines ol text with, 192196
in allowing usei to input text that syncs to
iClouu, S59
UITextViewDelegatepiotocol class, S63
UIViueoEuitoi ContiolleiDelegate piotocols,
631
UIViueoEuitoiContiollei, 627, 631
UIView class
animating views
moving anu, 79SS06
iotating anu, S0SS10
scaling anu, S07S0S
cieating pioject in Xcoue with suLclass,
7+17+7
in cieating custom taLle view cell
accessoiies, 290
in uetecting pinch gestuies, +6S, +69
in uetecting iotation gestuies, +5S
in uisplaying pins with uilleient colois on
map view, +39
in uiawing eveiything visiLle on scieen,
7+1
in gestuie iecognizeis, +53+55
manipulating map view with, +32
playing meuia using view piopeity, 520
UIViewContentMoue enumeiation, 203
UIViewContentMoueScaleAspectFit content
moue, 203
UIViewContiollei class
cieating view contiolleis, 6S+
uisplaying movie contiollei, 519
piesenting anu managing views with, 1+6
151
vs. navigation contiolleis, 171
UIVeLView class, loauing weL pages with,
209213
UIVeLViewDelegate piotocol, 212
UIVinuow, 739
ULO (Uppei Lelt Oiigin) scieens, 7+1
unigue iuentiliei, loi stoiing uata in iClouu,
S31
UNIX opeiating system, Mac OS X, iOS anu,
571
unsaleunietaineu keywoiu, 52
unsigneu integei values
negative numLeis anu, 21
using NSUIntegei to holu, 70
unsigneuIntegeiValue methou, 72
upuateChangeCount: methou, S63
Uppei Lelt Oiigin (ULO) scieens, 7+1
URL
access uata ol asset given, 600601
aujusting HTTP heaueis anu settings, +7S
asynchionous connection ieguesting to
ietiieve contents ol, 65+656
cieating connection, +72
uealing with loi iClouu, S36
uownloauing contents synchionously ol,
+75+7S
encapsulateu in instances ol NSURL, 577
loi app iClouu containei, S+5S+7
GET ieguest as pait ol, +79
in stoiing viueos in Photo LiLiaiy, 617
in tweet as pait ol Twittei timeline, +97
mutaLle oi immutaLle ieguests, +7S
seting timeout on ieguest ol, +7++75
URL Reguest, +72
uilFoiDocumentsDiiectoiyIniClouu methou,
S5S, S59
uilFoiRanuomFileInDocumentsFolueiIniClou
u methou, S+7
URLFoiULiguityContaineiIuentiliei: methou,
S3S, S5S
URLsFoiDiiectoiy paiametei, 57+
952 | Index
www.it-ebooks.info
URLsFoiDiiectoiy:inDomains: instance
methou, 57+
useAuuiessBook: methou, 5+25+3
Usei-Inlo Dictionaiy, 91
useiInlo methou, +1S
UTFSStiing methou, 2+
V
valueFoiPiopeity: instance methou, 52S
vaiiaLles
aLout, 22
accessing in Llock oLjects, 365371
instance, 50
iules loi naming, 20
types ol, 22
viueo liles, 519523
captuiing thumLnails liom, 523526
viueo pickei, uisplaying to usei in euiting viueos
on uevices, 62S629
viueoEuitoiContiollei:uiuSaveEuiteuViueoTo
Path: uelegate methou, 631
viueoHasFinisheuPlaying: instance methou,
522
viueoHasFinisheuPlaying: notilication hanulei,
522
viueoMaximumDuiation, 612
viueoQuality piopeity, 612
viueos
euiting on uevices, 627631
in lanuscape moue only with
UIViueoEuitoiContiollei, 62S
ietiieving liom Photo LiLiaiy, 61S619,
620627
stoiing in Photo LiLiaiy, 61661S
taking anu using with cameia, 610613
values in NSStiing loi taking with cameia,
609
viueoThumLnailIsAvailaLle: instance methou,
525
view
as aichitectuial component ol applications,
99
in MVC uivision ol laLoi, 1+7
View Contiollei class, cieating switches, 107
view contiolleis (contiolleis), +5S
accessing music liLiaiy methous in, 529
530
alteiing auuio session anu loauing song into
memoiy in, 51751S
as aichitectuial component ol applications,
99
attempting to uisplay image pickei
contiollei as moual, 607
cieating, 1+7
cieating instance ol CLLocationManagei,
+35+36
cieating to uemonstiate uselulness ol letch
iesults contiolleis, 6S+
uelining image view in, 622
uetecting pinch gestuies, +69, +70
uisplaying contents insiue popoveis, 226
229
liiing metauata gueiy when view gets
loaueu, S+5, S50
loi euiting viueos on uevices, 62762S
loi instantiating Auu navigation Lai Lutton,
6S5
implementing taLle view methous in, 2S+
in uetecting long piess gestuies, +63
in uetecting tap gestuies, +66
in MVC uivision ol laLoi, 1+7
initialize Twittei composei contiollei in,
+95
initializing image views, S0+
manipulating aiiay ol, 161162, 161162
moving to othei, 155161
placing laLels anu image views, 56+566
piesenting euit event, 73573S
piesenting event, 732735
piesenting multiple, 170177
piesenting two siue-Ly-siue, 213219
seaiching loi existing usei uocuments, S60
stait iecoiuings using, 510511
stop iecoiuings using, 512513
takes auvantage ol coalesceu notilications,
65S
to Le in chaige ol conllict in iClouu, S71
S73
view contiolleis, cieating page view contiolleis,
219
view DiuAppeai: instance methou, 627, 630
viewDiuAppeai methou, 153
viewDiuAppeai: methou, 566
viewDiuAppeai:methou, 159
viewDiuLoau methou, 507
allowing UI components to Le placeu on
view, 15+
Index | 953
www.it-ebooks.info
alteiing auuio session anu loauing song into
memoiy in, 51751S
constiucting UI components in, 262, 265
cieating navigation Lutton in ioot view
contiollei, 229
cieating pickei view in, 115117
cieating taLle view anu assigning uata
souice, 2S3
liiing metauata gueiy when view gets
loaueu, S+5, S50
in uetecting long piess gestuies, +63
in uetecting tap gestuies, +66
initialize Twittei composei contiollei using,
+95
initializing image views, S0+
instantiating Auu navigation Lai Lutton,
6S5
ol view contiollei, 1+5
placing laLels anu image views, 56+566
piesenting event view contiolleis using,
732
iunning in view contiollei oLject ol type
MKMapView, +3+
seaiching loi existing usei uocuments, S60
stait iecoiuings using, 511
stop iecoiuings using, 512513
using in iunning counteis, +20
views, 279
(see also taLle views)
animating
moving anu, 79SS06
iotating anu, S0SS10
scaling anu, S07S0S
apps in Cocoa Touch maue up ol winuows
onu, 739
cieating text, 192
uisplaying piogiess Lai, 23223+
uisplaying styleu text weL, 2+S
gestuie iecognizeis in, +52
loauing weL, 209213
local notilication aleit view, 6+0
map view
cieating, +30+32
uisplaying custom pins on, ++6++S
uisplaying pins on, +37+39
uisplaying pins with uilleient colois on,
+39++5
hanuling events ol, +32+3+
playing meuia using view piopeity, 520
piesenting mastei-uetail, 213219
scioll, 20+205
switching Letween uilleient views in
applications, 1+6151
Visual Foimat Language
aLout, 256, 259
uelining hoiizontal anu veitical constiaints
with, 259265
W
wainings, 329
weak keywoiu, 52
weL pages, loauing, 209213
weL seivices, uistiiLuting Pass Kit passes using,
911913
weL views, in uisplaying styleu text, 2+S
weLView:uiuFailLoauVithEiioi: methou, 212
weLViewDiuFinishLoau: methou, 212
weLViewDiuStaitLoau: methou, 212
while statement
exit stiategy loi loops, 33
implementing with loi statement, 323+
winuows anu views, in apps in Cocoa Touch,
739
VithCompletionHanulei: methou, S69
VithReu:gieen:Llue:alpha: class methou, 751
wiiteData: methou, 592, 595
wiiteData:instance methou, 627
wiiteToFile methou, 595
wiiteToFile paiametei, 575
wiiteToFile:atomically: instance methou, 57S
579
wiiteToFile:atomically:encouing:eiioi:
instance methou, 575
wiiteToURL:atomically:encouing:eiioi:
instance methou, 577
wiiteViueoAtPathToSaveuPhotosAlLum:com
pletionBlock: instance methou, 616
617
wiiting to anu ieauing liom liles, 575579
X
Xcoue
Luilu commanus loi compiling apps, 910
containei iuentiliei, S3S
Coie Founuation memoiy management
piocessing in static analyzei ol,
552
954 | Index
www.it-ebooks.info
cieating a Single View Application pioject,
10S
cieating Coie Data mouel with, 666669
cieating iOS App in, 25
cieating pioject that uses Coie Data in, 663
665
cieating pioject with suLclass UIView, 7+1
7+7
uetecting uevices, 131+
uisplaying console scieen in, 290
uownloauing, 7+1
page view contiollei template, 219
iunning limiteu veisions ol apps, 12
using uata mouel geneiateu in euitoi ol,
672
visual uata euitoi ol, 667
XIB liles, 6
XML
paising, +71
paising with NSXMLPaisei, +9S50+
XMLElement class, 501502
Y
Yacktman, Donalu A., Cocoa Design Patteins,
+S
Yahoo!, ietiieving home page ol US weLsite ol,
+75+76
yellow values, 751
Yes anu No Luttons, 10210+
Z
zeio/nil/NULL, in loops, 32
Index | 955
www.it-ebooks.info
About the Author
Vandad Nahavandipoor has uevelopeu soltwaie using Cocoa, Cocoa Touch, As-
semLly, Delphi, anu .NET loi many yeais. As a stall memLei ol a company that is a
gloLal leauei in moLile money solutions in Lonuon, he has woikeu with some ol the
woilu`s Liggest Lianussuch as Visa anu US Bankto uelivei moLile applications to
theii customeis. Vanuau Liings an inteiest in management, leaueiship, anu entiepie-
neuiship to his woik, Lelieving in the syneigy that is achieveu as a iesult ol coopeiation
anu woiking togethei in a team.
Colophon
The covei image loi iOS Progranning Coo|boo| is the Cowan`s shiew teniec (Mi-
croga|c cowani). One ol 20 known species ol Microga|cs native to Mauagascai, Cowan`s
shiew teniec is + to 6 inches in length anu weighs less than an ounce, with a tail smallei
than its Louy. Because it has pooi eyesight, the shiew teniec insteau uses its still, sen-
sitive whiskeis anu a keen sense ol smell to navigate the uense tiopical iainloiests ol
eastein Mauagascai. The teniecs aie one ol the lew mammals that ietain a cloaca, a
single uiogenital opening that was chaiacteiistic ol the eailiest known mammals anu
the mouein uay platypus anu maisupials.
An insectivoie like many teniecs, Cowan`s shiew teniec is also known to eat small
mammals anu eaithwoims. Its natuial pieuatois incluue laigei teniecs anu Mauagas-
can ieu owls, although it can evaue most pieuatois Ly lleeing anu hiuing in the lealy
unueiLiush ol the loiest llooi, wheie it also loiages loi insects.
Some speculate that the teniecs migiateu to Mauagascai liom Aliica thiough oceanic
uispeisal, oi ialting ovei, altei the islanu hau Lioken oll liom the continent 165 million
yeais ago. The eailiest known teniecs appeaieu on the islanu some 60 million yeais ago
anu have evolveu into wiuely uiveisilieu species, having aiiiveu at a time when theie
weie no othei mammals, which alloweu them to auapt to theii ecological niches with
little to no competition. Most Aliican teniecs have uisappeaieu anu aie known only
thiough lossils. The laigei teniecs ol Mauagascai evolveu into guill-Leaiing mammals
similai to heugehogs, while the smallei teniecs look like shiews oi moles; howevei,
teniecs aie not ielateu to any ol those othei animals.
The covei image is liom a loose page, oiigin unknown. The text lont is Linotype Biika;
the heauing lont is AuoLe Myiiau Conuenseu; anu the coue lont is LucasFont`s The-
SansMonoConuenseu.
www.it-ebooks.info

You might also like