O'Reilly iOS Programming Guide
Below you will find brief information for iOS 6. This programming guide provides fundamentals of iPhone, iPad, and iPod touch development, covering iOS 6.1 and Xcode 4.6.
PDF
Document
Advertisement
Advertisement
THIRD EDITION Programming iOS 6 Matt Neuburg Programming iOS 6, Third Edition by Matt Neuburg Copyright © 2013 Matt Neuburg. All rights reserved. Printed in the United States of America. Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472. O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are also available for most titles (http://my.safaribooksonline.com). For more information, contact our corporate/ institutional sales department: (800) 998-9938 or [email protected]. Editor: Rachel Roumeliotis Production Editor: Kristen Borg Proofreader: O’Reilly Production Services Indexer: Matt Neuburg March 2013: Cover Designer: Randy Comer Interior Designer: David Futato Illustrator: Matt Neuburg Third Edition Revision History for the Third Edition: 2013-02-27: First release See http://oreilly.com/catalog/errata.csp?isbn=9781449365769 for release details. Nutshell Handbook, the Nutshell Handbook logo, and the O’Reilly logo are registered trademarks of O’Reilly Media, Inc. Programming iOS 6, the image of a kingbird, and related trade dress are trademarks of O’Reilly Media, Inc. Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks. Where those designations appear in this book, and O’Reilly Media, Inc., was aware of a trade‐ mark claim, the designations have been printed in caps or initial caps. While every precaution has been taken in the preparation of this book, the publisher and author assume no responsibility for errors or omissions, or for damages resulting from the use of the information contained herein. ISBN: 978-1-449-36576-9 [LSI] Table of Contents Preface. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xvii Part I. Language 1. Just Enough C. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Compilation, Statements, and Comments Variable Declaration, Initialization, and Data Types Structs Pointers Arrays Operators Flow Control and Conditions Functions Pointer Parameters and the Address Operator Files The Standard Library More Preprocessor Directives Data Type Qualifiers 5 6 9 11 14 15 17 21 24 26 30 30 31 2. Object-Based Programming. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 Objects Messages and Methods Classes and Instances Class Methods Instance Variables The Object-Based Philosophy 35 36 37 40 41 42 3. Objective-C Objects and Messages. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 An Instance Reference Is a Pointer 47 iii Instance References, Initialization, and nil Instance References and Assignment Instance References and Memory Management Messages and Methods Sending a Message Declaring a Method Nesting Method Calls No Overloading Parameter Lists Unrecognized Selectors Typecasting and the id Type Messages as Data Type C Functions CFTypeRefs Blocks 49 51 52 54 54 55 56 57 58 59 61 65 66 67 68 4. Objective-C Classes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 Class and Superclass Interface and Implementation Header File and Implementation File Class Methods The Secret Life of Classes 75 77 79 82 83 5. Objective-C Instances. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 How Instances Are Created Ready-Made Instances Instantiation from Scratch Nib-Based Instantiation Polymorphism The Keyword self The Keyword super Instance Variables and Accessors Key–Value Coding Properties How to Write an Initializer Part II. 85 85 87 90 91 93 97 98 100 102 104 IDE 6. Anatomy of an Xcode Project. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 New Project The Project Window iv | Table of Contents 110 112 The Navigator Pane The Utilities Pane The Editor The Project File and Its Dependents The Target Build Phases Build Settings Configurations Schemes and Destinations From Project to App Build Settings Property List Settings Nib Files and Storyboard Files Other Resources Code Frameworks and SDKs 113 118 119 122 125 125 126 128 129 131 133 133 134 135 137 139 7. Nib Management. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145 A Tour of the Nib-Editing Interface The Dock Canvas Inspectors and Libraries Nib Loading and File’s Owner Making and Loading a Nib Outlet Connections More Ways to Create Outlets More About Outlets Action Connections Additional Initialization of Nib-Based Instances 146 147 148 151 153 154 156 161 164 165 168 8. Documentation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171 The Documentation Window Class Documentation Pages Sample Code Other Resources Quick Help Symbols Header Files Internet Resources 172 174 177 178 178 179 180 180 9. Life Cycle of a Project. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183 Device Architecture and Conditional Code 183 Table of Contents | v Localization Editing Your Code Autocompletion Snippets Fix-it and Live Syntax Checking Navigating Your Code Debugging Caveman Debugging The Xcode Debugger Unit Testing Static Analyzer Clean Running in the Simulator Running on a Device Profile and Device Management Version Control Instruments Distribution Ad Hoc Distribution Final App Preparations Icons in the App Other Icons Launch Images Screenshots Property List Settings Submission to the App Store Part III. 188 192 193 195 195 196 199 199 202 208 208 209 210 212 215 216 219 223 225 226 226 227 228 230 231 233 Cocoa 10. Cocoa Classes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239 Subclassing Categories Splitting a Class Class Extensions Protocols Optional Methods Some Foundation Classes Useful Structs and Constants NSString and Friends NSDate and Friends NSNumber vi | Table of Contents 239 242 243 244 245 250 252 252 253 255 256 NSValue NSData Equality and Comparison NSIndexSet NSArray and NSMutableArray NSSet and Friends NSDictionary and NSMutableDictionary NSNull Immutable and Mutable Property Lists The Secret Life of NSObject 257 257 258 258 259 261 262 264 264 265 266 11. Cocoa Events. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269 Reasons for Events Subclassing Notifications Receiving a Built-In Notification Unregistering NSTimer Delegation Data Sources Actions The Responder Chain Deferring Responsibility Nil-Targeted Actions Swamped by Events Delayed Performance Application Lifetime Events 270 270 272 273 275 276 277 280 281 283 284 285 286 289 292 12. Accessors and Memory Management. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297 Key–Value Coding KVC and Outlets Key Paths and Array Accessors Memory Management Principles of Cocoa Memory Management The Golden Rules of Memory Management What ARC Is and What It Does How Cocoa Objects Manage Memory Autorelease Memory Management of Instance Variables (Non-ARC) Memory Management of Instance Variables (ARC) Retain Cycles and Weak References 298 300 301 303 303 305 307 310 312 316 320 321 Table of Contents | vii Unusual Memory Management Situations Nib Loading and Memory Management Memory Management of Global Variables Memory Management of Pointer-to-Void Context Info Memory Management of CFTypeRefs Properties Property Memory Management Policies Property Declaration Syntax Property Accessor Synthesis Dynamic Accessors 324 329 330 331 332 335 336 338 340 342 13. Data Communication. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347 Model–View–Controller Instance Visibility Visibility by Instantiation Visibility by Relationship Global Visibility Notifications Key–Value Observing Part IV. 347 349 350 351 352 353 354 Views 14. Views. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363 The Window Subview and Superview Visibility and Opacity Frame Bounds and Center Transform Layout Autoresizing Autolayout Constraints in the Nib Order of Layout Events Autolayout and View Transforms 364 367 369 370 371 375 380 381 383 393 398 399 15. Drawing. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403 UIImage and UIImageView Graphics Contexts UIImage Drawing CGImage Drawing viii | Table of Contents 403 409 412 414 CIFilter and CIImage Drawing a UIView Graphics Context Settings Paths and Drawing Clipping Gradients Colors and Patterns Graphics Context Transforms Shadows Points and Pixels Content Mode 418 421 423 425 429 430 432 434 436 437 438 16. Layers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441 View and Layer Layers and Sublayers Manipulating the Layer Hierarchy Positioning a Sublayer CAScrollLayer Layout of Sublayers Drawing in a Layer Content Resizing and Positioning Layers that Draw Themselves Transforms Depth Shadows, Borders, and More Layer Efficiency Layers and Key–Value Coding 442 444 446 446 447 448 449 452 455 456 460 463 464 466 17. Animation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 469 Drawing, Animation, and Threading UIImageView and UIImage Animation View Animation Animation Blocks Modifying an Animation Block Transition Animations Block-Based View Animation Implicit Layer Animation Animation Transactions Media Timing Functions Core Animation CABasicAnimation and Its Inheritance Using a CABasicAnimation 470 472 475 475 476 480 481 487 488 489 491 491 493 Table of Contents | ix Keyframe Animation Making a Property Animatable Grouped Animations Transitions The Animations List Animation and Autolayout Actions What an Action Is The Action Search Hooking Into the Action Search Nonproperty Actions Emitter Layers CIFilter Transitions 497 498 499 503 505 507 511 511 511 513 516 517 523 18. Touches. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 527 Touch Events and Views Receiving Touches Restricting Touches Interpreting Touches Gesture Recognizers Gesture Recognizer Classes Multiple Gesture Recognizers Subclassing Gesture Recognizers Gesture Recognizer Delegate Gesture Recognizers in the Nib Touch Delivery Hit-Testing Initial Touch Event Delivery Gesture Recognizer and View Touch Exclusion Logic Recognition Touches and the Responder Chain Part V. 528 530 531 532 537 538 543 544 546 549 550 551 556 556 558 558 560 Interface 19. View Controllers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 565 The View Controller Hierarchy View Controller and View Creation Manual View Generic Automatic View View in a Separate Nib x | Table of Contents 568 572 575 578 579 Nib-Instantiated View Controller Storyboard-Instantiated View Controller Rotation Rotation and Layout Events Initial Orientation Presented View Controller Presented View Animation Presentation Styles Rotation of a Presented View Presenting a View in Response to Rotation Tab Bar Controllers Tab Bar Items Configuring a Tab Bar Controller Navigation Controllers Bar Button Items Navigation Items Toolbar Items Configuring a Navigation Controller Page View Controller Container View Controllers Storyboards Segues Unwind Segues Storyboards and Custom Container View Controllers View Controller Lifetime Events View Controller Memory Management State Restoration Participating in State Restoration Restoration ID and Restoration Class Restoring View Controller State 583 585 588 592 595 599 604 605 608 609 610 611 612 614 617 619 622 622 625 630 633 635 637 642 642 646 649 651 653 661 20. Scroll Views. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 667 Creating a Scroll View Scrolling Paging Tiling Zooming Zooming Programmatically Zooming with Detail Scroll View Delegate Scroll View Touches 667 673 676 677 679 682 682 685 687 Table of Contents | xi Scroll View Performance 692 21. Table Views and Collection Views. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 695 Table View Cells Built-In Cell Styles Registering a Cell Class Custom Cells Table View Data The Three Big Questions Table View Sections Refreshing Table View Data Variable Row Heights Table View Selection Table View Scrolling and Layout Table View State Restoration Table View Searching Table View Editing Deleting Table Items Editable Content in Table Items Inserting Table Items Rearranging Table Items Dynamic Table Content Table View Menus Collection Views 698 699 705 708 715 716 719 726 729 732 737 738 739 745 749 750 752 754 755 756 758 22. Popovers and Split Views. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 767 Configuring and Displaying a Popover Managing a Popover Dismissing a Popover Popovers and Presented Views Popover Segues Automatic Popovers Split Views 769 774 774 778 778 780 782 23. Text. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 787 Attributed Strings UILabel UITextField Summoning and Dismissing the Keyboard Keyboard Covers Text Field Configuring the Keyboard Text Field Delegate and Control Event Messages xii | Table of Contents 788 797 800 803 804 808 809 The Text Field Menu UITextView Core Text 812 814 817 24. Web Views. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 825 Loading Web View Content Web View State Restoration Communicating with a Web View 826 833 834 25. Controls and Other Views. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 837 UIActivityIndicatorView UIProgressView UIPickerView UISearchBar UIControl UISwitch UIStepper UIPageControl UIDatePicker UISlider UISegmentedControl UIButton Custom Controls Bars UINavigationBar UIToolbar UITabBar Appearance Proxy 837 839 841 843 847 852 853 854 855 858 861 865 870 873 873 878 879 883 26. Modal Dialogs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 887 Alert View Action Sheet Dialog Alternatives Local Notifications Activity View Part VI. 888 891 896 897 900 Some Frameworks 27. Audio. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 909 System Sounds Audio Session 909 910 Table of Contents | xiii Interruptions Routing Changes Audio Player Remote Control of Your Sound Playing Sound in the Background Further Topics in Sound 913 915 916 918 921 923 28. Video. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 925 MPMoviePlayerController MPMoviePlayerViewController UIVideoEditorController Introduction to AV Foundation Video 926 932 934 936 29. Music Library. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 943 Exploring the Music Library The Music Player The Music Picker 943 948 954 30. Photo Library and Image Capture. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 957 UIImagePickerController Choosing from the Photo Library Using the Camera Image Capture With AV Foundation The Assets Library Framework 957 958 962 966 969 31. Address Book. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 973 Address Book Database Address Book Interface ABPeoplePickerNavigationController ABPersonViewController ABNewPersonViewController ABUnknownPersonViewController 973 977 978 980 981 982 32. Calendar. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 985 Calendar Database Calendar Interface 985 995 33. Mail and Messages. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1003 Mail Message Text Message xiv | Table of Contents 1003 1005 Twitter Post 1006 34. Maps. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1007 Displaying a Map Annotations Overlays Map Kit and Current Location Geocoding Communicating With the Maps App 1007 1010 1017 1024 1025 1027 35. Sensors. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1029 Location Heading Acceleration and Attitude Shake Events Raw Acceleration Gyroscope Part VII. 1030 1035 1036 1037 1038 1042 Final Topics 36. Persistent Storage. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1051 The Sandbox Basic File Operations Saving and Reading Files User Defaults File Sharing Document Types Handing Off a Document The Document Architecture iCloud XML SQLite Core Data Image File Formats 1052 1053 1054 1056 1058 1059 1060 1064 1068 1070 1077 1078 1084 37. Basic Networking. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1087 HTTP Requests Bonjour Push Notifications 1087 1096 1098 Table of Contents | xv Beyond Basic Networking 1099 38. Threads. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1101 The Main Thread Why Threading Is Hard Three Ways of Threading Manual Threads NSOperation Grand Central Dispatch Threads and App Backgrounding 1101 1104 1106 1107 1109 1114 1119 39. Undo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1123 The Undo Manager The Undo Interface The Undo Architecture 1123 1127 1130 40. Epilogue. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1133 Index. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1135 xvi | Table of Contents Preface Aut lego vel scribo; doceo scrutorve sophian. —Sedulius Scottus With the advent of version 2 of the iPhone system, Apple proved they could do a re‐ markable thing — adapt their existing Cocoa computer application programming framework to make applications for a touch-based device with limited memory and speed and a dauntingly tiny display. The resulting Cocoa Touch framework, in fact, turned out to be in many ways better than the original Cocoa. A programming framework has a kind of personality, an overall flavor that provides an insight into the goals and mindset of those who created it. When I first encountered Cocoa Touch, my assessment of its personality was: “Wow, the people who wrote this are really clever!” On the one hand, the number of built-in interface widgets was severely and deliberately limited; on the other hand, the power and flexibility of some of those widgets, especially such things as UITableView, was greatly enhanced over their Mac OS X counterparts. Even more important, Apple created a particularly brilliant way (UIViewController) to help the programmer make entire blocks of interface come and go and supplant one another in a controlled, hierarchical manner, thus allowing that tiny iPhone display to unfold virtually into multiple interface worlds within a single app without the user becoming lost or confused. Even more impressive, Apple took the opportunity to recreate and rationalize Cocoa from the ground up as Cocoa Touch. Cocoa itself is very old, having begun life as NeXTStep before Mac OS X even existed. It has grown by accretion and with a certain conservatism in order to maintain something like backward compatibility. With Cocoa Touch, on the other hand, Apple had the opportunity to throw out the baby with the bath water, and they seized this opportunity with both hands. So, although Cocoa Touch is conceptually based on Mac OS X Cocoa, it is very clearly not Mac OS X Cocoa, nor is it limited or defined by Mac OS X Cocoa. It’s an independent creature, a leaner, meaner, smarter Cocoa. I could praise Cocoa Touch’s deliberate use of systematization (and its healthy respect for Occam’s Razor) through numerous ex‐ xvii amples. Where Mac OS X’s animation layers are glommed onto views as a kind of af‐ terthought, a Cocoa Touch view always has an animation layer counterpart. Memory management policies, such as how top-level objects are managed when a nib loads, are simplified and clarified. And so on. At the same time, Cocoa Touch is still a form of Cocoa. It still requires a knowledge of Objective-C. It is not a scripting language; it is certainly not aimed at nonprogrammers, like HyperCard’s HyperTalk or Apple’s AppleScript. It is still huge and complicated. In fact, it’s rather difficult. The popularity of the iPhone, with its largely free or very inexpensive apps, and the subsequent popularity of the iPad, have brought and will continue to bring into the fold many new programmers who see programming for these devices as worthwhile and doable, even though they may not have felt the same way about Mac OS X. Apple’s own annual WWDC developer conventions have reflected this trend, with their emphasis shifted from Mac OS X to iOS instruction. The widespread eagerness to program iOS, however, though delightful on the one hand, has also fostered a certain tendency to try to run without first learning to walk. iOS gives the programmer mighty powers that can seem as limitless as imagination itself, but it also has fundamentals. I often see questions online from programmers who are evidently deep into the creation of some interesting app, but who are stymied in a way that reveals quite clearly that they are unfamiliar with the basics of the very world in which they are so happily cavorting. It is this state of affairs that has motivated me to write this book, which is intended to ground the reader in the fundamentals of iOS. I love Cocoa and have long wished to write about it, but it is iOS and its popularity that has given me a proximate excuse to do so. Indeed, my working title was “Fundamentals of Cocoa Touch Programming.” Here I have attempted to marshal and expound, in what I hope is a pedagogically helpful and instructive yet ruthlessly Euclidean and logical order, the principles on which sound iOS programming rests, including a good basic knowledge of Objective-C (starting with C itself) and the nature of object-oriented programming, advice on the use of the tools, the full story on how Cocoa objects are instantiated, referred to, put in communication with one another, and managed over their lifetimes, and a survey of the primary interface widgets and other common tasks. My hope, as with my previous books, is that you will both read this book cover to cover (learning something new often enough to keep you turning the pages) and keep it by you as a handy reference. This book is not intended to disparage Apple’s own documentation and example projects. They are wonderful resources and have become more wonderful as time goes on. I have depended heavily on them in the preparation of this book. But I also find that they don’t fulfill the same function as a reasoned, ordered presentation of the facts. The online documentation must make assumptions as to how much you already know; it can’t guarantee that you’ll approach it in a given order. And online documentation is xviii | Preface more suitable to reference than to instruction. A fully written example, no matter how well commented, is difficult to follow; it demonstrates, but it does not teach. A book, on the other hand, has numbered chapters and sequential pages; I can assume you know C before you know Objective-C for the simple reason that Chapter 1 precedes Chapter 2. And along with facts, I also bring to the table a degree of experience, which I try to communicate to you. Throughout this book you’ll see me referring to “common beginner mistakes”; in most cases, these are mistakes that I have made myself, in addition to seeing others make them. I try to tell you what the pitfalls are because I assume that, in the course of things, you will otherwise fall into them just as naturally as I did as I was learning. You’ll also see me construct many examples piece by piece or extract and explain just one tiny portion of a larger app. It is not a massive finished program that teaches programming, but an exposition of the thought process that developed that program. It is this thought process, more than anything else, that I hope you will gain from reading this book. iOS is huge, massive, immense. It’s far too big to be encompassed in a book even of this size. And in any case, that would be inappropriate and unnecessary. There are entire areas of Cocoa Touch that I have ruthlessly avoided discussing. Some of them would require an entire book of their own. Others you can pick up well enough, when the time comes, from the documentation. This book is only a beginning — the fundamentals. But I hope that it will be the firm foundation that will make it easier for you to tackle whatever lies beyond, in your own fun and rewarding iOS programming future. Conventions Used in This Book The following typographical conventions are used in this book: Italic Indicates new terms, URLs, email addresses, filenames, and file extensions. Constant width Used for program listings, as well as within paragraphs to refer to program elements such as variable or function names, databases, data types, environment variables, statements, and keywords. Constant width bold Shows commands or other text that should be typed literally by the user. Constant width italic Shows text that should be replaced with user-supplied values or by values deter‐ mined by context. Preface | xix This icon signifies a tip, suggestion, or general note. This icon indicates a warning or caution. Using Code Examples This book is here to help you get your job done. In general, you may use the code in this book in your programs and documentation. You do not need to contact us for permission unless you’re reproducing a significant portion of the code. For example, writing a program that uses several chunks of code from this book does not require permission. Selling or distributing a CD-ROM of examples from O’Reilly books does require permission. Answering a question by citing this book and quoting example code does not require permission. Incorporating a significant amount of example code from this book into your product’s documentation does require permission. We appreciate, but do not require, attribution. An attribution usually includes the title, author, publisher, and ISBN. For example: “Programming iOS 6 by Matt Neuburg (O’Reilly). Copyright 2013 Matt Neuburg, 978-1-449-36576-9.” If you feel your use of code examples falls outside fair use or the permission given above, feel free to contact us at [email protected]. Safari® Books Online Safari Books Online is an on-demand digital library that lets you easily search over 7,500 technology and creative reference books and videos to find the answers you need quickly. With a subscription, you can read any page and watch any video from our library online. Read books on your cell phone and mobile devices. Access new titles before they are available for print, and get exclusive access to manuscripts in development and post feedback for the authors. Copy and paste code samples, organize your favorites, down‐ load chapters, bookmark key sections, create notes, print out pages, and benefit from tons of other time-saving features. O’Reilly Media has uploaded this book to the Safari Books Online service. To have full digital access to this book and others on similar topics from O’Reilly and other pub‐ lishers, sign up for free at http://my.safaribooksonline.com. xx | Preface How to Contact Us Please address comments and questions concerning this book to the publisher: O’Reilly Media, Inc. 1005 Gravenstein Highway North Sebastopol, CA 95472 800-998-9938 (in the United States or Canada) 707-829-0515 (international or local) 707-829-0104 (fax) We have a web page for this book, where we list errata, examples, and any additional information. You can access this page at: http://oreil.ly/programming_ios_6_3e To comment or ask technical questions about this book, send email to: [email protected] For more information about our books, courses, conferences, and news, see our website at http://www.oreilly.com. Find us on Facebook: http://facebook.com/oreilly Follow us on Twitter: http://twitter.com/oreillymedia Watch us on YouTube: http://www.youtube.com/oreillymedia Acknowledgments for the First Edition It’s a poor craftsman who blames his tools. No blame attaches to the really great tools by which I have been assisted in the writing of this book. I am particularly grateful to the Unicomp Model M keyboard (http://pckeyboard.com), without which I could not have produced so large a book so painlessly. I was also aided by wonderful software, including TextMate (http://macromates.com) and AsciiDoc (http://www.methods.co.nz/ asciidoc). BBEdit (http://www.barebones.com) helped with its diff display. Screenshots were created with Snapz Pro X (http://www.ambrosiasw.com) and GraphicConverter (http://www.lemkesoft.com); diagrams were drawn with OmniGraffle (http:// www.omnigroup.com). The splendid O’Reilly production process converted my AsciiDoc text files into PDF while I worked, allowing me to proofread in simulated book format. Were it not for this, and the Early Release program that permitted me to provide my readers with periodic updates of the book as it grew, I would never have agreed to undertake this project in the first place. I would like particularly to thank Tools maven Abby Fox for her constant assistance. Preface | xxi I have taken advice from two tech reviewers, Dave Smith and David Rowland, and have been assisted materially and spiritually by many readers who submitted errata and en‐ couragement. I was particularly fortunate in having Brian Jepson as editor; he provided enthusiasm for the O’Reilly tools and the electronic book formats, a watchful eye, and a trusting attitude; he also endured the role of communications pipeline when I needed to prod various parts of the O’Reilly machine. I have never written an O’Reilly book without the help of Nancy Kotary, and I didn’t intend to start now; her sharp eye has smoothed the bristles of my punctuation-laden style. For errors that remain, I take responsibility, of course. Notes on the Second Printing For the second printing of this book, screenshots have been rendered more legible, and a major technical error in the presentation of key–value coding in Chapter 5 has been corrected. In addition, numerous small emendations have been made; many of these have resulted from errata submissions by my readers, whom I should like to thank once again for their continued assistance and kind support. Please note that these changes have altered the pagination of the printed and PDF editions of the book. Acknowledgments for the Second Edition Not surprisingly, I’d like to thank once again my editor, Brian Jepson, who made me write this new edition. You can put down the whip now, Brian. Thanks also to the O’Reilly team for their many-faceted assistance, and always to my readers for their enthusiasm, encouragement, loyalty, and suggestions. Notes on the Second Edition In order to describe the relationship of the second edition of this book with the first edition, it will help if I first recap the recent history of iOS and Xcode versions. At the time I started writing the first edition this book, system versions 3.1.3 (on the iPhone) and 3.2 (on the iPad) were current. As I was working on the book, iOS 4 and the iPhone 4 came into being, but iOS 4 didn’t yet run on the iPad. Subsequently iOS 4.2 emerged; this was the first system able to run on both the iPhone and the iPad. At the same time, Xcode was improved up to 3.2.5. iOS 4 was the first version of the system to support multitasking, which necessitated much scurrying about on the part of de‐ velopers, to adapt their apps to the new world order. Just in time for my final revisions of the first edition, Xcode 3.2.6 and iOS 4.3 were released, along with the first public version of the long-awaited Xcode 4. Xcode 4 was a thorough overhaul of the IDE: menus, windows, and preferences are quite different from Xcode 3.2.x. Both Xcode 4 and Xcode 3.2.x can coexist on the same machine (up through Snow Leopard) and can be used to work on the same project; moreover, Xcode xxii | Preface 3.2.x has some specialized capabilities that Xcode 4 lacks, so some long-standing de‐ velopers may well continue to use it. This situation presents a dilemma for an author describing the development process. However, for iOS programming, I recommend adoption of Xcode 4, and the first edition of this book assumed that the reader had adopted it. Such was the situation in May 2011, when the first edition was formally released, de‐ scribing how to program iOS 4. Less than five months later, in October 2011, Apple released iOS 5. Some of the features that are new in iOS 5 are dramatic and pervasive, and it is this fact which has necessitated a full revision of this book. At the same time, Apple also released Xcode 4.2, and this book assumes that you are using that version of Xcode (or later), since it is the earliest version of Xcode on which iOS 5 development is officially possible. (It may be that, by deep trickery, one can develop for iOS 5 using an earlier version of Xcode, but that would constitute unsupported behavior.) The first edition had a few mentions of menu commands and other interface in Xcode 3.2.x, but they have been excised from this edition. Xcode 4.2 comes in two flavors, depending whether you’re running Snow Leopard (Mac OS X 10.6) or Lion (Mac OS X 10.7) on your development machine; they are supposed to behave more or less identically, but in fact each has its own bugs, so feel free to try both. As I was finishing the second edition, in February 2012, Xcode 4.3 was released (for Lion only). Its chief innovation has to do with the organization of files on disk: instead of arriving as an installer that creates a top-level Developer folder to hold its many ancillary files and folders, Xcode 4.3 contains the Developer folder inside its file package (you can see it with the Finder’s Show Package Contents command). So when I speak of the Developer folder in this book, you would need to understand that I mean some‐ thing like /Applications/Xcode.app/Contents/Developer. I have not found any other ma‐ jor differences between Xcode 4.2 and Xcode 4.3, and in this book I will sometimes say “Xcode 4.2” to mean Xcode 4.2 or later. The chief purpose of this new edition, then, is to bring the book up to date for iOS 5. You, the reader, might be coming to iOS programming for the first time, so this edition assumes no prior knowledge of iOS 4 or any previous version. On the other hand, you, like me, could be making the transition from iOS 4 to iOS 5, so this edition lays some special emphasis on features that are new in iOS 5. This emphasis could also be useful to new iOS programmers who are thinking of writing apps that can also run under iOS 4. My goal, however, is not to burden the reader with outdated information. The vast majority of devices that could run iOS 4 have probably been updated to iOS 5, and you will probably be right in assuming that there will plenty of iOS 5 users out there, without your having to bother to target earlier systems. And from a pedagogical point of view, it seems counterproductive to describe how things used to be — especially as, if you’re really interested, you can always consult the previous edition of this book! For this Preface | xxiii reason, some references to the state of things before iOS 4.2 have been excised from this edition. Here is a case in point, showing my attitude and pedagogical approach with regard to new iOS 5 features in this edition. iOS 5 introduces ARC (automatic reference counting), which changes the way in which Objective-C programmers manage object memory so profoundly as to render Objective-C a different language. Use of ARC is optional in programming iOS, but it is extraordinarily helpful to have it turned on, and in this book I therefore assume throughout that you do have it turned on. In Chapter 12, where I discuss memory management, I still describe what life is like without ARC, as I did in the previous edition; but, outside that chapter, all code examples, unless specifically stated otherwise, are supposed to be running under ARC. If you start a new Xcode project with File → New Project and pick any iOS application template, then if “Use Automatic Reference Counting” is checked in the second screen, you’re using ARC. iOS 5 also introduces storyboards. A storyboard file is similar to a nib file: it’s a place where Xcode lets you “draw” parts of the interface. The main difference is that a single storyboard file can do the work of multiple nib files. Nib files and storyboard files are not identical, nor are they used identically, but because of their similarity, when I speak of a nib file generically, in this book, I mean a nib or storyboard file, indifferently. I’ll try to indicate this at the time, but the reader will forgive me if I don’t keep saying “nib or storyboard” all the time. In closing, I should like to say a few words to the people who have, in my opinion, gratuitously criticized the previous edition of this book on one or more of the following grounds: a. It isn’t a “cookbook” (a book full of step-by-step instructions for creating full work‐ ing applications). b. It devotes hundreds of pages to fundamentals. c. It doesn’t get the reader started early on with hands-on programming; there isn’t even a “Hello, World” tutorial. All of that is perfectly true. It is also quite deliberate. As both the table of contents and this preface are at pains to make clear, this is not that type of book. To paraphrase Butler’s Law, this book is the type of book it is, and not some other type. That’s why I wrote this book in the first place. The books of the type that these critics seem to want this book to be exist by the score; books of the type that this book is, however, seemed to me not to exist at all. As with all my other books, so with this one: when I couldn’t find the book I wanted, I wrote it myself. I expect this book to be useful to those who need this type of book. People who prefer some other type of book should get some other type of book, and not mar my book’s web page by criticizing it for not being what it was never intended to be. xxiv | Preface The purpose of this book is to proceed by focusing on the underlying knowledge needed for an actual understanding of iOS programming. That is precisely the opposite of a cookbook. This book has no simple recipes ready for you to drop into your own code and come up with an app. I don’t give you some fish; I teach you what a fish is and what you need to know to obtain one. The number of books out there that skip blithely past the fundamentals, leaving the reader to pick up Objective-C somehow independently, is painfully huge. The result is that numerous learners are encouraged to try their hand at programming when, to judge from the nature of the questions they ask and the con‐ fusion they exhibit, they don’t understand what they are doing. This book acts as a corrective, which in turn requires that space be devoted to funda‐ mentals. The book does not hold a gun to your head and force you to read all about all of those fundamentals; if you already know everything there is to know about C, about Objective-C, about Xcode, about Cocoa, about views and drawing or whatever (but do you? do you really?), then by all means, skip those opening chapters. But don’t begrudge to the people who need them the explanations that this book contains, as those are the people at whom they are aimed. That explains why there’s no attempt, in this book, to rush the reader into hands-on programming. My book does not pander to a desire for the false, cheap gratification of making believe that one is a programmer merely because one can parrot some instruc‐ tions. My book is about knowledge — hard-won, rigorously gained knowledge. It’s about gaining an understanding of what you are doing when you program iOS 5. It calls for a substantial investment of time and thought, and many pages elapse before any practical programming is demonstrated. Perhaps part of the misunderstanding here is that the critic has not noticed, or has not understood, the sentence earlier in this Preface stating that my book is written in “a pedagogically helpful and instructive yet ruthlessly Euclidean and logical order.” Some people may not know or appreciate what “Euclidean” means. It means “in the manner of Euclid.” Euclid wrote our first surviving mathematical textbook, and it is distin‐ guished by the following remarkable characteristic, among others: if concept or asser‐ tion B depends upon concept or assertion A, A comes first. Nothing is postponed; Euclid never says, “I’ll explain/prove/discuss this point later, but for now, just take my word for it.” I have attempted to copy Euclid’s model. So, to take an obvious example, all real iOS apps use view controllers. It’s true, then, that the reader isn’t told what’s involved in constructing a real iOS app until Chapter 19 is reached and view controllers are dis‐ cussed. But to understand view controllers, you need to know what’s being controlled, namely, a view; hence Chapter 14 and the rest of Part IV. And to grasp the relationship between a view controller and its view, you need to know about Cocoa’s architectural patterns, such as lifetime events and the responder chain; hence Chapter 11 and the rest of Part III. Moreover, a view controller’s view is often loaded from a nib; hence Chap‐ ter 7. And all of that requires a knowledge of the programming language you’ll be using, Preface | xxv Objective-C; hence Chapter 3. But Objective-C is C; hence Chapter 1. So to reach view controllers any sooner would have been impossible. I rest my case. Anyway, the complaint that the reader of my book doesn’t get to run any code is factually false. The book is crammed full of substantial code examples — all of which are available for download from my GitHub site (https://github.com/mattneub), so you can obtain them, run them in Xcode, and play with them to your heart’s content. So you can and should, in fact, be running code right from the outset. Nevertheless, the purpose of the code in this book is not for the fun of running it. All of my code is to support your understanding of whatever concepts I’m explaining at that point in the book. In any case, perfectly good hands-on “Hello, World” tutorials are a dime a dozen; they’re plastered all over the Internet, including at Apple’s own site (http://developer.apple.com/ library/ios/#documentation/iPhone/Conceptual/iPhone101/Articles/). You don’t need me to show you that the process of writing a trivial iPhone application is fun and easy. Still, for those who feel strongly that I haven’t done my job unless I supply a “Hello, World” example, here is one, complete with step-by-step instructions: 1. Install Xcode, and launch the Xcode application. 2. Choose File → New → Project. 3. In the “Choose a template” dialog, under “iOS” on the left (not “Mac OS X”), click Application. On the right, click Empty Application. Click Next. 4. For Product Name, type Hello. Enter a company identifier if there isn’t one already, such as com.yourLastName.yourFirstName. Choose Device Family: iPhone. Un‐ check all three checkboxes. Click Next. 5. Navigate to the Desktop. Uncheck “Create local git repository.” Click Create. 6. The project window opens. Press Command-1. At the left, click AppDelegate.m. 7. Work in the editor in the middle of the window. Look for the words “Override point for customization after application launch.” Place the cursor to the right of those words and hit Return a few times, to make some white space. Click in that white space and type these lines of code: UILabel* label = [[UILabel alloc] init]; label.text = @"Hello, world!"; [label sizeToFit]; CGRect f = label.frame; f.origin = CGPointMake(100,100); label.frame = f; [self.window addSubview:label]; 8. Press Command-R. If you see a dialog asking whether you want to save, accept. 9. After a while, the iOS Simulator application appears, containing a white window with “Hello, world!” in it. xxvi | Preface Congratulations. You’ve made a “Hello, world” example. Wasn’t that easy? Wasn’t it boring? Wasn’t it pointless? And are you any the wiser as to what, in fact, you just did? To find out — and, even more important, to know enough to be able to progress further on your own — read this book. Acknowledgments for the Third Edition This edition was written in the full public gaze, and I’d like to thank, as always, my many sharp-eyed readers who assisted me by spotting mistakes and making suggestions. I would also like to say a word for wonderful, wonderful git (http://git-scm.com), as well as the extraordinary SourceTree (http://www.sourcetreeapp.com). At O’Reilly Media, I am grateful to XSL and CSS wizard Sarah Schneider, who brilliantly and quickly tweaked the automated layout process to make this book look great in printed and PDF form. Notes on the Third Edition Shortly after the official release of iOS 6 and Xcode 4.5, I began revising the code ex‐ amples in this book (available at https://github.com/mattneub) to use and demonstrate the new iOS features. When that was done, I proceeded to rewrite the book text; while I was doing so, iOS 6.1 and Xcode 4.6 were released, so those are the versions that the book now assumes you’re using. For this third edition, I have eliminated most references to previous iOS versions. Many iOS 6 features, of course, do not exist in iOS 5 or before; I usually mention that a new feature is new, but I have not generally addressed the problem of writing backwardscompatible code. The text would become confusing and bloated if everything had to be qualified with advice for different versions (“but if you’re targeting iOS 5.1, do this; if you’re targeting iOS 5.0, do that; if you’re targeting iOS 4.3, do the other”). I believe I can justify such omission on the grounds that the previous editions of this book exist! If you’re targeting iOS 5, I’ve already described what to do, in the second edition; there’s no need to repeat myself here. New iOS 6 features are, of course, both explained and adopted in this edition. For ex‐ ample, having described NSArray subscripting (in Chapter 10), I then use it consistently, in place of objectAtIndex:, throughout the rest of the book. Aside from this, the book’s structure remains the same as in previous editions, growing where necessary to ac‐ commodate explanations of new features, such as autolayout (in Chapter 14), state re‐ storation (in Chapter 19), and collection views (in Chapter 21). Also, in response to reader requests, I have inserted a short example of Core Data programming into Chap‐ ter 36. Preface | xxvii PART I Language Apple has provided a vast toolbox for programming iOS to make an app come to life and behave the way you want it to. That toolbox is the API (application programming interface). To use the API, you must speak the API’s language. That language, for the most part, is Objective-C, which itself is built on top of C; some pieces of the API use C itself. This part of the book instructs you in the basics of these languages: • Chapter 1 explains C. In general, you will probably not need to know all the ins and outs of C, so this chapter restricts itself to those aspects of C that you need to know in order to use both Objective-C and the C-based areas of the API. • Chapter 2 prepares the ground for Objective-C, by discussing object-based pro‐ gramming in general architectural terms. It also explains some extremely important words that will be used throughout the book, along with the concepts that lie behind them. • Chapter 3 introduces the basic syntax of Objective-C. • Chapter 4 continues the explanation of Objective-C, discussing the nature of Objective-C classes, with emphasis on how to create a class in code. • Chapter 5 completes the introduction to Objective-C, discussing how instances are created and initialized, along with an explanation of such related topics as poly‐ morphism, instance variables, accessors, self and super, key–value coding, and properties. We’ll return in Part III to a description of further aspects of the Objective-C language — those that are particularly bound up with the Cocoa frameworks. CHAPTER 1 Just Enough C Do you believe in C? Do you believe in anything that has to do with me? —Leonard Bernstein and Stephen Schwartz, Mass To program for iOS, you need to speak to iOS. Everything you say to iOS will be in accordance with the iOS API. (An API, for application programming interface, is a list or specification of things you are allowed to say when communicating.) Therefore, you will need some knowledge of the C programming language, for two reasons: • Most of the iOS API involves the Objective-C language, and most of your iOS programming will be in the Objective-C language; and Objective-C is a superset of C. This means that Objective-C presupposes C; everything that is true of C trickles up to Objective-C. A common mistake is to forget that “Objective-C is C” and to neglect a basic understanding of C. • Some of the iOS API involves C rather than Objective-C. Even in Objective-C code, you often need to use C data structures and C function calls. For example, a rectangle is represented as a CGRect, which is a C struct, and to create a CGRect from four numbers you call CGRectMake, which is a C function. The iOS API documentation will very often show you C expressions and expect you to understand them. The best way to learn C is to read The C Programming Language (PTR Prentice Hall, 1988) by Brian W. Kernighan and Dennis M. Ritchie, commonly called K&R (Ritchie was the creator of C). It is one of the best computer books ever written: brief, dense, and stunningly precise and clear. K&R is so important for effective iOS (and Mac OS X) programming that I keep a physical copy beside me at all times while coding, and I recommend that you do the same. Another useful manual is The C Book, by Mike Banahan, Declan Brady and Mark Doran, available online at http://publications.gbdir ect.co.uk/c_book/. 3 It would be impossible, and unnecessary, for me to describe all of C in a single chapter. C is not a large or difficult language, but it has some tricky corners and can be extremely subtle, powerful, and low-level. Moreover, since C is described fully and correctly in the manuals I’ve just mentioned, it would be a mistake for me to repeat what they can tell you better than I. You don’t have to know all about C in order to use Objective-C effectively, though; so my purpose in this chapter is to outline those aspects of C that are important for you to understand at the outset, before you even start using Objective-C for iOS programming. That’s why this chapter is “Just Enough C”: it’s just enough to get you going, comfortably and safely. Just keep in mind that this chapter is not a technical manual of C. If you know no C at all, I suggest that, as an accompaniment to this chapter, you also read select parts of K&R (think of this as “C: The Good Parts Version”). Here’s my proposed K&R syllabus: • Quickly skim K&R Chapter 1, the tutorial. • Carefully read K&R Chapters 2 through 4. • Read the first three sections of K&R Chapter 5 on pointers and arrays. You don’t need to read the rest of Chapter 5 because you won’t typically be doing any pointer arithmetic, but you do need to understand clearly what a pointer is, as ObjectiveC is all about objects, and every reference to an object is a pointer; you’ll be seeing and using that * character constantly. • Read also the first section of K&R Chapter 6, on structures (structs); as a beginner, you probably won’t define any structs, but you will use them quite a lot, so you’ll need to know the notation (for example, as I’ve already said, a CGRect is a struct). • Glance over K&R Appendix B, which covers the standard library, because you may find yourself making certain standard library calls, such as the mathematical func‐ tions; forgetting that the library exists is a typical beginner mistake. Just to make things a little more confusing, the C defined in K&R is not precisely the C that forms the basis of Objective-C. Developments subsequent to K&R have resulted in further C standards (ANSI C, C89, C99), and the Xcode compiler extends the C language in its own ways. By default, Xcode projects are treated as GNU99, which is itself an extension of C99 (though you could specify another C standard if you really wanted to). Fortunately, the most important differences between K&R’s C and Xcode’s C are small, convenient improvements that are easily remembered, so K&R remains the best and most reliable C reference. 4 | Chapter 1: Just Enough C Compilation, Statements, and Comments C is a compiled language. You write your program as text; to run the program, things proceed in two stages. First your text is compiled into machine instructions; then those machine instructions are executed. Thus, as with any compiled language, you can make two kinds of mistake: • Any purely syntactic errors (meaning that you spoke the C language incorrectly) will be caught by the compiler, and the program won’t even begin to run. • If your program gets past the compiler, then it will run, but there is no guarantee that you haven’t made some other sort of mistake, which can be detected only by noticing that the program doesn’t behave as intended. The C compiler is fussy, but you should accept its interference with good grace. The compiler is your friend: learn to love it. It may emit what looks like an irrelevant or incomprehensible error message, but when it does, the fact is that you’ve done some‐ thing wrong and the compiler has helpfully caught it for you. Also, the compiler can warn you if something seems like a possible mistake, even though it isn’t strictly illegal; these warnings, which differ from outright errors, are also helpful and should not be ignored. I have said that running a program requires a preceding stage: compilation. But in fact there is a third stage that precedes compilation: preprocessing. (It doesn’t really matter whether you think of preprocessing as a stage preceding compilation or as the first stage of compilation.) Preprocessing modifies your text, so when your text is handed to the compiler, it is not identical to the text you wrote. Preprocessing might sound tricky and intrusive, but in fact it proceeds only according to your instructions and is helpful for making your code clearer and more compact. Xcode allows you to view the effects of preprocessing on your program text (choose Product → Generate Output → Preprocessed File), so if you think you’ve made a mistake in instructing the preprocessor, you can track it down. I’ll talk more later about some of the things you’re likely to say to the preprocessor. C is a statement-based language; every statement ends in a semicolon. (Forgetting the semicolon is a common beginner’s mistake.) For readability, programs are mostly writ‐ ten with one statement per line, but this is by no means a hard and fast rule: long statements (which, unfortunately, arise very often because of Objective-C’s verbosity) are commonly split over multiple lines, and extremely short statements are sometimes written two or three to a line. You cannot split a line just anywhere, however; for example, a literal string can’t contain a return character. Indentation is linguistically meaningless and is purely a matter of convention (and C programmers argue over those conventions with near-religious fervor); Xcode helps “intelligently” by indenting automatically, and Compilation, Statements, and Comments | 5 Choosing a Compiler The compiler situation in Xcode is rather complicated. Originally, Xcode’s compiler was the free open source GCC (http://gcc.gnu.org). More recently, Xcode has phased in use of another free open source compiler, LLVM (http://llvm.org). Changing compilers is scary, so Apple has proceeded in stages, as follows: • A hybrid compiler, LLVM-GCC, provides the advantages of LLVM compilation, but the code is parsed with GCC for maximum backward compatibility. • A pure LLVM compiler (also referred to as Clang) does its own parsing and provides more intelligent and helpful error messages and warnings. As Xcode 3.2.x evolved, LLVM-GCC was eventually considered the best choice, but Apple was hesitant to make it the default compiler, so GCC remained the default. When Xcode 4 emerged, LLVM-GCC was the default compiler, but GCC remained available. Finally, in Xcode 4.2, LLVM 3.0 became the default compiler, and pure GCC was with‐ drawn; in Xcode 4.6, LLVM has advanced to version 4.2. (The choice of compiler is a project-level build setting; see Chapter 6.) you can use its automatic indentation both to keep your code readable and to confirm that you’re not making any basic syntactic mistakes. Comments are delimited in K&R C by /* ... */; the material between the delimiters can consist of multiple lines (K&R 1.2). In modern versions of C, a comment also can be denoted by two slashes (//); the rule is that if two slashes appear, they and everything after them on the same line are ignored: int lower = 0; // lower limit of temperature table These are sometimes called C++-style comments and are much more convenient for brief comments than the K&R comment syntax. Throughout the C language (and therefore, throughout Objective-C as well), capitali‐ zation matters. All names are case-sensitive. There is no such data type as Int; it’s low‐ ercase “int.” If you declare an int called lower and then try to speak of the same variable as Lower, the compiler will complain. By convention, variable names tend to start with a lowercase letter. Variable Declaration, Initialization, and Data Types C is a strongly typed language. Every variable must be declared, indicating its data type, before it can be used. Declaration can also involve explicit initialization, giving the variable a value; a variable that is declared but not explicitly initialized is of uncertain value (and should be regarded as dangerous until it is initialized). In K&R C, declarations 6 | Chapter 1: Just Enough C must precede all other statements, but in modern versions of C, this rule is relaxed so that you don’t have to declare a variable until just before you start using it: int height = 2; int width = height * 2; height = height + 1; int area = height * width; The basic built-in C data types are all numeric: char (one byte), int (four bytes), float and double (floating-point numbers), and varieties such as short (short integer), long (long integer), unsigned short, and so on. A numeric literal may optionally express its type through a suffixed letter or letters: for example, 4 is an int, but 4UL is an unsigned long; 4.0 is a double, but 4.0f is a float. Objective-C makes use of some further numeric types derived from the C numeric types (by way of the typedef statement, K&R 6.7) designed to respond to the question of whether the processor is 64-bit; the most im‐ portant of these are NSInteger (along with NSUInteger) and CGFloat. You don’t need to use them explicitly unless an API tells you to, and even when you do, just think of NSInteger as int and CGFloat as float, and you’ll be fine. To cast (or typecast) a variable’s value explicitly to another type, precede the variable’s name with the other type’s name in parentheses: int height = 2; float fheight = (float)height; In that particular example, the explicit cast is unnecessary because the integer value will be cast to a float implicitly as it is assigned to a float variable, but it illustrates the notation. You’ll find yourself typecasting quite a bit in Objective-C, mostly to subdue the worries of the compiler (examples appear in Chapter 3). Another form of numeric initialization is the enum (K&R 2.3). It’s a way of assigning names to a sequence of numeric values and is useful when a value represents one of several possible options. The Cocoa API uses this device a lot. For example, the three possible types of status bar animation are defined like this: typedef enum { UIStatusBarAnimationNone, UIStatusBarAnimationFade, UIStatusBarAnimationSlide, } UIStatusBarAnimation; That definition assigns the value 0 to the name UIStatusBarAnimationNone, the value 1 to the name UIStatusBarAnimationFade, and the value 2 to the name UIStatusBarAnimationSlide. The upshot is that you can use the suggestively meaningful names without caring about, or even knowing, the arbitrary numeric values they represent. It’s a useful idiom, and you may well have reason to define enums in your own code. Variable Declaration, Initialization, and Data Types | 7 Modern Enum Notation Starting with LLVM compiler version 4.0, which made its debut in Xcode 4.4, ObjectiveC extends the enum notation ever so slightly. The status bar animation types, for ex‐ ample, are now defined like this: typedef NS_ENUM(NSInteger, UIStatusBarAnimation) { UIStatusBarAnimationNone, UIStatusBarAnimationFade, UIStatusBarAnimationSlide, }; NS_ENUM is a macro, a form of preprocessor text substitution discussed at the end of this chapter; when the text substitution is performed, that code turns out to be shorthand for this: typedef enum UIStatusBarAnimation : NSInteger UIStatusBarAnimation; enum UIStatusBarAnimation : NSInteger { UIStatusBarAnimationNone, UIStatusBarAnimationFade, UIStatusBarAnimationSlide, }; That looks almost exactly like the old way of expressing the same enum, but the new way involves some notation that isn’t part of standard C, telling the compiler what variety of integer value is being used here (it’s an NSInteger). This makes UIStatusBarAnimation a little more like a genuine data type. It also lets Xcode help you more intelligently — for example, when performing code completion, as discussed in Chapter 9. Another macro, NS_OPTIONS, evaluates in Objective-C as a synonym of NS_ENUM (they are distinct only in C++ code, which is not discussed in this book). There appears to be a native text type (a string) in C, but this is something of an illusion; behind the scenes, it is actually a null-terminated array of char. For example, in C you can write a string literal like this: "string" But in fact this is stored as 7 bytes, the numeric (ASCII) equivalents of each letter fol‐ lowed by a byte consisting of 0 to signal the end of the string. This data structure, called a C string, is rarely encountered while programming iOS. In general, when working with strings, you’ll use an Objective-C object type called NSString. An NSString is totally different from a C string; it happens, however, that Objective-C lets you write a literal NSString in a way that looks very like a C string: @"string" 8 | Chapter 1: Just Enough C Notice the at-sign! This expression is actually a directive to the Objective-C compiler to form an NSString object. A common mistake is forgetting the at-sign, thus causing your expression to be interpreted as a C string, which is a completely different animal. Because the notation for literal NSStrings is modeled on the notation for C strings, it is worth knowing something about C strings, even though you won’t generally encounter them. For example, K&R lists a number of escaped characters (K&R 2.3), which you can also use in a literal NSString, including the following: \n A Unix newline character \t A tab character \" A quotation mark (escaped to show that this is not the end of the string literal) \\ A backslash NSStrings are natively Unicode-based, but because Objective-C is C, including non-ASCII characters in a literal NSString was, until quite recently, remarkably tricky, and you needed to know about such things as the \x and \u escape sequences. Now, however, it is perfectly legal to type a non-ASCII character directly into an NSString literal, and you should ignore old Internet postings (and even an occasional sentence in Apple’s own documentation) warning that it is not. K&R also mention a notation for concatenating string literals, in which multiple string literals separated only by white space are automatically concatenated and treated as a single string literal. This notation is useful for splitting a long string into multiple lines for legibility, and Objective-C copies this convention for literal NSStrings as well, except that you have to remember the at-sign: @"This is a big long literal string " @"which I have broken over two lines of code."; Structs C offers few simple native data types, so how are more complex data types made? There are three ways: structures, pointers, and arrays. Both structures and pointers are going to be crucial when you’re programming iOS. You’re less likely to need a C array, because Objective-C has its own NSArray object type, but it will arise in a couple of examples later in this book. Structs | 9 A C structure, usually called a struct (K&R 6.1), is a compound data type: it combines multiple data types into a single type, which can be passed around as a single entity. Moreover, the elements constituting the compound entity have names and can be ac‐ cessed by those names through the compound entity, using dot-notation. The iOS API has many commonly used structs, typically accompanied by convenience functions for working with them. For example, the iOS documentation tells you that a CGPoint is defined as follows: struct CGPoint { CGFloat x; CGFloat y; }; typedef struct CGPoint CGPoint; Recall that a CGFloat is basically a float, so this is a compound data type made up of two simple native data types; in effect, a CGPoint has two CGFloat parts, and their names are x and y. (The rather odd-looking last line merely asserts that one can use the term CGPoint instead of the more verbose struct CGPoint.) So we can write: CGPoint myPoint; myPoint.x = 4.3; myPoint.y = 7.1; Just as we can assign to myPoint.x to set this part of the struct, we can say myPoint.x to get this part of the struct. It’s as if myPoint.x were the name of a variable. Moreover, an element of a struct can itself be a struct, and the dot-notation can be chained. To illustrate, first note the existence of another iOS struct, CGSize: struct CGSize { CGFloat width; CGFloat height; }; typedef struct CGSize CGSize; Put a CGPoint and a CGSize together and you’ve got a CGRect: struct CGRect { CGPoint origin; CGSize size; }; typedef struct CGRect CGRect; So suppose we’ve got a CGRect variable called myRect, already initialized. Then myRect.origin is a CGPoint, and myRect.origin.x is a CGFloat. Similarly, myRect.size is a CGSize, and myRect.size.width is a CGFloat. You could change just the width part of our CGRect directly, like this: myRect.size.width = 8.6; 10 | Chapter 1: Just Enough C Instead of initializing a struct by assigning to each of its elements, you can initialize it at declaration time by assigning values for all its elements at once, in curly braces and separated by commas, like this: CGPoint myPoint = { 4.3, 7.1 }; CGRect myRect = { myPoint, {10, 20} }; You don’t actually have to be assigning to a struct-typed variable to use a struct initializer; you can use an initializer anywhere the given struct type is expected, but you might also have to cast to that struct type in order to explain to the compiler what your curly braces mean, like this: CGContextFillRect(con, (CGRect){myPoint, {10, 20}}); In that example, CGContextFillRect is a function. I’ll talk about functions later in this chapter, but the upshot of the example is that what comes after the first comma has to be a CGRect, and can therefore be a CGRect initializer provided this is accompanied by a CGRect cast. Pointers The other big way that C extends its range of data types is by means of pointers (K&R 5.1). A pointer is an integer (of some size or other) with a meaning: it designates the location in memory where the real data is to be found. Knowing the structure of that data and how to work with it, as well as allocating a block of memory of the required size beforehand and disposing of that block of memory when it’s no longer needed, is a very complicated business. Luckily, this is exactly the sort of complicated business that Objective-C is going to take care of for us. So all you really have to know to use pointers is what they are and what notation is used to refer to them. Let’s start with a simple declaration. If we wanted to declare an integer in C, we could say: int i; That line says, “i is an integer.” Now let’s instead declare a pointer to an integer: int* intPtr; That line says, “intPtr is a pointer to an integer.” Never mind how we know there really is going to be an integer at the address designated by this pointer; here, I’m concerned only with the notation. It is permitted to place the asterisk in the declaration before the name rather than after the type: int *intPtr; You could even put a space on both sides of the asterisk (though this is rarely done): int * intPtr; Pointers | 11 I prefer the first form, but I do occasionally use the second form, and Apple quite often uses it, so be sure you understand that these are all ways of saying the same thing. No matter how the spaces are inserted, the name of the type is still int*. If you are asked what type is intPtr is, the answer is int* (a pointer to an int); the asterisk is part of the name of the type of this variable. If you needed to cast a variable p to this type, you’d cast like this: (int*)p. Once again, it is possible that you’ll see code where there’s a space before the asterisk, like this: (int *)p. Pointers are very important in Objective-C, because Objective-C is all about objects (Chapter 2), and every variable referring to an object is itself a pointer. For example, I’ve already mentioned that the Objective-C string type is called NSString. So the way to declare an NSString variable is as a pointer to an NSString: NSString* s; An NSString literal is an NSString value, so we can even declare and initialize this NSString object, thus writing a seriously useful line of Objective-C code: NSString* s = @"Hello, world!"; In pure C, having declared a pointer-to-integer called intPtr, you are liable to speak later in your code of *intPtr. This notation, outside of a declaration, means “the thing pointed to by the pointer intPtr.” You speak of *intPtr because you wish to access the integer at the far end of the pointer; this is called dereferencing the pointer. But in Objective-C, this is generally not the case. In your code, you’ll be treating the pointer to an object as the object; you’ll never dereference it. So, for example, having declared s as a pointer to an NSString, you will not then proceed to speak of *s; rather, you will speak simply of s, as if it were the string. All the Objective-C stuff you’ll want to do with an object will expect the pointer, not the object at the far end of the pointer; behind the scenes, Objective-C itself will take care of the messy business of following the pointer to its block of memory and doing whatever needs to be done in that block of memory. This fact is extremely convenient for you as a programmer, but it does cause Objective-C users to speak a little loosely; we tend to say that “s is an NSString,” when of course it is actually a pointer to an NSString. The logic of how pointers work, both in C and in Objective-C, is different from the logic of how simple data types work. The difference is particularly evident with assignment. Assignment to a simple data type changes the data value. Assignment to a pointer re‐ points the pointer. Suppose ptr1 and ptr2 are both pointers, and you say: ptr1 = ptr2; Now ptr1 and ptr2 are pointing at the same thing. Any change to the thing pointed to by ptr1 will also change the thing pointed to by ptr2, because they are the same thing (Figure 1-1). Meanwhile, whatever ptr1 was pointing to before the assignment is now not being pointed to by ptr1; it might, indeed, be pointed to by nothing (which could 12 | Chapter 1: Just Enough C Figure 1-1. Pointers and assignment be bad). A firm understanding of these facts is crucial when working in Objective-C, and I’ll return to this topic in Chapter 3. The most general type of pointer is pointer-to-void (void*), the generic pointer. It is legal to use a generic pointer wherever a specific type of pointer is expected. In effect, pointerto-void casts away type checking as to what’s at the far end of the pointer. Thus, the following is legal: Pointers | 13 int* p1; // and pretend p1 has a value void* p2; p2 = p1; p1 = p2; Arrays A C array (K&R 5.3) consists of multiple elements of the same data type. An array declaration states the data type of the elements, followed by the name of the array, along with square brackets containing the number of elements: int arr[3]; // means: arr is an array consisting of 3 ints To refer to an element of an array, use the array’s name followed by the element number in square brackets. The first element of an array is numbered 0. So we can initialize an array by assigning values to each element in turn: int arr[3]; arr[0] = 123; arr[1] = 456; arr[2] = 789; Alternatively, you can initialize an array at declaration time by assigning a list of values in curly braces, just as with a struct. In this case, the size of the array can be omitted from the declaration, because it is implicit in the initialization (K&R 4.9): int arr[] = {123, 456, 789}; Curiously, the name of an array is the name of a pointer (to the first element of the array). Thus, for example, having declared arr as in the preceding examples, you can use arr wherever a value of type int* (a pointer to an int) is expected. This fact is the basis of some highly sophisticated C idioms that you almost certainly won’t need to know about (which is why I don’t recommend that you read any of K&R Chapter 5 beyond section 3). C arrays rarely arise in practice when programming iOS, because you’ll work mostly with the NSArray object type instead. But here’s a case where they do. The function CGContextStrokeLineSegments is declared like this: void CGContextStrokeLineSegments ( CGContextRef c, const CGPoint points[], size_t count ); The second parameter is an array (meaning a C array) of CGPoints. That’s what the square brackets tell you. So to call this function, you’d need to know at least how to make an array of CGPoints. You might do it like this: CGPoint arr[] = {{4,5}, {6,7}, {8,9}, {10,11}}; 14 | Chapter 1: Just Enough C Having done that, you can pass arr as the second argument in a call to CGContextStrokeLineSegments. Also, a C string, as I’ve already mentioned, is actually an array. For example, the NSString method stringWithUTF8String: takes (according to the documentation) “a NULLterminated C array of bytes in UTF8 encoding;” but the parameter is declared not as an array, but as a char*. Those are the same thing, and are both ways of saying that this method takes a C string. (The colon at the end of the method name stringWithUTF8String: is not a misprint; many Objective-C method names end with a colon. I’ll explain why in Chapter 3.) Operators Arithmetic operators are straightforward (K&R 2.5), but watch out for the rule that “integer division truncates any fractional part.” This rule is the cause of much novice error in C. If you have two integers and you want to divide them in such a way as to get a fractional result, you must represent at least one of them as a float: int i = 3; float f = i/2; // beware! not 1.5 To get 1.5, you should have written i/2.0 or (float)i/2. The integer increment and decrement operators (K&R 2.8), ++ and --, work differently depending on whether they precede or follow their variable. The expression ++i replaces the value of i by 1 more than its current value and then uses the resulting value; the expression i++ uses the current value of i and then replaces it with 1 more than its current value. This is one of C’s coolest features. C also provides bitwise operators (K&R 2.9), such as bitwise-and (&) and bitwise-or (|); they operate on the individual binary bits that constitute integers. Of these, the one you are most likely to need is bitwise-or, because the Cocoa API often uses bits as switches when multiple options are to be specified simultaneously. For example, there are various ways in which a UIView can be resized automatically as its superview is resized, and you’re supposed to provide one or more of these when setting a UIView’s autoresizingMask property. The autoresizing options are listed in the documentation as follows: typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) { UIViewAutoresizingNone = 0, UIViewAutoresizingFlexibleLeftMargin = 1 << 0, UIViewAutoresizingFlexibleWidth = 1 << 1, UIViewAutoresizingFlexibleRightMargin = 1 << 2, UIViewAutoresizingFlexibleTopMargin = 1 << 3, UIViewAutoresizingFlexibleHeight = 1 << 4, UIViewAutoresizingFlexibleBottomMargin = 1 << 5 }; Operators | 15 The << symbol is the left shift operator; the right operand says how many bits to shift the left operand. So pretend that an NSUInteger is 8 bits (it isn’t, but let’s keep things simple and short). Then this enum means that the following name–value pairs are de‐ fined (using binary notation for the values): UIViewAutoresizingNone 00000000 UIViewAutoresizingFlexibleLeftMargin 00000001 UIViewAutoresizingFlexibleWidth 00000010 UIViewAutoresizingFlexibleRightMargin 00000100 UIViewAutoresizingFlexibleTopMargin 00001000 and so on. The reason for this bit-based representation is that these values can be com‐ bined into a single value (a bitmask) that you pass to set the autoresizingMask. All Cocoa has to do to understand your intentions is to look to see which bits in the value that you pass are set to 1. So, for example, 00001010 would mean that UIViewAutoresizingFlexibleTopMargin and UIViewAutoresizingFlexibleWidth are true (and that the others, by implication, are all false). The question is how to form the value 00001010 in order to pass it. You could just do the math, figure out that binary 00001010 is decimal 10, and set the autoresizingMask property to 10, but that’s not what you’re supposed to do, and it’s not a very good idea, because it’s error-prone and makes your code incomprehensible. Instead, use the bitwise-or operator to combine the desired options: myView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth; This notation works because the bitwise-or operator combines its operands by setting in the result any bits that are set in either of the operands, so 00001000 | 00000010 is 00001010, which is just the value we’re trying to convey. (And how does the runtime parse the bitmask to discover whether a given bit is set? With the bitwise-and operator.) Simple assignment (K&R 2.10) is by the equal sign. But there are also compound as‐ signment operators that combine assignment with some other operation. For example: height *= 2; // same as saying: height = height * 2; The ternary operator (?:) is a way of specifying one of two values depending on a condition (K&R 2.11). The scheme is as follows: 16 | Chapter 1: Just Enough C (condition) ? exp1 : exp2 If the condition is true (see the next section for what that means), the expression exp1 is evaluated and the result is used; otherwise, the expression exp2 is evaluated and the result is used. For example, you might use the ternary operator while performing an assignment, using this schema: myVariable = (condition) ? exp1 : exp2; What gets assigned to myVariable depends on the truth value of the condition. There’s nothing happening here that couldn’t be accomplished more verbosely with flow control (see the next section), but the ternary operator can greatly improve clarity, and I use it a lot. Flow Control and Conditions Basic flow control is fairly simple and usually involves a condition in parentheses and a block of conditionally executed code in curly braces. These curly braces constitute a new scope, into which new variables can be introduced. So, for example: if (x == 7) { int i = 0; i += 1; } After the closing curly brace in the fourth line, the i introduced in the second line has ceased to exist, because its scope is the inside of the curly braces. If the contents of the curly braces consist of a single statement, the curly braces can be omitted, but I would advise beginners against this shorthand, as you can confuse yourself. A common be‐ ginner mistake (which will be caught by the compiler) is forgetting the parentheses around the condition. The full set of flow control statements is given in K&R Chapter 3, and I’ll just summarize them schematically here (Example 1-1). Example 1-1. The C flow control constructs if (condition) { statements; } if (condition) { statements; } else { statements; } if (condition) { statements; } else if (condition) { statements; } else { Flow Control and Conditions | 17 statements; } while (condition) { statements; } do { statements; } while (condition); for (before-all; condition; after-each) { statements; } The if...else if...else structure can have as many else if blocks as needed, and the else block is optional. Instead of an extended if...else if...else if...else structure, when the conditions would consist of comparing various values against a single value, you can use the switch statement; be careful, though, as it is rather con‐ fusing and can easily go wrong (see K&R 3.4 for full details). The main trick is to re‐ member to end every case with a break statement, unless you want it to “fall through” to the next case (Example 1-2). Example 1-2. A switch statement NSString* key; switch (tag) { case 1: { // i.e., if tag is 1 key = @"lesson"; break; } case 2: { // i.e., if tag is 2 key = @"lessonSection"; break; } case 3: { // i.e., if tag is 3 key = @"lessonSectionPartFirstWord"; break; } } The C for loop needs some elaboration for beginners (Example 1-1). The before-all statement is executed once as the for loop is first encountered and is usually used for initialization of the counter. The condition is then tested, and if true, the block is exe‐ cuted; the condition is usually used to test whether the counter has reached its limit. The after-each statement is then executed, and is usually used to increment or dec‐ rement the counter; the condition is then immediately tested again. Thus, to execute a block using integer values 1, 2, 3, 4, and 5 for i, the notation is: 18 | Chapter 1: Just Enough C int i; for (i = 1; i < 6; i++) { // ... statements ... } The need for a counter intended to exist solely within the for loop is so common that C99 permits the declaration of the counter as part of the before-all statement; the declared variable’s scope is then inside the curly braces: for (int i = 1; i < 6; i++) { // ... statements ... } The for loop is one of the few areas in which Objective-C extends C’s flow-control syntax. Certain Objective-C objects represent enumerable collections of other objects; “enu‐ merable” basically means that you can cycle through the collection, and cycling through a collection is called enumerating the collection. To make enumerating easy, ObjectiveC provides a for...in operator, which works like a for loop: SomeType* oneItem; for (oneItem in myCollection) { // ... statements .... } On each pass through the loop, the variable oneItem (or whatever you call it) takes on the next value from within the collection. As with the C99 for loop, oneItem can be declared in the for statement, limiting its scope to the curly braces: for (SomeType* oneItem in myCollection) { // ... statements .... } To abort a loop from inside the curly braces, use the break statement. To abort the current iteration from within the curly braces and proceed to the next iteration, use the continue statement. In the case of while and do, continue means to perform imme‐ diately the conditional test; in the case of a for loop, continue means to perform im‐ mediately the after-each statement and then the conditional test. C also has a goto statement that allows you to jump to a named (labeled) line in your code (K&R 3.8); even though goto is notoriously “considered harmful,” there are sit‐ uations in which it is pretty much necessary, especially because C’s flow control is otherwise so primitive. Flow Control and Conditions | 19 It is permissible for a C statement to be compounded of multiple state‐ ments, separated by commas, to be executed sequentially. The last of the multiple statements is the value of the compound statement as a whole. This construct, for instance, lets you perform some secondary action before each test of a condition or perform more than one after-each action (an example appears in Chapter 17). We can now turn to the question of what a condition consists of. C has no separate boolean type; a condition either evaluates to 0, in which case it is considered false, or it doesn’t, in which case it is true. Comparisons are performed using the equality and relational operators (K&R 2.6); for example, == compares for equality, and < compares for whether the first operand is less than the second. Logical expressions can be com‐ bined using the logical-and operator (&&) and the logical-or operator (||); using these along with parentheses and the not operator (!) you can form complex conditions. Evaluation of logical-and and logical-or expressions is short-circuited, meaning that if the left condition settles the question, the right condition is never even evaluated. Don’t confuse the logical-and operator (&&) and the logical-or operator (||) with the bitwise-and operator (&) and the bitwise-or operator (|) discussed earlier. Writing & when you mean && (or vice versa) can result in surprising behavior. The operator for testing basic equality, ==, is not a simple equal sign; forgetting the difference is a common novice mistake. The problem is that such code is legal: simple assignment, which is what the equal sign means, has a value, and any value is legal in a condition. So consider this piece of (nonsense) code: int i = 0; while (i = 1) { i = 0; } You might think that the while condition tests whether i is 1. You might then think: i is 0, so the while body will never be performed. Right? Wrong. The while condition does not test whether i is 1; it assigns 1 to i. The value of that assignment is also 1, so the condition evaluates to 1, which means true. So the while body is performed. Moreover, even though the while body assigns 0 to i, the condition is then evaluated again and assigns 1 to i a second time, which means true yet again. And so on, forever; we’ve written an endless loop, and the program will hang. (And, depending on what compiler and settings you’re using, you might not even get a warning of trouble ahead.) C programmers actually revel in the fact that testing for zero and testing for false are the same thing and use it to create compact conditional expressions, which are consid‐ 20 | Chapter 1: Just Enough C ered elegant and idiomatic. I don’t recommend that you make use of such idioms, as they can be confusing, but I must admit that even I do occasionally resort to it, especially because in Objective-C it is so common to test an object reference to see whether it is nil (discussed further in Chapter 3). Since nil is a form of zero, I usually ask whether an object s is nil like this: if (s) { // ... } Objective-C introduces a BOOL type, which you should use if you need to capture or maintain a condition’s value as a variable, along with constants YES and NO (actually representing 1 and 0), which you should use when setting a boolean value. Don’t com‐ pare anything against a BOOL, not even YES or NO, because a value like 2 is true in a condition but is not equal to YES or NO. Just use the BOOL directly as a condition, or as part of a complex condition, and all will be well. For example: BOOL isnil = (nil == s); if (isnil) { // not: if (isnil == YES) // ... } Functions C is a function-based language (K&R 4.1). A function is a block of code defining what should happen; when other code calls (invokes) that function, the function’s code does happen. A function returns a value, which is substituted for the call to that function. Here’s a definition of a function that accepts an integer and returns its square: int square(int i) { return i * i; } Now I’ll call that function: int i = square(3); Because of the way square is defined, that is exactly like saying: int i = 9; That example is extremely simple, but it illustrates many key aspects of functions. Let’s analyze how a function is defined: int square ( int i) { return i * i; } We start with the type of value that the function returns; here, it returns an int. Functions | 21 Then we have the name of the function, which is square. Then we have parentheses, and here we place the data type and name of any values that this function expects to receive. Here, square expects to receive one value, an int, which we are calling i. The name i (along with its expected data type) is a parameter; when the function is called, its value will be supplied as an argument. If a function expects to receive more than one value, multiple parameters in its definition are separated by a comma (and when the function is called, the arguments supplied are likewise separated by a comma). Finally, we have curly braces containing the statements that are to be executed when the function is called. Those curly braces constitute a scope; variables declared within them are local to the function. The names used for the parameters in the function definition are also local to the function; in other words, the i in the first line of the function definition is the same as the i in the second line of the function definition, but it has nothing to do with any i used outside the function definition (as when the result of the function call is assigned to a variable called i). The value of the i parameter in the function definition is assigned from the corresponding argument when the function is actually called; in the previous example, it is 3, which is why the function result is 9. Supplying a function call with arguments is thus a form of assignment. Suppose a function is defined like this: int myfunction(int i, int j) { // ... And suppose we call that function: int result = myfunction(3, 4); That function call effectively assigns 3 to the function’s i parameter and 4 to the func‐ tion’s j parameter. When a return statement is encountered, the value accompanying it is handed back as the result of the function call, and the function terminates. It is legal for a function to return no value; in such a case, the return statement has no accompanying value, and the definition states the type of value returned by the function as void. It is also legal to call a function and ignore its return value even if it has one. For example, we could say: square(3); That would be a somewhat silly thing to say, because we have gone to all the trouble of calling the function and having it generate the square of 3 — namely 9 — but we have done nothing to capture that 9. It is exactly as if we had said: 9; 22 | Chapter 1: Just Enough C You’re allowed to say that, but it doesn’t seem to serve much purpose. On the other hand, the point of a function might be not so much the value it returns as other things it does as it is executing, so then it might make perfect sense to ignore its result. The parentheses in a function’s syntax are crucial. Parentheses are how C knows there’s a function. Parentheses after the function name in the function definition are how C knows this is a function definition, and they are needed even if this function takes no parameters. Parentheses after the function name in the function call are how C knows this is a function call, and they are needed even if this function call supplies no argu‐ ments. Using the bare name of a function is possible, because the name is the name of something, but it doesn’t call the function. (I’ll talk later about something it does do.) Let’s return to the simple C function definition and call that I used as my example earlier. Suppose we combine that function definition and the call to that function into a single program: int square(int i) { return i * i; } int i = square(3); That is a legal program, but only because the definition of the square function precedes the call to that function. If we wanted to place the definition of the square function elsewhere, such as after the call to it, we would need at least to precede the call with a declaration of the square function (Example 1-3). The declaration looks just like the first line of the definition, but it is a statement, ending with a semicolon, rather than a left curly brace. Example 1-3. Declaring, calling, and defining a function int square(int i); int i = square(3); int square(int i) { return i * i; } The parameter names in the declaration do not have to match the parameter names in the definition, but all the types (and, of course, the name of the function) must match. The types constitute the signature of this function. In other words, it does not matter if the first line, the declaration, is rewritten thus: int square(int j); What does matter is that, both in the declaration and in the definition, square is a function taking one int parameter and returning an int. (In a modern Objective-C pro‐ gram, though, the function declaration usually won’t be necessary, even if the function call precedes its definition; see “Modern Objective-C Function Declarations” (page 29).) Functions | 23 In Objective-C, when you’re sending a message to an object (Chapter 2), you won’t use a function call; you’ll use a method call (Chapter 3). But you will most definitely use plenty of C function calls as well. For example, earlier we initialized a CGPoint by setting its x element and its y element and by assigning its elements values in curly braces. But what you’ll usually do to make a new CGPoint is to call CGPointMake, which is declared like this: CGPoint CGPointMake ( CGFloat x, CGFloat y ); Despite its multiple lines and its indentations, this is indeed a C function declaration, just like the declaration for our simple square function. It says that CGPointMake is a C function that takes two CGFloat parameters and returns a CGPoint. So now you know (I hope) that it would be legal (and typical) to write this sort of thing: CGPoint myPoint = CGPointMake(4.3, 7.1); Pointer Parameters and the Address Operator Objective-C is chock-a-block with pointers (and asterisks). Objective-C methods typ‐ ically expect pointer parameters and return a pointer value. But this doesn’t make things more complicated, because, as I’ve already mentioned, your variables referring to Objective-C objects are pointers. Pointers are what Objective-C expects, but pointers are also what Objective-C gives you. Pointers are exactly what you’ve got, so there’s no problem. For example, one way to concatenate two NSStrings is to call the NSString method stringByAppendingString:, which the documentation tells you is declared as follows: - (NSString *)stringByAppendingString:(NSString *)aString This declaration is telling you (after you allow for the Objective-C syntax) that this method expects one NSString* parameter and returns an NSString*. That sounds messy, but it isn’t, because every NSString is really an NSString*. So nothing could be simpler than to obtain a new NSString consisting of two concatenated NSStrings: NSString* s1 = @"Hello, "; NSString* s2 = @"World!" NSString* s3 = [s1 stringByAppendingString: s2]; Sometimes, however, a function or method expects as a parameter a pointer to a thing, but what you’ve got is not that pointer but the thing itself. Thus, you need a way to create a pointer to that thing. The solution is the address operator (K&R 5.1), which is an ampersand before the name of the thing. 24 | Chapter 1: Just Enough C For example, there’s an NSString method for reading from a file into an NSString, which is declared like this: + (id)stringWithContentsOfFile:(NSString *)path encoding:(NSStringEncoding)enc error:(NSError **)error Now, never mind what an id is, and don’t worry about the Objective-C method decla‐ ration syntax. Just consider the types of the parameters. The first one is an NSString*; that’s no problem, as every reference to an NSString is actually a pointer to an NSString. An NSStringEncoding turns out to be merely an alias to a primitive data type, an NSUInteger, so that’s no problem either. But what on earth is an NSError**? By all logic, it looks like an NSError** should be a pointer to a pointer to an NSError. And that’s exactly what it is. This method is asking to be passed a pointer to a pointer to an NSError. Well, it’s easy to declare a pointer to an NSError: NSError* myError; But how can we obtain a pointer to that? With the address operator! So our code might look, schematically, like this: NSString* myPath NSStringEncoding NSError* myError NSString* result = // something or other; myEnc = // something or other; = nil; = [NSString stringWithContentsOfFile: myPath encoding: myEnc error: &myError]; The important thing to notice is the ampersand. Because myError is a pointer to an NSError, &myError is a pointer to a pointer to an NSError, which is just what we’re expected to provide. Thus, everything goes swimmingly. This method effectively returns two results. It returns a real result, which we have cap‐ tured by assigning it to the NSString pointer we’re calling result. But if there’s an error, it also wants to set the value of another object, an NSError object; the idea is that you can then study that NSError object to find out what went wrong. (Perhaps the file wasn’t where you said it was, or it wasn’t stored in the encoding you claimed it was.) By passing a pointer to a pointer to an NSError, you give the method free rein to do that. Before the call to stringWithContentsOfFile:, myError was initialized to nil; during the call to stringWithContentsOfFile:, if there’s an error, the pointer is repointed, thus giving myError a meaningful NSError value describing that error. (Repointing a pointer in this way is sometimes called indirection.) So the idea is that you first check result to see whether it’s nil. If it isn’t, fine; it’s the string you asked for. If it is, you then study the NSError that myError is now pointing to, to learn what went wrong. This pattern is frequently used in Cocoa. Pointer Parameters and the Address Operator | 25 You can use the address operator to create a pointer to any named variable. A C function is technically a kind of named variable, so you can even create a pointer to a function! This is an example of when you’d use the name of the function without the parentheses: you aren’t calling the function, you’re talking about it. For example, &square is a pointer to the square function. Moreover, just as the bare name of an array is implicitly a pointer to its first element, the bare name of a function is implicitly a pointer to the function; the address operator is optional. In Chapter 3, I describe a situation in which specifying a pointer to a function is a useful thing to do. Another operator used in connection with pointers, or when memory must be allocated dynamically, is sizeof. It may be followed by a type name in parentheses or by a variable name; a variable name needn’t be in parentheses, but it can be, so most programmers ignore the distinction and use parentheses routinely, as if sizeof were a function. For example, the documentation shows the declaration for the CTParagraphStyle- Setting struct like this: typedef struct CTParagraphStyleSetting { CTParagraphStyleSpecifier spec; size_t valueSize; const void* value; } CTParagraphStyleSetting; A CTParagraphStyleSpecifier is just an enum, so concentrate on the second and third elements of this struct, valueSize and value. The value element is a pointer-to-void, meaning an anonymous pointer; it’s a pointer to something-or-other. Since pointer-tovoid casts away any concern for what data type the pointer is pointing to, it also casts away any knowledge of how big that data type is. The job of the second element of the struct is to provide that information. Here’s an actual example of initializing a CTParagraphStyleSetting struct (from Chapter 23): CTTextAlignment centerValue = kCTCenterTextAlignment; CTParagraphStyleSetting center = {kCTParagraphStyleSpecifierAlignment, sizeof(centerValue), &centerValue}; Files The little dance of declaring a function before calling it (Example 1-3) may seem rather absurd, but it is of tremendous importance in the C language, because it is what allows a C program to be arbitrarily large and complex. As your program grows, you can divide and organize it into multiple files. This kind of organization can make a large program much more maintainable — easier to read, easier to understand, easier to change without accidentally breaking things. A large C program therefore usually consists of two kinds of file: code files, whose filename extension is .c, and header files, whose filename extension is .h. The build system will automatically 26 | Chapter 1: Just Enough C “see” all the files and will know that together they constitute a single program, but there is also a rule in C that code inside one file cannot “see” another file unless it is explicitly told to do so. Thus, a file itself constitutes a scope; this is a deliberate and valuable feature of C, because it helps you keep things nicely pigeonholed. The way you tell a C file to “see” another file is with the #include directive. The hash sign in the term #include is a signal that this line is an instruction to the preproces‐ sor. In this case, the word #include is followed by the name of another file, and the directive means that the preprocessor should simply replace the directive by the entire contents of the file that’s named. So the strategy for constructing a large C program is something like this: • In each .c file, put the code that only this file needs to know about; typically, each file’s code consists of related functionality. • In each .h file, put the function declarations that multiple .c files might need to know about. • Have each .c file include those .h files containing the declarations it needs to know about. So, for example, if function1 is defined in file1.c, but file2.c might need to call function1, the declaration for function1 can go in file1.h. Now file1.c can include file1.h, so all of its functions, regardless of order, can call function1, and file2.c can also include file1.h, so all of its functions can call function1 (Figure 1-2). In short, header files are a way of letting code files share knowledge about one another without actually sharing code (because, if they did share code, that would violate the entire point of keeping the code in separate files). But how does the compiler know where, among all these multiple .c files, to begin ex‐ ecution? Every real C program contains, somewhere, exactly one function called main, and this is always the entry point for the program as a whole: the compiler sets things up so that when the program executes, main is called. The organization for large C programs that I’ve just described will also be, in effect, the organization for your iOS programs. (The chief difference will be that instead of .c files, you’ll use .m files, because .m is the conventional filename extension for telling Xcode that your files are written in Objective-C, not pure C.) Moreover, if you look at any iOS Xcode project, you’ll discover that it contains a file called main.m; and if you look at that file, you’ll find that it contains a function called main. That’s the entry point to your application’s code when it runs. The big difference between your Objective-C code files and the C code files I’ve been discussing is that instead of saying #include, your files will say #import. The #import preprocessor directive is not mentioned in K&R. It’s an Objective-C addition to the Files | 27 Figure 1-2. How a large C program is divided into files language. It’s based on #include, but it is used instead of #include because it (#import) contains some logic for making sure that the same material is not included more than once. Such repeated inclusion is a danger whenever there are many cross-dependent header files; use of #import solves the problem neatly. Furthermore, your iOS programs consist not only of your code files and their corre‐ sponding .h files, but also of Apple’s code files and their corresponding .h files. The difference is that Apple’s code files (which are what constitutes Cocoa, see Part III) have already been compiled. But your code must still #import Apple’s .h files so as to be able to see Apple’s declarations. If you look at an iOS Xcode project, you’ll find that any .h files it contains by default, as well as its main.m file, contain a line of this form: #import <UIKit/UIKit.h> That line is essentially a single massive #import that copies into your program the dec‐ larations for the entire basic iOS API. Moreover, each of your .m files #imports its corresponding .h file, including whatever the .h file #imports. Thus, all your code files include the basic iOS declarations. For example, earlier I said that CGPoint was defined like this: struct CGPoint { CGFloat x; CGFloat y; }; typedef struct CGPoint CGPoint; 28 | Chapter 1: Just Enough C Modern Objective-C Function Declarations Starting with LLVM compiler version 3.1, which made its debut in Xcode 4.3, ObjectiveC no longer requires that a function declaration precede the use of that function, pro‐ vided that the definition of that function follows in the same file. In other words, code inside an Objective-C class can call a function — or an Objective-C method — even if that call precedes the definition of that function or method, and even if there is no separate declaration of that function or method. Thus, in modern Objective-C, the order of functions and methods within a .m file doesn’t matter, and it is not necessary to declare functions or methods within a .m file at all! The only place you’ll ever need to declare functions or methods will be in a .h file, and only so that some .m file other than the file where they are defined can import that .h file and call the function (or method). Bear in mind that this convenience is a feature of Objective-C, not of C. I’m talking about .m files, not .c files. I’ll describe more precisely in Chapter 4 the region of a .m file in which this convenience applies — namely, a class’s implementation section. After the preprocessor operates on all your files, your .m files actually contain that definition of CGPoint. (You can even choose Product → Generate Output → Prepro‐ cessed File, as I mentioned earlier, to confirm that this is true.) And that is why your code is able to use a CGPoint! The #import directive, like the #include directive (K&R 4.11), can specify a file in angle brackets or in quotation marks: #import <UIKit/UIKit.h> #import "MyHeader.h" Here’s what those two forms of syntax mean: Quotation marks Look for the named file in the same folder as this file (the .m file in which the #import line occurs). Angle brackets Look for the named file among the various header search paths supplied in the build settings. (These search paths are set for you automatically, and you normally won’t need to modify them.) In general, you’ll use angle brackets to refer to a header file owned by the Cocoa API and quotation marks to refer to a header file that you wrote. If you’re curious as to what an #import directive imports, select it (in Xcode) and choose File → Open Quickly to display the contents of the designated header file. Files | 29 The Standard Library You also have at your disposal a large collection of built-in C library files. A library file is a centrally located collection of C functions, along with a .h file that you can include so as to make those functions available to your code. For example, suppose you want to round a float up to the next highest integer. The way to do this is to call some variety of the ceil function. You can read the ceil man page by typing man ceil in the Terminal. The documentation tells you what #include to use to incorporate the correct header and also shows you the function declarations and tells you what those functions do. A small pure C program might thus look like this: #include <math.h> float f = 4.5; int i = ceilf(f); // now i is 5 In your iOS programs, math.h is included for you as part of the massive UIKit #import, so there’s no need to include it again. But some library functions might require an explicit #import. The standard library is discussed in K&R Appendix B. But the modern standard library has evolved since K&R; it is a superset of K&R’s library. The ceil function, for example, is listed in K&R appendix B, but the ceilf function is not. Similarly, if you wanted to generate a random number (which is likely if you’re writing a game program that needs to incorporate some unpredictable behavior), you probably wouldn’t use the rand func‐ tion listed in K&R; you’d use the random function, which supersedes it. Forgetting that Objective-C is C and that the C library functions are available to your code is a common beginner mistake. More Preprocessor Directives Of the many other available preprocessor directives, the one you’ll use most often is #define. It is followed by a name and a value; at preprocess time, the value is substituted for the name down through this code file. As K&R very well explain (K&R 1.4), this is a good way to prevent “magic numbers” from being hidden and hard-coded into your program in a way that makes the program difficult to understand and maintain. For example, in an iOS app that lays out some text fields vertically, I might want them all to have the same space between them. Let’s say this space is 3.0. I shouldn’t write 3.0 repeatedly throughout my code as I calculate the layout; instead, I write: #define MIDSPACE 3.0 Now instead of the “magic number” 3.0, my code uses a meaningful name, MIDSPACE; at preprocessor time, the text MIDSPACE is replaced with the text 3.0. So it amounts to 30 | Chapter 1: Just Enough C the same thing, but if I decide to change this value and try a different one, all I have to change is the #define line, not every occurrence of the number 3.0. A #define simply performs text substitution, so any expression can be used as the value. Sometimes you’ll want that expression to be an NSString literal. Here’s why. In Cocoa, NSString literals can be used as a key to a dictionary or the name of a notification. (Never mind for now what a dictionary or a notification is.) This situation is an invitation to error. If you have a dictionary containing a key @"mykey" and you mistype this elsewhere in your code as @"myKey" or @"mikey", the compiler won’t complain, but your program will misbehave. The solution is to define a name for this literal string: #define MYKEY @"mykey" Now use MYKEY throughout your code instead of @"mykey", and if you mistype it (as MYKKEY or what have you), the preprocessor won’t perform any substitution and the compiler will complain, catching the mistake for you. The #define directive can also be used to create a macro (K&R 4.11.2), a more elaborate form of text substitution. You’ll encounter a few Cocoa macros in the course of this book, but they will appear indistinguishable from functions; their secret identity as macros won’t concern you. The #warning directive deliberately triggers a warning in Xcode at compile time; this can be a way to remind yourself of some impending task or requirement: #warning Don't forget to fix this bit of code There is also a #pragma mark directive that’s useful with Xcode; I talk about it when discussing the Xcode programming environment (Chapter 9). Data Type Qualifiers A variable’s data type can be declared with a qualifier before the name of the type, modifying something about how that variable is to be used. For example, the declaration can be preceded by the term const, which means (K&R 2.4) that it is illegal to change the variable’s value; the variable must be initialized in the same line as the declaration, and that’s the only value it can ever have. You can use a const variable as an alternative way (instead of #define) to prevent “magic numbers” and similar expressions. For example: NSString* const MYKEY = @"Howdy"; The Cocoa API itself makes heavy use of this device. For example, in some circumstances Cocoa will pass a dictionary of information to your code. The documentation tells you what keys this dictionary contains. But instead of telling you a key as a string, the doc‐ umentation tells you the key as a const NSString variable name: Data Type Qualifiers | 31 UIKIT_EXTERN NSString *const UIApplicationStatusBarOrientationUserInfoKey; (Never mind what UIKIT_EXTERN means.) This declaration tells you that UIApplicationStatusBarOrientationUserInfoKey is the name of an NSString, and you are to trust that its value is set for you. You are to go ahead and use this name whenever you want to speak of this particular key, secure in the knowledge that the actual string value will be substituted. You do not have to know what that actual string value is. In this way, if you make a mistake in typing the variable name, the compiler will catch the mistake because you’ll be using the name of an undefined variable. Another commonly used qualifier is static. This term is unfortunately used in two rather different ways in C; the way I commonly use it is inside a function. Inside a function, static indicates that the memory set aside for a variable should not be released after the function returns; rather, the variable remains and maintains its value for the next time the function is called. A static variable is useful, for example, when you want to call a function many times without the overhead of calculating the result each time (after the first time). First test to see whether the static value has already been calculated: if it hasn’t, this must be the first time the function is being called, so you calculate it; if it has, you just return it. Here’s a schematic version: int myfunction() { static int result = 0; // 0 means we haven't done the calculation yet if (result == 0) { // calculate result and set it } return result; } A very common use of a static variable in Objective-C is to implement a singleton instance returned by a class factory method. If that sounds complicated, don’t worry; it isn’t. Here’s an example from my own code, which you can grasp even though we haven’t discussed Objective-C yet: + (CardPainter*) sharedPainter { static CardPainter* sp = nil; if (nil == sp) sp = [CardPainter new]; return sp; } That code says: If the CardPainter instance sp has never been created, create it, and in any case, now return it. Thus, no matter how many times this method is called, the instance will be created just once and that same instance will be returned every time. 32 | Chapter 1: Just Enough C Static variables are a C language feature, not an Objective-C language feature. Therefore, a static variable knows nothing of classes and in‐ stances; even if it appears inside a function or a method, it is defined at the level of a file, which means, in effect, at the level of your program as a whole. That’s fine when you’re using it in a class factory method, because a class is unique to your program as a whole. But never use a static variable in an Objective-C instance method, because your pro‐ gram can have multiple such instances, and the value of this one static variable will apply across all of them. In other words, don’t use a C static variable as a lazy substitute for an Objective-C instance variable (Chap‐ ter 2). I’ve made that mistake, and trust me, the results are not pretty. Data Type Qualifiers | 33 CHAPTER 2 Object-Based Programming My object all sublime. —W. S. Gilbert, The Mikado Objective-C, the native language for programming the Cocoa API, is an object-oriented language; to use it, the programmer must have an appreciation of the nature of objects and object-based programming. There’s little point in learning the syntax of ObjectiveC message sending or instantiation without a clear understanding of what a message or an instance is. That is what this chapter is about. Objects An object, in programming, is based on the concept of an object in the real world. It’s an independent, self-contained thing. These objects, unlike purely inert objects in the real world, have abilities. So an object in programming is more like a clock than a rock; it doesn’t just sit there, but actually does something. Perhaps one could compare an object in programming more to the animate objects of the real world, as opposed to the inanimate objects, except that — unlike real-world animate things — a programming object is supposed to be predictable: in particular, it does what you tell it. In the real world, you tell a dog to sit and anything can happen; in the programming world, you tell a dog to sit and it sits. (This is why so many of us prefer programming to dealing with the real world.) In object-based programming, a program is organized into many discrete objects. This organization can make life much easier for the programmer. Each object has abilities that are specialized for that object. You can think of this as being a little like how an automobile assembly line works. Each worker or station along the line does one thing (screw on the bumpers, or paint the door, or whatever) and does it well. You can see immediately how this organization helps the programmer. If the car is coming off the assembly line with the door badly painted, it is very likely that the blame lies with the 35 door-painting object, so we know where to look for the bug in our code. Or, if we decide to change the color that the door is to be painted, we have but to make a small change in the door-painting object. Meanwhile, other objects just go on doing what they do. They neither know nor care what the door-painting object does or how it works. Objects, then, are an organizational tool, a set of boxes for encapsulating the code that accomplishes a particular task. They are also a conceptual tool. The programmer, being forced to think in terms of discrete objects, must divide the goals and behaviors of the program into discrete tasks, each task being assigned to an appropriate object. Of course, objects can cooperate with one another, and the ways in which this cooperation can be arranged are innumerable. The assembly-line analogy illustrates one such arrangement — first, object 1 operates upon the end-product; then it hands it off to object 2, and object 2 operates upon the end-product, and so on — but that arrangement won’t be appropriate to most tasks. Coming up with an appropriate arrangement — an archi‐ tecture — for the cooperative and orderly relationship between objects is one of the most challenging aspects of object-based programming. Messages and Methods Nothing in a computer program happens unless it is instructed to happen. In a C pro‐ gram, all code belongs to a function and doesn’t run unless that function is called. In an object-based program, all code belongs to an object, and doesn’t run unless that object is told to run that code. All the action in an object-based program happens because an object was told to act. What does it mean to tell an object something? An object, in object-based programming, has a well-defined set of abilities — things it knows how to do. For example, imagine an object that is to represent a dog. We can design a highly simplified, schematic dog that knows how to do an extremely limited range of things: eat, come for a walk, bark, sit, lie down, sleep. The purpose of these abilities is so that the object can be told, as appropriate, to exercise them. So, again, we can imagine our schematic dog, rather like some child’s toy robot, responding to simple commands: Eat! Come for a walk! Bark! In object-based programming, a command directed to an object is called a message. To make the dog object eat, we send the eat message to the dog object. This mechanism of message sending is the basis of all activity in the program. The program consists entirely of objects, so its activity consists entirely of objects sending messages to one another. For objects to send messages to one another, objects must know about one another in some appropriate way at some appropriate time. Ensuring such mutual knowledge is part of the architectural design process I spoke of earlier. Returning for a moment to the assembly-line architecture, it’s no use saying that object 1 operates on the endproduct and then object 2 operates on the end-product; that isn’t going to happen all 36 | Chapter 2: Object-Based Programming by itself. It has to be arranged somehow. We can imagine various architectures for ar‐ ranging it. Perhaps we will set things up so that object 1 knows about object 2, and as the last step in its own operation, sends a message to object 2, handing it the end-product and telling it to commence its own operation. Or perhaps we will have a conveyor-belt object, which will hand the end-product to object 1 and tell it to commence its operation, wait until object 1 finishes with it, and then hand the end-product to object 2 and tell it to commence its operation. Each of these is a perfectly reasonable architectural pat‐ tern, and many others are possible; it is the programmer’s job to implement an archi‐ tecture that not only makes the program work appropriately, but also makes the program itself clear and easy for the programmer to work on. But the problem of making sure that within that architecture, each object knows about — technically, has a reference to — any other object to which it might need to send a message can be quite tricky (so much so, indeed, that an entire chapter of this book, Chapter 13, is devoted to it). A moment ago, I said that in a C program, all code belongs to a function. The objectbased analogue to a function is called a method. So, for example, a dog object might have an eat method. When the dog object is sent the eat message, it responds by calling the eat method. It may sound as if I’m not drawing any clear distinction between a message and a meth‐ od. But there is a difference. A message is what one object says to another. A method is a bundle of code that gets called. The connection between the two is not perfectly direct. You might send a message to an object that corresponds to no method of that object. For example, you might tell the dog to recite the soliloquy from Hamlet. I’m not sure what will happen if you do that; the details are implementation-dependent. (The dog might just sit there silently. Or it might get annoyed and bite you. Or, I suppose, it might nip off, read Hamlet, memorize the soliloquy, and recite it.) But that implementationdependence is exactly the point of the distinction between message and method. Nevertheless, in general the distinction between sending a message and calling a method won’t usually be important in real life. Most of the time, when you’re using ObjectiveC, your reason for sending a message to an object will be that that object implements the corresponding method and you are expecting to call that method. So sending a message to an object and calling a method of an object will appear to be the same act. Classes and Instances We come now to an extremely characteristic and profound feature of object-based pro‐ gramming. Just like in the real world, every object in the object-based programming world is of some type. This type, called a class, is the object-based analogy to the data type in C. Just as a simple variable in C might be an int or a float, an object in the objectbased programming world might be a Dog (or an NSString). In the object-based pro‐ gramming world, the idea of this arrangement is to ensure that more than one individual object can be relied upon to act the same way. Classes and Instances | 37 There can, for example, be more than one dog. You might have a dog called Fido and I might have a dog called Rover. But both dogs know how to eat, come for a walk, and bark. In object-based programming, they know this because they both belong to the Dog class. The knowledge of how to eat, come for a walk, and bark is part of the Dog class. Your dog Fido and my dog Rover possess this knowledge solely by virtue of being Dog objects. From the programmer’s point of view, what this means is simple: all the code you write is put into a class. All the methods you write will be part of some class or other. You don’t program an individual dog object: you program the Dog class. But I just got through saying that an object-based program works through the sending of messages to individual objects. So even though the programmer does not write the code for an individual dog object, there still needs to be an individual dog object in order for there to be something to send a message to. It is the Dog class that knows how to bark, but it is an individual dog object that is told to bark, and that actually does bark. So the question is: if all Dog code lives in a Dog class, where do individual dogs come from? The answer is that they have to be created in the course of the program as it runs. When the program starts out, it contains code for a Dog class, but no individual dog objects. If any barking by any dogs is to be done, the program must first create an individual dog object. This object will belong to the Dog class, so it can be sent the bark message. An individual object belonging to the Dog class (or any class) is an instance of that class. To manufacture, from a class, an actual individual object that is an instance of that class, is to instantiate that class. So every individual object, such as I talked about in the preceding sections — every individual object, that is, to which a message can be sent — is an instance of some class. Classes exist from the get-go, as part of the fact that the program exists in the first place; they are where the code is. Instances are manufactured, deliberately and individually, as the program runs. Each instance is manufactured from a class, it is an instance of that class, and it has methods by virtue of the fact that the class has those methods. The instance can then be sent a message; what it will do in response depends on what code the class contains in its methods. The instance is the individual thing that can be sent messages; the class, with its methods, is the locus of the thing’s ability to respond to messages (Figure 2-1). This relationship between instance and class begins to sound rather ethereal or meta‐ physical. Instances and classes seem to be programming-language analogies to what a philosopher would call particulars and universals. Indeed, the whole setup reminds one of nothing so much as Plato’s theory of Forms. For Plato, this world of ours is the world of individual things, but those things derive their natures by virtue of archetypal Forms that live off in another world. I’m not the only person ever to make this comparison to Platonic Forms — it is, indeed, implicit in the design of object-based languages and has 38 | Chapter 2: Object-Based Programming Figure 2-1. Class and instance been evoked explicitly in discussions of such languages ever since Smalltalk. But the comparison is still an apt one. As I said many years ago in my book REALbasic: The Definitive Guide: Indeed, object-oriented programming seems to fulfill Plato’s philosophical program an‐ nounced in the Euthyphro (6e, my translation): SOCRATES. Now, you recall that I asked you to explain to me, not this or that particular pious thing, but that Form Itself through which all pious things are pious? You did say, I believe, that it was through one Form that impious things are impious and pious things are pious; don’t you remember? EUTHYPHRO. Yes, I do. SOCRATES. All right, then; so, explain to me what is this Form Itself, so that by keeping my eyes upon it and using it as a model, I may declare that whatever you or anyone else does that is of this sort, is pious, and that whatever is not, is not. The problems with Plato’s characterization are well known: the Form seems to be a “thing” separate from the particular things of the world around us, the notion “through” is crucial but slippery, and Plato seems to equivocate rather glibly between the Form’s being re‐ sponsible for a thing’s being such and such and our ability to know that a thing is such and such; thus, his program is almost certainly doomed to failure as an explanation of how the world works. But he is perfectly accurate about how an object-oriented program works! If an instance is of the Pious type, there really is a separate Pious class that really is responsible for the instance being such as it is. Because every individual object is an instance of a class, to know what messages you can officially send to that object, you need to know at least what methods its class has Classes and Instances | 39 endowed it with. The public knowledge of this information is that class’s API. (A class may also have methods that you’re not really supposed to call from outside that object; these would not be public and other objects couldn’t officially send those messages to an instance of that class.) That’s why Apple’s own Cocoa documentation consists largely of pages listing and describing the methods supplied by some class. For example, to know what messages you can send to an NSString object (instance), you’d start by studying the NSString class documentation. That page is really just a big list of methods, so it tells you what an NSString object can do. That isn’t everything in the world there is to know about an NSString, but it’s a big percentage of it. Class Methods Up to now I’ve been keeping something back, and if you’ve been paying close attention, you may have caught me at it, because it looks as though I’ve contradicted myself. I said that nothing happens in a program unless a message is sent to an object. But I also said that there are no instances until they are created as the program runs. The contradiction is that if messages can be sent only to instances, it appears that no instances can ever be created (because, when the program starts up, there are no instances to which you can send the message asking for an instance to be created). The truth that I’ve been keeping back, which complicates things only a little, is that classes are themselves objects and can be sent messages. This revelation solves the con‐ tradiction completely. No instances exist as the program starts up, but the classes do. The classes may live off in a world of Platonic Forms, but they can still be sent messages. And one of the most important things you can ask a class to do by sending it a message is to instantiate itself. You cannot, however, ask an instance to instantiate itself. It thus begins to look as if there must be two kinds of message: messages that you are allowed to send to a class (such as telling the Dog class to instantiate itself) and messages that you are allowed to send to an instance (such as telling an individual dog to bark). That is exactly true. More pre‐ cisely, all code lives as a method in a class, but methods are of two kinds: class methods and instance methods. If a method is a class method, you can send that message to the class. If a method is an instance method, you can send that message to an instance of the class. In Objective-C syntax, class methods and instance methods are distinguished by the use of a plus sign or a minus sign. For example, Apple’s NSString class documentation page listing the methods of the NSString class starts out like this: + string – init The string method is a class method. The init method is an instance method. 40 | Chapter 2: Object-Based Programming In general, though not exclusively, class methods tend to be factory methods — that is, methods for generating an instance. This makes sense, because making an instance of itself is one of the main things you’re likely to want to ask a class to do. You might think that a class really needs only one class method for generating an instance of itself, and that is rigorously true, but classes tend to provide multiple factory methods purely as a convenience to the programmer. For example, here are three NSString class methods: + string + stringWithFormat: + stringWithContentsOfFile:encoding:error: They all make instances. The first class method, string, generates an empty NSString instance (a string with no text). The second class method, stringWithFormat:, gener‐ ates an NSString instance based on text that you provide, which can include transform‐ ing other values into text; for example, you might use it to start with an integer 9 and generate an NSString instance @"9". The third class method reads the contents of a file and generates an NSString instance from those contents. When you come to write your own classes, you too might well create multiple class methods that act as instance fac‐ tories for your own future programming convenience. Instance Variables Now that I’ve revealed that classes are objects and can be sent messages, you might be wondering why there need to be instances at all. Why doesn’t the mere existence of classes as objects suffice for object-based programming? Why would you ever bother to instantiate any of the classes? Why wouldn’t you write all your code as class methods, have the program send messages from one class object to another, and be done with it? The answer is that instances have a feature that classes do not: instance variables. An instance variable is just what the name suggests: it’s a variable belonging to an instance. Like instance methods, instance variables are defined as part of the class. But the val‐ ue of an instance variable is set as the program runs and belongs to one instance alone. In other words, different instances can have different values for the same instance vari‐ able. For example, suppose we have a Dog class and we decide that it might be a good idea for every dog to have a name. Just as you can learn a real-world dog’s name by reading the tag on its collar, we want to be able to assign every dog instance a name and, sub‐ sequently, to learn what that name is. So, in designing the Dog class, we declare that this class has an instance variable called name, whose value is a string (probably an NSString, as we’re using Objective-C). Now when our program runs we can instantiate Dog and assign the resulting dog instance a name (that is, we can assign its name instance variable a value). We can also instantiate Dog again and assign that resulting dog instance a name. Let’s say these are two different names: one is @"Rover" and one is @"Fido". Then Instance Variables | 41 Figure 2-2. Instance variables we’ve got two instances of Dog, and they are significantly different; they differ in the value of their name instance variables (Figure 2-2). So an instance is a reflection of the instance methods of its class, but that isn’t all it is; it’s also a collection of instance variables. The class is responsible for what instance variables the instance has, but not for the values of those variables. The values can change as the program runs and apply only to a particular instance. An instance is a cluster of particular instance variable values. In short, an instance is both code and data. The code it gets from its class and in a sense is shared with all other instances of that class, but the data belong to it alone. The data can persist as long as the instance persists. The instance has, at every moment, a state — the complete collection of its own personal instance variable values. An instance is a device for maintaining state. It’s a box for storage of data. The Object-Based Philosophy In my REALbasic book, I summarized the nature of objects in two phrases: encapsula‐ tion of functionality, and maintenance of state: Encapsulation of functionality Each object does its own job, and presents to the rest of the world — to other objects, and indeed in a sense to the programmer — an opaque wall whose only entrances are the methods to which it promises to respond and the actions it promises to 42 | Chapter 2: Object-Based Programming perform when the corresponding messages are sent to it. The details of how, behind the scenes, it actually implements those actions are secreted within itself; no other object needs to know them. Maintenance of state Each individual instance is a bundle of data that it maintains. Typically that data is private, which means that it’s encapsulated as well; no other object knows what that data is or in what form it is kept. The only way to discover from outside what data an object is maintaining is if there’s a method that reveals it. As an example, imagine an object whose job is to implement a stack — it might be an instance of a Stack class. A stack is a data structure that maintains a set of data in LIFO order (last in, first out). It responds to just two messages: push and pop. Push means to add a given piece of data to the set. Pop means to remove from the set the piece of data that was most recently pushed and hand it out. It’s like a stack of plates: plates are placed onto the top of the stack or removed from the top of the stack one by one, so the first plate to go onto the stack can’t be retrieved until all other subsequently added plates have been removed (Figure 2-3). The stack object illustrates encapsulation of functionality because the outside world knows nothing of how the stack is actually implemented. It might be an array, it might be a linked list, it might be any of a number of other implementations. But a client object — an object that actually sends a push or pop message to the stack object — knows nothing of this and cares less, provided the stack object adheres to its contract of be‐ having like a stack. This is also good for the programmer, who can, as the program develops, safely substitute one implementation for another without harming the vast machinery of the program as a whole. And just the other way round, the stack object knows nothing and cares less about who is telling it to push or to pop, and why. It just hums along and does its job in its reliable little way. The stack object illustrates maintenance of state because it isn’t just the gateway to the stack data — it is the stack data. Every object that has a reference to the stack object has the same access to its data, the same ability to push or to pop. (And that’s all it can do. The stack data is effectively inside the stack object; no one else can see it. All that another object can do is push or pop.) If a certain object is at the top of our stack object’s stack right now, then whatever object sends the pop message to this stack object will receive that object in return. If no object sends the pop message to this stack object, then the object at the top of the stack will just sit there, waiting. As a second example of the philosophy and nature of object-based programming at work, I’ll revert to another imaginary scenario I used in my REALbasic book. Pretend we’re writing an arcade game where the user is to “shoot” at moving “targets,” and the score increases every time a target is hit. We immediately have a sense of how we might organize our code using object-based programming and can see how object-based pro‐ gramming will fulfill its nature and purpose: The Object-Based Philosophy | 43 Figure 2-3. A stack • There will be a Target class. Every target object will be an instance of this class. This decision makes sense because we want every target to behave the same way. A target will need to know how to draw itself; that knowledge will be part of the Target class, which makes sense because all targets will draw themselves in the same way. Thus we have the relationship between class and instance. • Targets may draw themselves the same way, but they may also differ in appearance. Perhaps some targets are blue, others are red, and so on. This difference between individual targets can be expressed as an instance variable. Call it color. Every time we instantiate a target, we’ll assign it a color. The Target class’s code for drawing an individual target will look at that target’s color instance variable and use it when filling in the target’s shape. Clearly, we could extend this individualization as much as we like: targets could have different sizes, different shapes, and so on, and all of these parametric distinctions could be made on an individual basis through the use of instance variables. Thus we have both encapsulation of functionality and main‐ 44 | Chapter 2: Object-Based Programming tenance of state. A target has a state, the parameters that describe how it should look, and also has the ability to draw itself, expressing that state visually. • When a target is hit by the user, it will explode. So perhaps the Target class will have an explode instance method; thus, every target knows how to explode. One thing that should happen whenever a target explodes is that the user’s score should in‐ crease. So let’s imagine a score object — an instance of the Score class. Give every target object a reference to this score object so that it can send a message to it. When a target explodes, one of the things its explode instance method will do is send an increase message to the score object. Thus we have both encapsulation of func‐ tionality and maintenance of state. The score object responds indifferently to any object that sends it the increase message; it doesn’t need to know why it’s being sent that message. Nor does the score object even need to know that targets exist, or indeed that it’s part of a game. It just sits there maintaining the score, and when it receives the increase message, it increases it. This chapter has described only the rudiments of object-based philosophy — enough to communicate the correct mind-set. Using object-based programming effectively to make a program clear and maintainable is something of an art; your abilities will im‐ prove with experience. Eventually, you may want to do some further reading on how to construct an object-based program most effectively. I recommend in particular two classic, favorite books. Refactoring, by Martin Fowler (Addison-Wesley, 1999), describes how you can get a sense that you might need to rearrange what methods belong to what classes (and how to conquer your fear of doing so). Design Patterns, by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides (also known as “the Gang of Four”), is the bible on architecting object-based programs, listing all the ways you can arrange objects with the right powers and the right knowledge of one another (Addison-Wesley, 1994). The Object-Based Philosophy | 45 CHAPTER 3 Objective-C Objects and Messages One of the first object-based programming languages to achieve maturity and wide‐ spread dissemination was Smalltalk. It was developed during the 1970s at Xerox PARC under the leadership of Alan Kay and started becoming widely known in 1980. The purpose of Objective-C, created by Brad Cox and Tom Love in 1986, was to build Smalltalk-like syntax and behavior on top of C. Objective-C was licensed by NeXT in 1988 and was the basis for its application framework API, NeXTStep. Eventually, NeXT and Apple merged, and the NeXT application framework evolved into Cocoa, the framework for Mac OS X applications, still revolving around Objective-C. That history explains why Objective-C is the base language for iOS programming. (It also explains why Cocoa class names often begin with “NS” — it stands for “NeXTStep.”) Having learned the basics of C (Chapter 1) and the nature of object-based programming (Chapter 2), you are ready to meet Objective-C. This chapter describes Objective-C structural fundamentals; the next two chapters provide more detail about how Objective-C classes and instances work. (A few additional features of the language are discussed in Chapter 10.) As with the C language, my intention is not to describe the Objective-C language completely, but to provide a practical linguistic grounding, founded on my own experience of those aspects of the language that need to be firmly understood as a basis for iOS programming. An Instance Reference Is a Pointer In C, every variable must be declared to be of some type. In an object-based language such as Objective-C, an instance’s type is its class. The C language includes very few basic data types. To facilitate the multiplicity of class types required by its object-based nature, Objective-C takes advantage of C pointers. So, in Objective-C, if a variable is an instance of the class MyClass, that variable is of type MyClass* — a pointer to a MyClass. In general, in Objective-C, a reference to an instance is a pointer and the name of the data type of what’s at the far end of that pointer is the name of the instance’s class. 47 Note the convention for capitalization. Variable names tend to start with a lowercase letter; class names tend to start with an uppercase letter. As I mentioned in Chapter 1, the fact that a reference to an instance is a pointer in Objective-C will generally not cause you any difficulties, because pointers are used con‐ sistently throughout the language. For example, a message to an instance is directed at the pointer, so there is no need to dereference the pointer. Indeed, having established that a variable representing an instance is a pointer, you’re likely to forget that this variable even is a pointer and just work directly with that variable: NSString* s = @"Hello, world!"; NSString* s2 = [s uppercaseString]; Having established that s is an NSString*, you would never dereference s (that is, you would never speak of *s) to access the “real” NSString. So it feels as if the pointer is the real NSString. Thus, in the previous example, once the variable s is declared as a pointer to an NSString, the uppercaseString message is sent directly to the variable s. (The uppercaseString message asks an NSString to generate and return an uppercase ver‐ sion of itself; so, after that code, s2 is @"HELLO, WORLD!") The tie between a pointer, an instance, and the class of that instance is so close that it is natural to speak of an expression like MyClass* as meaning “a MyClass instance,” and of a MyClass* value as “a MyClass.” A Objective-C programmer will say simply that, in the previous example, s is an NSString, that uppercaseString returns “an NSString,” and so forth. It is fine to speak like that, and I do it myself (and will do it in this book) — provided you remember that this is a shorthand. Such an expression means “an NSString instance,” and because an instance is represented as a C pointer, it means an NSString*, a pointer to an NSString. Although the fact that instance references in Objective-C are pointers does not cause any special difficulty, you must still be conscious of what pointers are and how they work. As I emphasized in Chapter 1, when you’re working with pointers, you must keep in mind the special meaning of your actions. So here are some basic facts about pointers that you should keep in mind when working with instance references in Objective-C. Forgetting the asterisk in an instance declaration is a common beginner mistake, and will net you a mysterious compiler error message, such as “Interface type cannot be statically allocated.” 48 | Chapter 3: Objective-C Objects and Messages Instance References, Initialization, and nil Merely declaring an instance reference’s type doesn’t bring any instance into exis‐ tence. For example: NSString* s; // only a declaration; no instance is pointed to After that declaration, s is typed as a pointer to an NSString, but it is not in fact pointing to an NSString. You have created a pointer, but you haven’t supplied an NSString for it to point to. It’s just sitting there, waiting for you to point it at an NSString, typically by assignment (as we did with @"Hello, world!" earlier). Such assignment initializes the variable, giving it an actual meaningful value of the proper type. You can declare a variable as an instance reference in one line of code and initialize it later, like this: NSString* s; // ... time passes ... s = @"Hello, world!"; But this is not common. It is much more common, wherever possible, to declare and initialize a variable all in one line of code: NSString* s = @"Hello, world!"; Declaration without initialization, before the advent of ARC in iOS 5 (Chapter 12), created a dangerous situation: NSString* s; What is s after a mere declaration like that? It could be anything. But it is claiming to be a pointer to an NSString, and so your code might proceed to treat it as a pointer to an NSString. But it is pointing at garbage. A pointer pointing at garbage is liable to cause serious trouble down the road when you accidentally try to use it as an instance. Sending a message to a garbage pointer, or otherwise treating it as a meaningful instance, can crash your program. Even worse, it might not crash your program: it might cause your program to behave very, very oddly instead — and figuring out why can be difficult. For this reason, if you aren’t going to initialize an instance reference pointer at the moment you declare it by assigning it a real value, it’s a good idea to assign it nil: NSString* s = nil; A small but delightful bonus feature of using ARC is that this assignment is performed for you, implicitly and invisibly, as soon as you declare a variable without initializing it: NSString* s; // under ARC, s is immediately set to nil for you This prevents the existence of a garbage pointer, and could save you from yourself by preventing a crash when you accidentally use s as an instance without initializing it. Nevertheless, long years of habit have trained me to initialize or explicitly set to nil an An Instance Reference Is a Pointer | 49 instance pointer as soon as I declare it, and you’ll see that I continue to do so in examples in this book. What is nil? It’s simply a form of zero — the form of zero appropriate to an instance reference. The nil value simply means: “This instance reference isn’t pointing to any instance.” Indeed, you can test an instance reference against nil as a way of finding out whether it is in fact pointing to a real instance. This is an extremely common thing to do: if (nil == s) // ... As I mentioned in Chapter 1, the explicit comparison with nil isn’t strictly necessary; because nil is a form of zero, and because zero means false in a condition, you can perform the same test like this: if (!s) // ... I do in fact write nil tests in that second form all the time, but some programmers would take me to task for bad style. The first form has the advantage that its real meaning is made explicit, rather than relying on a cute implicit feature of C. The first form places nil first in the comparison so that if the programmer accidentally omits an equal sign, performing an assignment instead of a comparison, the compiler will catch the error (because assignment to nil is illegal). Many Cocoa methods use a return value of nil, instead of an expected instance, to signify that something went wrong. You are supposed to capture this return value and test it for nil in order to discover whether something did go wrong. For example, the documentation for the NSString class method stringWithContentsOfFile:encoding:error: says that it returns “a string created by reading data from the file named by path using the encoding, enc. If the file can’t be opened or there is an encoding error, returns nil.” So, as I described in Chapter 1, your next move after calling this method and capturing the result should be to test that result against nil, just to make sure you’ve really got an instance now: NSString* path = // ... whatever; NSStringEncoding enc = // ... whatever; NSError* err = nil; NSString* s = [NSString stringWithContentsOfFile:path encoding:enc error:&err]; if (nil == s) // oops! something went wrong... You should now be wondering about the implications of a nil-value pointer for sending a message to a noninstance. For example, you can send a message to an NSString in‐ stance like this: NSString* s2 = [s uppercaseString]; That code sends the uppercaseString message to s. So s is supposedly an NSString instance. But what if s is nil? With some object-based programming languages, sending 50 | Chapter 3: Objective-C Objects and Messages a message to nil constitutes a runtime error and will cause your program to terminate prematurely (REALbasic and Ruby are examples). But Objective-C doesn’t work like that. In Objective-C, sending a message to nil is legal and does not interrupt execution. Moreover, if you capture the result of the method call, it will be a form of zero — which means that if you assign that result to an instance reference pointer, it too will be nil: NSString* s = nil; // now s is nil NSString* s2 = [s uppercaseString]; // now s2 is nil Whether this behavior of Objective-C is a good thing is a quasi-religious issue and a subject of vociferous debate among programmers. It is useful, but it is also extremely easy to be tricked by it. The usual scenario is that you accidentally send a message to a nil reference without realizing it, and then later your program doesn’t behave as ex‐ pected. Because the point where the unexpected behavior occurs is later than the mo‐ ment when the nil pointer arose in the first place, the genesis of the nil pointer can be difficult to track down (indeed, it often fails to occur to the programmer that a nil pointer is the cause of the trouble in the first place). Short of peppering your code with tests to ascertain that your instance reference pointers are not accidentally nil, which is not generally a good idea, there isn’t much you can do about this. This behavior is strongly built into the language and is not going to change. It’s just something you need to be aware of. If, on the other hand, a method call can return nil, be conscious of that fact. Don’t assume that everything will go well and that it won’t return nil. On the contrary, if something can go wrong, it probably will. For example, to omit the nil test after calling stringWithContentsOfFile:encoding:error: is just stupid. I don’t care if you know perfectly well that the file exists and the encoding is what you say it is — test the result for nil! In pure C code, you will sometimes see a pointer-to-nothing expressed as NULL. NULL and nil are functionally equivalent nowadays, and I’ll use nil exclusively in this book. Instance References and Assignment As I said in Chapter 1, assigning to a pointer does not mutate the value at the far end of the pointer; rather, it repoints the pointer. Moreover, assigning one pointer to another repoints the pointer in such a way that both pointers are now pointing to the very same thing. Failure to keep these simple facts firmly in mind can have results that range from surprising to disastrous. For example, instances in general are usually mutable: they typically have instance vari‐ ables that can change. If two references are pointing at one and the same instance, then when the instance is mutated by way of one reference, that mutation also affects the An Instance Reference Is a Pointer | 51 instance as seen through the other reference. To illustrate, pretend that we’ve imple‐ mented the Stack class described in the previous chapter: Stack* myStack1 = // ... create Stack instance and initialize myStack1 ... ; Stack* myStack2 = myStack1; [myStack1 push: @"Hello"]; [myStack1 push: @"World"]; NSString* s = [myStack2 pop]; After we pop myStack2, s is @"World" even though nothing was ever pushed onto myStack2 (and the stack myStack1 contains only @"Hello" even though nothing was ever popped off of myStack1). That’s because we did push two strings onto myStack1 and then pop one string off myStack2, and myStack1 is myStack2 — in the sense that they are both pointers to the very same stack instance. That’s perfectly fine, as long as you understand and intend this behavior. In real life, you’re likely to pass an instance off to some other object, or to receive it from some other object: Stack* myStack = // ... create Stack instance and initialize myStack ... ; // ... more code might go here ... [myObject doSomethingWithThis: myStack]; // pass myStack to myObject After that code, myObject has a pointer to the very same instance we’re already pointing to as myStack. So we must be careful and thoughtful. The object myObject might mutate myStack right under our very noses. Even more, the object myObject might keep its reference to the stack instance and mutate it later — possibly much later, in a way that could surprise us. This is possible because instances can have instance variables that point to other objects, and those pointers can persist as long as the instances themselves do. This kind of shared referent situation can be intentional, but it is also something to watch out for and be conscious of (Figure 3-1). Another possible misunderstanding is to imagine that the assignment myStack2 = myStack1 somehow makes a new, separate instance that duplicates myStack1. That’s not at all the case. It doesn’t make a new instance; it just points myStack2 at the very same instance that myStack1 is pointing at. It may be possible to make a new instance that duplicates a given instance, but the ability to do so is not a given and it is not going to happen through mere assignment. (For how a separate duplicate instance might be generated, see the NSCopying protocol and the copy method mentioned in Chapter 10.) Instance References and Memory Management The pointer nature of instance references in Objective-C also has implications for man‐ agement of memory. The scope, and in particular the lifetime, of variables in pure C is typically quite straightforward: if you bring a piece of variable storage into existence by declaring that variable within a certain scope, then when that scope ceases to exist, the 52 | Chapter 3: Objective-C Objects and Messages Figure 3-1. Two instances end up with pointers to the same third instance variable storage ceases to exist. That sort of variable is called automatic (K&R 1.10). So, for example: void myFunction() { int i; // storage for an int is set aside i = 7; // 7 is placed in that storage } // the scope ends, so the int storage and its contents vanish But in the case of a pointer, there are two pieces of memory to worry about: the pointer itself, which is an integer signifying an address in memory, and whatever is at that address, at the far end of that pointer. Nothing about the C language causes the de‐ struction of what a pointer points to when the pointer itself is automatically destroyed as it goes out of scope: void myFunction() { NSString* s = @"Hello, world!"; // pointer and NSString NSString* s2 = [s uppercaseString]; // pointer and NSString } // the two pointers go out of existence... // ... but what about the two NSStrings they point to? Some object-based programming languages in which a reference to an instance is a pointer do manage automatically the memory pointed to by instance references (REALbasic and Ruby are examples). But Objective-C, at least the way it’s implemented when you’re programming for iOS, is not one of those languages. Because the C language has nothing to say about the automatic destruction of what is pointed to by a reference An Instance Reference Is a Pointer | 53 to an instance, Objective-C implements an explicit mechanism for the management of memory. I’ll talk in a later chapter (Chapter 12) about what that mechanism is and what responsibilities for the programmer it entails. Fortunately, under ARC, those respon‐ sibilities are fewer than they used to be; but memory must still be managed, and you must still understand how memory management works. Messages and Methods An Objective-C method is defined as part of a class. It has three aspects: Whether it’s a class method or an instance method If it’s a class method, you call it by sending a message to the class itself. If it’s an instance method, you call it by sending a message to an instance of the class. Its parameters and return value As with a C function, an Objective-C method takes some number of parameters; each parameter is of some specified type. And, as with a C function, it may return a value, which is also of some specified type; if the method returns nothing, its return type is declared as void. Its name An Objective-C method’s name must contain as many colons as it takes parameters. The name is split after each colon in a method call or declaration, so it is usual for the part of the name preceding each colon to describe the corresponding parameter. Sending a Message As you’ve doubtless gathered, the syntax for sending a message to an object involves square brackets. The first thing in the square brackets is the object to which the message is to be sent; this object is the message’s receiver. Then follows the message: NSString* s2 = [s uppercaseString]; // send "uppercaseString" message to s ... // ... (and assign result to s2) If the message is a method that takes parameters, each corresponding argument value comes after a colon: [myStack1 push: @"Hello"]; // send "push:" message to myStack1 ... // ...with one argument, the NSString @"Hello" To send a message to a class (calling a class method), you can represent the class by the literal name of the class: NSString* s = [NSString string]; // send "string" message to NSString class To send a message to an instance (calling an instance method), you’ll need a reference to an instance, which (as you know) is a pointer: 54 | Chapter 3: Objective-C Objects and Messages NSString* s = @"Hello, world!"; // s is initialized as an NSString instance NSString* s2 = [s uppercaseString]; // send "uppercaseString" message to s You can send a class method to a class, and an instance method to an instance, no matter how you got hold of and represent the class or the instance. For example, @"Hello, world!" is itself an NSString instance, so it’s legal to say: NSString* s2 = [@"Hello, world!" uppercaseString]; If a method takes no parameters, then its name contains no colons, like the NSString instance method uppercaseString. If a method takes one parameter, then its name contains one colon, which is the final character of the method name, like the hypothet‐ ical Stack instance method push:. If a method takes two or more parameters, its name contains that number of colons. In the minimal case, its name ends with that number of colons. For example, a method taking three parameters might be called hereAreThreeStrings:::. To call it, we split the name after each colon and follow each colon with an argument, which looks like this: [someObject hereAreThreeStrings: @"string1" : @"string2" : @"string3"]; That’s a legal way to name a method, but it isn’t very common, mostly because it isn’t very informative. Usually the name will have more text; in particular, the part before each colon will describe the parameter that follows that colon. For example, there’s a UIColor class method for generating an instance of a UIColor from four CGFloat numbers representing its red, green, blue, and alpha (transparency) components, and it’s called colorWithRed:green:blue:alpha:. Notice the clever con‐ struction of this name. The colorWith part tells something about the method’s purpose: it generates a color, starting with some set of information. All the rest of the name, Red:green:blue:alpha:, describes the meaning of each parameter. And you call it like this: UIColor* c = [UIColor colorWithRed: 0.0 green: 0.5 blue: 0.25 alpha: 1.0]; The space after each colon in the method call is optional. (Space before a colon is also legal, though in practice one rarely sees this.) The rules for naming an Objective-C method, along with the conventions governing such names (like trying to make the name informative about the method’s purpose and the meanings of its parameters), lead to some rather long and unwieldy method names, such as getBytes:maxLength:usedLength:encoding:options:range:remainingRange:. Such verbosity of nomenclature is characteristic of Objective-C. Method calls, and even method declarations, are often split across multiple lines to prevent a single line of code from becoming so long that it wraps within the editor, as well as for clarity. Declaring a Method The declaration for a method has three parts: Messages and Methods | 55 • Either + or -, meaning that the method is a class method or an instance method, respectively. • The data type of the return value, in parentheses. • The name of the method, split after each colon. Following each colon is the corre‐ sponding parameter, expressed as the data type of the parameter, in parentheses, followed by a placeholder name for the parameter. So, for example, Apple’s documentation tells us that the declaration for the UIColor class method colorWithRed:green:blue:alpha: is: + (UIColor*) colorWithRed: (CGFloat) red green: (CGFloat) green blue: (CGFloat) blue alpha: (CGFloat) alpha (Note that I’ve split the declaration into two lines, for legibility and to fit onto this page. The documentation puts it all on a single line.) Make very sure you can read this declaration! You should be able to look at it and say to yourself instantly, “The name of this method is colorWithRed:green:blue:alpha:. It’s a class method that takes four CGFloat parameters and returns a UIColor.” It is not uncommon, outside of code, to write a method’s name along with the plus sign or the minus sign, to make it clear whether this is a class method or an instance method. So you might speak informally of “-uppercaseString,” just as a way of reminding yourself or a reader that this is an instance method. Again outside of code, it is not uncommon, especially when communicating with other Objective-C programmers, to speak of a method’s name along with the class in which this method is defined. So you might say “NSString’s -uppercaseString,” or even something like “-[NSString uppercaseString].” Notice that that isn’t code, or even pseudo-code, because you are not actually speaking of a method call, and in any case you could never send the uppercaseString message to the NSString class; it’s just a compact way of saying, “I’m talking about the uppercaseString that’s an instance method of NSString.” Nesting Method Calls Wherever in a method call an object of a certain type is supposed to appear, you can put another method call that returns that type. Thus you can nest method calls. A method call can appear as the message’s receiver: NSString* s = [[NSString string] uppercaseString]; // silly but legal That’s legal because NSString’s class method string returns an NSString instance (for‐ mally, an NSString* value, remember), so we can send an NSString instance method to that result. Similarly, a method call can appear as an argument in a method call: [myStack push: [NSString string]]; // ok if push: expects NSString* parameter 56 | Chapter 3: Objective-C Objects and Messages However, I must caution you against overdoing that sort of thing. Code with a lot of nested square brackets is very difficult to read (and to write). Furthermore, if one of the nested method calls happens to return nil unexpectedly, you have no way to detect this fact. It is often better, then, to be even more verbose and declare a temporary variable for each piece of the method call. Just to take an example from my own code, instead of writing this: NSArray* arr = [[MPMediaQuery albumsQuery] collections]; I might write this: MPMediaQuery* query = [MPMediaQuery albumsQuery]; NSArray* arr = [query collections]; Even though the first version is quite short and legible, and even though in the second version the variable query will never be used again — it exists solely in order to be the receiver of the collections message in the second line — it is worth creating it as a separate variable. For one thing, it makes this code far easier to step through in the debugger later on, when I want to pause after the albumsQuery call and see whether the expected sort of result is being returned. Incorrect number or pairing of nested square brackets can net you some curious messages from the compiler. For example, too many pairs of square brackets ([[query collections]]) or an unbalanced left square bracket ([[query collections]) is reported as “Expected identifier.” No Overloading The data type returned by a method, together with the data types of each of its param‐ eters in order, constitute that method’s signature. It is illegal for two methods of the same type (class method or instance method) to exist in the same class with the same name but different signatures. So, for example, you could not have two MyClass instance methods called myMethod, one of which returns void and one of which returns an NSString. Similarly, you could not have two MyClass instance methods called myMethod:, both returning void, one taking a CGFloat parameter and one taking an NSString parameter. An attempt to vi‐ olate this rule will be stopped dead in its tracks by the compiler, which will announce a “duplicate declaration” error. The reason for this rule is that if two such conflicting methods were allowed to exist, there would be no way to determine from a method call to one of them which method was being called. You might think that the issue could be decided by looking at the types involved in the call. If one myMethod: takes a CGFloat parameter and the other myMethod: takes an NSString parameter, you might think that when myMethod: is called, Objective-C could Messages and Methods | 57 look at the actual argument and realize that the former method is meant if the argument is a CGFloat and the latter if the argument is an NSString. But Objective-C doesn’t work that way. There are languages that permit this feature, called overloading, but ObjectiveC is not one of them. Parameter Lists It isn’t uncommon for an Objective-C method to require an unknown number of pa‐ rameters. A good example is the NSArray class method arrayWithObjects:, which looks from the name as if it takes one parameter but in fact takes any number of pa‐ rameters, separated by comma. The parameters are the objects of which the NSArray is to consist. The trick here, however, which you must discover by reading the docu‐ mentation, is that the list must end with nil. The nil is not one of the objects to go into the NSArray (nil isn’t an object, so an NSArray can’t contain nil); it’s to show where the list ends. So, here’s a correct way to call the arrayWithObjects: method: NSArray* pep = [NSArray arrayWithObjects:@"Manny", @"Moe", @"Jack", nil]; The declaration for arrayWithObjects: uses three dots to show that a comma-separated list is legal: + (id)arrayWithObjects:(id)firstObj, ... ; Without the nil terminator, the program will not know where the list ends, and bad things will happen when the program runs, as it goes hunting off into the weeds of memory, incorporating all sorts of garbage into the NSArray that you never meant to have incorporated. Forgetting the nil terminator is a common beginner error, but not as common as it used to be: by a bit of deep-C voodoo, the Objective-C compiler now notices if you’ve for‐ gotten the nil, and warns you (“missing sentinel in method dispatch”). Even though it’s just a warning, don’t run that code! Another way to avoid forgetting the nil terminator is to avoid calling arrayWithObjects: altogether; this is now possible starting with LLVM compiler version 4.0 (Xcode 4.4 or later), which allows you to form a literal NSArray object directly, using @[...] syntax, like this: NSArray* pep = @[@"Manny", @"Moe", @"Jack"]; That’s just a notation, a kind of syntactic sugar; behind the scenes, arrayWithObjects: is presumably still being called for you. But it’s being called for you correctly, nil terminator and all, so this notation is much more bullet-proof than explicitly calling arrayWithObjects: yourself; plus it’s a lot less typing. I’ll be using this new ObjectiveC notation for literal arrays throughout this book. 58 | Chapter 3: Objective-C Objects and Messages Nevertheless, you will still encounter other Objective-C methods that do have a pa‐ rameter that’s a nil-terminated list of variable length. For example, there’s the UIAp‐ pearance protocol class method appearanceWhenContainedIn: (Chapter 25), or UIAlertView’s initWithTitle:message:delegate:cancelButtonTitle:otherButtonTitles: (Chapter 26). It’s a pity that Apple hasn’t somehow tweaked ObjectiveC or these methods to avoid the use of the nil terminator; for instance, they could have made the variable-length list parameter into an NSArray parameter instead. But until they do, knowing how to call such methods remains important. The C language has explicit provision for argument lists of unspecified length, which Objective-C methods such as arrayWithObjects: are using behind the scenes. I’m not going to explain the C mechanism, because I don’t expect you’ll ever write a method or function that requires it; see K&R 7.3 if you need the gory details. Unrecognized Selectors Objective-C messaging is dynamic, meaning that the compiler takes no formal respon‐ sibility for whether a particular object is a legal recipient of a given message. That’s because whether an object can deal with a message sent to it isn’t decided until the program actually runs and the message actually arrives. Objective-C has various devices for dealing at runtime with a message that doesn’t correspond directly to a method, and for all the compiler knows, one of them might come into play in this case. For example, at the time the program runs, the recipient of the message might be nil — and it’s harm‐ less to send any message to nil. Thus, it is theoretically legal to direct a message at an object with no corresponding method. The only guardian against this possibility is the compiler. Before ARC, the compiler was not a very strong guardian in this respect. For example: NSString* s = @"Hello, world!"; [s rockTheCasbah]; // without ARC, compiler warns An NSString has no method rockTheCasbah. But the (non-ARC) compiler will not stop you from running a program containing this code; it’s legal. The compiler will warn you, but it won’t stop you. There are actually two possible warnings: • If no rockTheCasbah method is defined anywhere in your code, the compiler will say: “Instance method ‘-rockTheCasbah’ not found (return type defaults to ‘id’).” Without going into the details, what the compiler means is: “I know of no instance method rockTheCasbah, so I can’t check its signature against the return type and arguments you’re actually using, so I’ll just make some loose assumptions and let it pass.” • If a rockTheCasbah method is defined somewhere in your code, the compiler will say: “‘NSString’ may not respond to ‘rockTheCasbah’.” This means: “There’s a rock- Messages and Methods | 59 TheCasbah method, all right, but you seem to be sending the rockTheCasbah meth‐ od to an instance of a class that doesn’t have it as an instance method.” This is a good example of what I meant in Chapter 2 when I said that sending a message and calling a method were not the same thing. The compiler is saying that NSString has no rockTheCasbah instance method, but that it isn’t going to stop you from sending an NSString a rockTheCasbah message. At runtime, the object that receives the rockTheCasbah message might be able to deal with it, for all the compiler knows. With ARC, however, the compiler is much stricter. The example above won’t compile at all under ARC! The compiler declares a fatal compilation error: “Receiver type ‘NSString’ for instance message does not declare a method with selector ‘rockTheCas‐ bah’.” There is no NSString method rockTheCasbah, and by golly the compiler isn’t going to let you send the rockTheCasbah message to an NSString, and that’s final. This is another of those delightful secondary benefits of using ARC. In order to do what it primarily does (manage memory), ARC must insist on more information about classes and their methods than the Objective-C standard calls for. Here, ARC is demanding that you prove that an NSString can respond to rockTheCasbah, or it won’t let you run this code at all. (Nevertheless, if you really want to, you can slip past even ARC’s stringent guardianship; I’ll explain how in the next section.) Let us assume for a moment that we are compiling without ARC, or that we have some‐ how tricked even ARC into letting us compile successfully. Warning or no warning, we are now ready to run a program that sends the rockTheCasbah message to an NSString, and damn the consequences. What might those consequences be? Quite simply, if you send a message to an object that can’t deal with it, your program will crash at that instant. So, for example, our attempt to send an NSString the rockTheCasbah message will crash our program, with a message (in the console log) of this form: “-[NSCFConstantString rockTheCasbah]: unrecognized selector sent to instance 0x3048.” The important thing here is the phrase unrecognized selector. The term “selector” is roughly equivalent to “message,” so this is a way of saying that a certain instance was sent a message it couldn’t deal with. The console message also tries to tell us what instance this was. 0x3048 is the value of the instance pointer; it is the address in memory to which our NSString* variable s was actually pointing. (Never mind why the NSString is described as an NSCFConstantString; this has to do with NSString’s implementation behind the scenes.) (Strictly speaking, I should not say that a situation like this will “crash our program.” What it will actually do is to generate an exception, an internal message as the program runs signifying that something bad has happened. It is possible for Objective-C code to “catch” an exception, in which case the program will not crash. The reason the program crashes, technically, is not that a message was sent to an object that couldn’t handle it, 60 | Chapter 3: Objective-C Objects and Messages but that the exception generated in response wasn’t caught. That’s why the crash log may also say, “Terminating app due to uncaught exception.”) Typecasting and the id Type One way to silence the compiler when it warns in the way I’ve just described is by typecasting. A typecast, however, is not a viable way of fixing the problem unless it also tells the truth. It is perfectly possible to lie to the compiler by typecasting; this is not nice, and is not likely to yield nice consequences. For example, suppose we’ve defined a class MyClass that does contain an instance method rockTheCasbah. As a result, it is fine with the compiler if you send the rockTheCasbah message to a MyClass, although it is not fine to send the rockTheCasbah message to an NSString. So you can silence the compiler by claiming that an NSString instance is a MyClass instance: NSString* s = @"Hello, world!"; [(MyClass*)s rockTheCasbah]; The typecast silences the compiler; there is no warning. Notice that the typecast is not a value conversion; it’s merely a claim about what the type will turn out to be at runtime. You’re saying that when the program runs, s will magically turn out to be a MyClass instance. Because MyClass has a rockTheCasbah instance method, that silences the compiler. Of course, you’ve lied to the compiler, so when the program runs it will crash anyway, in exactly the same way as before! You’re still sending an NSString a message it can’t deal with, so the very same exception about sending an unrecognized selector to an NSCFConstantString instance will result. So don’t do that! Sometimes, however, typecasting to silence the compiler is exactly what you do want to do. This situation quite often arises in connection with class inheritance. We haven’t discussed class inheritance yet, but I’ll give an example anyway. Let’s take the built-in Cocoa class UINavigationController. Its topViewController method is declared to re‐ turn a UIViewController instance. In real life, though, it is likely to return an instance of some class you’ve created. So in order to call a method of the class you’ve created on the instance returned by topViewController without upsetting the compiler, you have to reassure the compiler that this instance really will be an instance of the class you’ve created. That’s what I’m doing in this line from one of my own apps: [(RootViewController*)[navigationController topViewController] setAlbums: arr]; The expression (RootViewController*) is a typecast in which I’m assuring the com‐ piler that at this moment in the program, the value returned by the topViewController method call will in fact be an instance of RootViewController, which is my own defined class. The typecast silences the compiler when I send this instance the setAlbums: message, because my RootViewController class has a setAlbums: instance Typecasting and the id Type | 61 method and the compiler knows this. And the program doesn’t crash, because I’m not lying: this topViewController method call really will return a RootViewController in‐ stance. Objective-C also provides a special type designed to silence the compiler’s worries about object data types altogether. This is the id type. An id is a pointer, so you don’t say id*. It is defined to mean “an object pointer,” plain and simple, with no further speci‐ fication. Thus, every instance reference is also an id. Use of the id type causes the compiler to stop worrying about the relationship between object types and messages. The compiler can’t know anything about what the object will really be, so it throws up its hands and doesn’t warn about anything. Moreover, any object value can be assigned or typecast to an id, and a value typed as an id can be assigned where any object type is expected. The notion of assignment includes param‐ eter passing. So you can pass a value typed as an id as an argument where a parameter of some particular object type is expected, and you can pass any object as an argument where a parameter of type id is expected. (I like to think of an id as analogous to both type AB blood and type O blood: it is both a universal recipient and a universal donor.) So, for example: NSString* s = @"Hello, world!"; id unknown = s; [unknown rockTheCasbah]; The second line is legal, because any object value can be assigned to an id. The third line doesn’t generate any compiler warning, because any message can be sent to an id. (Of course the program will still crash when it actually runs and unknown turns out to be an NSString — which is incapable of receiving of the rockTheCasbah message!) That trick works even under ARC, with one caveat. ARC is willing to let that code compile — but only if a matching rockTheCasbah method is defined somewhere in your code (even if it isn’t an NSString method). If there’s no such method, ARC will stop you with a different error: “No known instance method for selector ‘rockTheCasbah’.” This is another way of saying the same thing the non-ARC compiler said earlier: “I know of no instance method rockTheCasbah, so I can’t check its signature against the return type and arguments you’re actually using.” But instead of implicitly adding, “So I’ll just make some loose assumptions and let it pass,” ARC is stricter. After all, even without knowing what class unknown will turn out to be when the program runs, ARC can be pretty sure that that class won’t have a rockTheCasbah method, because no known class has a rockTheCasbah method. So ARC, like a good guardian, continues to bar the way. If, however, a matching rockTheCasbah method is defined somewhere in your code, even though it isn’t an NSString method, ARC now takes its hands off the tiller entirely, and permits the program to compile and run without warning. You are now sending a 62 | Chapter 3: Objective-C Objects and Messages message to an id, and an id can legally receive any message. If you crash at runtime, that’s your problem; ARC can’t save you from yourself. If an id’s ability to receive any message reminds you of nil, it should. I have already said that nil is a form of zero; I can now specify what form of zero it is. It’s zero cast as an id. Of course, it still makes a difference at runtime whether an id is nil or something else; sending a message to nil won’t crash the program, but sending an unknown message to an actual object will. Thus, id is a device for turning off the compiler’s type checking altogether. Concerns about what type an object is are postponed until the program is actually running. All the compiler can do is intelligently analyze your code to see if you might be making a mistake that could matter at runtime. Using id turns off this part of the compiler’s intelligence and leaves you to your own devices. I do not recommend that you make extensive use of id to live in a world of pure dyna‐ mism. The compiler is your friend; you should let it use what intelligence it has to catch mistakes in your code. Thus, I almost never declare a variable or parameter as an id. I want my object types to be specific, so that the compiler can help check my code. On the other hand, the Cocoa API does make frequent use of id, because it has to. For example, consider the NSArray class, which is the object-based version of an array. In pure C, you have to declare what type of thing lives in an array; for example, you could have “an array of int.” In Objective-C, using an NSArray, you can’t do that. Every NSAr‐ ray is an array of id, meaning that each element of the array can be of any object type. You can put a specific type of object into an NSArray because any specific type of object can be assigned to an id (id is the universal recipient). You can get any specific type of object back out of an NSArray because an id can be assigned to any specific type of object (id is the universal donor). So, for example, NSArray’s lastObject method is defined as returning an id. So, given an NSArray arr, I can fetch its last element like this: id unknown = [arr lastObject]; However, after that code, unknown can now be sent any message at all, and we are dis‐ pensing with the compiler’s type checking. Therefore, if I happen to know what type of object an array element is, I always assign or cast it to that type. For example, let’s say I happen to know that arr contains nothing but NSString instances (because I put them there in the first place). Then I will say: NSString* s = [arr lastObject]; The compiler doesn’t complain, because an id can be assigned to any specific type of object (id is the universal donor). Moreover, from here on in, the compiler regards s as an NSString, and uses its type checking abilities to make sure I don’t send s any non- Typecasting and the id Type | 63 NSString messages, which is just what I wanted. And I didn’t lie to the compiler; at runtime, s really is an NSString, so everything is fine. The compiler’s type checking is called static typing, as opposed to the dynamic behavior that takes place when the program actually runs. What I’m saying here, then, is that I prefer to take advantage of static typing as much as possible. The Cocoa API will sometimes return an id from a method call where you might not expect it. It’s good to be conscious of this, because otherwise the compiler can mislead you into thinking you’re doing something safe when you’re not. For example, consider this code: UIColor* c = [NSString string]; This is clearly a mistake — you’re assigning an NSString to a UIColor variable, which is likely to lead to a crash later on — but the compiler is silent. Why doesn’t the compiler warn here? It’s because the NSString string class method is declared like this: + (id)string The string method returns an NSString, but its return value is typed as an id. An id can be assigned where any object type is expected, so the compiler doesn’t complain when it’s assigned to a UIColor variable. This fact is a common source of programmer mistakes (especially if the programmer is me). Earlier, I said that it is illegal for the same class to define methods of the same type (class method or instance method) with the same name but different signatures. But I did not say what happens when two different classes declare conflicting signatures for the same method name. This is another case in which it matters whether you’re using static or dynamic typing. If you’re using static typing — that is, the type of the object receiving the message is specified — there’s no problem, because there’s no doubt which method is being called (it’s the one in that object’s class). But if you’re using dynamic typing, where the object receiving the message is an id, you might get a warning from the compiler; and if you’re using ARC, you’ll get a downright error: “Multiple methods named ‘rockTheCasbah’ found with mismatched result, parameter type or attributes.” This is another reason why method names are so verbose: it’s in order to make each method name unique, preventing two different classes from declaring conflicting sig‐ natures for the same method. 64 | Chapter 3: Objective-C Objects and Messages Accidentally defining your own method with the same name as an ex‐ isting Cocoa method can cause mysterious problems. For example, in a recent online query, a programmer was confused because the compiler complained that his call to initWithObjects: lacked a nil terminator, even though his initWithObjects: didn’t need a nil terminator. No, his initWithObjects: didn’t, but Cocoa’s did, and the compiler couldn’t distinguish them because this message was being sent to an id. He should have picked a different name. Messages as Data Type Objective-C is so dynamic that it doesn’t have to know until runtime what message to send to an object or what object to send it to. Certain important methods actually accept both pieces of information as parameters. For example, consider this method declara‐ tion from Cocoa’s NSNotificationCenter class: - (void)addObserver:(id)notificationObserver selector:(SEL)notificationSelector name:(NSString *)notificationName object:(id)notificationSender We’ll discuss later what this method does (when we talk about notifications in Chap‐ ter 11), but the important thing to understand here is that it constitutes an instruction to send a certain message to a certain object at some later, appropriate time. For example, our purpose in calling this method might be to arrange to have the message tickleMeElmo: sent at some later, appropriate time to the object myObject. So let’s consider how we might actually make this method call. The object to which the message will be sent is here called notificationObserver, and is typed as an id (making it possible to specify any type of object to send the message to). So, for the notificationObserver parameter, we’re going to pass myObject. The message itself is the notificationSelector parameter, which has a special data type, SEL (for “selector,” the technical term for a message name). The question now is how to express the message name tickleMeElmo:. You can’t just put tickleMeElmo: as a bare term; that doesn’t work syntactically. You might think you could express it as an NSString, @"tickleMeElmo:", but surprisingly, that doesn’t work either. It turns out that the correct way to do it is like this: @selector(tickleMeElmo:) The term @selector() is a directive to the compiler, telling it that what’s in parentheses is a message name. Notice that what’s in parentheses is not an NSString; it’s the bare message name. And because it is the name, it must have no spaces and must include any colons that are part of the message name. Messages as Data Type | 65 So the rule is extremely easy: when a SEL is expected, you’ll usually pass a @selector expression. Failure to get this syntax right, however, is a common beginner error. Notice also that this syntax is an invitation to make a typing mistake, especially because there is no checking by the compiler. If myObject implements a tickleMeElmo: method and I accidentally type @selector(tickleMeElmo), forgetting the colon or making any other mistake in specifying the message name, there is no compiler error; the problem won’t be discovered until the program runs and something bad happens. (In this case, if the tickleMeElmo message without the colon is ever sent to myObject, the app will probably crash with an unrecognized selector exception.) C Functions Although your code will certainly call many Objective-C methods, it will also probably call quite a few C functions. For example, I mentioned in Chapter 1 that the usual way of initializing a CGPoint based on its x and y values is to call CGPointMake, which is declared like this: CGPoint CGPointMake ( CGFloat x, CGFloat y ); Make certain that you can see at a glance that this is a C function, not an Objective-C method, and be sure you understand the difference in the calling syntax. To call an Objective-C method, you send a message to an object, in square brackets, with each argument following a colon in the method’s name; to call a C function, you use the function’s name followed by parentheses containing the arguments. You might even have reason to write your own C functions as part of a class, instead of writing a method. A C function has lower overhead than a full-fledged method; so even though it lacks the object-oriented abilities of a method, it is sometimes useful to write one, as when some utility calculation must be called rapidly and frequently. Also, once in a while you might encounter a Cocoa method or function that requires you to supply a C function as a “callback.” An example is the NSArray method sortedArrayUsingFunction:context:. The first parameter is typed like this: NSInteger (*)(id, id, void *) That expression denotes, in the rather tricky C syntax used for these things, a pointer to a function that takes three parameters and returns an NSInteger. The three parameters of the function are an id, an id, and a pointer-to-void (which means any C pointer). The bare name of a function (see Chapter 1) can be used as a pointer to a C function. So to call sortedArrayUsingFunction:context: you’d need to write a C function that meets this description, and use its name as the first argument. 66 | Chapter 3: Objective-C Objects and Messages To illustrate, I’ll write a “callback” function to sort an NSArray of NSStrings on the last character of each string. (This would be an odd thing to do, but it’s only an example!) The NSInteger returned by the function has a special meaning: it indicates whether the first parameter is to be considered less than, equal to, or larger than the second. I’ll obtain it by calling the NSString compare: method, which returns an NSInteger with that same meaning. Example 3-1 defines the function and shows how we’d call sortedArrayUsingFunction:context: with that function as our callback (assume that arr is an NSArray of strings). Example 3-1. Using a pointer to a callback function NSInteger sortByLastCharacter(id string1, id string2, void* context) { NSString* s1 = (NSString*) string1; NSString* s2 = (NSString*) string2; NSString* string1end = [s1 substringFromIndex:[s1 length] - 1]; NSString* string2end = [s2 substringFromIndex:[s2 length] - 1]; return [string1end compare:string2end]; } NSArray* arr2 = [arr sortedArrayUsingFunction:sortByLastCharacter context:nil]; CFTypeRefs Many Objective-C objects have lower-level C counterparts, along with C functions for manipulating them. For example, besides the Objective-C NSString, there is also some‐ thing called a CFString; the “CF” stands for “Core Foundation,” which is a lower-level C-based API. A CFString is an opaque C struct (“opaque” means that the elements constituting this struct are kept secret, and that you should operate on a CFString only by means of appropriate functions). As with an NSString or any other object, in your code you’ll typically refer to a CFString by way of a C pointer; the pointer to a CFString has a type name, CFStringRef (a “reference to a CFString,” evidently). You work with a CFString in pure C, by calling functions. You might, on occasion, actually have to work with a Core Foundation type even when a corresponding object type exists. For example, you might find that NSString, for all its power, fails to implement a needed piece of functionality, which is in fact available for a CFString. Luckily, an NSString (a value typed as NSString*) and a CFString (a value typed as CFStringRef) are interchangeable: you can use one where the other is expected, though you will have to typecast in order to quiet the worries of the compiler. The documentation describes this interchangeability by saying that NSString and CFString are “toll-free bridged” to one another. To illustrate, I’ll use a CFString to convert an NSString representing an integer to that integer (this use of CFString is unnecessary, and is just by way of demonstrating the syntax; NSString has an intValue method): CFTypeRefs | 67 NSString *answer = @"42"; CFStringRef stringRef = (CFStringRef)answer; // non-ARC int ans = CFStringGetIntValue(stringRef); The typecast prevents the compiler from complaining, and works because NSString is toll-free bridged to CFString — in effect, behind the scenes, an NSString is a CFString. Under ARC, that code won’t compile unless you supply a little more information. ARC, as we’ll see in Chapter 12, is about memory management; but ARC manages only Objective-C objects, not their C counterparts. So although ARC manages the memory for an NSString, it leaves memory management for a CFStringRef up to you; and in order to compile that code, it needs you to show it that you understand the memory management status of this value as it crosses the toll-free bridge. You do so like this: NSString *answer = @"42"; CFStringRef stringRef = (__bridge CFStringRef)answer; int ans = CFStringGetIntValue(stringRef); The extra qualifier __bridge means: “Don’t worry, ARC, I know I’m crossing the tollfree bridge, and I assure you that this has no implications for memory management.” On the other hand, there are situations where crossing the toll-free bridge does have implications for memory management, and you may rest assured that I’ll discuss them in Chapter 12. The pointer-to-struct C data types, whose name typically ends in “Ref ”, may be referred to collectively as CFTypeRef, which is actually just the generic pointer-to-void. Thus, crossing the toll-free bridge may usefully be thought of as a cast between an object pointer and a generic pointer — that is, in general terms, from id to void* or from void* to id. Even where there is no toll-free bridging between specific types (as there is with NSString and CFString), there is always bridging at the top of the hierarchy, so to speak, between NSObject (the base object class, as explained in Chapter 4) and CFType‐ Ref. It is sometimes necessary to assign a CFTypeRef to an id variable or parameter. For example, a CALayer’s setContents: method (Chap‐ ter 16) expects an id parameter, but the actual value must be a CGImageRef. This is legal, because a pointer is just a pointer, but the compiler will complain unless you also typecast to an id, along with a __bridge qualifier if you’re using ARC. Blocks A block is an extension to the C language, introduced in Mac OS X 10.6 and available in iOS 4.0 or later. It’s a way of bundling up some code and handing off that entire bundle as an argument to a C function or Objective-C method. This is similar to what we did 68 | Chapter 3: Objective-C Objects and Messages in Example 3-1, handing off a pointer to a function as an argument, but instead we’re handing off the code itself. The latter has some major advantages over the former, which I’ll discuss in a moment. As an example, I’ll rewrite Example 3-1 to use a block instead of a function pointer. Instead of calling sortedArrayUsingFunction:context:, I’ll call sortedArrayUsingComparator:, which takes a block as its parameter. The block is typed like this: NSComparisonResult (^)(id obj1, id obj2) That’s similar to the syntax for specifying the type of a pointer to a function, but a caret character is used instead of an asterisk character. So this means a block that takes two id parameters and returns an NSComparisonResult (which is merely an NSInteger, with just the same meaning as in Example 3-1). We can define the block and hand it off as the argument to sortedArrayUsingComparator: all in a single move, as in Example 3-2. Example 3-2. Using a block instead of a callback function NSArray* arr2 = [arr sortedArrayUsingComparator: ^(id obj1, id obj2) { NSString* s1 = (NSString*) obj1; NSString* s2 = (NSString*) obj2; NSString* string1end = [s1 substringFromIndex:[s1 length] - 1]; NSString* string2end = [s2 substringFromIndex:[s2 length] - 1]; return [string1end compare:string2end]; }]; The syntax of the inline block definition is: ^ (id obj1, id obj2) { First, the caret character. Then, parentheses containing the parameters. Finally, curly braces containing the block’s content. Thanks to the block, as you can see, we’ve combined the definition of the callback function with its use. You might object that this means the callback isn’t reusable; if we had two calls to sortedArrayUsingComparator: using the same callback, we’d have to write out the callback in full twice. To avoid such repetition, or simply for clarity, a block can be assigned to a variable: NSComparisonResult (^sortByLastCharacter)(id, id) = ^(id obj1, id obj2) { NSString* s1 = (NSString*) obj1; NSString* s2 = (NSString*) obj2; NSString* string1end = [s1 substringFromIndex:[s1 length] - 1]; NSString* string2end = [s2 substringFromIndex:[s2 length] - 1]; return [string1end compare:string2end]; }; NSArray* arr2 = [arr sortedArrayUsingComparator: sortByLastCharacter]; NSArray* arr4 = [arr3 sortedArrayUsingComparator: sortByLastCharacter]; Blocks | 69 The return type in an inline block definition is usually omitted. If in‐ cluded, it follows the caret character, not in parentheses. If omitted, you may have to use typecasting in the return line to make the returned type match the expected type. For a complete technical syntax specifi‐ cation for blocks, see http://clang.llvm.org/docs/BlockLanguageS pec.html. The power of blocks really starts to emerge when they are used instead of a selector name. In an example earlier in this chapter, we talked about how you could pass @selector(tickleMeElmo:) as the second argument to addObserver:selector: name:object: as a way of saying, “When the time comes, please call my tickleMeElmo: method.” We also talked about how error-prone this syntax was: make a typing error, and your tickleMeElmo: method mysteriously won’t be called. Moreover, such code is hard to maintain; there’s the tickleMeElmo: method sitting there, completely separate from the code that calls addObserver:selector:name:object:, yet existing only to specify what should happen at the later time when our message arrives. It might well be clearer and more compact to call addObserverForName:object:queue:usingBlock: and specify there and then as a block what should happen at message time, with no separate method callback. (I’ll talk about this again, along with an example, in Chapter 11.) Perhaps the most remarkable feature of blocks is this: variables in scope at the point where a block is defined keep their value within the block at that moment, even though the block may be executed at some later moment. (Technically, we say that a block is a closure.) It is this aspect of blocks that makes them useful for specifying functionality to be executed at some later time, or even, as we’ll see in Chapter 38, in some other thread. Here’s an example that will appear in Chapter 17. It will make perfect sense to you in its proper context, so I won’t explain it fully now; but the point is that outside any blocks we have a UIView object v in scope, along with a CGPoint p and another CGPoint pOrig, and we can use the two CGPoint values to mutate v inside two blocks (called anim and after), even though these blocks won’t be executed until some indeterminate moment in the future, at the start and end of an animation: CGPoint p = v.center; CGPoint pOrig = p; p.x += 100; void (^anim) (void) = ^{ v.center = p; }; void (^after) (BOOL) = ^(BOOL f) { v.center = pOrig; 70 | Chapter 3: Objective-C Objects and Messages }; NSUInteger opts = UIViewAnimationOptionAutoreverse; [UIView animateWithDuration:1 delay:0 options:opts animations:anim completion:after]; If a variable outside a block is in scope within the block, and if that variable is an object reference, messages can be sent to it and the object may be mutated, as we did with the UIView object v in that example. But if we try, inside a block, to assign directly to a variable outside the block, we can’t do it; the variable is protected, and the compiler will stop us (“variable is not assignable”): CGPoint p; void (^aBlock) (void) = ^{ p = CGPointMake(1,2); // error }; On rare occasions, you may need to turn off this protection; you can do so by declaring the variable using the __block qualifier. Here’s an example that will appear in Chap‐ ter 35. We cycle through an array until we find the value we want; when we find it, we set a variable (dir) to that value. That variable is declared outside the block, because we intend to use its value after executing the block; therefore we qualify the variable’s dec‐ laration with __block, so that we can assign to it from inside the block: CGFloat h = newHeading.magneticHeading; __block NSString* dir = @"N"; NSArray* cards = @[@"N", @"NE", @"E", @"SE", @"S", @"SW", @"W", @"NW"]; [cards enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { if (h < 45.0/2.0 + 45*idx) { dir = obj; *stop = YES; } }]; // now we can use dir (Note also the assignment to a dereferenced pointer-to-BOOL. When the method to which we are submitting a block is going to call the block repeatedly as the equivalent of a for loop, we can’t abort the loop with a break statement, because this isn’t a real for loop. So the method will commonly specify that our block should take a pointer-toBOOL parameter; the idea is that we can set this BOOL by indirection to YES, and the method will notice this as it prepares to call the block for the next iteration, and will stop instead. This is one of the few common situations in iOS programming where it is necessary to dereference a pointer.) Another use of the __block qualifier is to allow a block to capture the value of a variable that is set by the very same method call that takes the block as an argument. Here’s an example that will appear in Chapter 38: Blocks | 71 __block UIBackgroundTaskIdentifier bti = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler: ^{ [[UIApplication sharedApplication] endBackgroundTask:bti]; }]; The method beginBackgroundTaskWithExpirationHandler: takes a block and returns a UIBackgroundTaskIdentifier, which is really just an integer. We want to use that integer inside the block, which will actually be executed at some later time (if ever). If we don’t declare the integer variable with the __block qualifier, the block will capture the variable’s value at the time the block is defined, which is before the beginBackgroundTaskWithExpirationHandler: method call is actually executed. After the method call is executed, the variable is set to its true value, the value we want to use inside the block; because we declared the variable with __block, the block has access to that true value. Note that this trick works only because the block is being stored (by the receiver of the beginBackgroundTaskWithExpirationHandler: message) for later execution. If the block were to be executed right now, before returning from the beginBackgroundTaskWithExpirationHandler: call, the result of that call would not yet have been set. At the same time that blocks were introduced into Objective-C, Apple introduced a system library of C functions called Grand Central Dispatch (GCD) that makes heavy use of them. GCD’s most important use is for threading (Chapter 38), but it also comes in handy for expressing neatly and compactly certain notions about when code should be executed. For example, GCD can help us delay execution of our code (delayed per‐ formance). The following code (from Chapter 14) means, “change the bounds of v1, but not right this moment — wait two seconds and then do it”: dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ CGRect f = v1.bounds; f.size.width += 40; f.size.height -= 50; v1.bounds = f; }); This next example rewrites the code from the end of Chapter 1, where a class method vends a singleton object. GCD promises that the block creating the singleton object to begin with will execute only once in the entire life of our program, thus guaranteeing that the singleton is a singleton: + (CardPainter*) sharedPainter { static CardPainter* sp = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sp = [CardPainter new]; }); return sp; } 72 | Chapter 3: Objective-C Objects and Messages Why is calling dispatch_once better, as a way of making sure we generate the singleton instance only once, than testing sp against nil, as in Chapter 1? Aside from being threadsafe, it isn’t; it’s just an example of GCD’s elegant use of a block. Blocks | 73 CHAPTER 4 Objective-C Classes This chapter describes some linguistic and structural features of Objective-C having to do with classes; in the next chapter, we’ll do the same for instances. Class and Superclass In Objective-C, as in many other object-oriented languages, a mechanism is provided for specifying a relationship between two classes: they can be subclass and superclass of one another. For example, we might have a class Quadruped and a class Dog and make Quadruped the superclass of Dog. A class may have many subclasses, but a class can have only one immediate superclass. I say “immediate” because that superclass might itself have a superclass, and so on in a rising chain, until we get to the ultimate superclass, called the base class, or root class. Because a class can have many subclasses but only one superclass, there is a hierarchical tree of subclasses, each branching from its superclass, and so on, with a single class, the base class, at the top. Indeed, Cocoa itself consists of just such a tree (a huge tree!) of hierarchically arranged classes, even before you write a single line of code or create any classes of your own. We can imagine diagramming this tree as an outline, with a single ultimate superclass at the top, then all of its immediate subclasses in the next level below that, then each of their immediate subclasses in the next level below that, and so on. And in fact Xcode will show you this outline: choose View → Navigators → Show Symbol Navigator and click Hierarchical, with the first and third icons in the filter bar darkened (Figure 4-1). The reason for the class–subclass relationship is to allow related classes to share func‐ tionality. Suppose, for example, we have a Dog class and a Cat class, and we are con‐ sidering defining a walk method for both of them. We might reason that both a dog and a cat walk in pretty much the same way, by virtue of both being quadrupeds. So it might make sense to define walk as a method of the Quadruped class, and make both Dog and 75 Figure 4-1. Browsing the built-in class hierarchy in Xcode Cat subclasses of Quadruped. The result is that both Dog and Cat can be sent the walk message, even if neither of them has a walk method, because each of them has a super‐ class that does have a walk method. We say that a subclass inherits the methods of its superclass. The purpose of subclassing is not merely so that a class can inherit another class’s meth‐ ods; it’s so that it can define methods of its own. Typically, a subclass consists of the methods inherited from its superclass and then some. If Dog has no methods of its own, it’s hard to see why it should exist separately from Quadruped. But if a Dog knows how to do something that not every Quadruped knows how to do — let’s say, bark — then it makes sense as a separate class. If we define bark in the Dog class, and walk in the Quadruped class, and make Dog a subclass of Quadruped, then Dog inherits the ability to walk from the Quadruped class and also knows how to bark. It is also permitted for a subclass to redefine a method inherited from its superclass. For example, perhaps some dogs bark differently from other dogs. We might have a class NoisyDog, for instance, that is a subclass of Dog. Dog defines bark, but NoisyDog also defines bark, and defines it differently from how Dog defines it. This is called overrid‐ ing. The very natural rule is that if a subclass overrides a method inherited from its superclass, then when the corresponding message is sent to an instance of that subclass, it is the subclass’s version of that method that is called. 76 | Chapter 4: Objective-C Classes Interface and Implementation As you already know from Chapter 2, all your code is going to go into some class or other. So the first thing we must do is specify what is meant by putting code “into a class” in Objective-C. How does Objective-C say, linguistically and structurally, “This is the code for such-and-such a class”? To write the code for a class, you must provide two chunks or sections of code, called the interface and the implementation. Here’s the complete minimum code required to define a class called MyClass. This class is so minimal that it doesn’t even have any methods of its own: @interface MyClass @end @implementation MyClass @end The @interface and @implementation compiler directives show the compiler where the interface and implementation sections begin for the class that’s being defined, My‐ Class; the corresponding @end lines show where each of those sections end. In real life, the implementation section is where any methods for MyClass would be defined. So here’s a class that’s actually defined to do something: @interface MyClass @end @implementation MyClass - (NSString*) sayGoodnightGracie { return @"Good night, Gracie!"; } @end Observe how a method is defined. The first line is just like a method declaration, stating the type of method (class or instance), the type of value returned, and the name of the method along with the types of any parameters and local names for those parameters (see Chapter 3). That’s followed by curly braces containing the code to be executed when the method is called, just as with a C function (see Chapter 1). Our minimal class is still pretty much useless, because it can’t be instantiated. In Cocoa, knowledge of how to be instantiated, plus how to do a number of other things that any class should know how to do, resides in the base class, which is the NSObject class. Therefore, all Cocoa classes must be based ultimately on the NSObject class, by declaring as the superclass for your class either NSObject or some other class that inherits from NSObject (as just about any other Cocoa class does). The syntax for this declaration is a colon followed by the superclass name in the @interface line, like this: Interface and Implementation | 77 @interface MyClass : NSObject @end @implementation MyClass - (NSString*) sayGoodnightGracie { return @"Good night, Gracie!"; } @end NSObject is not the only Cocoa base class. It used to be, but there is now another, NSProxy. NSProxy is used only in very special circumstances and is not discussed in this book. If you have no reason for your class to inherit from any other class, make it inherit from NSObject. In its fullest form, the interface section might contain some more material. In particular, if we want to declare our methods, so that other classes can learn about them and call them, those method declarations go into the interface section. A method declaration in code matches the name and signature for the method definition and ends with a sem‐ icolon (required): @interface MyClass : NSObject - (NSString*) sayGoodnightGracie; @end @implementation MyClass - (NSString*) sayGoodnightGracie { return @"Good night, Gracie!"; } @end (Actually, it’s legal for a method definition to have a semicolon as well, before the curly braces. But that notation is rare, and I never use it in this book.) There are also instance variables to be considered. If our class is to have any instance variables (other than those inherited from its superclass), they must be declared. In actual fact, in modern Objective-C, you will probably declare most of your instance variables implicitly, using a technique that I’ll explain in Chapter 5 and Chapter 12. But you might still occasionally declare an instance variable explicitly; and in any case, you certainly need to know how to do so. Before iOS 5.0, explicit declaration of instance variables had to take place in curly braces at the start of the interface section: @interface MyClass : NSObject { // instance variable declarations go here } - (NSString*) sayGoodnightGracie; @end @implementation MyClass 78 | Chapter 4: Objective-C Classes - (NSString*) sayGoodnightGracie { return @"Good night, Gracie!"; } @end However, starting with LLVM compiler version 3.0 (Xcode 4.2 and later), it is permitted to put instance variable declarations in curly braces at the start of the implementation section instead. This is a more logical place for variable declarations to go, because, as I’ll explain in the next section, the interface section is usually visible to other classes, but there is no reason why instance variables need to be visible to other classes, as they are usually private. Therefore, I prefer the new style, and will use it consistently through‐ out this book: @interface MyClass : NSObject - (NSString*) sayGoodnightGracie; @end @implementation MyClass { // instance variable declarations go here } - (NSString*) sayGoodnightGracie { return @"Good night, Gracie!"; } @end I’ll go into more detail about instance variables in Chapter 5. Header File and Implementation File It’s perfectly possible for the interface and implementation of a class to appear in the same file, or for multiple classes to be defined in a single file, but that isn’t the usual convention. The usual convention is one class, two files: one file containing the interface section, the other file containing the implementation section. For example, let’s suppose you are defining a class MyClass. Then you have two files, MyClass.h and MyClass.m. (The file naming is not magical or necessary; it’s just part of the convention. The file extensions are pretty much necessary, though, because the build process and Xcode itself rely on them.) The interface section goes into MyClass.h, which is called the header file. The implementation section goes into MyClass.m, which is called the implementa‐ tion file. The separation into two files is not inconvenient, because Xcode, expecting you to follow this convention, makes it easy to jump from editing a .h file to the corre‐ sponding .m file and vice versa (Navigate → Jump to Next Counterpart). Finally, the implementation file imports the header file (see Chapter 1 on the #import directive); this effectively unites the full class definition, making the definition legal even though it is split between two files. With this arrangement in place, further imports become easy to configure. The header file imports the basic header file for the entire Cocoa framework; in the case of an iOS program, that’s UIKit.h (again, see Chapter 1). There is no need for the implementation Header File and Implementation File | 79 file to import UIKit.h, because the header file imports it, and the implementation file imports the header file. If a class needs to know about another class that isn’t already imported in this way, its implementation file imports that class’s header file. Example 4-1 summarizes this conventional schema. Example 4-1. Conventional schema for defining a class // MyClass.h: #import <UIKit/UIKit.h> @interface MyClass : NSObject - (NSString*) sayGoodnightGracie; @end // MyClass.m: #import "MyClass.h" #import "OtherClass.h" @implementation MyClass { // instance variable declarations go here } - (NSString*) sayGoodnightGracie { return @"Good night, Gracie!"; } @end The result of this arrangement is that everything has the right visibility. No file ever imports an implementation file; that way, what’s inside a class’s implementation file is private to that class. If something about a class needs to be public, such as a method that you want other classes to be able to call, it is declared in the header file, and other classes import that header file in their implementation files (as I do with OtherClass.h in Example 4-1); this keeps the chain of imports clear and simple. A header file is also an appropriate place to define constants. In Chapter 1, for example, I talked about the problem of mistyping the name of a notification or dictionary key, which is a literal NSString, and how you could solve this problem by defining a name for such a string: #define MYKEY @"mykey" The question then arises of where to put that definition. If only one class needs to know about it, the definition can go near the start of its implementation file (it doesn’t need to be inside the implementation section). But if multiple classes need to know about this name, then a header file is an appropriate location; every implementation file that imports this header file will acquire the definition, and you can use the name MYKEY in that implementation file. 80 | Chapter 4: Objective-C Classes The ultimate header file in an Xcode project is the .pch file. The suf‐ fix .pch stands for “precompiled header”, and your project has exactly one such file, which is implicitly imported by all .h files. It isn’t common to edit the .pch file, but sometimes it’s the most convenient place to define a constant, or even to import a class interface section, that needs to be visible to pretty much every class in your program. I’ll talk more about the .pch file in Chapter 6. A slight problem arises when a header file needs to mention one of your other classes. Suppose, for example, that MyClass has a public method that takes or returns an instance of MyOtherClass. So MyClass.h needs to speak of MyOtherClass*. But MyClass.h does not import MyOtherClass.h, so MyClass.h doesn’t know about MyOtherClass, and the compiler will complain. To silence the compiler without violating the arrangement of imports (by importing MyOtherClass.h in the header file MyClass.h), use the @class directive. The word @class is followed by a comma-separated list of class names, ending with a semicolon. So MyClass.h might start out like this: #import <UIKit/UIKit.h> @class MyOtherClass; Then the interface section would follow, as before. The @class directive simply tells the compiler, “Don’t worry, MyOtherClass really is the name of a class.” That’s all the com‐ piler needs to know in order to permit the mention of the type MyOtherClass* in the header file. If, on the other hand, MyClass is to be a subclass of some other class, then MyClass’s header file must import that superclass’s header file (or some other header file that imports that superclass’s header file); otherwise, it would be unable to speak of that superclass. For instance, in Example 4-1, MyClass.h imports UIKit.h; thus it knows about NSObject, so that MyClass can declare NSObject as its superclass. Header File and Implementation File | 81 Cocoa’s Own Header Files The Cocoa classes themselves also follow the convention described in Example 4-1: each class is separated into a header file (containing the interface) and an implementation file. However, the Cocoa class implementation files are not visible to you. This is one of the major limitations of Cocoa; unlike many programming frameworks, you can’t see the source code for Cocoa — it’s secret. To figure out how Cocoa works, you have to rely purely on the documentation (and experimentation). You can, however, see the Cocoa header files, and indeed you are expected to look at them, as they can be a useful form of documentation (see Chapter 8). The Global Namespace When defining classes, choose your class names wisely to prevent name collisions. Objective-C has no namespaces; there’s a single vast name‐ space containing all names. You don’t want your own class name (or, for that matter, any other top-level constant name) to match a name defined in Cocoa. Instead of namespaces, there’s a convention: each Cocoa framework prefixes its names with a particular pair of capital letters (NSString and NSArray, CGFloat and CGRect, and so on). Ap‐ ple suggests that you use a prefix of your own as well; in fact, when you create a new project in Xcode, you’re offered an opportunity to specify a prefix, which will appear before the automatically created class names. Don’t use any of Apple’s prefixes. Nothing limits your prefix to two letters, or requires that both letters be uppercase. In fact, because all of Apple’s own prefixes are two uppercase letters, “My” as a prefix is safe. Class Methods Class methods are useful in general for two main purposes: Factory methods A factory method is a method that dispenses an instance of that class. For example, the UIFont class has a class method fontWithName:size:. You supply a name and a size, and the UIFont class hands you back a UIFont instance corresponding to a font with that name and size. A class method that vends a singleton instance, such as appears at the end of Chapter 1, is also a factory method. Global utility methods Classes are global (visible from all code, Chapter 13), so a class is a good place to put a utility method that anyone might need to call and that doesn’t require the overhead of an instance. For example, the UIFont class has a class method familyNames. It returns an array of strings (that is, an NSArray of NSString instances) 82 | Chapter 4: Objective-C Classes consisting of the names of the font families installed on this device. Because this method has to do with fonts, the UIFont class is as good a place as any to put it. Most methods that you write will be instance methods, but now and then you might write a class method. When you do, your purpose will probably be similar to those examples. The Secret Life of Classes A class method may be called by sending a message directly to the name of a class. For example, the familyNames class method of UIFont that I mentioned a moment ago might be called like this: NSArray* fams = [UIFont familyNames]; Clearly, this is possible because a class is an object (Chapter 2), and the name of the class here represents that object. You don’t have to do anything to create a class object. One class object for every class your program defines is created for you automatically as the program starts up. (This includes the classes your program imports, so there’s a MyClass class object because you defined MyClass, and there’s an NSString class object because you imported UIKit.h and the whole Cocoa framework.) It is to this class object that you’re referring when you send a message to the name of the class. Your ability to send a message directly to the bare name of a class is due to a kind of syntactic shorthand. You can use the bare class name only in two ways (and we already know about both of them): To send a message to In the expression [UIFont familyNames], the bare name UIFont is sent the familyNames message. To specify an instance type In the expression NSString*, the bare name NSString is followed by an asterisk to signify a pointer to an instance of this class. Otherwise, to speak of a class object, you need to obtain that object formally. One way to do this is to send the class message to a class or instance. For example, [MyClass class] returns the actual class object. Some built-in Cocoa methods expect a class object parameter, whose type is described as Class. To supply this as an argument, you’d need to obtain a class object formally. Take, for example, introspection on an object to inquire what its class is. The isKindOfClass: instance method is declared like this: - (BOOL)isKindOfClass:(Class)aClass So that means you could call it like this: The Secret Life of Classes | 83 if ([someObject isKindOfClass: [MyClass class]]) // ... A class object is not an instance, but it is definitely a full-fledged object. Therefore, a class object can be used wherever an object can be used. For example, it can be assigned to a variable of type id: id classObject = [MyClass class]; You could then call a class method by sending a message to that object, because it is the class object: id classObject = [MyClass class]; [classObject someClassMethod]; All class objects are also members of the Class class, so you could say this: Class classObject = [MyClass class]; [classObject someClassMethod]; 84 | Chapter 4: Objective-C Classes CHAPTER 5 Objective-C Instances Instances are the heart of the action in an Objective-C program. Most of the methods you’ll define when creating your own classes will be instance methods; most of the messages you’ll send in your code will call instance methods. This chapter describes how instances come into existence and how they work. How Instances Are Created Your class objects are created for you automatically as your program starts up, but instances must be created deliberately as the program runs. The entire question of where instances come from is thus crucial. Ultimately, every instance comes into existence in just one way: someone deliberately asks a class to instantiate itself. But there are three different ways in which this can occur: ready-made instances, instantiation from scratch, and nib-based instantiation. Ready-Made Instances One way to create an instance is indirectly, by calling code that does the instantiation for you. You can think of an instance obtained in this indirect manner as a “ready-made instance.” (That’s my made-up phrase, not an official technical term.) Consider this simple code: NSString* s2 = [s uppercaseString]; The documentation for the NSString instance method uppercaseString says that it returns “a string with each character from the receiver changed to its corresponding uppercase value.” In other words, you send the uppercaseString message to an NSString, and you get back a different, newly created NSString. After that line of code, s2 points to an NSString instance that didn’t exist beforehand. 85 The NSString produced by the uppercaseString method is a ready-made NSString instance. Your code didn’t say anything about instantiation; it just sent the uppercaseString message. But clearly someone said something about instantiation, because in‐ stantiation took place; this is a newly minted NSString instance. That someone is pre‐ sumably some code inside the NSString class. But we don’t have to worry about the details. We are guaranteed of receiving a complete brand spanking new ready-to-roll NSString, and that’s all we care about. Similarly, any class factory method instantiates the class and dispenses the resulting instance as a ready-made instance. So, for example, the NSString class method stringWithContentsOfFile:encoding:error: reads a file and produces an NSString repre‐ senting its contents. All the work of instantiation has been done for you. You just accept the resulting string and away you go. A Cocoa class factory method is likely to have its return value typed as id. As I mentioned in Chapter 3, this can lead to trouble if you mistak‐ enly assign the resulting instance where a different class of object is expected; the compiler doesn’t complain (because id is the universal donor) but you can mysteriously crash later when the wrong message is sent to the instance. Not every method that returns an instance returns a new instance, of course. For ex‐ ample, this is how you ask an array (an NSArray) for its last element: id last = [myArray lastObject]; The NSArray myArray didn’t create the object that it hands you. That object already existed; myArray was merely containing it, as it were — it was holding the object, point‐ ing to it. Now it’s sharing that object with you, that’s all. Similarly, many classes dispense one particular object. For example, your app has exactly one instance of the UIApplication class (we call this the singleton UIApplication in‐ stance); to access it, you send the sharedApplication class method to the UIApplication class: UIApplication* theApp = [UIApplication sharedApplication]; This singleton instance existed before you asked for it; indeed, it existed before any code of yours could possibly run. You don’t care how it was brought into being; all you care is that you can get hold of it when you want it. I’ll talk more about globally available singleton objects of this kind in Chapter 13. 86 | Chapter 5: Objective-C Instances Instantiation from Scratch The alternative to requesting a ready-made instance is to tell a class, yourself, directly, to instantiate itself. There is basically one way to do this: you send a class the alloc message. The alloc class method is implemented by the NSObject class, the root class from which all other classes inherit. It causes memory to be set aside for the instance so that an instance pointer can point to it. (Management of that memory is a separate issue, discussed in Chapter 12.) You must never, never, never call alloc by itself. You must immediately call another method, an instance method that initializes the newly created instance, placing it into a known valid state so that it can be sent other messages. Such a method is called an initializer. Moreover, an initializer returns an instance — usually the same instance, initialized. Therefore you can, and always should, call alloc and the initializer in the same line of code. The minimal initializer is init. So the basic pattern, known informally as “alloc-init,” looks like Example 5-1. Example 5-1. The basic pattern for instantiation from scratch SomeClass* aVariable = [[SomeClass alloc] init]; You cannot instantiate from scratch if you do not also know how to initialize, so we turn immediately to a discussion of initialization. Initialization Every class defines or inherits at least one initializer. This is an instance method; the instance has just been created, by calling alloc on the class, and it is to this newly minted instance that the initializer message must be sent. An initialization message must be sent to an instance immediately after that instance is created by means of the alloc message, and it must not be sent to an instance at any other time. The basic initialization pattern, as shown in Example 5-1, is to nest the alloc call in the initialization call, assigning the result of the initialization (not the alloc!) to a variable. One reason for this is that if something goes wrong and the instance can’t be created or initialized, the initializer will return nil; therefore it’s important to capture the result of the initializer and treat that, not the result of alloc, as the pointer to the instance. To help you identify initializers, all initializers are named in a conventional manner. The convention is that all initializers, and only initializers, begin with the word init. The ultimate bare-bones initializer is called simply init, and takes no parameters. Other initializers do take parameters, and usually begin with the phrase initWith followed by descriptions of their parameters. For example, the NSArray class documentation lists these methods: How Instances Are Created | 87 – – – – – – initWithArray: initWithArray:copyItems: initWithContentsOfFile: initWithContentsOfURL: initWithObjects: initWithObjects:count: Let’s try a real example. A particularly easy and generally useful initializer for NSArray is initWithObjects:. It takes a list of objects; the list must be terminated by nil. In Chapter 3, we illustrated this by creating an NSArray from three strings, by means of a class factory method that returned a ready-made instance: NSArray* pep = [NSArray arrayWithObjects:@"Manny", @"Moe", @"Jack", nil]; Now we’ll do what amounts to exactly the same thing, except that we’ll create the in‐ stance ourselves, from scratch: NSArray* pep = [[NSArray alloc] initWithObjects:@"Manny", @"Moe", @"Jack", nil]; In that particular case, there exist both a factory method and an initializer that work from the same set of data. Ultimately, it makes no difference which you use; given the same arguments, both approaches result in NSArray instances that are indistinguishable from one another. It will turn out in the discussion of memory management (Chap‐ ter 12) that there might be a reason to choose instantiation from scratch over readymade instances (though not, perhaps, under ARC). In modern Objective-C, as I mentioned in Chapter 3, you are unlikely to call arrayWithObjects:, because there is now a convenient literal array syntax that calls it for you. For the same reason, you are unlikely to call initWithObjects:. So I’ll give another example. Suppose that, one way or another, you now have an array pep containing the three strings @"Manny", @"Moe", and @"Jack", and that you want to instantiate a second array based on it and containing those same three strings. It is not sufficient to assign pep to another NSArray variable: NSArray* pep2 = pep; // no, that isn't another array Object references are pointers, and pointer assignment merely points two references at the same thing (Chapter 3). So pep2 in that code isn’t a second array; it’s the same array, which isn’t what we said we wanted. To make a new array instance based on the first, we can call the class method arrayWithArray:, like this: NSArray* pep2 = [NSArray arrayWithArray: pep]; Now pep2 is a newly minted instance, separate from pep. It’s a ready-made instance, returned from a class factory method. To create the instance ourselves, from scratch, we call the corresponding initializer: NSArray* pep2 = [[NSArray alloc] initWithArray: pep]; 88 | Chapter 5: Objective-C Instances In looking through the documentation for an initializer, don’t forget to look upward through the class hierarchy. For example, the class documentation for UIWebView lists no initializers, but UIWebView inherits from UIView, and in UIView’s class documen‐ tation you’ll discover initWithFrame:. Moreover, the init method is defined as an instance method of the NSObject class, so every class inherits it and every newly minted instance can be sent the init message. Thus it is a given that if a class defines no ini‐ tializers of its own, you can initialize an instance of it with init. For example, the UIResponder class documentation lists no initializers at all (and no factory methods). So to create a UIResponder instance from scratch, you’d call alloc and init. In just the single case where init is the initializer you want to call, you can collapse the successive calls to alloc and init into a call to new. In other words, [MyClass new] is a synonym for [[MyClass alloc] init]. I used to avoid new as confusing, chiefly because it conceals the initialization that guarantees this is a proper instance (and, before ARC, the need for memory management). But recently I’ve reversed course; I now use new quite a bit, and I’ll use it freely in this book. The designated initializer If a class does define initializers, one of them may be described in the documentation as the designated initializer. (There’s nothing about a method’s name that tells you it’s the designated initializer; you must peruse the documentation to find out.) For example, in the UIView class documentation, the initWithFrame: method is described as the designated initializer. A class that does not define a designated initializer inherits its designated initializer; the ultimate designated initializer, inherited by all classes without any other designated initializer anywhere in their superclass chain, is init. The designated initializer is the initializer on which any other initializers depend, in this class or any subclasses: ultimately, they must call it. The designated initializer might have the most parameters, allowing the most instance variables to be set explicitly, with the other initializers supplying default values for some instance variables, for conve‐ nience. Or it might just be the most basic form of initialization. But in any case, it is a bottleneck through which all other initializers pass. Here are some examples: • The NSDate class documentation says that initWithTimeIntervalSinceReferenceDate: is the designated initializer, and that initWithTimeIntervalSinceNow: calls it. • The UIView class documentation says that initWithFrame: is the designated ini‐ tializer. UIView contains no other initializers, but some of its subclasses do. UIWeb‐ View, a UIView subclass, has no initializer, so initWithFrame: is its inherited des‐ ignated initializer. UIImageView, a UIView subclass, has initializers such as initHow Instances Are Created | 89 Figure 5-1. Dragging a button into a view WithImage:, but none of them is a designated initializer; so initWithFrame: is its inherited designated initializer as well, and initWithImage: must call initWithFrame:. Moreover, a class that implements a designated initializer will override the designated initializer inherited from its superclass. The idea is typically that even the inherited designated initializer, if called, will be overridden so as to call this class’s designated initializer. For example, UIView overrides the inherited init to call its own designated initializer, initWithFrame:, with a value of (CGRect){{0, 0}, {0, 0}}. Nib-Based Instantiation The third means of instantiation is through a nib file (or storyboard file). A nib file is where Xcode lets you “draw” parts of the user interface. Most Xcode projects will include at least one nib file, which will be built into the app bundle, and will then be loaded as the app runs. A nib file consists, in a sense, of the names of classes along with instructions for instantiating and initializing them. When the app runs and a nib file is loaded, those instructions are carried out — those classes are instantiated and initialized. For example, suppose you’d like the user to be presented with a view containing a button whose title is “Howdy.” Xcode lets you arrange this graphically by editing a nib file: you drag a button from the Object library into the view, place it at a certain position in the view, and then set its title to “Howdy” (Figure 5-1). In effect, you create a drawing of what you want the view and its contents to look like. When the app runs, the nib file loads, and that drawing is turned into reality. To do this, the drawing is treated as a set of instructions for instantiating objects. The button that you dragged into the view is treated as a representative of the UIButton class. The UI‐ Button class is told to instantiate itself, and that instance is then initialized, giving it the same position you gave it in the drawing (the instance’s frame), the same title you gave it in the drawing (the instance’s title), and putting it into the window. In effect, the 90 | Chapter 5: Objective-C Instances loading of your nib file is equivalent to this code (assuming that view is a reference to the view object): UIButton* b = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [b setTitle:@"Howdy!" forState:UIControlStateNormal]; [b setFrame: CGRectMake(100,100,100,35)]; [view addSubview:b]; // // // // instantiate set up title set up frame place button in view The fact that nib files are a source of instances, and that those instances are brought into existence as the nib file is loaded, is a source of confusion to beginners. I’ll discuss nib files and how they are used to generate instances in much more detail in Chapter 7. Polymorphism The compiler, even in the world of static typing, is perfectly happy for you to supply a subclass instance where a superclass type is declared. To see this, let’s start with the first line of the previous example: UIButton* b = [UIButton buttonWithType:UIButtonTypeRoundedRect]; UIButton is a subclass of UIControl, which is a subclass of UIView. So it would be perfectly legal and acceptable to say this: UIButton* b = [UIButton buttonWithType:UIButtonTypeRoundedRect]; UIView* v = b; The variable b is a UIButton instance, but I’m assigning it to a variable declared as a UIView. That’s legal and acceptable because UIView is an ancestor (up the superclass chain) of UIButton. Putting it another way, I’m behaving as if a UIButton were a UIView, and the compiler accepts this because a UIButton is a UIView. What’s important when the app runs, however, is not the declared class of a variable, but the actual class of the object to which that variable points. Even if I assign the UIButton instance b to a UIView variable v, the object to which the variable v points is still a UIButton. So I can send it messages appropriate to a UIButton. For example: UIButton* b = [UIButton buttonWithType:UIButtonTypeRoundedRect]; UIView* v = b; [v setTitle:@"Howdy!" forState:UIControlStateNormal]; That code will cause the compiler to complain, because UIView doesn’t implement setTitle:forState:; under ARC, in fact, that code won’t even compile. So I’ll calm the compiler’s fears by typecasting: UIButton* b = [UIButton buttonWithType:UIButtonTypeRoundedRect]; UIView* v = b; [(UIButton*)v setTitle:@"Howdy!" forState:UIControlStateNormal]; Polymorphism | 91 The typecast calms the compiler’s fears, but the important thing is what happens when the program runs. What happens is that this code works just fine! It works fine not because I typecast v to a UIButton (typecasting doesn’t magically convert anything to anything else; it’s just a hint to the compiler), but because v really is a UIButton. So when the message setTitle:forState: arrives at the object pointed to by v, everything is fine. If v had been a UIView but not a UIButton, on the other hand, the program would have crashed at that instant. An object, then, responds to a message sent to it on the basis of what it really is, not on the basis of anything said about what it is — and what it really is cannot be known until the program actually runs and the message is actually sent to that object. Now let’s turn the tables. We called a UIButton a UIView and sent it a UIButton message. Now we’re going to call a UIButton a UIButton and send it a UIView message. What an object really is depends not just upon its class but also upon that class’s inher‐ itance. A message is acceptable even if an object’s own class doesn’t implement a cor‐ responding method, provided that the method is implemented somewhere up the su‐ perclass chain. For example, returning again to the same code: UIButton* b = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [b setFrame: CGRectMake(100,100,100,35)]; This code works fine. But you won’t find setFrame: in the documentation for the UI‐ Button class. That’s because you’re looking in the wrong place. A UIButton is a UICon‐ trol, and a UIControl is a UIView. To find out about setFrame:, look in the UIView class’s documentation. (Okay, it’s more complicated than that; you won’t find setFrame: there either. But you will find a term frame which is called a “property,” and this amounts to the same thing, as I’ll explain later in this chapter.) So the setFrame: message is sent to a UIButton, but it corresponds to a method defined on a UIView. Yet it works fine, because a UIButton is a UIView. A common beginner mistake is to consult the documentation without following the superclass chain. If you want to know what you can say to a UIButton, don’t just look in the UIButton class documentation: also look in the UIControl class documentation, the UIView class docu‐ mentation, and so on. To sum up: we treated a UIButton object as a UIView, yet we were still able to send it a UIButton message. We treated a UIButton as a UIButton, yet we were still able to send it a UIView message. What matters when a message is sent to an object is not how the variable pointing to that object is declared but what class the object really is. What an object really is depends upon its class, along with that class’s inheritance from the su‐ perclass chain; these facts are innate to the object and are independent of how your code 92 | Chapter 5: Objective-C Instances characterizes the variable pointing to the object. This independent maintenance of ob‐ ject type integrity is the basis of what is called polymorphism. But it is not quite the whole of polymorphism. To understand the whole of polymor‐ phism, we must go further into the dynamics of message sending. The Keyword self A common situation is that code in an instance method defined in a class must call another instance method defined within the same class. We have not yet discussed how to do this. A method is called by sending a message to an object; in this situation, what object would that be? The answer is supplied by a special keyword, self. Here’s a simple example: @implementation MyClass - (NSString*) greeting { return @"Goodnight, Gracie!"; } - (NSString*) sayGoodnightGracie { return [self greeting]; } @end When the sayGoodnightGracie message is sent to a MyClass instance, the sayGoodnightGracie method runs. It sends the greeting message to self. As a result, the greeting instance method is called; it returns the string @"Goodnight, Gracie!", and this same string is then returned from the sayGoodnightGracie method. The example seems straightforward enough, and it is. In real life, your code when you define a class will sometimes consist of a few public instance methods along with lots of other instance methods on which they rely. The instance methods within this class will be calling each other constantly. They do this by sending messages to self. Behind this simple example, though, is a subtle and important mechanism having to do with the real meaning of the keyword self. The keyword self does not actually mean “in the same class.” It’s an instance, after all, not a class. What instance? It’s this same instance. The same as what? The same instance to which the message was sent that resulted in the keyword self being encountered in the first place. So let’s consider in more detail what happens when we instantiate MyClass and send the sayGoodnightGracie message to that instance: MyClass* thing = [MyClass new]; NSString* s = [thing sayGoodnightGracie]; The Keyword self | 93 Figure 5-2. The meaning of self We instantiate MyClass and assign the instance to a variable thing. We then send the sayGoodnightGracie message to thing, the instance we just created. The message ar‐ rives, and it turns out this instance is a MyClass. Sure enough, MyClass implements a sayGoodnightGracie instance method, and this method is called. As it runs, the key‐ word self is encountered. It means “the instance to which the original message was sent in the first place.” That, as it happens, is the instance pointed to by the variable thing. So now the greeting message is sent to that instance (Figure 5-2). This mechanism may seem rather elaborate, considering that the outcome is just what you’d intuitively expect. But the mechanism needs to be elaborate in order to get the right outcome. This is particularly evident when superclasses are involved and a class overrides a method of its superclass. To illustrate, suppose we have a class Dog with an instance method bark. And suppose Dog also has an instance method speak, which simply calls bark. Now suppose we subclass Dog with a class Basenji, which overrides bark (because Basenjis can’t bark). What happens when we send the speak message to a Basenji instance, as in Example 5-2? 94 | Chapter 5: Objective-C Instances Example 5-2. Polymorphism in action @implementation Dog - (NSString*) bark { return @"Woof!"; } - (NSString*) speak { return [self bark]; } @end @implementation Basenji : Dog - (NSString*) bark { return @""; // empty string, Basenjis can't bark } @end // So, in some other class: Basenji* b = [Basenji new]; NSString* s = [b speak]; If the keyword self meant merely “the same class where this keyword appears,” then when we send the speak message to a Basenji instance, we would arrive at the imple‐ mentation of speak in the Dog class (because that’s where speak is implemented), and the Dog class’s bark method would be called. This would be terrible, because it would make nonsense of the notion of overriding; we’d return @"Woof!", which is wrong for a Basenji. But that is not what the keyword self means. It has to do with the instance, not the class. So here’s what happens. The speak message is sent to our Basenji instance, b. The Basenji class doesn’t implement a speak method, so we look upward in the class hierarchy and discover that speak is implemented in the superclass, Dog. We call Dog’s instance method speak, the speak method runs, and the keyword self is encountered. It means “the instance to which the original message was sent in the first place.” That instance is still our Basenji instance b. So we send the bark message to the Basenji instance b. The Basenji class implements a bark instance method, so this method is found and called, and the empty string is returned (Figure 5-3). Of course, if the Basenji class had not overridden bark, then when the bark message was sent to the Basenji instance, we would have looked upward in the class hierarchy again and found the bark method implemented in the Dog class and called that. Thus, The Keyword self | 95 Figure 5-3. Class inheritance, overriding, self, and polymorphism thanks to the way the keyword self works, inheritance works correctly both when there is overriding and when there is not. If you understand that example, you understand polymorphism. The mechanism I’ve just described is crucial to polymorphism and is the basis of object-oriented program‐ ming. (Observe that I now speak of object-oriented programming, not just object-based programming as in Chapter 2. That’s because, in my view, the addition of polymorphism is what turns object-based programming into object-oriented programming.) 96 | Chapter 5: Objective-C Instances The Keyword super Sometimes (quite often, in Cocoa programming) you want to override an inherited method but still access the overridden functionality. To do so, you’ll use the keyword super. Like self, the keyword super is something you send a message to. But its mean‐ ing has nothing to do with “this instance” or any other instance. The keyword super is class-based, and it means: “Start the search for messages I receive in the superclass of this class” (where “this class” is the class where the keyword super appears). You can do anything you like with super, but its primary purpose, as I’ve already said, is to access overridden functionality — typically from within the very functionality that does the overriding, so as to get both the overridden functionality and some additional functionality. For example, suppose we define a class NoisyDog, a subclass of Dog. When told to bark, it barks twice: @implementation NoisyDog : Dog - (NSString*) bark { return [NSString stringWithFormat: @"%@ %@", [super bark], [super bark]]; } @end That code calls super’s implementation of bark, twice; it assembles the two resulting strings into a single string with a space between, and returns that (using the stringWithFormat: method). Because Dog’s bark method returns @"Woof!", NoisyDog’s bark method returns @"Woof! Woof!". Notice that there is no circularity or recursion here: NoisyDog’s bark method will never call itself. A nice feature of this architecture is that by sending a message to the keyword super, rather than hard-coding @"Woof!" into NoisyDog’s bark method, we ensure maintain‐ ability: if Dog’s bark method is changed, the result of NoisyDog’s bark method will change to match. For example, if we later go back and change Dog’s bark method to return @"Arf!", NoisyDog’s bark method will return @"Arf! Arf!" with no further change on our part. In real Cocoa programming, it will very often be Cocoa’s own methods that you’re overriding. For example, the UIViewController class, which is built into Cocoa, imple‐ ments a method viewDidAppear:, defined as follows: - (void)viewDidAppear:(BOOL)animated The documentation says that UIViewController is a class for which you are very likely to define a subclass (so as to get all of UIViewController’s mighty powers — we’ll find out what they are in Chapter 19 — along with your own custom behavior). The docu‐ The Keyword super | 97 mentation proceeds to suggest that in your subclass of UIViewController you might want to override this method, but cautions that if you do, “you must call super at some point in your implementation.” The phrase “call super” is a kind of shorthand, meaning “pass on to super the very same call and arguments that were sent to you.” So your own implementation might look like this: @implementation MyViewController : UIViewController // ... - (void) viewDidAppear: (BOOL) animated { [super viewDidAppear: animated]; // ... do more stuff here ... } The result is that when viewDidAppear: is called in a MyViewController instance, we do both the standard stuff that its superclass UIViewController does in response to viewDidAppear: and the custom stuff pertaining to our own class MyViewController. In this particular case, we don’t even know exactly what the UIViewController stuff is, and we don’t care. When the documentation tells you to call super when overriding, call super when overriding! Instance Variables and Accessors In Chapter 3, I explained that one of the main reasons there are instances and not just classes is that instances can have instance variables. Instance variables, you remember, are declared when you define the class, and in Chapter 4 I said that these declarations go into curly braces at the start of the class’s interface section or, in modern ObjectiveC, its implementation section. But the value of an instance variable differs for each instance. The term “instance variable” arises so often that it is often abbreviated to ivar. I’ll use both terms indiscriminately from now on. Let’s write a class that uses an instance variable. Suppose we have a Dog class and we want every Dog instance to have a number, which should be an int. (For example, this number might correspond to the dog’s license number, or something like that.) In modern Objective-C, we would probably declare number in the implementation section for the Dog class, like this: @implementation Dog { int number; } // method implementations go here @end 98 | Chapter 5: Objective-C Instances (You might ask why, for this example, I don’t use instead the concept of giving the dog a name. The reason is that a name would be an NSString instance, which is an object; instance variables that are pointers to objects raise some additional issues I don’t want to discuss just now. But instance variables that are simple C data types raise no such issues. We’ll return to this matter in Chapter 12.) By default, instance variables are protected, meaning that other classes (except for sub‐ classes) can’t see them. So if, somewhere else, I instantiate a Dog, I won’t be able to access that Dog instance’s number instance variable. This is a deliberate feature of Objective-C; you can work around it if you like, but in general you should not. Instead, if you want to provide public access to an instance variable, write an accessor method and make the method declaration public. Within a class, on the other hand, that class’s own instance variables are global. Any Dog method can just use the variable name number and access this instance variable, just like any other variable. But code that does this can be confusing when you’re reading it; suddenly there’s a variable called number and you don’t understand what it is, because there’s no nearby declaration for it. So I often use a different notation, like this: self->ivarName. The “arrow” operator, formed by a minus sign and a greater-than sign, is called the structure pointer operator, because of its original use in C (K&R 6.2). So let’s write, in Dog’s implementation section, a method that allows setting a value for the number ivar: - (void) setNumber: (int) n { self->number = n; } Of course, to make setNumber: public to any other class that imports Dog’s interface file, we must also declare it in Dog’s interface section: @interface Dog : NSObject - (void) setNumber: (int) n; @end We can now instantiate a Dog and assign that instance a number: Dog* fido = [Dog new]; [fido setNumber: 42]; We can now set a Dog’s number, but we can’t get it (from outside that Dog instance). To correct this problem, we’ll write a second accessor method, one that allows for getting the value of the number ivar: - (int) number { return self->number; } Again, we declare the number method in Dog’s interface section. Now we can both set and get a Dog instance’s number: Instance Variables and Accessors | 99 Dog* fido = [Dog new]; [fido setNumber: 42]; int n = [fido number]; // sure enough, n is now 42! This architecture is very typical. Your class can have as many ivars as you like, but if you want them to be publicly accessible, you must provide accessor methods. Luckily, Objective-C 2.0 — which is what you’re using to program for iOS — provides a mech‐ anism for generating accessor methods automatically (discussed in Chapter 12), so you won’t have to go through the tedium of writing them by hand every time you want to make an ivar publicly accessible. (Though, to be honest, I don’t see why you shouldn’t have to go through that tedium; before Objective-C 2.0, we all had to, so why shouldn’t you? We also had to clean the roads with our tongues on the way to school. And we liked it! You kids today, you don’t know what real programming is.) You’ve probably noticed that Dog now has both a number method and a number instance variable. This fact should not confuse you. It doesn’t confuse the compiler, because the method name and the instance variable name are used in completely different ways in code. If the compiler can tell the difference, so can you. Nevertheless, a convention that is becoming increasingly common, for reasons that I’ll explain in Chapter 12, is to begin ivar names with an underscore: _number, not number. If we follow this convention and rename our ivar, we’ll also have to rewrite (but not rename) the methods that access it: @implementation Dog { int _number; } - (void) setNumber: (int) n { self->_number = n; } - (int) number { return self->_number; } @end Key–Value Coding Objective-C provides a means for translating from a string to an instance variable ac‐ cessor, called key–value coding. Such translation is useful, for example, when the name of the desired instance variable will not be known until runtime. So instead of calling [fido number], we might have a string @"number" that tells us what accessor to call. This string is the “key.” The key–value coding equivalent of calling a getter is valueForKey:; the equivalent of calling a setter is setValue:forKey:. 100 | Chapter 5: Objective-C Instances Thus, for example, suppose we wish to get the value of the number instance variable from the fido instance. We can do this by sending valueForKey: to fido. However, even though the number instance variable is an int, the value returned by valueForKey: is an object — in this case, an NSNumber, the object equivalent of a number (see Chapter 10). If we want the actual int, NSNumber provides an instance method, intValue, that lets us extract it: NSNumber* num = [fido valueForKey: @"number"]; int n = [num intValue]; Similarly, to use key–value coding to set the value of the number instance variable in the fido instance, we would say: NSNumber* num = [NSNumber numberWithInt:42]; [fido setValue: num forKey: @"number"]; Before handing off the number 42 as the value argument in setValue:forKey:, we had to wrap it up as an object — in this case, an NSNumber object. Starting with LLVM compiler version 4.0 (Xcode 4.4), there’s a syntactic shorthand for doing that; just as we can create an NSString by wrapping text in a compiler directive @"...", we can create an NSNumber by wrapping a numeric expression in a compiler directive @(...) — or, if the numeric expression is just a literal number, by preceding that literal number with @. So we can rewrite the previous example like this: NSNumber* num = @42; [fido setValue: num forKey: @"number"]; In real life, you’d probably omit the intermediate variable num and write the whole thing as a single line of code: [fido setValue: @42 forKey: @"number"]; In these examples there is no advantage to using key–value coding over just calling the accessors. But suppose we had received the value @"number" in a variable (as the result of a method call, perhaps). Suppose that variable is called something. Then we could say: id result = [fido valueForKey: something]; Thus we could access a different instance variable under different circumstances. This powerful flexibility is possible because Objective-C is such a dynamic language that a message to be sent to an object does not have to be formed until the program is already running. When you call valueForKey: or setValue:forKey:, the correct accessor method is called if there is one. Thus, when we use @"number" as the key, a number method and a setNumber: method are called if they exist. (This is one reason why your accessors should be properly named.) On the other hand, if there isn’t an accessor method, the instance variable is accessed directly. Such direct access violates the privacy of instance Key–Value Coding | 101 variables, so there’s a way to turn off this feature for a particular class if you don’t like it. (I’ll explain what it is, with more about key–value coding, in Chapter 12.) Properties A property is a syntactic feature of Objective-C 2.0 designed to provide an alternative to the standard syntax for calling an accessor method. As syntactic sugar for formally calling a method, you can append the property name to an instance reference using dotnotation. You can use the resulting expression either on the left side of an equal sign (to call the corresponding setter) or elsewhere (to call the corresponding getter). The name of the property relies, by default, on the accessor naming conventions. I’ll use the Dog class as an example. If the Dog class has a public getter method called number and a public setter method called setNumber:, then the Dog class also has a number property. This means that, instead of saying things like this: [fido setNumber: 42]; int n = [fido number]; You can talk like this: fido.number = 42; int n = fido.number; Your use of property syntax is entirely optional. The existence of a property is equivalent to the existence of the corresponding getter and setter methods, and you’re free to call those methods by either syntax. When you use property syntax in code, it is translated behind the scenes into a call to the corresponding getter or setter method, so it’s all the same if you call the corresponding getter or setter method explicitly. In the case of Dog, you can use number as a property, or you can call the getter and setter methods number and setNumber:. (Naturally, there are verbal quasi-religious wars on this topic, with one side claiming that property syntax is convenient and compact, and makes Objective-C more like other languages that use dot-notation, and the other side retorting that it does no such thing, because it is so limited. For example, property syntax opponents would argue, a UIScrollView has a contentView property, but when setting it you are most likely to want to animate the scroll view at the same time, which you do by calling setContentView:animated:. That’s a kind of setter, but it takes two parameters; property syntax can’t express that, so we’re back to using an explicit method call, and property syntax has saved us nothing, and in fact is more likely to mislead us into forgetting to add the animation. Another objection to property notation is that the compiler restricts its use; for example, you can use a formal method call to send the number message to a Dog instance typed as an id, but you can’t append the number property with dot-notation to such an instance.) 102 | Chapter 5: Objective-C Instances To use a property within the class that has that property, you must use self explicitly. So, for example: self.number = 42; Do not confuse a property with an instance variable. An expression like self->number = n, or even simply number = n, sets the instance vari‐ able directly (and is possible only within the class, because instance variables are protected by default). An expression like fido.number or self.number involves a property and is equivalent to calling a getter or setter method. That getter or setter method may access an instance variable, and that instance variable may even have the same name as the property, but that doesn’t make them the same thing. Properties will be taken up again in Chapter 12, where it will turn out that they are much more powerful and interesting beasts than I’m suggesting here. But I’m telling you about properties now because they are so widely used in Cocoa and because you’ll encounter them so frequently in the documentation. For example, in Chapter 1, I talked about setting a UIView’s autoresizingMask property: myView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth; How did I know I could talk that way? Because the UIView documentation says that UIView has an autoresizingMask property. Near the top of the documentation page, we see this line: autoresizingMask property And further down, we get the details: autoresizingMask An integer bit mask that determines how the receiver resizes itself when its superview’s bounds change. @property(nonatomic) UIViewAutoresizing autoresizingMask That last line is a property declaration. From the point of view of the UIView class’s client — in this case, that’s you — the property declaration is simply a shorthand, telling you that such a property exists, rather than bothering to tell you about the two accessor methods autoresizingMask and setAutoresizingMask:. (Never mind for now what nonatomic means.) That’s how I knew there was a setter setAutoresizingMask:. In my code, I used property syntax as a way of calling that setter method; alternatively, I could have called setAutoresizingMask: explicitly. Properties | 103 Similarly, earlier in this chapter I called UIView’s setFrame: method, even though no such method is mentioned in the UIView documentation. What the UIView documen‐ tation does say is this: frame The frame rectangle, which describes the view’s location and size in its superview’s co‐ ordinate system. @property(nonatomic) CGRect frame The documentation is telling me about the UIView property name frame, but that’s the same thing as telling me about the existence of UIView instance methods frame and setFrame:; I can use these methods either through the frame property and dot-notation or by calling them explicitly. Objective-C uses dot-notation for properties, and C uses dot-notation for structs; these can be chained. So, for example, UIView’s frame is a property whose value is a struct (a CGRect); thus, you can say myView.frame.size.height, where frame is a property that returns a struct, size is an element of that struct, and height is an element of that struct. But there are limitations on this syntax; you cannot (for example) set a frame’s height directly through a chain starting with the UIView, like this: myView.frame.size.height = 36.0; // error, "Expression is not assignable" Instead, if you want to change a component of a struct property, you must fetch the property value into a struct variable, change the struct variable’s value, and set the entire property value from the struct variable: CGRect f = myView.frame; f.size.height = 0; myView.frame = f; How to Write an Initializer Now that you know about self and super and instance variables, we can return to a topic that I blithely skipped over earlier. I described how to initialize a newly minted instance by calling an initializer, and emphasized that you must always do so, but I said nothing about how to write an initializer in your own classes. You will wish to do so only when you want your class to provide a convenient initializer that goes beyond the functionality of the inherited initializers. Often your purpose will be to accept some parameters and use them to set the initial values of some instance variables. For example, in the case of a Dog with a number, let’s say we don’t want any Dog instances to come into existence without a number; every Dog must have one. So having a value for its number ivar is a sine qua non of a Dog being instantiated in the first place. An 104 | Chapter 5: Objective-C Instances initializer publicizes this rule and helps to enforce it — especially if it is the class’s des‐ ignated initializer. So let’s decide that this initializer will be Dog’s designated initializer. Moreover, let’s say that a Dog’s number should not be changed. Once the Dog has come into existence, along with a number, that number should remain attached to that Dog instance for as long as that Dog instance persists. So delete the setNumber: method and its declaration, thus destroying any ability of other classes to set a Dog instance’s number after it has been initialized. Instead, we’re going to set a Dog’s number as it is initialized, using a method we’ll declare like this: - (id) initWithNumber: (int) n Our return value is typed as id, not as a pointer to a Dog, even though in fact we will return a Dog object. This is a convention that we should obey. The name is conventional as well; as you know, the init beginning tells the world this is an initializer. Now I’m just going to show you the actual code for the initializer (Example 5-3). Much of this code is conventional — a dance you are required to do. You should not question this dance: just do it. I’ll describe the meaning of the code, but I’m not going to try to justify all the parts of the convention. Example 5-3. Conventional schema for an initializer - (id) initWithNumber: (int) n { self = [super init]; if (self) { self->_number = n; } return self; } The parts of the convention are: We send some sort of initialization message, calling a designated initializer. If the method we are writing is our class’s designated initializer, this message is sent to super and calls the superclass’s designated initializer. Otherwise, it is sent to self and calls either this class’s designated initializer or another initializer that calls this class’s designated initializer. In this case, the method we are writing is our class’s designated initializer, and the superclass’s designated initializer is init. We capture the result of the initialization message to super, and assign that result to self. It comes as a surprise to many beginners (and not-so-beginners) that one can assign to self at all or that it would make sense to do so. But one can assign to self (because of how Objective-C messaging works behind the scenes), and it makes sense to do so because in certain cases the instance returned from the call to super might not be same as the self we started with. How to Write an Initializer | 105 If self is not nil, we initialize any instance variables we care to. This part of the code is typically the only part you’ll customize; the rest will be according to the pattern. Observe that I don’t use any setter methods (or properties); in initializing an instance variable not inherited from the superclass, you should assign directly to the instance variable. We return self. All instance variables are set to a form of zero by alloc. Therefore, any instance variables not initialized explicitly in an initializer remain 0. This means, among other things, that by default a BOOL instance vari‐ able is NO and an object reference instance variable is nil. It is common practice to take advantage of these defaults in your program; if the de‐ fault values are satisfactory initial values, you won’t bother to set them in your designated initializer. But we are not finished. Recall from earlier in this chapter that a class that defines a designated initializer should also override the inherited designated initializer (in this case, init). And you can see why: if we don’t, someone could say [[Dog alloc] init] (or [Dog new]) and create a dog without a number — the very thing our initializer is trying to prevent. Just for the sake of the example, I’ll make the overridden init assign a negative number as a signal that there’s a problem. Notice that we’re still obeying the rules: this initializer is not the designated initializer, so it calls this class’s designated initializer. - (id) init { return [self initWithNumber: -9999]; } Just to complete the story, here’s some code showing how we now would instantiate a Dog: Dog* fido = [[Dog alloc] initWithNumber:42]; int n = [fido number]; // n is now 42; our initialization worked! 106 | Chapter 5: Objective-C Instances PART II IDE By now, you’re doubtless anxious to jump in and start writing an app. To do that, you need a solid grounding in the tools you’ll be using. The heart and soul of those tools can be summed up in one word: Xcode. In this part of the book we explore Xcode, the IDE (integrated development environment) in which you’ll be programming iOS. Xcode is a big program, and writing an app involves coordinating a lot of pieces; this part of the book will help you become comfortable with Xcode. Along the way, we’ll generate a simple working app through some hands-on tutorials. • Chapter 6 tours Xcode and explains the architecture of the project, the collection of files from which an app is generated. • Chapter 7 is about nibs. A nib is a file containing a drawing of your interface. Un‐ derstanding nibs — knowing how they work and how they relate to your code — is crucial to your use of Xcode and to proper development of just about any app. • Chapter 8 pauses to discuss the Xcode documentation and other sources of infor‐ mation on the API. • Chapter 9 explains editing your code, testing and debugging your code, and the various steps you’ll take on the way to submitting your app to the App Store. You’ll probably want to skim this chapter quickly at first, returning to it as a detailed reference later while developing and submitting an actual app. CHAPTER 6 Anatomy of an Xcode Project Xcode is the application used to develop an iOS app. An Xcode project is the source for an app; it’s the entire collection of files and settings needed to construct the app. To create, develop, and maintain an app, you must know how to manipulate and navigate an Xcode project. So you must know something about Xcode, and you must know something about the nature and structure of Xcode projects and how Xcode shows them to you. That’s the subject of this chapter. The term “Xcode” is actually used in two ways. It’s the name for the entire suite of developer tools — the Xcode tools — and it’s the name of one application within that suite, the application in which you edit and build your app. This ambiguity should generally present little dif‐ ficulty. Xcode is a powerful, complex, and extremely large program. My approach in introduc‐ ing Xcode is to suggest that you adopt a kind of deliberate tunnel vision: if you don’t understand something, don’t worry about it — don’t even look at it, and don’t touch it, because you might change something important. Our survey of Xcode will chart a safe, restricted, and essential path, focusing on aspects of Xcode that you most need to un‐ derstand immediately, and resolutely ignoring everything else. For full information, study Apple’s own documentation (choose Help → Xcode Help); it may seem overwhelming at first, but what you need to know is probably in there somewhere. There are also entire books devoted to describing and explaining Xcode. 109 The structure of the Xcode installation changed starting with Xcode 4.3. The Developer folder in Xcode 4.2 and before was a top-level install folder. In Xcode 4.3 and later, the Developer folder is inside the Xcode application bundle itself, Xcode.app/Contents/Developer. When I say /Developer, this is the folder I’m referring to. New Project Even before you’ve written any code, an Xcode project is quite elaborate. To see this, let’s make a new, essentially “empty” project; you’ll see instantly that it isn’t empty at all. 1. Start up Xcode and choose File → New → Project. 2. The “Choose a template” dialog appears. The template is your project’s initial set of files and settings. When you pick a template, you’re really picking an existing folder full of files; basically, it will be one of the folders inside /Developer/Platforms/ iPhoneOS.platform/Developer/Library/Xcode/Templates/Project Templates/Appli‐ cation. This template folder will essentially be copied, and a few values will be filled in, in order to create your project. So, in this case, on the left, under iOS (not Mac OS X!), choose Application. On the right, select Single View Application. Click Next. 3. You are now asked to provide a name for your project (Product Name). Let’s call our new project Empty Window. In a real project, you should give some thought to the project’s name, as you’re going to be living in close quarters with it. As Xcode copies the template folder, it’s going to use the project’s name to “fill in the blank” in several places, including some filenames and some settings, such as the name of the app. Thus, whatever you type at this moment is something you’ll be seeing in a lot of places throughout your project. I’ll talk at the end of this chapter about how to change an existing project’s name. It’s fine to use spaces in a project name. Spaces are legal in the folder name, the project name, the app name, and the various names of files that Xcode will generate automatically; and in the few places where spaces are problematic (such as the bundle identifier, discussed in the next paragraph), the name you type as the Prod‐ uct Name will have its spaces converted to hyphens. 4. Note the Company Identifier field. The first time you create a project, this field will be blank, and you should fill it in. The goal here is to create a unique string (unique to you personally); your app’s bundle identifier, which is shown in gray below the company identifier, will consist of the company identifier plus a version of the project’s name, and because every project should have a unique name, the bundle 110 | Chapter 6: Anatomy of an Xcode Project identifier will also be unique and will thus uniquely identify this project along with the app that it produces and everything else connected with it. The convention is to start the company identifier with com. and to follow it with a string (possibly with multiple dot-components) that no one else is likely to use. For example, I use com.neuburg.matt. 5. Make sure the Devices pop-up menu is set to iPhone. Make sure that Use Automatic Reference Counting is checked but that the other two checkboxes are unchecked. (Ignore the Class Prefix field for now; it should be empty, with its default value “XYZ” shown in gray.) Click Next. 6. You’ve now told Xcode how to construct your project. Basically, it’s going to copy the Single View Application.xctemplate folder from within the Project Templates/ Application folder I mentioned earlier. But you need to tell it where to copy this template folder to. That’s why Xcode is now presenting a Save dialog. You are to specify the location of a folder that is about to be created — a folder that will be the project folder for this project. The project folder can go just about anywhere, and you can move it after creating it. I usually create new projects on the Desktop. 7. Xcode also offers to create a git repository for your project. In real life, this can be a great convenience (see Chapter 9), but for now, uncheck that checkbox. Click Create. 8. The Empty Window project folder is created on disk (on the Desktop, if that’s the location you just specified), and the project window for the Empty Window project opens in Xcode. The project we’ve just created is a working project; it really does build an iOS app called Empty Window. To see this, make sure that the Scheme pop-up menu in the project window’s toolbar reads Empty Window → iPhone 6.0 Simulator (though the exact sys‐ tem version number might be different), and choose Product → Run. After some delay, the iOS Simulator application eventually opens and displays your app running — an empty gray screen. To build a project is to compile its code and assemble the compiled code, together with various resources, into the actual app. Typically, if you want to know whether your code compiles and your project is consis‐ tently and correctly constructed, you’ll build the project (Product → Build). To run a project is to launch the built app, in the Simulator or on a connected device; if you want to know whether your code works as expected, you’ll run the project (Product → Run), which automati‐ cally builds first if necessary. New Project | 111 Figure 6-1. The project window, on steroids The Project Window An Xcode project embodies a lot of information about what files constitute the project and how they are to be used when building the app, such as: • The source files (your code) that are to be compiled • Any resources, such as icons, images, or sound files, as well as nib and storyboard files, that are to be part of the app • Any frameworks to which the code must be linked as the app is built • All settings (instructions to the compiler, to the linker, and so on) that are to be obeyed as the app is built Xcode presents this information in graphical form, and this is one reason why a project window is so elaborate, and why learning to navigate and understand it takes time. Also, this single window must let you access, edit, and navigate your code, as well as reporting the progress and results of such procedures as building or debugging an app. In short, the single project window displays a lot of information and embodies a lot of function‐ ality. You won’t lose your way, however, if you just take a moment to explore this window and see how it is constructed. Figure 6-1 shows the project window, configured in rather an extreme manner, so as to display as many parts of the window as possible. In real life, you’d probably never show all these parts of the window at the same time, except very briefly, unless you had a really big monitor. 112 | Chapter 6: Anatomy of an Xcode Project 1. On the left is the Navigator pane. Show and hide it with View → Navigators → Show/ Hide Navigator (Command-0) or with the first button in the View segmented con‐ trol in the toolbar. 2. In the middle is the Editor pane (or simply “editor”). This is the main area of a project window. A project window nearly always displays at least one Editor pane. I could have made this window display multiple Editor panes, but I was afraid that might make you run screaming from the room. 3. On the right is the Utilities pane. Show and hide it with View → Utilities → Show/ Hide Utilities (Command-Option-0) or with the third button in the View segmen‐ ted control in the toolbar. 4. At the bottom is the Debugger pane. Show and hide it with View → Show/Hide Debug Area (Shift-Command-Y) or with the second button in the View segmented control in the toolbar. All Xcode keyboard shortcuts can be customized; see the Key Bindings pane of the Preferences window. Keyboard shortcuts that I cite are the defaults. The Navigator Pane The Navigator pane is the column of information at the left of the window. Among other things, it’s your primary mechanism for controlling what you see in the main area of the project window. An important general use pattern for Xcode is: you select something in the Navigator pane, and that thing is displayed in the main area (the editor) of the project window. It is possible to toggle the visibility of the Navigator pane (View → Navigators → Hide/ Show Navigator, or Command-0); for example, once you’ve used the Navigator pane to reach the item you want to see or work on in the editor, you might hide the Navigator pane temporarily to maximize your screen real estate (especially on a smaller monitor). You can change the Navigator pane’s width by dragging the vertical line at its right edge. The Navigator pane itself can display seven different sets of information; thus, there are actually seven navigators. These are represented by the seven icons across its top; to switch among them, use these icons or their keyboard shortcuts (Command-1, Command-2, and so on). You will quickly become adept at switching to the navigator you want; their keyboard shortcuts will become second nature. If the Navigator pane is hidden, pressing a navigator’s keyboard shortcut both shows the Navigator pane and switches to that navigator. The Project Window | 113 Depending on your settings in the Behaviors pane of Xcode’s preferences, a navigator might show itself automatically when you perform a certain action. For example, by default, when you build your project, if warning messages or error messages are gen‐ erated, the Issue navigator will appear. This automatic behavior will not prove trouble‐ some, because it is generally precisely the behavior you want, and if it isn’t, you can change it; plus you can easily switch to a different navigator at any time. Let’s begin experimenting immediately with the various navigators: Project navigator (Command-1) Click here for basic navigation through the files that constitute your project. For example, in the Empty Window folder (these folder-like things in the Project nav‐ igator are actually called groups), click AppDelegate.m to view its code in the editor (Figure 6-2). At the top level of the Project navigator, with a blue Xcode icon, is the Empty Win‐ dow project itself; click it to view the settings associated with your project and its targets. Don’t change anything here without knowing what you’re doing! I’ll talk later in this chapter about what these settings are for. The filter bar at the bottom of the Project navigator lets you limit what files are shown; when there are many files, this is great for quickly reaching a file with a known name. For example, try typing “delegate” in the filter bar search field. Don’t forget to remove your filter when you’re done experimenting. Once you’ve filtered a navigator, it stays filtered until you remove the filter — even if you close the project! A common mistake is to filter a navigator, forget that you’ve done so, fail to notice the filter (because you’re looking at the navigator itself, not down at the bottom where the filter bar is), and wonder, “Hey, where did all my files go?” Symbol navigator (Command-2) A symbol is a name, typically the name of a class or method. Depending on which of the three icons in the filter bar at the bottom of the Symbol navigator you high‐ light, you can view Cocoa’s built-in symbols or the symbols defined in your project. The former can be a useful form of documentation; the latter can be helpful for navigating your code. For example, highlight the first two icons in the filter bar (the first two are dark-colored, the third is light), and see how quickly you can reach the definition of AppDelegate’s applicationDidBecomeActive: method. Try highlighting the filter bar icons in various ways to see how the contents of the Symbol navigator change. Type in the search field in the filter bar to limit what appears in the Symbol navigator; for example, try typing “active” in the search field, and see what happens. 114 | Chapter 6: Anatomy of an Xcode Project Figure 6-2. The Project navigator Search navigator (Command-3) This is a powerful search facility for finding text globally in your project, and even in the headers of Cocoa frameworks. You can also summon the Search navigator with Edit → Find → Find in Workspace (Shift-Command-F). To access the full set of options, click the magnifying glass and choose Show Find Options. For example, try searching for “delegate” (Figure 6-3). Click a search result to jump to it in your code. You can type in the other search field, the one in the filter bar at the bottom, to limit further which search results are displayed. (I’m going to stop calling your attention to the filter bar now, but every navigator has it in some form.) Issue navigator (Command-4) You’ll need this navigator primarily when your code has issues. This doesn’t refer to emotional instability; it’s Xcode’s term for warning and error messages emitted when you build your project. To see the Issue navigator in action, you’ll need to give your code an issue. For example, navigate (as you already know how to do, in at least three different ways) to the file AppDelegate.m, and in the blank line after the last comment at the top of the file’s contents, above the #import line, type howdy. Build (Command-B), saving if you’re prompted to. The Issue navigator will display numerous error messages, showing that the compiler is totally unable to cope with this illegal word appearing in an illegal place. Click an issue to see it within its file. In your code, issue “balloons” may appear to the right of lines containing issues; if you’re distracted or hampered by these, toggle their visibility with Editor → Issues → Hide/Show All Issues (Control-Command-M). The Project Window | 115 Figure 6-3. The Search navigator Now that you’ve made Xcode miserable, select “howdy” and delete it; build again, and your issues will be gone. If only real life were this easy! Debug navigator (Command-5) By default, this navigator will appear when your code is paused while you’re de‐ bugging it. There is not a strong distinction in Xcode between running and de‐ bugging; the milieu is the same. The difference is mostly a matter of whether break‐ points are obeyed (more about that, and about debugging in general, in Chap‐ ter 9). If your code runs and doesn’t pause, the Debug navigator by default won’t come into play. To see the Debug navigator in action, you’ll need to give your code a breakpoint. Navigate once more to the file AppDelegate.m, select in the line that says return YES, and choose Product → Debug → Add Breakpoint at Current Line to make a blue breakpoint arrow appear on that line. Run the project. (If the project is already running, the Stop dialog may appear; click Stop to terminate the current run and begin a new one.) By default, as the breakpoint is encountered, the Navigator pane switches to the Debug navigator, and the Debug pane appears at the bottom of the window. This overall layout (Figure 6-4) will rapidly become familiar as you debug your projects. The Debug navigator displays the call stack, with the names of the nested methods in which the pause occurs; as you would expect, you can click on a method name to navigate to it. You can shorten or lengthen the list with the slider at the 116 | Chapter 6: Anatomy of an Xcode Project Figure 6-4. The Debug layout bottom of the navigator. The Debug pane, which can be shown or hidden at will (View → Debug Area → Hide/Show Debug Area, or Shift-Command-Y), consists of two subpanes — the variables list and the console. Either of these can be hidden using the segmented control at the top right of the pane. The console can also be summoned by choosing View → Debug Area → Activate Console. • On the left, the variables list is populated with the variables in scope for the selected method in the call stack (and you can optionally display processor registers as well). • On the right is the console, where the debugger displays text messages; that’s how you learn of exceptions thrown by your running app. Exceptions are ex‐ tremely important to know about, and this is your only way to know about them, so keep an eye on the console as your app runs. You can also use the console to communicate via text with the debugger. This can often be a better way to explore variable values during a pause than the variables list. Breakpoint navigator (Command-6) This navigator lists all your breakpoints. At the moment you’ve only one, but when you’re actively debugging a large project with many breakpoints, you’ll be glad of this navigator. Also, this is where you create special breakpoints (such as symbolic breakpoints), and in general it’s your center for managing existing breakpoints. We’ll return to this topic in Chapter 9. Log navigator (Command-7) This navigator lists your recent major actions, such as building or running (de‐ bugging) your project. Click on a listing to see the log file generated when you performed that action. The log file might contain information that isn’t displayed in any other way, and also it lets you dredge up messages from the recent past (“What was that exception I got while debugging a moment ago?”). For example, by clicking on the listing for a successful build, and by choosing to display All and All Messages using the filter switches at the top of the log, we can The Project Window | 117 Figure 6-5. Viewing a log see the steps by which a build takes place (Figure 6-5). To reveal the full text of a step, click on that step and then click the Expand Transcript button that appears at the far right (and see also the menu items in the Editor menu). When navigating by clicking in the Navigator pane, modifications to your click can determine where navigation takes place. By default, Option-click navigates in an assis‐ tant pane (discussed later in this chapter), double-click navigates by opening a new window, and Shift-Option-click summons the navigation window, a little heads-up pane where you can specify where to navigate (a new window, a new tab, or a new assistant pane). For the settings that govern these click modifications, see the General pane of Xcode’s preferences. The Utilities Pane The Utilities pane is the column at the right of the project window. It contains inspectors that provide information about the current selection or its settings; in some cases, these inspectors let you change those settings. It also contains libraries that function as a source of objects you may need while editing your project. The Utilities pane’s impor‐ tance emerges mostly when you’re working in the nib editor (Chapter 7). But it can also be useful while editing code, because Quick Help, a form of documentation (Chap‐ ter 8), is displayed here as well, plus the Utilities pane is the source of code snippets (Chapter 9). To toggle the visibility of the Utilities pane, choose View → Utilities → Hide/Show Utilities (Command-Option-0). You can change the Utilities pane’s width by dragging the vertical line at its left edge. Many individual inspectors and libraries are discussed in subsequent chapters. Here, I’ll just describe the overall physical characteristics of the Utilities pane. The Utilities pane consists of a set of palettes. Actually, there are so many of these palettes that they are clumped into multiple sets, divided into two major groups: the top half of 118 | Chapter 6: Anatomy of an Xcode Project the pane and the bottom half of the pane. You can change the relative heights of these two halves by dragging the horizontal line that separates them. The top half What appears in the top half of the Utilities pane depends on what’s selected in the current editor. There are two main cases: A code file is being edited The top half of the Utilities pane shows either the File inspector or Quick Help. Toggle between them with the icons at the top of this half of the Utilities pane, or with their keyboard shortcuts (Command-Option-1, Command-Option-2). The File inspector is rarely needed, but Quick Help can be useful as documen‐ tation. The File inspector consists of multiple sections, each of which can be expanded or collapsed by clicking its header. A nib or storyboard file is being edited The top half of the Utilities pane shows, in addition to the File inspector and Quick Help, the Identity inspector (Command-Option-3), the Attributes in‐ spector (Command-Option-4), the Size inspector (Command-Option-5), and the Connections inspector (Command-Option-6). Like the File inspector, these can consist of multiple sections, each of which can be expanded or col‐ lapsed by clicking its header. The bottom half The bottom half of the Utilities pane shows one of four libraries. Toggle between them with the icons at the top of this half of the Utilities pane, or with their keyboard shortcuts. They are the File Template library (Command-Option-Control-1), the Code Snippet library (Command-Option-Control-2), the Object library (Command-Option-Control-3), and the Media library (Command-OptionControl-4). The Object library is the most important; you’ll use it heavily when editing a nib or storyboard. To see a help pop-up describing the currently selected item in a library, press Spacebar. The Editor In the middle of the project window is the editor. This is where you get actual work done, reading and writing your code (Chapter 9), or designing your interface in a nib or storyboard file (Chapter 7). The editor is the core of the project window. You can eliminate the Navigator pane, the Utilities pane, and the Debug pane, but there is no such thing as a project window without an editor (though you can cover the editor completely with the Debug pane). The editor provides its own form of navigation, the jump bar across the top. Not only does the jump bar show you hierarchically what file is currently being edited, but also The Project Window | 119 it allows you to switch to a different file. In particular, each path component in the jump bar is also a pop-up menu. These pop-up menus can be summoned by clicking on a path component, or by using keyboard shortcuts (shown in the second section of the View → Standard Editor submenu). For example, Control-4 summons a hierarchical pop-up menu, which can be navigated entirely with the keyboard, allowing you to choose a different file in your project to edit. Moreover, each pop-up menu in the jump bar also has a filter field; to see it, summon a pop-up menu from the jump bar and start typing. Thus you can navigate your project even if the Project navigator isn’t showing. It is extremely likely, as you develop a project, that you’ll want to edit more than one file simultaneously, or obtain multiple views of a single file so that you can edit two areas of it simultaneously. This can be achieved in three ways: assistants, tabs, and secondary windows. Assistants You can split the editor into multiple editors by summoning an assistant pane. To do so, click the second button in the Editor segmented control in the toolbar, or choose View → Assistant Editor → Show Assistant Editor (Command-OptionReturn). Also, by default, adding the Option key to navigation opens an assistant pane; for example, Option-click in the Navigator pane, or Option-choose in the jump bar, to navigate by opening an assistant pane (or to navigate in an existing assistant pane if there is one). To remove the assistant pane, click the first button in the Editor segmented control in the toolbar, or choose View → Standard Editor → Show Standard Editor (Command-Return), or click the X button at the assistant pane’s top right. Your first task will be to decide how you want multiple editor panes arranged with respect to one another. To do so, choose from the View → Assistant Editor submenu. I usually prefer All Editors Stacked Vertically, but it’s purely a matter of personal taste and convenience. Once you’ve summoned an assistant pane, you can split it further into additional assistant panes. To do so, click the Plus button at the top right of an assistant pane. To dismiss an assistant pane, click the X button at its top right. What makes an assistant pane an assistant, and not just a form of split-pane editing, is that it can bear a special relationship to the primary editor pane. The primary editor pane is the one whose contents, by default, are determined by what you click on in the Navigator pane; an assistant pane, meanwhile, can respond to what file is being edited in the primary editor pane by changing intelligently what file it (the assistant pane) is editing. This is called tracking. To see tracking in action, open a single assistant pane and set the first component in its jump bar to Counterparts (Figure 6-6). Now use the Project navigator to select AppDelegate.m; the primary editor pane displays this file, and the assistant auto‐ matically displays AppDelegate.h. Next, use the Project navigator to select App‐ 120 | Chapter 6: Anatomy of an Xcode Project Figure 6-6. Telling an assistant pane to display counterparts Delegate.h; the primary editor pane displays this file, and the assistant automatically displays AppDelegate.m. There’s a lot of convenience and power lurking here, which you’ll explore as you need it. Tabs You can embody the entire project window interface as a tab. To do so, choose File → New → Tab (Command-T), revealing the tab bar (just below the toolbar) if it wasn’t showing already. Use of a tabbed interface will likely be familiar from appli‐ cations such as Safari. You can switch between tabs by clicking on a tab, or with Command-Shift-}. At first, your new tab will look largely identical to the original window from which it was spawned. But now you can make changes in a tab — change what panes are showing or what file is being edited, for example — without affecting any other tabs. Thus you can get multiple views of your project. You can assign a descriptive name to a tab: double-click on a tab name to make it editable. Secondary windows A secondary project window is similar to a tab, but it appears as a separate window instead of a tab in the same window. To create one, choose File → New → Window (Command-Shift-T). Alternatively, you can promote a tab to be a window by drag‐ ging it right out of its current window. Or choose Navigate → Open In and navigate left in the resulting dialog until the dialog offers to make a new window. There isn’t a strong difference between a tab and a secondary window; which you use, and for what, will be a matter of taste and convenience. I find that the advantage of a secondary window is that you can see it at the same time as the main window, and that it can be small. Thus, when I have a file I frequently want to refer to, I often spawn off a secondary window displaying that file, sized fairly small and without any panes other than the editor. The Project Window | 121 Figure 6-7. The Project navigator again The Project File and Its Dependents Now that you’re comfortable with the Xcode project window, you’re ready to explore the project and its constituents. The first item in the Project navigator (Command-1) represents the project file on disk (in our new project, this is called Empty Window). Hierarchically dependent upon it are items that contribute to the building of the project (Figure 6-7). Many of these items, including the project file itself, correspond to items on disk in the project folder. To survey this correspondence, let’s examine the project folder in the Finder simultaneously with the Xcode project window. Select the project file listing in the Project navigator and choose File → Show in Finder. The Finder displays the contents of your project folder (Figure 6-8). The most important of these is Empty Window.xcodeproj. This is the project file. All Xcode’s knowledge about your project — what files it consists of and how to build the project — is stored in this file. To open a project from the Finder, double-click the project file. This will launch Xcode if it isn’t already running. 122 | Chapter 6: Anatomy of an Xcode Project Figure 6-8. The project folder Never, never, never touch anything in a project folder by way of the Finder, except for double-clicking the project file to open the project. Don’t put anything directly into a project folder. Don’t remove any‐ thing from a project folder. Don’t rename anything in a project folder. Don’t touch anything in a project folder! Do all your interaction with the project through the project window in Xcode. (When you’re an Xcode power user, you’ll know when you can disobey this rule. Until then, just obey it blindly and rigorously.) The reason is that the project expects things in the project folder to be a certain way. If you make any alterations to the project folder directly in the Finder, behind the project’s back, you can upset those expecta‐ tions and break the project. When you work in the project window, it is Xcode itself that makes any necessary changes in the project folder, and all will be well. Consider now the groups and files shown in the Project navigator (Figure 6-7) as hier‐ archically dependent upon the project file, and how they correspond to reality on disk as portrayed in the Finder (Figure 6-8). (Recall that group is the technical term for the folder-like objects shown in the Project navigator.) Observe that groups in the Project navigator don’t necessarily correspond to folders on disk in the Finder, and folders on disk in the Finder don’t necessarily correspond to groups in the Project navigator. • The Empty Window group is, to some extent, real; it corresponds directly to the Empty Window folder on disk. If you were to create additional files (which, in real life, you would almost certainly do in the course of developing your project), you would likely put them in the Empty Window group in the Project navigator so that The Project File and Its Dependents | 123 they’d be in the Empty Window folder on disk. (Doing so, however, is not a re‐ quirement; your files can live anywhere and your project will still work fine.) • The Supporting Files group, on the other hand, corresponds to nothing on disk; it’s just a way of clumping some items together in the Project navigator, so that they can be located easily and can be shown or hidden together. The things inside this group are real, however; you can see that the four files Empty Window-Info.plist, InfoPlist.strings, Empty Window-Prefix.pch, and main.m, along with the three De‐ fault.png files, do exist on disk — they’re just not inside anything called Supporting Files. Rather, they’re at the top level of the Empty Window folder. • Two files, InfoPlist.strings and ViewController.xib, appear in the Finder inside a folder called en.lproj, which doesn’t appear in the Project navigator. The folder en.lproj has to do with localization, which I’ll discuss in Chapter 9. You may be tempted to find all this confusing. Don’t! Remember what I said about not involving yourself with the project folder on disk in the Finder. Keep your attention on the Project navigator, make your modifications to the project there, and all will be well. By convention, as you add other files to your project that are not code but need to be copied into the app as it is built, such as sound and image files, you would usually put them into yet another group — probably, though not necessarily, a group inside the Empty Window group. You might call this group Resources. (I usually do.) And as your project grows further, you should feel free to create even more groups to help organize your files. To make a new group, choose File → New → Group. To rename a group, select it in the Project navigator and press Return to make the name editable. When I say “feel free,” I mean it. You want navigating your project to be easy and intuitive. That’s what groups are for. They are just ways of making the Project navigator work well for you. As we’ve seen, they don’t necessarily affect how the actual files are stored on disk. Even more important, they don’t affect how the app is built. It is not the placement of files in groups or in the Finder that causes them to be built into the app; it’s their inclusion in the appropriate target build phase, as I’ll explain later in this chapter. The things in the Frameworks group and the Products group don’t correspond to any‐ thing in the project folder, but they do correspond to real things that the project needs to know about in order to build and run: Frameworks This group, by convention, lists frameworks (Cocoa code) on which your code depends. Frameworks exist on disk, but they are not built into your app when it is constructed; they don’t have to be, because they are present also on the target device (an iPhone, iPod touch, or iPad). Instead, the frameworks are linked to the app, meaning that the app knows about them and expects to find them on the device when it runs. Thus, all the framework code is omitted from the app itself, saving considerable space. 124 | Chapter 6: Anatomy of an Xcode Project Products This group, by convention, holds an automatically generated reference to the built app. The Target A target is a collection of parts along with rules and settings for how to build a product from them. It is a major determinant of how an app is built. Whenever you build, what you’re really building is a target. Select the Empty Window project at the top of the Project navigator, and you’ll see two things on the left side of the editor: the project itself, and a list of your targets. In this case, there is only one target, called Empty Window (just like the project itself). But there could be more than one target, under certain circumstances. For example, you might want to write an app that can be built as an iPhone app or as an iPad app — two different apps that share a lot of the same code. So you might want one project containing two targets. If you select the project in the left side of the editor, you edit the project. If you select the target in the left side of the editor, you edit the target. I’ll use those expressions a lot in later instructions. Build Phases Edit the target and click Build Phases at the top of the editor (Figure 6-9). These are the stages by which your app is built. By default, there are three of them with content — Compile Sources, Link Binary With Libraries, and Copy Bundle Resources — and those are the only stages you’ll usually need, though you can add others. The build phases are both a report to you on how the target will be built and a set of instructions to Xcode on how to build the target; if you change the build phases, you change the build process. The meanings of the three build phases are pretty straightforward: Compile Sources Certain files (your code) are compiled, and the resulting compiled code is copied into the app. Link Binary With Libraries Certain libraries, usually frameworks, are linked to the compiled code (now referred to as the binary), so that it will expect them to be present on the device when the app runs. Copy Bundle Resources Certain files are copied into the app, so that your code or the system can find them there when the app runs. For example, if your app had an icon, it would need to be copied into the app so the device could find and display it. The Target | 125 Figure 6-9. Build phases By opening the build phases in the editor, you can see the files to which each phase applies. The first phase, Compile Sources, presently compiles three files (main.m, App‐ Delegate.m, and ViewController.m). The second phase, Link Binary With Libraries, presently links three libraries (frameworks). The third phase, Copy Bundle Resources, presently copies five files — InfoPlist.strings, ViewController.xib (a nib file), and three .png files that supply a default image of your app as it launches, as explained in Chapter 9. You can alter these lists. If something in your project was not in Copy Bundle Resources and you wanted it copied into the app during the build process, you would drag it from the Project navigator into the Copy Bundle Resources list, or (easier) click the Plus button beneath the Copy Bundle Resources list to get a helpful dialog listing everything in your project. If something in your project was in Copy Bundle Resources and you didn’t want it copied in the app, you would delete it from the list; this would not delete it from your project, from the Project navigator, or from the Finder, but only from the list of things to be copied into your app. Build Settings Build phases are only one aspect of how a target knows how to build the app. The other aspect is build settings. To see them, edit the target and click Build Settings at the top 126 | Chapter 6: Anatomy of an Xcode Project Figure 6-10. Target build settings of the editor (Figure 6-10). Here you’ll find a long list of settings, most of which you’ll never touch. But Xcode examines this list in order to know what to do at various stages of the build process. Build settings are the reason your project compiles and builds the way it does. You can determine what build settings are displayed by clicking Basic or All. The settings are combined into categories, and you can close or open each category heading to save room. If you know something about a setting you want to see, such as its name, you can use the search field at the top right to filter what settings are shown. You can determine how build settings are displayed by clicking Combined or Levels; in Figure 6-10, I’ve clicked Levels, in order to discuss what levels are. It turns out that not only does a target contain values for the build settings, but the project also contains values for the same build settings; furthermore, Xcode has certain built-in default build setting values. The Levels display shows all of these levels at once, so you can understand the derivation of the actual values used for every build setting. To understand the chart, read from right to left. For example, the iOS default for the Build Active Architecture Only setting’s Debug configuration (far right) is No. But then the project comes along (second column from the right) and sets it to Yes. The target (third column from the right) doesn’t change that setting, so the result (fourth column from the right) is that the setting resolves to Yes. If you wanted to change this value, you could, here and now. You could change the value at the project level or at the target level. I’m not suggesting that you should do so; indeed, you will rarely have occasion to manipulate build settings directly, as the defaults are usually acceptable. Nevertheless, you can change build setting values, and this is where you would do so. For details on what the various build settings are, consult Apple’s documentation, especially the Xcode Build Setting Reference. Also, you can select a build setting and show Quick Help in the Utilities pane to learn more about it. The Target | 127 Figure 6-11. Configurations Configurations There are actually multiple lists of build setting values — though only one such list applies when a build is performed. Each such list is called a configuration. Multiple configurations are needed because you build in different ways at different times for different purposes, and thus you’ll want certain build settings to take on different values under different circumstances. By default, there are two configurations: Debug This configuration is used throughout the development process, as you write and run your app. Release This configuration is used for late-stage testing, when you want to check perfor‐ mance on a device. Configurations exist at all because the project says so. To see where the project says so, edit the project and click Info at the top of the editor (Figure 6-11). Note that these configurations are just names. You can make additional configurations, and when you do, you’re just adding to a list of names. The importance of configurations emerges only when those names are coupled with build setting values. Configurations can affect build setting values both at the project level and at the target level. For example, return to the target build settings (Figure 6-10) and type “Optim” into the search field. Now you can look at the Optimization Level build setting. The Debug configuration value for Optimization Level is None: while you’re developing your app, you build with the Debug configuration, so your code is just compiled line by line in a straightforward way. The Release configuration value for Optimization Level is Fastest, Smallest; when your app is ready to ship, you build it with the Release configuration, so the resulting binary is faster and smaller, which is great for your users installing and running the app on a device, but would be no good while you’re developing the app because breakpoints and stepping in the debugger wouldn’t work properly. 128 | Chapter 6: Anatomy of an Xcode Project Schemes and Destinations So far, I have said that there are configurations, and I have explained that you may need to switch between configurations in order to get the build setting values appropriate for your current purpose. But I have not said how the configuration is determined as you actually build. It’s determined by a scheme. A scheme unites a target (or multiple targets) with a build configuration, with respect to the purpose for which you’re building. A new project comes by default with a single scheme, named after the project’s single target. Thus the Empty Window project’s single scheme is currently called Empty Window. To see it, choose Product → Edit Scheme. The scheme editor dialog opens. Make sure that Info at the top of the dialog is selected. On the left side of the scheme editor are listed various actions you might perform from the Product menu. Click an action to see its corresponding settings in this scheme. The first action, the Build action, is different from the other actions, because it is common to all of them (the other actions all implicitly involve building); thus the Build action merely determines what target(s) will be built when each of the other actions is per‐ formed, and for our simple project this is trivial, because we’ve only one target and we always need it built. So, now consider the Run action. When you click the Run action at the left, the editor displays the settings that will be used when you build and run (Figure 6-12). As you can see, the Build Configuration pop-up menu is set to Debug. That explains where the current build configuration comes from. At the moment, whenever you build and run, you’re using the Debug build configuration and the build setting values that correspond to it, because you’re using this scheme, and that’s what this scheme says to do when you build and run. Now dismiss the scheme editor, and consider how you might proceed if you wanted to build and run using the Release build configuration. (The Debug build configuration settings may affect the behavior of the built app, so you want to test the app as an actual user would experience it.) One way would be to return to the scheme editor and change the build configuration for the Run action for this scheme. Xcode makes this convenient: hold the Option key as you choose Product → Run (or as you click the Run button in the toolbar). The scheme editor appears, containing a Run button. So now you can make any changes you like, such as setting the Build Configuration pop-up menu to Release for the Run action, and proceed directly to build and run the app by clicking Run. (If you’re following along and you did make this change, open the scheme editor again and set the Build Configuration pop-up for the Run action in our Empty Window scheme back to Debug.) On the other hand, if you were to find yourself often wanting to switch between building and running with the Debug configuration and building and running with the Release configuration, you might create a distinct, additional scheme that uses the Release debug configuration for the Run action. This is easy to do: in the scheme editor, click Duplicate The Target | 129 Figure 6-12. The scheme editor Figure 6-13. The Scheme pop-up menu Scheme. The name of the new scheme is editable; let’s call it Release. Change the Build Configuration pop-up for the Run action in our new scheme to Release, and dismiss the scheme editor. Now you have two schemes, Empty Window (whose build configuration for running is Debug) and Release (whose build configuration for running is Release). To switch be‐ tween them easily, you can use the Scheme pop-up menu in the project window toolbar (Figure 6-13) before you build and run. The Scheme pop-up menu lists each scheme, along with each destination on which you might run your built app. A destination is effectively a machine that can run your app. For example, you might want to run the app in the Simulator or on a physical device. There is no configuration of destinations; you are automatically assigned destinations, 130 | Chapter 6: Anatomy of an Xcode Project Figure 6-14. The built app, in the Finder depending on what system your project is set to run on and what devices are connected to your computer. Destinations and schemes have nothing to do with one another; your app is built the same way regardless of your chosen destination. The presence of destinations in the Scheme pop-up menu is intended as a convenience, allowing you to use this one popup menu to choose either a scheme or a destination, or both, in a single move. To switch easily among destinations without changing schemes, click near the right end of the Scheme pop-up menu. To switch among schemes, possibly also determining the desti‐ nation (as shown in Figure 6-13), click near the left end of the Scheme pop-up menu. You can also switch among schemes or among destinations by using the scheme editor. From Project to App An app file is really a special kind of folder called a package (and a special kind of package called a bundle). The Finder normally disguises a package as a file and does not dive into it to reveal its contents to the user, but you can bypass this protection and investigate an app bundle with the Show Package Contents command. By doing so, you can study the internal structure of your built app bundle. We’ll use the Empty Window app that we built earlier as a sample minimal app to investigate. You’ll have to locate it in the Finder; by default, it should be somewhere in your user Library/Developer/Xcode/DerivedData folder, as shown in Figure 6-14. (If you’re using Mountain Lion, I presume you know how to reveal the user Library direc‐ tory. In theory, you should be able to select the app under Products in Xcode’s Navigation pane and choose File → Show in Finder, but there seems to be a long-standing bug preventing this.) In the Finder, Control-click the Empty Window app, and choose Show Package Contents from the contextual menu. From Project to App | 131 Figure 6-15. Contents of the app package Looking inside our minimal app bundle (Figure 6-15), we see that it contains these files: Default.png and friends The three launch image files have been copied to the top level of the bundle, where they can be found for display at launch time. Empty Window Our app’s compiled code (the binary). When the app is launched, the binary is linked to the various frameworks, and the code begins to run (starting with the entry point in the main function). Info.plist A configuration file in a strict text format (a property list file). It is derived from the project file Empty Window-Info.plist. It contains instructions to the system about how to treat and launch the app. For example, if our app had an icon, Info.plist would tell the system its name, so that the system could dive into the app bundle, find it, and display it. It also tells the system things like the name of the binary, so that the system can find it and launch the app correctly. PkgInfo A tiny text file reading APPL????, signifying the type and creator codes for this app. The PkgInfo file is something of a dinosaur; it isn’t really necessary for the func‐ tioning of an iOS app and is generated automatically. You’ll never need to touch it. InfoPlist.strings A text file intended for text appearing in our Info.plist that might need to be trans‐ lated into different languages. It is copied directly from InfoPlist.strings in the project. We haven’t edited this file, and our app currently appears only in English, so this file is of no interest at the moment (strings files are discussed in Chapter 9). ViewController.nib Our app’s only nib file. It contains instructions for generating the initial contents of our app’s main window (currently just a gray rectangle). It is created (“compiled”) 132 | Chapter 6: Anatomy of an Xcode Project from the ViewController.xib file in the project; a .xib file and a .nib file are different forms of the same thing. In real life, an app bundle will contain more files, but the difference will mostly be one of degree, not kind. For example, our project might have additional nib files, icon image files, and image or sound files. All of these would make their way into the app bundle. You are now in a position to appreciate, in a general sense, how the components of our project are treated and assembled into an app, and what responsibilities accrue to you, the programmer, in order to ensure that the app is built correctly. The rest of this chapter outlines what goes into the building of an app from a project. Build Settings We have already talked about how build settings are determined. Xcode itself, the project, and the target all contribute to the resolved build setting values, some of which may differ depending on the build configuration. Before building, you, the programmer, will have already specified a scheme; the scheme determines the build configuration, the specific set of build setting values that will apply as this build proceeds. Property List Settings Your project contains a property list file that will be used to generate the built app’s Info.plist file. The target knows what file it is because it is specified in the Info.plist File build setting. For example, in our project, the value of the Info.plist File build setting has been set automatically to Empty Window/Empty Window-Info.plist. (Take a look at the build settings and see!) Because the name of the file in your project from which the built app’s Info.plist file is generated will vary, depending on the name of the project, I’ll refer to it generically as the project’s Info.plist. The property list file is a collection of key–value pairs. You can edit it, and you may well need to do so. There are two main ways to edit your project’s Info.plist: • Select the Info.plist file in the Project navigator and edit in the editor. By default, the key names (and some of the values) are displayed descriptively, in terms of their functionality; for example, it says “Bundle name” instead of the actual key, which is CFBundleName. But you can view the actual keys by choosing Editor → Show Raw Keys & Values (you might have to click in the editor to enable this menu item). • Edit the target, and click Info at the top of the editor. This pane shows effectively the same information as editing the Info.plist in the editor. From Project to App | 133 For a complete list of the possible keys and their meanings, see Apple’s document Information Property List Key Reference. I’ll talk more in Chapter 9 about property list settings that you’re particularly likely to edit. Nib Files and Storyboard Files Every app that you write is likely to have at least one nib file (.xib) or storyboard file (.storyboard), and possibly more. You edit a nib file to describe graphically some objects that you want instantiated when the nib file loads (Chapter 5). By breaking your interface into multiple nib files, you simplify the relationship between each nib file and your code; also, if nibs that aren’t needed when your app launches aren’t loaded until they are needed, you speed up your app’s launch time, and you streamline your app’s memory usage (because nib objects are not instantiated until the nib is loaded, and can then be destroyed when they are no longer needed). A storyboard file is like many nib files in one: in it, you describe graphically the various interfaces (called scenes) that you want to appear as the user works with your app. Just as with nib files, a storyboard scene is transformed into actual interface only when it is needed for display, and the memory needed to maintain that interface can be given back when that interface is no longer showing. The target knows about your nib files and storyboard files because they appear in its Copy Bundle Resources build phase. In the case of a nib file in .xib format, the file is not merely copied into the app bundle; Xcode also translates (compiles) it into a small‐ er .nib file (using the ibtool tool). Similarly, Xcode translates (compiles) a .story‐ board file into a smaller .storyboardc file in the built app (again, using the ibtool tool). Nib files located inside your app bundle are typically loaded when they are needed as the app runs, usually because code tells them to load. If you elect to use a storyboard as the basis of your main interface, however, it will need to load before any code has a chance to do so. Such a storyboard file is called the main storyboard file. This situation is handled through the Info.plist file; it contains a key “Main storyboard file base name” (UIMainStoryboardFile), and the system sees this and loads the designated storyboard file automatically as the app launches. (Instead of a main storyboard file, it is possible to have a main nib file that loads automatically when the app launches; this was the standard approach for apps created with Xcode 3.2.x and Xcode 4.0, but none of the current Xcode project templates exemplify this approach, so I don’t discuss it in this edition of the book.) 134 | Chapter 6: Anatomy of an Xcode Project A universal app — that is, an app that runs both on the iPad and on the iPhone — typically has nib files or storyboard files in pairs, one to be loaded on the iPad and the other to be loaded on the iPhone. Thus the app can have different basic interfaces on the two different types of device. Naming conventions and Info.plist keys allow the runtime to know which nib or storyboard to load depending on the device type. For example, a second Info.plist key, “Main storyboard file base name (iPad)” (UIMainStoryboardFile~ipad), specifies the storyboard file to be loaded at launch time on the iPad. See Chapter 7 for more about editing nib files (and storyboard files) and how they create instances when your code runs. Full details on how nib files and storyboard files are loaded and why — in particular, their relationship to view controllers — appear in Chapter 19. Other Resources The three Default.png launch image files are examples of resource files. The target knows about them because they appear in its Copy Bundle Resources build phase. Such re‐ sources are copied more or less unchanged into the app bundle; I say “more or less” because it turns out that some files, such as .png files, may be optimized as they are copied when you build for a device. In real life, you are likely to add further resources to your project, because you want your running app to be able to fetch them out of its bundle. For example, if your app needs to display a certain image, you’d add the image to your project and make sure it appears in the Copy Bundle Resources build phase. When the app runs, your code (or possibly the code implied by a loaded nib file) reaches into the app bundle, locates the image, and displays it (Chapter 15). To add a resource to your project, start in the Project navigator and choose File → Add Files to Empty Window (or whatever the name of the project is). Alternatively, drag the resource from the Finder into the Project navigator. Either way, a dialog appears (Figure 6-16) containing a pane in which you make the following settings: Copy items into destination group’s folder (if needed) You should almost certainly check this checkbox. Doing so causes the resource to be copied into the project folder. If you leave this checkbox unchecked, your project will be relying on a file that’s outside the project folder and that you might delete or change unintentionally. Keeping everything your project needs inside the project folder is far safer. From Project to App | 135 Figure 6-16. Options when adding a resource to a project Folders This choice matters only if what you’re adding to the project is a folder. In both cases, whether the folder is copied into the project folder depends on whether you checked the checkbox discussed in the previous paragraph; the difference is in how the project references the folder contents: Create groups for any added folders The folder is expressed as a group within the Project navigator, but its contents all appear individually in the Copy Bundle Resources build phase, so they will all be copied individually into the app bundle. Create folder references for any added folders The folder itself is shown in blue in the Project navigator and appears as a folder in the Copy Bundle Resources build phase; thus, the build process will copy the entire folder and its contents into the app bundle. This means that the resources inside the folder won’t be at the top level of the bundle, but in a subfolder of it. Such an arrangement can be valuable if you have many resources and you want to separate them into categories (rather than clumping them all at the top level of the app bundle) or if the folder hierarchy among resources is meaningful to your app. Add to Targets Checking this checkbox causes the resource to be added to the target’s Copy Bundle Resources build phase. Thus you will almost certainly want to check it; why else would you be adding this resource to the project? But if this checkbox is unchecked and you realize later that a resource listed in the Project navigator needs to be added to the Copy Bundle Resources build phase, you can add it manually, as I described earlier. An alternative way to copy resources from your project into the app bundle while building is through a custom Copy Files build phase that you add to your target. To make one, edit the target, switch to Build Phases, and click Add Build Phase (at the lower 136 | Chapter 6: Anatomy of an Xcode Project right) and choose Add Copy Files. A Copy Files build phase appears; open its triangle, and you’ll find you can specify a custom path within the app bundle. For example, if you leave the Destination pop-up menu set to Resources and type “Pix” in the Subpath field, then any resources you add to this build phase will be copied into a folder called Pix in the app bundle. A custom Copy Files build phase of this sort can be a good way of keeping resources organized by folder inside your app bundle; I frequently use it for this purpose. Bear in mind, however, that it is entirely up to you to make sure that the desired resources are placed inside the appropriate Copy Files build phase (and that they are not placed in the normal Copy Bundle Resources build phase, because if they are, you’ll end up with two copies of the resource in your app bundle). If you copy resources into a subfolder of your app bundle, either with a folder reference or a custom Copy Files build phase, your code may have to specify that subfolder in order to fetch the resource from inside the app bundle. Code Code for two classes, AppDelegate and ViewController, was created for you when the project was created; the implementation files for these classes (AppDelegate.m and ViewController.m) appear in the target’s Compile Sources build phase. If you create any further class files, you’ll specify that they should be added to the target, and they too will then have their implementation files listed in the Compile Sources build phase. This (the contents of the Compile Sources build phase) is how your target knows what files to compile to create the app’s binary. The binary that results from compilation of these files is your project’s executable, and is placed into the app bundle, with its name being by default the same as the name of the target. The system is able to locate the executable inside the app bundle and launch the app because the app bundle’s Info.plist file has an “Executable file” key (CFBundleExecutable) whose value tells the system the name of the binary. Besides the class code files you create (or that Xcode creates for you), your project contains a main.m file. This too is in the Compile Sources build phase; it had better be, because this file contains the all-important main function, the entry point to your app’s code! Here are the main function’s contents: From Project to App | 137 int main(int argc, char *argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } The main function is very simple, but it’s crucial. It calls UIApplicationMain, which sets everything else in motion. UIApplicationMain is responsible for solving some tricky problems. As your app starts up, how will any of its code ever run? And how will its starting repertoire of instances ever be generated? UIApplicationMain takes care of these issues. First, your app is a C program, and a C program’s main function is always called, to start the program running; thus, UIApplicationMain will in fact be called. Then, UIApplicationMain does the following things: • It creates your very first instance — the shared application instance, subsequently accessible in code by calling [UIApplication sharedApplication]. The third ar‐ gument to UIApplicationMain specifies, as a string, what class the shared applica‐ tion instance should be an instance of. If nil, which will usually be the case, the default class is UIApplication; but you can subclass UIApplication and specify that subclass here by substituting something like this (depending on what the subclass is called) as the third argument: NSStringFromClass([MyUIApplicationSubclass class]) • Optionally, it also creates your second instance — the application instance’s dele‐ gate. Delegation is an important and pervasive Cocoa pattern, described in detail in Chapter 10, but for now let’s just say that it is crucial that every app you write have an app delegate instance. The fourth argument to UIApplicationMain speci‐ fies, as a string, what class the app delegate instance should be. If this class is speci‐ fied, as here, UIApplicationMain instantiates that class and ties that instance to the shared application instance as the latter’s delegate. If this class is not specified (the fourth argument is nil), it is up to you to provide a delegate instance in some other way; since you cannot do this sufficiently early in code, you would have to do it through the loading of the main nib file. (Before iOS 5 and Xcode 4.2, this was in fact the usual way in which the app delegate was instantiated; but Apple has sub‐ sequently changed the default pattern so that the app delegate is generated in code by the call to UIApplicationMain.) • If the Info.plist file specifies a main storyboard file or main nib file, UIApplicationMain loads it. (In the latter case, the nib file’s owner is the shared application in‐ stance.) • An app delegate instance has now been generated, either because UIApplicationMain instantiated it directly in response to the value of its fourth argument, or 138 | Chapter 6: Anatomy of an Xcode Project because UIApplicationMain loaded a main nib file which instantiated it. UIApplicationMain now turns to this app delegate instance and starts calling some of its code — in particular, it calls application:didFinishLaunchingWithOptions:, which is typically responsible, in turn, for displaying your app’s initial interface. (Starting in iOS 6, the sequence of calls to the app delegate’s code begins with application:willFinishLaunchingWithOptions: if it exists, as I’ll explain in Chapter 19). • The app is now launched and visible to the user. UIApplicationMain is still running (like Charlie on the M.T.A., UIApplicationMain never returns), and is now just sitting there, watching for the user to do something, maintaining the event loop, which will respond to user actions as they occur. The call to UIApplicationMain is wrapped in some memory management functionality (the @autoreleasepool curly braces) that I’ll explain in Chapter 12. Finally, notice the file Empty Window-Prefix.pch in the Project navigator. This is your project’s precompiled header file. It isn’t listed in the Compile Sources build phase be‐ cause it is actually compiled before that build phase; the target knows about it because it is pointed to by the Prefix Header build setting. The precompiled header is a device for making compilation go faster. It’s a header file; it is compiled once (or at least, very infrequently) and the results are cached (off in the DerivedData folder) and are implicitly imported by all your code files. So the precom‐ piled header should consist primarily of #import directives for headers that never change (such as the built-in Cocoa headers); it is also a reasonable place to put #defines that will never change and that are to be shared by all your code, as I mentioned in Chapter 4. The default precompiled header file imports <Foundation/Foundation.h> (the Core Foundation framework header) and <UIKit/UIKit.h> (the Cocoa framework). I’ll talk in the next section about what that means. Frameworks and SDKs A framework is a library of compiled code used by your code. Most of the frameworks you are likely to use will be Apple’s built-in frameworks; they are built-in in the sense that they are part of the system on the device where your app will run — they live in /System/Library/Frameworks on the device, though you can’t tell that on an iPhone or iPad because there’s no way (normally) to view the file hierarchy directly. However, your code needs to use these frameworks not only when running on a device but also when building on your computer. It also needs them when running in the Simulator. To make all this possible, part of the device’s system — in particular, the part containing its frameworks — is duplicated on your computer, in the Developer folder. From Project to App | 139 Renaming Things The name assigned to your project at creation time is used in many places throughout the project, leading beginners to worry that they can never rename a project without breaking something. But fear not! To rename a project, select the project listing at the top of the Project navigator, press Return to make its name editable, type the new name, and press Return again. Xcode presents a dialog proposing to change some other names to match, including the target, the built app, the precompiled header file, and the In‐ fo.plist — and, by implication, the build settings specifying these. You can check or uncheck any name, and click Rename; your project will continue to work correctly. You can freely change the target name independently of the project name. It is the target name, not the project name, that is used to derive the name of the product and thus the bundle name, bundle display name, and bundle identifier mentioned earlier in this chapter. Thus, when you settle on a real name for your app, it might be sufficient to change the target name. Changing the project name (or target name) does not automatically change the scheme name to match. There is no particular need to do so, but you can change a scheme name freely; choose Product → Manage Schemes and click on the scheme name to make it editable. Changing the project name (or target name) does not automatically change the main group name to match. There is no particular need to do so, but you can freely change the name of a group in the Project navigator, because these names are arbitrary; they have no effect on the build settings or the build process. However, the main group is special, because (as I’ve already said) it corresponds to a real folder on disk, the folder that sits beside your project file at the top level of the project folder. You can change the group’s name (changing the project name does not do this for you automatically), but you should not delete it, and beginners should not change the name of the folder on disk to which it corresponds, as that folder name is hard-coded into several build set‐ tings. You can change the name of the project folder in the Finder at any time, and you can move the project folder in the Finder at will, because all build setting references to file and folder items in the project folder are relative. This duplicated subset of the device’s system is called an SDK (for “software development kit”). To use a framework in your code, you must do two things: Import the framework’s header A framework has a header file, which provides (usually by importing other header files within the framework) the interface information about classes in that frame‐ 140 | Chapter 6: Anatomy of an Xcode Project work. Your code needs this information in order to compile successfully. You import the header with an appropriate #import directive. Link to the framework A framework is a package; you must instruct the build system to associate this package with your app’s executable binary, so that your binary’s calls to code within that framework can be routed into the framework’s compiled code. This is necessary in order for your app to run successfully. Such an association is called linking the binary with the framework, and this association must be formed when building. You instruct the build system to do this by including the framework in the target’s Link Binary With Libraries build phase. You might think that linkage is impossible because the framework that we ultimately want to use is off on a target device somewhere. But linkage is path-based, and the path is determined relative to the current SDK. When the app launches on the device, there is no SDK, and the path becomes absolute. So, for example, the linkage to the UIKit framework uses the path System/Library/ Frameworks/UIKit.framework. This path is relative to the current SDK. Thus: • When we build for a device, we link to the System/Library/Frameworks/ UIKit.framework inside the current SDK, which is /Developer/Platforms/ iPhoneOS.platform/Developer/SDKs/iPhoneOS6.1.sdk. • When we run on a device, there is no SDK, and the established linkage routes our code into the device’s top-level /System/Library/Frameworks/UIKit.framework. By default, three frameworks are linked into your target: Foundation Many basic Cocoa classes, such as NSString and NSArray and others whose names begin with “NS,” are part of the Foundation framework. The Foundation framework is imported in the precompiled header file (and, by default, in the headers of new classes that you create). In turn, it imports the Core Foundation headers and loads the Core Foundation framework as a subframework; thus, there is no need for you to import or link explicitly to the Core Foundation framework (which is full of functions and pointer types whose names begin with “CF,” such as CFStringRef). UIKit Cocoa classes that are specialized for iOS, whose names begin with “UI,” are part of the UIKit framework. The UIKit framework is imported in the precompiled header file (and by class code files that constitute the app templates, such as App‐ Delegate.h). From Project to App | 141 Core Graphics The Core Graphics framework defines many structs and functions connected with drawing, whose names begin with “CG.” It is imported by many UIKit headers, so you don’t need to import it explicitly. You might find that the three default frameworks are sufficient to your needs, or you might find that you need other frameworks to provide additional functionality. How will you know that a class or function you want to use resides outside the three default frameworks? You might get a clue from its name, which won’t begin with “NS,” “UI,” or “CG”, but more often, if you’re like me, you’ll be alerted by banging up against the compiler. For example, let’s say you’ve just found out about animation (Chapter 17) and you’re raring to try it in your app. So, in your code, you create a CABasicAnimation: CABasicAnimation* anim = [CABasicAnimation animation]; The next time you try to build your app, the compiler complains that CABasicAnimation is undeclared (and that it therefore can’t make sense of anim either). That’s when you realize you need to import a framework header. Near the start of the CABasicAnimation class documentation is a line announcing that it’s in QuartzCore.framework. You might guess (correctly) that the way to import the main Quartz Core framework header is to put this line near the start of your implementation file: #import <QuartzCore/QuartzCore.h> This works to quiet the compiler. Remember, though, that using a framework requires two things; we’ve done only one of them. So your code still doesn’t build. This time, you get a build error during the link phase of the build process complaining about _OBJC_CLASS_$_CABasicAnimation and saying, “Symbol(s) not found.” That mysterious-sounding error merely means that you’ve forgotten to link your target to the Quartz Core framework. To link your target to a framework, edit the target, click Summary at the top of the editor, and scroll down to the Linked Frameworks and Libraries section. (This is the same information that appears which you click Build Phases at the top of the editor and open the Link Binary with Libraries build phase.) Click the Plus button at the left just below the frameworks. A dialog appears listing the existing frameworks that are part of the active SDK. Select QuartzCore.framework and click Add. The Quartz Core framework is added to the target’s Link Binary With Libraries build phase. (It also appears in the Project navigator; you might like to drag it manually into the Frameworks group, for the sake of neatness.) Now you can build (and run) your app. You might wonder why the project isn’t linked by default to all the frameworks, so that you don’t have to go through this process every time you stray beyond the default three frameworks. It’s just a matter of time and resources. Importing headers increases the 142 | Chapter 6: Anatomy of an Xcode Project size of your code; linking to frameworks slows down your app’s launch time. You should link to only the frameworks needed for your code to run. Where you import a framework header depends on how you intend to use it. It’s simply a matter of scope. If a framework’s classes are to be mentioned only within a single implementation file, then you can import it at the start of that implementation file. If you want to subclass one of the framework’s classes (or adopt one of its protocols, Chapter 10), you’ll need to import it at the start of the interface file that declares the subclass; in that case, every implementation file that imports this interface file imports the framework header, and there’s no need to import the framework header separately in the implementation file. Of course, for maximum scope, you can simply import the framework header in the precompiled header file, making that framework available throughout your code. From Project to App | 143 CHAPTER 7 Nib Management A nib file, or simply nib, is a file containing a drawing of a piece of your interface. The term nib is not really an English word (it has nothing to do with fountain pens or bits of chocolate); it is based on the file extension .nib, which originated as an acronym for “NeXTStep Interface Builder”. Nowadays, you will usually develop your interface using a file format whose extension is .xib; when your app is built, your target’s .xib files are translated (“compiled”) into .nib format (Chapter 6). But a .xib file is still referred to as a nib file. I will speak of the same nib file as having either a .xib extension (if you’re editing it) or a .nib extension (if it’s in the built app). You construct your program in two ways — writing code, and drawing the interface. But these are really two ways of accomplishing the same ends; drawing the interface is a way of writing code. When the app runs and your drawing of the interface in a nib file is loaded, it is translated into instructions for instantiating and initializing the objects in the nib file. You could equally have instantiated and initialized those same objects in code. (This point is crucial; see “Nib-Based Instantiation” (page 90).) Indeed, deciding whether to create an interface object in code or through a nib file is not always easy; each approach has its advantages. The important thing is to understand how interface objects drawn in a nib file are instantiated and connected to your code when the app runs. That’s the subject of this chapter. (Most of this chapter applies equally to storyboards. Don’t skip this chapter on the grounds that you intend to use storyboards instead of nibs! Storyboards do not relieve you of the need to understand nib management. I’ll discuss the particular nature and use of storyboards in Chapter 19.) 145 Figure 7-1. Editing a nib file Up through Xcode 3.2.x, nib editing was performed in a separate application, Interface Builder. Starting in Xcode 4, the functionality of Interface Builder was rolled into Xcode itself. Nevertheless, the Xcode interface for nib editing is still referred to as Interface Builder. A Tour of the Nib-Editing Interface Let’s use an actual nib file to explore the Xcode nib-editing interface. In Chapter 6, we created a simple Xcode project, Empty Window; it contains a nib file, so we’ll use that. In Xcode, open the Empty Window project, locate the ViewController.xib listing in the Project navigator, and click it to edit it. Figure 7-1 shows the project window after selecting ViewController.xib and making some additional adjustments. The Navigator pane is hidden; the Utilities pane is show‐ ing. Within the Utilities pane, the Size inspector and the Object library are showing. The interface may be considered in four pieces: 1. At the left of the editor is the dock. In Figure 7-1, the dock is collapsed, showing the nib’s top-level objects graphically. The dock can be expanded by dragging its right edge or by clicking the right-pointing triangle-in-a-square-in-a-circle at its lower right; then it shows all of the nib’s objects hierarchically by name. 146 | Chapter 7: Nib Management 2. The remainder of the editor is devoted to the canvas, where you physically design your app’s interface. The canvas portrays views in your app’s interface and things that can contain views. (A view is an interface object, which draws itself into a rectangular area. The phrase “things that can contain views” is my way of including view controllers, which are represented in the canvas even though they are not drawn in your app’s interface.) 3. The inspectors in the Utilities pane are where you view and edit details of the cur‐ rently selected object. 4. The libraries in the Utilities pane, especially the Object library, are your source for interface objects to be added to the nib. The Dock The collapsed dock, as I’ve already said, shows the nib’s top-level objects. To see what this means, you need first to envision the nib as containing objects. Some of these objects — those that represent views — are arranged in a hierarchy of containment. Objects that are contained by no other object are top-level objects. A view can contain other views (its subviews) and can be contained by another view (its superview); for example, if we were to put a button into the view that occupies the canvas in Figure 7-1, the button would be a subview of that view, and that view would be the button’s superview. One view can contain many subviews, which might themselves contain subviews. But each view can have only one immediate superview. Thus there is a hierarchical tree of subviews contained by their superviews with a single object at the top. The highest superview of any such hierarchy in the nib is a top-level object and appears in the dock. That’s why the view object (labeled View in Figure 7-1) appears in this nib’s dock: it is a view contained by no other view. A top-level object, then, is either a view without a superview or else not a view at all. A nib file can actually portray two types of top-level object: Placeholders (proxy objects) A placeholder, or proxy object, isn’t actually in the nib. It represents an object that already exists in your app’s code at the time the nib is loaded. Proxy objects are portrayed as top-level objects in a nib file chiefly so that you can provide commu‐ nication between objects in your app’s code and objects instantiated from the nib (by means of connections, discussed later in this chapter). You can’t create or delete a proxy object; the dock is populated automatically with them. Proxy objects are shown above the dividing line in the dock. A Tour of the Nib-Editing Interface | 147 Figure 7-2. The dock, expanded Nib objects A nib object is an object that is instantiated by the nib — that is, the instance it represents will be created when your code runs and the nib loads. You can create new nib objects. Top-level nib objects are shown below the dividing line in the dock. The dock can be expanded (by clicking the right-pointing triangle-in-a-square-in-acircle at its lower right); it then portrays objects by name, and shows as an outline the full hierarchy of objects in this nib (Figure 7-2). At present, expanding the dock may seem silly, because there is no hierarchy; all objects in this nib are top-level objects. But when a nib contains many levels of hierarchically arranged objects (plus, starting in iOS 6, their autolayout constraints — see Chapter 14), you’re going to be very glad of the ability to survey them all in a nice outline, and to select the one you’re after, thanks to the expanded dock. You can also rearrange the hierarchy here; for example, if you’ve made an object a subview of the wrong view, you can reposition it within this outline by dragging its name. You can also select objects using the jump bar at the top of the editor. For example, if you click on the canvas background so that no object is selected, and the rightmost jump bar path component reads No Selection, then the entire hierarchy of objects in your nib is shown as a set of hierarchical menus off that path component (Control-6). Again, this may seem like small potatoes now, when your nib contains just three top-level objects and nothing more, but it will be valuable when you’ve many nib objects in a hierarchy. The name by which a nib object is designated is its label. This name is meaningful to the nib file, not to your code. When the dock is expanded, each object is portrayed by its label, as shown in Figure 7-2. When the dock is collapsed, you can see a top-level object’s label by hovering the mouse over it, as shown in Figure 7-1. If you find an object’s label unhelpful, you can change it: select the object and edit the Label field in the Docu‐ ment section of the Identity inspector (Command-Option-3). Alternatively, select the object’s label in the expanded dock and press Return to make it editable. Canvas The canvas provides a graphical representation of a top-level nib object along with its subviews, similar to what you’re probably accustomed to in any drawing program. If a 148 | Chapter 7: Nib Management Figure 7-3. Dragging a button into a view top-level nib object has a graphical representation (not every top-level nib object has one), you can click on it in the dock to display that representation in the canvas. To remove the canvas representation of a top-level nib object, click the X at its upper left; this merely clears the representation from the canvas — it does not remove the toplevel nib object from the dock (or from the nib), and of course you can always bring back the graphical representation by clicking that nib object in the dock again. On the other hand, the canvas is scrollable and automatically accommodates however many graphical representations it contains, so, rather than removing and restoring graphical representations, you can keep many graphical representations open in the canvas and scroll to see each one. Our simple Empty Window project’s ViewController.xib contains just one top-level nib object that has a graphical representation — the UIView destined to be the root view of the app’s window, called View. The term “root” here implies that the view occupies the entire window. Because this view will be the root view of our app’s window, any changes you make here will be reflected in the app’s user interface when you run it. To see this, we’re going to add a subview to it: 1. Ensure that the View in the dock is being displayed in the canvas. 2. Look at the Object library (Control-Option-Command-3). Click the second button in the segmented control to put the Object library into list view, if it isn’t in list view already. Locate the Round Rect Button (you can type “button” into the filter bar at the bottom of the library as a shortcut). 3. Drag the Round Rect Button from the Object library into the View in the canvas (Figure 7-3). Don’t accidentally drop the button onto the canvas background, out‐ side of the View! This would cause the button to become a top-level object, which is not what you want. If that happens, select the button in the dock and press Delete, and try again. A Tour of the Nib-Editing Interface | 149 A button now appears in the view in the canvas. The move we’ve just performed — dragging from the Object library into the canvas — is extremely characteristic; you’ll do it often as you design your interface. Alternatively, select an object in the Object library and press Return to copy the object into your interface (you might first want to make sure the correct superview is selected in the canvas). Filtering by name with the filter bar also selects, and switching to the Object library with Control-OptionCommand-3 also puts focus in the filter bar, so a rapid keyboard-only way to add a button to your interface is to type Control-Option-Command-3, “button”, possibly Up or Down arrow to select Round Rect Button, Return. Take a moment to play around with the button in the view in the canvas. Much as in a drawing program, the nib editor provides features to aid you in designing your interface. Here are some things to try: • Select it: resizing handles appear. • Resize it to make it wider: dimension information appears. • Drag it near the edge of the view: a guideline appears, showing a standard margin space between the edge of the button and the edge of the view. Similarly, drag it near the center of the view: a guideline shows you when the button is centered. • With the button selected, hold down the Option key and hover the mouse outside the button: arrows and numbers appear showing the distance between the button and the edges of the view. (If you accidentally clicked and dragged while you were holding Option, you’ll now have two buttons. That’s because Option-dragging an object duplicates it. Select the unwanted button and press Delete to remove it.) • Shift-Control-click on the button: a menu appears, letting you select the button or whatever’s behind it (in this case, the view). (In Xcode 4.5 and later, you’ll also see what look like guidelines or dimension bars when the button is selected and at rest. Those are autolayout constraints, to be discussed in Chapter 14.) Let’s prove that we really are designing our app’s interface. We’ll run the app to see that its interface has changed. 1. Make sure that the Breakpoints button in the project window toolbar is not selected, as we don’t want to pause at any breakpoints you may have created while reading the previous chapter. 2. Make sure the destination in the Scheme pop-up menu is the iPhone Simulator. 3. Choose Product → Run (or click the Run button in the toolbar). After a heart-stopping pause, the iOS Simulator opens, and presto, our empty window is empty no longer (Figure 7-4); it contains a round rect button! You can tap this button 150 | Chapter 7: Nib Management Figure 7-4. The Empty Window app’s window is empty no longer with the mouse, emulating what the user would do with a finger; the button highlights as you tap it. Inspectors and Libraries There are four inspectors that appear only when you’re editing a nib and apply to what‐ ever object is selected in the dock or canvas: Identity inspector (Command-Option-3) Far and away the most important section of this inspector is the first one, the Cus‐ tom Class. The selected object’s Class setting tells you the object’s class, and you can use it to change the object’s class. Some situations in which you’ll need to change the class of an object in the nib appear later in this chapter. Attributes inspector (Command-Option-4) Settings here correspond to properties and methods that you might use to configure the object in code. For example, changing the setting in the Background pop-up menu in the Attributes inspector for our view corresponds to setting the backgroundColor property for the view in code. Similarly, typing a value in the Title A Tour of the Nib-Editing Interface | 151 field in the Attributes inspector for our button is like calling the button’s setTitle:forState: method. The Attributes inspector has sections corresponding to the selected object’s class inheritance. For example, the UIButton Attributes inspector has three sections, because a UIButton is also a UIControl (“Control” in the inspector) and a UIView (“View” in the inspector). The correspondence between Attributes inspector settings and Objective-C methods is mostly a matter of guesswork. The Attributes inspector doesn’t always tell you, and there’s no way to see the code generated when the nib actually loads. Size inspector (Command-Option-5) The X, Y, Width, and Height fields determine the object’s frame (its position and size within its superview), corresponding to its frame property in code; you can equally do this in the canvas by dragging and resizing, but numeric precision can be desirable. What else you see in the Size inspector depends on whether this nib is using auto‐ layout or not. Autolayout, a new iOS 6 feature, may be toggled on or off for a nib at file level: select the nib file in the Project navigator, show the File inspector (Command-Option-1), and check or uncheck Use Autolayout. The default for new nibs in Xcode 4.5 and later, and thus for our Empty Window project, is that auto‐ layout is on. The possibilities for what you’ll see in the rest of the Size inspector are: Autolayout is off The Size inspector displays an Autosizing box that corresponds to the autoresizingMask property, determining how the object will be repositioned and resized when its superview is resized; a delightful animation demonstrates visually the implications of your settings. The Arrange pop-up menu contains useful commands for positioning the selected object. Autolayout is on The Size inspector displays autolayout-related settings: the object’s content hugging and content compression resistance priorities, plus any autolayout constraints involving this object. There is no Arrange pop-up menu, but ef‐ fectively the same menu pops up from the leftmost segment of the little car‐ touche at the lower right of the canvas. Connections inspector (Command-Option-6) I’ll discuss this later in this chapter. There are two libraries that are of particular importance when you’re editing a nib: 152 | Chapter 7: Nib Management Object library (Control-Option-Command-3) This library, as we’ve already seen, is your source for objects that you want to add to the nib. Media library (Control-Option-Command-4) This library lists media in your project, such as images that you might want to drag into a UIImageView or directly into your interface (in which case a UIImageView is created for you). Nib Loading and File’s Owner A nib file is useless until your app runs and the nib file is loaded. If a nib is designated by the Info.plist key “Main nib file base name” (NSMainNibFile, see Chapter 6), it is loaded automatically as the app launches; but this is an exceptional case, and has now fallen out of favor — there are no automatically loaded main nib files in the current project templates. In general, nibs are loaded explicitly as needed while the app runs. In our Empty Window application, you can actually see where this happens, in App‐ Delegate.m: self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil]; That line of code does several things, one of which is that (for reasons to be explained more fully in Chapter 19) it causes the nib named @"ViewController" (i.e., the nib file compiled from ViewController.xib, the nib file we’ve been editing) to be loaded, and the resulting views to be put into our app’s interface — which is how we were able to obtain the outcome shown in Figure 7-4. So a nib is not loaded until the app runs and our code decides, at some point in the life of the app, that that nib is needed. This architecture is a source of great efficiency. For example, imagine our app has two complete sets of interface, and the user might never ask to see the second one. It makes obvious sense not to load a nib containing the second set of interface until the user does ask to see it. By this strategy, a nib is loaded when its instances are needed, and those instances are destroyed when they are no longer needed. Thus memory usage is kept to a minimum, which is important because memory is at a premium in a mobile device. Also, loading a nib takes time, so loading fewer nibs at launch time makes launching faster. In order to use nibs (or storyboards, since a storyboard is like a collection of multiple nibs), it is crucial that you understand what happens when a nib loads. When a nib loads, some already existing instance is designated its owner. A nib cannot load without an owner, and the owner must exist before the nib can load. The nib owner can be an instance of any class; it will often, though not necessarily, be a UIView‐ Controller instance, because a UIViewController already knows how to load a nib and manage a view that it contains (Chapter 19). Nib Loading and File’s Owner | 153 The three most common ways of telling a nib to load are: initWithNibName:bundle: This is UIViewController’s designated initializer. It tells the UIViewController to which it is sent to prepare to load the named nib with itself as owner. (That’s what’s happening in the line of code from AppDelegate.m that I quoted just a moment ago.) The moment of actual loading is automatically postponed until the nib is needed. I’ll talk much more about this in Chapter 19. loadNibNamed:owner:options: An NSBundle instance method. Usually, you’ll direct it to [NSBundle mainBundle]. Observe that the owner is one of the parameters. I’ll show an example in the next section of this chapter. instantiateWithOwner:options: A UINib instance method. The nib in question was specified when UINib was instantiated. Again, the owner is one of the parameters. An example appears in Chapter 21. When a nib loads, its nib objects are instantiated, meaning its top-level nib objects and all deeper-level nib objects hierarchically dependent on them. (Proxy objects, by defi‐ nition, exist before the nib loads; nib loading does not instantiate them.) For example, in our nib, the view is instantiated when the nib loads, bringing with it the button inside it. (Again, see “Nib-Based Instantiation” (page 90); make very sure you understand this point!) This is what nibs are for — to instantiate objects when they load. To put it another way, that is what nib loading is — it is the instantiation of the nib objects described in the nib. At that point, having loaded, the nib’s work is done; the nib does not, for example, have to be “unloaded.” The same nib can be loaded multiple times, generating an entirely new set of instances each time. A frequent beginner question is, “I have a view in a nib; how do I make multiple copies of this view?” The simple solution is to load that nib multiple times. This is common practice. For example, consider table view cells. Every “row” of a table view is a table view cell. Let’s say there’s a certain look and behavior you want each “row” to have. You design the cell in a nib of its own as a UITableView‐ Cell. If the table has to display ten rows, you load that nib ten times (Chapter 21). Making and Loading a Nib Let’s create our own nib-loading code, illustrating at the same time the fact that any instance can be a nib’s owner. To do so, we’ll need a second nib file in our project. 154 | Chapter 7: Nib Management First, we’ll make the nib: 1. Choose File → New → File. The “Choose a template” dialog for files appears. 2. At the left of the dialog, under iOS (not Mac OS X!), choose User Interface, and select View in the main part of the dialog. Click Next. 3. For the Device Family pop-up menu, specify iPhone. Click Next. 4. In the Save dialog, name the file MyNib. Make sure you’re saving into the Empty Window project folder, that the group is Empty Window, and that the target is Empty Window (and checked); all those things should be true by default. Click Create. We’ve now created a nib file, MyNib.xib, containing a single top-level nib object, a UI‐ View. Look at MyNib.xib in the editor to see that this is true. We’ll also need an instance to act as the nib’s owner. By the time our code will run, we will already have at least one instance we could use (the AppDelegate instance), but to illustrate the procedure fully, we’ll create our own class whose sole purpose is to be instantiated so that this instance can act as the owner of the nib file as it loads: 1. In the Empty Window project in Xcode, choose File → New → File. The “Choose a template” dialog for files appears. 2. At the left of the dialog, under iOS (not Mac OS X!), select Cocoa Touch, and select Objective-C Class in the main part of the dialog. Click Next. 3. Name the file MyClass. The dialog also offers you a chance to specify what superclass the new class should be a subclass of. Make sure this is NSObject. Click Next. 4. In the Save dialog be sure that you’re saving into the Empty Window project folder, that the group is Empty Window, and that the target is Empty Window (and checked); all those things should be true by default. Click Create. We’ve now created files MyClass.h and MyClass.m declaring a class called MyClass. Next, we’ll write code that will load our new nib when the app runs. We need a place in our little app where our code is guaranteed to run: we’ll use the AppDelegate instance method application:didFinishLaunchingWithOptions: in the file AppDelegate.m. Just before or after the call to makeKeyAndVisible, insert this code to instantiate MyClass and load MyNib.nib with that instance as its owner: MyClass* mc = [MyClass new]; [[NSBundle mainBundle] loadNibNamed:@"MyNib" owner:mc options:nil]; Xcode will complain about this, because you can’t speak of MyClass without importing its declaration, so after the existing #import at the start of this file, add this line: #import "MyClass.h" Making and Loading a Nib | 155 Now build and run the project. Our new MyNib.nib file loads, and its UIView top-level nib object is instantiated. Unfortunately, you can’t see that this is true! That’s because we haven’t done anything to obtain the UIView instance that came into existence from the nib loading; in fact, what really happened is that the UIView instance popped into ex‐ istence and popped right back out again, like a virtual particle in quantum field theory. The next section corrects this, and shows how to obtain visible proof that our nib is loading and that its top-level nib objects are being instantiated. Outlet Connections You know how to load a nib file, thus instantiating its top-level nib objects. But those instances are useless to you if you don’t know how to get a reference to any of them in your code! Doing things with an object such as a label or a button or a text field or whatever (such as setting or getting the text it displays) is easy; but you have to be able to talk to the object in the first place, meaning that you need a reference to it, a variable that points to that instance (Chapter 3). Getting a reference to an instance that you created in code is trivial, because you assigned it to a variable at the time you created it (Chapter 5). But there’s no such assignment when you load a nib; you just load it and that’s the end of that: [[NSBundle mainBundle] loadNibNamed:@"MyNib" owner:mc options:nil]; // no assignment??!! dude, where are my nib-created instances? To refer in code to instances generated from nib objects when the nib loads, you need to have previously set up an outlet connection from a proxy object in the same nib. A connection is a named unidirectional linkage from one object in a nib file (the con‐ nection’s source) to another object in the same nib file (the connection’s target). An outlet is a connection whose name corresponds to an instance variable in the source object. When the nib loads, and the target object is instantiated, the nib-loading mech‐ anism assigns the value of the instance variable to be the target object. Thus the source object winds up with a reference to the target object as the value of one of its instance variables. Connections can link any two objects in a nib file, but a proxy object as the source of a connection is special because it represents an object that exists before the nib loads. Thus an outlet from a proxy object causes an object that exists before the nib loads to end up with a reference to an object that doesn’t exist until after the nib loads — an object that is in fact instantiated by the loading of the nib. In the most typical configuration, the proxy object will be the File’s Owner. The idea is that the instance that owns the nib has an instance variable, and the File’s Owner in the nib has a corresponding outlet to a nib object; the nib loads, and the owner instance ends up with an instance variable that refers to the instance generated from the nib object (Figure 7-5). 156 | Chapter 7: Nib Management Figure 7-5. How an outlet provides a reference to a nib-instantiated object The File’s Owner top-level object in a nib file is a proxy for the instance that will be the nib’s owner when the nib loads. To form a successful connection between this proxy object and a nib object, the nib needs to know the class of that instance. In the nib editor, you must set the File’s Owner’s class to match the nib owner’s class. Obviously this means that you must know in advance, while editing the nib, what the class of the nib owner will be when the nib loads. But you do know this, because you (i.e. your code) is what’s going to load the nib. To demonstrate the use of an outlet connection, we’ll implement exactly the schema illustrated in Figure 7-5, by making an outlet from the File’s Owner to a nib object in MyNib.xib. The nib owner is going to be a MyClass instance when the nib loads. As I’ve just said, we must tell the nib that this is the case. Let’s do that first: 1. In Xcode, click MyNib.xib to edit it. 2. In the dock, select the File’s Owner proxy object. Outlet Connections | 157 3. Show the Identity inspector (Command-Option-3). The Class, under Custom Class, is NSObject. Change this to MyClass. (If you type “My,” the word “MyClass” should just appear, as it’s the only class Xcode knows about whose name starts with “My.” Accept this by pressing Return.) Next, we need a nib object in MyNib.xib to make an outlet to. We already have one — the nib’s existing top-level UIView. But this lacks visual impact, so we’ll replace the UIView with a top-level UILabel, which will draw some text: 1. In Xcode, click MyNib.xib to edit it. 2. In the dock, select the View object and delete it. 3. Drag a Label object (UILabel) from the Object library into the canvas to become a new top-level object. Its graphical representation appears in the canvas. 4. Double-click the word “Label” in the label’s graphical representation in the canvas and type “Hello, world!” Hit Return to stop editing; the label resizes to match the size of its text. Now comes the really crucial part. We need two things, in two different places: The instance variable In its code, MyClass needs an instance variable. The outlet In the nib, the File’s Owner proxy, representing a MyClass instance, needs an outlet pointing at the label — an outlet with the same name as the instance variable. When the app runs and MyNib.nib is loaded with a MyClass instance as its owner, as we arranged in the code we’ve already written, those two pairs of things will be effectively equated: • The MyClass instance will be equated with the File’s Owner proxy in the nib, because it will be the nib’s owner as it loads. • MyClass’s instance variable will be equated with the File’s Owner outlet pointing at the label, because they have the same name. I’m simplifying. It isn’t really the identity of an instance variable’s name with that of the outlet that makes the match. It’s more complicated than that; the match is made using key–value coding. The rigorous details appear in Chapter 12. You thus need to work in two places at once: the nib, and MyClass’s code. Before Xcode 4, this required working separately in two different places, Xcode (where the code was 158 | Chapter 7: Nib Management Figure 7-6. Editing a nib, with code in the assistant pane edited) and Interface Builder (where the nib was edited). Nowadays, Xcode itself edits both the code and the nib, and furthermore you can see the code and the nib at the same time, all of which will make creating this pair of things, the instance variable and the outlet, much easier than it once was. I want you now to arrange to see two things at once: MyClass.m (the MyClass imple‐ mentation file, where we’ll declare the instance variable) and MyNib.xib (where we’ll create the outlet). You could use two project windows if you wanted, but for simplicity, let’s use an assistant: while editing MyNib.xib, switch to Assistant view (View → Assistant Editor → Show Assistant Editor) as in Figure 7-6. If, when you showed the assistant pane, it didn’t appear with MyClass’s header file showing, use the jump bar in the as‐ sistant pane to make the assistant pane show MyClass.m: for example, in the first path component choose Manual → Top Level Objects → MyClass.m. If the assistant pane is beside the nib editor pane rather than below it, choose View → Assistant Editor → All Editors Stacked Vertically. In MyClass.m in the assistant pane, at the start of the implementation section, create curly braces and declare a UILabel instance variable (and save): Outlet Connections | 159 Figure 7-7. Connecting an outlet from the Connections inspector @implementation MyClass { IBOutlet UILabel* theLabel; } @end The term IBOutlet is linguistically meaningless; it is #defined as an empty string, so it is deleted by the preprocessor before the compiler ever sees it. It’s purely a hint to Xcode to make it easy for you to create the outlet. Xcode responds by displaying an empty circle in the gutter to the left of the IBOutlet line; this indicates that although we’re speaking of an outlet in our code, no corresponding outlet connection yet exists in a nib. We’ll fix that in a moment. We have typed the instance variable as a UILabel*, because we happen to know that this is the type of object that this instance variable will be pointing to; we could also use id, or any superclass of UILabel. If we do not use one of these alternatives (id, UILabel, or a superclass of UILabel), we will not be able to form the connection to a UILabel in the nib. We have accomplished half our task: we’ve made the instance variable. Now we’re ready for the other half, namely, to make the outlet connection. There are several ways to do this, so I’ll just pick one for now and demonstrate the others later: 1. Select File’s Owner in the nib (which, you remember, represents a MyClass instance) and switch to the Connections inspector (Command-Option-6). Lo and behold, the name of our instance variable, theLabel, is listed here! This is the work of the IBOutlet hint we created earlier. 2. Click in the empty circle to the right of theLabel in the Connections inspector, drag to the Label object in the canvas (Figure 7-7), and release the mouse. (A kind of elastic line follows the mouse as you drag from the circle to show that you’re creating a connection.) With the File’s Owner object selected, look again at the Connections inspector; it shows that theLabel is connected to the Label nib object, and if you hover the mouse over the 160 | Chapter 7: Nib Management filled circle at the right, the label object in the nib is highlighted. And look at the IBOutlet line in MyClass.m; the circle in the gutter is now filled in, and if you click that filled circle, the label is specified in a pop-up menu next to the circle, and the label object in the nib is highlighted. Mission accomplished! We have made an outlet connection in the nib from the File’s Owner proxy (representing a MyClass instance) to the Label object, and this outlet connection has the same name as the instance variable theLabel in MyClass’s code. Therefore, when the nib loads and a MyClass instance is the nib’s owner, its theLabel instance variable will be set to the UILabel object that will be instantiated through the loading of the nib. To prove that this is indeed the case, we’ll use that instance variable in our code to do something dramatic. In particular, we’ll stick the UILabel into our window, thus making it visible. Its visibility will prove that the nib is loading and that the instance variable is being set by the outlet. Return to AppDelegate.m and modify the nib-loading code like this (you added the first two lines earlier): MyClass* mc = [MyClass new]; [[NSBundle mainBundle] loadNibNamed:@"MyNib" owner:mc options:nil]; UILabel* lab = [mc valueForKey: @"theLabel"]; [self.window.rootViewController.view addSubview: lab]; lab.center = CGPointMake(100,100); lab.frame = CGRectIntegral(lab.frame); (We haven’t written an accessor method in MyClass for theLabel, so to save time I used key–value coding.) Build and run the app. The words “Hello, world!” appear! This proves that our outlet worked. We loaded a nib and, using an outlet, we obtained a reference to a nib object and were able to manipulate that object, putting it into our interface. Making an instance variable and giving it an IBOutlet hint, but for‐ getting to connect the outlet to anything in the nib, is an unbelievably common beginner (and not-so-beginner) mistake. Had we made this mistake, our code would have run without error, but “Hello, world!” would not appear in the interface because lab would be nil. The unfilled circle that appears in the gutter next to an IBOutlet line for which no corresponding nib connection exists is your only clue that something’s amiss, so watch for it. More Ways to Create Outlets I said a moment ago that there were other ways to create the outlet. Let’s try some of them. Return to our assistant-paned nib editor, select the File’s Owner, switch to the Outlet Connections | 161 Figure 7-8. Connecting an outlet by Control-dragging from the source object Figure 7-9. Connecting an outlet by dragging from the Connections HUD Connections inspector, and delete the outlet by clicking the little X to its left. We’re going to make this outlet again, a different way: 1. Select the File’s Owner in the dock. 2. Hold down the Control key and drag from the File’s Owner to the label. An elastic line follows the mouse. Release the mouse. 3. A little window (called a HUD, for “heads-up display”) appears, titled Outlets, list‐ ing theLabel as a possibility (Figure 7-8). Click theLabel. Once again, look at the Connections inspector with the File’s Owner selected to confirm that this worked. You can even build and run the project again, to prove it to yourself if you’re in any doubt. Now delete the outlet again; we’re going to make this outlet in yet a different way: 1. Select the File’s Owner in the dock. 2. Control-click the File’s Owner in the dock. A HUD appears, looking a lot like the Connections inspector. 3. Drag from the circle to the right of theLabel to the label (Figure 7-9). Release the mouse. Now delete the outlet again; we’re going to make this outlet in another way. This time, we’re going to operate from the point of view of the label. The Connections inspector shows all connections emanating from the selected object; it also shows all connections linking to the selected object. So, select the label and look at the Connections inspector. 162 | Chapter 7: Nib Management It lists “New Referencing Outlet.” This means an outlet from something else to the thing we’re inspecting, the label. So: 1. From the circle at the right of “New Referencing Outlet,” drag to the File’s Owner. An elastic line follows the mouse. Release the mouse. 2. A HUD saying theLabel appears. Click it. Confirm that, once again, we’ve made an outlet from the File’s Owner to the label. (And we could also have done the same thing by Control-clicking the label to start with, to show its Connections HUD.) Now delete the outlet again; we’re going to make this outlet in another way. This time, we’re going to start with the label, but (hold onto your hat) we’re going to connect directly to the code which is sitting in the assistant pane: 1. Select the label. 2. Make sure that MyClass.m is showing in the assistant pane and that you can see the IBOutlet line declaring the instance variable theLabel. 3. Hold down the Control key and drag from the label in the nib across the barrier between panes to that line of code. An elastic line follows the mouse. When you’ve got the mouse positioned correctly, the words Connect Outlet will appear. Release the mouse. Yet again, confirm that we’ve successfully made the desired outlet. And you could also have done the same thing in reverse; starting with the circle at the left of the IBOutlet line in the code, you can drag (without holding Control) to the label in the nib. Now delete the outlet one last time, and (get this) delete the line of code declaring the instance variable (but leave the curly braces). We’re going to create the outlet and the instance variable declaration, all in a single amazing move: 1. Select the label. 2. Make sure MyClass.m is showing in the assistant pane. 3. Hold down the Control key and drag from the label in the nib to the area within the curly braces in the code. An elastic line follows the mouse. The words Insert Outlet or Outlet Collection appear. Release the mouse. 4. A little HUD appears, asking for the name of the instance variable that’s about to be created. Call it theLabel (and make sure the type is UILabel), and press Return. The IBOutlet line declaring the instance variable is created, and the outlet is formed to match it. Outlet Connections | 163 Connecting to Code is an Illusion Making an outlet by connecting directly between code and an interface object in the nib is extremely cool and convenient, but coolness and convenience do not relieve you of the necessity of understanding what an outlet is and how it works. No matter what physical gesture you make in Xcode, and no matter how much Xcode may give you the illusion that you are somehow connecting an object in the nib to the code, that’s not really the case. There is no connection between the instance variable in the code and the object in the nib; there is no identity between the instance variable in the code and the outlet connection in the nib. There are always, if an outlet is to work properly, two distinct and separate things — an instance variable in a class, and an outlet in the nib, with the same name and coming from an instance of that class. It is the identity of the names that allows the two to be matched at runtime when the nib loads, so that the instance variable is properly set at that moment. Xcode tries to help you by enforcing this identity of names and by indicating that the connection should work when the code runs, but it is not in fact magically connecting the code to the nib. More About Outlets All our examples so far have involved a proxy object, but an outlet connection can connect any two objects in the nib. The only requirement is that the source object be of a class that has an instance variable whose type matches the class of the target object. This class might be your own custom class with an ivar that you gave it, as in our earlier examples, or it might be a built-in Cocoa class with a built-in instance variable that can be used as an outlet. Nothing in the documentation for a built-in Cocoa class tells you which of its instance variables are available as outlets. In general, the only way to learn what outlets a built-in class provides is to examine a representative of that class in a nib. It is also possible to create an outlet collection. This is an NSArray instance variable matched by multiple connections to objects of the same type. For example, suppose a class contains this instance variable declaration: IBOutletCollection(UILabel) NSArray* labels; Then it is possible to form multiple labels outlets from an instance of that class in a nib, each one to a different UILabel in that nib. When the nib loads, those UILabel instances become the elements of the NSArray labels. The order in which the outlets are formed is the order of the elements in the array. This turns out to be particularly useful when forming outlets to autolayout constraints; examples will appear in Chap‐ ter 20 and Chapter 23. 164 | Chapter 7: Nib Management Connections Between Nibs You cannot draw a connection from an object in one nib to an object in another nib. If you expect to be able to do this, you haven’t understood what a nib is (or what a con‐ nection is). A connection applies to specific instances. An object in a nib, however, is only a potential object, becoming a real object when the nib is loaded and the object is instantiated. This potentiality can be realized never, once, or many times. Two objects in the same nib will be instantiated together on any particular occasion when the nib loads, so it’s clear what instances a connection between them is intended to connect. But a connection from an object in one nib to an object in another nib would be meaningless, because there’s no way to say what actual future instances the connection is supposed to connect. The problem of communicating between an instance instantiated from one nib and an instance instantiated from another nib is just a special case of the more general problem of how to communicate between instances in a program and is dis‐ cussed in Chapter 13. Action Connections Having explored outlet connections, we should also discuss the other kind of connec‐ tion, action connections. An action is a message emitted automatically by a Cocoa UIControl interface object (a control) when the user does something to it, such as tapping the control. The various user behaviors that will cause a control to emit an action message are called events. To see a list of possible events, look at the UIControl class documentation, under “Control Events.” For example, in the case of a UIButton, the user tapping the button corresponds to the UIControlEventTouchUpInside event. In the case of a UITextField, the user typ‐ ing or deleting or cutting or pasting corresponds to the UIControlEventEditingChanged event. A complete list of UIControls and what events they report is provided in Chapter 11, and each type of control is thoroughly dealt with in later chapters, espe‐ cially Chapter 25. An action message, then, is a way for your code to respond when the user does something to a control in the interface, such as tapping a button. But your code will not receive an action message from a control unless you explicitly make prior arrangements with that control. You must tell the control what event should trigger an action message, what instance to send the action message to, and what the action message’s name should be. There are two ways to make this arrangement: in code, or in a nib. Either way, we’re going to need a method for the action message to call. There are three standard signatures for a method that is to be called through an action message; the most commonly used one takes a single parameter, which will be a reference to the object that emitted the action message. (For full details, see Chapter 11.) So, for example, Action Connections | 165 you could have a method like this (let’s agree to put it in the implementation section for ViewController, in ViewController.m): - (void) buttonPressed: (id) sender { UIAlertView* av = [[UIAlertView alloc] initWithTitle:@"Howdy!" message:@"You tapped me." delegate:nil cancelButtonTitle:@"Cool" otherButtonTitles:nil]; [av show]; } Now, as I mentioned a moment ago, it is possible to arrange in code for buttonPressed: to be called when the user taps a button. In particular, if b is a reference to the button, then some ViewController code could say: [b addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside]; That code means: “Hey there, button! When the user taps on you (UIControlEventTouchUpInside), send me (self) a buttonPressed: message.” (See Chapter 3 if you’ve forgotten about the @selector directive.) Of course, such an instruction assumes that this object (self) really does implement a buttonPressed: method. (If it doesn’t, then when the user taps the button, the app will crash.) However, instead of doing that, we’re going to use the existing button in View‐ Controller.xib and arrange in the nib for its action message to be buttonPressed: and to be sent to a ViewController instance. We’re going to form an action connection in the nib. We can do this because, as I’ve already mentioned, a ViewController instance is the owner of ViewController.nib when it loads. The template has already set the File’s Owner proxy in ViewController.xib to be of the ViewController class (look at it and see!). So we can create an action connection in the nib from the button to the File’s Owner, as a way of communicating between the button and the ViewController instance that loads the nib when the app runs. As with outlets, there are several ways to do this; I’ll just show you the main ones and leave you to discover the rest. (They are all directly comparable to the many ways of creating an outlet connection.) 1. We need a hint, in our code, that a method with the expected signature exists. This hint involves substituting IBAction for the method’s void return type. (The sub‐ stitution is legal because IBAction is #defined as void; Xcode can see the hint in your code, but the preprocessor will turn IBAction back to void before the compiler ever sees it.) So, in ViewController.m, change the first line of our buttonPressed: method implementation to look like this (and save the file): - (IBAction) buttonPressed: (id) sender { 166 | Chapter 7: Nib Management Figure 7-10. Connecting an action from the Connections inspector This causes an empty circle to appear in the gutter next to the IBAction line. 2. Now edit ViewController.xib, select the button in the window, and look at the Con‐ nections inspector. The event for which we’d like to send the action message is Touch Up Inside. Drag from its circle to the File’s Owner nib object in the dock, which is to receive the message (Figure 7-10). Release the mouse. 3. A little window listing possible ViewController action methods appears; in this case, it lists only buttonPressed:. Click on buttonPressed: to form the connection. To see that the action connection has been formed, look at the Connections inspector. If you select the button, the Connections inspector reports that the button’s Touch Up Inside event is connected to the File’s Owner’s buttonPressed: method. If you select the File’s Owner object, the Connections inspector reports a Received Action where buttonPressed: is called by the Rounded Rect Button’s Touch Up Inside event. Finally, look at the code in ViewController.m; the circle next to the IBAction line is filled, and you can click it to reveal that the connection is from the button. Finally, to make assurance doubly sure, you can also build and run the project to confirm that the action connection is working. In the running app, the button inside the window now actually does something when the user taps it! It summons an alert. As with outlets, we could have formed the action connection by Control-dragging from the button directly to the File’s Owner, instead of involving the Connections inspector. If you just Control-drag, Interface Builder assumes a default event for you (in this case, it would assume Touch Up Inside). If that isn’t what you want, start by Control-clicking on the button to summon a HUD version of the Connections inspector, and drag from the desired event’s circle just as you would do from the real Connections inspector. As with outlets, you can also form the action connection directly from nib to code. (But please reread “Connecting to Code is an Illusion” (page 164); that warning applies Action Connections | 167 Figure 7-11. Connecting an action to a method implementation equally to action connections.) In Figure 7-11, we’ve Control-clicked the button in the nib to summon its Connections HUD, and dragged from the Touch Up Inside circle to the buttonPressed: implementation in code. And we could equally have gone the other way, dragging from the unfilled circle next to the IBAction line in the code to the button in the nib. But wait, there’s more! Instead of writing the action method ahead of time, you can ask Xcode to stub it out for you. To do so, Control-drag from the nib to an empty spot in ViewController’s implementation section; the words Insert Action appear, and when you release the mouse, a dialog appears, letting you specify the name of the action method, the number of arguments it should take, and the control event to be used as a trigger. Xcode inserts the method implementation, but doesn’t put any code between the curly braces; it’s smart, but not smart enough to guess what you want the method to do! Additional Initialization of Nib-Based Instances By the time a nib finishes loading, its instances are fully fledged; they have been initial‐ ized and configured with all the attributes dictated through the Attributes and Size inspectors, and their outlets have been used to set the values of the corresponding in‐ stance variables. Nevertheless, you might want to append your own code to the initial‐ 168 | Chapter 7: Nib Management ization process as an object is instantiated from a loading nib. Most commonly, to do this, you’ll implement awakeFromNib (possibly subclassing a Cocoa class in order to do so). The awakeFromNib message is sent to all nib-instantiated objects just after they are instantiated by the loading of the nib: at the point where this happens, the object has been initialized and configured and its connections are operational. For example, our Empty Window app is loading MyNib.xib, extracting a UILabel from it, and inserting that label into our interface; the result is that the words “Hello, world!” appear in our window. Let’s modify the behavior of this UILabel so that it does some additional self-initialization in code. To do that, we will need a class of our own to which our UILabel will belong. Clearly, this needs to be a UILabel subclass. So: 1. In Xcode, choose File → New → File and specify that you want a Cocoa Touch Objective-C class. Click Next. 2. Call the new class MyLabel. Make it a subclass of UILabel. Click Next. 3. Make sure you’re saving into the project folder, with the Empty Window group and the Empty Window target (this should be right by default). Click Create. 4. In MyLabel.m, somewhere in the implementation section, implement awakeFromNib: - (void) awakeFromNib { [super awakeFromNib]; self.text = @"I initialized myself!"; [self sizeToFit]; } 5. That code won’t apply to the label in MyNib.xib unless that label is a MyLabel, so edit MyNib.xib and change the label’s class to MyLabel in the Identity inspector. Now build and run the project. Instead of “Hello, world!” we now see “I initialized myself!” in the window. Mac OS X Programmer Alert If you’re an experienced Mac OS X programmer, you may be accus‐ tomed to rarely or never calling super from awakeFromNib; doing so used to raise an exception, in fact. In iOS, you must always call super in awakeFromNib. Another major difference is that in Mac OS X, a nib owner’s awakeFromNib is called when the nib loads, so it’s possible for an object to be sent awakeFromNib multiple times; in iOS, awakeFromNib is sent to an object only when that object is itself instantiated from a nib, so it can be sent to an object a maximum of once. Additional Initialization of Nib-Based Instances | 169 Sometimes, you might need to interfere with a nib object’s initialization at an even earlier stage. If this object is a UIView or UIViewController (or a subclass of either), you can implement initWithCoder:. In your implementation, be sure to call super and return self as you would do in any initializer. Your purpose here would typically be to initialize additional instance variables that your subclass has declared, as with any initializer. Here, for example, is an implementation of MyLabel that declares an instance variable that is an int called _num and manipulates it first in initWithCoder: and then in awakeFromNib, thus proving that the two are called in that order: @implementation MyLabel { int _num; } - (id) initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { self->_num = 42; } return self; } - (void) awakeFromNib { [super awakeFromNib]; self.text = [NSString stringWithFormat: @"The answer is %i", self->_num]; [self sizeToFit]; } @end That’s trivial and unnecessary, but it illustrates the principle. 170 | Chapter 7: Nib Management CHAPTER 8 Documentation Knowledge is of two kinds. We know a subject ourselves, or we know where we can find information upon it. —Samuel Johnson, Boswell’s Life of Johnson You don’t remember Cocoa; you look it up! —Anonymous programmer, cited by Beam and Davidson, Cocoa in a Nutshell No aspect of Cocoa programming is more important than a fluid and nimble relation‐ ship with the documentation. There is a huge number of built-in classes, with many methods and properties and other details. Apple’s documentation, whatever its flaws, is the definitive official word on how you can expect Cocoa to behave and on the con‐ tractual rules incumbent upon you in working with this massive framework whose inner workings you cannot see directly. The Xcode documentation installed on your machine comes in large chunks called documentation sets (or doc sets, also called libraries). You do not merely install a docu‐ mentation set; you subscribe to it, so that when Apple releases a documentation update (because a new version of iOS has been released, or because there has been an incre‐ mental revision of the documentation), you can obtain the updated version. When you first install Xcode, the bulk of the documentation is not installed on your machine; viewing the documentation in the documentation window (discussed in the next section) requires an Internet connection, so that you can see the online docs at Apple’s site. Therefore, you should start up Xcode immediately after installation to let it download and install your initial documentation sets. The process can be monitored, to some extent, in the Downloads pane of the Preferences window (under Documen‐ tation); you can also specify here whether you want updates installed automatically or whether you want to click Check and Install Now manually from time to time. This is 171 also where you specify which doc sets you want; I believe that the iOS 6.1 Documentation Set and the Xcode 4.6 Developer Library are all you need for iOS development. You may have to provide your machine’s admin password when a doc set is first installed. The Documentation Window Your primary access to the documentation is in Xcode, through the Documentation tab of the Organizer window (Window → Organizer and then click Documentation, or Help → Documentation and API Reference). I’ll refer to this as the documentation window, even though it’s really an aspect of the Organizer window. The documentation window behaves basically as a glorified web browser, because the documentation consists essentially of web pages. Indeed, most of the same pages can be accessed at Apple’s developer site, http://developer.apple.com. And any page open in the documentation window can be opened instead in your web browser: Control-click for the contextual menu and choose Open Page in Browser. Notice too the contextual menu for links within a documentation window, such as Copy Link and Open Link in Browser. When you’re trying to figure something out, the ability to spawn off a page as a secondary window in a browser while you go on searching in the Xcode documenta‐ tion window can be very useful. Each doc set has a home page, which you access from the Browse navigator (Editor → Explore Documentation) or from the first component of the jump bar. A typical home page presents a full list of documents, which can be sorted by column and filtered by keyword. Some home pages, such as the iOS 6.1 Documentation Set home page, also have a broad categorical list down the left side, which can similarly be used to filter the document list. In practice I rarely use these home pages, though they can come in handy when you’re looking for broad topic introductions (click Guides on the left). The Browse navigator (and the jump bar) can also be used to explore a doc set by category. When you encounter a documentation page to which you’re likely to want to return, make it a bookmark (Editor → Add Bookmark). Bookmarks are accessed through the Bookmarks navigator (Editor → Documentation Bookmarks). Documentation book‐ mark management is simple but effective: you can rearrange bookmarks or delete a bookmark, and that’s all. My chief way into the documentation — and, I suspect, most users’ chief way — is by searching (Editor → Search Documentation). Type a term into the search field (Help → Documentation and API Reference, Shift-Option-Command-?). Click the magnifying glass to choose Show Find Options if they aren’t showing. It’s important to set these options correctly: Hits must This pop-up menu determines how your search terms are understood. Your choices are “contain search term”, “start with search term”, and “match search term”. It’s good 172 | Chapter 8: Documentation to be nimble about changing this setting as needed. For example, if you are typing the start of the name of a class you want to search for, do a “start with” search, not a “contain” search. Languages Check only those languages you’re likely to be interested in (probably Objective-C and C). Doc Sets Check only those doc sets that interest you; if you’re doing iOS development, for example, uncheck any Mac OS X libraries to eliminate inapplicable and duplicate results. Enter a search term in the search field, and pause. Search results are displayed in cate‐ gories, in relevance order, in the navigation pane; click a result to view that page. One would like to perform this move — from seeing a list of results in the navigation pane to viewing the page for one of those results — without using the mouse, but I haven’t discovered a reliable way to do that. It’s important also to be able to switch nimbly from editing code to consulting the doc‐ umentation on a term used in that code. Here are two ways: • Select a term in the editor (or anywhere else that you can select text) and choose Help → Search Documentation for Selected Text (Control-Option-Command-/). This command switches to the documentation window and enters the selected term into the search field, performing the search using the current find options, in a single move. • Hold Option and hover the mouse over a likely term in code, until the cursor be‐ comes a question mark (and the term turns blue with a dashed underline); then rapidly Option-double-click the term. This, in my opinion, is much the best way, because it bypasses the search field altogether and actually performs the search for the correct term in the correct class in the main documentation display. You can perform the same move during code completion (Chapter 9): select one of the terms offered as a completion, and click the More link at the bottom of the popup menu. Don’t confuse searching the documentation with finding within the current page. To find within the current documentation page, make sure the focus is within the page itself (probably by clicking in the page), and then use the Edit → Find menu commands. Command-F summons a find bar, as in Safari. A major difference between the display of a documentation page in Xcode and the display of the same page as a web page at http://developer.apple.com is that the latter often shows a Table of Contents column at the left side. In Xcode, this Table of Contents column is suppressed, which saves space, but makes it harder to get a sense for where The Documentation Window | 173 you are in a document or a set of related documents. The intention is presumably that you should use the jump bar both to get your bearings and to navigate, though personally I find this approach clumsy and frustrating. Class Documentation Pages In the vast majority of cases, your target documentation page will be the documentation for a class. I have frequently spoken already of the importance of class documentation pages. A common move on your part will be to search on a class name in the docu‐ mentation window. If you search on, say, NSString, the search result whose title is NSString Class Reference is the class documentation for NSString. Let’s pause to notice the key features of a class documentation page. I’ll use UIButton as an example (Figure 8-1): Inherits from Lists, and links to, the chain of superclasses. One of the biggest beginner mistakes is failing to read the documentation up the superclass chain. A class inherits from its superclasses, so the functionality or information you’re looking for may be in a superclass. You won’t find out about addTarget:action:forControlEvents: from the UIButton class page; that information is in the UIControl class page. You won’t find out that a UIButton has a frame property from the UIButton class page; that information is in the UIView class page. Conforms to Lists, and links to, the protocols implemented by this class. Protocols are discussed in Chapter 10. Methods injected into a class by a category (Chapter 10) are often not listed on that class’s documentation page and can be very difficult to discover. For example, awakeFromNib isn’t mentioned in the document for UIButton or for any of its superclasses or protocols. This is a major weakness in Apple’s organization and display of the documentation. A third-party documentation display application such as AppKiDo can be helpful here (http://appkido.com). Framework Tells what framework this class is part of. Your code must link to this framework in order to use this class (see Chapter 6). Availability States the earliest version of the operating system where this class is implement‐ ed. For example, EKEventViewController, along with the whole EventKit frame‐ work (consisting of classes for querying the user’s calendar; see Chapter 32) wasn’t 174 | Chapter 8: Documentation Figure 8-1. The start of a typical class documentation page invented until iOS 4.0. So if you want to use this feature in your app, you must make sure either that your app targets only iOS 4.0 or later or that you take precautions not to call into this framework on earlier versions of the operating system. The availability information also confirms that you’re looking at the right documenta‐ tion page; if you’re doing iOS programming and this class is available only on Mac OS X, reading this page is pointless. Note that individual methods also have avail‐ ability information. Companion guide If a class documentation page lists a companion guide, you might want to click that link and read that guide. Guides are broad surveys of a topic; they provide important information (including, often, useful code examples), and they can serve to orient Class Documentation Pages | 175 your thinking and make you aware of your options. (See the UIView class page for an example.) Declared in The header(s) where this class is declared. Unfortunately this is not a link; I have not found any quick way to view a header starting from within the documentation. That’s a pity, as it can often be worth looking at the header file, which may contain helpful comments or other details. You can open the header file from your project window, as explained later in this chapter. Related sample code If a class documentation page links to sample code, you might want to examine that code. (But see my remarks on sample code in the next section of this chapter.) Overview Some class pages provide extremely important introductory information in the Overview section, including links to related guides and further information. (See the UIView class page for an example.) Tasks This section lists in categorical order, and links to, the properties and methods that appear later on the page. (Recall from Chapter 5 that a property is a syntactic short‐ cut for calling an accessor method; the documentation lists the property rather than the accessor.) Often, just looking over this list can give you the hint you’re looking for. Properties, Class Methods, Instance Methods These sections provide the full documentation for this class’s methods. In recent years, this part of the documentation has become quite splendid, with good hyper‐ links. Note the following subsections: The property or method name This name is suitable for copying and pasting into your code (if, for example, you need to enter the name of a selector). The property or method’s purpose A short summary of what it does. The formal declaration for the property or method Read this to learn things like the method’s parameters and return type. (Chap‐ ter 12 explains how to read a property declaration.) Suitable for copying and pasting into your code in order to enter a call to this method, though you are more likely to use Xcode’s code completion feature where possible (see Chap‐ ter 9). Parameters and return value Precise information on the meaning and purpose of these. 176 | Chapter 8: Documentation Discussion Often contains extremely important further details about how this method behaves. Always pay attention to this section! Availability An old class can acquire new methods as the operating system advances; if a newer method is crucial to your app, you might want to exclude your app from running on older operating systems that don’t implement the method. See also Lists and links to related methods. Very helpful for giving you a larger per‐ spective on how this method fits into the overall behavior of this class. Related sample code It can sometimes be worth consulting the sample code to see an example of how this particular method is used. Declared in The relevant header file. Constants Many classes define constants that accompany particular methods. For example, to create a UIButton instance in code, you call the buttonWithType: class method; the argument value will be a constant, listed under UIButtonType in the Constants section. (To help you get there, there’s a link from the buttonWithType: method to the UIButtonType section in Constants.) There’s a formal definition of the constant; you won’t usually care about this (but do see Chapter 1 if you don’t know how to read it). Then each value is explained, and the value name is suitable for copying and pasting into your code. Sample Code Apple provides plenty of sample code projects. You can view the code directly in the documentation window; sometimes this will be sufficient, but you can see only one class implementation or header file at a time, so it’s difficult to get an overview. The alternative is to open the sample code project in Xcode. When you look at a sample code page from your browser, there’s a button that reads Download Sample Code. In fact, the sample code may already be on your computer. When you look at the same sample code page in the documentation window, the same button will read Open Project. The sample code on your hard disk is zipped, so even if the code is already on your computer, it is first unzipped (into your Downloads folder). This policy of keeping the sample code projects zipped on your hard disk is a good one, as it prevents you from accidentally altering the original, and you are free to experiment with the unzipped copy. Sample Code | 177 If a sample code project was linked against the frameworks of an older SDK that isn’t installed on your computer, the project will be described in the Project navigator with the words “missing base SDK.” In earlier versions of Xcode, this situation could prevent you from building and running the project, and features that depend on indexing might not work. In Xcode 4.2 and later, however, the project should build and run regardless. To remove the “missing base SDK” annotation, edit the tar‐ get, switch to Build Settings, and change the outdated Base SDK setting to Latest iOS. As a form of documentation, sample code is both good and bad. It can be a superb source of working code that you can often copy and paste and use with very little alteration in your own projects. It is usually heavily commented, because the Apple folks are aware, as they write the code, that it is intended for instructional purposes. Sample code also illustrates concepts that users have difficulty extracting from the documentation. (Users who have not grasped UITouch handling, for instance, often find that the lightbulb goes on when they discover the MoveMe example.) But the logic of a project is often spread over multiple files, and nothing is more difficult to understand than someone else’s code (except, perhaps, your own code). Moreover, what learners most need is not the fait accompli of a fully written project but the reasoning process that constructed the project, which no amount of commentary can provide. My own assessment is that Apple’s sample code is generally very thoughtful and in‐ structive and definitely a major component of the documentation, and that it deserves more appreciation and usage than it seems to get. But it is most useful, I think, after you’ve reached a certain level of competence and comfort. Other Resources Here is a survey of other useful resources that supplement the documentation. Quick Help Quick Help is a condensed rendering of the documentation on some single topic, usually a symbol name (a class or method). It appears with regard to the current selection or insertion point automatically in the Quick Help inspector (Option-Command-2) if the inspector is showing. Thus, for example, if you’re editing code and the insertion point or selection is within the term CGPointMake, documentation for CGPointMake appears in the Quick Help inspector if it is visible. Quick Help is also available in the Quick Help inspector for interface objects selected while editing a nib, for build settings while editing a project or target, and so forth. 178 | Chapter 8: Documentation A slightly reduced version of the same Quick Help documentation can be displayed as a small floating window, without the Quick Help inspector. Select a term and choose Help → Quick Help for Selected Item (Shift-Control-Command-?). Alternatively, hold down Option and hover the mouse over a term until the cursor becomes a question mark (and the term turns blue with a dashed underline); then Option-click the term. The Quick Help documentation contains links. For example, click the Reference link to open the full documentation in the documentation window; click the header link to open the appropriate header file. Symbols A symbol is a nonlocally defined term, such as the name of a class, method, or instance variable. If you can see the name of a symbol in your code in an editor in Xcode, you can jump quickly to the definition of the symbol. Select text and choose Navigate → Jump to Definition (Control-Command-J). Alternatively, hold down Command and hover the mouse over a prospective term, until the cursor becomes a pointing finger (and the term becomes blue with a solid underline); Command-click the term to jump to the definition for that symbol. If the symbol is defined in a Cocoa framework, you jump to the declaration in the header file. If the symbol is defined in your code, you jump to the class or method definition; this can be very helpful not only for understanding your code but also for navigating it. The precise meaning of the notion “jump” depends upon the modifier keys you use in addition to the Command key, and on your settings in the General pane of Xcode’s preferences. For example, if you haven’t changed these settings from the default, Command-click jumps in the same editor, Command-Option-click jumps in an assis‐ tant pane, and Command-double-click jumps in a new window. Similarly, ControlOption-Command-J jumps in an assistant pane to the definition of the selected term. Another way to see a list of your project’s symbols, and navigate to a symbol definition, is through the Symbol navigator (Chapter 6). An important and often neglected way to jump to a method or class definition whose name you know, even if you can’t see the name in the code before you, is to choose File → Open Quickly (Shift-Command-O). In the search field, type key letters from the name, which will be interpreted intelligently; for example, to search for applicationDidFinishLaunching:, you might type “appdid”. Header file declarations are intermin‐ gled with your definitions; for example, for applicationDidFinishLaunching: the first listing is this method’s declaration in the Cocoa header file UIApplication.h, while the second listing is your own AppDelegate class’s implementation of this method. Other Resources | 179 Header Files Sometimes a header file can be a useful form of documentation. It compactly summa‐ rizes a class’s instance variables and methods and may contain comments and other helpful information — information that might be documented nowhere else. A single header file can contain declarations for multiple class interfaces and protocols. So it can be an excellent quick reference. There are various ways to see a header file from an Xcode editor: • If the class is your own and you’re in the implementation file, choose Navigate → Jump to Next Counterpart (Control-Command-Up). • Click the Related Files button at the left of the jump bar (Control-1). The menu lets you jump to any header files imported in the current file (as well as any files that import the current file) and to the header files of the current class file’s superclasses and subclasses and so forth. Hold Option to jump in an assistant pane. • Select text and choose File → Open Quickly (Shift-Command-O). This command brings up a dialog listing all source and header files containing a given symbol, as I mentioned in the previous section. • Command-click a symbol, choose Navigate → Jump to Definition, or pass through Quick Help, as described in the previous sections. • Use the Symbol navigator (Chapter 6). All of these approaches require that a project window be open; File → Open Quickly requires an active SDK for effective operation, and the others all operate on specific windows or words in an open project. An alternative that works under all circumstances, even when no project is open, is to switch to the Terminal and use the open -h command to open a header file in Xcode. The argument may represent part of a header file’s name. The command is interactive if there’s an ambiguity; for example, open -h NSString proposes to open NSString.h or NSStringDrawing.h (or both, or neither). I wish this command were built into Xcode itself. Internet Resources Programming has become a lot easier since the Internet came along and Google started indexing it. It’s amazing what you can find out with a Google search. Your problem is very likely one that someone else has faced, solved, and written about on the Internet. Often you’ll find sample code that you can paste into your project and adapt. Apple’s documentation resources are available at http://developer.apple.com. These re‐ sources are updated before the changes are rolled into your doc sets for download. There are also some materials here that aren’t part of the Xcode documentation on your com‐ puter. As a registered iOS developer, you have access to iTunes videos, including the 180 | Chapter 8: Documentation videos for all WWDC 2012 sessions (as well as for some earlier years), and to Apple’s developer forums (https://devforums.apple.com). Also, much of Apple’s documentation comes in an alternative PDF format, convenient for storing and viewing on an iPad. Even better, Ole Zorn’s Docsets app will let you download and browse entire docsets on an iPad or iPhone; it isn’t freeware, but it’s open source (https://github.com/omz/DocSetsfor-iOS), so it’s free if you’re willing to build it yourself. Apple maintains some public mailing lists (http://lists.apple.com/mailman/listinfo). I have long subscribed to the Xcode-users group (for questions about use of the Xcode tools) and the Cocoa-dev group (for questions about programming Cocoa). Cocoa-dev does permit iOS questions, but it is not heavily used for these. The lists are searchable, but Apple’s own search doesn’t work very well; you’re better off using Google with a site:lists.apple.com term, or http://www.cocoabuilder.com, which archives the lists. Apple has not added a mailing list devoted to iOS programming; that’s what the devel‐ oper forums are supposed to be for, but the interface for these is extraordinarily clunky, and this — plus the lack of openness (to Google and to the world in general) — has limited their usefulness. Other online resources, such as forums, have sprung up spontaneously as iOS pro‐ gramming has become more popular, and lots of iOS and Cocoa programmers blog about their experiences. I am particularly fond of Stack Overflow (http://www.stackoverflow.com); it isn’t devoted exclusively to iOS programming, of course, but lots of iOS programmers hang out there, questions are answered succinctly and correctly, and the interface lets you focus on the right answer quickly and easily. Other Resources | 181 CHAPTER 9 Life Cycle of a Project This chapter surveys some of the main stages in the life cycle of an Xcode project, from inception to submission at the App Store. This survey will provide an opportunity to discuss some additional features of the Xcode development environment. You already know how to create a project, define a class, and link to a framework (Chapter 6), as well as how to create and edit a nib (Chapter 7) and how to use the documentation (Chapter 8). Device Architecture and Conditional Code As you create a project (File → New → Project), after you pick a project template, in the screen where you name your project, the Devices pop-up menu offers a choice of iPad, iPhone, or Universal (meaning an app that runs on both iPhone and iPad natively, typically with a different interface on each type of device). You are not tied forever to your initial decision, but your life will be simpler if you decide correctly from the outset. The iPhone and iPad differ in their physical characteristics as well as their programming interfaces. The iPad has a larger screen size, along with some built-in interface features that don’t exist on the iPhone, such as split views and popovers (Chapter 22); thus an iPad project’s nib files and some other resources will typically differ from those of an iPhone project. Your choice in the Devices pop-up menu affects the details of the template on which your new project will be based. It also affects your project’s Targeted Device Family build setting: iPad The app will run only on an iPad. 183 Additional Simulator SDKs When the Deployment Target is set to a system earlier than 6.0, earlier Simulator SDK versions may become available as destinations in the Scheme pop-up menu. Exactly what versions appear depends on the contents of /Developer/Platforms/iPhoneSimula‐ tor.platform/Developer/SDKs/. Xcode 4.6 includes only the iOS 6.1 Simulator SDK, but you can download and install the iOS 6.0 and iOS 5.1/5.0 Simulator SDKs from the Downloads pane of the Preferences window (under Components). iPhone The app will run on an iPhone or iPod touch; it can also run on an iPad, but not as a native iPad app (it runs in a reduced enlargeable window, which I call the iPhone Emulator; Apple sometimes refers to this as “compatibility mode”). iPhone/iPad The app will run natively on both kinds of device, and should be structured as a universal app. Two additional build settings determine what systems your device will run on: Base SDK The latest system your app can run on. As of this writing, in Xcode 4.6, you have just two choices, iOS 6.1 and Latest iOS — but Latest iOS means iOS 6.1, so what’s the difference? It’s that, if you update Xcode to develop for a subsequent system, any existing projects that are already set to Latest iOS will use that newer system’s SDK as their Base SDK automatically, without your also having to update their Base SDK setting. Latest iOS is the default when you create a new project. For example, while I was writing this book, iOS 6.1 was released, so the current iOS version changed from iOS 6.0 to iOS 6.1. All my existing projects automatically started using the iOS 6.1 SDK as their Base SDK, because Latest iOS, which had been interpreted previously as meaning iOS 6.0, was now interpreted as meaning iOS 6.1. iOS Deployment Target The earliest system your app can run on: in Xcode 4.5 and later, this can be any major iOS system number from the current system all the way back to 4.3. You can change the iOS Deployment Target setting easily by editing your project or your target: the project’s Info tab has an iOS Deployment Target pop-up menu, and the target’s Summary tab has a Deployment Target pop-up menu. These both represent the iOS Deployment Target build setting; you will probably want to edit the target, because if you edit the project only, the target setting will override it. 184 | Chapter 9: Life Cycle of a Project Writing an app whose Deployment Target differs from its Base SDK is something of a challenge. There are two chief problems: Unsupported features With each new system, Apple adds new features. Xcode will happily allow you to compile using any features of the Base SDK, even if they don’t exist on the Deploy‐ ment Target system; but your app will crash if execution encounters features not supported by the system (device or Simulator) on which it is actually running. Thus, if you were to set the target’s Deployment Target to iOS 5, it would be able to compile and run on an iOS 5 device even if it contained iOS 6–only features, but it would crash on the iOS 5 device if any of those features were actually encountered. Our Empty Window project is a case in point. Install the iOS 5.1 Simulator SDK, change the Empty Window target’s Deployment Target to 5.1, set the destination in the Scheme pop-up menu to iPhone 5.1 Simulator, and run the project. Crash! Why? Because, by default, a new project’s nibs use autolayout, and any interface widgets they contain — such as the button in our ViewController.xib — use auto‐ layout constraints, which are instances of NSLayoutConstraint. But there is no NSLayoutConstraint class in iOS 5.1 or before. Changed behavior With each new system, Apple permits itself to change the way some features work. The result is that such features work differently on different systems, and will thus require two different sets of code. Sometimes these two sets of code can live side by side; sometimes you will have to write conditional code, so that one set of code executes when running on one system, another when running on another. Interface rotation is an obvious case in point; this UIViewController feature (Chapter 19) was completely revised between iOS 5 and iOS 6. If your app launches into portrait orientation, the UIViewController methods called are totally different on the two different systems; code that launches your app correctly and successfully on iOS 5 might end up displaying a blank screen on iOS 6 (guess how I know that?). More insidiously, text is drawn differently on iOS 6 from how it was drawn on iOS 5; the very same code might thus display text in a certain position on iOS 5, but in a different position on iOS 6 (guess how I know that?). How can you guard against such problems? Backwards compatibility isn’t easy, and it gets harder the further backwards you want to be compatible. Xcode 4.5 and later doesn’t support a Deployment Target earlier than 4.3; to compile for an earlier system, you’ll need an earlier version of Xcode. Xcode 4.5 and later doesn’t support a Simulator SDK earlier than 5.0; to test on an earlier version of the Simulator, you’ll need an earlier version of Xcode. But writing code compatible with an earlier version of Xcode is itself not easy; many of the modern Objective-C features used in this book won’t work in Xcode 4.2 or earlier. Moreover, testing in the Simulator is not enough; a physical device is essential for testing, implying that you need to maintain an arsenal of old iOS devices, Device Architecture and Conditional Code | 185 in order to discover compatibility issues before your app is let loose upon a world of users. Personally, I adopt wherever possible the Dr. Kronkheit Defense (look it up on Wikipedia): Don’t do that. Once I’ve rewritten one of my apps for iOS 6, it usually runs only on iOS 6 or later. Even if you can afford the luxury of not attempting backwards compatibility, however, you still might need to grapple with the problem of conditional code — if you want to write a universal app. Although you’ll probably want to reduce duplication by sharing some code between the iPhone and the iPad version of the app, nevertheless some code will likely have to be kept separate, because your app will need to behave differently on the different types of device. As I already mentioned, you can’t summon a popover on an iPhone; and the complexities can run considerably deeper, because the overall in‐ terfaces might be quite different, and might behave very differently — tapping a table cell on the iPhone might summon an entire new screenful of stuff, whereas on the larger iPad, it might only alter what appears in one region of the screen. Various programming devices help govern dynamically what code is encountered, based on what system or device type the app is running on; thus you can steer your code away from a crash or from undesirable behavior based on the runtime environment (see also Example 29-1): • The UIDevice class lets you query the current device to learn its system version (systemVersion) and type (userInterfaceIdiom, either UIUserInterfaceIdiomPhone or UIUserInterfaceIdiomPad): if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone) { // do things appropriate to iPhone } else { // do things appropriate to iPad } For an actual example, make a Universal project from the Master–Detail Applica‐ tion template and look in AppDelegate.m. You’ll see code that configures the initial interface differently depending on the device type we’re running on. • Certain Info.plist settings apply only to one device type or the other. Again, a Uni‐ versal project based on the Master–Detail Application template is a case in point. You’ll see that the Info.plist contains two sets of “Supported interface orientations” settings, a general set and an iPad-only set that overrides the general case when the app launches on an iPad. Similarly, if you create your Master-Detail Application Universal project with Use Storyboards checked, the project contains two storyboards, one containing the in‐ terface for running on an iPhone, the other for an iPad. The choice between them is made through the Info.plist setting “Main storyboard file base name”, which ap‐ pears twice, once for the general case and once for iPad only, the latter overriding 186 | Chapter 9: Life Cycle of a Project the former when the app launches on an iPad. (If you create your Master-Detail Application Universal project without Use Storyboards checked, the project con‐ tains two pairs of nibs, and the choice of which ones to load as the app launches is made in code, in App Delegate’s application:didFinishLaunchingWithOptions:, using the userInterfaceIdiom technique from the previous paragraph.) • Many calls that load resources by name from your app’s bundle will automatically select an alternative resource whose name (before the extension) ends with ~iphone or ~ipad as appropriate to the device type — if there is such an alternative resource. This relieves your code from using conditionals. For example, UIImage’s imageNamed: method, if you specify the image name as @"linen.png", will load an image called linen~ipad.png if it finds one and if we’re running on an iPad. We’ll see in Chapter 15 that the same sort of naming convention will also help you automatically load a double-resolution image on a device with a double-resolution screen. • If your app is linked to a framework and tries to run on a system that lacks that framework, it will crash at launch time. The solution is to link to that framework optionally, by changing the Required pop-up menu item in its listing in the target’s Linked Frameworks and Libraries to Optional; this is technically referred to as weak-linking the framework. • You can test for the existence of a method using respondsToSelector: and related NSObject calls: if ([UIButton respondsToSelector: @selector(appearance)]) { // ok to call appearance class method } else { // don't call appearance class method } • You can test for the existence of a class using the NSClassFromString function, which yields nil if the class doesn’t exist. Also, if the Base SDK is 5.0 or later, and if the class’s framework is present or weak-linked, you can send the class any message (such as [CIFilter class]) and test the result for nil; this works because classes are themselves weak-linked starting in iOS 5: // assume Core Image framework is weak-linked if ([CIFilter class]) { // ok to do things with CIFilter • You can test for the existence of a constant name, including the name of a C function, by taking the name’s address and testing against zero. For example: if (&UIApplicationWillEnterForegroundNotification) { // OK to refer to UIApplicationWillEnterForegroundNotification Device Architecture and Conditional Code | 187 Localization A device can be set by the user to prefer a certain language as its primary language. You might like the text in your app’s interface to respond to this situation by appearing in that language. This is achieved by localizing the app for that language. Localization operates through localization folders in your project and in the built app bundle. Let’s say that a resource in one of these localization folders has a counterpart in the other localization folders. Then, when your app goes to load such a resource, it automatically loads the one appropriate to the user’s preferred language. For example, if there’s a copy of InfoPlist.strings in the English localization folder and a copy of InfoPlist.strings in the French localization folder, the latter will be used when the app needs a copy of InfoPlist.strings on a device on which French is the preferred language. Not for nothing have I used InfoPlist.strings as my example. This is a file that’s present by default in your project — for example, it appears in our Empty Window example project — but its purpose wasn’t discussed in Chapter 6, so presumably you’ve been on tenterhooks since then, wondering what it was for. Well, it’s a .strings file; the purpose of a .strings file is to be localized. The purpose of this particular .strings file, InfoPlist.strings, is to store localized versions of Info.plist key values. So, for example, the value of the CFBundleDisplayName key, as set in your project’s Info.plist file, appears under your app’s icon on the user’s device. We might want to change this name depending the user’s primary language setting. For example, on a French language device, we might like our Empty Window app to be called Fenêtre Vide. As an example of localization, let’s arrange for that very thing to happen. First we must set up our app for localization to French; then we must localize InfoPlist.strings. 1. Edit the project. Under Info, the Localizations table lists our app’s localizations. 2. Click the Plus button under the Localizations table. From the pop-up menu that appears, choose French. 3. A dialog appears, listing files that are currently localized for English (because they came that way as part of the app template). We’re dealing here with just Info‐ Plist.strings, so leave it checked but uncheck any other files that appear here. Click Finish. We have now set up InfoPlist.strings to be localized for both English and French. This fact is reflected in two ways: • In the Project navigator, the listing for InfoPlist.strings has acquired a flippy triangle. Open the triangle to reveal that our project now contains two copies of Info‐ 188 | Chapter 9: Life Cycle of a Project Figure 9-1. How a localized strings file is represented in Xcode Plist.strings, one for English and one for French (Figure 9-1). Thus we can now edit either one individually. • In the Empty Window project folder on disk, there is now both an en.lproj folder and a fr.lproj folder. The former contains the copy of InfoPlist.strings destined for English language users; the latter contains the copy of InfoPlist.strings destined for French language users. Moreover, when we build, this folder structure is copied into the built app. Now let’s edit our InfoPlist.strings files. A .strings file is simply a collection of key–value pairs in the following format: /* Optional comments are C-style comments */ "key" = "value"; In the case of InfoPlist.strings, the key is simply the key name from Info.plist — the raw key name, not the English-like name. So the English InfoPlist.strings should look like this: "CFBundleDisplayName" = "Empty Window"; The French InfoPlist.strings should look like this: "CFBundleDisplayName" = "Fenêtre Vide"; Now let’s try it! 1. Build and run Empty Window on the iPhone Simulator. 2. In Xcode, stop the running project. In the Simulator, the home screen is revealed. 3. Examine the name of our app, as displayed in the Simulator home screen. It is Empty Window (truncated to “Empty…ndow”). 4. In the Simulator, launch the Settings app and change the language to French (Gen‐ eral → International → Language → Français). Our app’s name is now displayed as Fenêtre Vide. Is this fun or what? When you’re done marveling at your own cosmopolitanism, change the Simulator’s language back to English. Now let’s talk about nib files (and storyboard files). Before Xcode 4.5 and iOS 6, the case of a nib file (or storyboard file) was similar to what we just did with InfoPlist.strings: it was necessary to localize the entire nib (or storyboard). So, for example, you would have Localization | 189 selected ViewController.xib in the Project navigator, switched to the File inspector, and checked French in the Localization table. This would cause you to end up with two copies of ViewController.xib, and you would edit each one so that any text displayed in the interface, such as button titles, appeared in the appropriate language. Starting in Xcode 4.5 and iOS 6, however, there’s a better way: 1. Edit the project again, and below the Localization table, check Use Base Interna‐ tionalization. 2. A dialog appears, listing nib and storyboard files that are currently localized only for English. At present, it lists just ViewController.xib, and it is checked. That’s good! Click Finish. 3. Back in the Project navigator, select ViewController.xib. Look in the File inspector. The Localization table now contains three entries: Base, English, and French. Base is already checked. Check French. 4. Clean the build folder (hold Option and choose Product → Clean Build Folder)! Omitting this step will probably cause your app to misbehave in future. In the Project navigator, the result is that ViewController.xib has a flippy triangle. Open it to reveal that ViewController.xib is now split into two different types of file: • If the user’s device is not localized for French, the Base file will be used. That’s the nib file itself, which has been moved on disk into a new Base.lproj folder. Thus we can continue to edit the nib file, ViewController.xib, using English as the default language. • If the user’s device is localized for French, a .strings file will be used — View‐ Controller.strings, located on disk inside the fr.lproj folder. This file, including the keys and initial values, has been generated for us automatically based on the content of ViewController.xib. So, at the moment the French ViewController.strings file contains this line: "38.normalTitle" = "Button"; Let’s change that to French. Don’t change the key! It’s meaningless to you and out of your control (though if you’re really determined you can pretty easily work out how it is derived), and you don’t want to break the connection between this string and the button to which it applies. Change only the value: "38.normalTitle" = "Bouton"; Build and run the app in the Simulator and switch languages as before to see the effects of your work. 190 | Chapter 9: Life Cycle of a Project Finally, what about strings that appear in your app’s interface but whose value is gen‐ erated in code? (In the Empty Window app as we’ve developed it so far, examples include the modified text of the UILabel, or the content of the alert summoned by tapping the button.) The approach is the same — a .strings file — but your code must be modified to use it explicitly. There are various ways to do this, but the simplest is to use the NSLocalizedString macro (which calls an NSBundle instance method, localizedStringForKey:table:). So, for example, we might modify our buttonPressed: method to look like this: UIAlertView* av = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"AlertGreeting", nil) message:NSLocalizedString(@"YouTappedMe", nil) delegate:nil cancelButtonTitle:NSLocalizedString(@"Cool", nil) otherButtonTitles:nil]; The string provided as the first argument to NSLocalizedString is the key in a .strings file. Our code is now broken, however, as there is no corresponding .strings file. By default, the .strings file expected here is called Localizable.strings. But no such file exists. There’s no error, but these keys have no value either — so the key itself is used when the alert appears, which is not what we want. You’ll need to create the re‐ quired .strings file: 1. Choose File → New → File. 2. The “choose a template” dialog appears. On the left, under iOS, select Resource. On the right, select Strings File. Click Next. 3. Name the file Localizable.strings. Pick an appropriate Group, and make sure this file is part of our Empty Window target. Click Create. 4. Now we must localize the new file. In the Project navigator, select Localiza‐ ble.strings. In the File inspector, under Localization, click the “Make localized” but‐ ton. A dialog offers to move the existing file into the English localization, which is exactly what you want. 5. In the File inspector, you can now add localizations as desired. For example, you could check French. You must now also provide our Localizable.strings files with content, in accordance with the localizable string keys specified in your code. What? We have to comb through our code, looking for calls to NSLocalizedString, and copying out the keys into our .strings files? This sounds like a royal pain, not to mention being an invitation to make some careless mistake. Fortunately, the genstrings command-line tool will do the work for you, seeking out the NSLocalizedString calls and generating the initial contents of a .strings file (using the keys as default values). So, for example, on my machine I would now say, in the Terminal: Localization | 191 $ genstrings /Users/matt/Desktop/Empty\ Window/Empty\ Window/ViewController.m The result is a file Localizable.strings in the current directory, reading as follows: /* No comment provided by engineer. */ "AlertGreeting" = "AlertGreeting"; /* No comment provided by engineer. */ "Cool" = "Cool"; /* No comment provided by engineer. */ "YouTappedMe" = "YouTappedMe"; We are now waving our hands; completing the localization of our Empty Window project is left as an exercise for the reader. For a full if somewhat outdated discussion of localization, see Apple’s Internationalization Programming Topics. Editing Your Code Many aspects of Xcode’s editing environment can be modified to suit your tastes. Your first step should be to pick a font face and size you like in the Fonts & Colors preference pane. Nothing is so important as being able to read and write code comfortably! I like a largish size (13, 14 or even 16) and a pleasant monospaced font such as Monaco, Menlo, or Consolas (or the freeware Inconsolata). Xcode has some formatting, autotyping, and text selection features adapted for Objective-C. Exactly how these behave depends upon your settings in the Editing and Indentation tabs of Xcode’s Text Editing preference pane. I’m not going to describe these settings in detail, but I urge you to take advantage of them. Under Editing, I like to check just about everything, including Line Numbers; visible line numbers are useful when debugging. Under Indentation, I like to have just about everything checked too; I find the way Xcode lays out Objective-C code to be excellent with these settings. A sound approach might be to check everything initially and then, when you’ve some experience editing with Xcode, switch off features you don’t prefer. If you like Xcode’s smart syntax-aware indenting, but you find that once in a while a line of code isn’t indenting itself correctly, try choosing Editor → Structure → Re-Indent (Control-I), which autoindents the current line. (Autoindent problems can also be caused by incorrect syntax earlier in the file, so hunt for that too.) Under Editing, notice “Automatically balance brackets in Objective-C method calls.” If this option is checked, then when you type a closing square bracket after some text, Xcode intelligently inserts the opening square bracket before the text. I like this feature, as it allows me to type nested square brackets without planning ahead. For example, I type this: UIAlertView* av = [UIAlertView alloc 192 | Chapter 9: Life Cycle of a Project I now type the right square bracket twice. The first right square bracket closes the open left square bracket (which highlights to indicate this). The second right square bracket also inserts a space before itself, plus the missing left square bracket: UIAlertView* av = [[UIAlertView alloc] ] // insertion point is here: ^ The insertion point is positioned before the second right square bracket, ready for me to type init. With “Enable type-over completions” checked, Xcode goes even further. As I start to type that same line of code: UIAlertView* av = [U Xcode automatically appends the closing right square bracket, with the insertion point still positioned before it: UIAlertView* av = [U] That closing right square bracket, however, is tentative; it’s in gray. When I finish typing the first nested method call: UIAlertView* av = [UIAlertView alloc] I can now confirm the closing right square bracket in any of several ways. I can actually type a right square bracket; or I can type Tab or Right arrow. The tentative right square bracket is replaced by a real right square bracket, and the insertion point is now posi‐ tioned after it, ready for me to continue typing. With practice, you’ll quickly get used to this feature, which has greatly increased my own fluidity in typing code. Autocompletion As you write code, you’ll take advantage of Xcode’s autocompletion feature. ObjectiveC is a verbose language, and whatever reduces your time and effort typing will be a relief. However, I personally do not check “Suggest completions while typing” under Editing; instead, I check “Use Escape key to show completion suggestions”, and when I want autocompletion to happen, I ask for it manually, by pressing Esc. For example, suppose my code is as displayed in the previous example, with the insertion point before the second right square bracket. I now type init and then press Esc, and a little menu pops up, listing the four init methods appropriate to a UIAlertView (Figure 9-2). You can navigate this menu, dismiss it, or accept the selection, using only the keyboard. So, if it were not already selected by default, I would navigate to initWithTitle:... and press Return to accept the selected choice. Alternatively, I might press Control-Period instead of Esc. Pressing Control-Period re‐ peatedly cycles through the alternatives. Again, press Return to accept the selected choice. Another possibility is to press Tab, which performs a partial completion without Editing Your Code | 193 Figure 9-2. The autocompletion menu dismissing the autocompletion menu; in Figure 9-2, if I were to press Tab at this moment, initWith would be completed in my code — that’s what the dashed underlines are telling me — and bare init, no longer an eligible completion, would be eliminated from the menu. Observe also that there is a reduced form of Quick Help at the bottom of the autocom‐ pletion menu; click the More link to view (in the documentation window) the full doc‐ umentation for the currently selected method (Chapter 8). When I choose an alternative from the autocompletion menu, the template for the correct method call is entered in my code (I’ve broken it manually into multiple lines to show it here): [[UIAlertView alloc] initWithTitle:<#(NSString message:<#(NSString delegate:<#(id)#> cancelButtonTitle:<#(NSString otherButtonTitles:<#(NSString *)#> *)#> *)#> *), ...#>, nil] The expressions in <#...#> are placeholders, showing the type of each parameter; you can select the next placeholder with Tab (if the insertion point precedes a placeholder) or by choosing Navigate → Jump to Next Placeholder (Control-Slash). Thus I can select a placeholder and type in its place the actual argument I wish to pass, select the next placeholder and type that argument, and so forth. Placeholders are delimited by <#...#> behind the scenes, but they appear in Xcode as “text tokens” to prevent them from being edited accidentally. To convert a placeholder to a normal string without the delimiters, select it and press Return, or double-click it. Autocompletion also works for method declarations. You don’t have to know or enter a method’s return type beforehand. Just type the initial - or + (to indicate an instance method or a class method) followed by the first few letters of the method’s name. For example, in my app delegate I might type: 194 | Chapter 9: Life Cycle of a Project - appli If I then press Esc, I see a list of methods such as application:didChangeStatusBarFrame:; these are methods that might be sent to my app delegate (by virtue of its being the app delegate, as discussed in Chapter 11). When I choose one, the declaration is filled in for me, including the return type and the parameter names: - (void)application:(UIApplication *)application didChangeStatusBarFrame:(CGRect)oldStatusBarFrame At this point I’m ready to type the left curly brace, followed by a Return character; this causes the matching right curly brace to appear, with the insertion point positioned between them, ready for me to start typing the body of this method. Snippets Code autocompletion is supplemented by code snippets. A code snippet is a bit of text with an abbreviation. Code snippets are kept in the Code Snippet library (ControlOption-Command-2), but a code snippet’s abbreviation is globally available, so you can use it without showing the library. You type the abbreviation and the snippet’s name is included among the possible completions. For example, to enter an if block, I would type if and press Esc, to get autocompletion, and select “If Statement”. When I press Return, the if block appears in my code, and the condition area (between the parentheses) and statements area (between the curly braces) are placeholders. To learn a snippet’s abbreviation, you must open its editing window — double-click the snippet in the Code Snippet library — and click Edit. If learning a snippet’s abbreviation is too much trouble, simply drag it from the Code Snippet library into your text. You can add your own snippets, which will be categorized as User snippets; the easiest way is to drag text into the Code Snippet library. Edit to suit your taste, providing a name, a description, and an abbreviation; use the <#...#> construct to form any desired placeholders. Fix-it and Live Syntax Checking Xcode’s extremely cool Fix-it feature can actually make and implement positive sug‐ gestions on how to avert a problem. To summon it, click on an issue badge in the gutter. Such an issue badge will appear after compilation if there’s a problem. For instance, in Figure 9-3 I’ve accidentally omitted the @ before an Objective-C NSString literal, and the compiler is warning (because what I’ve typed is a C string literal, a very different thing). By clicking on the warning badge in the gutter, I’ve summoned a little dialog that not only describes the mistake but tells me how to fix it. Not only that: it has tentatively (in grey) implemented that solution; it has inserted the missing @ into Editing Your Code | 195 Figure 9-3. A warning with a Fix-it suggestion my code. Not only that: if I press Return, or double-click the “Fix-it” button in the dialog, Xcode really inserts the missing @ into my code — and the warning vanishes, because the problem is solved. If I’m confident that Xcode will do the right thing, I can choose Editor → Fix All in Scope (Control-Option-Command-F), and Xcode will implement all nearby Fix-it suggestions without my even having to show the dialog. Live syntax checking is like a form of constant compilation. Even if you don’t compile or even save, live syntax checking can detect the presence of a problem, and can suggest the solution with Fix-it. This feature can be toggled on or off using the “Show live issues” checkbox in the General preference pane. Personally, I keep it turned off, as I find it intrusive. My code is almost never valid while I’m typing, because the terms and paren‐ theses are always half-finished; that’s what it means to be typing. For example, merely typing a left parenthesis will instantly cause the syntax checker to complain of a parse error (until I type the corresponding right parenthesis). Navigating Your Code Developing an Xcode project involves editing code in many files at once. Xcode provides numerous ways to navigate your code. Many of these have been mentioned in previous chapters. Most navigation methods can be tweaked with the Option key to navigate in an assistant pane instead of the main editor, or with Shift-Option to bring up the nav‐ igation window. The Project navigator If you know something about the name of a file, you can find it quickly in the Project navigator (Command-1) by typing into the search field in the filter bar at the bottom of the navigator (Edit → Filter → Filter in Navigator, Command-Option-J). For example, type xib to see just your nib files. Moreover, after using the filter bar, you can press Tab and then the Up or Down arrow key to navigate the Project navigator. Thus you can reach the desired file with the keyboard alone. The Symbol navigator If you highlight the first two icons in the filter bar (the first two are dark, the third is light), the Symbol navigator lists your project’s classes and their methods. Now 196 | Chapter 9: Life Cycle of a Project you can navigate to a desired method. As with the Project navigator, the filter bar’s search field can quickly get you where you want to go. The jump bar Every path component of the jump bar is a menu: The bottom level At the bottom level (farthest right) in the jump bar is a list of your file’s method and function declarations and definitions, in the order in which they appear (hold Command while choosing the menu to see them in alphabetical order); choose one to navigate to it. Start typing while the menu is open to filter what the menu displays. You can add section titles to this bottom-level menu using the #pragma mark directive. For example, try modifying ViewController.m in our Empty Window project: #pragma mark - View lifecycle - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view... } The result is that the “viewDidLoad” item in the bottom-level menu falls within a “View lifecycle” section. (But only if a method definition precedes the #pragma line. I regard this limitation as a bug.) To make a section divider line in the menu, type a #pragma mark directive whose value is a hyphen; in the preceding example, both a hyphen (to make a section divider line) and a title (to make a bold section title) are used. Similarly, comments outside of any method and starting with TODO:, FIXME:, ???:, or !!!: will appear in the bottom-level menu. Higher levels Higher-level path components are hierarchical menus; thus you can use any of them to work your way down the file hierarchy. History Each editor pane remembers the names of files you’ve edited in it. The Back and Forward triangles are both buttons and pop-up menus (or choose Navigate → Go Back and Navigate → Go Forward, Control-Command-Left and ControlCommand-Right). Related items The leftmost button in the jump bar summons a hierarchical menu of files related to the current file, such as counterparts, superclasses, and included files. Navigating Your Code | 197 New in Xcode 4.5 and later, this list even includes methods that call or are called by the currently selected method. The Assistant pane The Assistant lets you be in two places at once. Hold Option while navigating to open something in an Assistant pane instead of the primary editor pane. The first path component in an Assistant pane’s jump bar sets its automatic rela‐ tionship to the main pane (tracking). This is effectively the same hierarchical menu of related items I mentioned a moment ago, applied to the main pane. If the chosen relationship involves multiple files, triangle buttons appear at the right end of the jump bar, letting you navigate between them; or choose from the second path com‐ ponent’s pop-up menu (Control-5). For example, show AppDelegate.m in the main pane and switch the assistant pane’s related items pop-up menu to Includes; the triangle buttons at the right end of the jump bar then navigate between different files #imported by AppDelegate.m. You can also be in two places at once by opening a tab or a separate window. Jump to definition Navigate → Jump to Definition (Control-Command-J) lets you jump to the decla‐ ration or definition of the symbol already selected in your code. Open quickly File → Open Quickly (Shift-Command-O) searches in a dialog for a symbol in your code and the Cocoa headers. You can type the symbol in the search field, or, if a symbol is selected when you summon the dialog, it will be entered in the search field for you. You can navigate the dialog entirely with the keyboard. Breakpoints The Breakpoint navigator lists all breakpoints in your code. Xcode lacks code book‐ marks, but you can misuse a disabled breakpoint as a bookmark. Breakpoints are discussed later in this chapter. Finding Finding is a form of navigation. Xcode has both a global find (Edit → Find → Find in Workspace, Shift-Command-F, which is the same as using the Search navigator) and an editor-level find (Edit → Find → Find, Command-F); don’t confuse them. Find options are all-important. Both sorts of find have options that you can sum‐ mon by clicking the magnifying glass. The global find options (Figure 6-3) allow you to specify the scope of a search (which files will be searched) in sophisticated ways: choose Custom in the “Find in” pop-up menu to create a scope. The global find search bar also pops down a menu automatically as you type if the find options 198 | Chapter 9: Life Cycle of a Project aren’t showing, letting you switch among the most important options. You can also find using regular expressions. There’s a lot of power lurking here. To replace text, click on the word Find at the left end of the search bar to summon the pop-up menu, and choose Replace. (It may be necessary to perform a global find first, before a global replace on the same search term will work.) You can replace all occurrences, or select particular find results in the Search navigator and replace only those (click Replace instead of Replace All). The Search navigator’s Preview button summons a dialog that shows you the effect of each possible replacement, and lets you check or uncheck particular replacements in advance of performing the replacement. For editor-level find, hold Option before clicking Replace All, to find-and-replace within only the current selection. A sophisticated form of editor-level find is Editor → Edit All In Scope, which finds simultaneously all occurrences of the currently selected term (usually a variable name) within the current set of curly braces; you can use this to change a variable’s name throughout its scope, or just to survey how the name is used. To change a symbol’s name throughout your code, as well as for auto‐ mated, intelligent assistance in performing various code rearrange‐ ments that commonly arise in Objective-C programming, use Xcode’s Refactoring feature (see “Make Projectwide Changes” in the Xcode 4 User Guide). Debugging Debugging is the art of figuring out what’s wrong with the behavior of your app as it runs. I divide this art into two main techniques: caveman debugging and pausing your running app. Caveman Debugging Caveman debugging consists of altering your code, usually temporarily, typically by adding code to dump informative messages into the console. The standard command for sending a message to the console is NSLog. It’s a C function, and it takes an NSString which operates as a format string, followed by the format arguments. A format string is a string (here, an NSString) containing symbols called format speci‐ fiers, for which values (the format arguments) will be substituted at runtime. All format specifiers begin with a percent sign (%), so the only way to enter a literal percent sign in a format string is as a double percent sign (%%). The character(s) following the percent sign specify the type of value that will be supplied at runtime. The most common format Debugging | 199 specifiers are %@ (an object reference), %i (an integer), %f (a float), and %p (a pointer, usually an object reference, shown as the address in memory pointed to, useful for making certain that two references refer to the same instance). For example: NSLog(@"the window: %@", self.window); In that example, self.window is the first (and only) format argument, so its value will be substituted for the first (and only) format specifier, %@, when the format string is printed in the console. Thus the console output looks something like this: the window: <UIWindow: 0x6a08140; frame = (0 0; 320 480); layer = <UIWindowLayer: 0x6a08230>> This nice display of information is due to UIWindow’s implementation of the description method: an object’s description method is called when that object is used with the %@ format specifier. For this reason, you will probably want to implement description in your own classes, so that you can investigate an instance with a simple NSLog call. For the complete repertory of format specifiers available in a format string, read Apple’s document String Format Specifiers. The format specifiers are largely based on those of the C printf standard library function; see K&R B1.2, the sprintf man page, and the IEEE printf specification linked from the documentation. If an object reference has been set to nil, NSLog will report it as (null). But if an object reference is uninitialized, an NSLog call refer‐ ring to it will probably fail silently, or even crash the debugger. This is very frustrating, especially since the fact that this object reference is uninitialized is probably just what you were trying to debug. Fortu‐ nately, if you use ARC (Chapter 12), an object reference is autoinitial‐ ized to nil if you don’t initialize it explicitly. The main ways to go wrong with NSLog (or any format string) are to supply a different number of format arguments from the number of format specifiers in the string, or to supply an argument value different from the type declared by the corresponding format specifier. I often see beginners claim that logging shows a certain value to be nonsense, when in fact it is their NSLog call that is nonsense; for example, a format specifier was %i but the value of the corresponding argument was a float. Fortunately, recent versions of the compiler will try to help you with warnings. C structs are not objects, so to see a struct’s value with NSLog you must somehow deconstruct or translate the struct. Common Cocoa structs usually supply convenience functions for this purpose. For example: NSLog(@"%@", NSStringFromCGRect(self.window.frame)); // {{0, 0}, {320, 480}} 200 | Chapter 9: Life Cycle of a Project Purists may scoff at caveman debugging, but I use it heavily: it’s easy, informative, and lightweight. And sometimes it’s the only way. Unlike the debugger, NSLog works with any build configuration (Debug or Release) and wherever your app runs (in the Simu‐ lator or on a device). It works when pausing is impossible (because of threading issues, for example). It even works on someone else’s device, such as a tester to whom you’ve distributed your app. It’s a little tricky for a tester to get a look at the console so as to be able to report back to you, but it can be done: the tester can connect the device to a computer and view its log in Xcode’s Organizer window or with Apple’s iPhone Con‐ figuration Utility; there’s also a free utility app called Console that displays the log right on the device. Remember to remove or comment out NSLog calls before shipping your app, as you probably don’t want your finished app to dump lots of messages into the console. A useful trick (shamelessly stolen from Jens Alfke) is to call MyLog instead of NSLog, and define MyLog like this in your precompiled header (and when it’s time to stop logging, change the 0 to 1): #define MyLog if(0); else NSLog A useful fact when logging is that the variable name _cmd holds the selector for the current method. Thus a single form of statement can signal where you are: NSLog(@"Logging %@ in %@", NSStringFromSelector(_cmd), self); (Similarly, in a C function, NSLog(@"%s", __FUNCTION__) logs the name of the func‐ tion.) Another sort of call with which you can pepper your code is asserts. Asserts are condi‐ tions that you claim (assert) are true at that moment — and you feel so strongly about this that you want your app to crash if you’re wrong. Asserts are a very good way to confirm that the situation matches your expectations, not just now as you write your code, but in the future as the app develops. The simplest form of assert is the C function (actually it’s a macro) assert, to which you pass one argument, a condition — something that can be evaluated as false (0) or true (some other value). If it’s false, your app will crash when this line is encountered, along with a nice explanation in the log. For example, suppose we assert NO, which is false and will certainly cause a crash. Then when this line is encountered we crash with this log message: Assertion failed: (NO), function -[AppDelegate application:didFinishLaunchingWithOptions:], file /Users/mattleopard/Desktop/testing/testing/AppDelegate.m, line 20. That’s plenty for us to track down the assertion failure: we know the assertion condition, the method in which the assertion occurred, the file containing that method, and the line number. Debugging | 201 For higher-level asserts, look at NSAssert (used in Objective-C methods) and NSCAssert (used in C functions). They allow you to form your own log message, which is to appear in the console in addition to the native assert logging; the log message can be a format string followed by values corresponding to the format specifiers, as with NSLog. Some developers think that asserts should be allowed to remain in your code even when your app is finished. By default, however, higher-level asserts are disabled in a Release build, thanks to the Other C Flags build setting, which is set to -DNS_BLOCK_ASSERTIONS=1 in Apple’s project templates; the effect of this setting is to #define the preprocessor macro NS_BLOCK_ASSERTIONS, which in turn is the signal for asserts to be effectively neutered at precompile time. To keep asserts working in a Release build, clear that value from the Other C Flags build setting in your target. The Xcode Debugger When you’re building and running in Xcode, you can pause in the debugger and use Xcode’s debugging facilities. There isn’t a strong difference between running and de‐ bugging in Xcode; the main distinction is whether breakpoints are effective or ignored. The effectiveness of breakpoints can be toggled at two levels: Globally Breakpoints as a whole are either active or inactive. If breakpoints are inactive, we won’t pause at any breakpoints. Individually A given breakpoint is either enabled or disabled. Even if breakpoints are active, we won’t pause at this one if it is disabled. Disabling a breakpoint allows you to leave in place a breakpoint that you might need later without pausing at it every time it’s encountered. A breakpoint, then, is ignored if it is disabled or if breakpoints as a whole are inactive. The important thing, if you want to use the debugger, is that the app should be built with the Debug build configuration. The debugger is not very helpful against an app built with the Release build configuration, not least because compiler optimizations can destroy the correspondence between steps in the compiled code and lines in your code. Trying to debug a Release build is a common beginner error (though it’s less likely to occur accidentally in Xcode 4, in which by default a scheme’s Run action uses the Debug build configuration). To create a breakpoint (Figure 9-4), select in the editor the line where you want to pause, and choose Product → Debug → Add Breakpoint at Current Line (CommandBackslash). This keyboard shortcut toggles between adding and removing a breakpoint for the current line. The breakpoint is symbolized by an arrow in the gutter. Alterna‐ tively, a simple click in the gutter adds a breakpoint; to remove a breakpoint gesturally, drag it out of the gutter. 202 | Chapter 9: Life Cycle of a Project Figure 9-4. A breakpoint Figure 9-5. A disabled breakpoint To disable a breakpoint at the current line, click on the breakpoint in the gutter to toggle its enabled status. Alternatively, Control-click on the breakpoint and choose Disable Breakpoint in the contextual menu. A dark breakpoint is enabled; a light breakpoint is disabled (Figure 9-5). Once you have some breakpoints in your code, you’ll want to survey and manage them. That’s what the Breakpoint navigator is for. Here you can navigate to a breakpoint, enable or disable a breakpoint by clicking on its arrow in the navigator, and delete a breakpoint. You can also edit a breakpoint’s behavior. Control-click on the breakpoint, in the gutter or in the Breakpoint navigator, and choose Edit Breakpoint; or Command-Option-click the breakpoint. This is a very powerful facility: you can have a breakpoint pause only under a certain condition or after it has been encountered a certain number of times, and you can have a breakpoint perform one or more actions when it is encountered, such as issuing a debugger command, logging, playing a sound, speaking text, or run‐ ning a script. A breakpoint can be configured to continue automatically after performing its action when it is encountered. This can be an excellent alternative to caveman debugging: instead of inserting an NSLog call, which must be compiled into your code and later removed when the app is released, you can set a breakpoint that logs and continues; by definition, such a breakpoint operates only when you’re debugging. In the Breakpoint navigator, you can create two kinds of breakpoint that you can’t create in the code editor: exception breakpoints and symbolic breakpoints. Click the Plus button at the bottom of the navigator and choose from its pop-up menu. Exception breakpoint An exception breakpoint causes your app to pause at the time an exception is thrown or caught, without regard to whether the exception would crash your app later. I recommend that you create an exception breakpoint to pause on all exceptions Debugging | 203 Figure 9-6. Paused at a breakpoint when they are thrown, because this gives the best view of the call stack and variable values at the moment of the exception (rather than later when the crash actually occurs); you can see where you are in your code, and you can examine variable values, which may help you understand the cause of the problem. If you do create such an exception breakpoint, I also suggest that you use the contextual menu to say Move Breakpoint To → User, which makes this breakpoint permanent and global to all your projects. Symbolic breakpoint A symbolic breakpoint causes your app to pause when a certain method or function is called, regardless of what object called it or to what object the message is sent. The method or function name may be specified directly; a method may alternatively be specified using the instance method or class method symbol (- or +) followed by square brackets containing the class name and the method name. For example, to learn where in my app the beginReceivingRemoteControlEvents message was being sent to my shared application instance, I configured a symbolic breakpoint like this: -[UIApplication beginReceivingRemoteControlEvents] To toggle the active status of breakpoints as a whole, click the Breakpoints button in the project window toolbar, or choose Product → Debug → Activate/Deactivate Break‐ points (Command-Y). The active status of breakpoints as a whole doesn’t affect the enabled or disabled status of any breakpoints; if breakpoints are inactive, they are simply ignored en masse, and no pausing at breakpoints takes place. Breakpoint arrows are blue if breakpoints are active, gray if they are inactive. When the app runs with breakpoints active and an enabled breakpoint is encountered (and assuming its conditions are met, and so on), the app pauses. In the active project window, the editor shows the file containing the point of execution, which will usually be the file containing the breakpoint. The point of execution is shown as a green arrow; this is the line that is about to be executed (Figure 9-6). Depending on the settings for Running → Pauses in the Behaviors preference pane, the Debug navigator and the Debug pane will also appear. Here are some things you might like to do while paused at a breakpoint: 204 | Chapter 9: Life Cycle of a Project Which Debugger? Throughout the history of Xcode, the debugger tool has been GDB. Starting in Xcode 4.2, the debugger LLDB became available as an alternative (http://lldb.llvm.org); starting in Xcode 4.3, LLDB became the default debugger for new projects. LLDB is said to be the way of the future, and in this edition I’ve knuckled under, keying my discussion to LLDB. To switch debuggers, use the Scheme editor; in the Info pane of the Run action, change the Debugger pop-up menu to GDB or LLDB. See where you are One common reason for setting a breakpoint is to make sure that the path of exe‐ cution is passing through a certain line. You can see where you are in any of your methods by clicking on the method name in the call stack, shown in the Debug navigator. Methods listed in the call stack with a User icon, with the text in black, are yours; click one to see where you are paused in that method. Other methods, with the text in gray, are methods for which you have no source code, so there would be little point clicking one unless you know something about assembly language. The slider in the filter bar hides chunks of the call chain, to save space, starting with the meth‐ ods for which you have no source. You can also navigate the call stack using the jump bar at the top of the Debug pane. Study variable values This is a very common reason for pausing. In the Debug pane, variable values for the current scope (corresponding to what’s selected in the call stack) are visible in the variables list. You can see additional object features, such as collection elements, instance variables, and even some private information, by opening triangles. Switch the pop-up menu above the variables list to Auto to see only those variables that Xcode thinks will interest you (because their value has been recently changed, for instance); if you’re after completeness, Local will probably be the best setting. You can use the search field to filter variables by name or value. In some cases, toggling Show Summmaries in the contextual menu can give a faster or more reliable display of variables. Even with formatted summaries turned off, you can send description to an object variable and view the output: choose Print Description of [Variable] from the contextual menu. Set a watchpoint A watchpoint is like a breakpoint, but instead of depending on a certain line of code it depends on a variable’s value: the debugger pauses whenever the variable’s value changes. You can set a watchpoint only while paused in the debugger. Control-click Debugging | 205 on the variable in the variables list and choose Watch [Variable]. Watchpoints, once created, are listed and managed in the Breakpoint navigator. Manage expressions An expression is code to be added to the variables list and evaluated every time we pause. Choose Add Expression from the contextual menu in the variables list. The expression is evaluated within the current context in your code, so be careful of side effects! Using expr in the console or as a breakpoint’s Debugger Command action (see the next paragraph) would be less of a blunt instrument. Talk to the debugger You can communicate verbally with the debugger in the console. Xcode’s debugger is a front end to an underlying command-line debugger tool (GDB or LLDB). Thus, by talking directly to that command-line tool you can do everything that you can do through the Xcode debugger interface, and more. A common command is po (for “print object”) followed by an object variable’s name or a method call that returns an object; it calls the object’s description method, just like NSLog. Another valuable command is expr, which evaluates an ObjectiveC expression in the current context — meaning, among other things, that you can call a method, or change the value of a variable in scope! Any such command is also eligible to be used as a breakpoint’s Debugger Command action, meaning that a breakpoint can issue the command automatically. For a good list of other things you’re likely to say, see http://lldb.llvm.org/lldbgdb.html. Fiddle with breakpoints You are free to create, destroy, enable and disable, and otherwise manage break‐ points dynamically even though your app is running, which is useful because where you’d like to pause next might depend on what you learn while you’re paused here. Indeed, this is one of the main advantages of breakpoints over caveman debugging. To change your caveman debugging, you have to stop the app, edit it, rebuild it, and start running the app all over again. But to fiddle with breakpoints, you don’t have to be stopped; you don’t even have to be paused! An operation that went wrong, if it doesn’t crash your app, can probably be repeated in real time; so you can just add a breakpoint and try again. For example, if tapping a button produces the wrong results, you can add a breakpoint and tap the button again; this time through the same code, you can work out what the trouble is. Step or continue To proceed with your paused app, you can either resume running until the next breakpoint is encountered (Product → Debug → Continue) or take one step and pause again. Also, if you hover the mouse over the gutter, a green Continue to Here 206 | Chapter 9: Life Cycle of a Project button appears; pressing this, or alternatively choosing Product → Debug → Con‐ tinue to Current Line (or Continue to Here in the contextual menu), effectively sets a breakpoint at the chosen line, continues, and removes the breakpoint. The stepping commands (under Product → Debug) are: Step Over Pause at the next line. Step Into Pause in your method that the current line calls, if there is one; otherwise, pause at the next line. Step Out Pause when we return from the current method. You can access these commands through convenient buttons at the top of the Debug pane. Even if the Debug pane is collapsed, the part containing the buttons appears while running. You can also float the project window over everything else on your computer while debugging by choosing Product → Debug Workflow → Xcode Always In Front; after you then switch to the Simulator, you can interact with the Xcode window without giving it focus. If you do want to give it focus, to type in a filter bar for instance, click Focus in the toolbar. This mode of working could be useful while you’re interacting with the Simulator, so as not to have to keep switching between the Simulator and Xcode. To return the project window to its normal state, choose Standard Windowing from the Debugging pop-up menu in the window toolbar (or click Stop in the toolbar to kill the running app). Start over, or abort To kill the running app, click Stop in the toolbar (Product → Stop, CommandPeriod). To kill the running app and relaunch it without rebuilding it, Control-click Run in the toolbar (Product → Perform Action → Run Without Building, ControlCommand-R). You can make changes to your code while the app is running or paused, but those changes are not magically communicated to the running app; there are languages and programming milieus where that sort of thing is possible, but Xcode and Objective-C are not among them. You must stop the app and run in the normal way (which includes building) to see your changes in action. Clicking the Home button in the Simulator or on the device does not stop the running app in the multitasking world of iOS 4 and later. Debugging | 207 Unit Testing Another way of verifying the correctness of your code is through unit tests. A unit test is basically a suite of methods that call methods of your app’s code and use asserts to describe what should happen. Typically, unit tests are constructed so as to confirm not only that the app behaves as expected under normal conditions, but also that incorrect or extreme inputs are handled properly. There’s even a school of thought that suggests you should write unit tests before writing the real code. The easiest way to attach unit tests to your app is at the time you create the project: in the second dialog, check Include Unit Tests. Xcode endows your project with a secon‐ dary target, which is a Unit Testing Bundle consisting of the test code and linked to the SenTestingKit framework. The unit testing target has a dependency on the normal target; thus, if you build the normal target, you build your app normally, but if you build the unit testing target, you build your app along with the unit testing bundle. To run unit tests against your app, you choose Product → Test. The project’s scheme specifies that this means to build the unit testing target, and lists the test methods that are to be run; to specify particular test methods, edit the scheme. You can subsequently add another Unit Testing Bundle target to your project if you like. When you do, an additional scheme is created. So, to run the tests in an added unit testing target, you’d change the scheme selection in the Scheme pop-up menu to specify that target, and choose Product → Test. However, adding such targets may require fur‐ ther work on your part: you might have to set up the necessary target dependency, edit the scheme, and adjust the target membership of your app’s class files. The details can be tricky: see Setting Up Application Unit Tests in Apple’s Xcode Unit Testing Guide. For more information about unit testing, see Apple’s Xcode Unit Testing Guide. The appendix to that document lists the SenTestingKit assert functions (actually macros) that you can use. Static Analyzer From time to time, you should use the static analyzer to look for possible sources of error in your code; choose Product → Analyze (Shift-Command-B). This command causes your code to be compiled, and the static analyzer studies it and reports its findings in the Issue navigator and in your code. The static analyzer is static (it’s analyzing your code, not debugging in real time), but it is remarkably intelligent and may well alert you to potential problems that could other‐ wise escape your notice. You might think that the compiler — including ARC, if you’re using it — knows all there is to know about your code; and it is certainly true that one of the main reasons for using the static analyzer, namely, to assist with manual memory management of Objective-C instances, is essentially gone if you’re using ARC. Still, the 208 | Chapter 9: Life Cycle of a Project static analyzer actually studies the possible values and paths of execution in your code, and can detect potential sources of trouble in your program’s logic that no mere compiler would worry about. For example, in this code, the static analyzer knows that i in the second line is uninitialized: int i; if (i) NSLog(@"here"); In this code, the static analyzer knows that the second line throws away the existing value of i without that value ever having been read: int i=0; i=1; Those are tiny problems, but they illustrate how, in a complex program, the static ana‐ lyzer is capable of noticing possible sources of trouble and bringing them to your at‐ tention. For more about the static analyzer, see http://clang-analyzer.llvm.org. Clean From time to time, during repeated testing and debugging, and before making a dif‐ ferent sort of build (switching from Debug to Release, or running on a device instead of the Simulator), it is a good idea to clean your target. This means that existing builds will be removed and caches will be cleared, so that all code will be considered to be in need of compilation and the next build will build your app from scratch. The first build of your app after you clean will take longer than usual. But it’s worth it, because cleaning removes the cruft, quite literally. For example, suppose you have been including a certain resource in your app, and you decide it is no longer needed. You can remove it from the Copy Bundle Resources build phase (or from your project as a whole), but that doesn’t remove it from your built app. Only cleaning will do that, be‐ cause it removes the built app completely. To clean, choose Product → Clean. For more complete cleaning, hold Option to get Product → Clean Build Folder. In addition, Xcode stores builds and project indexes in ~/Library/Developer/Xcode/ DerivedData. From time to time, with Xcode not running, I like to move the contents of that folder to the trash. This is effectively a massive and even more complete clean of every project that you’ve opened recently. Alternatively, to trash the folder in Derived‐ Data for a single project from within Xcode, switch to the Projects tab of the Organizer window (Window → Organizer), select the project at the left, and click the Delete button next to the Derived Data listing at the top of the window. A project will take longer to open for the first time afterward, because its index must be rebuilt, and it will take longer to build, because its build information has been removed. But the space savings on your hard disk can be significant, and forcing the index to rebuild itself can actually ward off certain problems. Clean | 209 You should also from time to time remove all versions of your built app from the Sim‐ ulator cache. Choose iOS Simulator → Reset Content and Settings. Alternatively, you can clean the Simulator cache by hand. To do so, first quit the Simulator if it’s running. Then find the cache in ~/Library/Application Support/iPhone Simulator, followed by the system version of the SDK (for example, there might be a folder called 6.1); within this, find the Applications folder, and move the contents of that folder to the trash. If there are multiple system version folders here, you might want to jettison the contents of the Applications folders of all of them. Running in the Simulator When you build and run with the Simulator as the destination, you run in the iOS Simulator application. The Simulator window represents a device. If your app runs on either iPhone or iPad (natively or in the iPhone emulator), you can choose which device is simulated as you choose your destination; similarly, if your app runs on multiple system versions, you can choose the system version of the simulated device as you choose your destination. (See Chapter 6 on destinations, and the first section of this chapter on device architectures and the Deployment Target build setting.) You can also switch device types by choosing Hardware → Device in the Simulator. This quits your app running in the Simulator; you can relaunch it by building and running in Xcode again, or by clicking your app’s icon in the Simulator. In the latter case there is no longer any connection to Xcode (you aren’t using the debugger, so you won’t stop at breakpoints, and log messages won’t be relayed to the Xcode console); still, you might do this just to check quickly on how your app looks or behaves on a different device. The one key choice you can make using Hardware → Device in the Simulator that you can’t make by choosing a destination in Xcode is between iPad and iPad (Retina), or between iPhone, iPhone (Retina 3.5-inch), and iPhone (Retina 4-inch): • The Retina display is a double-resolution screen, so it can be displayed at double size, with each pixel of the Retina display corresponding to a pixel of your com‐ puter’s monitor. • The Retina 4-inch display is the size of the iPhone 5 and 5th-generation iPod touch screen, as opposed to the Retina 3.5-inch screen, which is the size of the iPhone 4 and 4S, as well as the 4th-generation iPod touch. The Retina 3.5-inch screen is the double-resolution version of the screens of all earlier single-resolution iPhones and iPod touches. Changing this setting quits your app running in the Simulator, but your choice will stick if you return to Xcode and build and run on iPhone again. The Simulator window can be displayed at half, three-quarter, or full size (choose from Window → Scale). This is a matter of display merely, comparable to zooming the win‐ 210 | Chapter 9: Life Cycle of a Project dow, so your app running in the Simulator does not quit when you change this setting. For example, you might run a Retina device in the Simulator at full size to see every double-resolution pixel, or at half size to save space. You can interact with the Simulator in some of the same basic ways as you would a device. Using the mouse, you can tap on the device’s screen; hold Option to make the mouse represent two fingers and Option-Shift to move those fingers in parallel. Some Simulator representations display a Home button, which you click with the mouse, but the most reliable way to click the Home button is to choose Hardware → Home (ShiftCommand-H). Menu items also let you perform hardware gestures such as rotating the device, shaking it, and locking its screen; you can also test your app by simulating certain rare events, such as a low-memory situation (and this is a useful thing to do from time to time; I’ll talk more about it in Chapter 19). The Debug menu in the Simulator is useful for detecting problems with animations and drawing. You can choose from this menu while your app is running in the Simulator, without causing the app to quit. Toggle Slow Animations is unique to the Simulator; it makes animations unfold in slow motion so that you can see just what’s happening (animation is discussed in Chapter 17). The other four menu items represent features that were previously available only when running on a device using Instruments (men‐ tioned later in this chapter), under the Core Animation instrument; now they are rolled directly into the Simulator as well. I’ll return to the specifics of what these menu items do when discussing drawing (Chapter 15) and layers (Chapter 16); but here’s an example you can try immediately. Return to the Empty Window project developed in Chapter 7. In AppDelegate.m, we are pulling a label out of a nib and putting it into our interface by setting its center, like this: [self.window.rootViewController.view addSubview: lab]; lab.center = CGPointMake(100,100); lab.frame = CGRectIntegral(lab.frame); If you comment out that last line, run the project in the Simulator with the device set to iPhone — not iPhone (Retina) — and toggle on Debug → Color Misaligned Images, you may see the label painted with a magenta overlay. That’s because, without the call to CGRectIntegral, the label is misaligned; by default, the label is 21 points high, which is an odd number, so setting its center to an integral point value has caused its vertical position to be halfway between two integer pixel values on the device. The effect of this misalignment is actually visible to the naked eye if you know what to look for: the text looks fuzzy or bold. Using Debug → Color Misaligned Images alerts you to the issue; calling CGRectIntegral fixes it. The Debug menu also contains some items that are useful when you’re testing an app that uses Core Location (discussed in Chapter 35). Running in the Simulator | 211 Running on a Device Sooner or later, you’re going to want to switch from running and testing and debugging in the Simulator to running and testing and debugging on a real device. The Simulator is nice, but it’s only a simulation; there are many differences between the Simulator and a real device. The Simulator is really your computer, which is fast and has lots of memory, so problems with memory management and speed won’t be exposed until you run on a device. User interaction with the Simulator is limited to what can be done with a mouse: you can click, you can drag, you can hold Option to simulate use of two fingers, but more elaborate gestures can be performed only on an actual device. And many iOS facilities, such as the accelerometer and access to the music library, are not present on the Simulator at all, so that testing an app that uses them is possible only on a device. Don’t even think of developing an app without testing it on a device. You have no idea how your app really looks and behaves until you run it on a device. Submitting to the App Store an app that you have not run on a device is asking for trouble. Before you can run your app on a device, even just to test, you must join the iOS De‐ veloper Program by paying the annual fee. (Yes, this is infuriating. Now get over it.) Only in this way can you obtain and provide to Xcode the credentials for running on a device. Once you have joined the iOS Developer Program, obtaining these credentials involves use of the iOS Provisioning Portal, which is accessed online, through your web browser (or, for certain actions, through Xcode itself). To reach the iOS Provisioning Portal in your browser (once you’re an iOS Developer Program member), go to http://developer.apple.com/ devcenter/ios. Click Log In to log in, and then click iOS Provisioning Portal at the upper right. You will need to perform the following initial steps once: 1. Join the iOS Developer Program (http://developer.apple.com/programs/ios). This requires filling out a form and paying the annual fee. Unless you have multiple developers, all of whom might need to build and run on their own devices, the Individual program is sufficient. The Company program costs no more, but adds the ability to privilege additional developers in various roles. (You do not need the Company program just in order to distribute your built app to other users for test‐ ing.) 2. Obtain a development certificate that identifies and authorizes your computer. This is the computer to which you’ll be attaching the device so you can run on it. Basically, 212 | Chapter 9: Life Cycle of a Project this certificate matches the person who uses your computer to the person interact‐ ing with the iOS Provisioning Portal. The certificate will be stored in your com‐ puter’s keychain, where Xcode will be able to see it automatically. The certificate depends upon a private–public key pair. The private key will live in your keychain; the public key will be handed over to the iOS Provisioning Portal, to be built into the certificate. The way you give the Portal your public key is through a request for the certificate. So, you generate the private–public key pair; your keychain keeps the private key; the public key goes into the certificate request; you submit the request, containing the public key, to the Portal; and the Portal sends back the certificate, also containing the public key, which also goes into your keychain, where it is matched with the private key, thus ensuring that you are you. Detailed instructions for generating the private–public key pair and the certificate re‐ quest are available once you’ve joined the iOS Developer Program and have logged in at Apple’s developer site. (The process is described at http://developer.apple.com/ios/ manage/certificates/team/howto.action. A video review of the steps involved is available to anyone at http://developer.apple.com/ios/videos/popupcerts.action.) Basically, you start up Keychain Access and choose Keychain Access → Certificate Assistant → Request a Certificate from a Certificate Authority. Using your name and email address as iden‐ tifiers, you generate and save to disk a 2048-bit RSA certificate request file. Your private key is stored in your keychain then and there; the certificate request contains your public key. You then go to the iOS Provisioning Portal in your browser. At the Portal, upload the certificate request file using the Development (not Distribution!) tab of the Certificates section. You may have to approve your own request, and you may have to refresh that web page to see the Download button. If this is your very, very first time obtaining any certificate from the Portal, you will need another certificate: the WWDR Intermediate Cer‐ tificate. This is the certificate that certifies that certificates issued by WWDR (the Apple Worldwide Developer Relations Certification Au‐ thority) are to be trusted. (You can’t make this stuff up.) You’ll see a link for this intermediate certificate; click it to download the intermediate certificate. Double-click the intermediate certificate file; it is imported by your keychain. You can then throw the file away. When the development certificate itself is ready, you download it and double-click it; Keychain Access automatically imports the certificate and stores it in your keychain. You do not need to keep the certificate request file or the development certificate file; your keychain now contains all the needed credentials. If this has worked, you can see Running on a Device | 213 Figure 9-7. A valid development certificate, as shown in Keychain Access the certificate in your keychain, read its details, and observe that it is valid and linked to your private key (Figure 9-7). With your development certificate in place, you need to register a device for develop‐ ment use, meaning that you’ll be able to build and run from Xcode onto that device rather than the Simulator. This can be done entirely from within Xcode. Open the Or‐ ganizer window (Window → Organizer) and switch to the Devices tab. Select Provi‐ sioning Profiles under Library at the left, and make sure Automatic Device Provisioning is checked at the bottom of the window. Attach your device to the computer; the device name appears at the left under Devices. Select it, and click Use For Development. You’ll be asked for your Portal username and password. Xcode connects to the Portal via the Internet and does two things: • It registers your device at the Portal by its name and unique identifier number. You could have done this yourself in your browser (at the Portal, under Devices), but this way it is done for you. • It creates and downloads from the Portal a universal development provisioning profile (referred to as a team provisioning profile) for development on this device. This is something you can’t do at the Portal yourself. A development provisioning profile created manually at the Portal applies to a single app; in the past, when the Portal was the only way to obtain a development provisioning profile, you had to generate a new development provisioning profile for each app you wanted to test on a device, which was very inconvenient. But the team provisioning profile gen‐ erated by Xcode applies to all apps. The team provisioning profile appears in the Organizer, under Provisioning Profiles; you can identify it because it is called iOS 214 | Chapter 9: Life Cycle of a Project Team Provisioning Profile and has an app identifier consisting of just a key and an asterisk, like this: B398E68A3D.*. If your device is already registered at the Portal but Use For Development doesn’t appear in Xcode and you’ve no team provisioning profile, go back to Provisioning Profiles under Library and click Refresh at the bottom right of the window. The team provi‐ sioning profile will be regenerated. If you later add further devices for development (Use for Development) and you already have a team provisioning profile, they will be added to it automatically, within Xcode. If you develop an app that uses certain specialized features, such as push notifications (Chapter 37), iCloud (Chapter 36), or in-app purchases, you must generate a development provisioning profile the old way, manually at the Portal, in order to obtain the necessary entitlements. To do so, first enter your app by name and bundle id in the App IDs section of the Portal. Now go to Provisioning and the Development section and generate a new provisioning profile, specifying that app and your device(s). You can then download the provisioning profile in the Organizer window, under Provisioning Profiles, by clicking the Refresh button. You now have a development provisioning profile in Xcode (the team provisioning profile). You can install this provisioning profile onto your device manually in the Or‐ ganizer window by dragging its listing (under Provisioning Profiles) onto the device’s name (under Devices) when the device is connected. Alternatively, you can just start building and running on the device. Start with a project window. With the device at‐ tached to the computer, pick the destination in the Scheme pop-up menu corresponding to your device; then build and run. If Xcode complains that your device doesn’t contain a copy of the provisioning profile, and offers to install it for you, accept that offer. The app is built, loaded onto your device, and runs. As long as you launch the app from Xcode, everything is just as when running in the Simulator: you can run, or you can debug, and the running app is in communication with Xcode, so that you can stop at breakpoints, read messages in the console, and so on. The outward difference is that to interact physically with the app, you use the device (attached to your computer), not the Simulator. Profile and Device Management Your central location for surveying provisioning profiles, identities (certificates) and devices is the Devices tab of the Organizer window (Window → Organizer). Under Profile and Device Management | 215 Library, select Provisioning Profiles for a list of profiles. Under Teams, you’ll see a list of your developer identities and their associated certificates. As someone with more than one computer, I find the coolest feature of this interface to be the Export button at the bottom of the window. When you click it, you’re asked for a password (twice), which can be anything you like; it outputs a .developerprofile file. On another computer, run Xcode and double-click that .developerprofile file in the Finder. Xcode asks for a password. Enter the same password you gave previously, and like magic the entire suite of teams and identities and certificates and provisioning profiles springs to life in that other copy of Xcode, including the entries in your keychain. When a device is attached to the computer, it is listed with a green dot under Devices. Click its name to access information on the device. You can see the device’s unique identifier. You can see provisioning profiles that have been installed on the device. You can view the device’s console log in real time, just as if you were running the Console application to view your computer’s logs. You can see log reports for crashes that took place on the device. And you can take screenshots that image your device’s screen; you’ll need to do this for your app when you submit it to the App Store. Device logs and screenshots are also available under Library. Version Control Various systems of version control exist for taking periodic snapshots (technically called commits) of your project. The value of such a system to you will depend on what system you use and how you use it; for example, you might use version control because it lets you store your commits in a repository offsite, so that your code isn’t lost in case of a local computer glitch or some equivalent “hit by a bus” scenario, or because it allows multiple developers to access the same code. To me, personally, the chief value of version control is freedom from fear. Having version control actually changes the way I program. A project is a complicated thing, consisting of numerous files. Often, changes must be made in many files before a new feature can be tested. Thus it is all too easy to start down some virtual road involving creating or editing multiple files, only to find yourself at the end of a blind alley and needing to retrace your steps. Version control means that I can easily retrace my steps; I have but to say, in the language of some version control system I’ve been using, “Forget everything I just did and return the whole project to where it was at such-and-such a commit.” I rarely, if ever, in fact retrace my steps, but the knowledge that I could do so gives me the courage to try some programming strategy whose outcome may not be apparent until after many days of effort. Also, I can ask a version control system, “What the heck are all the changes I’ve made since the last commit?” In short, without version control I’d be lost, confused, hesitant, rooted to the spot, paralyzed with uncertainty; with it, I forge boldly ahead and get things done. For this reason, my current personal favorite version 216 | Chapter 9: Life Cycle of a Project Figure 9-8. Version comparison control system is git (http://git-scm.com), whose agile facilities for managing branches give me tremendous license to experiment. Xcode provides various version control facilities. Starting with Xcode 4, those facilities concentrate on git and Subversion (http://subversion.apache.org). This doesn’t mean you can’t use any other version control system with your projects! It means only that you can’t use any other version control system in an integrated fashion from inside Xcode. Personally, I don’t find that to be any kind of restriction. For years I’ve used Subversion, and more recently git, on my Xcode projects from the command line in Terminal, or through specialized third-party GUI front ends such as svnX for Subver‐ sion (http://www.lachoseinteractive.net/en/products) or SourceTree for git (http:// www.sourcetreeapp.com). I’m comfortable and nimble at the command line, and access to version control from within Xcode itself is not a priority for me. At the same time, version control integration in Xcode 4 is greatly improved and far more extensive than previously: Automatic git repository creation When you create a new project, the Save dialog includes a checkbox that offers to place a git repository into your project folder from the outset. Automatic repository detection When you open an existing project, if that project is already managed with Sub‐ version or git, Xcode detects this and is ready instantly to display version control information in its interface. Version comparison The Version editor (View → Version Editor → Show Version Editor, or click the third button in the Editor segmented control in the project window toolbar) in‐ cludes a view similar to that of the File Merge utility, graphically displaying the differences between versions of a file. For example, in Figure 9-8, I can see that in the more recent version of this file (on the left) I’ve changed representativeItem to items[0]. The Version editor also includes various ways to survey and navigate versions and commit logs. For example, if I switch to Blame view I can see my own commit message explaining the change I just mentioned: “Stop using representativeItem, in order to avoid nasty log messages (reported to Apple).” Version Control | 217 Without minimizing these features, I don’t rely on them exclusively or even primarily (although I certainly take advantage of them where convenient). I find version control management through the command line far easier and clearer for many purposes, and Xcode doesn’t come close to the command line’s power, especially for managing branch‐ es; Xcode has nothing like the visual branch representation of git’s own gitk tool; and Xcode’s repository management in the Organizer window is downright crude. In ad‐ dition, as of this writing, Xcode’s git integration is fundamentally flawed: if I create a new file in a git-controlled project, Xcode adds it to the staging area (the git index) rather than letting me compose the commit in my own way, so that I typically have to switch to the command line and say git reset to fend off Xcode’s interference. Version control in general is a large and complicated topic. Use and configuration of any version control system can be tricky and scary at first and always requires some care. So I’m deliberately not going to say anything specific about it; I’m mentioning it at all only because version control of some sort is in fact likely, sooner or later, to play a role in the life cycle of your projects. When it does, you’ll want to read up on the use of your chosen version control system, along with “Save and Revert Changes to Projects” in the Xcode 4 User Guide. You’ll find Xcode’s integrated version control facilities in three chief locations: The File menu The relevant menu items are all under File → Source Control. The most frequently used commands are Add and Commit on the one hand, and Discard Changes on the other. You can go a very long way with elementary use of git through just those three menu items. The Version editor Choose View → Version Editor → Show Version Editor, or click the third button in the Editor segmented control in the project window toolbar. The Organizer The Repositories tab of the Organizer window lists known repositories and branch‐ es for each project, along with their commit logs. Also, use the Plus button at the bottom of the navigator to enter data about a remote repository, so that you can obtain a copy of its contents. Xcode also contains its own way of taking and storing a snapshot of your project as a whole; this is done using File → Create Snapshot (and, according to your settings, some mass operations such as find-and-replace or refactoring may offer to take a snapshot first). Snapshots themselves are managed in the Projects tab of the Organizer window. Although these snapshots are not to be treated as full-fledged version control, they are in fact maintained as git repositories, and can certainly serve the purpose of giving confidence in advance of performing some change that might subsequently engender regret. You can manage snapshots in the Projects tab of the Organizer window; here you export a snapshot, thus resurrecting an earlier state of your project folder. 218 | Chapter 9: Life Cycle of a Project Instruments As your app approaches completion, you may wish to fine-tune it for memory usage, speed, and other real-time behavior. Xcode provides a sophisticated and powerful utility application, Instruments, that lets you collect profiling data on your app as it runs. The graphical display and detailed data provided by Instruments may give you the clues you need to optimize your app. You can use Instruments on the Simulator or the device. The device is where you’ll do your ultimate testing, and certain instruments (such as Core Animation) are available only for the device; on the other hand, certain other instruments (such as Zombies) are available only in the Simulator. To get started with Instruments, set the desired destination in the Scheme pop-up menu in the project window toolbar, and choose Product → Profile. (For memory usage, your destination can be the Simulator, but for most other forms of analysis, you’ll want to run on a device to achieve maximum verisimilitude.) Your app builds using the Profile action for your scheme; by default, this uses the Release build configuration, which is probably what you want. If you’re running on a device, you may see some some vali‐ dation warnings, but you can safely ignore them. Instruments launches; if your scheme’s Instrument pop-up menu for the Profile action is set to Ask on Launch (the default), Instruments presents a dialog where you choose a trace template. If you’re running on the Simulator, you might have to pass through an authorization dialog the first time you use Instruments. With Instruments running, you should interact with your app like a user; Instruments will record its statistics. Once Instruments is running, it can be further customized to profile the kind of data that particularly interests you, and you can save the structure of the Instruments window as a custom template. Use of Instruments is an advanced topic and beyond the scope of this book. Indeed, an entire book could (and really should) be written about Instruments alone. For proper information, you should read Apple’s documents, especially the Instruments User Ref‐ erence and Instruments User Guide. Also, many WWDC videos from current and prior years are about Instruments; look for sessions with “Instruments” or “Performance” in their names. Here, I’ll just demonstrate, without much explanation, the sort of thing Instruments can do. I’ll start by charting the memory usage of my TidBITS News app as it starts up and the user proceeds to work with it. Memory is a scarce resource on a mobile device, so it’s important to be certain that we’re not hogging too much of it. I’ll set the destination to the Simulator and choose Product → Profile; Instruments launches, and I’ll choose the Allocations trace template and click Profile. My app starts running in the Simulator, and I work with it for a while and then pause Instruments, which meanwhile has charted my memory usage (Figure 9-9). Examining the chart, I find there are a couple of spikes early on, first as the app launches and then as the app downloads and parses an RSS Instruments | 219 Figure 9-9. Instruments graphs memory usage over time Figure 9-10. Instruments describes a leak feed; but it’s only 5.40 MB at its maximum, and the app settles down to use slightly over 2 MB pretty steadily thereafter. These are very gentle memory usage figures, so I’m happy. Another field of Instruments expertise is the ability to detect memory leaks. Memory leaks, discussed further in Chapter 12, remain possible even under ARC. In this trivial example, I have two classes, MyClass1 and MyClass2; MyClass1 has an ivar property which is a MyClass2 instance, and MyClass2 has an ivar property which is a MyClass1 instance. The app runs this code: MyClass1* MyClass2* m1.ivar = m2.ivar = m1 = [MyClass1 new]; m2 = [MyClass2 new]; m2; m1; There are steps I could have taken to prevent this from being a memory leak, as I’ll explain in Chapter 12; but I haven’t taken those steps, so it is a memory leak. I’ll set the destination to the Simulator and choose Product → Profile; Instruments launches, and I’ll choose the Leaks trace template and click Profile. My app starts running in the Simulator, and after about 10 seconds (the default interval at which Instruments runs its leak analysis), a leak is detected. After some appropriate button-pushing, I’m actually shown a diagram of the mistake that’s causing this leak (Figure 9-10)! 220 | Chapter 9: Life Cycle of a Project Figure 9-11. A time profile in Instruments In this final example, I’m concerned with what’s taking my Albumen app so long to switch from master view to detail view. I’ll set the destination to a device, because that’s where speed matters and needs to be measured, and choose Product → Profile; Instru‐ ments launches, and I’ll choose the Time Profiler trace template and click Profile. The master view appears; I’ll tap a cell in the table view, and after a significant delay, the detail view appears. Now I’ll pause Instruments and look at what it’s telling me. As we can see from Figure 9-11, this transition is taking nearly three seconds. Opening the triangles in the lower portion of the window, it turns out that much of this is spent in something described as CA::Layer::layout_and_display_if_needed. That’s not my code; it’s deep inside Cocoa. But by clicking the little arrow that appears to the right of that line when I hover the mouse over it, I can see the call stack and discover how my code is involved in this call (Figure 9-12). One line of my code is involved in this call: tableView:heightForRowAtIndexPath:. This is where we work out the heights of the table view cells to be shown in the detail view. By double-clicking the listing of that line, I can see my own code, time-profiled (Figure 9-13). This is really useful information. It’s also fairly depressing. The bulk of the time is being spent in Cocoa’s systemLayoutSizeFittingSize:. That call is how I calculate the height Instruments | 221 Figure 9-12. Drilling down into the time profile Figure 9-13. My code, time-profiled of the table view cell using iOS 6’s new autolayout feature (Chapter 21). This approach is working perfectly, but clearly it is relatively expensive. 222 | Chapter 9: Life Cycle of a Project It is a programming proverb that one should not optimize prematurely; equally, one should not spend time optimizing when the resulting savings will make no perceptible difference to the user. I know how I used to calculate the table view cell height before iOS 6; it was much less elegant, but it was faster — and I can prove this quantitatively through further measurement, analysis, and experimentation. That’s exactly the value of Instruments: for guesswork and impressions, it substitutes actual numbers and facts. Unfortunately, Instruments can’t tell me how to make the trade-off between the in‐ creased speed of the old approach and the greater elegance and reliability of the new approach. Distribution By distribution is meant providing your app to others who are not developers on your team. There are two kinds of distribution: Ad Hoc distribution You are providing a copy of your app to a limited set of known users so that they can try it on their devices and report bugs, make suggestions, and so forth. App Store distribution You are providing the app to the App Store so that anyone can download it (possibly for a fee) and run it. The Portal imposes a registration limit of 100 devices per year per de‐ veloper (not per app), which limits your number of Ad Hoc testers. Your own devices used for development are counted against this limit. To perform any kind of distribution, you will need a distribution certificate, which is different from the development certificate discussed earlier in this chapter. Like the development certificate, you need only one distribution certificate; it identifies you as you. Obtaining a distribution certificate is exactly like obtaining a development certif‐ icate, except that, at the iOS Provisioning Portal, under Certificates, you use the Dis‐ tribution tab instead of the Development tab. You will also need a distribution profile specifically for this app, which is different from the development profile you obtained earlier. You can’t obtain a distribution profile from within Xcode; you must get it at the Portal in your browser. You might need two distri‐ bution profiles, because the profile for an Ad Hoc distribution is different from the profile for an App Store distribution. Remember, you will need a separate set of distri‐ bution profiles for each app you plan to distribute. When you build for distribution, you’ll use the Product → Archive command. Indeed, you can think of archive as meaning “build for distribution.” However, you have some preparation to do before you can archive in such a way as to make an app you can actually Distribution | 223 distribute. If you look at the Archive action in your default scheme, you’ll discover that it is set to use the Release distribution configuration. But if you examine the Code Signing Identity build setting for your project, you’ll see that by default it uses a devel‐ opment profile (most likely the team development profile). This won’t do; when you intend to distribute a copy of your app, you want to use a distribution profile. The solution I recommend is to create a third build configuration called Distribution; you can then set the Archive action in your scheme to use the Distribution build configu‐ ration, and set the Code Signing Identity build setting to use the distribution profile when the Distribution build configuration is in force. First, here are the steps for obtaining a distribution profile: 1. To obtain an Ad Hoc distribution profile, collect the unique identifiers of all the devices where this build is to run, and add each of the device identifiers at the Portal under Devices. (For an App Store profile, omit this step.) 2. In the Portal, in the Distribution (not Development!) tab of the Provisioning sec‐ tion, ask for a New Profile. In the New Profile form, ask for an Ad Hoc profile or an App Store profile, depending on which you’re after. 3. Describe the profile, giving it a name, and specifying your distribution certificate and this app. For an Ad Hoc profile, also specify all the devices you want the app to run on. Be careful about the profile’s name, as you will need to be able to identify it later from within Xcode! My own practice is to assign a name containing both the name of the app and the term “adhoc” or “appstore”. 4. Click Submit to generate the profile; you might then have to refresh the browser window to see the Download button next to your new profile. Download the profile and drag it onto Xcode’s icon in the Dock. You can now throw the profile away in the Finder; Xcode has kept a copy (which should appear in the Organizer window). Now here are the steps to create and use a Distribution build configuration for your project: 1. Edit the project. In the Info tab, click the Plus button below the list of configurations, and duplicate the Release configuration. Name the new configuration Distribution. 2. Edit the project (still). In the Build Settings tab, locate the Code Signing Identity entry. The Distribution build setting is now listed here, with a subentry Any iOS SDK. Set the value of this subentry to the appropriate distribution profile for this app. 3. Edit the scheme, and switch to the Archive action. Change the build configuration to Distribution, and click OK. 224 | Chapter 9: Life Cycle of a Project The result is that from now on, when you choose Build → Archive, you’ll use a distri‐ bution profile associated with this app. That means you’ll be able to distribute the ar‐ chived app. Ad Hoc Distribution To create and distribute an Ad Hoc distribution build, first switch to the iOS Device destination in the Scheme pop-up menu in the project window toolbar. Until you do this, the Product → Archive menu item will be disabled. You do not have to have a device connected; you are not building to run on a particular device, but to save an archive. Apple’s docs say that an Ad Hoc distribution build should include an icon that will appear in iTunes, but my experience is that this step is unnecessary. If you want to include this icon, it should be a PNG or JPEG file, 512×512 pixels in size, and its name should be iTunesArtwork, with no file extension. Make sure the icon is included in the build, being present in the Copy Bundle Resources build phase. Now choose Product → Archive. The build is created and copied into a date folder within ~/Library/Developer/Xcode/Archives; it also appears in the Organizer window in the Archives tab. Locate the archive in the Organizer window. You can add a comment here; you can also change the archive’s name (this won’t affect the name of the app). If Xcode refuses to build because of a Code Sign error, it may help to close the project window and delete this project’s entire build folder from the DerivedData directory, as described earlier in this chapter. When you reopen the project, after Xcode has finished reindexing it, check the build settings for your Distribution configuration; it may help to set once again the value of Any iOS SDK for the Distribution con‐ figuration under Code Signing Identity. See also Apple’s tech note TN2250, “Understanding and Resolving Code Signing Issues.” Select the archive and press the Distribute button at the upper right of the window. A dialog appears. Here, you are to specify a procedure; choose Save for Enterprise or AdHoc Deployment. You are now asked to choose a code signing identity; specify the identity associated with the Ad Hoc distribution profile for this app. Click Next. After a while, a Save dialog appears. Give the file a useful name; this won’t affect the name of the app. Save the file to disk. It will have the suffix .ipa (“iPhone app”). Locate in the Finder the file you just saved. Provide this file to your users with instruc‐ tions. A user should copy the .ipa file to a safe location, such as the Desktop, and then launch iTunes and drag the .ipa file from the Finder onto the iTunes icon in the Dock. Then the user should connect the device to the computer, make certain the app is present and checked in the list of apps for this device, and sync the device to cause the app to be Ad Hoc Distribution | 225 copied to it. (If this isn’t the first version of your app that you’ve distributed to your ad hoc testers, the user might need to delete the current version from the device beforehand; otherwise, the new version might not be copied to the device when syncing.) If you listed your own device as one of the devices for which this Ad Hoc distribution profile was to be enabled, you can obey these instructions yourself to make sure the Ad Hoc distribution is working as expected. First, remove from your device any previous copies of this app (such as development copies) and any profiles that might be associated with this app (in the Settings app, under General → Profiles). Then copy the app onto your device by syncing with iTunes as just described. The app should run on your device, and you should see the Ad Hoc distribution profile on your device (in the Settings app). Because you are not privileged over your other Ad Hoc testers, what works for you should work for them. Final App Preparations As the big day approaches when you’re thinking of submitting your app to the App Store, don’t let the prospect of huge fame or massive profits hasten you past the allimportant final stages of app preparation. Apple has a lot of requirements for your app, such as icons and launch images, and failure to meet them can cause your app to be rejected. Take your time. Make a checklist and go through it carefully. See the iOS Ap‐ plication Programming Guide for full details. At various stages, you can obtain validation of your app to confirm that you haven’t omitted certain requirements. For example, by default, a new project’s Release build configuration has the Validate Build Product build setting set to Yes. Thus, when I do a build of the Empty Window app we’ve developed in previous chapters, if that build uses the Release build configuration (or the Distribution build configuration duplicated from it), Xcode warns that the app has no icon. When you submit your app to the App Store, it will be subjected to even more rigorous validation. Icons in the App An icon file must be a PNG file, without alpha transparency. It should be a full square, without shading (the “shine” effect that you see in the upper part of icons on your device); the rounding of the corners and shine will be added for you. You can prevent the shine effect from being added to the icon for your App Store build by defining and checking the “Icon already includes gloss and bevel effects” key (UIPrerenderedIcon) in your Info.plist. On a device, the system uses the “Icon files” key in your app’s Info.plist file to locate your icons, and it decides which icon to use under what circumstances by examining their sizes. Therefore, these sizes must be exactly correct. The required sizes for current sys‐ tems and devices are as follows: 226 | Chapter 9: Life Cycle of a Project • For an iPhone app, there should be two primary app icons, one 57×57 pixels, the other 114×114 pixels (for use on the double-resolution Retina display). • For an iPad app, there should be two primary app icons, one 72×72 pixels, the other 144×144 pixels (for use on the double-resolution Retina display). A double-resolution variant of an icon should have the same name as the singleresolution variant, except for the addition of @2x to its name. A universal app will need all four icons. To add your icons, edit the target and drag-and-drop each icon into the appropriate space in the Summary tab. Xcode will incorporate the icons into the project and the target and configure your Info.plist for you. For example, if I drop a 57×57 PNG file called myDumbIcon.png onto the first iPhone icon space, it is copied into the project and added to the target. In my Info.plist, the result is a structure as follows: Icon files (iOS 5) Primary Icon Icon files Item 0 (Dictionary) (Dictionary) (Array) myDumbIcon.png Other icons can be added to the “Icon files” array. (The reason for this rather convoluted structure is so that Newsstand apps can include a separate Newsstand icon.) Alterna‐ tively, you can specify the icon file(s) manually. You will then have to take upon yourself the responsibility for making sure that each icon file is part of the target and the Copy Bundle Resources build phase, and you’ll have to edit Info.plist yourself. Optionally, you may elect to include smaller versions of your icon to appear when the user does a search on the device, as well as in the Settings app, if you include a settings bundle (Chapter 36). The smaller icon sizes are 29×29 (and 58×58 pixels for its doubleresolution partner) for iPhone search results and the Settings bundle, and 50×50 (and 100×100 for its double-resolution partner) for iPad search results. Follow the instruc‐ tions in the previous paragraph for specifying these icon files manually. However, I never include these icons, and no ill consequences have accrued. The difficulty of getting the required icon sizes right is greatly increased by the proliferation of outdated information throughout Apple’s own documentation. The “App-Related Resources” chapter of the iOS App Programming Guide appears to be the best source of information at the moment. See also “Custom Icon and Image Creation Guidelines” in Apple’s iOS Human Interface Guidelines. Other Icons When you submit the app to the App Store, you will be asked to supply a 1024×1024 PNG, JPEG, or TIFF icon to be displayed at the App Store. Have this icon ready before Final App Preparations | 227 submission. Apple’s guidelines say that it should not merely be a scaled-up version of your app’s icon, but it must not differ perceptibly from your app’s icon, either, or your app will be rejected (I know this from experience). The App Store icon does not need to be built into your app; indeed, it should not be, as it will merely swell the built app’s size unnecessarily (remember that space is at a pre‐ mium on a device, and that your app must be downloaded from the App Store, so users appreciate your keeping your app as small as possible). On the other hand, you will probably want to keep it in your project (and in your project folder) so that you can find and maintain it easily. So I recommend that you import it into your project and copy it into your project folder, but do not add it to any target. If you created a 512×512 icon file for Ad Hoc distribution, you may wish to delete it from the Copy Bundle Resources build phase now so that it doesn’t swell the final app’s size unnecessarily. Launch Images There is a delay between the moment when the user taps your app’s icon to launch it and the moment when your app is up and running and displaying its initial window. To cover this delay and give the user the sense that something is happening, you must provide a launch image to be displayed during that interval. The launch image might be just a blank depiction of the main elements or regions of the app’s interface, so that when the actual window appears, those elements or regions will seem to be filled in. The best way to create such a launch image is to start with a screenshot of your app’s actual initial interface. That way, all you have to do is blank out the details. Typically, I add some temporary code to my app such that it will launch into a blank version of its normal interface; I then take a screenshot of that, and remove the temporary code. Taking screenshots is covered in the next section. You do not need to blank out the status bar. On an iPhone (or iPad touch), the status bar area of your launch image will be covered by the real status bar. For an iPad, you must trim the status bar area off your launch image entirely. (I use the shareware GraphicConverter, http://www.lemkesoft.com, to do this easily and precisely.) Starting with the advent of the iPhone 5 (and fifth-generation iPod touch), whose screen has a longer height dimension, the runtime now uses the launch image for a second purpose — namely, to determine whether your app is to run “natively” on these devices. The rule is that if your app contains a launch image specifically targeted to this elongated screen size, your app will occupy the entire screen; if not, it will be displayed letterboxed, at the size of the iPhone 4 screen, with black bars at the top and bottom. 228 | Chapter 9: Life Cycle of a Project Don’t add an iPhone 5 launch image to your app unless it can run na‐ tively on the iPhone 5! Your app must be able to respond to the fact that it might appear in the iPhone 4’s shorter screen dimensions or in the iPhone 5’s longer screen dimensions. This will require adjustment of the interface in real time. The best way to perform such adjustment is through autolayout constraints (Chapter 14), but of course there’s a backwards-compatibility trade-off here, because (as I mentioned earlier in this chapter) you can’t use autolayout constraints in an app running on iOS 5 or earlier. A launch image must be a PNG file, and must be named Default.png with the addition of appropriate name qualifiers. An iPhone app will typically have a single initial launch orientation, but an iPad app is supposed to launch into either portrait or landscape orientation and thus requires a launch image for each orientation. A minimally full set of launch images must therefore have the following names and sizes: • Default.png, 320×480 pixels • [email protected], 640×960 pixels (Retina) • [email protected], 640×1136 pixels (iPhone 5) • Default-Portrait~ipad.png, 768×1004 pixels • Default-Landscape~ipad.png, 1004×768 pixels • Default-Portrait@2x~ipad.png, 1536×2008 pixels (Retina) • Default-Landscape@2x~ipad.png, 2008×1536 pixels (Retina) The current versions of the Xcode app templates include initial all-black versions of the three iPhone launch images. This is a courtesy that permits you to run your app on the iPhone 5, including the Simulator, at native size from the outset. You’ll need to replace these with real launch images before submission to the App Store. Annoyingly, initial all-black versions of the four iPad launch images are not included in the app templates — and the consequence is that, for a universal app, the iPhone launch images are wrongly used on the iPad! I have submitted a bug to Apple regarding this, and my impression is that I’m not the only one. In Xcode 4.5 and later, adding launch images is easy. Delete the existing launch images first. Now edit the target and drag-and-drop each launch image onto the appropriate area of the Summary tab. Xcode will copy and rename the image for you, and include it in your target and the Copy Bundle Resources build phase. For example, if I drop a 320×480 PNG file called myLaunchImage.png onto the first iPhone launch image space Final App Preparations | 229 for our Empty Window project, it is copied into the project and added to the target, and the copy is renamed Default.png. In theory, you can use the orientation suffixes in the names of launch images on the iPhone as well. To distinguish between a launch image to be used on the iPhone and a launch image with the same orientation suffix to be used on the iPad, use additional suffixes ~ipad and ~iphone. Thus you can end up with file names like DefaultPortrait@2x~iphone.png. In addition, you can replace Default with some other base name by creating the “Launch image” key in your Info.plist file and setting its value appropriately; but I’ve never done that. For further details, see the “App-Related Resources” chapter of the iOS App Program‐ ming Guide, and “Custom Icon and Image Creation Guidelines” in Apple’s iOS Human Interface Guidelines. Screenshots When you submit the app to the App Store, you will be asked for one or more screenshots of your app in action to be displayed at the App Store. You should take these screenshots beforehand and be prepared to provide them during the app submission process. The required screenshot sizes are listed in Apple’s iTunes Connect Developer Guide, under “Adding New Apps”; look for Table 7-3, “Icon and screenshot field descriptions”. The dimensions of a screenshot depend on its orientation, the screen size, and whether this is a full-screen app — if it isn’t, you must trim the status bar off the screenshot. You must provide at least one screenshot corresponding to the screen size of every device on which your app can run, except that all screenshots must be double-resolution — not because the target device will necessarily be double-resolution, but because there’s a chance that this screenshot will be viewed on a double-resolution device. Typical screenshot dimensions for an app that displays the status bar are thus 640×920 or 960×600 (iPhone), 640×1096 or 1136×600 (iPhone 5), and 1536×2008 or 2048×1496 (iPad). You can obtain screenshots either from the Simulator or from a device connected to the computer. The Simulator is a particularly good approach when you need a doubleresolution launch image and you don’t have a double-resolution device. If you’re going to use the Simulator, configure it to the correct device with the Hardware → Device menu. Run the app and get it into the desired state. Then: Simulator In the Simulator application, choose File → Save Screen Shot. Device In Xcode, in the Organizer window, locate your device under Devices and click Screenshots. Click New Screenshot, at the lower right of the window. 230 | Chapter 9: Life Cycle of a Project To make screenshots available for upload, select each one in the left side of the Devices tab of the Organizer window and click Export to save it with a nice filename into the Finder. Trim off the status bar if necessary. You may need to rotate a screenshot to get it into the correct orientation. If a screenshot is listed in the Organizer window, you can turn it directly into a launch image (see the previous section): select it and click Save as Launch Image. A dialog will ask what name to assign to it and what open project to add it to. Property List Settings A number of settings in Info.plist are crucial to the proper behavior of your app. You should peruse Apple’s Information Property List Key Reference for full information. Most of the required keys are created as part of the template, and are given reasonable default values, but you should check them anyway. The following are particularly worthy of attention: Bundle display name (CFBundleDisplayName) The name that appears under your app’s icon on the device screen; this name needs to be short in order to avoid truncation. Status bar style (UIStatusBarStyle) On the iPhone and iPod touch, the look of the status bar. (On the iPad, the status bar is always black opaque.) In Xcode 4.5 and later, you can set this value using the Style pop-up menu in the Summary tab when you edit your target. Your choices are Default (“Gray style”, UIStatusBarStyleDefault), Black Translucent (“Trans‐ parent black style”, UIStatusBarStyleBlackTranslucent), and Black Opaque (“Opaque black style”, UIStatusBarStyleBlackOpaque). This setting will be used in conjunction with your launch image, even before the app is actually running. However, in iOS 6 the old default status bar style (“Gray style”) won’t appear when the app runs. Instead, the default status bar is black opaque, and if your Style choice is Default, the Tinting pop-up menu comes into play. The reason is that, in iOS 6 on an iPhone, whenever there is a navigation bar at the top of the screen (Chap‐ ter 25), the status bar is automatically tinted to match it. You cannot prevent this behavior. Therefore, if there is a navigation bar at the top of your app’s initial in‐ terface, you might like the status bar that appears during launch to match the run‐ ning app’s initial status bar. (Otherwise, the status bar will appear to change color during launch — which is no terrible thing, and in my experience Apple won’t reject your app for it.) To arrange that, you must describe your initial navigation bar in your Info.plist: • If your initial navigation bar has a standard color style (Default, Black Trans‐ lucent, or Black Opaque), use that style here. Final App Preparations | 231 • If your initial navigation bar has a tint color, use Custom Color and set the tint color in the color well. • If your initial navigation bar has a custom background image, use Custom Image and choose that image. (If your app draws a custom image from scratch at runtime, run in the Simulator to show the interface, use Custom Color, show the color picker, click the magnifying glass icon, and sample the color of a pixel near the bottom of your running app’s navigation bar.) • If there is no initial navigation bar, use Disabled; the status bar will be black opaque during launch. If your Tinting choice is not Disabled, the “Status bar tinting parameters” key (UIStatusBarTintParameters) is set to a “Navigation bar” dictionary describing the navigation bar. If the status bar is to be hidden initially, set “Status bar is initially hidden” (UIStatusBarHidden) instead. Supported interface orientations (UISupportedInterfaceOrientations) In iOS 6, this key designates the totality of orientations in which the app is ever permitted to appear (Chapter 19). This is a major change from iOS 5 and before. You can perform this setting graphically in the Summary tab when editing your target. But you may also need to edit the Info.plist manually to rearrange the order of possible orientations, because on an iPhone the first orientation listed is the one into which the app will actually launch. Required device capabilities (UIRequiredDeviceCapabilities) You should set this key if the app requires capabilities that are not present on all devices. Be sure to look over the list of possible values. Don’t use this key unless it makes no sense for your app to run at all on a device lacking the specified capabil‐ ities. (The current project templates include armv7 in the list of required device capabil‐ ities. This may prove troublesome for backwards compatibility.) Property list settings can adopt different values depending on what device type you’re running on. To specify that a property list setting applies only on a particular type of device, you add to its key the suffix ~iphone, ~ipod, or ~ipad. This feature is typically useful in a universal app, as I described earlier in this chapter. Your app also needs a version number. Edit the Target and click Summary at the top of the page; enter a version string in the Version text field. Things are a little confusing here because there is both a Version field and a Bundle field; the former corresponds to “Bundle versions string, short” (CFBundleShortVersionString), while the latter cor‐ responds to “Bundle version” (CFBundleVersion). As far as I can determine, Apple will pay attention to the former if it is set, and otherwise will fall back on the latter. In general 232 | Chapter 9: Life Cycle of a Project I play it safe and set both to the same value when submitting to the App Store. The value needs to be a version string, such as “1.0”. This version number will appear at the App Store. Failure to increment the version string when submitting an update will cause the update to be rejected. Submission to the App Store Before submitting your app to the App Store, build it (Product → Archive) and test it as an Ad Hoc build. The archived build that appears in the Organizer window can be used to generate either an Ad Hoc build or an App Store build. You can’t test an App Store build, so you use this archived build to generate an Ad Hoc build and test with that. When you generate the App Store build, you use this same archived build; it is the exact same binary, so you are guaranteed that its behavior will be exactly the same as the build you tested. (That is one of the purposes of archiving.) When you’re satisfied that your app works well, and you’ve installed or collected all the necessary resources, you’re ready to submit your app to the App Store for distribu‐ tion. To do so, you’ll need to make preparations at the iTunes Connect website. You can find a link to it on the iOS developer pages when you’ve logged in at Apple’s site. You can go directly to http://itunesconnect.apple.com, but you’ll still need to log in with your iOS Developer username and password. The first time you visit iTunes Connect, you should go to the Contracts section and complete submission of your contract. You can’t offer any apps for sale until you do, and even free apps require completion of a contractual form. I’m not going to recite all the steps you have to go through to tell iTunes Connect about your app, as these are described thoroughly in Apple’s iTunes Connect Developer Guide, which is the final word on such matters. But I’ll just mention the main pieces of information you will have to supply: Your app’s name This is the name that will appear at the App Store; it need not be identical to the short name that will appear under the app’s icon on the device, dictated by the Bundle Display Name setting in your Info.plist file. This name can be up to 255 characters long, though Apple recommends that you limit it to fewer than 70 and ideally to fewer than 35 characters. You can get a rude shock when you submit your app’s information to iTunes Connect and discover that the name you wanted is already taken. There is no reliable way to learn this in advance, and such a discovery can require a certain amount of scrambling on your part: you might have to Build Submission to the App Store | 233 and Archive your app yet again with a new name and possibly other last-minute changes. Description You must supply a description of fewer than 4,000 characters; Apple recommends fewer than 580 characters, and the first paragraph is the most important, because this may be all that users see at first when they visit the App Store. It must be pure text, without HTML and without character styling. Keywords This is a comma-separated list shorter than 100 characters. These keywords will be used, in addition to your app’s name, to help users discover your app through the Search feature of the App Store. Support This the URL of a website where users can find more information about your app; it’s good to have the site ready in advance. Copyright Do not include a copyright symbol in this string; it will be added for you at the App Store. SKU number This is unimportant, so don’t get nervous about it. It’s just a unique identifier, unique within the world of your own apps. It’s convenient if it has something to do with your app’s name. It needn’t be a number; it can actually be any string. Price You don’t get to make up a price. You have to choose from a list of pricing “tiers.” Availability Date There’s an option to make the app available as soon as it is approved, and this will typically be your choice. Alternatively, Apple will send you an email when the app is approved, and you can then return to iTunes Connect and make the app available manually. When you’ve submitted the information for your app, you can do a final validation check: return to the Organizer window, select the archived build, and click Validate. (This feature has not worked well for me in the past, however.) Finally, when you’re ready to upload the app for which you’ve already submitted the information at iTunes Connect, and when the iTunes Connect status for your app is “Waiting for Upload,” you can perform the upload using Xcode. Select the archived build in the Organizer and click Distribute. In the dialog, choose “Submit to the iOS App Store.” You’ll be asked to provide your developer username and password, so that Xcode can make sure that this app really is waiting for upload at iTunes Connect. You’ll 234 | Chapter 9: Life Cycle of a Project then specify your identity as contained in the App Store distribution profile, and Xcode will proceed to upload the app. Some validation will then be performed at the far end. Alternatively, you can use Application Loader. Export the archive as an .ipa file, as for an Ad Hoc distribution, but use the App Store distribution profile. Launch Application Loader by choosing Xcode → Open Developer Tool → Application Loader, and hand it the .ipa file. You will subsequently receive emails from Apple informing you of your app’s status as it passes through various stages: “Waiting For Review,” “In Review,” and finally, if all has gone well, “Ready For Sale” (even if it’s a free app). Your app will then appear at the App Store. Submission to the App Store | 235 When Your Certificate Expires When one of your certificates expires, as will happen after a year, all profiles dependent upon it will become invalid. I have never figured out what Apple expects you to do at this point; certainly none of the courses of action suggested in Apple’s documentation have worked for me. The only thing that ever has worked for me is to delete every‐ thing (except the WWDR certificate, which remains good for several years) and start over from scratch: 1. Before you even begin to make yourself a new certificate, quit Xcode. This step is crucial. Xcode has a nasty habit of unexpectedly downloading fresh copies of your profiles from the Portal. But your existing profiles are part of the problem: they are expiring. Moreover, when this happens, Xcode has an even nastier habit of installing the certificates contained in these profiles into your keychain. But those certificates are heart of the problem: they are expiring. Moreover, Xcode will balk if it finds two versions of a certificate in your keychain — even if Xcode itself installed them! Therefore you must take Xcode out of the picture before you begin. 2. Go the Portal in your browser and delete all development and distribution profiles. That’s because they depend on your old certificates. You don’t want them in the Portal, because if they are still there when you next run Xcode, Xcode might down‐ load them (see the previous step). 3. Now launch Xcode. You are safe to do so: Xcode cannot now download fresh copies of your profiles from the Portal, because there are no profiles at the Portal! So proceed to delete all development and distribution profiles from the Provisioning Profiles section of the Devices tab of the Organizer window. Just to be on the safe side, it might be a good idea at this point to delete all development and distribution profiles from each of your test devices as well. 4. Delete the development and distribution certificates from your keychain. 5. Everything is now gone, and it’s safe to begin recreating it all from scratch. First, repeat the process of obtaining fresh development and distribution certificates, downloading them, and installing them in your keychain. 6. At the Portal, create any actively needed distribution profiles, and any development profiles with special entitlements. Your app ID and device information is still at the Portal, and your certificates are now fresh, so this won’t present any difficulties. Download and install the profiles. 7. Finally, you need to prod Xcode into recreating the team development profile. To do so, connect one of your development devices to the computer and ask Xcode to add it at the Portal (even though it has already been added to the Portal previously). This in turn will cause Xcode to ask the Portal for a new team development profile. PART III Cocoa When you program for iOS, you take advantage of a suite of frameworks provided by Apple. These frameworks, taken together, constitute Cocoa; the brand of Cocoa that provides the API for programming iOS is Cocoa Touch. Cocoa thus plays an important and fundamental role in iOS programming; your code will ultimately be almost entirely about communicating with Cocoa — interacting with the frameworks provided by Ap‐ ple, in order to make an app that does what you want it to do. The Cocoa Touch frameworks are a huge boon to you, the programmer, because they provide the underlying functionality that any iOS app needs to have. Your app can put up a window, show the interface containing a button, respond to that button being tapped by the user, and so forth, because Cocoa knows how to do those things. But with the great advantages of working with a framework come great responsibilities. You have to think the way the framework thinks, put your code where the framework expects it, and fulfill many obligations imposed on you by the framework. • Chapter 10 picks up where Chapter 5 left off, describing some Objective-C linguistic features used by Cocoa, such as categories and protocols; it also surveys some im‐ portant fundamental classes. • Chapter 11 describes Cocoa’s event-driven model, along with its major design pat‐ terns. An event is a message sent by Cocoa to your code. Cocoa is event-based; if Cocoa doesn’t send your code an event, your code doesn’t run. Getting your code to run at the appropriate moment is all about knowing what events you can expect Cocoa to send you and when. • Chapter 12 describes your responsibilities for making your instances nicely encap‐ sulated and good memory-management citizens in the world of Cocoa objects. • Chapter 13 surveys some answers to the question of how your objects are going to see and communicate with one another within the Cocoa-based world. CHAPTER 10 Cocoa Classes Using the Cocoa frameworks requires an understanding of how those frameworks or‐ ganize their classes. Cocoa class organization depends upon certain Objective-C language features that are introduced in this chapter. The chapter also surveys some commonly used Cocoa utility classes, along with a discussion of the Cocoa root class. Subclassing Cocoa effectively hands you a large repertory of objects that already know how to behave in certain desirable ways. A UIButton, for example, knows how to draw itself and how to respond when the user taps it; a UITextField knows how to display editable text, how to summon the keyboard when the user taps in it, and how to accept keyboard input. Often, the default behavior or appearance of an object supplied by Cocoa won’t be quite what you’re after, and you’ll want to customize it. Cocoa classes are heavily endowed with methods that you can call and properties that you can set for precisely this purpose, and these will be your first resort. Always study the documentation for a Cocoa class to see whether instances can already be made to do what you want. For example, the class documentation for UILabel (Chapter 27) shows that you can set the font, size, color, line-breaking behavior, and horizontal alignment of its text, among other things. Nevertheless, sometimes setting properties and calling methods won’t suffice to cus‐ tomize an instance the way you want to. In such cases, Cocoa may provide methods that are called internally as an instance does its thing, and whose behavior you can customize by subclassing and overriding (Chapter 4). You don’t have the code to any of Cocoa’s built-in classes, but you can still subclass them, creating a new class that acts just like a built-in class except for the modifications you provide. Oddly enough, however (and you might be particularly surprised by this if you’ve used another object-oriented application framework), subclassing is probably one of the less important ways in which your code will relate to Cocoa. Knowing or deciding when to 239 subclass can be somewhat tricky, but the general rule is that you probably shouldn’t subclass unless you’re invited to. A common case is a UIView that is to be drawn in some custom manner. You don’t actually draw a UIView; rather, when a UIView needs drawing, its drawRect: method is called so that the view can draw itself. So the way to draw a UIView in some completely custom manner is to subclass UIView and implement drawRect: in the subclass. As the documentation says, “Subclasses override this method if they actually draw their views.” That’s a pretty strong hint that you need to subclass UIView in this situation. For example, suppose we want our window to contain a horizontal line. There is no horizontal line interface widget built into Cocoa, so we’ll just have to roll our own — a UIView that draws itself as a horizontal line. Let’s try it: 1. In our Empty Window example project, choose File → New → File and specify a Cocoa Touch Objective-C class, and in particular a subclass of UIView. Call it MyHorizLine. Xcode creates MyHorizLine.m and MyHorizLine.h. 2. In MyHorizLine.m, replace the contents of the implementation section with this (without further explanation; you’ll know all about this after you read Chapter 15): - (id)initWithCoder:(NSCoder *)decoder { self = [super initWithCoder:decoder]; if (self) { self.backgroundColor = [UIColor clearColor]; } return self; } - (void)drawRect:(CGRect)rect { CGContextRef c = UIGraphicsGetCurrentContext(); CGContextMoveToPoint(c, 0, 0); CGContextAddLineToPoint(c, self.bounds.size.width, 0); CGContextStrokePath(c); } 3. Edit ViewController.xib. Find UIView in the Object library, and drag it into the View object in the canvas. You may resize it to be less tall. 4. With the UIView that you just dragged into the canvas still selected, use the Identity inspector to change its class to MyHorizLine. Build and run the app in the Simulator. You’ll see a horizontal line corresponding to the location of the top of the MyHorizLine instance in the window. Our view has drawn itself as a horizontal line, because we subclassed it to do so. In that example, we started with a bare UIView that had no drawing functionality of its own. That’s why there was no need to call super; the default implementation of UIView’s drawRect: does nothing. But you might also be able to subclass a built-in UIView sub‐ 240 | Chapter 10: Cocoa Classes class to modify the way it already draws itself. Again using UILabel as an example, the documentation shows that two methods are present for exactly this purpose. Both drawTextInRect: and textRectForBounds:limitedToNumberOfLines: explicitly tell us: “You should not call this method directly. This method should only be overridden by subclasses.” The implication is that these are methods that will be called for us, auto‐ matically, by Cocoa, as a label draws itself; thus, we can subclass UILabel and implement them in our subclass to modify how a particular type of label draws itself. Here’s an example from one of my own apps, in which I subclass UILabel to make a label that draws its own rectangular border and has its content inset somewhat from that border, by overriding drawTextInRect:. As the documentation tells us: “In your overridden method, you can configure the current [graphics] context further and then invoke super to do the actual drawing [of the text].” Let’s try it: 1. In the Empty Window project, make a new class file, a UILabel subclass this time; call it MyBoundedLabel. 2. In MyBoundedLabel.m, insert this code into the implementation section: - (void)drawTextInRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextStrokeRect(context, CGRectInset(self.bounds, 1.0, 1.0)); [super drawTextInRect:CGRectInset(rect, 5.0, 5.0)]; } 3. In MyNib.xib, select the UILabel and change its class in the Identity inspector to MyBoundedLabel. Build and run the app, and you’ll see how the rectangle is drawn and the label’s text is inset within it. Similarly, in a table view (a UITableView) you might very well be able to avoid sub‐ classing the table view cell (UITableViewCell), because it provides so many properties through which you can customize its appearance. If you want text to appear in the cell using a certain font, the built-in cell styles and the ability to access and modify the cell’s labels might be quite sufficient. You can directly replace a cell’s background or put a checkmark at the right end of the cell. All of that is simply a matter of setting the cell’s built-in properties. But if you want a table view cell that doesn’t look or behave like any of the built-in cell styles, then you’ll probably subclass UITableViewCell. (We’ll go deeply into this in Chapter 21.) You wouldn’t subclass UIApplication (the class of the singleton shared application in‐ stance) just in order to respond when the application has finished launching, because the delegate mechanism (Chapter 11) provides a way to do that (application:didFinishLaunchingWithOptions:). On the other hand, if you need to perform certain tricky customizations of your app’s fundamental event messaging behavior, you might subclass UIApplication in order to override sendEvent:. The documentation does tell Subclassing | 241 you this, and it also tells you, rightly, that needing to do this would be fairly rare (though I have had occasion to do it). If you do subclass UIApplication, you’ll need to change the third argu‐ ment in the call to UIApplicationMain in main.m from nil to the NSString name of your subclass. Otherwise your UIApplication sub‐ class won’t be instantiated as the shared application instance. Another class that’s commonly subclassed is UIViewController (Chapter 19). And any class you write will naturally need to be a subclass of NSObject, if nothing else. You definitely want your class to inherit all of NSObject’s yummy goodness, including alloc and init, which make it possible to instantiate your class in the first place (see “The Secret Life of NSObject” (page 266)). Categories A category is an Objective-C language feature that allows you to reach right into an existing class and define additional methods. You can do this even if you don’t have the code for the class, as with Cocoa’s classes. Your instance methods can refer to self, and this will mean the instance to which the message was originally sent, as usual. A category, unlike a subclass, cannot define additional instance variables; it can override methods, but you should probably not take advantage of this ability. Defining a category is just like defining the class on which the category is being defined: you need an interface section and an implementation section, and you’ll typically dis‐ tribute them into the standard .h and .m class file pair. At the start of both the interface section and the implementation section, where you give the class’s name, you add a category name in parentheses. The .h file will probably need to import the header for the original class (or the header of the framework that defines it), and the .m file will, as usual, import the .h file, as will any .m file that wants to call one of your additional methods. The easiest way to set up your .h and .m class file pair as a category is to ask Xcode to do it for you. Choose File → New → File, and in the “Choose a template” dialog, among the iOS Cocoa Touch file types, pick “Objective-C category”. You’ll be asked to give a name for the category and the class on which you’re defining this category. For example, in one of my apps I found myself performing a bunch of string transfor‐ mations in order to derive the path to various resource files inside the app bundle based on the resource’s name and purpose. I ended up with half a dozen utility methods. Given that these methods all operated on an NSString, it was appropriate to implement them as a category of NSString, thus allowing any NSString, anywhere in my code, to respond to them. 242 | Chapter 10: Cocoa Classes The code was structured like this (I’ll show just one of the methods): // StringCategories.h: #import <Foundation/Foundation.h> @interface NSString (MyStringCategories) - (NSString*) basePictureName; @end // StringCategories.m: #import "StringCategories.h" @implementation NSString (MyStringCategories) - (NSString*) basePictureName { return [self stringByAppendingString:@"IO"]; } @end If basePictureName had been implemented as a utility method within some other class, it would need to take a parameter — we’d have to pass an NSString to it — and, it were an instance method, we’d need to go to the extra trouble of obtaining a reference to an instance of that class. A category is neater and more compact. We’ve extended NSString itself to have basePictureName as an instance method, so, in any .m file that imports StringCategories.h, we can send the basePictureName message directly to any NSString we want to transform: NSString* aName = [someString basePictureName]; A category is particularly appropriate in the case of a class like NSString, because the documentation warns us that subclassing NSString is a bad idea. That’s because NSString is part of a complex of classes called a class cluster, which means that an NSString object’s real class might actually be some other class. A category is a much better way to modify a class within a class cluster than subclassing. A method defined through a category can equally be a class method. Thus you can inject utility methods into any appropriate class and call those methods without the overhead of instantiating anything at all. Classes are globally available, so your method becomes, in effect, a global method (see Chapter 13). Splitting a Class A category can be used to split a class over multiple .h/.m file pairs. If a class threatens to become long and unwieldy, yet it clearly needs to be a single class, you can define the basic part of it (including instance variables) in one file pair, and then add another file pair defining a category on your own class to contain further methods. Cocoa itself does this. A good example is NSString. NSString is defined as part of the Foundation framework, and its basic methods are declared in NSString.h. Here we find that NSString itself, with no category, has just two methods, length and characterAtCategories | 243 Index:, because these are regarded as the minimum that a string needs to do in order to be a string. Additional methods (those that create a string, deal with a string’s en‐ coding, split a string, search in a string, and so on) are clumped into categories. The interface for many of these categories appears in this same file, NSString.h. But a string may serve as a file pathname, so we also find a category on NSString in NSPath‐ Utilities.h, where methods are declared for splitting a pathname string into its constit‐ uents and the like. Then, in NSURL.h, there’s another NSString category, declaring a couple of methods for dealing with percent-escaping in a URL string. Finally, off in a completely different framework (UIKit), UIStringDrawing.h adds yet another NSString category, with methods for drawing a string in a graphics context. This organization won’t matter to you as a programmer, because an NSString is an NSString, no matter how it acquires its methods, but it can matter when you consult the documentation. The NSString methods declared in NSString.h, NSPathUtilities.h, and NSURL.h are documented in the NSString class documentation page, but the NSString methods declared in UIStringDrawing.h are not, presumably because they originate in a different framework. Instead, they appear in a separate document, NSString UIKit Additions Reference. As a result, the string drawing methods can be difficult to discover, especially as the NSString class documentation doesn’t link to the other document. I regard this as a major flaw in the structure of the Cocoa documen‐ tation. A third-party utility such as AppKiDo can be helpful here. Class Extensions A class extension is a nameless category that exists solely as an interface section, like this: @interface MyClass () // stuff goes here @end Typically, the only classes that will be permitted to “see” a class extension will be the class that’s being extended or a subclass of that class. If only the former is the case, the class extension will usually appear directly in the class’s implementation file, like this: // MyClass.m: @interface MyClass () // stuff goes here @end @implementation MyClass { // ivars } // methods @end 244 | Chapter 10: Cocoa Classes That’s such a common arrangement that Xcode’s project template files actually give you a class extension in certain classes. For example, our Empty Window project comes with a class extension at the start of ViewController.m — take a look and see! I’m sure you’re leaping out of your chair with eagerness to know what on earth sort of “stuff ” could possibly go into a class extension to make it so useful that it appears in a template file. Unfortunately, in modern Objective-C the answer has mostly to do with property declarations, which I don’t discuss until Chapter 12. So your curiosity will have to remain unsatisfied until then. A class extension used to be the standard solution to the problem of method definition order. One method in an implementation section couldn’t call another method in that same implementation section unless either the definition or a method declaration for that other method preceded it. It’s finicky work trying to arrange all the method defi‐ nitions in the right order, so the obvious solution is a method declaration. A method declaration can go only into an interface section. But to put a method declaration into the interface section in this class’s header file is annoying — it means we must switch to another file — and, even worse, it makes that method public; any class that imports that header file can now see and call this method. That’s fine if this method is supposed to be public; but what if we wanted to keep it private? The solution: a class extension at the start of this class’s implementation file. Put the method declarations into that class extension; all the methods in the implementation section can now see those method declarations and can call one another, but no other class can see them. However, since LLVM compiler version 3.1 (Xcode 4.3) that trick has been unnecessary: methods (and functions) in a class implementation can see and call one another re‐ gardless of order. Protocols Every reasonably sophisticated object-oriented language must face the fact that the hi‐ erarchy of subclasses and superclasses is insufficient to express the desired relationships between classes. For example, a Bee object and a Bird object might need to have certain features in common by virtue of the fact that both a bee and a bird can fly. But Bee might inherit from Insect, and not every insect can fly, so how can Bee acquire the aspects of a Flier in a way that isn’t completely independent of how Bird acquires them? Some object-oriented languages solve this problem through mixin classes. For example, in Ruby you could define a Flier module, complete with method definitions, and in‐ corporate it into both Bee and Bird. Objective-C uses a simpler, lighter-weight approach — the protocol. Cocoa makes heavy use of protocols. A protocol is just a named list of method declarations, with no implementation. A class may formally declare that it conforms to (or adopts) a protocol; such conformance is inherited by subclasses. This declaration satisfies the compiler when you try to send a Protocols | 245 corresponding message. If a protocol declares an instance method myCoolMethod, and if MyClass declares conformance to that protocol, then you can send the myCoolMethod message to a MyClass instance and the compiler won’t complain. Actually implementing the methods declared in a protocol is up to the class that con‐ forms to it. A protocol method may be required or optional. If a protocol method is required, then if a class conforms to that protocol, the compiler will warn if that class fails to implement that method. Implementing optional methods, on the other hand, is optional. (Of course, that’s just the compiler’s point of view; at runtime, if a message is sent to an object with no implementation for the corresponding method, a crash can result; see Chapter 3.) Here’s an example of how Cocoa uses a protocol. Some objects can be copied; some can’t. This has nothing to do with an object’s class heritage. Yet we would like a uniform method to which any object that can be copied will respond. So Cocoa defines a protocol named NSCopying, which declares just one method, copyWithZone: (required). A class that explicitly conforms to NSCopying is promising that it implements copyWithZone:. Here’s how the NSCopying protocol is defined (in NSObject.h, where your code can see it): @protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end That’s all there is to defining a protocol. The definition uses the @protocol compiler directive; it states the name of the protocol; it consists entirely of method declarations; and it is terminated by the @end compiler directive. A protocol definition will typically appear in a header file, so that classes that need to know about it, in order to adopt it or call its methods, can import it. A protocol section of a header file is not inside any other section (such as an interface section). Any optional methods must be preceded by the @optional directive. A protocol definition may state that the protocol incorporates other protocols; these constitute a comma-separated list in angle brackets after the pro‐ tocol’s name, like this example from Apple’s own code (UIAlertView.h): @protocol UIAlertViewDelegate <NSObject> @optional - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex; // ... more optional method declarations ... @end The NSCopying protocol definition in NSObject.h is just a definition; it is not a state‐ ment that NSObject conforms to NSCopying. Indeed, NSObject does not conform to NSCopying. To see this, try sending the copyWithZone: method to your own subclass of NSObject: 246 | Chapter 10: Cocoa Classes MyClass* mc = [MyClass new]; MyClass* mc2 = [mc copyWithZone: [mc zone]]; The compiler warns that a MyClass instance may not respond to copyWithZone:; under ARC, this code won’t compile at all. To conform formally to a protocol, a class’s interface section appends the name of the protocol, in angle brackets, after the name of the superclass (or, if this is a category declaration, after the parentheses). This will necessitate importing the header file that declares the protocol (or some header file that imports that header file). To state that a class conforms to multiple protocols, put multiple protocol names in the angle brackets, separated by comma. Let’s see what happens if you conform formally to the NSCopying protocol. Modify the first line of the interface section of your class as follows: @interface MyClass : NSObject <NSCopying> Now the compiler warns that MyClass fails to implement copyWithZone: and thus does not fully implement the NSCopying protocol (because copyWithZone: is a required method of the NSCopying protocol). The name of a protocol may also be used when specifying an object type. Most often, the object will be typed as an id, but with the accompanying proviso that it conforms to a protocol, whose name appears in angle brackets. To illustrate, let’s look at another typical example of how Cocoa uses protocols, namely in connection with a table (UITableView). A UITableView has a dataSource property, declared like this: @property (nonatomic, assign) id<UITableViewDataSource> dataSource This property represents an instance variable whose type is id <UITableViewDataSource>. This means “I don’t care what class my data source belongs to, but whatever it is, it should conform to the UITableViewDataSource protocol.” Such conformance constitutes a promise that the data source will implement at least the required instance methods tableView:numberOfRowsInSection: and tableView:cellForRowAtIndexPath:, which the table view will call when it needs to know what data to display. If you attempt to set a table view’s dataSource property to an object that does not conform to UITableViewDataSource, you’ll get a warning from the compiler. So, for example: MyClass* mc = [MyClass new]; UITableView* tv = [UITableView new]; tv.dataSource = mc; // compiler warns Protocols | 247 Under ARC, this warning is couched in rather confusing terms, along these lines: “Pass‐ ing ‘MyClass *const __strong’ to parameter of incompatible type ‘id<UITableView‐ DataSource>’.” To quiet the compiler, MyClass’s declaration should state that it conforms to UITable‐ ViewDataSource. Once it does so, MyClass is an id <UITableViewDataSource>, and the third line no longer generates a warning. Of course, you must also supply imple‐ mentations of tableView:numberOfRowsInSection: and tableView:cellForRowAtIndexPath: in MyClass to avoid the other warning, namely that you’re not fully im‐ plementing a protocol you’ve claimed to conform to. In a very large percentage of cases, the object that you want to assign where conformity to a protocol is expected is self. In this situation, you can declare this class’s conformity to the protocol in the implementation file as part of a class extension, like this: // MyClass.m: @interface MyClass () <UITableViewDataSource> @end @implementation MyClass - (void) someMethod { UITableView* tv = [UITableView new]; tv.dataSource = self; } @end I prefer this architecture, because it means that the declaration of conformity to the protocol is right there in the same implementation file that uses the protocol, and be‐ cause the header defining the protocol can be imported in the implementation file, rather than in the class’s header file where it will be unnecessarily shared with any other classes that import the same header file. A prevalent use of protocols in Cocoa is in connection with delegate objects. We’ll talk in detail about delegates in Chapter 11, but you can readily see that many classes have a delegate property and that the class of this property is often id <SomeProtocol>. For example, in our Empty Window project, the AppDelegate class provided by the project template is declared like this: @interface AppDelegate : UIResponder <UIApplicationDelegate> The reason is that AppDelegate’s purpose on earth is to serve as the shared application’s delegate. The shared application object is a UIApplication, and a UIApplication’s delegate property is typed as an id <UIApplicationDelegate>. So AppDelegate an‐ nounces its role by explicitly conforming to UIApplicationDelegate. As a programmer, Cocoa’s use of protocols will matter to you in two ways: 248 | Chapter 10: Cocoa Classes Conformity As I’ve just been saying, if an object value that you wish to assign or pass as an argument is typed as id <SomeProtocol>, you must make sure that that object’s class does indeed conform to SomeProtocol (and implements any methods required by that protocol). Using the documentation A protocol has its own documentation page. When the UIApplication class docu‐ mentation tells you that a UIApplication’s delegate property is typed as an id <UIApplicationDelegate>, it’s implicitly telling you that if you want to know what messages a UIApplication’s delegate might receive, you need to look in the UIApplicationDelegate protocol documentation. Similarly, when a class’s documentation mentions that the class conforms to a pro‐ tocol, don’t forget to examine that protocol’s documentation, because the latter might contain important information about how the class behaves. To learn what messages can be sent to an object, you need to look upward through the superclass inheritance chain (Chapter 8); you also need to look at any protocols that this ob‐ ject’s class conforms to. You will probably not have frequent cause to define a protocol yourself. But protocols effectively allow one class to declare a method that another class is to implement, and there are certain situations where that’s exactly the problem you need to solve; so a protocol will be the solution. For example, in one of my apps I present a view where the user can move three sliders to choose a color. Appropriately, its code is in a class called ColorPickerController. When the user taps Done or Cancel, the view should be dismissed; but first, the code that presented this view needs to hear about what color the user chose. So I need to send a message from the ColorPickerController instance back to the instance that presented it. Here is the declaration for that message: - (void) colorPicker:(ColorPickerController*)picker didSetColorNamed:(NSString*)theName toColor:(UIColor*)theColor; The question is: where should this declaration go? Now, it happens that in my app I know the class of the instance that will present the ColorPickerController’s view: it is a SettingsController. So I could simply declare this method in the interface section of SettingsController’s header file. But this feels wrong: • It should not be up to SettingsController to declare a method that it is implementing only in deference to ColorPickerController. • If SettingsController declares this message in its header file, ColorPickerController will have to import that header file in order to send the message; but this means Protocols | 249 that ColorPickerController now knows all about SettingsController, whereas the only thing it needs to know about SettingsController is that it implements this one method. • It is merely a contingent fact that the instance being sent this message is a Settings‐ Controller; it should be open to any class to present and dismiss a ColorPicker‐ Controller’s view, and thus to be eligible to receive this message. Therefore we want ColorPickerController itself to declare the method that it itself is going to send; and we want it to send the message blindly to some receiver, without regard to the class of that receiver. Thus there needs to be a linkage, as it were, between the declaration of this method in ColorPickerController and the implementation of this method in the receiver. That linkage is precisely what a protocol creates! The solution, then, is for ColorPickerController to define a protocol in its header file, with this method as part of that protocol, and for the class that presents a ColorPickerController’s view to conform to that protocol. If you create a project from Xcode’s own Utility Application template, you will see that this is exactly the architecture it exemplifies. We start with a MainViewController. It eventually creates a FlipsideViewController. When the FlipsideViewController is ready to go out of existence, it is going to want to send the flipsideViewControllerDidFinish: message back to whoever created it. So FlipsideViewController defines a FlipsideViewControllerDelegate protocol requiring the flipsideViewControllerDidFinish: method, along with a delegate property typed as id <FlipsideViewControllerDelegate>. When a MainViewController instance creates a FlipsideView‐ Controller instance, it specifies that it itself, the MainViewController instance, is the FlipsideViewController’s delegate; and it can do this, because MainViewController does in fact adopt the FlipsideViewControllerDelegate protocol! Problem solved, mis‐ sion accomplished. Optional Methods A protocol can explicitly designate some or all of its methods as optional. The question thus arises: How, in practice, is such an optional method feasible? We know that if a message is sent to an object and the object can’t handle that message, an exception is raised (and your app will likely crash). But a method declaration is a contract suggesting that the object can handle that message. If we subvert that contract by declaring a method that might or might not be implemented, aren’t we inviting crashes? The answer is that Objective-C is not only dynamic but also introspective. You can ask an object whether it can deal with a message without actually sending it that message. This makes optional methods quite safe, provided you know that a method is optional. 250 | Chapter 10: Cocoa Classes Informal Protocols You may occasionally see, online or in the documentation, a reference to an informal protocol. An informal protocol isn’t really a protocol at all; it’s just a way of providing the compiler with a method signature so that it will allow a message to be sent without complaining. There are two complementary ways to implement an informal protocol. One is to define a category on NSObject; this makes any object eligible to receive the messages listed in the category. The other is to define a protocol to which no class formally conforms; instead, send any message listed in the protocol only to objects typed as id, thus suppressing any possible objections from the compiler. These techniques were widespread before protocols could declare methods as optional; now they are largely unnecessary. (They are still used, but decreasingly so; in iOS 6 very few informal protocols remain.) They are also mildly dangerous, because you might accidentally de‐ fine a method with the same name as an existing method but a different signature, with unpredictable results. The key method here is NSObject’s respondsToSelector:, which takes a selector pa‐ rameter and returns a BOOL. With it, you can send a message to an object only if it would be safe to do so: MyClass* mc = [MyClass new]; if ([mc respondsToSelector:@selector(woohoo)]) { [mc woohoo]; } You wouldn’t want to do this before sending just any old message, because it isn’t nec‐ essary except for optional methods, and it slows things down a little. But Cocoa does in fact call respondsToSelector: on your objects as a matter of course. To see that this is true, implement respondsToSelector: on AppDelegate in our Empty Window project and instrument it with logging: - (BOOL) respondsToSelector: (SEL) sel { NSLog(@"%@", NSStringFromSelector(sel)); return [super respondsToSelector:(sel)]; } The output on my machine, as the Empty Window app launches, includes the following (I’m omitting private methods and multiple calls to the same method): application:handleOpenURL: application:openURL:sourceApplication:annotation: applicationDidReceiveMemoryWarning: applicationWillTerminate: applicationSignificantTimeChange: application:willChangeStatusBarOrientation:duration: application:didChangeStatusBarOrientation: application:willChangeStatusBarFrame: Optional Methods | 251 application:didChangeStatusBarFrame: application:deviceAccelerated: application:deviceChangedOrientation: applicationDidBecomeActive: applicationWillResignActive: applicationDidEnterBackground: applicationWillEnterForeground: applicationWillSuspend: application:didResumeWithOptions: application:shouldSaveApplicationState: application:supportedInterfaceOrientationsForWindow: application:willFinishLaunchingWithOptions: application:didFinishLaunchingWithOptions: That’s Cocoa, checking to see which of the optional UIApplicationDelegate protocol methods (including a couple of undocumented methods) are actually implemented by our AppDelegate instance — which, because it is the UIApplication object’s delegate and formally conforms to the UIApplicationDelegate protocol, has explicitly agreed that it might be willing to respond to any of those messages. The entire delegate pattern (Chapter 11) depends upon this technique. Observe the policy followed here by Cocoa: it checks all the optional protocol methods once, when it first meets the object in ques‐ tion, and presumably stores the results; thus, the app is slowed a tiny bit by this onetime initial bombardment of respondsToSelector: calls, but now Cocoa knows all the answers and won’t have to perform any of these same checks on the same object later on. Some Foundation Classes The Foundation classes of Cocoa provide basic data types and utilities that will form the basis of much that you do in Cocoa. Obviously I can’t list all of them, let alone describe them fully, but I can survey a few that I use frequently and that you’ll probably want to be aware of before writing even the simplest Cocoa program. For more infor‐ mation, start with Apple’s list of the Foundation classes in the Foundation Framework Reference. Useful Structs and Constants NSRange is a struct of importance in dealing with some of the classes I’m about to discuss. Its components are integers (NSUInteger), location and length. For example, a range whose location is 1 starts at the second element of something (because element counting is always zero-based), and if its length is 2 it designates this element and the next. Cocoa also supplies various convenience methods for dealing with a range; you’ll use NSMakeRange frequently. (Note that the name, NSMakeRange, is backward compared to names like CGPointMake and CGRectMake.) 252 | Chapter 10: Cocoa Classes NSNotFound is a constant integer indicating that some requested element was not found. For example, if you ask for the index of a certain object in an NSArray and the object isn’t present in the array, the result is NSNotFound. The result could not be 0 to indicate the absence of the object, because 0 would indicate the first element of the array. Nor could it be nil, because nil is 0 (and in any case is not appropriate when an integer is expected). The true numeric value of NSNotFound is of no concern to you; always compare against NSNotFound itself, to learn whether a result is a meaningful index. If a search returns a range and the thing sought is not present, the location component of the resulting NSRange will be NSNotFound. NSString and Friends NSString, which has already been used rather liberally in examples earlier in this book, is the Cocoa object version of a string. You can create an NSString through a number of class methods and initializers, or by using the NSString literal notation @"...", which is really a compiler directive. Particularly important is stringWithFormat:, which lets you convert numbers to strings and combine strings; see Chapter 9, where I discussed format strings in connection with NSLog. Here are some strings in action: int x = 5; NSString* s = @"widgets"; NSString* s2 = [NSString stringWithFormat:@"You have %i %@.", x, s]; NSString has a modern, Unicode-based idea of what a string can consist of. A string’s “elements” are its characters, whose count is its length. These are not bytes, because the numeric representation of a Unicode character could be multiple bytes, depending on the encoding. Nor are they glyphs, because a composed character sequence that prints as a single “letter” can consist of multiple characters. Thus the length of an NSRange indicating a single “character” might be greater than 1. An NSString can be searched using various rangeOf... methods, which return an NSRange. In addition, NSScanner lets you walk through a string looking for pieces that fit certain criteria; for example, with NSScanner (and NSCharacterSet) you can skip past everything in a string that precedes a number and then extract the number. The rangeOfString: family of search methods lets you look for a substring; it can specify an option NSRegularExpressionSearch, which lets you search using a regular expres‐ sion, and regular expressions are also supported as a separate class, NSRegular‐ Expression (which uses NSTextCheckingResult to describe match results). In this example from one of my apps, the user has tapped a button whose title is some‐ thing like “5 by 4” or “4 by 3”. I want to know both numbers; one tells me how many rows the layout is to have, the other how many columns. I use an NSScanner to locate the two numbers in the title: Some Foundation Classes | 253 NSString* s = [as buttonTitleAtIndex:ix]; NSScanner* sc = [NSScanner scannerWithString:s]; int rows, cols; [sc scanInt:&rows]; [sc scanUpToCharactersFromSet:[NSCharacterSet decimalDigitCharacterSet] intoString:nil]; [sc scanInt:&cols]; Here’s how I might do the same thing using a regular expression: NSString* s = [as buttonTitleAtIndex:ix]; int rowcol[2]; int* prowcol = rowcol; NSError* err = nil; NSRegularExpression* r = [NSRegularExpression regularExpressionWithPattern:@"\\d" options:0 error:&err]; // error-checking omitted for (NSTextCheckingResult* match in [r matchesInString:s options:0 range:NSMakeRange(0, [s length])]) *prowcol++ = [[s substringWithRange: [match range]] intValue]; The syntax seems oddly tortured, though, because we must convert each match from an NSTextCheckingResult to a range, then to a substring of our original string, and finally to an integer. More sophisticated automated textual analysis is supported by some additional classes, such as NSDataDetector, an NSRegularExpression subclass that efficiently finds certain types of string expression such as a URL or a phone number, and NSLinguisticTagger, which actually attempts to analyze text into its grammatical parts of speech. An NSString object’s string is immutable. You can use a string to generate another string in various ways, such as by appending another string or by extracting a substring, but you can’t alter the string itself. For that, you need NSString’s subclass, NSMutableString. NSString has convenience utilities for working with a file path string, and is often used in conjunction with NSURL, which is another Foundation class worth looking into. NSString and some other classes discussed in this section provide methods for writing out to a file’s contents or reading in a file’s contents; when they do, the file can be specified either as an NSString file path or as an NSURL (Chapter 36). An NSString carries no font and size information. Interface objects that display strings (such as UILabel) have a font property that is a UIFont; but this determines the single font and size in which the string will display. Before iOS 6, display of styled text — where different runs of text have different style attributes (size, font, color, and so forth) — was quite challenging. The NSAttributedString class, embodying a string along with style runs, required the use of Core Text (Chapter 23), and you had to lay out the styled text by drawing it yourself; you couldn’t display styled text in any standard interface object. 254 | Chapter 10: Cocoa Classes Starting in iOS 6, however, NSAttributedString is a full-fledged Objective-C class, with methods and supporting classes that allow you to style text and paragraphs easily in sophisticated ways — and the built-in interface objects that display text can display styled text. This is a major improvement. String drawing in a graphics context can be performed with methods provided through the UIStringDrawing category on NSString (see the String UIKit Additions Reference) and the NSStringDrawing category on NSAttributedString (see the NSAttributedString UIKit Additions Reference, new in iOS 6). NSAttributedString, along with its supporting classes (NSMutableAttributedString, NSParagraphStyle, NSMutableParagraphStyle) and its drawing commands, is discussed in Chapter 23. NSDate and Friends An NSDate is a date and time, represented internally as a number of seconds (NSTime‐ Interval) since some reference date. Calling [NSDate date] gives you a date object for the current date and time; other date operations may involve NSDateComponents and NSCalendar and can be a bit tricky because calendars are complicated (see the Date and Time Programming Guide; NSDateComponents examples appear in Chapter 25 and Chapter 32). You will also likely be concerned with dates represented as strings. Creation and parsing of date strings involves NSDateFormatter, which uses a format string similar to NSString’s stringWithFormat. A complication is added by the fact that the exact string representation of a date component or format can depend upon the user’s locale, con‐ sisting of language, region format, and calendar settings. (Actually, locale considerations can also play a role in NSString format strings.) In this example from one of my apps, I prepare the content of a UILabel reporting the date and time when our data was last updated. The app is not localized — the word “at” appearing in the string is always going to be in English — so I want complete control of the presentation of the date and time components as well. To get it, I have to insist upon a particular locale: NSDateFormatter *df = [NSDateFormatter new]; if ([[NSLocale availableLocaleIdentifiers] indexOfObject:@"en_US"] != NSNotFound) { NSLocale* loc = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]; [df setLocale:loc]; // English month name and time zone name if possible } [df setDateFormat:@"'Updated' d MMMM yyyy 'at' h:mm a z"]; [self setRefreshControlTitle:[df stringFromDate: [NSDate date]]]; // just now Locales are an interesting and complicated topic; to learn more, consult in your browser the documentation for ICU (International Components for Unicode), from which the Some Foundation Classes | 255 iOS support for creating and parsing date strings is derived. To study what locales exist, use the locale explorer at http://demo.icu-project.org/icu-bin/locexp. NSNumber An NSNumber is an object that wraps a numeric value (including BOOL). Thus, you can use it to store and pass a number where an object is expected. An NSNumber is formed from an actual number with a method that specifies the numeric type; for ex‐ ample, you can call numberWithInt: to form a number from an int: [[NSUserDefaults standardUserDefaults] registerDefaults: [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt: 4], @"cardMatrixRows", [NSNumber numberWithInt: 3], @"cardMatrixColumns", nil]]; As I mentioned in Chapter 5, LLVM compiler version 4.0 (Xcode 4.4) brought with it a new syntax for forming a new NSNumber instance: • Precede a literal number (or BOOL) with @. To specify further the numeric type, follow the literal number with U (unsigned integer), L (long integer), LL (long long integer), or F (float). (There is no NSNumber wrapper for an unsigned long.) For example, @3.1415 is equivalent to [NSNumber numberWithDouble:3.1415]; @YES is equivalent to [NSNumber numberWithBool:YES]. • If an expression yields a number, wrap it in parentheses and precede the left pa‐ renthesis with @. For example, if height and width are floats, @(height/width) is equivalent to [NSNumber numberWithFloat: height/width]. Thus, the preceding example can be rewritten like this: [[NSUserDefaults standardUserDefaults] registerDefaults: [NSDictionary dictionaryWithObjectsAndKeys: @4, @"cardMatrixRows", @3, @"cardMatrixColumns", nil]]; (There is also a new NSDictionary literal syntax, so it will turn out, a few pages from now, that we can rewrite that code even more compactly.) An NSNumber is not itself a number, however, so you still can’t use it in calculations or where an actual number is expected. Instead, you must explicitly extract the number from its NSNumber wrapper using the inverse of the method that wrapped the number to begin with. Knowing what that method was is up to you. So, for example, if an NSNumber wraps an int, you can call intValue to extract the int: 256 | Chapter 10: Cocoa Classes NSUserDefaults* ud = [NSUserDefaults standardUserDefaults]; int therows = [[ud objectForKey:@"cardMatrixRows"] intValue]; int thecols = [[ud objectForKey:@"cardMatrixColumns"] intValue]; Actually, this is such a common transformation when communicating with NSUser‐ Defaults that it provides convenience methods. So I could have written the same thing this way: NSUserDefaults* ud = [NSUserDefaults standardUserDefaults]; int therows = [ud integerForKey:@"cardMatrixRows"]; int thecols = [ud integerForKey:@"cardMatrixColumns"]; An NSNumber subclass, NSDecimalNumber, can be used in calculations, thanks to a bunch of arithmetic methods (or their C equivalent functions, which are faster). This is useful particularly for rounding, because there’s a handy way to specify exactly the desired rounding behavior. NSValue NSValue is NSNumber’s superclass. Use it for wrapping nonnumeric C values such as structs. Convenience methods provided through the NSValueUIGeometryExtensions category on NSValue (see the NSValue UIKit Additions Reference) allow easy wrapping and unwrapping of CGPoint, CGSize, CGRect, CGAffineTransform, UIEdgeInsets, and UIOffset; additional categories allow easy wrapping and unwrapping of CATrans‐ form3D, CMTime, CMTimeMapping, CMTimeRange, MKCoordinate, and MKCoordinateSpan. You are unlikely to need to store any other kind of C value in an NSValue, but you can if you need to. NSData NSData is a general sequence of bytes; basically, it’s just a buffer, a chunk of memory. It is immutable; the mutable version is its subclass NSMutableData. In practice, NSData tends to arise in two main ways: • When downloading data from the Internet. For example, the NSURLConnection class supplies whatever it retrieves from the Internet as NSData. Transforming it from there into (let’s say) a string, specifying the correct encoding, would then be up to you. • When storing an object as a file or in user preferences. For example, you can’t store a UIColor value directly into user preferences. So if the user has made a color choice and you need to save it, you transform the UIColor into an NSData (using NSKeyedArchiver) and save that: Some Foundation Classes | 257 [[NSUserDefaults standardUserDefaults] registerDefaults: [NSDictionary dictionaryWithObjectsAndKeys: [NSKeyedArchiver archivedDataWithRootObject:[UIColor blueColor]], @"myColor", nil]]; The use of NSKeyedArchiver, and its reversal with NSKeyedUnarchiver, is dis‐ cussed further in Chapter 19 and Chapter 36. Equality and Comparison The foregoing types will quickly come to seem to you like basic data types, but of course they are actually object types — which means that they are pointers (Chapter 3) There‐ fore you cannot compare them using the C operators for testing equality as you would with actual numbers. That’s because, in the case of object types, the C operators compare the pointers, not the object content of the instances. For example: NSString* s1 = [NSString stringWithFormat:@"%@, %@", @"Hello", @"world"]; NSString* s2 = [NSString stringWithFormat:@"%@, %@", @"Hello", @"world"]; if (s1 == s2) // false // ... The two strings are equivalent (@"Hello, world") but are not the same object. (The example is deliberately elaborate because Cocoa’s efficient management of string literals sees to it that two strings initialized directly as @"Hello, world" are the same object, which wouldn’t illustrate the point I’m making.) It is up to individual classes to imple‐ ment a test for equality. The general test, isEqual:, is inherited from NSObject and overridden, but some classes also define more specific and efficient tests. Thus, the correct way to perform the above test is like this: if ([s1 isEqualToString: s2]) Similarly, it is up to individual classes to supply ordered comparison methods. The standard method is called compare:, and returns one of three constants: NSOrderedAscending (the receiver is less than the argument), NSOrderedSame (the receiver is equal to the argument), or NSOrderedDescending (the receiver is greater than the argument); for an example, see Example 3-2. NSIndexSet NSIndexSet expresses a collection of unique whole numbers; its purpose is to express element numbers of an ordered collection, such as an NSArray. Thus, for instance, to retrieve multiple objects simultaneously from an array, you specify the desired indexes as an NSIndexSet. It is also used with other things that are array-like; for example, you pass an NSIndexSet to a UITableView to indicate what sections to insert or delete. 258 | Chapter 10: Cocoa Classes To take a specific example, let’s say you want to speak of elements 1, 2, 3, 4, 8, 9, and 10 of an NSArray. NSIndexSet expresses this notion in some compact implementation that can be readily queried. The actual implementation is opaque, but you can imagine that in this case the set might consist of two NSRange structs, {1,4} and {8,3}, and NSIndexSet’s methods actually invite you to think of an NSIndexSet as composed of ranges. An NSIndexSet is immutable; its mutable subclass is NSMutableIndexSet. You can form a simple NSIndexSet consisting of just one contiguous range directly, by passing an NSRange to indexSetWithIndexesInRange:; but to form a more complex index set you’ll need to use NSMutableIndexSet so that you can append additional ranges. To walk through (enumerate) the index values or ranges specified by an NSIndexSet, call enumerateIndexesUsingBlock: or enumerateRangesUsingBlock: or their var‐ iants. NSArray and NSMutableArray An NSArray is an ordered collection of objects. Its length is its count, and a particular object can be obtained by index number using objectAtIndex:. The index of the first object is zero, so the index of the last object is count minus one. Starting with LLVM compiler version 4.0 (Xcode 4.5), it is no longer necessary to call objectAtIndex:; instead, you can use a notation reminiscent of C and other languages that have arrays, namely, append square brackets containing the index number to the array reference (subscripting). So, for example, if pep contains @"Manny", @"Moe", and @"Jack", then pep[2] yields @"Jack"; it is equivalent to [pep objectAtIndex:2]. Okay, I lied; actually, pep[2] is equivalent to [pep objectAtIndexedSubscript:2]. That’s because the subscripting notation causes any reference to which the subscript is appended to be sent objectAtIndexedSubscript:. This in turn means that any class can implement objectAtIndexedSubscript: and become eligible for subscripting notation — including your classes. Note that this method must be publicly declared for the compiler to permit the subscripting notation. You can form an NSArray in various ways, but typically you’ll start by supplying a list of the objects it is to contain. As I mentioned in Chapter 3, a new Objective-C literal syntax (starting with LLVM compiler version 4.0, Xcode 4.4 or later) lets you wrap this list in @[...] as a way of generating the NSArray: NSArray* pep = @[@"Manny", @"Moe", @"Jack"]; An NSArray is immutable. This doesn’t mean you can’t mutate any of the objects it contains; it means that once the NSArray is formed you can’t remove an object from it, insert an object into it, or replace an object at a given index. To do those things, you can Some Foundation Classes | 259 derive a new array consisting of the original array plus or minus some objects, or use NSArray’s subclass, NSMutableArray. NSMutableArray’s addObject: and replaceObjectAtIndex:withObject: are supple‐ mented by the same subscripting notation that applies to NSArray. In this case, though, the subscripted reference is an lvalue — you’re assigning to it: pep[3] = @"Zelda"; That causes the NSMutableArray to be sent setObject:atIndexedSubscript:. The way NSMutableArray implements this, if pep has three elements, pep[3] = @"Zelda" is equivalent to addObject: (you’re appending to the end of the array); if pep has more than three elements, it’s equivalent to replaceObjectAtIndex:withObject:. (If pep has fewer than three elements, an exception is thrown.) You can walk through (enumerate) every object in an array with the for...in construct described in Chapter 1. (You’ll get an exception if you try to mutate an array while enumerating it.) You can seek an object within an array with indexOfObject: or indexOfObjectIdenticalTo:; the former’s idea of equality is to call isEqual:, whereas the latter uses pointer equality. Those familiar with other languages may miss such utility array functions as map, which builds a new array of the results of calling a method on each object in the array. (makeObjectsPerformSelector: requires a selector that returns no value, and enumerateObjectsUsingBlock: requires a block function that returns no value.) The usual work‐ around is to make an empty mutable array and then enumerate the original array, calling a method and appending each result to the mutable array (Example 10-1). It is also sometimes possible to use key–value coding as a map substitute (see Chapter 12). Example 10-1. Building an array by enumerating another array NSMutableArray* marr = [NSMutableArray array]; for (id obj in myArray) { id result = [obj doSomething]; [marr addObject: result]; } You can filter an array to produce a new array consisting of just those objects meeting a test that can be described as an NSPredicate: NSArray* pep = @[@"Manny", @"Moe", @"Jack"]; NSPredicate* p = [NSPredicate predicateWithFormat:@"self BEGINSWITH[cd] 'm'"]; NSArray* ems = [pep filteredArrayUsingPredicate:p]; To search or filter an array on a more customized test, you can walk through the array applying the test and adding those that meet it to an NSMutableArray (similar to 260 | Chapter 10: Cocoa Classes Example 10-1). And there are many methods that give you the ability to search or filter an array using a block: NSArray* pep = @[@"Manny", @"Moe", @"Jack"]; NSArray* ems = [pep objectsAtIndexes: [pep indexesOfObjectsPassingTest: ^BOOL(id obj, NSUInteger idx, BOOL *stop) { return ([(NSString*)obj rangeOfString:@"m" options:NSCaseInsensitiveSearch].location == 0); }]]; You can derive a sorted version of the array, supplying the sorting rules in various ways, or if it’s a mutable array, you can sort it directly; see Example 3-1 and Example 3-2. Forming a new array from some or all of the elements of an existing array is not an expensive operation. The objects constituting the ele‐ ments of the first array are not copied; the new array consists merely of a new set of pointers to the already existing objects. The same is true for the other collection types I’m about to discuss. NSSet and Friends An NSSet is an unordered collection of distinct objects. “Distinct” means that no two objects in a set can return YES when they are compared using isEqual:. Learning whether an object is present in a set is much more efficient than seeking it in an array, and you can ask whether one set is a subset of, or intersects, another set. You can walk through (enumerate) a set with the for...in construct, though the order is of course undefined. You can filter a set, as you can an array. Indeed, much of what you can do with a set is parallel to what you can do with an array, except that of course you can’t do anything with a set that involves the notion of ordering. To escape even that restriction, you can use an ordered set. An ordered set (NSOrdered‐ Set) is very like an array, and the methods for working with it are very similar to the methods for working with an array — NSOrderedSet even implements objectAtIndexedSubscript:, so you can fetch an element by subscripting. But an ordered set’s elements must be distinct. Handing an array over to an ordered set uniques the array, meaning that order is maintained but only the first occurrence of an equal object is moved to the set. An ordered set provides many of the advantages of sets: for example, as with an NSSet, learning whether an object is present in an ordered set is much more efficient than for an array, and you can readily take the union, intersection, or difference with another set. Since the distinctness restriction will often prove no restriction at all (because the elements were going to be distinct anyway), it is likely that programmers will want to get into the habit of using NSOrderedSet instead of NSArray wherever possible. Some Foundation Classes | 261 An NSSet is immutable. You can derive one NSSet from another by adding or removing elements, or you can use its subclass, NSMutableSet. Similarly, NSOrderedSet has its mutable counterpart, NSMutableOrderedSet (which implements setObject:atIndexedSubscript:). There is no penalty for adding to, or inserting into, a mutable set an object that the set already contains; nothing is added (and so the distinctness rule is enforced), but there’s no error. NSCountedSet, a subclass of NSMutableSet, is a mutable unordered collection of objects that are not necessarily distinct (this concept is usually referred to as a bag). It is im‐ plemented as a set plus a count of how many times each element has been added. NSDictionary and NSMutableDictionary An NSDictionary is an unordered collection of key–value pairs. The key is usually an NSString, though it doesn’t have to be. The value can be any object. An NSDictionary is immutable; its mutable subclass is NSMutableDictionary. The keys of a dictionary are distinct (using isEqual: for comparison). If you add a key– value pair to an NSMutableDictionary, then if that key is not already present, the pair is simply added, but if the key is already present, then the corresponding value is re‐ placed. The fundamental use of an NSDictionary is to request an entry’s value by key (using objectForKey:); if no such key exists, the result is nil, so this is also the way to find out whether a key is present. A dictionary is thus an easy, flexible data storage device, an object-based analogue to a struct. Cocoa often uses a dictionary to provide you with an extra packet of named values, as in the userInfo of an NSNotification, the options parameter of application:didFinishLaunchingWithOptions:, and so on. The same Objective-C modernizations that brought us array literals and subscripting have brought us dictionary literals and subscripting. In addition to forming a dictionary from an array of objects and an array of keys (dictionaryWithObjects:forKeys:) or as a nil-terminated list of alternating objects and keys (dictionaryWithObjectsAndKeys:), a dictionary may be formed literally as a comma-separated list of key–value pairs, each key followed by a colon and the value, and wrapped in @{...}. Thus, recall our earlier NSUserDefaults example: [[NSUserDefaults standardUserDefaults] registerDefaults: [NSDictionary dictionaryWithObjectsAndKeys: @4, @"cardMatrixRows", @3, @"cardMatrixColumns", nil]]; That can be rewritten like this: 262 | Chapter 10: Cocoa Classes [[NSUserDefaults standardUserDefaults] registerDefaults: @{@"cardMatrixRows":@4, @"cardMatrixColumns":@3}]; To fetch a value from a dictionary by its key, instead of calling objectForKey:, you can now subscript the key in square brackets to the dictionary reference: dict[key]. Sim‐ ilarly, to add a key–value pair to an NSMutableDictionary, instead of calling setObject:forKey:, you can assign to the subscripted dictionary reference. Parallel to NSArray, this is accomplished behind the scenes by calling objectForKeyedSubscript: and setObject:forKeyedSubscript:, and your own classes can declare these methods and be eligible for keyed subscripting notation. Data structures such as an array of dictionaries, a dictionary of dictionaries, and so forth, are extremely common, and will often lie at the heart of an app’s functionality. Here’s an example from one of my own apps. The app bundle contains a text file laid out like this: chapterNumber [tab] pictureName [return] chapterNumber [tab] pictureName [return] As the app launches, I load this text file and parse it into a dictionary, each entry of which has the following structure: key: (chapterNumber, as an NSNumber) value: [Mutable Array] (pictureName) (pictureName) ... Thus, as we walk the text file, we end up with all pictures for a chapter collected under the number of that chapter. This makes it easy for me later to present all the pictures for a given chapter. For each line of the text file, if the dictionary entry for that chapter number doesn’t exist, we create it, with an empty mutable array as its value. Whether that dictionary entry existed or not, it does now, and its value is a mutable array, so we append the picture name to that mutable array. Observe how this single typical example (Example 10-2) brings together many of the Foundation classes discussed in this section. Example 10-2. Parsing a file with Foundation classes NSString* f = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"txt"]; NSError* err = nil; NSString* s = [NSString stringWithContentsOfFile:f encoding:NSUTF8StringEncoding error:&err]; // error-checking omitted NSMutableDictionary* d = [NSMutableDictionary dictionary]; for (NSString* line in [s componentsSeparatedByString:@"\n"]) { NSArray* items = [line componentsSeparatedByString:@"\t"]; NSInteger chnum = [items[0] integerValue]; NSNumber* key = @(chnum); NSMutableArray* marr = d[key]; Some Foundation Classes | 263 if (!marr) { // no such key, create key–value pair marr = [NSMutableArray array]; d[key] = marr; } // marr is now a mutable array, empty or otherwise NSString* picname = items[1]; [marr addObject: picname]; } You can get from an NSDictionary a list of keys, a sorted list of keys, or a list of values. You can walk through (enumerate) a dictionary by its keys with the for...in construct, though the order is of course undefined. A dictionary also supplies an objectEnumerator, which you can use with the for...in construct to walk through just the values. You can also walk through the key–value pairs together using a block, and you can even filter an NSDictionary by some test against its values. Migrating to Modern Objective-C If you have old code that you’d like to convert to use the modern NSNumber, NSArray, and NSDictionary literal Objective-C syntax, and to use array and dictionary subscripting, you can do so with no work whatever. Simply choose Edit → Refactor → Convert to Modern Objective-C Syntax. NSNull NSNull does nothing but supply a pointer to a singleton object, [NSNull null]. Use this singleton object to stand for nil in situations where an actual object is required and nil is not permitted. For example, you can’t use nil as the value of an element of a collection (such as NSArray, NSSet, or NSDictionary), so you’d use [NSNull null] instead. Despite what I said earlier about equality, you can test an object against [NSNull null] using the C equality operator, because this is a singleton instance and therefore pointer comparison works. Immutable and Mutable Beginners sometimes have difficulty with the Foundation’s immutable/mutable class pairs, so here are some hints. The documentation may not make it completely obvious that the mutable classes obey and, if appropriate, override the methods of the immutable classes. Thus, for example, [NSArray array] generates an immutable array, but [NSMutableArray array] gener‐ ates a mutable array. (You will look in vain for the expected [NSMutableArray mutable- 264 | Chapter 10: Cocoa Classes Array].) The same is true of all the initializers and convenience class methods for in‐ stantiation: they may all have “array” in their name, but when sent to NSMutableArray, they yield a mutable array. That fact also answers the question of how to make an immutable array mutable, and vice versa. If arrayWithArray:, sent to the NSArray class, yields a new immutable array containing the same objects in the same order as the original array, then the same method, arrayWithArray:, sent to the NSMutableArray class, yields a mutable array containing the same objects in the same order as the original. Thus this single method can transform an array between immutable and mutable in either direction. You can also use copy (produces an immutable copy) and mutableCopy (produces a mutable copy). All of the above applies equally, of course, to the other immutable/mutable class pairs. You will often want to work internally and temporarily with a mutable instance but then store (and possibly vend, as an instance variable) an immutable instance, thus protecting the value from being changed accidentally or behind your own back. What matters is not a variable’s declared class but what class the instance really is (polymorphism; see Chapter 5), so it’s good that you can easily switch between an immutable and a mutable version of the same data. To test whether an instance is mutable or immutable, do not ask for its class. These immutable/mutable class pairs are all implemented as class clusters, which means that Cocoa uses a secret class, different from the documented class you work with. This secret class is subject to change without notice, because it’s none of your business and you should never have looked at it in the first place. Thus, code of this form is subject to breakage: if ([NSStringFromClass([n class]) isEqualToString: @"NSCFArray"]) // wrong! Instead, to learn whether an object is mutable, ask it whether it responds to a mutability method: if ([n respondsToSelector:@selector(addObject:)]) // right Here’s a reminder: just because a collection class is immutable doesn’t mean that the objects it collects are immutable. They are still objects and do not lose any of their normal behavior merely because they are pointed to by an immutable collection. Property Lists A property list is a string (XML) representation of data. The Foundation classes NSString, NSData, NSArray, and NSDictionary are the only classes that can be con‐ verted into a property list. Moreover, an NSArray or NSDictionary can be converted Some Foundation Classes | 265 into a property list only if the only classes it collects are these classes, along with NSDate and NSNumber. (This is why, as mentioned earlier, you must convert a UIColor into an NSData in order to store it in user defaults; the user defaults is a property list.) The primary use of a property list is to store data as a file. NSArray and NSDictionary provide convenience methods writeToFile:atomically: and writeToURL:atomically: that generate property list files given a pathname or file URL, re‐ spectively; they also provide inverse convenience methods that initialize an NSArray object or an NSDictionary object based on the property list contents of a given file. For this very reason, you are likely to start with one of these classes when you want to create a property list. (NSString and NSData, with their methods writeToFile:... and writeToURL:..., just write the data out as a file directly, not as a property list.) When you initialize an NSArray or NSDictionary from a property list file in this way, the objects in the collection are all immutable. If you want them to be mutable, or if you want to convert an instance of one of the other property list classes to a property list, you’ll use the NSPropertyListSerialization class (see the Property List Programming Guide). The Secret Life of NSObject Because every class inherits from NSObject, it’s worth taking some time to investigate and understand NSObject. NSObject is constructed in a rather elaborate way: • It defines some native class methods and instance methods having mostly to do with the basics of instantiation and of method sending and resolution. (See the NSObject Class Reference.) • It adopts the NSObject protocol. This protocol declares instance methods having mostly to do with memory management, the relationship between an instance and its class, and introspection. Because all the NSObject protocol methods are re‐ quired, the NSObject class implements them all. (See the NSObject Protocol Refer‐ ence.) This architecture is what permits NSProxy to be a root class; it, too, adopts the NSObject protocol. • It implements convenience methods related to the NSCopying, NSMutable‐ Copying, and NSCoding protocols, without formally adopting those protocols. NSObject intentionally doesn’t adopt these protocols because this would cause all other classes to adopt them, which would be wrong. But thanks to this architecture, if a class does adopt one of these protocols, you can call the corresponding conve‐ nience method. For example, NSObject implements the copy instance method, so you can call copy on any instance, but you’ll crash unless the instance’s class adopts the NSCopying protocol and implements copyWithZone:. 266 | Chapter 10: Cocoa Classes • A large number of methods are injected into NSObject by more than two dozen categories on NSObject, scattered among various header files. For example, awakeFromNib (see Chapter 7) comes from the UINibLoadingAdditions category on NSObject, declared in UINibLoading.h. And performSelector:withObject:afterDelay:, discussed in Chapter 11, comes from the NSDelayed‐ Performing category on NSObject, declared in NSRunLoop.h. • A class object, as explained in Chapter 4, is an object. Therefore all classes, which are objects of type Class, inherit from NSObject. Therefore, any method defined as an instance method by NSObject can be called on a class object as a class method! For example, respondsToSelector: is defined as an instance method by NSObject, but it can (therefore) be treated also as a class method and sent to a class object. The problem for the programmer is that Apple’s documentation is rather rigid about classification. When you’re trying to work out what you can say to an object, you don’t care where that object’s methods come from; you just care what you can say. But Apple differentiates methods by where they come from. Even though NSObject is the root class, the most important class, from which all other classes inherit, no single page of the documentation provides a conspectus of all its methods. Instead, you have to look at both the NSObject Class Reference and the NSObject Protocol Reference simultaneously, plus the pages documenting the NSCopying, NSMutableCopying, and NSCoding protocols (in order to understand how they interact with methods defined by NSObject), plus you have to supply mentally a class method version of every NSObject instance method! Of the methods injected into NSObject by categories, many are delegate methods used in restricted situations (so that these are really informal protocols), and do not need centralized documentation; for example, animationDidStart: is documented under the CAAnimation class, quite rightly, because you need to know about it only and exactly when you’re working with CAAnimation. Others that are general in nature are docu‐ mented on the NSObject class documentation page itself; for example, cancelPreviousPerformRequestsWithTarget: comes from a category declared in NSRunLoop.h, but it is documented under NSObject, quite rightly, since this is a class method, and there‐ fore effectively a global method, that you might want to send at any time. However, every object responds to awakeFromNib, and it’s likely to be crucial to every app you write; yet you must learn about it outside of the NSObject documentation, sitting all by itself in the NSObject UIKit Additions Reference page, where you’re extremely unlikely to discover it! The same goes, it might be argued, for all the key–value coding methods (Chapter 12) and key–value observing methods (Chapter 13). Once you’ve collected, by hook or by crook, all the NSObject methods, you can see that they fall into a certain natural classification, much as outlined in Apple’s documentation (see also “The Root Class” in the “Cocoa Objects” section of the Cocoa Fundamentals Guide): The Secret Life of NSObject | 267 Creation, destruction, and memory management Methods for creating an instance, such as alloc and copy, along with methods that you might override in order to learn when something is happening in the lifetime of an object, such as initialize (see Chapter 11) and dealloc (see Chapter 12), plus methods that manage memory (see Chapter 12). Class relationships Methods for learning an object’s class and inheritance, such as class, superclass, isKindOfClass:, and isMemberOfClass:. To check the class of an instance (or class), use methods such as isKindOfClass: and isMemberOfClass:. Direct comparison of two class objects, as in [someObject class] == [otherObject class], is rarely advisable, especially because a Cocoa instance’s class might be a private, undocumented subclass of the class you expect. I mentioned this already in connection with class clusters, and it can happen in other cases. Object introspection and comparison Methods for asking what would happen if an object were sent a certain message, such as respondsToSelector:; for representing an object as a string (description, used in debugging; see Chapter 9); and for comparing objects (isEqual:). Message response Methods for meddling with what does happen when an object is sent a certain message, such as doesNotRecognizeSelector:. If you’re curious, see the ObjectiveC Runtime Programming Guide. An example appears in Chapter 25. Message sending Methods for sending a message indirectly. For example, performSelector: takes a selector as parameter, and sending it to an object tells that object to perform that selector. This might seem identical to just sending that message to that object, but what if you don’t know what message to send until runtime? Moreover, variants on performSelector: allow you send a message on a specified thread (Chapter 38), or send a message after a certain amount of time has passed (performSelector:withObject:afterDelay: and similar). 268 | Chapter 10: Cocoa Classes CHAPTER 11 Cocoa Events None of your code runs until Cocoa calls it. The art of Cocoa programming consists largely of knowing when and why Cocoa will call your code. If you know this, you can put your code in the correct place, with the correct method name, so that your code runs at the correct moment, and your app behaves the way you intend. In Chapter 7, for example, we wrote a method to be called when the user taps a certain button in our interface, and we also arranged things so that that method would be called when the user taps that button: - (void) buttonPressed: (id) sender { // ... react to the button being pressed } This architecture typifies the underpinnings of a Cocoa program. Your code itself is like a panel of buttons, waiting for Cocoa to press one. If something happens that Cocoa feels your code needs to know about and respond to, it presses the right button — if the right button is there. You organize your code with Cocoa’s behavior in mind. Cocoa makes certain promises about how and when it will dispatch messages to your code. These are Cocoa’s events. You know what these events are, and you arrange for your code to be ready when Cocoa delivers them. Thus, to program for Cocoa, you must, in a sense, surrender control. Your code never gets to run just whenever it feels like it. It can run only in response to some kind of event. Something happens, such as the user making a gesture on the screen, or some specific stage arriving in the lifetime of your app, and Cocoa dispatches an event to your code — if your code is prepared to receive it. So you don’t write just any old code you want to and put it in any old place. You use the framework, by letting the framework use you. You submit to Cocoa’s rules and promises and expectations, so that your code will be called at the right time and in the right way. 269 The specific events that you can receive are listed in the documentation. The overall architecture of how and when events are dispatched and the ways in which your code arranges to receive them is the subject of this chapter. Reasons for Events Broadly speaking, the reasons you might receive an event may be divided informally into four categories. These categories are not official; I made them up. Often it isn’t completely clear which of these categories an event fits into; an event may well appear to fit two categories. But they are still generally useful for visualizing how and why Cocoa interacts with your code: User events The user does something interactive, and an event is triggered directly. Obvious examples are events that you get when the user taps or swipes the screen, or types a key on the keyboard. Lifetime events These are events notifying you of the arrival of a stage in the life of the app, such as the fact that the app is starting up or is about to go into the background, or of a component of the app, such as the fact that a UIViewController’s view has just loaded or is about to be removed from the screen. Functional events Cocoa is about to do something, and turns to you in case you want to supply ad‐ ditional functionality. I would put into this category things like UIView’s drawRect: (your chance to have a view draw itself) and UILabel’s drawTextInRect: (your chance to modify the look of a label), with which we experimented in Chap‐ ter 10. Query events Cocoa turns to you to ask a question; its behavior will depend upon your answer. For example, the way data appears in a table (a UITableView) is that whenever Cocoa needs a cell for a row of the table, it turns to you and asks for the cell. Subclassing A built-in Cocoa class may define methods that Cocoa itself will call and that you are invited (or required) to override in a subclass, so that your custom behavior, and not (merely) the default behavior, will take place. An example I gave in Chapter 10 was UIView’s drawRect:. This is what I call a functional event. By overriding drawRect: in a UIView subclass, you dictate the full procedure by which a view draws itself. You don’t know exactly when this method will be called, and you don’t care; when it is, you draw, and this guarantees that the view will always appear 270 | Chapter 11: Cocoa Events the way you want it to. (You never call drawRect: yourself; if some underlying condition has changed and you want the view to be redrawn, you call setNeedsDisplay and let Cocoa call drawRect: in response.) Built-in UIView subclasses may have other functional event methods you’ll want to customize through subclassing. Typically this will be in order to change the way the view is drawn, without taking command of the entire drawing procedure yourself. In Chapter 10 I gave an example involving UILabel and its drawTextInRect:. Another example is UISlider, which lets you customize the position and size of the slider’s “thumb” by overriding thumbRectForBounds:trackRect:value: (Chapter 25). UIViewController (Chapter 19) is a good example of a class meant for subclassing. Of the methods listed in the UIViewController class documentation, just about all are methods you might have reason to override. If you create a UIViewController subclass in Xcode, you’ll see that the template already includes a few methods to get you started; these are all method overrides. For example, viewDidLoad is called to let you know that your view controller’s view has loaded, so you can perform initializations; it’s an obvious example of a lifetime event. A UIViewController method like supportedInterfaceOrientations is what I call a query event. Your job is to return a bitmask telling Cocoa what orientations your view can appear in at this moment — whenever that may be. You don’t know exactly when this method will be called, and you don’t care; you trust Cocoa to call it at the appropriate moments, so that if the user rotates the device, your app will or won’t be rotated to compensate, depending on what value you return. When looking for events that you can receive through subclassing, be sure to look upward though the inheritance hierarchy. For example, if you’re wondering how to be notified when your custom UILabel subclass is embedded into another view, you won’t find the answer in the UILabel class documentation; a UILabel receives the appropriate event by virtue of being a UIView. In the UIView class documentation, you’ll learn that you can override didMoveToSuperview to be informed when this happens. Even further up the inheritance hierarchy, you’ll find things like NSObject’s initialize class method. Before any class is sent its first class message (including instantiation), it is sent the initialize message. Thus, initialize can be overridden in order to run code extremely early in a class’s lifetime (before it even has an instance). Your project’s application delegate class (such as AppDelegate in our Empty Window project) is in‐ stantiated very early in the app’s lifetime, so its initialize can be a good place to perform very early app initializations, such as setting default values for any user pref‐ erences. When implementing initialize, we must test, as a matter of course, whether self really is the class in question (and this is one of the few situations in which we will compare two classes directly against one another); otherwise there is a chance that Subclassing | 271 initialize will be called again (and our code will run again) if a subclass of this class is used: // MyClass.m: + (void)initialize { if (self == [MyClass class]) { // do stuff } } Notifications Cocoa provides your app with a single instance of NSNotificationCenter, informally called the notification center, and available as [NSNotificationCenter defaultCenter]. This instance is the basis of a mechanism for sending messages called notifi‐ cations. A notification includes an instance of NSNotification (a notification object). The idea is that any object can be registered with the notification center to receive certain notifications. Another object can hand the notification center a notification object to send out (this is called posting the notification). The notification center will then send that notification object, in a notification, to all objects that are registered to receive it. The notification mechanism is often described as a dispatching or broadcasting mech‐ anism, and with good reason. It lets an object send a message without knowing or caring what object or how many objects receive it. This relieves your app’s architecture from the formal responsibility of somehow hooking up instances just so a message can pass from one to the other (which can sometimes be quite tricky or onerous, as discussed in Chapter 13). When objects are conceptually “distant” from one another, notifications can be a fairly lightweight way of permitting one to message the other. An NSNotification object has three pieces of information associated with it, which can be retrieved by instance methods: name An NSString which specifies the notification’s meaning. object An instance associated with the notification; typically, the instance that posted it. userInfo Not every notification has a userInfo; it is an NSDictionary, and can contain ad‐ ditional information associated with the notification. What information this NSDictionary will contain, and under what keys, depends on the particular noti‐ fication; you have to consult the documentation. For example, the documentation tells us that UIApplication’s UIApplicationDidChangeStatusBarFrameNotification includes a userInfo dictionary with a key UIApplicationStatusBarFrameUserInfoKey whose value is the status bar’s frame. When you post a no‐ 272 | Chapter 11: Cocoa Events tification yourself, you can put anything you like into the userInfo for the notifi‐ cation’s recipient(s) to retrieve. Receiving a Built-In Notification Cocoa itself posts notifications through the notification center, and your code can reg‐ ister to receive them. You’ll find a separate Notifications section in the documentation for a class that provides them. To register for a notification, you send one of two messages to the notification center. One is addObserver:selector:name:object:. The parameters are as follows: addObserver: The instance to which the notification is to be sent. This will typically be self; it isn’t usual for one instance to register a different instance as the receiver of a noti‐ fication. selector: The message to be sent to the observer instance when the notification occurs. The designated method should return void and should take one parameter, which will be the NSNotification object (so the parameter should be typed as NSNotification* or id). Don’t forget to implement this method! If the notification center sends a notification by sending the message specified as the selector: here, and there is no method implemented to receive this message, your app will crash. Failing to specify the selector: accurately is a common beginner mistake (and the compiler doesn’t save you from yourself). name: The NSString name of the notification you’d like to receive. If this parameter is nil, you’re asking to receive all notifications sent by the object designated in the object: parameter. A built-in Cocoa notification’s name is usually a constant. As I explained in Chapter 1, this is helpful, because if you flub the name of a constant, the compiler will complain, whereas if you enter the name of the notification directly as an NSString literal and you get it wrong, the compiler won’t complain but you will mysteriously fail to get any notifications (because no notification has the name you actually entered) — a very difficult sort of mistake to track down. object: The object of the notification you’re interested in, which will usually be the object that posted it. If this is nil, you’re asking to receive all notifications with the name designated in the name parameter. (If both the name: and object: parameters are nil, you’re asking to receive all notifications!) For example, in one of my apps I need to respond, by changing my interface, if the device’s music player starts playing a different song. The API for the device’s built-in Notifications | 273 music player belongs to the MPMusicPlayerController class (Chapter 29); this class provides a notification to tell me when the built-in music player changes its playing state, listed under Notifications in the MPMusicPlayerController’s class documentation as MPMusicPlayerControllerNowPlayingItemDidChangeNotification. It turns out, looking at the documentation, that this notification won’t be posted at all unless I call MPMusicPlayerController’s beginGeneratingPlaybackNotifications instance method. This architecture is not uncommon; Cocoa saves itself some time and effort by not sending out certain notifications unless they are switched on, as it were. So my first job is to get an instance of MPMusicPlayerController and call this method: MPMusicPlayerController* mp = [MPMusicPlayerController iPodMusicPlayer]; [mp beginGeneratingPlaybackNotifications]; Now I register myself to receive the desired playback notification: [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(nowPlayingItemChanged:) name:MPMusicPlayerControllerNowPlayingItemDidChangeNotification object:nil]; So now, whenever an MPMusicPlayerControllerNowPlayingItemDidChangeNotification is posted, my nowPlayingItemChanged: method will be called: - (void) nowPlayingItemChanged: (NSNotification*) n { MPMusicPlayerController* mp = [MPMusicPlayerController iPodMusicPlayer]; self->_nowPlayingItem = mp.nowPlayingItem; // ... and so on ... } The other way to register to receive a notification is by calling addObserverForName:object:queue:usingBlock:. Its name: and object: parameters are just like those of addObserver:selector:name:object:, but it doesn’t specify an observer and it doesn’t specify a selector. Instead, you provide a block — the actual code to be executed when the notification fires. There is no need to specify an observer, and there is no userInfo: parameter, because you’re providing a block: the code that will be called is this block, right here, and there can be no difficulty providing the block’s code with whatever values it needs. (This method also returns a value, whose purpose I’ll explain in a mo‐ ment.) This way of registering for a notification has some tremendous advantages. For addObserver:selector:name:object: to work properly, you must get the selector right and make sure you implement the corresponding method. With a block, there is no selector and there is no separate method; everything happens right there in the block, like this: 274 | Chapter 11: Cocoa Events MPMusicPlayerController* mp = [MPMusicPlayerController iPodMusicPlayer]; [mp beginGeneratingPlaybackNotifications]; id ob = [[NSNotificationCenter defaultCenter] addObserverForName:MPMusicPlayerControllerNowPlayingItemDidChangeNotification object:nil queue:nil usingBlock:^(NSNotification *n) { self->_nowPlayingItem = mp.nowPlayingItem; // ... and so on ... } }]; Consider how maintainable and understandable that code is. Heavy use of addObserver:selector:name:object: means that your code ends up peppered with methods that exist solely in order to be called by the notification center. But there is nothing about these methods that tells you what they are for — you will probably want to use explicit comments in order to remind yourself — and the methods are separate from the registration call, all of which makes your code very method-heavy and con‐ fusing. With a block, on the other hand, the whole purpose of the registration is crystalclear, because the block accompanies it. And notice how, in the block, I don’t have to redefine mp as I did in the separate method nowPlayingItemChanged:; it is still in scope from where it was defined a couple of lines earlier. Blocks are so convenient! Unregistering It is up to you, for every object that you register as a recipient of notifications, to un‐ register that object before it goes out of existence. If you fail to do this, and if the object does go out of existence, and if a notification for which that object is registered is posted, the notification center will attempt to send the appropriate message to that object, which is now missing in action. The result will be a crash at best, and chaos at worst. To unregister an object as a recipient of notifications, send the notification center the removeObserver: message. (Alternatively, you can unregister an object for just a specific set of notifications with removeObserver:name:object:.) The object passed as the observer: argument is the object that is no longer to receive notifications. What object that is depends on how you registered in the first place: You called addObserver:... You supplied an observer originally; that is the observer you must now unregister. You called addObserverForName:... The call returned an observer token object, which you captured as an id variable (its real class and nature are no concern of yours); that is the observer you must now unregister. The trick is finding the right moment to do this. The fallback solution is the registered instance’s dealloc method, this being the last lifetime event an instance is sent before it goes out of existence. If you’re using ARC and addObserverForName:..., there are memory management implications that I’ll talk about in Chapter 12. Notifications | 275 Keep it simple, because complicated logic for registering and unregistering for notifi‐ cations can be difficult to debug, especially as NSNotificationCenter provides no kind of introspection: you cannot ask an NSNotificationCenter what objects are registered with it as notification recipients. I once had a devil of a time understanding why one of my instances was not receiving a notification for which it was registered. Caveman debugging didn’t help. Eventually I realized that some code I’d forgotten about was unregistering my instance. If you’re calling addObserverForName:... multiple times from the same class, you’re going to end up receiving from the notification center multiple observer tokens, which you need to preserve so that you can unregister by handing them back to the notification center. If your plan is to unregister everything at once, one way to handle this situation is through an instance variable that is a mutable collection. So, for example, I might have an NSMutableSet instance variable called _observers. Early on, I initialize it to an empty set: self->_observers = [NSMutableSet set]; Each time I register for a notification using a block, I capture the result and add it to the set: id ob = [[NSNotificationCenter defaultCenter] addObserverForName:@"whatever" object:nil queue:nil usingBlock:^(NSNotification *note) { // ... whatever ... }]; [self->_observers addObject:ob]; Ultimately, I unregister by enumerating the set: for (id ob in self->_observers) [[NSNotificationCenter defaultCenter] removeObserver:ob]; The tedium of doing all that is a price worth paying in order to take advantage of blocks when using notifications. I am skipping over some other aspects of notifications that you probably won’t need to know about. Read Apple’s Notification Programming Topics for Cocoa if you want the gory details. NSTimer A timer (NSTimer) is not, strictly speaking, a notification; but it behaves very similar‐ ly. It is an object that gives off a signal (fires) after the lapse of a certain time interval. The signal is a message to one of your instances. Thus you can arrange to be notified when a certain time has elapsed. The timing is not perfectly accurate, but it’s pretty good. 276 | Chapter 11: Cocoa Events Timer management is not exactly tricky, but it is a little unusual. A timer that is actively watching the clock is said to be scheduled. A timer may fire once, or it may be a repeat‐ ing timer. To make a timer go out of existence, it must be invalidated. A timer that is set to fire once is invalidated automatically after it fires; a repeating timer repeats until you invalidate it by sending it the invalidate message. An invalidated timer should be regarded as off-limits: you cannot revive it or use it for anything further, and you should probably not send any messages to it. The straightforward way to create a timer is with the NSTimer class method scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:. This creates the timer and schedules it, so that it begins watching the clock immediately. The target and selector determine what message will be sent to what object when the timer fires; the method in question should take one parameter, which will be a reference to the timer. The userInfo is just like the userInfo of a notification. For example, one of my apps is a game with a score; I want to penalize the user, by diminishing the score, for every ten seconds after each move that elapses without the user making a further move. So each time the user makes a move, I create a repeating timer whose time interval is ten seconds (and I also invalidate any existing timer); in the method that the timer calls, I diminish the score. Timers have some memory management implications that I’ll discuss in Chapter 12. Delegation Delegation is an object-oriented design pattern, a relationship between two objects, in which the first object’s behavior is customized or assisted by the second. The second object is the first object’s delegate. No subclassing is involved, and indeed the first object is agnostic about the second object’s class. As implemented by Cocoa, here’s how delegation works. A built-in Cocoa class has an instance variable, usually called delegate (it will certainly have delegate in its name). For some instance of that Cocoa class, you set the value of this instance variable to an instance of one of your classes. At certain moments in its activity, the Cocoa class prom‐ ises to turn to its delegate for instructions by sending it a certain message: if the Cocoa instance finds that its delegate is not nil, and that its delegate is prepared to receive that message (see Chapter 10 on respondsToSelector:), the Cocoa instance sends the mes‐ sage to the delegate. Recall the discussion of protocols from Chapter 10. Delegation is one of Cocoa’s main uses of protocols. In the old days, delegate methods were listed in the Cocoa class’s documentation, and their method signatures were made known to the compiler through an informal protocol (a category on NSObject). Now, though, a class’s delegate methods are usually listed in a genuine protocol with its own documentation. There are over 70 Delegation | 277 Cocoa delegate protocols, showing how heavily Cocoa relies on delegation. Most dele‐ gate methods are optional, but in a few cases you’ll discover some that are required. To customize a Cocoa instance’s behavior through delegation, you start with one of your classes, which, if necessary, declares conformance to the relevant delegate protocol. When the app runs, you set the Cocoa instance’s delegate ivar (or whatever its name is) to an instance of your class. You might do this in code, usually through a property; you might do it in a nib, by connecting an instance’s delegate outlet (or whatever it’s called) to an appropriate instance that is to serve as delegate. Your delegate class will probably do other things besides serving as this instance’s delegate. Indeed, one of the nice things about delegation is that it leaves you free to slot delegate code into your class architecture however you like. For example, if a view has a controller (a UIView‐ Controller), it will often make sense for the controller to serve also as the delegate of that view, and even of its subviews. Here’s a simple example, involving UIAlertView. If a UIAlertView has no delegate, then when its Cancel button is tapped, the alert view is dismissed. But if you want to do something in response to the alert view being dismissed, you need to give it a delegate so that you can receive an event telling you that the alert view was dismissed. It’s so common to give a UIAlertView a delegate that its designated initializer allows you to supply one; typically, the delegate will be the instance that summoned the alert view in the first place: - (void) gameWon { UIAlertView* av = [[UIAlertView alloc] initWithTitle:@"Congratulations!" message:@"You won the game. Another game?" delegate:self cancelButtonTitle:@"No, thanks." otherButtonTitles:@"Sure!", nil]; [av show]; } - (void) alertView:(UIAlertView*) av didDismissWithButtonIndex: (NSInteger) ix { if (ix == 1) { // user said "Sure!" [self newGame]; } } The delegation mechanism is the last piece of the puzzle needed to explain the built-in bootstrapping procedure of a minimal app like our Empty Window project. Recall, from Chapter 6, that the fourth argument to UIApplicationMain is the string name of the class of the shared application instance’s delegate. So, having instantiated the class of the shared application (usually UIApplication), UIApplicationMain instantiates the class nominated in its fourth argument — in this case, AppDelegate; there is now, there‐ fore, before much of anything has happened, an AppDelegate instance. Moreover, 278 | Chapter 11: Cocoa Events UIApplicationMain sets the shared application’s delegate property to this AppDelegate instance. UIApplication’s delegate is typed as id <UIApplicationDelegate> — and, by golly, AppDelegate is declared as conforming to the UIApplicationDelegate protocol. This, as we saw in Chapter 10, causes the shared application instance to bombard this AppDelegate instance with respondsToSelector: messages, to find out exactly which UIApplicationDelegate methods AppDelegate actually implements. One such method that it does implement is application:didFinishLaunchingWithOptions:. So the UIApplication instance now actually sends application:didFinishLaunchingWithOptions: to its delegate, the AppDelegate instance. That is why, in some earlier exam‐ ples, we put code into the implementation of that method: this is code that is guaranteed, thanks to the UIApplication’s contract with its delegate, to run very early in the app’s lifetime. We know the application:didFinishLaunchingWithOptions: message will be sent, we know when it will be sent (early in our app’s lifetime), and we know to whom it will be sent (the application’s delegate object); so we’ve put appropriate code there, waiting to be called. Moreover, there is already boilerplate code in the project template’s implementation of this method that does some very important things, such as making our app’s window and showing it: self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; [self.window makeKeyAndVisible]; The UIApplication delegate methods are also provided as notifica‐ tions. This lets an instance other than the app delegate hear conveniently about application lifetime events, by registering for them. A few other classes provide duplicate events similarly; for example, UITableView’s delegate method tableView:didSelectRowAtIndexPath: is matched by a notification UITableViewSelectionDidChangeNotification. By convention, many Cocoa delegate method names contain the modal verbs should, will, or did. A will message is sent to the delegate just before something happens; a did message is sent to the delegate just after something happens. A should method is special: it returns a BOOL, and you are expected to respond with YES to permit some‐ thing or NO to prevent it. The documentation tells you what the default response is; you don’t have to implement a should method if the default response is always accept‐ able. In many cases, a property will control the overall behavior; the delegate message lets you pick and choose the behavior based on circumstances at runtime. For example, whether the user can tap the status bar to make a scroll view scroll quickly to the top is governed by the scroll view’s scrollsToTop property; but even if this property’s value is YES, you can prevent this behavior for a particular tap by returning NO from the delegate’s scrollViewShouldScrollToTop:. Delegation | 279 When you’re searching the documentation for how you can be notified of a certain event, be sure to consult the corresponding delegate protocol, if there is one. (And don’t forget to consult the class’s superclasses to see if one of them has a corresponding delegate protocol.) You’d like to know when the user taps in a UITextField to start editing it? You won’t find anything relevant in the UITextField class documentation; what you’re after is textFieldDidBeginEditing: in the UITextFieldDelegate protocol. You want to re‐ spond when the user rearranges items on your tab bar? Look in UITabBarController‐ Delegate. You want to know how to make a UITextView zoomable (through the user making a pinch gesture)? A UITextView is a UIScrollView; a scroll view is not zoomable unless its delegate returns a view from viewForZoomingInScrollView:, documented under UIScrollViewDelegate. Data Sources A data source is like a delegate, except that its methods supply the data for another object to display. The chief Cocoa classes with data sources are UITableView, UICollection‐ View, UIPickerView, and UIPageViewController. In each case, the data source must formally conform to a protocol with required methods. It comes as a surprise to some beginners that a data source is necessary at all. Why isn’t a table’s data just part of the table? Or why isn’t there at least some fixed data structure that contains the data? The reason is that such policies would violate generality. Use of a data source separates the object that displays the data from the object that manages the data, and leaves the latter free to store and obtain that data however it likes (see on model–view–controller in Chapter 13). The only requirement is that the data source must be able to supply information quickly, because it will be asked for it in real time when the data needs displaying. Another surprise is that the data source is different from the delegate. But this again is only for generality; it’s an option, not a requirement. There is no reason why the data source and the delegate should not be the same object, and most of the time they prob‐ ably will be. In this simple example, we implement a UIPickerView that allows the user to select by name a day of the week (the Gregorian week, using English day names). The first two methods are UIPickerView data source methods; the third method is a UIPickerView delegate method: - (NSInteger) numberOfComponentsInPickerView: (UIPickerView*) pickerView { return 1; } - (NSInteger) pickerView: (UIPickerView*) pickerView numberOfRowsInComponent: (NSInteger) component { return 7; } 280 | Chapter 11: Cocoa Events - (NSString*) pickerView:(UIPickerView*)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component { NSArray* arr = @[@"Sunday", @"Monday", @"Tuesday", @"Wednesday", @"Thursday", @"Friday", @"Saturday"]; return arr[row]; } Actions Recall the discussion of actions in Chapter 7. An action is a message emitted by an instance of a UIControl subclass (a control) reporting a significant user event taking place in that control. The UIControl subclasses (Chapter 25) are all simple interface objects that the user can interact with directly, like a button (UIButton), a switch (UISwitch), a segmented control (UISegmentedControl), a slider (UISlider), or a text field (UITextField). The significant user events (control events) are listed under UIControlEvents in the Constants section of the UIControl class documentation. See Chapter 25 for a list of which controls implement which control events. The way you hear about a control event is through an action message. A control main‐ tains an internal dispatch table: for each control event, there is some number of target– action pairs, of which the action is a selector (the name of a method) and the target is the object to which that message is to be sent. When a control event occurs, the control consults its dispatch table, finds all the target–action pairs associated with that control event, and sends each action message to the corresponding target. This architecture is reminiscent of a notification (Figure 11-1). There are two ways to manipulate a control’s action dispatch table: you can configure an action connection in a nib (as explained in Chapter 7), or you can use code. To use code, you send the control the message addTarget:action:forControlEvents:, where the target: is an object, the action: is a selector, and the controlEvents: are desig‐ nated by a bitmask (see Chapter 1 if you’ve forgotten how to construct a bitmask). Unlike a notification center, a control also has methods for introspecting the dispatch table (Chapter 25). Recall the example from Chapter 7 (where b is a reference to a UIButton): [b addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside]; Actions | 281 Figure 11-1. The target–action architecture After that, whenever the user taps in the button, our buttonPressed: method will be called. It might, again as in Chapter 7, look like this: - (void) buttonPressed: (id) sender { UIAlertView* av = [[UIAlertView alloc] initWithTitle:@"Howdy!" message:@"You tapped me." delegate:nil cancelButtonTitle:@"Cool" otherButtonTitles:nil]; [av show]; } The signature for the action selector can be in any of three forms. The fullest form takes two parameters: • The control, usually typed as id. 282 | Chapter 11: Cocoa Events • The UIEvent that generated the control event. A shorter form (the most commonly used form) omits the second parameter; a still shorter form omits both parameters. Mac OS X Programmer Alert If you’re an experienced Mac OS X Cocoa developer, you’ll note that there are some major differences between the Mac OS X implementa‐ tion of actions and the iOS implementation. In Mac OS X, a control has just one action; in iOS, a control may respond to multiple control events. In Mac OS X, an action has just one target; in iOS, a single event can trigger multiple action messages to multiple targets. In Mac OS X, an action message selector comes in just one form; in iOS, there are three possible forms. What is the UIEvent, and what is it for? Well, a touch event is generated whenever the user does something with a finger (sets it down on the screen, moves it, raises it from the screen). UIEvents are the lowest-level objects charged with communication of touch events to your app. A UIEvent is basically a timestamp (a double) along with a collection (NSSet) of touch events (UITouch). The action mechanism deliberately shields you from the complexities of touch events, but by electing to receive the UIEvent, you can still deal with those complexities if you want to. (See Chapter 18 for full details.) Curiously, none of the action selector parameters provide any way to learn which control event triggered the current action selector call! Thus, for example, to distinguish a Touch Up Inside control event from a Touch Up Outside control event, their corresponding target–action pairs must specify two different action handlers; if you dispatch them to the same action handler, that handler cannot discover which control event occurred. The Responder Chain A responder is an object that knows how to receive UIEvents directly (see the previous section). It knows this because it is an instance of UIResponder or a UIResponder sub‐ class. If you examine the Cocoa class hierarchy, you’ll find that just about any class that has anything to do with display on the screen is a responder. A UIView is a responder. A UIWindow is a responder. A UIViewController is a responder. Even a UIApplication is a responder. In iOS 5 and later, the app delegate is a responder. If you look in the documentation for the UIResponder class, you’ll find that it imple‐ ments four low-level methods for receiving touch-related UIEvents: touchesBegan:withEvent:, touchesMoved:withEvent:, touchesEnded:withEvent: and touchesCancelled:withEvent:. These are called to notify a responder of a touch event. No matter how your code ultimately hears about a user-related touch event — indeed, The Responder Chain | 283 even if your code never hears about a touch event (because Cocoa reacted in some automatic way to the touch, without your code’s intervention) — the touch was initially communicated to a responder through one of these methods. The mechanism for this communication starts by deciding which responder the user touched. The UIView methods hitTest:withEvent: and pointInside:withEvent: are called until the correct view (the hit-test view) is located. Then UIApplication’s sendEvent: method is called, which calls UIWindow’s sendEvent:, which calls the correct method of the hit-test view (a responder). I’ll cover all this again in full detail in Chap‐ ter 18. The responders in your app participate in a responder chain, which essentially links them up through the view hierarchy. A UIView can sit inside another UIView, its su‐ perview, and so on until we reach the app’s UIWindow (a UIView that has no superview). The responder chain, from bottom to top, looks like this: 1. The UIView that we start with (here, the hit-test view). 2. The UIViewController that controls that UIView, if there is one. 3. The UIView’s superview, and then its UIViewController if there is one. Repeat this step, moving up the superview hierarchy one superview at a time, until we reach… 4. The UIWindow. 5. The UIApplication. 6. The UIApplication’s delegate. Deferring Responsibility The responder chain can be used to let a responder defer responsibility for handling a touch event. If a responder receives a touch event and can’t handle it, the event can be passed up the responder chain to look for a responder that can handle it. This can happen in two main ways: (1) the responder doesn’t implement the relevant method; (2) the responder implements the relevant method to call super. For example, a plain vanilla UIView has no native implementation of the touch event methods. Thus, by default, even if a UIView is the hit-test view, the touch event effec‐ tively falls through the UIView and travels up the responder chain, looking for someone to respond to it. If this UIView is an instance of your own subclass, you might implement the touch event methods in that subclass to catch touch events in the UIView itself; but if the UIView is controlled by a UIViewController, you have already subclassed UIView‐ Controller, and that subclass is probably where the interface behavior logic for this UIView is already situated, so you might well prefer to implement the touch event methods there instead. You are thus taking advantage of the responder chain to defer 284 | Chapter 11: Cocoa Events responsibility for handling touch events from the UIView to its UIViewController, in a natural and completely automatic way. Again, I’ll come back to this in Chapter 18; don’t worry about it for now. I’m actually telling you about the responder chain chiefly in order to discuss nil-targeted actions, which is the subject of the next section. Nil-Targeted Actions A nil-targeted action is a target–action pair in which the target is nil. There is no des‐ ignated target object, so the following rule is used: starting with the hit-test view (the view with which the user is interacting), Cocoa looks up the responder chain for an object that can respond to the action message. Suppose, for example, we have a UIButton inside a UIView. And suppose we run this code early in the button’s lifetime, where b is the button: [b addTarget:nil action:@selector(doButton:) forControlEvents:UIControlEventTouchUpInside]; That’s a nil-targeted action. So what happens when the user taps the button? First, Cocoa looks in the UIButton itself to see whether it responds to doButton:. If not, then it looks in the UIView that is its superview. And so on, up the responder chain. If a responder is found that handles doButton:, the action message is sent to that object; otherwise, the message goes unhandled. Thus, suppose the UIView containing the UIButton is an instance of your own UIView subclass. Let’s call it MyView. If MyView implements doButton:, then when the user taps the button, it is MyView’s doButton: that will be called. To create a nil-targeted action in a nib, you form a connection to the First Responder proxy object (in the dock). This is what the First Responder proxy object is for! The First Responder isn’t a real object with a known class, so before you can connect an action to it, you have to define the action message within the First Responder proxy object, like this: 1. Select the First Responder proxy in the nib, and switch to the Attributes inspector. 2. You’ll see a table (probably empty) of user-defined nil-targeted First Responder actions. Click the Plus button and give the new action a signature; it must take a single parameter (so that its name will end with a colon). 3. Now you can Control-drag from a control, such as a UIButton, to the First Res‐ ponder proxy to specify a nil-targeted action with the signature you specified. The Responder Chain | 285 The Term “First Responder” Cocoa uses the term first responder in a confusing way. An arbitrary responder object can be assigned formal first responder status (by sending it becomeFirstResponder, provided that this responder returns YES from canBecomeFirstResponder). But this does not make the object first responder for purposes of handling nil-targeted actions! Cocoa’s hunt for a responder that can handle a nil-targeted action still starts with the control that the user is interacting with (the hit-test view) and goes up the responder chain from there. Typical legitimate uses of becomeFirstResponder are: • To put a UITextField into editing mode, as if the user had tapped in it (Chapter 23). • To specify the object that should initially be sent remote events (Chapter 27). • To designate an object that is to present a menu (Chapter 39). Swamped by Events Your code runs only because Cocoa sends an event and you had previously set up a method ready to receive it. Cocoa has the potential to send lots of events, telling you what the user has done, informing you of each stage in the lifetime of your app and its objects, asking for your input on how to proceed. To receive the events that you need to hear about, your code is peppered with methods that are entry points — methods that you have written with just the right name and in just the right class so that they can be called by Cocoa through events. In fact, it is easy to imagine that in many cases your code for a class will consist almost entirely of entry points. That fact is one of your primary challenges as an iOS programmer. You know what you want to do, but you have to divide it up and allocate it according to when Cocoa is going to call into your code. Before you’ve written a single line of your own code, the skeleton structure of a class is likely to have been largely mapped out for you by the need to be prepared to receive the events that Cocoa is going to want to send you. Suppose, for example, that your iPhone app contains a screen that effectively consists entirely of a table view. (This is in fact an extremely probable scenario.) You’re most like to have a corresponding UITableViewController subclass; UITableViewController is a built-in UIViewController subclass, plus you’ll probably use this same class as the table view’s data source and delegate. In this single class, then, you’re likely to want to im‐ plement at a minimum the following methods: initWithCoder: or initWithNibName:bundle: UIViewController lifetime method, where you perform custom instance initiali‐ zations. 286 | Chapter 11: Cocoa Events viewDidLoad: UIViewController lifetime method, where you perform view-related initializations. viewWillAppear: UIViewController lifetime method, where you set up states that need to apply only while your view is onscreen. For example, if you’re going to register for a notification or set up a timer, this is a likely place to do it. viewDidDisappear: UIViewController lifetime method, where you reverse what you did in viewWillAppear:. For example, this would be a likely place to unregister for a notification or invalidate a repeating timer that you set up in viewWillAppear:. supportedInterfaceOrientations UIViewController query method, where you specify what device orientations are allowed for this view. numberOfSectionsInTableView: tableView:numberOfRowsInSection: tableView:cellForRowAtIndexPath: UITableView data source query methods, where you specify the contents of the table. tableView:didSelectRowAtIndexPath: UITableView delegate user action method, where you respond when the user taps a row of the table. dealloc NSObject lifetime method, where you perform end-of-life cleanup. (If you’re not using ARC, you will have memory management tasks to perform here.) Suppose, further, that you did in fact use viewWillAppear: to register for a notification and to set up a timer. Then that notification has a selector (unless you used a block), and the timer has a selector; you must therefore also implement the methods described by those selectors. We already have, then, about a dozen methods whose presence is effectively a matter of boilerplate. These are not your methods; you are never going to call them. They are Cocoa’s methods, which you have placed here so that each can be called at the appro‐ priate moment in the life story of your app. (Don’t try to learn any of those method names now! I’ll talk in detail about these matters in Chapter 19 and Chapter 21. At the moment I’m just showing you that a major portion of the structure of this class is likely to be dictated to you by the event-driven nature of a Cocoa app.) Swamped by Events | 287 The logic of a program laid out in this fashion is by no means easy to understand! I’m not criticizing Cocoa here — indeed, it’s hard to imagine how else an application frame‐ work could work — but, purely as an objective matter of fact, the result is that a Cocoa program, even your own program, even while you’re developing it, is hard to read, be‐ cause it consists of numerous disconnected entry points, each with its own meaning, each called at its own set moment which is not in any way obvious from looking at the program. To understand what our hypothetical class does, you have to know already such things as when viewWillAppear: is called and how it is typically used; otherwise, you don’t even know where to look to find the program’s logic and behavior, let alone how to interpret what you see when you do look there. And this difficulty is greatly compounded when you try to read someone else’s code (this is one reason why, as I mentioned in Chapter 8, sample code is not all that helpful to a beginner). Looking at the code of an iOS program — even your own code — your eyes can easily glaze over at the sight of all these methods called automatically by Cocoa under various circumstances. To be sure, experience will teach you about such things as the overridden UIViewController methods and the table view delegate and data source methods. On the other hand, no amount of experience will tell you that a certain method is called as a button’s action or through a notification. Comments really help, and I strongly advise you, as you develop any iOS app, to comment every method, quite heavily if need be, saying what that method does and under what circumstances you expect it to be called — especially if it is an entry point, where it is Cocoa itself that will do the calling. Perhaps the most common kind of mistake in writing a Cocoa app is not that there’s a bug in your code itself, but that you’ve put the code in the wrong place. Your code isn’t running, or it’s running at the wrong time, or the pieces are running in the wrong order. I see questions about this sort of thing all the time on the various online user forums (these are all actual examples that appeared over the course of just two days): • “There’s a delay between the time when my view appears and when my button takes on its correct title.” That’s because you put the code that sets the button’s title in viewDidAppear:. That’s too late; your code needs to run earlier, perhaps in viewWillAppear:. • “My subviews are positioned in code and they’re turning out all wrong.” That’s because you put the code that positions your subviews in viewDidLoad. That’s too early; your code needs to run later, when your view’s dimensions have been deter‐ mined. • “My view is rotating even though my view controller’s supportedInterfaceOrientations says not to.” That’s because you implemented supportedInterfaceOrientations in the wrong class; it needs to be implemented in the UINavigation‐ Controller that contains your view controller. 288 | Chapter 11: Cocoa Events • “I set up an action connection for Value Changed on a text field, but my code isn’t being called when the user edits.” That’s because you connected the wrong action; a text field emits Editing Changed, not Value Changed. Adding to your challenges is that fact that you can’t really know precisely when an entry point will be called. The documentation may give you a general sense, but in most cases it doesn’t guarantee anything about precisely when events will arrive and in what order. What you think is going to happen, and even what the documentation leads you to believe is going to happen, might not be quite what really does happen. Your own code can trigger unintended events. The documentation might not make it clear just when a notification will be sent. There could even be a bug in Cocoa such that events are called in a way that seems to contradict the documentation. And you have no access to the Cocoa source code, so you can’t work out the underlying details. Therefore I also rec‐ ommend that as you develop your app, you instrument your code heavily with caveman debugging (NSLog; see Chapter 9). As you test your code, keep an eye on the console output and check whether the messages make sense. You may be surprised at what you discover. For example, in one app that I was developing, I suddenly found that in a UIView‐ Controller subclass, viewDidLoad was being called twice as the app started up, which should be impossible. Fortunately, my code was heavily instrumented with NSLog calls, or I would never have discovered this problem. Adding even more NSLog calls, I found that viewDidLoad was being called while I was still in the middle of executing awakeFromNib, which should really be impossible. The reason turned out to be my own mis‐ take: I was referring to my class’s view property during awakeFromNib, which was caus‐ ing viewDidLoad to be called. The problem went away when I corrected my mistake. Delayed Performance Some of your code tells Cocoa what to do. But Cocoa is a black box, so what Cocoa actually will do, and precisely when it will do it, is out of your control. Your code was executed in response to some event; but your code in turn may trigger a new event or chain of events. Sometimes this causes bad things to happen: there might be a crash, or Cocoa might appear not to have done what you said to do. One of the chief causes of these difficulties is the chain of triggered events itself. Sometimes you just need to step outside that chain for a moment and wait for everything to settle down before pro‐ ceeding. The technique for doing this is called delayed performance. You tell Cocoa to do some‐ thing not right this moment, but in a little while, when things have settled down. Your purpose might be a matter of simple timing, such as when you want to do something different depending whether the user taps twice in quick succession or only once; ba‐ sically, when the user first taps, you respond using delayed performance, to give the user Delayed Performance | 289 time to tap again if two taps are intended (Chapter 18). Or perhaps you need only a very short delay, possibly even as short as zero seconds, just to let Cocoa finish doing some‐ thing, such as laying out interface. Technically, you’re allowing the current run loop to finish, completing and unwinding the entire current method call stack, before proceed‐ ing further with your own code. You’re likely to be using delayed performance a lot more than you might expect. With experience, you’ll develop a kind of sixth sense for when delayed performance might be the solution to your difficulties. There are three chief implementations of delayed per‐ formance that I use in my own code: performSelector:withObject:afterDelay: I mentioned this NSObject method at the end of Chapter 10. It limits you as to the signature of the selector — it must take one parameter or none — so you might have to restructure your own code slightly. dispatch_after I mentioned this in Chapter 3. It takes a block, not a selector, which can result in more direct and readable code. dispatch_async Often, the delay you’re after doesn’t need to be more than zero. What you’re trying to do is postpone the next step until the consequences of the previous step have worked themselves out. So it suffices to wait until nothing is happening. You can do this with a call to dispatch_async onto the same queue where everything is happening now, namely the main queue (dispatch_get_main_queue, Chapter 38). In all three cases, what you propose to do will be done later on; you’re deliberately breaking out of your own code’s line-by-line sequence of execution. So a delayed per‐ formance call will be the last call in its method (or block), and cannot return any value. In this example from one of my own apps, the user has tapped a row of a table, and my code responds by creating and showing a new view controller: - (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { TracksViewController *t = [[TracksViewController alloc] initWithMediaItemCollection:(self.albums)[indexPath.row]]; [self.navigationController pushViewController:t animated:YES]; } Unfortunately, the innocent-looking call to my TracksViewController method initWithMediaItemCollection: can take a moment to complete, so the app comes to a stop with the table row highlighted — very briefly, but just long enough to startle the user. To cover this delay with a sense of activity, I’ve rigged my UITableViewCell subclass to show a spinning activity indicator when it’s selected: 290 | Chapter 11: Cocoa Events - (void)setSelected:(BOOL)selected animated:(BOOL)animated { if (selected) { [self.activityIndicator startAnimating]; // appear and spin } else { [self.activityIndicator stopAnimating]; // disappear } [super setSelected:selected animated:animated]; } However, the spinning activity indicator never appears and never spins. The reason is that the events are stumbling over one another here. UITableViewCell’s setSelected:animated: isn’t called until the UITableView delegate method tableView:didSelectRowAtIndexPath: has finished. But the delay we’re trying to paper over is during tableView:didSelectRowAtIndexPath:; the whole problem is that it doesn’t finish fast enough. Delayed performance to the rescue! I’ll rewrite tableView:didSelectRowAtIndexPath: so that it finishes immediately — thus triggering setSelected:animated: immediately and causing the activity indicator to appear and spin — and call initWithMediaItemCollection: later on, when the interface has ironed itself out: - (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { // tiny delay to allow spinner to start spinning double delayInSeconds = 0.1; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ TracksViewController *t = [[TracksViewController alloc] initWithMediaItemCollection:(self.albums)[indexPath.row]]; [self.navigationController pushViewController:t animated:YES]; }); } Here’s an example that I came across on the Internet, involving a crash. The developer has a table view each of whose rows contains a text field. If the user deletes everything in one of those text fields, the table row containing it should be deleted. The code is an implementation of one of the text field’s delegate methods: - (void)textFieldEditingDidEnd:(UITextField *)textField { NSIndexPath *indexPath = // Index path of the row in the table view if ([textField.text length] == 0) { // Delete the cell from the table view [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; } } This was crashing. My suggestion — which worked — was to call deleteRowsAtIndexPaths:withRowAnimation: using delayed performance. The reason is that, as things Delayed Performance | 291 stand, we are trying to delete the row containing the text field while the text field is still busy reporting to its delegate that editing is ending. With delayed performance, we allow Cocoa’s call to this delegate method to finish, and then we delete the row. There will be many more examples of delayed performance later in this book. Application Lifetime Events As I explained in Chapter 6, your app’s one and only application object (a UIApplication instance, or on rare occasions a UIApplication subclass instance) is created for you as the shared application object by UIApplicationMain, along with its delegate; in the Xcode project templates, this is an instance of the AppDelegate class. As I’ve discussed earlier in this chapter, the application immediately starts reporting lifetime events through method calls to its delegate; subsequently, your other instances can also register to receive these same events as notifications. I can’t think of a better place in this book to describe these events, so I’m going to do so here and now. What application lifetime events you can receive depends on whether or not your app participates in multitasking. In the old days, before iOS 4, there was no multitasking. If the user pressed the Home button while running your app, your app was terminated. The next time the user launched your app by tapping its icon, your app launched from scratch. Even under iOS 4 and later, your app can opt out of multitasking and behave like a pre–iOS 4 app, if you set the “Application does not run in background” key (UIApplicationExitsOnSuspend) in your Info.plist. For some apps, such as certain games, this might be a reasonable thing to do. The suite of basic application lifetime events received by the app delegate in a nonmul‐ titasking app is pretty simple: application:didFinishLaunchingWithOptions: The app has started up. This, as we have already seen, is the earliest opportunity for your code to configure the interface by creating and showing the app’s window, and it’s fair to assume that every app you ever write will do exactly that. If you don’t show your app’s interface, the user won’t see anything! (In an app with a main storyboard, however, the storyboard loading mechanism creates the window for you.) Of course you can and will perform other early initializations here. Starting in iOS 6, there’s a new event, application:willFinishLaunchingWithOptions:, that arrives even earlier than application:didFinishLaunchingWithOptions:. Its purpose is to al‐ low your app to participate in the new mechanism for saving and re‐ storing state. Since view controllers are the primary basis of this mech‐ anism, I’ll discuss it in Chapter 19. 292 | Chapter 11: Cocoa Events applicationDidBecomeActive: The app has started up; received after application:didFinishLaunchingWithOptions:. Also received after the end of the situation that caused the app delegate to receive applicationWillResignActive:. applicationWillResignActive: Something has blocked the app’s interface. The most common cause is that the screen has been locked. An alert dialog from outside your app, or an incoming phone call whose interface takes over the screen, could also cause this event. When this situation ends, the app delegate will receive applicationDidBecomeActive:. applicationWillTerminate: The app is about to quit. This is your last signal to preserve state (typically, by storing information with NSUserDefaults) and perform other final cleanup tasks. If your app participates in multitasking, as it almost certainly will, applicationWillTerminate: is virtually a dead letter. The Home button doesn’t terminate your app; it backgrounds and suspends it. This means that your app is essentially freeze-dried in the background; its process still exists, but it isn’t actively running, and it isn’t getting any events — though notifications can be stored by the system for later delivery if your app comes to the front once again. Your app is terminated, not because the user switches away from it, but because the system has killed it while it was suspended (for example, because it needed to reclaim the memory your suspended app was using). Thus you’ll probably never get applicationWillTerminate:, because when your app is terminated by the system, it was already suspended and incapable of receiving events. Under highly specialized circumstances (discussed, for instance, in Chapter 27 and Chapter 35), your app can be backgrounded without being suspended. Nevertheless, throughout this section I’ll speak as if backgrounding and suspension are one and the same. In the multitasking world, you have to worry about what will happen when the app is suspended and when it returns from being suspended (applicationDidEnterBackground: and applicationWillEnterForeground:, and their corresponding noti‐ fications), and the notion of the application becoming inactive or active also takes on increased importance (applicationWillResignActive: and applicationDidBecomeActive:, and their notifications). These notifications all take on a wide range of meaning — indeed, in my opinion, the information your app is given is unfortunately too coarsegrained — so they are best understood by examining some typical scenarios: The app launches freshly Your app delegate receives these messages (just as in the premultitasking world): Application Lifetime Events | 293 • application:didFinishLaunchingWithOptions: • applicationDidBecomeActive: The user clicks the Home button If your app is frontmost, it is suspended, and your app delegate receives these mes‐ sages: • applicationWillResignActive: • applicationDidEnterBackground: The user summons your suspended app to the front Your app delegate receives these messages: • applicationWillEnterForeground: • applicationDidBecomeActive: If the user summons your suspended app to the front indirectly, another delegate message may be sent between these two calls. For example, if the user asks another app to hand a file off to your app (Chapter 36), your app receives application:handleOpenURL: between applicationWillEnterForeground: and applicationDidBecomeActive:. If the user taps a local notification alert belonging to your app (Chapter 26), your app receives application:didReceiveLocalNotification: between applicationWillEnterForeground: and applicationDidBecomeActive:. The user double-clicks the Home button The user can now work in the app switcher. If your app is frontmost, your app delegate receives this message: • applicationWillResignActive: The user, in the app switcher, taps on your app’s window Your app delegate receives this message: • applicationDidBecomeActive: The user, in the app switcher, chooses another app If your app is frontmost, your app delegate receives this message: • applicationDidEnterBackground: A local notification alert (Chapter 26) from another app appears If your app is frontmost, your app delegate receives this message: 294 | Chapter 11: Cocoa Events • applicationWillResignActive: From a local notification alert, the user launches the other app Your app delegate receives these messages: • applicationDidBecomeActive: • applicationWillResignActive: • applicationDidEnterBackground: The screen is locked If your app is frontmost, your app delegate receives these messages: • applicationWillResignActive: • applicationDidEnterBackground: The screen is unlocked If your app is frontmost, your app delegate receives these messages: • applicationWillEnterForeground: • applicationDidBecomeActive: The user holds the screen-lock button down The device offers to shut itself down. If your app is frontmost, your app delegate receives this message: • applicationWillResignActive: The user, as the device offers to shut itself down, cancels If your app is frontmost, your app delegate receives this message: • applicationDidBecomeActive: The user, as the device offers to shut itself down, accepts If your app is frontmost, your app delegate receives these messages: • applicationDidEnterBackground: • applicationWillTerminate: (probably the only way a normal app will receive this message in a multitasking world) You can see what I mean when I say that this repertory of events is rather coarse-grained. applicationWillResignActive:, for example, could mean that the user is summoning the app switcher, or that another application’s local notification alert has appeared in front of your app, or that the user is locking the screen, or that the user has single-clicked the Home button to leave your app altogether, or that a phone call has arrived while your app was frontmost. But you can’t distinguish which of these things is happening. Application Lifetime Events | 295 Of all the tasks with which you’ll concern yourself over your app’s lifetime, probably the most important is saving state. If the user has done or specified things that the app needs to preserve, it must do so before it is terminated. Since a multitasking app is probably never going to be notified by applicationWillTerminate:, you’ll need to find an ap‐ propriate earlier moment. Unless your app is killed by the system outright, before the user’s eyes, for committing some crime (such as hogging the main thread for too long at a stretch), you’ll surely receive applicationDidEnterBackground: before being ter‐ minated, and indeed this might well be the last event your app ever receives; so it is clearly the default signal that you should save state. (You are given a little time to do this before your app is actually suspended; Chapter 38 discusses what to do if you think a little time might not be enough.) In iOS 6, as I’ve already mentioned, there’s a new mechanism for helping you save state. It’s quite possible that your app, if it adopts this new mechanism, won’t need to save state in applicationDidEnterBackground: after all. (See Chapter 19.) On the other hand, you still might want to respond to applicationDidEnterBackground: by saving infor‐ mation that doesn’t qualify as state. For instance, your app stands a better chance of not being terminated while suspended, the less memory resources it uses; you might there‐ fore take applicationDidEnterBackground: as a signal to release whatever large mem‐ ory resources you can, perhaps writing them out to disk and recovering them when your app receives applicationWillEnterForeground:. (In addition, while running in the foreground, your app will be sent the delegate message applicationDidReceiveMemoryWarning: to inform you of a low memory situation. I’ll return to this topic in Chapter 19 as well.) 296 | Chapter 11: Cocoa Events CHAPTER 12 Accessors and Memory Management An accessor is a method for getting or setting the value of an instance variable. An accessor that gets the instance variable’s value is called a getter; an accessor that sets the instance variable’s value is called a setter. Accessors are important in part because instance variables, by default, are protected (Chapter 5), whereas publicly declared methods are public; without public accessor methods, a protected instance variable can’t be accessed by any object whose class (or superclass) isn’t the one that declares the instance variable. You might be tempted to conclude from this that you needn’t bother making an accessor for an instance variable that isn’t intended for public access, and to some extent this is a reasonable conclusion. But here are some counterarguments: • Cocoa often uses the string name of an instance variable to derive the name of the accessor and call it if it exists. Thus there needs to be an accessor so that Cocoa can find it. • If your app doesn’t use ARC, and if your instance variable is an object, there are going to be memory management tasks to worry about every time you get and (especially) set that value; the best way to ensure that you’re carrying out those tasks reliably and consistently is to pass through an accessor. • Even if your app does use ARC, there may be additional tasks that need to be per‐ formed every time the instance variable’s value is touched; an accessor, acting as a gateway to the instance variable, ensures that these tasks are performed consistently. • Making accessors is no bother, as you usually won’t have to write the code for an accessor; Objective-C can write your accessors for you. This chapter will discuss all of those points in depth. There are naming conventions for accessors, and you should obey them. The conven‐ tions are simple: 297 The setter A setter’s name should start with set, followed by a capitalized version of the in‐ stance variable’s name (without an initial underscore if the instance variable has one). The setter should take one parameter — the new value to be assigned to the instance variable. Thus, the instance variable is named myVar (or _myVar), the setter should be named setMyVar:. The getter A getter should have the same name as the instance variable (without an initial underscore if the instance variable has one). This will not cause you or the compiler any confusion, because variable names and method names are used in completely different contexts. Thus, if the instance variable is named myVar (or _myVar), the getter should be named myVar. If the instance variable’s value is a BOOL, you may optionally start the getter’s name with is (for example, an ivar showing or _showing can have a getter isShowing), though in fact I never do this. Although I keep saying that the names of the accessor methods use the name of the instance variable, there is no law requiring that they use the name of a real instance variable. Quite the contrary: you might deliberately have methods myVar and setMyVar: when in fact there is no myVar (or _myVar) instance variable. Perhaps the accessors are mask‐ ing the real name of the instance variable, or perhaps there is no instance variable at all, and these accessors are really doing something quite dif‐ ferent behind the scenes. Accessors effectively present a façade, as if there were a certain instance variable, shielding the caller from any knowledge of the underlying details. Key–Value Coding Cocoa derives the name of an accessor from a string name through a mechanism called key–value coding, or simply KVC. (See also Chapter 5, where I introduced key–value coding.) The key is a string (an NSString) that names the value to be accessed. The basis for key–value coding is the NSKeyValueCoding protocol, an informal protocol (it is actually a category) to which NSObject (and therefore every object) conforms. Key– value coding is a big subject; see the Key-Value Coding Programming Guide for full information. The fundamental key–value coding methods are valueForKey: and setValue:forKey:. When one of these methods is called on an object, the object is introspected. In simplified terms, first the appropriate accessor is sought; if it doesn’t exist, the instance variable is accessed directly. 298 | Chapter 12: Accessors and Memory Management So, for example, suppose the call is this: [myObject setValue:@"Hello" forKey:@"greeting"]; First, a method setGreeting: is sought in myObject; if it exists, it is called, passing @"Hello" as its argument. If that fails, but if myObject has an instance variable called greeting (or _greeting), the value @"Hello" is assigned directly to that ivar. The key–value coding mechanism can bypass completely the privacy of an instance variable! Cocoa knows that you might not want to allow that, so a class method accessInstanceVariablesDirectly is sup‐ plied, which you can override to return NO (the default is YES). Both valueForKey: and setValue:forKey: require an object as the value. Your acces‐ sor’s signature (or, if there is no accessor, the instance variable itself) might not use an object as the value, so the key–value coding mechanism converts for you. Numeric types (including BOOL) are expressed as an NSNumber; other types (such as CGRect and CGPoint) are expressed as an NSValue. A class is key–value coding compliant (or KVC compliant) on a given key if it implements the methods, or possesses the instance variable, required for access via that key. Another useful pair of methods is dictionaryWithValuesForKeys: and setValuesForKeysWithDictionary:, which allow you to get and set multiple key–value pairs by way of an NSDictionary with a single command. KVC is extremely dynamic. It allows you, in effect, to decide at runtime what instance variable to access; you obtain the instance variable’s name as an NSString and pass that to valueForKey: or setValue:forKey:. Thus, by using an NSString instead of an in‐ stance variable or method name, you’re throwing away compile-time checking as to the message you’re sending. Moreover, key–value coding is agnostic about the actual class of the object you’re talking to; you can send valueForKey: to any object and successfully get a result, provided the class of that object is key–value coding compliant for that key, so you’re throwing away compile-time checking as to the object you’re sending the message to. These are both strong advantages of key–value coding, and I often find myself using it because of them. Here’s an example of key–value coding used in my own code on my own object. In a flashcard app, I have a class Term, representing a Latin term, that defines many instance variables. Each card displays one term, with its instance variables shown in different text fields. If the user taps any of three text fields, I want the interface to change from the term that’s currently showing to the next term whose value is different for the in‐ Key–Value Coding | 299 stance variable that this text field represents. Thus this code is the same for all three text fields; the only difference is what instance variable to consider as we hunt for the term to be displayed. By far the simplest way to express this is through key–value coding: NSInteger tag = g.view.tag; // the tag tells us which text field was tapped NSString* key = nil; switch (tag) { case 1: key = @"lesson"; break; case 2: key = @"lessonSection"; break; case 3: key = @"lessonSectionPartFirstWord"; break; } // get current value of corresponding instance variable NSString* curValue = [[self currentCardController].term valueForKey: key]; // ... A number of built-in Cocoa classes permit you to use key–value coding in a special way. For example: • If you send valueForKey: to an NSArray, it sends valueForKey: to each of its elements and returns a new array consisting of the results, an elegant shorthand (and a kind of poor man’s map). NSSet behaves similarly. • NSSortDescriptor sorts an NSArray by sending valueForKey: to each of its ele‐ ments. • NSDictionary implements valueForKey: as an alternative to objectForKey: (use‐ ful particularly if you have an NSArray of dictionaries). Similarly, NSMutable‐ Dictionary treats setValue:forKey: as a synonym for setObject:forKey:, except that value: can be nil, in which case removeObject:forKey: is called. • CALayer (Chapter 16) and CAAnimation (Chapter 17) permit you to use key–value coding to define and retrieve the values for arbitrary keys, as if they were a kind of dictionary; this is useful for attaching identifying and configuration information to one of these instances. • NSManagedObject, used in conjunction with Core Data (Chapter 36), is guaranteed to be key–value coding compliant for attributes you’ve configured in the entity model. Therefore, it’s common to access those attributes with valueForKey: and setValue:forKey:. KVC and Outlets Key–value coding lies at the basis of how outlet connections work. I said in Chapter 7 that the name of the outlet in the nib is matched to the name of an instance variable, but I waved my hands over how this matching is performed. The truth is that key–value coding is used. The name of the outlet in the nib is a string. Key–value coding turns the string into a hunt for appropriate accessors. 300 | Chapter 12: Accessors and Memory Management Suppose you have a class MyClass with an instance variable myVar, and you’ve drawn a myVar outlet from that class’s representative in the nib to an OtherClass nib object. When the nib loads, the outlet name myVar is translated to the method name setMyVar:, and your MyClass instance’s setMyVar: method, if it exists, is called with the OtherClass instance as its parameter, thus setting the value of your MyClass instance’s instance variable to the OtherClass instance (Figure 7-5). By the same token, you should not use accessor names for methods that aren’t accessors! For example, you probably would not want MyClass to have a method called setMyVar: if it is not the accessor for myVar. If it did have such a method, it would be called when the nib loads, the OtherClass instance would be passed to it, and the OtherClass instance would not be assigned to the myVar instance variable! As a result, references in your code to myVar would be references to nil. On the other hand, an attempt to access a nonexistent key through key–value coding will result, by default, in a crash at runtime, with an error message of this form: “This class is not key value coding-compliant for the key myKey.” The lack of quotation marks around the word after “the key” has misled many a beginner, so remember: the last word in that error message is the name of the key that gave Cocoa trouble. A common way to encounter this error message is to change the name of an instance variable so that the name of an outlet in a nib no longer matches it; at runtime, when the nib loads, Cocoa will attempt to use key–value coding to set a value in your object based on the name of the outlet, will fail (because there is no longer an instance variable or accessor by that name), and will generate this error. Key Paths and Array Accessors A key path allows you to chain keys in a single expression. If an object is key–value coding compliant for a certain key, and if the value of that key is itself an object that is key–value coding compliant for another key, you can chain those keys by calling valueForKeyPath: and setValue:forKeyPath:. A key path string looks like a succession of key names joined with a dot (.). For example, valueForKeyPath:@"key1.key2" effec‐ tively calls valueForKey: on the message receiver, with @"key1" as the key, and then takes the object returned from that call and calls valueForKey: on that object, with @"key2" as the key. To illustrate this shorthand, imagine that our object myObject has an instance variable theData which is an array of dictionaries such that each dictionary has a name key and a description key. I’ll show you the actual value of theData as displayed by NSLog: ( { description = "The one with glasses."; name = Manny; }, Key–Value Coding | 301 { }, { ) description = "Looks a little like Governor Dewey."; name = Moe; description = "The one without a mustache."; name = Jack; } Then [myObject valueForKeyPath: @"theData.name"] returns an array consisting of the strings @"Manny", @"Moe", and @"Jack". If you don’t understand why, review what I said a few paragraphs ago about how NSArray and NSDictionary implement valueForKey:. Key–value coding also allows an object to implement a key as if its value were an array (or a set), even if it isn’t. This is similar to what I said earlier about how accessors function as a façade, putting an instance variable name in front of hidden complexities. To il‐ lustrate, I’ll add these methods to the class of our object myObject: - (NSUInteger) countOfPepBoys { return [self.theData count]; } - (id) objectInPepBoysAtIndex: (NSUInteger) ix { return (self.theData)[ix]; } By implementing countOf... and objectIn...AtIndex:, I’m telling the key–value coding system to act as if the given key (@"pepBoys" in this case) existed and were an array. An attempt to fetch the value of the key @"pepBoys" by way of key–value coding will succeed, and will return an object that can be treated as an array, though in fact it is a proxy object (an NSKeyValueArray). Thus we can now say [myObject valueForKey: @"pepBoys"] to obtain this array proxy, and we can say [myObject valueForKeyPath: @"pepBoys.name"] to get the same array of strings as before. This particular example may seem a little silly because the underlying implementation is already an array instance variable, but you can imagine an implementation whereby the result of objectInPepBoysAtIndex: is obtained through some completely different sort of op‐ eration. The proxy object returned through this sort of façade behaves like an NSArray, not like an NSMutableArray. If you want the caller to be able to manipulate the proxy object provided by a KVC façade as if it were a mutable array, you must implement two more methods, and you must obtain a different proxy object by calling mutableArrayValueForKey:. So, for example: 302 | Chapter 12: Accessors and Memory Management - (void) insertObject: (id) val inPepBoysAtIndex: (NSUInteger) ix { [self.theData insertObject:val atIndex:ix]; } - (void) removeObjectFromPepBoysAtIndex: (NSUInteger) ix { [self.theData removeObjectAtIndex: ix]; } Now you can call [myObject mutableArrayValueForKey: @"pepBoys"] to obtain something that acts like a mutable array. (The true usefulness of mutableArrayValueForKey: will be clearer when we talk about key–value observing in Chapter 13.) A complication for the programmer is that none of these methods can be looked up directly in the documentation, because they involve key names that are specific to your object. You can’t find out from the documentation what removeObjectFromPepBoysAtIndex: is for; you have to know, in some other way, that it is part of the implementation of key–value coding compliance for a key @"pepBoys" that can be obtained as a mutable array. Be sure to comment your code so that you’ll be able to understand it later. Another complication, of course, is that getting a method name wrong can cause your object not to be key–value coding compliant. Figuring out why things aren’t working as expected in a case like that can be tricky. Memory Management It comes as a surprise to many beginning Cocoa coders that the programmer has an important role to play in the explicit management of memory. What’s more, managing memory incorrectly is probably the most frequent cause of crashes — or, inversely, of memory leakage, whereby your app’s use of memory increases relentlessly until, in the worst-case scenario, there’s no memory left. Fortunately, if your app uses ARC, your explicit memory management responsibilities can be greatly reduced, which is a tremendous relief, as you are far less likely to make a mistake, and more of your time is liberated to concentrate on what your app actually does instead of dealing with memory management concerns. But even with ARC it is still possible to make a memory management mistake (I speak from personal experi‐ ence), so you still need to understand Cocoa memory management, so that you know what ARC is doing for you, and so that you know how to interface with ARC in situations where it needs your assistance. Do not, therefore, suppose that you don’t need to read this section on the grounds that you’re going to be using ARC. Principles of Cocoa Memory Management The reason why memory must be managed at all is that object references are pointers. As I explained in Chapter 1, the pointers themselves are simple C values (basically they are just integers) and are managed automatically, whereas what an object pointer points Memory Management | 303 to is a hunk of memory that must explicitly be set aside when the object is brought into existence and that must explicitly be freed up when the object goes out of existence. We already know how the memory is set aside — that is what alloc does. But how is this memory to be freed up, and when should it happen? At the very least, an object should certainly go out of existence when no other objects exist that have a pointer to it. An object without a pointer to it is useless; it is occupying memory, but no other object has, or can ever get, a reference to it. This is a memory leak. Many computer languages solve this problem through a policy called garbage col‐ lection. Simply put, the language prevents memory leaks by periodically sweeping through a central list of all objects and destroying those to which no pointer exists. But affixing a form of garbage collection to Objective-C would be an inappropriately ex‐ pensive strategy on an iOS device, where memory is strictly limited and the processor is relatively slow (and may have only a single core). Thus, memory in iOS must be managed more or less manually. But manual memory management is no piece of cake, because an object must go out existence neither too late nor too soon. Suppose we endow the language with the ability for one object to command that another object go out of existence now, this instant. But multiple objects can have a pointer (a reference) to the very same object. If both the object Manny and the object Moe have a pointer to the object Jack, and if Manny tells Jack to go out of existence now, poor old Moe is left with a pointer to nothing (or worse, to garbage). A pointer whose object has been destroyed behind the pointer’s back is a dangling pointer. If Moe subsequently uses that dangling pointer to send a message to the object that it thinks is there, the app will crash. To prevent both dangling pointers and memory leakage, Objective-C and Cocoa im‐ plement a policy of manual memory management based on a number, maintained by every object, called its retain count. Other objects can increment or decrement an object’s retain count. As long as an object’s retain count is positive, the object will persist. No object has the direct power to tell another object to be destroyed; rather, as soon as an object’s retain count is decremented to zero, it is destroyed automatically. By this policy, every object that needs Jack to persist should increment Jack’s retain count, and should decrement it once again when it no longer needs Jack to persist. As long as all objects are well-behaved in accordance with this policy, the problem of man‐ ual memory management is effectively solved: • There cannot be any dangling pointers, because any object that has a pointer to Jack has incremented Jack’s retain count, thus ensuring that Jack persists. • There cannot be any memory leaks, because any object that no longer needs Jack decrements Jack’s retain count, thus ensuring that eventually Jack will go out of 304 | Chapter 12: Accessors and Memory Management Debugging Memory Management Mistakes Memory management mistakes are among the most common pitfalls for beginners and even for experienced Cocoa programmers. Though far less likely to occur under ARC, they still can occur under ARC, especially because a programmer using ARC is prone to suppose (wrongly) that they can’t. What experience really teaches is to use every tool at your disposal to ferret out possible mistakes. Here are some of those tools (and see Chapter 9): • The static analyzer (Product → Analyze) knows a lot about memory management and can help call potential memory management mistakes to your attention. • Instruments has excellent tools for noticing leaks and tracking memory manage‐ ment of individual objects (Product → Profile). • Good old caveman debugging can help confirm that your objects are behaving as you want them to. Implement dealloc with an NSLog call. If it isn’t called, your object is not going out of existence. This technique can reveal problems that neither the static analyzer nor Instruments will directly expose. • Dangling pointers are particularly difficult to track down, but they can often be located by “turning on zombies.” This is easy in Instruments with the Zombies template, but unfortunately it doesn’t work on a device. For a device, edit the Run action in your scheme, switch to the Diagnostics tab, and check Enable Zombie Objects. The result is that no object ever goes out of existence; instead, it is replaced by a “zombie” that will report to the console if a message is sent to it (“message sent to deallocated instance”). Be sure to turn zombies back off when you’ve finished tracking down your dangling pointers. existence (when the retain count reaches zero, indicating that no object needs Jack any longer). Obviously, all of this depends upon all objects cooperating in obedience to this memory management policy. Cocoa’s objects (objects that are instances of built-in Cocoa classes) are well-behaved in this regard, but you must make sure your objects are well-behaved. Before ARC, ensuring that your objects were well-behaved was entirely up to you and your explicit code; under ARC, your objects will be well-behaved more or less auto‐ matically, provided you understand how to cooperate with ARC’s automated behavior. The Golden Rules of Memory Management An object is well-behaved with respect to memory management as long as it adheres to certain very simple rules in conformity with the basic concepts of memory management outlined in the previous section. Memory Management | 305 Before I tell you the rules, it may help if I remind you (because this is confusing to beginners) that a variable name, including an instance variable, is just a pointer. When you send a message to that pointer, you are really sending a message through that pointer, to the object to which it points. The rules for memory management are rules about objects, not names, references, or pointers. You cannot increment or decrement the retain count of a pointer; there is no such thing. The memory occupied by the pointer is managed automatically (and is tiny). Memory management is concerned with the object to which the pointer points. (That is why I’ve referred to my example objects by proper names — Manny, Moe, and Jack — and not by variable names. The question of who has retained Jack has nothing to do with the name by which any particular object refers to Jack.) The two things are easily confused, especially because — as I’ve often pointed out in earlier chapters — the variable name pointing to an object is so often treated as the object that there is a tendency to think that it is the object. It’s clumsy, in fact, to distin‐ guish the name from the object it points to. But in discussing memory management, I’ll try to maintain that distinction. Here, then, are the golden rules of Cocoa memory management: • To increment the retain count of any object, send it the retain message. This is called retaining the object. The object is now guaranteed to persist at least until its retain count is decremented once more. To make this a little more convenient, a retain call returns as its value the retained object — that is, [myObject retain] returns the object pointed to by myObject, but with its retain count incremented. • When you (meaning a certain object) say alloc to a class — or new, which is a way of saying alloc — the resulting instance comes into the world with its retain count already incremented. You do not need to retain an object you’ve just instantiated by saying alloc or new (and you should not). Similarly, when you say copy to an instance, the resulting new object (the copy) comes into the world with its retain count already incremented. You do not need to retain an object you’ve just instan‐ tiated by saying copy (and you should not). • To decrement the retain count of any object, send it the release message. This is called releasing the object. If you (meaning a certain object) obtained an object by saying alloc or copy, or if you said retain to an object, you (meaning the same object) should balance this eventually by saying release to that object, once. You should assume that thereafter the object no longer exists. A general way of understanding the golden rules of Cocoa memory management is to think in terms of ownership. If Manny has said alloc, retain, or copy with regard to Jack, Manny has asserted ownership of Jack. More than one object can own Jack at once, but each such object is responsible only for managing its own ownership of Jack cor‐ 306 | Chapter 12: Accessors and Memory Management rectly. It is the responsibility of an owner of Jack eventually to release Jack, and a non‐ owner of Jack must never release Jack. As long as all objects that ever take ownership of Jack behave this way, Jack will not leak nor will any pointer to Jack be left dangling. Now, under ARC, as I shall explain presently in more detail, these rules remain exactly the same, but they are obeyed for you in an automated fashion by the compiler. In an ARC-based app, you never say retain or release — in fact, you’re not allowed to. Instead, the compiler says retain or release for you, using exactly the principles you would have had to use if you had said them (the golden rules of Cocoa memory man‐ agement)! Since the compiler is smarter (or at least more ruthlessly tenacious) than you are about this sort of nit-picky rule-based behavior, it won’t make any of the mistakes you might have made due to carelessness or confusion. The moment an object is released, there is a chance it will be destroyed. Before ARC, this fact was a big worry for programmers. In a non-ARC program, you must take care not to send any messages subsequently through any pointer to an object that has been destroyed — including the pointer you just used to release the object. In effect, you’ve just turned your own pointer into a possible dangling pointer! If there is any danger that you might accidentally attempt to use this dangling pointer, a wise policy is to nilify the pointer — that is, to set the pointer itself to nil. A message to nil has no effect, so if you do send a message through that pointer, it won’t do any good, but at least it won’t do any harm (kind of like chicken soup). In an ARC-based program, this policy, too, is strictly followed: ARC will nilify for you any pointer to whose object it has just sent the last balancing release message (meaning that the object might now have gone out of existence). Since, as I mentioned in Chap‐ ter 3, ARC also sets an instance pointer to nil when you declare it (if you don’t initialize it yourself, there and then, to point to an actual instance), there follows as the night the day the following delightful corollary: under ARC, every instance pointer either points to an actual instance or is nil. This fact alone should send you rushing to convert all your existing non-ARC apps to ARC if you possibly can. What ARC Is and What It Does When you create a new Xcode project and choose an application template, a checkbox in the second dialog lets you elect to Use Automatic Reference Counting. Automatic Reference Counting is ARC. If this checkbox is checked, then (among other things): • The LLVM compiler build setting Objective-C Automatic Reference Counting (CLANG_ENABLE_OBJC_ARC) for your project is set to YES. • Any retain or release statements that would have been present in the non-ARC version of any of the project template’s .m files are stripped out. Memory Management | 307 • Any code that Xcode subsequently inserts automatically, such as a property gener‐ ated by Control-dragging from a nib into code, will conform to ARC conventions. It is also possible to convert an existing non-ARC project to ARC; choose Edit → Re‐ factor → Convert to Objective-C ARC for assistance with the necessary code changes. You do not have to adopt ARC for an entire project; if you have old non-ARC code, possibly written by someone else, you may wish to incorporate that code into your ARCbased project without substantially altering the non-ARC code. To do so, confine all non-ARC code to its own files, and for each of those files, edit the target, switch to the Build Phases tab, and in the Compile Sources section, double-click the non-ARC file’s listing and type -fno-objc-arc in the box (to enter it in the Compiler Flags column). ARC is actually a feature of LLVM 3.0 and later, and is one of the main purposes for which the LLVM compiler was developed. For full tech‐ nical information, see http://clang.llvm.org/docs/AutomaticReference Counting.html. When you compile an ARC-based project, the compiler will treat any explicit retain or release commands as an error, and will instead, behind the scenes, insert its own commands that effectively do the exact same work as retain and release commands. Your code is thus manually memory-managed, in conformity with the principles and golden rules of manual memory management that I’ve already described, but the author of the manual memory-management code is the compiler (and the memorymanagement code itself is invisible, unless you feel like reading assembly language). ARC does its work of inserting retain and release commands in two stages: 1. It behaves very, very conservatively; basically, if in doubt, it retains — and of course it later releases. In effect, ARC retains at every juncture that might have the slightest implications for memory management: it retains when an object is received as an argument, it retains when an object is assigned to a variable, and so forth. It may even insert temporary variables to enable it to refer sufficiently early to an object so that it can retain it. But of course it also releases to match. This means that at the end of the first stage, memory management is technically correct; there may be far more retains and releases on a single object than you would have put if you were writing those commands yourself, but at least you can be confident that no pointer will dangle and no object will leak. 2. It optimizes, removing as many retain and release pairs from each object as it possibly can while still ensuring safety with regard to the program’s actual behavior. This means that at the end of the second stage, memory management is still tech‐ nically correct, and it is also efficient. 308 | Chapter 12: Accessors and Memory Management So, for example, consider the following code: - (void) myMethod { NSArray* myArray = [NSArray array]; NSArray* myOtherArray = myArray; } Now, in actual fact, no additional memory management code is needed here (for reasons that I’ll clarify in the next section). But in its first pass, we may imagine that ARC will behave very, very conservatively: it will ensure that every variable is nil or points to an object, and it will retain every value as it is assigned to a variable, at the same time releasing the value previously pointed to by the variable being assigned to, on the as‐ sumption that it previously retained that value when assigning it to that variable as well. So we may imagine (though this is unlikely to be exactly correct) a scenario where ARC compiles that code at first into the equivalent of Example 12-1. Example 12-1. Imaginary scenario: ARC’s conservative memory management - (void) myMethod { // create all new object pointers as nil NSArray* myArray = nil; // retain as you assign, release the previous value id temp1 = myArray; myArray = [NSArray array]; [myArray retain]; [temp1 release]; // (no effect, it's nil) // create all new object pointers as nil NSArray* myOtherArray = nil; // retain as you assign, release the previous value id temp2 = myOtherArray; myOtherArray = myArray; [myOtherArray retain]; [temp2 release]; // (no effect, it's nil) // method is ending, balance out retains on local variables [myArray release]; myArray = nil; [myOtherArray release]; myOtherArray = nil; } The ARC optimizer will then come along and reduce the amount of work being done here. For example, it may observe that myArray and myOtherArray turn out to be point‐ ers to the same object, so it may therefore remove some of the intermediate retains and releases. And it may observe that there’s no need to send release to nil. But retains and releases are so efficient under ARC that it wouldn’t much matter if the optimizer didn’t remove any of the intermediate retains and releases. But there’s more to the manual memory management balancing act than matching retain and release: in particular, I said earlier that alloc and copy yielded objects whose retain count had already been incremented, so that they, too, must be balanced Memory Management | 309 by release. In order to obey this part of the golden rules of Cocoa memory manage‐ ment, ARC resorts to assumptions about how methods are named. This means that you had better conform, in your code, to the same assumptions about how methods are named, or you can accidentally cause ARC to do the wrong things (although, as it turns out, there are ways out of this predicament if you have a wrongly-named method whose name you absolutely can’t change). In particular, when your code receives an object as the returned value of a method call, ARC looks at the opening word (or words) of the camelCased method name. (The term camelCased describes a compound word whose individual words are demarcated by internal capitalization, like the words “camel” and “Cased” in the word “camelCased.”) If the opening word of the name of that method is alloc, init, new, copy, or mutableCopy, ARC assumes that the object it returns comes with an incremented retain count that will need to be balanced with a corresponding release. So, in the preceding example, if the array had been received from a call to [NSArray new] instead of [NSArray array], ARC would know that an extra release will be needed, to balance the incremented retain count of the object returned from a method whose name begins with new. Your own responsibility in this regard, then, is not to name any of your methods inap‐ propriately in such a way as to set off that sort of alarm bell in ARC’s head. The easiest approach is not to start any of your own method names with alloc, init (unless you’re writing an initializer, of course), new, copy, or mutableCopy. Doing so might not cause any damage, but it is better not to take the risk: obey the ARC naming conventions if you possibly can. How Cocoa Objects Manage Memory Built-in Cocoa objects will take ownership of objects you hand them, by retaining them, if it makes sense for them to do so. (Indeed, this is so generally true that if a Cocoa object is not going to retain an object you hand it, there will be a note to that effect in the documentation.) Thus, you don’t need to worry about managing memory for an object if the only thing you’re going to do with it is hand it over to a Cocoa object. A good example is an NSArray. Consider the following minimal example: NSString* s = [[NSDate date] description]; NSArray* arr = [NSArray arrayWithObject: s]; When you hand the string to the array, the array retains the string. As long as the array exists and the string is in the array, the string will exist. When the array goes out of existence, if the string is still in the array, the array will also release the string; if no other object is retaining the string, the string will then go out of existence in good order, without leaking, and all will be well. All of this is right and proper; the array could hardly “contain” the string without taking ownership of it. 310 | Chapter 12: Accessors and Memory Management An NSMutableArray works the same way, with additions. When you add an object to an NSMutableArray, the array retains it. When you remove an object from an NSMutableArray, the array releases it. Again, the array is always doing the right thing. Thus you should stay out of, and not worry yourself about, memory management for objects you don’t own; the right thing will happen all by itself. For instance, look back at Example 10-2. Here it is again: NSString* f = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"txt"]; NSError* err = nil; NSString* s = [NSString stringWithContentsOfFile:f encoding:NSUTF8StringEncoding error:&err]; // error-checking omitted NSMutableDictionary* d = [NSMutableDictionary dictionary]; for (NSString* line in [s componentsSeparatedByString:@"\n"]) { NSArray* items = [line componentsSeparatedByString:@"\t"]; NSInteger chnum = [items[0] integerValue]; NSNumber* key = @(chnum); NSMutableArray* marr = d[key]; if (!marr) { // no such key, create key–value pair marr = [NSMutableArray array]; d[key] = marr; } // marr is now a mutable array, empty or otherwise NSString* picname = items[1]; [marr addObject: picname]; } No explicit memory management is happening here, and no additional memory man‐ agement needs to happen (even if you aren’t using ARC). We’re generating a lot of objects, but never do we say alloc (or copy), so we have no ownership, and memory management is therefore not our concern. Moreover, no bad thing is going to happen between one line and the next while this code is running. The mutable dictionary d, for example, generated by calling [NSMutableDictionary dictionary], is not going to vanish mysteriously before we can finish adding objects to it. (I’ll say a bit more, later in this chapter, about why I’m so confident of this.) On the other hand, it is possible (if you aren’t using ARC) to be tripped up by how Cocoa objects manage memory. Consider the following: NSString* s = myMutableArray[0]; [myMutableArray removeObjectAtIndex: 0]; // bad idea! (but just fine under ARC) Here we remove a string from an array, keeping a reference to it ourselves as s. But, as I just said, when you remove an object from an NSMutableArray, the array releases it. So the commented line of code in the previous example involves an implicit release of the string in question, and if this reduces the string’s retain count to zero, it will be destroyed. In effect, we’ve just done the thing I warned you about earlier: we’ve turned Memory Management | 311 our own pointer s into a possible dangling pointer, and a crash may be in our future when we try to use it as if it were a string. The way to ensure against such possible destruction in non-ARC code is to retain the object before doing anything that might destroy it (Example 12-2). Example 12-2. How non-ARC code ensures a collection element’s persistence NSString* s = myMutableArray[0]; [s retain]; // this is non-ARC code [myMutableArray removeObjectAtIndex: 0]; Of course, now you have made management of this object your business; you have asserted ownership of it, and must make sure that this retain is eventually balanced by a subsequent release, or the string object may leak. However, the very same code works perfectly under ARC: NSString* s = myMutableArray[0]; [myMutableArray removeObjectAtIndex: 0]; // Just fine under ARC The reason is that, as I mentioned earlier, ARC is insanely conservative at the outset. Just as in Example 12-1, ARC retains on assignment, so we may imagine that ARC will operate according to something like the imaginary scenario shown in Example 12-3. Example 12-3. Imaginary scenario: ARC ensures a collection element’s persistence NSString* s = nil; // retain as you assign, release the previous value id temp = s; s = myMutableArray[0]; [s retain]; [temp release]; // (no effect, it's nil) // and now this move is safe [myMutableArray removeObjectAtIndex: 0]; // ... and later ... [s release]; s = nil; This turns out to be exactly the right thing to do! When the call to removeObjectAtIndex: comes along, the retain count of the object received from the array is still in‐ cremented, exactly as in our non-ARC Example 12-2. Autorelease When you call a method and receive as a result what Chapter 5 calls a ready-made instance, how does memory management work? Consider, for example, this code: NSArray* myArray = [NSArray array]; 312 | Chapter 12: Accessors and Memory Management According to the golden rules of memory management, the object now pointed to by myArray doesn’t need memory management. You didn’t say alloc in order to get it, so you haven’t claimed ownership of it and you don’t need to release it (and shouldn’t do so). But how is this possible? How is the NSArray class able to vend an array that you don’t have to release without also leaking that object? If you don’t see why this is mysterious, pretend that you are NSArray. How would you implement the array method so as to generate an array that the caller doesn’t have to memory-manage? Don’t say that you’d just call some other NSArray method that vends a ready-made instance; that merely pushes the same problem back one level. You are NSArray. Sooner or later, you must somehow supply this magical instance. Ultimately you will have to generate the instance from scratch, and then how will you manage its memory? You can’t do it like this: - (NSArray*) array { NSArray* arr = [[NSArray alloc] init]; return arr; // hmmm, not so fast... } This, it appears, can’t work. On the one hand, we generated arr’s value by saying alloc. This means we must release the object pointed to by arr. On the other hand, when are we going to do this? If we do it just before returning arr, arr will be pointing to garbage and we will be vending garbage. We cannot do it just after returning arr, because our method exits when we say return. This is a puzzle. It is our job, if we are to be a good Cocoa citizen and follow the golden rules of memory management, to decrement the retain count of this object. We need a way to vend this object without decrementing its retain count now (so that it stays in existence long enough for the caller to receive and work with it), yet ensure that we will decrement its retain count (to balance our alloc call and fulfill our own management of this object’s memory). The solution, which is explicit in pre-ARC code, is autorelease: - (NSArray*) array { NSArray* arr = [[NSArray alloc] init]; [arr autorelease]; return arr; } Or, because autorelease returns the object to which it sent, we can condense that: - (NSArray*) array { NSArray* arr = [[NSArray alloc] init]; return [arr autorelease]; } Here’s how autorelease works. Your code runs in the presence of something called an autorelease pool. (If you look in main.m, you can actually see an autorelease pool being created.) When you send autorelease to an object, that object is placed in the autore‐ Memory Management | 313 lease pool, and a number is incremented saying how many times this object has been placed in this autorelease pool. From time to time, when nothing else is going on, the autorelease pool is automatically drained. This means that the autorelease pool sends release to each of its objects, the same number of times as that object was placed in this autorelease pool, and empties itself of all objects. If that causes an object’s retain count to be zero, fine; the object is destroyed in the usual way. So autorelease is just like release — effectively, it is a form of release — but with a proviso, “later, not right this second.” You don’t need to know exactly when the current autorelease pool will be drained; in‐ deed, you can’t know (unless you force it, as we shall see). The important thing is that in a case like our method array, there will be plenty of time for whoever called array to retain the vended object if desired. The vended object in a case like our method array is called an autoreleased object. The object that is doing the vending has in fact completed its memory management of the vended object. The vended object thus potentially has a zero retain count. But it doesn’t have a zero retain count just yet. The vended object is not going to vanish right this second, just after your call to [NSArray array], because your code is still running and so the autorelease pool is not going to be drained right this second. The recipient of such an object needs to bear in mind that this object may be autoreleased. The object won’t vanish while the code that called the method that vended the object is running, but if the receiving object wants to be sure that the vended object will persist later on, it should retain it. This explains why there’s no explicit memory management in Example 10-2 (cited ear‐ lier in this chapter): we don’t madly retain every object we obtain in that code, even in non-ARC code, because those objects will all persist long enough for our code to finish. This fits with the golden rules of memory management. An object you receive by means other than those listed among the golden rules as asserting ownership (alloc or copy) isn’t under your ownership. The object will either be owned and retained by some other persistent object, in which case it won’t vanish while the other object persists, or it will be independent but autoreleased, in which case it will at least persist while your code continues to run. If you want it to persist and you’re afraid it might not, you should take ownership of it by retaining it. Under ARC, as you might expect, all the right things happen of their own accord. You don’t have to say autorelease, and indeed you cannot. Instead, ARC will say it for you. And it says it in accordance with the method naming rule I described earlier. A method called array, for example, does not start with a camelCase unit new, init, alloc, copy, or mutableCopy. Therefore it must return an object whose memory management is bal‐ anced, using autorelease for the last release. ARC will see to it that this is indeed the case. On the other side of the ledger, the method that called array and received an array 314 | Chapter 12: Accessors and Memory Management in return must assume that this object is autoreleased and could go out of existence if we don’t retain it. That’s exactly what ARC does assume. Sometimes you may wish to drain the autorelease pool immediately. Consider the fol‐ lowing: for (NSString* aWord in myArray) { NSString* lowerAndShorter = [[aWord lowercaseString] substringFromIndex:1]; [myMutableArray addObject: lowerAndShorter]; } Every time through that loop, two objects are added to the autorelease pool: the low‐ ercase version of the string we start with, and the shortened version of that. The first object, the lowercase version of the string, is purely an intermediate object: as the current iteration of the loop ends, no one except the autorelease pool has a pointer to it. If this loop had very many repetitions, or if these intermediate objects were themselves very large in size, this could add up to a lot of memory. These intermediate objects will all be released when the autorelease pool drains, so they are not leaking; nevertheless, they are accumulating in memory, and in certain cases there could be a danger that we will run out of memory before the autorelease pool drains. The problem can be even more acute than you know, because you might repeatedly call a built-in Cocoa method that itself accumulates a lot of intermediate objects. The solution is to intervene in the autorelease pool mechanism by supplying your own autorelease pool. This works because the autorelease pool used to store an autoreleased object is the most recently created pool. So you can just create an autorelease pool at the top of the loop and drain it at the bottom of the loop, each time through the loop. In modern Objective-C, the notation for doing this is to surround the code that is to run under its own autorelease pool with the directive @autoreleasepool{}, like this: for (NSString* aWord in myArray) { @autoreleasepool { NSString* lowerAndShorter = [[aWord lowercaseString] substringFromIndex:1]; [myMutableArray addObject: lowerAndShorter]; } } Many classes provide the programmer with two equivalent ways to obtain an object: either an autoreleased object or an object that you create yourself with alloc and some form of init. So, for example, NSArray supplies both the class method arrayWithObjects: and the instance method initWithObjects:. Which should you use? Before ARC, Apple stated that they would prefer you to lean toward initWithObjects:. In general, where you can generate an object with alloc and some form of init, they’d like you to do so. That way, you are in charge of releasing the object. This policy prevents your objects from hanging around in the autorelease pool and keeps your use of memory as low as possible. Under ARC, I still tend to adhere to this policy from force of habit, Memory Management | 315 but in fact the ARC autorelease pool architecture is so efficient that the old policy may no longer provide any advantage. Memory Management of Instance Variables (Non-ARC) Before ARC, the main place for the programmer to make a memory management mis‐ take was with respect to instance variables. Memory management of temporary vari‐ ables within a single method is pretty easy; you can see the whole method at once, so now just follow the golden rules of memory management, balancing every retain, alloc, or copy with a release (or, if you’re returning an object with an incremented retain count, autorelease). But instance variables make things complicated, for many reasons: • Instance variables are persistent. Your own instance variables will persist when this method is over and your code has stopped running and the autorelease pool has been drained. So if you want an object value pointed to by an instance variable not to vanish in a puff of smoke, leaving you with a dangling pointer, you’d better retain it as you assign it to the instance variable. • Instance variables are managed from different places in your code. This means that memory management can be spread out over several different methods, making it difficult to get right and difficult to debug if you get it wrong. For example, if you retained a value assigned to an instance variable, you’ll later need to release it, conforming with the golden rules of memory management, to prevent a leak — but in some other method. • Instance variables might not belong to you. You will often assign to or get a value from an instance variable belonging to another object. You are now sharing access to a value with some other persistent object. If that other object were to go out of existence and release its instance variables, and you have a pointer to the instance variable value coming from that other object and you haven’t asserted your own ownership by retaining that value, you can wind up with a dangling pointer. To see what I mean, return once more to Example 10-2. As I have already explained, there was no need to worry about memory management during this code, even without ARC. We have a mutable dictionary d, which we acquired as a ready-made instance by calling [NSMutableDictionary dictionary], and it isn’t going to vanish while we’re working with it. Now, however, suppose that in the next line we propose to assign d to an instance variable of ours: self->_theData = d; // in non-ARC code this would be a bad idea! Before ARC, that code constituted a serious potential mistake. If our code now comes to a stop, we’re left with a persistent pointer to an object over which we have never asserted ownership; it might vanish, leaving us with a dangling pointer. The solution, 316 | Chapter 12: Accessors and Memory Management obviously, is to retain this object as we assign it to our instance variable. You could do it like this: [d retain]; self->_theData = d; Or you could do it like this: self->_theData = d; [self->_theData retain]; Or, because retain returns the object to which it sent, you could actually do it like this: self->_theData = [d retain]; So which should you use? Probably none of them. Consider what a lot of trouble it will be if you ever want to assign a different value to self->_theData. You’re going to have to remember to release the object already pointed to (to balance the retain you’ve used here), and you’re going to have to remember to retain the next value as well. It would be much better to encapsulate memory management for this instance variable in an accessor (a setter). That way, as long as you always pass through the accessor, memory will be managed correctly. A standard template for such an accessor might look like Example 12-4. Example 12-4. A simple retaining setter - (void) setTheData: (NSMutableArray*) value { if (self->_theData != value) { [self->_theData release]; self->_theData = [value retain]; } } In Example 12-4, we release the object currently pointed to by our instance variable (and if that object is nil, no harm done) and retain the incoming value before assigning it to our instance variable (and if that value is nil, no harm done either). The test for whether the incoming value is the very same object already pointed to by our instance variable is not just to save a step; it’s because if we were to release that object, it could vanish then and there, instantly turning value into a dangling pointer — which we would then, horribly, assign to self->_theData. The setter accessor now manages memory correctly for us; provided we always use it to set our instance variable, all will be well. This is one of the main reasons why accessors are so important! So the assignment to the instance variable in our original code should now look like this: [self setTheData: d]; Memory Management | 317 Observe that we can also use this setter subsequently to release the value of the instance variable and nilify the instance variable itself, thus preventing a dangling pointer, all in a single easy step: [self setTheData: nil]; So there’s yet another benefit of using an accessor to manage memory. Our memory management for this instance variable is still incomplete, however. We (meaning the object whose instance variable this is) must also remember to release the object pointed to by this instance variable at the last minute before we ourselves go out of existence. Otherwise, if this instance variable points to a retained object, there will be a memory leak. The “last minute” is typically dealloc, the NSObject method (Chap‐ ter 10) that is called as an object goes out of existence. In dealloc, there is no need to use accessors to refer to an instance variable, and in fact it’s not a good idea to do so, because you never know what other side effects an accessor might have. And (under non-ARC code) you must always call super last of all. So here’s our implementation of this object’s dealloc: - (void) dealloc { [self->_theData release]; [super dealloc]; } That completes the memory management for one instance variable. In general, if you are not using ARC, you will need to make sure that every object of yours has a dealloc that releases every instance variable whose value has been retained. This, obviously, is one more very good opportunity for you to make a mistake. Never, never call dealloc in your code, except to call super last of all in your override of dealloc. Under ARC, you can’t call dealloc — yet another example of how ARC saves you from yourself. Just as it’s not a good idea to use your own accessors to refer to your own instance variable in dealloc, so you should not use your own accessors to refer to your own instance variables in an initializer (see Chapter 5). The reason is in part that the object is not yet fully formed, and in part that an accessor can have other side effects. Instead, you will set your instance variables directly, but you must also remember to manage memory. To illustrate, I’ll rewrite the example initializer from Chapter 5 (Example 5-3). This time I’ll allow our object (a Dog) to be initialized with a name. The reason I didn’t discuss this possibility in Chapter 5 is that a string is an object whose memory must be managed! So, imagine now that we have an instance variable _name whose value is an NSString, and we want an initializer that allows the caller to pass in a value for this instance variable. It might look like Example 12-5. 318 | Chapter 12: Accessors and Memory Management Example 12-5. A simple initializer that retains an ivar - (id) initWithName: (NSString*) s { self = [super init]; if (self) { self->_name = [s retain]; } return self; } Actually, it is more likely in the case of an NSString that you would copy it rather than merely retain it. The reason is that NSString has a mutable subclass NSMutableString, so some other object might call initWithName: and hand you a mutable string to which it still holds a reference — and then mutate it, thus changing this Dog’s name behind your back. So the initializer would look like Example 12-6. Example 12-6. A simple initializer that copies an ivar - (id) initWithName: (NSString*) s { self = [super init]; if (self) { self->_name = [s copy]; } return self; } In Example 12-6, we don’t bother to release the existing value of _name; it is certainly not pointing to any previous value (because there is no previous value), so there’s no point. Thus, memory management for an instance variable may take place in as many as three places: the initializer, the setter, and dealloc. This is a common architecture. It is a lot of work, and a common source of error, having to look in multiple places to check that you are managing memory consistently and correctly, but that’s what you must do if you aren’t using ARC (though, as I’ll point out later in this chapter, Objective-C has the ability to write your accessors for you). Earlier, I mentioned that KVC will set an instance variable directly if it can’t find a setter corresponding to the key. When it does this, it retains the incoming value. This fact is little-known and poorly documented — and scary. The last thing you want, in non-ARC code, is implicit mem‐ ory management. This is one more reason to provide accessors. On the other hand, if you’re using ARC, this is not such a worry, since ARC is already providing implicit memory management. Memory Management | 319 Memory Management of Instance Variables (ARC) If you’re using ARC, ARC will manage your instance variable memory for you; you needn’t (and, by and large, you can’t) do it for yourself. By default, ARC will treat an instance variable the same way it treats any variable: on assignment to that instance variable, it creates a temporary variable, retains the assigned value in it, releases the current value of the instance variable, and performs the assignment. Thus, you write this code: self->_theData = d; // an NSMutableDictionary ARC, in effect, in accordance with its rule that it retains on assignment and releases the old value, substitutes something like this scenario: // imaginary scenario: retain on assignment, release the previous value id temp = self->_theData; self->_theData = d; [self->_theData retain]; [temp release]; This is exactly the right thing to have happened; in fact, it will not have escaped your attention that it is virtually the same code you would have written for a formal accessor such as Example 12-4. So much for worrying about release and retain on assignment! If you did want to write a setter, it might consist of no more than a direct assignment: - (void) setTheData: (NSMutableArray*) value { self->_theData = value; } Moreover, when your object goes out of existence, ARC releases its retained instance variable values. So much for worrying about releasing in dealloc! You may still need, under ARC, to implement dealloc for other reasons — for example, it could still be the right place to unregister for a notification (Chapter 11) — but you won’t call release on any instance variables there, and you won’t call super. At the time dealloc is called, your instance variables have not yet been released, so it’s fine to refer to them in dealloc. At this point you may be imagining that, under ARC, you might be able to live without any accessors at all: instead, you can just assign directly to your instance variables and all the right memory-management things will happen, so who needs a formal setter? However, a formal accessor, as I’ll explain later, can do things above and beyond ARC’s automated insertion of release-and-retain, such as copying instead of retaining, dealing with multithreading, and adding your own custom behaviors. Also, obviously, accessors can be made public and so available to other objects, whereas an instance variable is not public. 320 | Chapter 12: Accessors and Memory Management In the absence of a release call, which is forbidden under ARC, what happens if you want to release an instance variable’s value manually? The solution is simple: set the instance variable to nil. When you nilify a variable, ARC releases its existing value for you by default. You may be wondering about ARC’s implications for the way you’ll write an initializer that involves setting object instance variable values, as in Example 12-5 and Example 12-6. The code for these initializers will be just the same under ARC as under non-ARC, except that you needn’t (and can’t) say retain. So Example 12-5 under ARC would look like Example 12-7. Example 12-7. A simple initializer that retains an ivar under ARC - (id) initWithName: (NSString*) s { self = [super init]; if (self) { self->_name = s; } return self; } Example 12-6 under ARC will be unchanged, as shown in Example 12-8; you can still say copy under ARC, and ARC understands how to manage the memory of an object returned from a method whose camelCased name starts with (or simply is) copy. Example 12-8. A simple initializer that copies an ivar under ARC - (id) initWithName: (NSString*) s { self = [super init]; if (self) { self->_name = [s copy]; } return self; } Retain Cycles and Weak References ARC’s behavior is automatic and mindless; it knows nothing of the logic of the rela‐ tionships between objects in your app. Sometimes, you have to provide ARC with fur‐ ther instructions to prevent it from doing something detrimental. Typically, this detri‐ mental thing will be the creation of a retain cycle. A retain cycle is a situation in which object A and object B are each retaining one another. This can arise quite innocently, because relationships in an object graph can run both ways. For example, in a system of orders and items, an order needs to know what its items are and an item might need to know what orders it is a part of, so you might be tempted to let it be the case both that an order retains its items and that an item retains Memory Management | 321 its orders. That’s a retain cycle, with object A (an order) retaining object B (an item) and vice versa. Such a situation, if allowed to persist, will result in a leak of both objects, as neither object’s retain count can decrement to zero. Another way of looking it is to say that object A, by retaining object B, is also retaining itself, and thus preventing its own destruction. To illustrate the problem, I’ll suppose a simple class MyClass with a single ivar _thing and a single public setter setThing:, with logging in dealloc, like this: @implementation MyClass { id _thing; } - (void) setThing: (id) what { self->_thing = what; } -(void)dealloc { NSLog(@"%@", @"dealloc"); } @end We now run this code: MyClass* MyClass* m1.thing m2.thing m1 = [MyClass new]; m2 = [MyClass new]; = m2; = m1; Under ARC, unless you take steps to the contrary, this will be a retain cycle; by default, m1 and m2 are now retaining one another, because by default, ARC retains on assignment. When the code runs, dealloc is never called for either of our MyClass instances. They have leaked. You can prevent an instance variable from retaining the object assigned to it by speci‐ fying that the instance variable should be a weak reference. You can do this with the __weak qualifier in the instance variable’s declaration: @implementation MyClass { __weak id _thing; } Now there is no retain cycle. In our example, since both m1 and m2 exist only as automatic variables in the scope of the code that creates them, they will both go out of existence instantly when that code comes to an end and ARC releases them both (to balance the new calls that created them). 322 | Chapter 12: Accessors and Memory Management In ARC, a reference not explicitly declared weak is a strong reference. Thus, a strong reference is one where ARC retains as it assigns. There is in fact a __strong qualifier, but in practice you’ll never use it, as it is the default. (There are also two additional qualifiers, __unsafe_unretained and __autoreleasing, but they are rarely need‐ ed and I don’t talk about them in this book.) In real life, a weak reference is most commonly used to connect an object to its delegate (Chapter 11). A delegate is an independent entity; there is usually no reason why an object needs to claim ownership of its delegate. The object should have no role in the persistence of its delegate; and it could even be that the delegate might for some reason retain the object, causing a retain cycle. Therefore, most delegates should be declared as weak references. For example, in an ARC project created from Xcode’s Utility Ap‐ plication project template, you’ll find this line: @property (weak, nonatomic) id <FlipsideViewControllerDelegate> delegate; (The delegate may also be tagged as an IBOutlet.) The keyword weak in the property declaration, as I’ll explain more fully later in this chapter, is equivalent to declaring the _delegate instance variable as __weak. In non-ARC code, a reference can be prevented from causing a retain cycle merely by not retaining when assigning to that reference; the reference isn’t memory-managed at all. You will see this referred to as a weak reference; it is not, however, quite the same thing as an ARC weak reference. A non-ARC weak reference risks turning into a dan‐ gling pointer when the instance to which it points is released. Thus it is possible for the reference to be non-nil and pointing to garbage, so that a message sent to it can have mysteriously disastrous consequences. Amazingly, however, this cannot happen with an ARC weak reference: the instance to which it points can be released and have its retain count reach zero and vanish, but when it does, any ARC weak reference that was pointing to it is set to nil! This amazing feat is accomplished by some behind-the-scenes bookkeeping: when an object is assigned to a weak reference, ARC in effect notes this fact on a scratchpad list. When the object is released, ARC consults the scratchpad list and discovers the existence of the weak reference to it, and assigns nil to that weak reference. This is yet another reason for preferring to use ARC wherever possible! ARC sometimes refers to non-ARC weak references, disdainfully but accurately, as “unsafe.” (Non-ARC weak references are in fact the __unsafe_unretained references I men‐ tioned a moment ago.) Unfortunately, large parts of Cocoa don’t use ARC. Most properties of built-in Cocoa classes that keep weak references are non-ARC weak references (because they are old and backwards-compatible, whereas ARC is new). Such properties are declared using the keyword assign. For example, UINavigationController’s delegate property is de‐ clared like this: Memory Management | 323 @property(nonatomic, assign) id<UINavigationControllerDelegate> delegate This means that if you assign some object to a UINavigationController as its delegate, and if that object is about to go out of existence at a time when this UINavigation‐ Controller still exists, you have a duty (regardless of whether you’re using ARC) to set that UINavigationController’s delegate property to some other object, or to nil; other‐ wise, it might try to send a message to its delegate at some future time, when the object no longer exists and its delegate property is a dangling pointer, and the app will then crash — and, since this happens at some future time, figuring out the cause of the crash can be quite difficult. (This is the sort of situation in which you might need to turn on zombies in order to debug, as described earlier in this chapter.) New in iOS 6 are collections whose memory management policy is up to you. NSPointerArray, NSHashTable, and NSMapTable are similar respectively to NSMutableArray, NSMutableSet, and NSMutable‐ Dictionary. But an NSHashTable, say, created with the class method weakObjectsHashTable maintains weak references to its elements. Un‐ der ARC, these are weak references in the ARC sense: they are replaced by nil if the retain count of the object to which they were pointing has dropped to zero. You may find uses for these classes as a way of avoiding retain cycles. Unusual Memory Management Situations NSNotificationCenter presents some curious memory management features. As you are likely to want to use notifications (Chapter 11), you’ll need to know about these. If you registered with the notification center using addObserver:selector:name: object:, you handed the notification center a reference to yourself as the first argument; the notification center’s reference to you is a non-ARC weak reference, and there is a danger that after you go out of existence the notification center will try to send a noti‐ fication to whatever is referred to, which, if it isn’t you (because you no longer exist), will be garbage. That is why you must unregister yourself before you go out of existence. By unregistering yourself, you remove the notification center’s reference to you, so there’s no chance it will ever again try to send you a notification. This is similar to the situation with delegates that I was talking about a moment ago. If you registered with the notification center using addObserverForName:object: queue:usingBlock:, memory management can be quite tricky, under ARC in partic‐ ular. Here are the key facts to know: • The observer token returned from the call to addObserverForName:object:queue:usingBlock: is retained by the notification center until you unregister it. 324 | Chapter 12: Accessors and Memory Management • The observer token may also be retaining you through the block. If so, then until you unregister the observer token from the notification center, the notification center is retaining you. This means that you will leak until you unregister. But you cannot unregister from the notification center in dealloc, because dealloc isn’t going to be called so long as you are registered. • In addition, if you also retain the observer token, then if the observer token is retaining you, you have a retain cycle on your hands. Consider, for example, this code, in which we register for a fictitious notification: self->_observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"heyho" object:nil queue:nil usingBlock:^(NSNotification *n) { NSLog(@"%@", self); }]; Our intention is eventually to unregister the observer; that’s why we’re keeping a refer‐ ence to it: [[NSNotificationCenter defaultCenter] removeObserver:self->_observer]; But there are two problems: The notification center is retaining us (self) The rule is that if self is mentioned in a block, then if the block is copied, self is retained. This is a situation where the block is copied. Thus the block retains self, the observer token retains the copied block, and the notification center retains the observer. Therefore we won’t be sent dealloc so long as the observer token remains registered. There’s a potential retain cycle Because self is mentioned in the block, the observer token is retaining us. But we are also retaining the observer token, through the assignment to an instance vari‐ able. How do we know that the block is copied and that self is retained? The NSNotificationCenter class documentation on addObserverForName:object:queue:usingBlock: says so: “The block is copied by the notification center and (the copy) held until the observer registration is removed.” Under ARC, a copied block retains self if self is referred to, even indirectly (that is, even if what is referred to is an instance variable). Memory Management | 325 In effect, we have retained ourselves twice, once by virtue of being registered with the notification center, and again by virtue of retaining the observer token. I will present three solutions to this problem, in what I take to be the order of increasing goodness: Unregister the observer and release the observer Since dealloc won’t be called until after we unregister, you’ll have to set up some earlier code that will be called. If this is a view controller, for example, viewDidDisappear: can be a good place. Unregister the observer, thus causing the notifi‐ cation center to release the observer token. Then set _observer to nil, thus causing ourselves to release the observer token. Now no one is retaining the observer token. The observer token goes out of existence, releasing self as it does so, and we won’t leak. Unregister the observer and don’t retain the observer in the first place Make _observer a weak reference. Now the assignment to self->_observer doesn’t retain the observer token. dealloc still won’t be called until after we un‐ register, so we still have to find earlier code that will be called. Unregister the ob‐ server, thus causing the notification center to release the observer token; no one else is retaining it, so it goes out of existence, releasing self as it does so, and we won’t leak. Don’t let the block retain self in the first place If the block doesn’t retain self, none of these problems arises. dealloc will be called even if the observer is still registered. In dealloc, unregister the observer. How can you prevent the block from retaining self? You use a technique demonstrated in Apple’s WWDC 2011 videos, commonly called “the weak–strong dance” (Example 12-9). Example 12-9. The weak–strong dance prevents a copied block from retaining self __weak MyClass* wself = self; self->observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"heyho" object:nil queue:nil usingBlock:^(NSNotification *n) { MyClass* sself = wself; if (sself) { NSLog(@"%@", sself); } }]; The weak–strong dance works like this: We form a local weak reference to self, outside the block but where the block can see it. It is this weak reference that will pass into the block. 326 | Chapter 12: Accessors and Memory Management Inside the block, we form from that weak reference a normal strong reference. This step may seem unnecessary, but in a multithreaded situation, there is a chance that a weak reference, even a weak reference to self, may vanish out from under us between one line of code and the next. Assigning to a strong reference retains self throughout the rest of the block. We use that normal strong reference in place of any references to self inside the block. The nil test is because, in a multithreaded situation, our weak reference to self may have vanished out from under us before the previous step; it would then be nil, because it’s an ARC weak reference, and in that case there would be no point continuing. The weak–strong dance may seem elaborate, but it’s worth learning to do. It is, as I said, the only one of the three proposed solutions that allows dealloc to be called before you unregister the observer. Thus, it is the only solution that allows you to unregister the observer in your dealloc implementation, which is typically just where you’d prefer to do it. If you expect the notification to be posted and the block to be called only once, there’s another solution: unregister in the block. I’ll show how to do that in Chapter 38. Another unusual case is NSTimer (Chapter 10). The NSTimer class documentation says that “run loops retain their timers”; it then says of scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: that “The target object is retained by the timer and released when the timer is invalidated.” This means that as long as a repeating timer has not been invalidated, the target is being retained by the run loop; the only way to stop this is to send the invalidate message to the timer. (With a nonrepeating timer, the problem doesn’t arise, because the timer invalidates itself immedi‐ ately after firing.) When you called scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:, you probably supplied self as the target: argument. This means that you (self) are being retained, and cannot go out of existence until you invalidate the timer. You can’t do this in your dealloc implementation, because as long as the timer is repeating and has not been sent the invalidate message, dealloc won’t be called. You therefore need to find another appropriate moment for sending invalidate to the timer. There’s no good way out of this situation; you simply have to find such a moment, and that’s that. A block-based alternative to a timer is available through GCD. The timer “object” is a dispatch_source_t, and must be retained, typically as an instance variable (which ARC Memory Management | 327 will manage for you, even though it’s a pseudo-object). The timer will fire repeatedly after you initially “resume” it, and will stop firing when it is released, typically by nilifying the instance variable. But you must still take precautions to prevent the timer’s block from retaining self and causing a retain cycle, just as with notification observers. Here’s some typical skeleton code: @implementation OtherViewController { dispatch_source_t _timer; // ARC will manage this pseudo-object } - (IBAction)doStart:(id)sender { self->_timer = dispatch_source_create( DISPATCH_SOURCE_TYPE_TIMER,0,0,dispatch_get_main_queue()); dispatch_source_set_timer( self->_timer, dispatch_walltime(NULL, 0), 1 * NSEC_PER_SEC, 0.1 * NSEC_PER_SEC); dispatch_source_set_event_handler(self->_timer, ^{ NSLog(@"%@", self); // retain cycle }); dispatch_resume(self->_timer); } - (IBAction)doStop:(id)sender { self->_timer = nil; } -(void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; self->_timer = nil; // break retain cycle } @end In general, you must be on the lookout for Cocoa objects with unusual memory man‐ agement behavior. Such behavior will usually be called out clearly in the documentation. For example, the UIWebView documentation warns: “Before releasing an instance of UIWebView for which you have set a delegate, you must first set its delegate property to nil.” And a CAAnimation object retains its delegate; this is exceptional and can cause trouble if you’re not conscious of it. There are also situations where the documentation fails to warn of any special memory management considerations, but ARC itself will warn of a possible retain cycle due to the use of self in a block. Again, the weak–strong dance is likely to be your best defense. An example is the completion handler of UIPageViewController’s instance method setViewControllers:direction:animated:completion:, where the compiler will warn, “Capturing ‘self ’ strongly in this block is likely to lead to a retain cycle.” Using the weak– strong dance, you capture self weakly instead. 328 | Chapter 12: Accessors and Memory Management Figure 12-1. An outlet graph with retain Nib Loading and Memory Management On iOS, when a nib loads, the top-level nib objects that it instantiates are autoreleased. So if someone doesn’t retain them, they’ll quickly vanish in a puff of smoke. There are two primary strategies for preventing that from happening: Outlet graph with retain A memory management graph is formed: every top-level object is retained by an‐ other top-level object (without retain cycles, of course), with the File’s Owner as the start of the graph. So, the File’s Owner proxy has an outlet to a top-level object; when the nib loads and the top-level object is assigned to the corresponding instance variable of the actual nib owner instance (Chapter 7), it is retained. If you arrange the chain of retains correctly, all objects that need to be retained will be (Figure 12-1). This is the strategy you’ll typically use when loading a nib. You can see this strategy being used, for example, in a project made from the Single View Application template. The ViewController class is a UIViewController sub‐ class; UIViewController has a view property which retains the value assigned to it. Inside the nib, an outlet called view runs from the File’s Owner, which is a View‐ Controller, to the top-level UIView (called View) in the nib. Thus this view is as‐ signed to the ViewController’s view property when the nib loads; therefore it is retained and doesn’t vanish in a puff of smoke. Mass retain The call to NSBundle’s loadNibNamed:owner:options: (Chapter 7) returns an NSArray of the top-level objects instantiated from the nib; retain this NSArray. This is the strategy used by UIApplicationMain when it loads the app’s main nib, if there is one. Similarly, UINib’s instantiateWithOwner:options: returns an array of the top-level objects instantiated from the nib. In Chapter 21 I’ll show an example. Memory Management | 329 Objects in the nib that are not top-level objects are already part of a memory manage‐ ment object graph, so there’s no need for you to retain them directly. For example, if you have a top-level UIView in the nib, and it contains a UIButton, the UIButton is the UIView’s subview — and a view retains its subviews and takes ownership of them. Thus, it is sufficient to manage the UIView’s memory and to let the UIView manage the UI‐ Button. If you have an outlet to this button, you typically don’t have to retain the button, because it is retained by the UIView as long as the UIButton is inside it (though you would want to retain the button in the rare case where you are planning at some point in your code to remove the button from its superview while keeping it on hand for later use). Mac OS X Programmer Alert Memory management for nib-loaded instances is different on iOS than on Mac OS X. On Mac OS X, nib-loaded instances are not autoreleased, so they don’t have to be retained, and memory management is usually automatic in any case because the file’s owner is usually an NSWindow‐ Controller, which takes care of these things for you. On iOS, memory management of top-level nib objects is up to you. On Mac OS X, an outlet to a non-top-level object does not cause an extra retain if there is no accessor for the corresponding ivar; on iOS, it does. Memory Management of Global Variables In C, and therefore in Objective-C, it is permitted to declare a variable outside of any method. K&R (Chapter 1) calls this an external variable (see K&R 4.3); I call it a global variable. It is common practice, though not strictly required, to qualify such a variable’s declaration as static; such qualification is a technical matter of scope and has no effect on the variable’s persistence or its global nature. Global variables are a C variable type, defined at file level; they know nothing of in‐ stances. Insofar as they have any relation to object-based programming, they may be defined in a class file so they are effectively class-level variables. In Objective-C code, a global variable is not uncommonly used as a constant. You can sometimes initialize it as you declare it: NSString* g_myString = @"my string"; If the value you want to assign to a global isn’t itself a constant, you’ll have to assign the value in actual code; the question is then where to put that code. Since a global variable is effectively a class-level variable, it makes sense to initialize it early in the lifetime of the class, namely in initialize (see Chapter 11). The upshot is that a global variable is a class-level value and thus persists for the lifetime of the program. It has no memory management connected with instances, because it 330 | Chapter 12: Accessors and Memory Management itself is not connected with instances. Thus in some sense it leaks, but deliberately so, in the same innocuous sense that a class object leaks. On the other hand, you might have to use a tiny bit of explicit memory management in order to initialize a global variable in the first place. For example, suppose you’re not using ARC and you initialize a global variable in initialize to an autoreleased value. Clearly you’ll have to retain it, or it will just vanish out from under you. But you’ll never bother to release it; there’s no need, and no place where it would make sense to do so. Memory Management of Pointer-to-Void Context Info A number of Cocoa methods take an optional parameter typed as void*, and often called context:. You might think that void*, the universal pointer type, would be the same as id, the universal object type, because a reference to an object is a pointer. But an id is a universal object type; void* is just a C pointer. This means that Cocoa won’t treat this value as an object. So the use of the void* type is a clue to you that Cocoa won’t do any memory management on this value. Thus, making sure that it persists long enough to be useful is up to you. The big change wrought by ARC in this regard has to do, not with memory management, but with “crossing the bridge” between an id and a void*. Before ARC, these two types were treated as equivalent, in the sense that you could supply one where the other was expected. But ARC is not so sanguine. ARC manages memory for objects only. Thus, it manages memory for something typed as id, but not for something typed as void*. Therefore, if you want to use an object where a void* is expected, or a void* where an object is expected, you must reassure ARC that you know what you’re doing. When an object comes into existence by instantiation under ARC, it is memorymanaged by ARC from birth to death, as it were. But when an object is cast to a void*, it passes out of the realm of ARC memory management, and ARC will not let go without more information, because it doesn’t understand what its memory management re‐ sponsibilities should be at this moment. Similarly, when a non-object (a void*) is cast to an object type, it passes ready-made into the realm of ARC memory management, and ARC will not accept it without more information. When you pass value in as a context: argument, your purpose is to get it back out again later; it’s an identifier, or a carrier of extra information or data. For example, when you pass a context: value as you send addObserver:forKeyPath:options:context: to some object (see on key–value observing in Chapter 13), this is so that you can obtain that same value when Cocoa later sends observeValueForKeyPath:ofObject: change:context: back to you. Cocoa isn’t going to retain the value for you, but on the other hand the value needs to exist only as long as you are likely to be called back in this way. Memory Management | 331 Thus it will make the most sense if you simply keep a reference to that value and manage its memory through that reference. The context: value itself is just a pointer. As a result, as the context: argument passes out of ARC’s purview, and later as it passes back in again, ARC has no memory management responsibilities: you just want ARC to permit the cast. The way to indicate this is to cast the value explicitly, with a __bridge qualifier. For example, let’s say that you write this: [someObject addObserver:self forKeyPath:@"yoho" options:0 context:myContext]; Before ARC, that code was legal. Under ARC, it isn’t; the compiler will stop you in your tracks with this complaint: “Implicit conversion of Objective-C pointer type ‘id’ to C pointer type ‘void *’ requires a bridged cast.” So you supply the bridged cast: [someObject addObserver:self forKeyPath:@"yoho" options:0 context:(__bridge void*) myContext]; Later, when the context comes back to you in a callback, you’ll cast it back to a __bridge id so that ARC will accept it and you can continue treating it as an object. This leaves only the question of how to manage the memory of the object that’s being handed back and forth as the context: argument. All this is happening in different methods, and the object must persist through all of them. Clearly the most sensible solution is to maintain the object through an instance variable. Under ARC, in partic‐ ular, this is a lightweight approach; the object will be memory-managed with no par‐ ticular effort on your part. It may persist even after it is no longer needed, but it won’t actually leak. The situation is only slightly more complicated if you’ve more than one context object to manage simultaneously; for example, you could store them all in a collection, such as an NSMutableSet instance variable. Considerations of this sort do not apply to parameters that are typed as objects. For instance, when you call postNotificationName:object:userInfo:, the userInfo is typed as an NSDictionary and is retained for you by the notification center (and released after the notification is posted); its memory management behind the scenes is not your concern. Memory Management of CFTypeRefs A CFTypeRef (see Chapter 3) is a value obtained through a C function that is a pointer to a struct; its type name will usually end in “Ref ”. It is a kind of object, even though it isn’t a full-fledged Cocoa Objective-C object, and it must be managed in much the same way as a Cocoa object. ARC is irrelevant to this fact. ARC manages Objective-C objects; it has no concern with CFTypeRefs. You must manage the memory of CFTypeRefs manually, even if you’re using ARC. Indeed, as I shall explain, the fact that you are using ARC actually increases the degree of your memory management responsibility. 332 | Chapter 12: Accessors and Memory Management I will divide the discussion into two halves: memory management of CFTypeRefs on their own, and what happens when you “cross the bridge” between a CFTypeRef and a full-fledged Objective-C object type. Just as, in the Objective-C world of objects, certain method names (alloc, copy, and retain) alert you to your memory management responsibilities, so too in the world of CFTypeRefs. The golden rule here is that if you obtained such an object through a function whose name contains the word Create or Copy, you are responsible for re‐ leasing it. In the case of a Core Foundation object (its type name begins with CF), you’ll release it with the CFRelease function; other object creation functions are paired with their own object release functions. An Objective-C object can be sent messages even if it is nil. But CFRelease cannot take a nil argument. Be sure that a CFTypeRef vari‐ able is not nil before releasing it. The matter is not a complicated one; it’s much simpler than memory management of Cocoa objects, and the documentation will usually give you a hint about your memory management responsibilities. As an example, here (without further explanation) is some actual code from one of my apps, strongly modeled on Apple’s own example code, in which I set up a base pattern color space (for drawing with a pattern): - (void) addPattern: (CGContextRef) context color: (CGColorRef) incolor { CGColorSpaceRef baseSpace = CGColorSpaceCreateDeviceRGB(); CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(baseSpace); CGContextSetFillColorSpace(context, patternSpace); CGColorSpaceRelease(patternSpace); CGColorSpaceRelease(baseSpace); // ... } Never mind exactly what that code does; the important thing here is that the values for baseSpace and patternSpace are a CFTypeRef (in particular, a CGColorSpaceRef) ob‐ tained through functions with Create in their name, so after we’re done using them, we release them with the corresponding release function (here, CGColorSpaceRelease). Similarly, you can retain a Core Foundation object, if you are afraid that it might go out of existence while you still need it, with the CFRetain function, and you are then, once again, responsible for releasing it with the CFRelease function. We now come to the business of “crossing the bridge.” As I explained in Chapter 3, many Core Foundation object types are toll-free bridged with a corresponding Cocoa object type. Now, from a theoretical point of view, memory management is memory manage‐ ment: it makes no difference whether you use Core Foundation memory management or Cocoa memory management. Thus, if you obtain a CFStringRef through a Create Memory Management | 333 or Copy function and assign it to an NSString variable, sending release to it through the NSString variable is just as good as calling CFRelease on it as a CFStringRef. And before ARC, that was the end of the matter. Under ARC, however, we face the same problem I described in the preceding section. ARC manages memory for Objective-C objects; it knows nothing of CFTypeRefs. Therefore, ARC is not going to let you hand an object into or out of its memorymanagement purview without explicit information about how to manage its memory. This means a little extra thought for you, but it’s a good thing, because it means you can tell ARC to do automatically what you would have done manually. For example, a moment ago I said that, before ARC, you might obtain a CFStringRef through a Create or Copy function, cast it to an NSString, and later send release to it through the NSString. Under ARC, you can’t say release, but you can arrange for ARC to do exactly the same thing: as you “cross the bridge”, you pass the CFString through the CFBridgingRelease function. The result is an id that can be assigned to an NSString variable, and that ARC will release to balance out the incremented retain count gener‐ ated by the original Create or Copy function. You have three choices as you cross the toll-free bridge: __bridge cast As illustrated in the previous section, you cast explicitly to the across-the-bridge type and qualify the cast with __bridge. This means that memory management responsibilities are independent on either side of the bridge. You’re telling ARC that you’re going to be performing complete and correct memory management on the CFTypeRef side of the bridge. CFBridgingRelease function You’re crossing the bridge from the CFTypeRef side to the object side. You’re telling ARC that memory management for this object is incomplete: it has a raised retain count on the CFTypeRef side (probably because you generated it with a Create or Copy function, or called CFRetain on it), and it will be up to ARC to perform the corresponding release on the object side. (Alternatively, you can do a __bridge_transfer cast.) Here’s an artificial but correct example: CFArrayRef arr_ref = CFLocaleCopyISOCountryCodes(); // note "copy" NSArray* arr = CFBridgingRelease(arr_ref); // memory management complete // ARC will manage this array correctly from here on CFBridgingRetain function You’re crossing the bridge from the object side to the CFTypeRef side. You’re telling ARC that it should leave memory management for this object incomplete: you’re aware of the raised retain count on the object side, and you intend to call CFRelease on it yourself on the CFTypeRef side. (Alternatively, you can do a __bridge_retained cast.) 334 | Chapter 12: Accessors and Memory Management You may see __bridge_transfer and __bridge_retained in code written by other people, but I strongly recommend that you stick to CFBridgingRelease and CFBridgingRetain in your own code, as they are eminently clearer (and better named). Note that it is perfectly possible to pass an object out of the object world with CFBridgingRetain and back into it later with CFBridgingRelease. Properties A property (see Chapter 5) is syntactic sugar for calling an accessor by using dotnotation. For instance, in an example earlier in this chapter we had an object with an NSMutableArray instance variable and a setter, which we called like this: [self setTheData: d]; We could equally have said this: self.theData = d; The effect would be exactly the same, because setting a property is just a shorthand for calling the setter method. Similarly, suppose we were to say this: NSMutableArray* arr = self.theData; That is exactly the same as calling the getter method, [self theData]. In those examples, we are presuming the existence of the getter and setter methods. The declaration of an accessor method is what permits us to use the corresponding notation: the declaration of the setter lets us use property notation in an lvalue (to assign to the property), and the declaration of the getter lets us use property notation otherwise (to fetch the property’s value). It is also possible to declare a property explicitly, instead of declaring the getter and setter methods. Declaring a property is thus a shorthand for declaring accessors, just as using a property is shorthand for calling an accessor. But declaring a property can do much more for you and your code than that. How much more it can do has increased historically, depending on what system and what version of Xcode you’re using; here’s a list of the powers of property declaration, roughly in order of increasing power, which is also roughly the order in which those powers were introduced historically: • A property declaration saves you from having to declare accessor methods. It is simpler to declare one property than to declare two accessor methods. • A property declaration includes a statement of the setter’s memory management policy. This lets you, the programmer, know easily, just by glancing at a property declaration, how the incoming value will be treated. You could find this out other‐ wise only by looking at the setter’s code — which, if this is a built-in Cocoa type, you cannot do (and even in the case of your own code, it’s a pain having to locate and consult the setter directly). Properties | 335 • With a property declaration, you can optionally omit writing one or both acces‐ sors. The compiler will write them for you! To get the compiler to do this, you include a @synthesize directive in your class’s implementation section. Such an automat‐ ically constructed accessor is called, naturally enough, a synthesized accessor. Writing accessors is boring and error-prone. It can also be hard! In a multithreading situation, it is doubtful that you would even know how to write a thread-safe ac‐ cessor; a synthesized accessor is thread-safe by default. Any time correct code is written for you automatically, it’s a major benefit. Moreover, your class is now key– value coding compliant for the accessor name, with no effort on your part. Furthermore, your setter memory management policy, as specified in the property declaration, is followed by the synthesized setter. Your wish is Cocoa’s command! • With a synthesized accessor, you don’t have to declare the corresponding instance variable that the accessor gets or sets. It is implicitly declared for you! Automatic implicit declaration of instance variables was introduced as part of a major advance in Objective-C: the documentation refers to the earlier period (when you still had to declare instance variables yourself, even with a declared property and a synthe‐ sized accessor) as “the legacy runtimes”, and the later period (automatic implicit declaration of instance variables) as “the modern runtimes”. As part of the @synthesize directive, you can specify the name of the instance variable that is to be implicitly declared for you. • The ultimate convenience is the most recent (starting in LLVM compiler version 4.0, Xcode 4.4): you can omit the @synthesize directive! The compiler automati‐ cally inserts it for you, implicitly. This is called autosynthesis. The only downside to taking advantage of autosynthesis is that, because the @synthesize directive is omitted, you have no place to specify the name of the automatically declared instance variable. That isn’t much of a disadvantage; the name is supplied according to a simple rule, and the vast majority of the time you’ll be perfectly happy with it. Thanks to autosynthesis, the mere presence of the property declaration — one line of code — is sufficient to trigger the entire stack of automatic behaviors: it equates to declaration of the accessors, and the accessors are written for you (in accordance with your declared memory management policy), and the instance variable is implicitly de‐ clared for you. Property Memory Management Policies The possible memory management policies correspond simply to what has already been said in this chapter about the ARC reference types and how a setter might behave: 336 | Chapter 12: Accessors and Memory Management strong, retain Under ARC, the instance variable itself will be a normal (strong) reference, so when ARC assigns the incoming value to it, it will retain the incoming value and release the existing value of the instance variable. Under non-ARC, the setter method will retain the incoming value and release the existing value of the instance variable. The terms are pure synonyms of one another and can be used in ARC or non-ARC code; retain is the term inherited, as it were, from pre-ARC days. copy The same as strong or retain, except that the incoming value is copied (by sending copy to it) and the copy, which has an increased retain count already, is assigned to the instance variable. This is appropriate particularly when a nonmutable class has a mutable subclass (such as NSString and NSMutableString, or NSArray and NSMutableArray), to prevent the setter’s caller from passing in an object of the mutable subclass; it is legal for the setter’s caller to do so, because (in accordance with polymorphism, Chapter 5) where an instance of a class is expected, an instance of its subclass can be passed, but the copy call creates an instance of the nonmutable class (Chapter 10). weak Under ARC, the instance variable will be a weak reference. ARC will assign the incoming value to it without retaining it. ARC will also magically nilify the instance variable if the instance to which it points goes out of existence. This is useful, as already explained earlier in this chapter, for breaking a potential retain cycle and for declining to retain inappropriately, and to reduce overhead where it is known that no memory management is needed, as with an interface object that is already retained by its superview. The setter method can be synthesized only under ARC; using weak in non-ARC code is not strictly impossible but probably makes no sense. assign (the default) This policy is inherited from pre-ARC days; it is used in the same ways as weak. The setter does not manage memory; the incoming value is assigned directly to the instance variable. The instance variable is not an ARC weak reference and will not be nilified automatically if the instance to which it points goes out of existence; it is a non-ARC weak reference (__unsafe_unretained) and can become a dangling pointer. As I’ve already said, a property’s declared memory management policy is an instruction to the compiler if the setter is synthesized. If the setter is not synthesized, the declared memory management policy is “purely conventional” (as the LLVM documentation puts it), meaning that if you write your own setter, you’d better make that setter behave the way you declared you would, but nothing is going to force you to do so. Properties | 337 Property Declaration Syntax We come now to the formal syntax for declaring a property. A property is declared in the same part of a class’s interface section where you would declare methods. Its syntax schema is as follows: @property (attribute, attribute, ...) type name; Here’s a real example, for the NSMutableArray instance variable we were talking about a moment ago: @property (nonatomic, strong) NSMutableArray* theData; The type and name will usually match the type and name of an instance variable, but what you’re really indicating here are the name of the property (as used in dot-notation) and the default names of the setter (here, setTheData:) and getter (here, theData), and the type of value to be passed to the setter and obtained from the getter. If this property will be represented by an outlet in a nib, you can say IBOutlet before the type. This is a hint to Xcode and has no formal meaning. The type doesn’t have to be an object type; it can be a simple type such as BOOL, CGFloat, or CGSize. Of course in that case no memory management is performed (as none is needed), and no memory management policy should be declared; but the ad‐ vantages of using a property remain — the accessors can be synthesized and the instance variable declared automatically. The possible attribute values are: A memory management policy I listed the names of these a few paragraphs ago. You will supply exactly one; under ARC this will usually be strong. The default if you omit any memory management policy is assign, but such omission is dangerous and you’ll get a warning from the compiler. nonatomic If omitted, the synthesized accessors will use locking to ensure correct operation if your app is multithreaded. This will rarely be a concern, and locking slows down the operation of the accessors, so you’ll probably specify nonatomic most of the time. It’s a pity that nonatomic isn’t the default, but such is life. readwrite or readonly If omitted, the default is readwrite. If you say readonly, any attempt to use the property as a setter will cause a compile error (a useful feature), and if the accessors are to be synthesized, no setter is synthesized. 338 | Chapter 12: Accessors and Memory Management getter=gname, setter=sname: By default, the property name is used to derive the names of the getter and setter methods that will be called when the property is used. If the property is named myProp, the default getter method name is myProp and the default setter name is setMyProp:. You can use either or both of these attributes to change that. If you say getter=getALife, you’re saying that the getter method corresponding to this prop‐ erty is called getALife (and if the accessors are synthesized, the getter will be given this name). Users of the property won’t be affected, but calling an accessor method explicitly under a nonexistent name is a compile error. To make a property declaration private, put it in a class extension (Chapter 10). Most commonly, the class extension will be at the top of the implementation (.m) file, before the implementation section. As a result, this class can use the property or call the ac‐ cessors but other classes cannot (Example 12-10). Example 12-10. A private property // MyClass.m: @interface MyClass () @property (nonatomic, strong) NSMutableArray* theData; // private @end @implementation MyClass // other code goes here @end Being able to declare private properties is so useful that I find myself routinely adding a class extension to the top of any new class files (if the Xcode project template hasn’t done it for me), to make it easy to add private properties later if I need to. Note that knowledge of private properties is not inherited by subclasses; an elegant solution is to move the class extension interface section off into an isolated .h file of its own and import that into the implementation files of both the superclass and the subclass. Another reason to put a property declaration in a class extension is so as to redeclare the property. For example, we might want our property to be readonly as far as the rest of the world knows, but readwrite for code within our class. To implement this, declare the property readonly in the interface section in the header file, which the rest of the world sees, and then redeclare it, not as readonly (in which case it will be readwrite by default), in the class extension in the implementation file, which only this class sees. All other attributes must match between both declarations. A property declaration can also appear in a protocol or category declaration. This makes sense because, with a property declaration, you’re really just declaring accessor methods, and these are places where method declarations can go. Properties | 339 Property Accessor Synthesis To request explicitly that the accessors be synthesized for you, use the @synthesize directive. It appears anywhere inside the class’s implementation section, any number of times, and takes a comma-separated list of property names. The behavior and names of the synthesized accessors will accord with the property declaration attributes I’ve just talked about. You can state that the synthesized accessors should access an instance variable whose name differs from the property name by using the syntax propertyName=ivarName in the property name list; otherwise, the instance variable will have the same name as the property. As I mentioned earlier, you don’t have to declare the instance variable; it will be declared for you automatically as part of accessor synthesis. An instance variable declared automatically through accessor synthesis is strictly private, meaning that it is not inherited by subclasses. This fact will rarely prove troublesome, but if it does, simply declare the instance variable explicitly. Thus, having declared a property theData, to request explicitly that accessors be syn‐ thesized, you’d say this in the implementation section: @synthesize theData; The result is that any accessors you don’t write (theData and setTheData:, unless you changed these names in the property declaration) will be written for you behind the scenes, and if you didn’t declare an instance variable theData, it will be declared for you. The name of the automatically declared instance variable is likely to be important to you, because you’re probably going to need to access the instance variable directly, es‐ pecially in an initializer (and in dealloc if you’re not using ARC), as well as in any accessors that you write yourself. Starting in the Xcode 4.2 application templates, Apple began following a convention where a synthesized accessor would take advantage of the propertyName=ivarName syntax to give the instance variable a name different from that of the property in that the former was prefixed with an underscore. For example, the AppDelegate class’s im‐ plementation section contained this line: @synthesize window = _window; The evident value of following this naming convention is that we can refer in our code to the property explicitly as self.window, but if we were accidentally to refer to the instance variable directly as window, we’d get a compilation error, because there is no instance variable window (it’s called _window). The convention thus prevents accidental direct access to the instance variable without passing through the accessors, as well as just distinguishing clearly in code which names are instance variables — they’re the ones 340 | Chapter 12: Accessors and Memory Management prefixed with an underscore. Moreover, this policy frees up the property name (here, window) to be used as a local variable in a method, without getting a warning from the compiler that we’re overshadowing the name of an instance variable. Autosynthesis follows the same naming policy. If you omit the @synthesize directive, the automatically generated name of the automatically declared instance variable is the name of the property prefixed with an underscore. For example, a declared property called theData will result in an instance variable called _theData. If for some reason that isn’t what you want, then use the @synthesize directive explicitly. Remember, if you do so, that if you don’t specify the instance variable name explicitly, the default instance variable name will be the same as the property name, without any underscore. Regardless of whether you explicitly include a @synthesize directive or you take ad‐ vantage of autosynthesis, you are permitted to write one or both accessors yourself. Synthesis means that any accessors you don’t provide will be provided for you. If you use autosynthesis (no @synthesize directive) and you provide both accessors, you won’t get any automatically declared instance variable. This is a very sensible policy: you’ve surrendered your chance to dictate the instance variable’s name in the @synthesize directive, but you’re also taking complete manual control of your accessors, so you’re given complete manual control of your instance variable as well. A useful trick is to take advantage of the @synthesize syntax propertyName=ivarName to override the synthesized accessor without losing any of its functionality. What I mean is this. Suppose you want the setter for _myIvar to do more than just set _myIvar. One possibility is to write your own setter; however, writing a setter from scratch is tedious and error-prone, whereas a synthesized setter does the job correctly and writ‐ ing it is no work at all. The solution is to declare a property myIvar along with a corre‐ sponding private property (Example 12-10) — let’s call it myIvarAlias — and synthesize the private property myIvarAlias to access the _myIvar instance variable. You must then write the accessors for myIvar by hand, but all they need to do, at a minimum, is use the myIvarAlias properties to set and get the value of _myIvar respectively. The key point is that you can also do other stuff in those accessors (Example 12-11); whoever gets or sets the property myIvar will be doing that other stuff. Example 12-11. Overriding synthesized accessors // In the header file: @interface MyClass : NSObject @property (nonatomic, strong) NSNumber* myIvar; @end // In the implementation file: @interface MyClass () @property (nonatomic, strong) NSNumber* myIvarAlias; @end Properties | 341 @implementation MyClass @synthesize myIvarAlias=_myIvar; - (void) setMyIvar: (NSNumber*) num { // do other stuff here self.myIvarAlias = num; } - (NSNumber*) myIvar { // do other stuff here return self.myIvarAlias; } @end Dynamic Accessors Instead of writing your own accessors or providing a @synthesize directive or using autosynthesis, you can accompany a property declaration with a @dynamic directive (in the implementation section). This tells the compiler that even though it doesn’t see any implementation of any accessors for this property, and even though it isn’t going to provide the accessors for you, it should permit the property declaration anyway, on the grounds that at runtime, when a call to one of the accessors arrives, your code will somehow magically handle it in some way that the compiler can’t grasp. Basically, you’re suppressing the compiler’s warning system; it just gives up and stands aside, and leaves you to hang yourself at runtime. This is a rare but not unheard-of thing to do. It arises chiefly in two contexts: when defining your own animatable view property (Chapter 17), and when using managed object properties in Core Data (Chapter 36). In both of those situations, you harness the power of Cocoa to perform the magic handling of the accessor calls; you don’t know precisely how Cocoa performs this magic, and you don’t care. But what if you wanted to perform this magic yourself? To put it another way, what sort of magic might Cocoa be using in those two limited situations? The answer lies in the power of Objective-C’s dynamic messaging. This is an advanced topic, but it’s so cool that I’ll show you an example anyway. I propose to write a class that declares properties name (an NSString) and number (an NSNumber) but that has no accessor methods for name or number and that doesn’t use accessor synthesis. Instead, in our interface section we declare these properties dynamic. Since we’re not getting any help from synthesis, we must also declare the instance vari‐ ables ourselves: // the interface section declares properties "name" and "number" @implementation MyClass { NSString* _name; NSNumber* _number; 342 | Chapter 12: Accessors and Memory Management } @dynamic name, number; // ...insert magic here... @end I can think of a couple of ways to concoct the necessary magic; in this example, I’m going to take advantage of a little-known NSObject class method called resolveInstanceMethod:. Recall that sending a message to an object is not the same as calling that method in that object; there are some additional steps, if that method is not found in that object, to resolve the method. One of the first of these steps, the first time a given message arrives and is found to have no corresponding method in the object’s class, is that the runtime looks for an implementation of resolveInstanceMethod in that class. If it finds it, it calls it, handing it the selector for the message that is giving us difficulty. resolveInstanceMethod: then returns a BOOL; a YES answer means, “Don’t worry, I’ve got it covered; go ahead and call that method.” How can resolveInstanceMethod: possibly say this? What could it do, if the method doesn’t exist, to make it possible to call that method? Well, it could create that method. Objective-C is so dynamic that there’s a way to do this. And remember, resolveInstanceMethod: is called just once per method, so once it has created a method and returned YES, the problem is solved forever after for that method. To create a method in real time, we call the class_addMethod function. (This will require importing <objc/runtime.h>.) It takes four parameters: • The class to which the method is to be added. • The selector for the method that is being added (basically, this is the name of the method). • The IMP for the method. What’s an IMP? It’s the function that backs this method. Behind every Objective-C method lies a C function. This function takes the same parameters as the Objective-C method, with the addition of two extra parameters, which come at the start: the object that acts as self within this function, and the selector for the method that this function is backing. • A C string describing, in a special code, the type of the function’s returned value (which is also the type of the method’s returned value) and the argument types of the function. When I say “type” I mean little more than C type; every object type is considered the same. In our example we have four methods to cover (the two accessors for the two dynamic properties) — name, setName:, number, and setNumber:. So in order to call class_addMethod in resolveInstanceMethod:, we will also have to have written C functions to act as the IMP for each of those methods. Now, we could just write four C functions — but that would be pointless! If we were going to do that, why are we going to all the Properties | 343 trouble of using a dynamic accessor? Instead, I propose to write just two C functions, one to handle any getter that we may care to direct at it, and one to handle any setter that we may care to direct at it. Let’s take the getter first, as it is much the simpler case. What must a generalized getter do? It must access the corresponding instance variable. And what’s the name of the corresponding instance variable? Well, the way we’ve set things up, it’s the name of the method with an underscore prefixed to it. So, we grab the name of the method (which we can do because it has arrived as the selector, the second parameter to this function), stick an underscore on the front, and return the value of the instance variable whose name we’ve just derived. To make life simple, I’ll obtain the value of that instance variable using key–value coding; the presence of the underscore means that this won’t result in any circularity (that is, our function won’t end up calling itself in an infinite recursion): id callValueForKey(id self, SEL _cmd) { NSString* key = NSStringFromSelector(_cmd); key = [@"_" stringByAppendingString:key]; return [self valueForKey:key]; } Now that we’ve done that, we can see how to write the setter. It’s just a matter of doing a slightly more elaborate manipulation of the selector’s name in order to get the name of the instance variable. We must pull the set off the front and the colon off the end, and make sure the first letter is lowercase — and then we prefix the underscore, just as before: void callSetValueForKey(id self, SEL _cmd, id value) { NSString* key = NSStringFromSelector(_cmd); key = [key substringWithRange:NSMakeRange(3, [key length]-4)]; NSString* firstCharLower = [[key substringWithRange:NSMakeRange(0,1)] lowercaseString]; key = [key stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:firstCharLower]; key = [@"_" stringByAppendingString:key]; [self setValue:value forKey:key]; } Finally, we’re ready to write resolveInstanceMethod:. In my implementation, I’ve used this method as a gatekeeper, explicitly checking that the method to be called is an ac‐ cessor for one of our dynamic properties: + (BOOL) resolveInstanceMethod: (SEL) // this method will be called if (sel == @selector(setName:) || class_addMethod([self class], return YES; } if (sel == @selector(name) || sel class_addMethod([self class], 344 | Chapter 12: Accessors and Memory Management sel { sel == @selector(setNumber:)) { sel, (IMP) callSetValueForKey, "v@:@"); == @selector(number)) { sel, (IMP) callValueForKey, "@@:"); } return YES; } return [super resolveInstanceMethod:sel]; You’ll just have to trust me on the encoded C string in the fourth argument to class_addMethod; if you don’t, read the documentation to see what it means. My overall imple‐ mentation here is simple-minded — in particular, my use of key–value coding is sort of an easy way out, and I’ve failed to grapple with the need for copy semantics in the NSString setter — but it’s quite general, and gives you a peek under the Objective-C hood. Properties | 345 CHAPTER 13 Data Communication As soon as an app grows to more than a few objects, puzzling questions can arise about how to send a message or communicate data between one object and another. The problem is essentially one of architecture. Constructing your code so that all the pieces fit together and key information can be shared is something of an art. But it isn’t difficult. This chapter presents some general considerations that may provide the needed clue. Model–View–Controller In Apple’s documentation and elsewhere, you’ll find references to the term model–view– controller, or MVC. This refers to an architectural goal of maintaining a distinction between three functional aspects of a program that displays information to the user and permits the user to alter that information. The notion goes back to the days of Smalltalk, and much has been written about it since then, but informally, here’s what the terms mean: Model The data and its management, often referred to as the program’s “business logic,” the hard-core stuff that the program is really all about. View What the user sees and interacts with. Controller The mediation between the model and the view. Consider, for example, a game where the current score is displayed to the user: • A UILabel that shows the user the current score for the game in progress is view; it is effectively nothing but a pixel-maker, and its business is to know how to draw itself. The knowledge of what it should draw — the score, and the fact that this is a 347 Figure 13-1. Model–view–controller score — lies elsewhere. A rookie programmer might try to use the score displayed by the UILabel as the actual score: to increment the score, read the UILabel’s string, turn that string into a number, increment the number, turn the number back into a string, and present that string in place of the previous string. That is a gross violation of the MVC philosophy. The view presented to the user should reflect the score; it should not store the score. • The score is data being maintained internally; it is model. It could be as simple as an instance variable along with a public increment method or as complicated as a Score object with a raft of methods. The score is numeric, whereas a UILabel dis‐ plays a string; this alone is enough to show that the view and the model are naturally different. • Telling the score when to change, and seeing that this fact is reflected in the user interface, is the work of the controller. This will be particularly clear if we imagine that the model’s numeric score needs to be transformed in some way for presenta‐ tion to the user. For example, suppose the UILabel that presents the score reads: “Your current score is 20”. The model is presumably storing and providing the number 20, so what’s the source of the phrase “Your current score is…”? Whoever is deciding that this phrase should precede the score in the presentation of the score to the user, and is making it so, is a controller. Even this simplistic example (Figure 13-1) illustrates very well the advantages of MVC. By separating powers in this way, we allow the aspects of the program to evolve with a great degree of independence. Do you want a different font and size in the presentation of the score? Change the view; the model and controller need know nothing about it, but will just go on working exactly as they did before. Do you want to change the phrase that precedes the score? Change the controller; the model and view are unchanged. 348 | Chapter 13: Data Communication Adherence to MVC is particularly appropriate in a Cocoa app, because Cocoa itself adheres to it. The very names of Cocoa classes reveal the MVC philosophy that underlies them. A UIView is a view. A UIViewController is a controller; its purpose is to embody the logic that tells the view what to display. In Chapter 11 we saw that a UIPickerView does not hold the data it displays; it gets that data from a data source. So the UIPicker‐ View is a view; the data source is model. A further distinction, found in Apple’s documentation, is this: true model material and true view material should be quite reusable, in the sense that they can be transferred wholesale into some other app; controller material is generally not reusable, because it is concerned with how this app mediates between the model and the view. In one of my own apps, for example, we download an XML (RSS) news feed and present the article titles to the user as a table. The storage and parsing of the XML are pure model material, and are so reusable that I didn’t even write this part of the code (I used some code called FeedParser, by Kevin Ballard). The table is a UITableView, which is obviously reusable, seeing as I obtained it directly from Cocoa. But when the UITableView turns to me and asks what I’d like to display in this cell, and I turn to the XML and ask for the title of the article corresponding to this row of the table, that’s controller logic. By keeping the MVC architectural philosophy in mind as you develop your app, you’ll implicitly solve one data communication problem. The data will live in the model, the view will be purely presentational in nature, and the communication between them will be handled by your own deliberately written controller code. You’ll be communicating between the view and the model because controller code is about communicating be‐ tween the view and model. Instance Visibility The problem of communication often comes down to one object being able to see an‐ other: object Manny needs to be able to find object Jack repeatedly and reliably over the long term so as to be able to send Jack messages. (This is the same problem I spoke of in Chapter 2 as getting a reference to an object.) An obvious solution is an instance variable of Manny whose value is Jack. This is ap‐ propriate particularly when Manny and Jack share certain responsibilities or supple‐ ment one another’s functionality, and when they will both persist, especially when they will both persist together. The application object and its delegate, a table view and its data source, a view controller and the view that it controls — these are cases where the former must have an instance variable pointing at the latter. With instance variables comes the question of memory management policy (Chap‐ ter 12). Should Manny, which has an instance variable pointing to Jack, also retain Jack? Basically, it depends on how closely allied the objects are. An object does not typically retain its delegate or its data source; it can exist without a delegate or a data source, and Instance Visibility | 349 the delegate and data source have lives of their own — it is none of this object’s business to say whether its delegate or data source should be allowed to go out of existence. This object is therefore always prepared for the possibility that its delegate or data source may be nil. Similarly, an object that implements the target–action pattern, such as a UIControl, does not retain its target. On the other hand, a view controller is useless without a view to control; its very job is to be coterminous with its view, and to release its view when it itself goes out of existence. Similarly, an object that owns a nib as the nib loads rules the lifetimes of that nib’s top-level objects. Even when two objects go together closely, it will not necessarily be the case that each holds an instance variable pointing at the other. When each does point to the other, you must of course be careful not to let each retain the other; that’s a retain cycle, and will cause both objects to leak. But if one object is the instigator of communication between the two, it can simply pass along a reference to itself as a method argument, if it thinks the second object might need this in order to send back a message later on. This behavior is conventional in a delegate message, for example. The parameter of the delegate message textFieldShouldBeginEditing: is a reference to the UITextField that sent the message. The same policy is followed by target–action messages in their fuller forms; the first parameter is a reference to the sender. You can follow a similar policy. Visibility by Instantiation The real question is how one object is to be introduced to the other in the first place. Much of the art of Cocoa programming (and of object-oriented programming generally) lies in getting a reference to a desired object. Every case is different and must be solved separately, but a major clue comes from the fact that every instance comes from some‐ where. This means that some object commanded this instance to come into existence in the first place. That object therefore has a reference to the instance at that moment. That fact is always the starting point for establishment of future communication. When Manny instantiates Jack, Manny has a reference to Jack, and can keep that ref‐ erence if it will be needed later. Moreover, if Manny knows that Jack is going to need a reference to itself (Manny) or to some piece of data, Manny can hand Jack that reference early in Jack’s lifetime. Indeed, you might write Jack with an initializer that will take this reference as a parameter, so that Jack will possess it from the moment it comes into existence. (Compare the approach taken, for example, by UIActionSheet and UIAlert‐ View, where the delegate is one of the initializer’s parameters, or by UIBarButtonItem, where the target is one of the initializer’s parameters.) This example, from one of my apps, is from a table view controller. The user has tapped a row of the table. We create a secondary table view controller, a TrackViewController instance, handing it the data it will need, and display the secondary table view. I delib‐ erately devised TrackViewController to have a designated initializer initWithMedia- 350 | Chapter 13: Data Communication ItemCollection: to make it virtually obligatory for a TrackViewController to have access to the data it needs: - (void)showItemsForRow: (NSIndexPath*) indexPath { // create subtable of tracks and go there TrackViewController *t = [[TrackViewController alloc] initWithMediaItemCollection: (self.albums)[indexPath.row]]; [self.navigationController pushViewController:t animated:YES]; } The loading of a nib is also a case of visibility by instantiation. As I explained at length in Chapter 7, you will want to prepare your nib objects, including some proxy object such as the File’s Owner, with outlets corresponding to instance variables or accessors in that object’s class; as the nib loads, the object pointed to by each outlet will be handed to the corresponding instance variable as its value, or the setter as its argument, so that each instance that will need a reference to an object instantiated from the nib will in fact now have it and will be able to communicate as needed with the nib-instantiated object (Figure 7-5). But what if two objects are conceptually distant from each other? A common case in point is when objects are going to be instantiated from different nibs. How can an in‐ stance from one nib get a reference to an instance from another nib? True, you can’t draw a connection between an object in nib A and an object in nib B (see “Connections Between Nibs” (page 165)). But someone (Manny) is going to be the file’s owner when nib A loads, and someone (Jack) is going to be the file’s owner when nib B loads. Those two file’s owners might be able to see each other; if so, the problem is solved. Perhaps they are the same object. Perhaps Manny instantiated Jack in the first place. Perhaps they are both instantiated by some third object, which provides a communication path for them. Visibility by Relationship Objects may acquire the ability to see one another automatically by virtue of their po‐ sition in a containing structure. Before worrying about how to supply one object with a reference to another, consider whether there may already be a chain of references leading from one to another. For example, a subview can see its superview, through its superview property. A su‐ perview can see all its subviews, through its subviews property, and can pick out a specific subview through that subview’s tag property, by calling viewWithTag:. A sub‐ view in a window can see its window, through its window property. (There will be more about all that in Chapter 14.) A responder (Chapter 11) can see the next responder in the responder chain, through the nextResponder method — which also means, because of the structure of the responder chain, that a view can see the view controller that manages it. Instance Visibility | 351 Similarly, view controllers are part of a containment hierarchy (Chapter 19) and there‐ fore can see one another. If a view controller is currently presenting a view through a second view controller, the latter is the former’s presentedViewController, and the former is the latter’s presentingViewController. If a view controller is contained by a UINavigationController, the latter is its navigationController. A UINavigation‐ Controller’s visible view is controlled by its visibleViewController. And from any of these, you can reach the view controller’s view through its view property, and so forth. All of these relationships are public. So if you can get a reference to just one object within any of these structures or a similar structure, you can effectively navigate the whole structure through a chain of references and lay your hands on any other object within the structure. Global Visibility Some objects are globally visible (that is, visible to all other objects). In general, these are singletons vended by a class method. Some of these objects have properties pointing to other objects, making those other objects likewise globally visible. For example, any object can see the singleton UIApplication instance by calling [UIApplication sharedApplication]. So any object can also see the app’s primary window, because that is its keyWindow property, and any object can see the app delegate, because that is its delegate property. And the chain continues: any object can see the app’s root view controller, because that is the primary window’s rootViewController — and from there, as I said in the previous section, we can navigate the view controller hierarchy and the view hierarchy. You can take advantage of this to make objects globally visible by attaching them to a globally visible object. A public property of the app del‐ egate, which you are free to create, is globally visible by virtue of the app delegate being globally visible (by virtue of the shared application being globally visible). Another globally visible object is the shared defaults object obtained by calling [NSUserDefaults standardUserDefaults]. This object is the gateway to storage and retrieval of user defaults, which is similar to a dictionary (a collection of values named by keys). The user defaults are automatically saved when your application quits and are auto‐ matically available when your application is launched again later, so they are one of the ways in which your app maintains state between launches. But, being globally visible, they are also a conduit for communicating values within your app. For example, in one of my apps there’s a setting I call @"hazyStripy". This determines whether a certain visible interface object is drawn with a hazy fill or a stripy fill. This is a setting that the user can change, so there is a preferences interface allowing the user to make this change. When the user displays this preferences interface, I examine the @"hazyStripy" setting in the user defaults to configure the interface to reflect it; if the 352 | Chapter 13: Data Communication Figure 13-2. The global visibility of user defaults user interacts with the preferences interface to change the @"hazyStripy" setting, I respond by changing the actual @"hazyStripy" setting in the user defaults. But the preferences interface is not the only object that uses the @"hazyStripy" setting in the user defaults; the drawing code that actually draws the hazy-or-stripy-filled object also uses it, so as to know which way to draw itself. Thus there is no need for the object that draws the hazy-or-stripy-filled object and the object that manages the preferences interface to be able to see one another! They can both see this common object, the @"hazyStripy" user default (Figure 13-2). Indeed, it is not uncommon to “misuse” the user defaults storage to hold information that is not used to maintain state between runs of the app, but is placed there just because this is a location globally visible to all objects. Notifications Notifications (Chapter 11) can be a way to communicate between objects that are con‐ ceptually distant from one another without bothering to provide any way for one to see the other. All they really need to have in common is a knowledge of the name of the notification. Using a notification in this way may seem lazy, an evasion of your respon‐ sibility to architect your objects sensibly. But sometimes one object doesn’t need to know, and indeed shouldn’t know, what object (or objects) it is sending a message to. For example, in one of my apps, the app delegate may detect a need to tear down the interface and built it back up again from scratch. If this is to happen without causing memory leaks (and all sorts of other havoc), every view controller that is currently Notifications | 353 running a repeating NSTimer needs to invalidate that timer (Chapter 12). Rather than my having to work out what view controllers those might be, and endowing every view controller with a method that can be called, I simply have the app delegate shout “Ev‐ erybody stop timers!” — by posting a notification. My view controllers that run timers have all registered for this notification, and they know what to do when they receive it. Key–Value Observing Key–value observing, or KVO, is a mechanism somewhat similar to the target–action mechanism, except that it is not limited to controls. (The KVO mechanism is provided through an informal protocol, NSKeyValueObserving, which is actually a set of cate‐ gories on NSObject and other classes.) The similarity is that objects register with a particular object to be notified when something happens. The “something” is that a certain value in that object is changed. Mac OS X Programmer Alert Mac OS X bindings don’t exist on iOS, but you can sometimes use KVO to achieve similar aims. KVO can be broken down into three stages: Registration To hear about a change in a value belonging to object A, object B must be registered with object A. Change The change takes place in the value belonging to object A, and it must take place in a special way — a KVO compliant way. Notification Object B is automatically notified that the value in object A has changed and can respond as desired. Here’s a simple complete example — a rather silly example, but sufficient to demonstrate the KVO mechanism in action. We have a class MyClass1; this will be the class of object A. We also have a class MyClass2; this will be the class of object B. Finally, we have code that creates a MyClass1 instance called objectA and a MyClass2 instance called objectB; this code registers objectB to hear about changes in an instance variable of objectA called value, and then changes value, and sure enough, objectB is automat‐ ically notified of the change: 354 | Chapter 13: Data Communication // MyClass1.h: @interface MyClass1 : NSObject @property (nonatomic, copy) NSString* value; @end // MyClass2.m: - (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { NSLog(@"I heard about the change!"); } // Somewhere else entirely: MyClass1* objectA = [MyClass1 new]; MyClass2* objectB = [MyClass2 new]; // register for KVO [objectA addObserver:objectB forKeyPath:@"value" options:0 context:nil]; // change the value in a KVO compliant way objectA.value = @"Hello, world!"; // result: objectB's observeValueForKeyPath:... is called We call addObserver:forKeyPath:options:context: to register objectB to hear about changes in objectA’s value. We didn’t use the options: or context: parameters for anything; I’ll talk about the options: parameter in a moment. (The context: parameter is for handing in a value to be provided as part of the notification; see Chapter 12.) We change objectA’s value, and we do it in a KVO compliant way, namely, by passing through the setter (because setting a property is equivalent to passing through the setter). This is another reason why, as I said in Chapter 12, accessors (and properties) are a good thing: they help you guarantee KVO compliance when changing a value. When we change objectA’s value, the third stage takes place automatically: a call is made to objectB’s observeValueForKeyPath:.... We have implemented this method in MyClass2 in order to receive the notification. In this simple example, we expect to receive only one notification, so we just log to indicate that we did indeed receive it. In real life, where a single object might be registered to receive more than one KVO notification, you’d use the incoming parameters to distinguish between different notifications and decide what to do. At the very least, you’ll probably want to know, when observeValueForKeyPath:... is called, what the new value is. We can find that out easily, because we are handed a reference to the object that changed, along with the key path for the value within that object. Thus we can use KVC to query the changed object in the most general way: Key–Value Observing | 355 - (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { id newValue = [object valueForKeyPath:keyPath]; NSLog(@"The key path %@ changed to %@", keyPath, newValue); } It is also possible to request that the new value be included as part of the notification. This depends upon the options passed with the original registration. Here, we’ll request that both the old and new values be included with the notification: objectA.value = @"Hello"; [objectA addObserver:objectB forKeyPath:@"value" options: NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context: nil]; objectA.value = @"Goodbye"; // notification is triggered When we receive the notification, we fetch the old and new values out of the change dictionary: - (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { id newValue = change[NSKeyValueChangeNewKey]; id oldValue = change[NSKeyValueChangeOldKey]; NSLog(@"The key path %@ changed from %@ to %@", keyPath, oldValue, newValue); } No memory management happens as part of the registration process, so it is incumbent upon you to unregister object B before it is destroyed. Otherwise, object A may later attempt to send a notification to a dangling pointer (see Chapter 12). This is done by sending object A the removeObserver:forKeyPath: message; you must explicitly un‐ register the observer for every key path for which it is registered; you can’t use nil as the second argument to mean “all key paths”. The runtime will send you a nice warning in the log if an object being observed under KVO goes out of existence. But you get no warning if an observer object goes out of existence. It is crucial that the observer should be unregistered with the observed as the observer goes out of existence, to prevent the observed from trying to send it any notifica‐ tions later. In real life, where an object will typically register itself as an observer, it will usually unregister itself in its dealloc implementation (and this could be yet another reason to implement dealloc under ARC). 356 | Chapter 13: Data Communication Beginners are often confused about how to use KVO to observe changes to a mutable array, to be notified when an object is added to, removed from, or replaced within the array. You can’t add an observer to an array itself; you have to observe through an object that has a key path to the array (through accessors, for example). The simple-minded solution is then to access the array using mutableArrayValueForKey:, which provides an observable proxy object. For example, as in Chapter 12, let’s posit an object with a property theData which is an array of dictionaries: ( { }, { }, { } description = "The one with glasses."; name = Manny; description = "Looks a little like Governor Dewey."; name = Moe; description = "The one without a mustache."; name = Jack; ) Suppose this is an NSMutableArray. Then we can register with our object to observe the key path @"theData": [objectA addObserver:objectB forKeyPath:@"theData" options:0 context:nil]; Now object B will be notified of changes to this mutable array, but only if those changes are performed through the mutableArrayValueForKey: proxy object: [[objectA mutableArrayValueForKeyPath:@"theData"] removeObjectAtIndex:0]; // notification is triggered But it seems onerous to require clients to know that they must call mutableArrayValueForKey:. The simple solution is for our object A itself to provide a getter that calls mutableArrayValueForKey:. Here’s a possible implementation: // MyClass1.h: @interface MyClass1 : NSObject @property (nonatomic, strong, getter=theDataGetter) NSMutableArray* theData; @end // MyClass1.m: - (NSMutableArray*) theDataGetter { return [self mutableArrayValueForKey:@"theData"]; } Key–Value Observing | 357 The result is that, as far as any client knows, this object has a key @"theData" and a property theData, and we can register to observe with the key and then access the mutable array through the property: [objectA addObserver:objectB forKeyPath:@"theData" options: NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil]; [objectA.theData removeObjectAtIndex:0]; // notification is triggered If you’re going to take this approach, you should really also implement (in MyClass1) the four KVC compliance methods for a mutable array façade (see Chapter 12). Al‐ though things will appear to work just fine without them, and although they appear trivial (they are merely delegating to self->_theData the equivalent calls), they will be called by the vended proxy object, which increases its efficiency (and, some would argue, its safety). Without these methods, the proxy object resorts to setting the instance vari‐ able directly, replacing the entire mutable array, every time a client changes the mutable array: - (NSUInteger) countOfTheData { return [self->_theData count]; } - (id) objectInTheDataAtIndex: (NSUInteger) ix { return self->_theData[ix]; } - (void) insertObject: (id) val inTheDataAtIndex: (NSUInteger) ix { [self->_theData insertObject:val atIndex:ix]; } - (void) removeObjectFromTheDataAtIndex: (NSUInteger) ix { [self->_theData removeObjectAtIndex: ix]; } If what you want to observe are mutations within an individual element of an array, things are more complicated. Suppose our array of dictionaries is an array of mutable dictionaries. To observe changes to the value of the @"description" key of any dictio‐ nary in the array, you’d need to register for that key with each dictionary in the array, separately. You can do that efficiently with NSArray’s instance method addObserver:toObjectsAtIndexes:forKeyPath:options:context:, but if the array itself is mutable then you’re also going to have to register for that key with any new dictionaries that are subsequently added to the array (and unregister when a dictionary is removed from the array). This is doable but daunting, and I’m not going to go into the details here. Key–value observing is a deep mechanism; consult Apple’s Key-Value Observing Guide for full information. It does have some unfortunate shortcomings — for one thing, it’s a pity that all notifications arrive by calling the same bottleneck method, observe- 358 | Chapter 13: Data Communication ValueForKeyPath:... — but in general, KVO is useful for keeping values coordinated in different objects. The properties of Apple’s built-in classes are typically KVO compliant. Indeed, so are many classes that don’t use properties per se; for example, NSUserDefaults is KVO compliant. Unfortunately, Apple warns that undocumented KVO compliance can’t necessarily be counted on. Key–Value Observing | 359 PART IV Views This part of the book is about the things that appear in an app’s interface. All such things are, ultimately, views. A view is a unit of your app that knows how to draw itself. A view also knows how to sense that the user has touched it. Views are what your user sees on the screen, and what your user interacts with by touching the screen. Thus, views are the primary constituent of an app’s visible, touchable manifestation. They are your app’s interface. So it’s going to be crucial to know how views work. • Chapter 14 discusses views in their most general aspect — their hierarchy, visibility, and position, including an explanation of autolayout, a way of positioning views that’s new in iOS 6. • Chapter 15 is about drawing. A view knows how to draw itself; this chapter explains how to tell a view what you want it to draw, from simply displaying an already existing image to constructing a drawing line by line. • Chapter 16 explains about layers. The drawing power of a view comes ultimately from its layer. To put it another way, a layer is effectively the aspect of a view that knows how to draw — with even more power. • Chapter 17 tells about animation. An iOS app’s interface isn’t generally static; it’s lively. Much of that liveliness comes from animation. iOS gives you great power to animate your interface with remarkable ease; that power resides ultimately in layers. • Chapter 18 is about touches. A view knows how to draw itself; it also knows how to sense that the user is touching it. This chapter explains the iOS view-based mechanisms for sensing and responding to touches, with details on how touches are routed to the appropriate view and how you can customize that routing. CHAPTER 14 Views A view (an object whose class is UIView or a subclass of UIView) knows how to draw itself into a rectangular area of the interface. Your app has a visible interface thanks to views. Creating and configuring a view can be extremely simple: “Set it and forget it.” You’ve already seen that you can drag an interface widget, such as a UIButton, into a view in the nib; when the app runs, the button appears, and works properly. But you can also manipulate views in powerful ways, in real time. Your code can do some or all of the view’s drawing of itself; it can make the view appear and disappear, move, resize itself, and display many other physical changes, possibly with animation. A view is also a responder (UIView is a subclass of UIResponder). This means that a view is subject to user interactions, such as taps and swipes. Thus, views are the basis not only of the interface that the user sees, but also of the interface that the user touches. Organizing your views so that the correct view reacts to a given touch allows you to allocate your code neatly and efficiently. The view hierarchy is the chief mode of view organization. A view can have subviews; a subview has exactly one immediate superview. Thus there is a tree of views. This hierarchy allows views to come and go together. If a view is removed from the interface, its subviews are removed; if a view is hidden (made invisible), its subviews are hidden; if a view is moved, its subviews move with it; and other changes in a view are likewise shared with its subviews. The view hierarchy is also the basis of, though it is not identical to, the responder chain (Chapter 11). A view may come from a nib, or you can create it in code. On balance, neither approach is to be preferred over the other; it depends on your needs and inclinations and on the overall architecture of your app. 363 The Window The top of the view hierarchy is the app’s window. It is an instance of UIWindow (or your own subclass thereof), which is a UIView subclass. Your app should have exactly one main window. It occupies the entire screen and forms the background to, and is the ultimate superview of, all your other visible views. Other views are visible by virtue of being subviews, at some depth, of your app’s window. (If your app can display views on an external screen, you’ll create an additional UIWindow to contain those views; but in this chapter I’ll behave as if there were just one screen, the device’s own screen, and just one window.) The Xcode project templates all generate your app’s window for you. The technique used, in a nonstoryboard app, is to create the window explicitly in code, in the app delegate’s application:didFinishLaunchingWithOptions:. The window must persist for the lifetime of the app, so the app delegate has a window property that retains it: self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; The window’s designated initializer is initWithFrame:; I’ll explain in a moment what “frame” and “bounds” are, but the effect is to make the window the same size as the screen. In the template, the comment, “Override point for customization after applica‐ tion launch,” comes after that line of code, because any code customizing what’s in the window will need the window to exist first. The various templates adopt various strate‐ gies for giving the window some content; this generally involves setting the window’s rootViewController to a UIViewController, whose view thus automatically becomes the window’s single primary subview. (I will refer to this as the window’s root view.) For example, in the Single View Application project template, the ViewController class is instantiated, and the resulting instance is set to the window’s rootViewController. This sets in motion a further train of events automatically. The nib ViewController.xib loads with the ViewController instance as its owner; the UIView pointed to by the File’s Owner’s view outlet in the nib is instantiated, and the ViewController instance’s view property is set by the nib-loading process to that UIView; and the window makes that view its single primary subview. Finally, the template code sends the window instance the makeKeyAndVisible message in order to make your app’s interface appear. If you choose the Storyboard option as you specify a template, the process works a little differently. The app is given a main storyboard, pointed to by the Info.plist key “Main storyboard file base name” (UIMainStoryboardFile). After UIApplicationMain in‐ stantiates the app delegate class (Chapter 6), it asks the app delegate for the value of its window property; if that value is nil, the window is created and assigned to the app delegate’s window property. The storyboard’s initial view controller is then instantiated and assigned to the window’s rootViewController property, with the result that its view is placed in the window as its root view; the window is then sent the makeKeyAnd- 364 | Chapter 14: Views Visible message. All of that is done behind the scenes by UIApplicationMain, with no visible code whatever. That is why, in a storyboard template, the application:didFinishLaunchingWithOptions: implementation is empty. An app whose main window has no rootViewController is not strictly illegal, but it is strongly discouraged by a warning from the runtime as the app launches. The Single View Application template supplies a minimal root view controller for you. The Empty Application template does not; if you use it as is, it generates the warning. To experiment with code that populates the interface with views, you can use the Empty Application template and put your code in its application:didFinishLaunchingWithOptions:, but if you want to avoid the warning, you’ll need to create a minimal root view controller and add the views to its view, like this: self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Override point for customization after application launch. self.window.rootViewController = [UIViewController new]; UIView* v = [[UIView alloc] initWithFrame:CGRectMake(100,100,50,50)]; v.backgroundColor = [UIColor redColor]; // small red square // add it to the root view controller's view [self.window.rootViewController.view addSubview: v]; self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; return YES; Alternatively, use the Single View Application template. In that case, any code that adds views should appear in View Controller’s viewDidLoad implementation, and the views should be added to self.view: [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. UIView* v = [[UIView alloc] initWithFrame:CGRectMake(100,100,50,50)]; v.backgroundColor = [UIColor redColor]; // small red square // add it to this view controller's view [self.view addSubview: v]; To experiment with views created in a nib, start with the Single View Application project template, as we did with our earlier Empty Window example. The view supplied in the nib will become the window’s root view, and whatever you drag into it in the nib will appear in the window when the app runs. It is improbable that you would want to subclass UIWindow and substitute an instance of your subclass as the app’s main window, but you can certainly do so. If the window is generated explicitly in code, you would obviously substitute the name of your window subclass as the class to be instantiated and assigned to the app delegate’s window property in application:didFinishLaunchingWithOptions:, in the template code I quoted a moment ago. If you’re using a main storyboard, however, application:didFinishLaunchingWithOptions: is too late; you’ll have to perform the substitution when UIApplicationMain asks for the app delegate’s window property, by implementing the The Window | 365 app delegate’s window getter to create the window and set the window property exactly once: - (UIWindow*) window { UIWindow* w = self->_window; if (!w) { w = [[MyWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; self->_window = w; } return w; } Once the app is up and running, the app delegate points to the window as the value of its window property; so any code in the app delegate class can refer to the window as self.window. Code elsewhere can get a reference to the app delegate, so it can also get a reference to the app’s window: UIWindow* theWindow = [[[UIApplication sharedApplication] delegate] window]; That code is unusual, though, and may require typecasting to quiet the compiler (be‐ cause the class of the application’s delegate property is otherwise unknown). You’d be more likely to use the application’s keyWindow property: UIWindow* theWindow = [[UIApplication sharedApplication] keyWindow]; Perhaps the most typical way to get a reference to your app’s window would be through a subview of the window, at any depth of the hierarchy. You are very likely to have a reference to at least one such subview, and its window property points to the window that contains it, which is the app’s window. You can also use a UIView’s window property as a way of asking whether it is ultimately embedded in a window; if it isn’t, its window property is nil. A UIView whose window property is nil cannot be visible to the user. Although your app will have exactly one primary window, it may generate other win‐ dows of which you are not conscious. For example, if you put up an alert view (UIAlert‐ View), it is displayed in a secondary window that lies on top of your app’s window; at that moment, this secondary window is the application’s keyWindow. You would not be conscious of this fact, however, unless you needed a reference to your app’s window while an alert was showing, which is unlikely. The window’s backgroundColor property, which it inherits from UIView, affects the appearance of the app if the window is visible behind its subviews. However, you are likely to give your window a primary subview that occupies the entire window and blocks it from sight; the window’s backgroundColor would then make no visible dif‐ ference. The window would function solely as a container for the app’s visible views. 366 | Chapter 14: Views Figure 14-1. Overlapping views Subview and Superview Once upon a time, and not so very long ago, a view owned precisely its rectangular area. No part of any view that was not a subview of this view could appear inside it, because when this view redrew its rectangle, it would erase the overlapping portion of the other view. No part of any subview of this view could appear outside it, because the view took responsibility for its own rectangle and no more. Those rules, however, were gradually relaxed, and starting in Mac OS X 10.5 Apple introduced an entirely new architecture for view drawing that lifted those restrictions completely. iOS view drawing is based on this revised architecture. So now some or all of a subview can appear outside its superview, and a view can overlap another view and can be drawn partially or totally in front of it without being its subview. So, for example, Figure 14-1 shows three overlapping views. All three views have a background color, so each is completely represented by a colored rectangle. You have no way of knowing, from this visual representation, exactly how the views are related within the view hierarchy. In actual fact, the view in the middle (horizontally) is a sibling view of the view on the left (they are both direct subviews of the root view), and the view on the right is a subview of the middle view. When views are created in the nib, you can examine the view hierarchy in the expanded dock to learn their actual relationship (Figure 14-2). When views are created in code, you know their hierarchical relationship because you created that hierarchy. But the visible interface doesn’t tell you, because view overlapping is so flexible. Nevertheless, a view’s position in the view hierarchy does affect how it is drawn. Most important, a view’s position in the view hierarchy dictates the order in which it is drawn. Sibling subviews of the same superview have a layering order: one is “further back” than the other. This will make no visible difference if there is no overlap, but the subview that is “further back” is drawn first, so if there is overlap, it will appear to be behind its sibling. Subview and Superview | 367 Figure 14-2. A view hierarchy as displayed in the nib Similarly, a superview is “further back” than its subviews; the superview is drawn first, so it will appear to be behind its subviews. You can see this illustrated in Figure 14-1. The view on the right is a subview of the view in the middle and is drawn on top of it. The view on the left is a sibling of the view in the middle, but it is a later sibling, so it is drawn on top of the view in the middle and on top of the view on the right. The view on the left cannot appear behind the view on the right but in front of the view in the middle, because those views are subview and superview and are drawn together — both are drawn either before or after the view on the left, depending on the “further back” ordering of the siblings. This layering order can be governed in the nib by arranging the views in the expanded dock. (If you click in the canvas, you may be able to use the menu items of the Editor → Arrange menu instead — Send to Front, Send to Back, Send Forward, Send Back‐ ward.) In code, there are methods for arranging the sibling order of views, which we’ll come to in a moment. Here are some other effects of the view hierarchy: • If a view is removed from or moved within its superview, its subviews go with it. • If a view’s size is changed, its subviews can be resized automatically. • A view’s degree of transparency is inherited by its subviews. • A view can optionally limit the drawing of its subviews so that any parts of them outside the view are not shown. This is called clipping and is set with the view’s clipsToBounds property. • A superview owns its subviews, in the memory-management sense, much as an NSArray owns its elements; it retains them and is responsible for releasing a subview when that subview ceases to be its subview (it is removed from the collection of this view’s subviews) or when it itself goes out of existence. A UIView has a superview property (a UIView) and a subviews property (an NSArray of UIViews, in back-to-front order), allowing you to trace the view hierarchy in code. There is also a method isDescendantOfView: letting you check whether one view is a subview of another at any depth. If you need a reference to a particular view, you will probably arrange this beforehand as an instance variable, perhaps through an outlet. 368 | Chapter 14: Views Alternatively, a view can have a numeric tag (its tag property), and can then be referred to by sending any view higher up the view hierarchy the viewWithTag: message. Seeing that all tags of interest are unique within their region of the hierarchy is up to you. Manipulating the view hierarchy in code is easy. This is part of what gives iOS apps their dynamic quality, and it compensates for the fact that there is basically just a single window. It is perfectly reasonable for your code to rip an entire hierarchy of views out of the superview and substitute another. Such behavior can be implemented elegantly by using a UIViewController, a subject to which we’ll return later (Chapter 19). But you can do it directly, too. The method addSubview: makes one view a subview of another; removeFromSuperview takes a subview out of its superview’s view hierarchy. In both cases, if the superview is part of the visible interface, the subview will appear or disap‐ pear; and of course this view may itself have subviews that accompany it. Just remember that removing a subview from its superview releases it; if you intend to reuse that sub‐ view later on, you will wish to retain it first. This is often taken care of through a property with a retain policy. Events inform a view of these dynamic changes. To respond to these events requires subclassing. Then you’ll be able to override any of didAddSubview: and willRemoveSubview:, didMoveToSuperview and willMoveToSuperview:, didMoveToWindow and willMoveToWindow:. When addSubview: is called, the view is placed last among its superview’s subviews; thus it is drawn last, meaning that it appears frontmost. A view’s subviews are indexed, starting at 0, which is rearmost. There are additional methods for inserting a subview at a given index (insertSubview:atIndex:), or below (behind) or above (in front of) a specific view (insertSubview:belowSubview:, insertSubview:aboveSubview:); for swapping two sibling views by index (exchangeSubviewAtIndex:withSubviewAtIndex:); and for moving a subview all the way to the front or back among its siblings (bringSubviewToFront:, sendSubviewToBack:). Oddly, there is no command for removing all of a view’s subviews at once. However, a view’s subviews array is an immutable copy of the internal list of subviews, so it is legal to cycle through it and remove each subview one at a time: for (UIView* v in view.subviews) [v removeFromSuperview]; Visibility and Opacity A view can be made invisible by setting its hidden property to YES, and visible again by setting it to NO. This takes it (and its subviews, of course) out of the visible interface without the overhead of actually removing it from the view hierarchy. A hidden view Visibility and Opacity | 369 does not (normally) receive touch events, so to the user it really is as if the view weren’t there. But it is there, so it can still be manipulated in code. A view can be assigned a background color through its backgroundColor property. A color is a UIColor; this is not a difficult class to use, and I’m not going to go into details. A view whose background color is nil (the default) has a transparent background. It is perfectly reasonable for a view to have a transparent background and to do no additional drawing of its own, just so that it can act as a convenient superview to other views, making them behave together. A view can be made partially or completely transparent through its alpha property: 1.0 means opaque, 0.0 means transparent, and a value may be anywhere between them, inclusive. This affects subviews: if a superview has an alpha of 0.5, none of its subviews can have an apparent opacity of more than 0.5, because whatever alpha value they have will be drawn relative to 0.5. (Just to make matters more complicated, colors have an alpha value as well. So, for example, a view can have an alpha of 1.0 but still have a transparent background because its backgroundColor has an alpha less than 1.0.) A view that is completely transparent (or very close to it) is like a view whose hidden is YES: it is invisible, along with its subviews, and cannot (normally) be touched. A view’s alpha property value affects the apparent transparency of its background color and the apparent transparency of its contents separately. For example, if a view displays an image and has a background color and its alpha is less than 1, the background color will seep through the image (and whatever is behind the view will seep through both). A view’s opaque property, on the other hand, is a horse of a different color; changing it has no effect on the view’s appearance. Rather, this property is a hint to the drawing system. If a view completely fills its bounds with ultimately opaque material and its alpha is 1.0, so that the view has no effective transparency, then it can be drawn more efficiently (with less drag on performance) if you inform the drawing system of this fact by setting its opaque to YES. Otherwise, you should set its opaque to NO. The opaque value is not changed for you when you set a view’s backgroundColor or alpha! Setting it correctly is entirely up to you; the default, perhaps surprisingly, is YES. Frame A view’s frame property, a CGRect, is the position of its rectangle within its superview, in the superview’s coordinate system. By default, the superview’s coordinate system will have the origin at its top left, with the x-coordinate growing positively rightward and the y-coordinate growing positively downward. Setting a view’s frame to a different CGRect value repositions the view, or resizes it, or both. If the view is visible, this change will be visibly reflected in the interface. On the other hand, you can also set a view’s frame when the view is not visible — for example, 370 | Chapter 14: Views when you create the view in code. In that case, the frame describes where the view will be positioned within its superview when it is given a superview. UIView’s designated initializer is initWithFrame:, and you’ll often assign a frame this way, especially because the default frame might otherwise be {{0,0},{0,0}}, which is rarely what you want. Forgetting to assign a view a frame when creating it in code, and then wondering why it isn’t appearing when added to a superview, is a com‐ mon beginner mistake. A view with a zero-size frame is effectively in‐ visible. If a view has a standard size that you want it to adopt, especially in relation to its contents (like a UIButton in relation to its title), an alternative is to send it the sizeToFit message. Knowing this, we can generate programmatically the interface displayed in Figure 14-1. This code might appear in the application:didFinishLaunchingWithOptions: method of the app delegate in an Empty Application template-based app (as I suggested earlier): UIView* v1 = [[UIView alloc] initWithFrame:CGRectMake(113, 111, 132, 194)]; v1.backgroundColor = [UIColor colorWithRed:1 green:.4 blue:1 alpha:1]; UIView* v2 = [[UIView alloc] initWithFrame:CGRectMake(41, 56, 132, 194)]; v2.backgroundColor = [UIColor colorWithRed:.5 green:1 blue:0 alpha:1]; UIView* v3 = [[UIView alloc] initWithFrame:CGRectMake(43, 197, 160, 230)]; v3.backgroundColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:1]; [self.window.rootViewController.view addSubview: v1]; [v1 addSubview: v2]; [self.window.rootViewController.view addSubview: v3]; In that code, we determined the layering order of v1 and v3 (the middle and left views, which are sibling subviews of the window) by the order in which we inserted them into the view hierarchy with addSubview:. Bounds and Center Suppose we wish to give a view a subview inset by 10 points, as in Figure 14-3. The utility function CGRectInset makes it easy to derive one rectangle as an inset from another, but what rectangle should we use as a basis? Not the superview’s frame; the frame rep‐ resents a view’s position within its superview, and in that superview’s coordinates. What we’re after is a CGRect describing our superview’s rectangle in its own coordinates, because those are the coordinates in which the subview’s frame is to be expressed. That CGRect, describing a view’s rectangle in its own coordinates, is the view’s bounds prop‐ erty. So, the code to generate Figure 14-3 looks like this: Bounds and Center | 371 Figure 14-3. A subview inset from its superview UIView* v1 = [[UIView alloc] initWithFrame:CGRectMake(113, 111, 132, 194)]; v1.backgroundColor = [UIColor colorWithRed:1 green:.4 blue:1 alpha:1]; UIView* v2 = [[UIView alloc] initWithFrame:CGRectInset(v1.bounds, 10, 10)]; v2.backgroundColor = [UIColor colorWithRed:.5 green:1 blue:0 alpha:1]; [self.window.rootViewController.view addSubview: v1]; [v1 addSubview: v2]; You’ll very often use a view’s bounds in this way. When you need coordinates for drawing inside a view, whether drawing manually or placing a subview, you’ll often refer to the view’s bounds. Interesting things happen when you set a view’s bounds. If you change a view’s bounds size, you change its frame. The change in the view’s frame takes place around its cen‐ ter, which remains unchanged. So, for example: UIView* v1 = [[UIView alloc] initWithFrame:CGRectMake(113, 111, 132, 194)]; v1.backgroundColor = [UIColor colorWithRed:1 green:.4 blue:1 alpha:1]; UIView* v2 = [[UIView alloc] initWithFrame:CGRectInset(v1.bounds, 10, 10)]; v2.backgroundColor = [UIColor colorWithRed:.5 green:1 blue:0 alpha:1]; [self.window.rootViewController.view addSubview: v1]; [v1 addSubview: v2]; CGRect f = v2.bounds; f.size.height += 20; f.size.width += 20; v2.bounds = f; What appears is a single rectangle; the subview completely and exactly covers its su‐ perview, its frame being the same as the superview’s bounds. The call to CGRectInset started with the superview’s bounds and shaved 10 points off the left, right, top, and bottom to set the subview’s frame (Figure 14-3). But then we added 20 points to the subview’s bounds height and width, and thus added 20 points to the subview’s frame height and width as well (Figure 14-4). The center didn’t move, so we effectively put the 10 points back onto the left, right, top, and bottom of the subview’s frame. 372 | Chapter 14: Views Figure 14-4. A subview exactly covering its superview When you create a UIView, its bounds coordinate system’s {0,0} point is at its top left. If you change a view’s bounds origin, you move the origin of its internal coordinate system. Because a subview is positioned in its superview with respect to its superview’s coordinate system, a change in the bounds origin of the superview will change the apparent position of a subview. To illustrate, we start with our subview inset evenly within its superview, and then change the bounds origin of the superview: UIView* v1 = [[UIView alloc] initWithFrame:CGRectMake(113, 111, 132, 194)]; v1.backgroundColor = [UIColor colorWithRed:1 green:.4 blue:1 alpha:1]; UIView* v2 = [[UIView alloc] initWithFrame:CGRectInset(v1.bounds, 10, 10)]; v2.backgroundColor = [UIColor colorWithRed:.5 green:1 blue:0 alpha:1]; [self.window.rootViewController.view addSubview: v1]; [v1 addSubview: v2]; CGRect f = v1.bounds; f.origin.x += 10; f.origin.y += 10; v1.bounds = f; Nothing happens to the superview’s size or position. But the subview has moved up and to the left so that it is flush with its superview’s top-left corner (Figure 14-5). Basically, what we’ve done is to say to the superview, “Instead of calling the point at your upper left {0,0}, call that point {10,10}.” Because the subview’s frame origin is itself at {10,10}, the subview now touches the superview’s top-left corner. The effect of chang‐ ing a view’s bounds origin may seem directionally backward — we increased the su‐ perview’s origin in the positive direction, but the subview moved in the negative direc‐ tion — but think of it this way: a view’s bounds origin point coincides with its frame’s top left. We have seen that changing a view’s bounds size affects its frame size. The converse is also true: changing a view’s frame size affects its bounds size. What is not affected by changing a view’s bounds size is the view’s center. This property, like the frame property, represents the view’s position within its superview, in the superview’s coordinates, but it is the position of the bounds center, the point derived from the bounds like this: Bounds and Center | 373 Figure 14-5. The superview’s bounds origin has been shifted CGPoint c = CGPointMake(CGRectGetMidX(theView.bounds), CGRectGetMidY(theView.bounds)); A view’s center is thus a single point establishing the positional relationship between a view’s bounds and its superview’s bounds. Changing a view’s bounds does not change its center (we already saw that when we increased a view’s bounds size, its frame ex‐ panded around a stationary center); changing a view’s center does not change its bounds. Thus, a view’s bounds and center are orthogonal (independent), and describe (among other things) both the view’s size and its position within its superview. The view’s frame is therefore superfluous! In fact, the frame property is merely a convenient expression of the center and bounds values. In most cases, this won’t matter to you; you’ll use the frame property anyway. When you first create a view from scratch, the designated ini‐ tializer is initWithFrame:. You can change the frame, and the bounds size and center will change to match. You can change the bounds size or the center, and the frame will change to match. Nevertheless, the proper and most reliable way to position and size a view within its superview is to use its bounds and center, not its frame; there are some situations in which the frame is meaningless (or will at least behave very oddly), but the bounds and center will always work. We have seen that every view has its own coordinate system, expressed by its bounds, and that a view’s coordinate system has a clear relationship to its superview’s coordinate system, expressed by its center. This is true of every view in a window, so it is possible to convert between the coordinates of any two views in the same window. Convenience methods are supplied to perform this conversion both for a CGPoint and for a CGRect: convertPoint:fromView:, convertPoint:toView:, convertRect:fromView:, and convertRect:toView:. If the second parameter is nil, it is taken to be the window. For example, if v2 is a subview of v1, then to center v2 within v1 you could say: v2.center = [v1 convertPoint:v1.center fromView:v1.superview]; 374 | Chapter 14: Views Window Coordinates and Screen Coordinates The device screen has no frame, but it has bounds. The main window has no superview, but its frame is set with respect to the screen’s bounds, as in the template code I cited earlier: self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; The window’s frame is unusual. It isn’t your app’s visible frame, because it may be partially covered by the status bar, which is actually another window, supplied by the system. Its coordinates are invariant, regardless of the rotation of the device: the window’s {0,0} point thus might be in any corner (from the user’s perspective). Thus, window coordi‐ nates are screen coordinates. The region of the window not covered by the status bar, in screen coordinates, which are also window coordinates, may be obtained from the main screen’s applicationFrame property: CGRect f = [UIScreen mainScreen].applicationFrame; Once the window is created, you will rarely need to access its coordinates, except to use its bounds as the ultimate coordinate reference system. The root view controller’s view will be much more important to you. By default, its frame is set to equal the applicationFrame, and if the device is rotated and the interface rotates to compensate, its frame is adjusted so that it continues to equal the applicationFrame. This is one of the main benefits of using a root view controller. When setting a view’s position by setting its center, if the height or width of the view is not an even integer, the view can end up mis‐ aligned (on a single-resolution screen): its point values in one or both dimensions are located between the screen pixels. This can cause the view to be displayed incorrectly; for example, if the view contains text, the text may be blurry. You can detect this situation in the Simulator by checking Debug → Color Misaligned Images. A simple solution is to set the view’s frame, after positioning it, to the CGRectIntegral of its frame. Transform A view’s transform property alters how the view is drawn — it may, for example, change the view’s perceived size and orientation — without affecting its bounds and center. A transformed view continues to behave correctly: a rotated button, for example, is still a button, and can be tapped in its apparent location and orientation. Transform | 375 A transform value is a CGAffineTransform, which is a struct representing six of the nine values of a 3×3 transformation matrix (the other three values are constants, so there’s no point representing them in the struct). You may have forgotten your high-school linear algebra, so you may not recall what a transformation matrix is. For the details, which are quite simple really, see the “Transforms” chapter of Apple’s Quartz 2D Pro‐ gramming Guide, especially the section called “The Math Behind the Matrices.” But you don’t really need to know those details, because convenience functions, whose names start with CGAffineTransformMake..., are provided for creating three of the basic types of transform: rotation, scaling, and translation (i.e., changing the view’s apparent posi‐ tion). A fourth basic transform type, skewing or shearing, has no convenience function. By default, a view’s transformation matrix is CGAffineTransformIdentity, the identity transform. It has no visible effect, so you’re unaware of it. Any transform that you do apply takes place around the view’s center, which is held constant. Here’s some code to illustrate use of a transform: UIView* v1 = [[UIView alloc] initWithFrame:CGRectMake(113, 111, 132, 194)]; v1.backgroundColor = [UIColor colorWithRed:1 green:.4 blue:1 alpha:1]; UIView* v2 = [[UIView alloc] initWithFrame:CGRectInset(v1.bounds, 10, 10)]; v2.backgroundColor = [UIColor colorWithRed:.5 green:1 blue:0 alpha:1]; [self.window.rootViewController.view addSubview: v1]; [v1 addSubview: v2]; v1.transform = CGAffineTransformMakeRotation(45 * M_PI/180.0); The transform property of the view v1 is set to a rotation transform. The result (Figure 14-6) is that the view appears to be rocked 45 degrees clockwise. (I think in degrees, but Core Graphics thinks in radians, so my code has to convert.) Observe that the view’s center property is unaffected, so that the rotation seems to have occurred around the view’s center. Moreover, the view’s bounds property is unaffected; the internal coordinate system is unchanged, so the subview is drawn in the same place relative to its superview. The view’s frame, however, is now useless, as no mere rectangle can de‐ scribe the region of the superview apparently occupied by the view; the frame’s actual value, {{63.7416, 92.7416}, {230.517, 230.517}}, describes the minimal bounding rectangle surrounding the view’s apparent position. The rule is that if a view’s transform is not the identity transform, you should not set its frame; also, automatic resizing of a subview, discussed later in this chapter, requires that the superview’s transform be the identity transform. Suppose, instead of CGAffineTransformMakeRotation, we call CGAffineTransformMakeScale, like this: v1.transform = CGAffineTransformMakeScale(1.8, 1); The bounds property of the view v1 is still unaffected, so the subview is still drawn in the same place relative to its superview; this means that the two views seem to have 376 | Chapter 14: Views Figure 14-6. A rotation transform Figure 14-7. A scale transform stretched horizontally together (Figure 14-7). No bounds or centers were harmed by the application of this transform! Transformation matrices can be chained. There are convenience functions for applying one transform to another. Their names do not contain “Make.” These functions are not commutative; that is, order matters. If you start with a transform that translates a view to the right and then apply a rotation of 45 degrees, the rotated view appears to the right of its original position; on the other hand, if you start with a transform that rotates a view 45 degrees and then apply a translation to the right, the meaning of “right” has changed, so the rotated view appears 45 degrees down from its original position. To demonstrate the difference, I’ll start with a subview that exactly overlaps its superview: UIView* v1 = [[UIView alloc] initWithFrame:CGRectMake(20, 111, 132, 194)]; v1.backgroundColor = [UIColor colorWithRed:1 green:.4 blue:1 alpha:1]; UIView* v2 = [[UIView alloc] initWithFrame:v1.bounds]; v2.backgroundColor = [UIColor colorWithRed:.5 green:1 blue:0 alpha:1]; [self.window.rootViewController.view addSubview: v1]; [v1 addSubview: v2]; Transform | 377 Figure 14-8. Translation, then rotation Figure 14-9. Rotation, then translation Then I’ll apply two successive transforms to the subview, leaving the superview to show where the subview was originally. In this example, I translate and then rotate (Figure 14-8): v2.transform = CGAffineTransformMakeTranslation(100, 0); v2.transform = CGAffineTransformRotate(v2.transform, 45 * M_PI/180.0); In this example, I rotate and then translate (Figure 14-9): v2.transform = CGAffineTransformMakeRotation(45 * M_PI/180.0); v2.transform = CGAffineTransformTranslate(v2.transform, 100, 0); The function CGAffineTransformConcat concatenates two transform matrices using matrix multiplication. Again, this operation is not commutative. The order is the op‐ posite of the order when using convenience functions for applying one transform to another. For example, this gives the same result as Figure 14-9: 378 | Chapter 14: Views Figure 14-10. Rotation, then translation, then inversion of the rotation Figure 14-11. Skew (shear) CGAffineTransform r = CGAffineTransformMakeRotation(45 * M_PI/180.0); CGAffineTransform t = CGAffineTransformMakeTranslation(100, 0); v2.transform = CGAffineTransformConcat(t,r); // not r,t To remove a transform from a combination of transforms, apply its inverse. A conve‐ nience function lets you obtain the inverse of a given affine transform. Again, order matters. In this example, I rotate the subview and shift it to its “right,” and then remove the rotation (Figure 14-10): CGAffineTransform r = CGAffineTransformMakeRotation(45 * M_PI/180.0); CGAffineTransform t = CGAffineTransformMakeTranslation(100, 0); v2.transform = CGAffineTransformConcat(t,r); v2.transform = CGAffineTransformConcat(CGAffineTransformInvert(r), v2.transform); Finally, as there are no convenience methods for creating a skew (shear) transform, I’ll illustrate by creating one manually, without further explanation (Figure 14-11): v1.transform = CGAffineTransformMake(1, 0, -0.2, 1, 0, 0); Transform | 379 Transforms are useful particularly as temporary visual indicators. For example, you might call attention to a view by applying a transform that scales it up slightly, and then applying the identity transform to restore it to its original size, and animating those changes (Chapter 17). The transform property lies at the heart of an iOS app’s ability to rotate its interface. The window’s frame and bounds, as I’ve already said, are invariant, locked to the screen; but the root view’s frame and bounds are not. Suppose the user rotates the device 90 degrees and the app interface is to rotate to compensate. How is this done? The root view’s frame is adjusted to match the new applicationFrame, so that it continues to fill the window except for the part covered by the status bar. In addition, a 90-degree ro‐ tation transform is applied to the root view, so that its {0,0} point moves to what the user now sees as the top left of the view. The root view’s subviews have their frame in the root view’s bounds coordinate system, so they are effectively rotated. But what about the position of the root view’s subviews? Consider, for example, a subview located at the bottom right of the screen when the device is in portrait orientation. If the device is rotated 90 degrees, the screen is now considerably shorter vertically, and if a 90-degree rotation transform is applied to the root view to compensate for the device rotation, the root view’s bounds width and bounds height are effectively swapped, with what was the longer dimension becoming the shorter dimension and vice versa. So that poor old subview will now be off the screen — unless something further is done. That’s the subject of the next section. Layout We have seen that a subview moves when its superview’s bounds origin is changed. But what happens to a subview when its superview’s bounds size is changed? (And remem‐ ber, this includes changing the superview’s frame size.) Of its own accord, nothing happens. The subview’s bounds and center haven’t changed, and the superview’s bounds origin hasn’t moved, so the subview stays in the same po‐ sition relative to the top left of its superview. In real life, however, that often won’t be what you want. You’ll want subviews to be resized and repositioned when their super‐ view’s bounds size is changed. This is called layout. The need for layout is obvious in a context such as Mac OS X, where the user can freely resize a window, potentially disturbing your interface. For example, you’d want an OK button near the lower-right corner to stay in the lower-right corner as the window grows, while a text field at the top of the window should stay at the top of the window, but perhaps should widen as the window widens. There are no user-resizable windows on an iOS device, but still, a superview might be resized dynamically. For example, you might respond to the user rotating the device 90 degrees by swapping the width and height values of a view; now its subviews should 380 | Chapter 14: Views shift to compensate. Or you might want to provide a reusable complex view, such as a table view cell containing several subviews, without knowing its precise final dimensions in advance. And the introduction of the iPhone 5, with its taller screen, means that one and the same app might launch into portrait orientation on an iPhone 4 and on an iPhone 5, with different height dimensions, which may call for some adjustment of the interface. Layout is performed in three primary ways in iOS 6: Manual layout The superview is sent the layoutSubviews message whenever it is resized; so, to lay out subviews manually, provide your own subclass and override layoutSubviews. Clearly this could turn out to be a lot of work, but it means you can do anything you like. Autoresizing Autoresizing is the pre-iOS 6 way of performing layout automatically. It depends ultimately on the superview’s autoresizesSubviews property. To turn off a view’s automatic resizing altogether, set this property to NO. If it is YES, then a subview will respond automatically to its superview’s being resized, in accordance with the rules prescribed by the subview’s autoresizingMask property value. Autoresizing is performed before layoutSubviews is called. Autolayout Autolayout, introduced in iOS 6, depends on the constraints of views. A constraint (an instance of NSLayoutConstraint) is much more sophisticated than the autoresizingMask; it’s a full-fledged object with numeric values, and can describe a relationship between any two views (not just a subview and its superview). Autolayout is an opt-in technology (though it is the default for new nibs created in Xcode 4.5 and later), and is incompatible with systems before iOS 6. You can im‐ plement it on a view by view basis; for example, you might lay out a superview using autoresizing but its subviews using autolayout. Autolayout replaces not only au‐ toresizing but also the use of a view’s frame (or bounds and center) to position that view; once you choose to use autolayout for a view, you should use only autolayout for that view, both to set its position and to determine what should happen if there’s a change in another view to which this one is bound by a constraint. Autoresizing Autoresizing is a matter of conceptually assigning a subview “springs and struts.” A spring can stretch; a strut can’t. Springs and struts can be assigned internally or exter‐ nally. Thus you can specify (using internal springs and struts) whether and how the view can be resized, and (using external springs and struts) whether and how the view can be repositioned. For example: Layout | 381 • Imagine a subview that is centered in its superview and is to stay centered, but is to resize itself as the superview is resized. It would have struts externally and springs internally. • Imagine a subview that is centered in its superview and is to stay centered, and is not to resize itself as the superview is resized. It would have springs externally and struts internally. • Imagine an OK button that is to stay in the lower right of its superview. It would have struts internally, struts externally to its right and bottom, and springs externally to its top and left. • Imagine a text field that is to stay at the top of its superview. It is to widen as the superview widens. It would have struts externally; internally it would have a vertical strut and a horizontal spring. To experiment with autoresizing in a nib, you’ll need autolayout to be turned off for that nib. By default, autolayout is turned on for a new nib created in Xcode 4.5 and later. To turn it off, select the nib in the Project navigator and show the File inspector: uncheck “Use autolayout.” When editing a nib file with autolayout turned off, you can assign a view springs and struts in the Size inspector (Autosizing). A solid line externally represents a strut; a solid line internally represents a spring. A helpful animation shows you the effect on your view’s position as its superview is resized. In code, a combination of springs and struts is set through a view’s autoresizingMask property. It’s a bitmask, so you use logical-or to combine options (Chapter 1). The options, with names that start with UIViewAutoresizingFlexible..., represent springs; whatever isn’t specified is a strut. The default is UIViewAutoresizingNone, meaning all struts — but of course it can’t really be all struts, because if the superview is resized, something needs to change; in reality, UIViewAutoresizingNone is the same as UIViewAutoresizingFlexibleRightMargin together with UIViewAutoresizingFlexibleBottomMargin. To demonstrate autoresizing, I’ll start with a view and two subviews, one stretched across the top, the other confined to the lower right (Figure 14-12): UIView* v1 = [[UIView alloc] initWithFrame:CGRectMake(100, 111, 132, 194)]; v1.backgroundColor = [UIColor colorWithRed:1 green:.4 blue:1 alpha:1]; UIView* v2 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 132, 10)]; v2.backgroundColor = [UIColor colorWithRed:.5 green:1 blue:0 alpha:1]; UIView* v3 = [[UIView alloc] initWithFrame:CGRectMake(v1.bounds.size.width-20, v1.bounds.size.height-20, 20, 20)]; 382 | Chapter 14: Views Figure 14-12. Before autoresizing Figure 14-13. After autoresizing v3.backgroundColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:1]; [self.window.rootViewController.view addSubview: v1]; [v1 addSubview: v2]; [v1 addSubview: v3]; To that example, I’ll add code applying springs and struts to the two subviews to make them behave like the text field and the OK button I was hypothesizing earlier: v2.autoresizingMask = UIViewAutoresizingFlexibleWidth; v3.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin; Now I’ll resize the superview, thus bringing autoresizing into play; as you can see (Figure 14-13), the subviews remain pinned in their correct relative positions: CGRect f = v1.bounds; f.size.width += 40; f.size.height -= 50; v1.bounds = f; Autolayout Autolayout is an opt-in technology. By default, as your app launches, autolayout is switched off, and the system behaves as in iOS 5 and before. But if, at any time while your app runs, the system sees an autolayout constraint (generated in code or by the Layout | 383 loading of a nib that has “Use autolayout” checked), the autolayout system is switched on, and from then on you’re running under autolayout. A common place to create constraints is in a view’s updateConstraints implementation (discussed later in this chapter). Howev‐ er, if there are no constraints to start with, updateConstraints won’t be called. So you might need a way to bootstrap autolayout. That way is to implement the UIView class method requiresConstraintBasedLayout to return YES in some UIView subclass. An autolayout constraint, or simply constraint, is an NSLayoutConstraint instance, and describes either the absolute width or height of a view or a relationship between an attribute of one view and an attribute of another view. In the latter case, the attributes don’t have to be the same attribute, and the two views don’t have to be siblings (subviews of the same superview) or parent and child (superview and subview) — the only re‐ quirement is that they share a common ancestor (a superview at some height up the view hierarchy). Here are the chief properties of an NSLayoutConstraint: firstItem firstAttribute secondItem secondAttribute The two views and their respective attributes involved in this constraint. If the constraint is describing a view’s absolute height or width, the second view will be nil and the second attribute will be NSLayoutAttributeNotAnAttribute (which you’ll probably write as 0). Additional attribute types are: • NSLayoutAttributeLeft • NSLayoutAttributeRight • NSLayoutAttributeTop • NSLayoutAttributeBottom • NSLayoutAttributeLeading • NSLayoutAttributeTrailing • NSLayoutAttributeWidth • NSLayoutAttributeHeight • NSLayoutAttributeCenterX • NSLayoutAttributeCenterY 384 | Chapter 14: Views • NSLayoutAttributeBaseline The meanings of the attributes are intuitively obvious, except that you might be wondering about what “leading” and “trailing” mean: they are the international equivalent of “left” and “right”, automatically reversing their meaning on systems whose language is written right-to-left (making it easy, say, to align the beginnings of several labels of different lengths, irrespective of localization). multiplier constant Numbers to be applied to the second attribute’s value to determine the first at‐ tribute’s value. The multiplier is multiplied by the second attribute’s value; the constant is added to that product. (The name constant is a very poor choice, as this value isn’t constant; have the Apple folks never heard the term addend?) Basi‐ cally, you’re writing an equation of the form a1 = ma2 + c, where a1 and a2 are the two attributes, and m and c are the multiplier and the constant. Thus, in the most degenerate case, when the first attribute’s value is to equal the second attribute’s value, the multiplier will be 1 and the constant will be 0. relation How the two attribute values are to be related to one another, as modified by the multiplier and the constant. This is the operator that goes in the spot where I put the equal sign in the equation in the preceding paragraph. It might be an equal sign (NSLayoutRelationEqual, which you’ll probably write as 0), but then again it might not; inequalities are also permitted (NSLayoutRelationLessThanOrEqual, NSLayoutRelationGreaterThanOrEqual). priority Priority values range from 1000 (required) down to 1, and certain standard behav‐ iors have standard priorities. Constraints can have different priorities, determining the order in which they are applied. Constraints are permitted to conflict with one another provided they have different priorities. A constraint belongs to a view. A view can have many constraints: a UIView has a constraints property, along with instance methods addConstraint:, addConstraints:, removeConstraint, and removeConstraints:. The question then is which view a given constraint should belong to. The answer is absolute: it is the closest superview of both views involved in a constraint. Thus, for example, if the constraint dictates a view’s absolute width, it belongs to that view; if it aligns the tops of two sibling views, it belongs to their superview; if it sets the top of a view in relation to the top of its superview, it belongs to the superview. The runtime may permit you to cheat and add a constraint at too high a level, but adding a constraint that refers to a view outside the subview hierarchy of the view to which you add it will cause a crash (with a helpful error message). Layout | 385 Both views involved in a constraint must be present in the view hierarchy before the constraint can be added. NSLayoutConstraint properties are read-only, except for priority and constant. In Chapter 17, it will turn out that changing a constraint’s constant in real time is a good way to animate a view. If you want to change anything else about a constraint, you must remove the constraint and add a new one. If you use constraints, and if a view is created either in code or in a nib where “Use autolayout” is unchecked, that view’s autoresizingMask is automatically translated into constraint form and applied in addition to any constraints you apply. It isn’t one of the view’s constraints, but it’s operating as a set of constraints anyway. If that isn’t what you want — that is, if only the constraints you apply are to be treated as constraints — you must explicitly turn off this behavior by setting the view’s translatesAutoresizingMaskIntoConstraints property to NO, because the default is YES. It may seem inconvenient to have to keep turning off translatesAutoresizingMaskIntoConstraints; why is the default YES? For a very good reason: that’s what allows you to use autolayout for some views and autoresizing for others. If a minimum of just one view has a min‐ imum of just one explicit constraint, the entire autolayout system springs to life throughout your entire interface. This doesn’t cause hav‐ oc, because all the views without explicit constraints have translatesAutoresizingMaskIntoConstraints turned on by default, so their au‐ toresizing masks are implicitly translated into constraints (hence the name!) and the layout dictated by those autoresizing masks continues to work. We are now ready to write some code involving constraints! I’ll generate the same views and subviews and layout behavior as in Figure 14-12 and Figure 14-13, but using con‐ straints: UIView* v1 = [[UIView alloc] initWithFrame:CGRectMake(100, 111, 132, 194)]; v1.backgroundColor = [UIColor colorWithRed:1 green:.4 blue:1 alpha:1]; UIView* v2 = [UIView new]; UIView* v3 = [UIView new]; v2.backgroundColor = [UIColor colorWithRed:.5 green:1 blue:0 alpha:1]; v3.backgroundColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:1]; [self.window.rootViewController.view addSubview: v1]; [v1 addSubview: v2]; [v1 addSubview: v3]; v2.translatesAutoresizingMaskIntoConstraints = NO; v3.translatesAutoresizingMaskIntoConstraints = NO; [v1 addConstraint: [NSLayoutConstraint 386 | Chapter 14: Views constraintWithItem:v2 attribute:NSLayoutAttributeLeft relatedBy:0 toItem:v1 attribute:NSLayoutAttributeLeft multiplier:1 constant:0]]; [v1 addConstraint: [NSLayoutConstraint constraintWithItem:v2 attribute:NSLayoutAttributeRight relatedBy:0 toItem:v1 attribute:NSLayoutAttributeRight multiplier:1 constant:0]]; [v1 addConstraint: [NSLayoutConstraint constraintWithItem:v2 attribute:NSLayoutAttributeTop relatedBy:0 toItem:v1 attribute:NSLayoutAttributeTop multiplier:1 constant:0]]; [v2 addConstraint: [NSLayoutConstraint constraintWithItem:v2 attribute:NSLayoutAttributeHeight relatedBy:0 toItem:nil attribute:0 multiplier:1 constant:10]]; [v3 addConstraint: [NSLayoutConstraint constraintWithItem:v3 attribute:NSLayoutAttributeWidth relatedBy:0 toItem:nil attribute:0 multiplier:1 constant:20]]; [v3 addConstraint: [NSLayoutConstraint constraintWithItem:v3 attribute:NSLayoutAttributeHeight relatedBy:0 toItem:nil attribute:0 multiplier:1 constant:20]]; [v1 addConstraint: [NSLayoutConstraint constraintWithItem:v3 attribute:NSLayoutAttributeRight relatedBy:0 toItem:v1 attribute:NSLayoutAttributeRight multiplier:1 constant:0]]; [v1 addConstraint: [NSLayoutConstraint constraintWithItem:v3 attribute:NSLayoutAttributeBottom relatedBy:0 toItem:v1 attribute:NSLayoutAttributeBottom multiplier:1 constant:0]]; Now, I know what you’re thinking. You’re thinking: “What are you, nuts? That is a boatload of code!” (Except that you probably used another four-letter word instead of “boat”.) But that’s something of an illusion. I’d argue that what we’re doing here is actually simpler than the code with which we created Figure 14-12 through autoresizing: Layout | 387 • We create eight constraints in eight commands; I’ve broken each command into multiple lines, but that’s just a matter of formatting. They’re verbose, but they are the same command repeated with different parameters, so creating them is just a matter of copy-and-paste. • It looks as though just two commands (setting the autoresizing masks of the two subviews) have been replaced by eight commands. But we’re getting more bang for our buck than that: we’re no longer assigning v2 and v3 an initial frame! The con‐ straints describe the positions of those views from the outset, and this, in constraint terms, remains their position even as their superview is resized. So constraints re‐ place both setting a view’s autoresizing mask and setting its frame (or bounds and center) as a way of describing its layout. • Constraints are a far clearer expression of what’s supposed to happen than setting the autoresizing mask. • Constraints are also a far clearer expression of a subview’s position than setting its frame! For example, in describing v3’s position, we don’t have to use any math to place its frame origin. Recall what we had to say before: v3 = [[UIView alloc] initWithFrame:CGRectMake(v1.bounds.size.width-20, v1.bounds.size.height-20, 20, 20)]; That business of subtracting the view’s height and width from its superview’s bounds height and width in order to place the view is skanky and error-prone. With constraints, we can speak the truth directly; our code says, plainly and simply, “v3 is 20 points wide and 20 points high and it’s flush with the bottom right corner of v1”. In addition, constraints can express things that autoresizing can’t. For example, instead of applying an absolute height to v2, we could require that its height be exactly onetenth of v1’s height, regardless of how v1 is resized. That sort of thing is utterly impossible without constraints (unless you implement layoutSubviews and enforce it manually, in code). If you really find our code too verbose, it may be possible to condense it somewhat. Instead of creating each constraint individually, we can sometimes describe multiple constraints simultaneously through a sort of text-based shorthand, called a visual for‐ mat. The shorthand is best understood by example: @"V:|[v2(10)]" In that expression, V: means that the vertical dimension is under discussion; the alter‐ native is H:, which is also the default (so it is permitted to specify no dimension). A view’s name appears in square brackets, and a pipe (|) signifies the superview, so here we’re describing v2’s top edge as butting up against its superview’s top edge. Numeric dimensions appear in parentheses, and a numeric dimension accompanying a view’s 388 | Chapter 14: Views name sets that dimension of that view, so here we’re also taking advantage of this spec‐ ification of the vertical dimension to set v2’s height to 10. To use a visual format, you have to provide a dictionary mapping the string name of each view mentioned to the actual view. For example, the dictionary accompanying the preceding expression might be @{@"v2":v2}. We can form this dictionary automatically with a macro, NSDictionaryOfVariableBindings, which takes a list of variable names. So here’s another way of expressing of the preceding code example, using the visual format shorthand throughout: UIView* v1 = [[UIView alloc] initWithFrame:CGRectMake(100, 111, 132, 194)]; v1.backgroundColor = [UIColor colorWithRed:1 green:.4 blue:1 alpha:1]; UIView* v2 = [UIView new]; UIView* v3 = [UIView new]; v2.backgroundColor = [UIColor colorWithRed:.5 green:1 blue:0 alpha:1]; v3.backgroundColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:1]; [self.window.rootViewController.view addSubview: v1]; [v1 addSubview: v2]; [v1 addSubview: v3]; NSDictionary *vs = NSDictionaryOfVariableBindings(v2,v3); v2.translatesAutoresizingMaskIntoConstraints = NO; v3.translatesAutoresizingMaskIntoConstraints = NO; [v1 addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[v2]|" options:0 metrics:nil views:vs]]; [v1 addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[v2(10)]" options:0 metrics:nil views:vs]]; [v1 addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"H:[v3(20)]|" options:0 metrics:nil views:vs]]; [v1 addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"V:[v3(20)]|" options:0 metrics:nil views:vs]]; That example creates the same constraints as the previous example, but in four com‐ mands instead of eight. The visual format syntax shows itself to best advantage when multiple views are laid out in relation to one another along the same dimension; in that situation, you get a lot of bang for your buck (many constraints generated by one visual format string). The syn‐ tax, however, is somewhat limited in what constraints it can express; it conceals the number and exact nature of the constraints that it produces; and personally I find it easier to make a mistake with the visual format syntax than with the complete expression Layout | 389 of each constraint. Still, you’ll want to become familiar with it, not least because console messages describing a constraint sometimes use it. Here are some further things to know when generating constraints with the visual for‐ mat syntax: • The metrics: parameter is a dictionary of NSNumber values. This lets you use a name in the visual format string where a numeric value needs to go. • The options: parameter is a bitmask letting you do things like add alignments. The alignments you specify are applied to all the views mentioned in the visual format string. • To specify the distance between two successive views, use hyphens surrounding the numeric value, like this: @"[v1]-20-[v2]". The numeric value may optionally be surrounded by parentheses. A single hyphen means that a default distance should be used. • A numeric value in parentheses may be preceded by an equality or inequality op‐ erator, and may be followed by an at sign with a priority. Multiple numeric values, separated by comma, may appear in parentheses together. For example: @"[v1(>=20@400,<=30)]". You can make two major kinds of mistake with constraints: Conflict You can apply constraints that can’t be satisfied simultaneously. This will be reported in the console (at great length). Only required constraints (priority 1000) can con‐ tribute to a conflict, as the runtime is free to ignore lower-priority constraints that it can’t satisfy. For example, to the previous code, append this line: [v1 addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"V:[v3(10)]|" options:0 metrics:nil views:vs]]; The height of v3 can’t be both 10 (as here) and 20 (as in the preceding line). The runtime reports the conflict, and tells you which constraints are causing it. Underdetermination (ambiguity) You haven’t supplied sufficient information to determine the size and position of some view. This is a far more insidious problem, because nothing bad may seem to happen, so you might not discover it until much later. If you’re lucky, the view will at least fail to appear, or will appear in an undesirable place, alerting you to the problem. For example, in the last line of the previous code, we set the height of v3 to 20; suppose we remove that specification: 390 | Chapter 14: Views [v1 addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"V:[v3]|" options:0 metrics:nil views:vs]]; Fortunately, v3 fails to appear in the interface, so we know we’ve made a mistake. To help you analyze ambiguity, log a view’s hasAmbiguousLayout property (a BOOL); be sure to remove that call before submitting your app to the App Store. Alternatively, pause the running app and ask the debugger for the key window’s _autolayoutTrace; ambiguously laid out views are clearly marked: (lldb) po [[UIWindow keyWindow] _autolayoutTrace] (id) $1 = 0x074a41a0 *<UIWindow:0x749b890> | *<UIView:0x749ccb0> | | *<UIView:0x749c280> | | | *<UIView:0x749c790> | | | *<UIView:0x749c930> - AMBIGUOUS LAYOUT I find it useful to set up a category on NSLayoutConstraint with a method that lets me check a view and all its subviews at any depth for ambiguity: @implementation NSLayoutConstraint (Ambiguity) + (void) reportAmbiguity:(UIView*) v { if (nil == v) v = [[UIApplication sharedApplication] keyWindow]; for (UIView* vv in v.subviews) { NSLog(@"%@ %i", vv, vv.hasAmbiguousLayout); if (vv.subviews.count) [self reportAmbiguity:vv]; } } @end Given the notions of conflict and ambiguity, we can understand what priorities are for. Imagine that all constraints have been placed in boxes, where each box is a priority value, in descending order. The first box (1000) contains all the required constraints, so all required constraints are obeyed first. (If they conflict, that’s bad, and a report appears in the log; meanwhile, the system implicitly lowers the priority of one of the conflicting constraints, so that it doesn’t have to obey it and can continue with layout by satisfying the remaining required constraints.) If there still isn’t enough information to perform unambiguous layout given the required priorities alone, we pull the constraints out of the next box and try to obey them. If we can, consistently with what we’ve already done, fine; if we can’t, or if ambiguity remains, we look in the next box — and so on. For a box after the first, we don’t care about obeying exactly the constraints it contains; if an ambiguity remains, we can use a lower-priority constraint value to give us something to aim at, resolving the ambiguity, without fully obeying the lower-priority constraint’s desires. For example, an inequality is an ambiguity, because an infinite number of values Layout | 391 will satisfy it; a lower-priority equality can tell us what value to prefer, resolving the ambiguity, but there’s no conflict even if we can’t fully achieve that preferred value. Some built-in interface objects have an inherent size in one or both dimensions, so they are not ambiguously laid out even if no explicit NSLayoutConstraint dictates their size. Rather, the inherent size is used to generate constraints implicitly. For example, a button has a standard height, and its width is determined by its title. This inherent size is the object’s intrinsic content size. You can supply an intrinsic size in your own custom UI‐ View subclass by implementing intrinsicContentSize. If you need the runtime to call intrinsicContentSize again, because that size has changed and the view needs to be laid out afresh, send your view the invalidateIntrinsicContentSize message. The tendency of an interface object to size itself to its intrinsic content size can conflict with its tendency to obey explicit constraints. For example, we wouldn’t want a UILabel to extend out of its superview, no matter how long its text may be; if the text isn’t per‐ mitted to wrap, it should be truncated. Therefore these tendencies have a priority: contentHuggingPriorityForAxis: The tendency of a view to refuse to grow larger than its intrinsic size in this di‐ mension. The default is 250 (also known as UILayoutPriorityDefaultLow). contentCompressionResistancePriorityForAxis: The tendency of a view to refuse to shrink smaller than its intrinsic size in this dimension. The default is 750 (also known as UILayoutPriorityDefaultHigh). (The dimensions are UILayoutConstraintAxisHorizontal and UILayoutConstraintAxisVertical.) Those methods are getters; there are corresponding setters. You’re un‐ likely, however, to change the priorities for these tendencies — at least, you’re unlikely to change them by much. A situation where you would possibly need to change them is when two views with an intrinsic content size are pinned to one another. This can result in an ambiguity. Of two adjacent labels, which should be truncated if the superview gets narrower? To dictate the answer, it suffices to raise the compression resistance priority of one of the labels by a single point. Another common situation is where you’ll want to lower the priority of some other constraint, to allow intrinsic content size to predominate. An example that Apple gives is a label to the left of a centered button: the button’s bottom is pinned to the superview’s bottom, and the label and button are pinned to one another with their baselines aligned, and the button’s horizontal center is pinned to its superview’s horizontal center. If the label’s text grows longer (or the superview’s width grows narrower), the label should not stretch leftward past the left side of its superview, so it has an inequality constraint pinning its left at a guaranteed minimum distance from the superview’s left. But the text should not then be truncated if it doesn’t have to be, so the priority with which the button is horizontally centered is made lower than the label’s compression resistance priority: 392 | Chapter 14: Views self.button.translatesAutoresizingMaskIntoConstraints = NO; self.label.translatesAutoresizingMaskIntoConstraints = NO; id button = self.button; id label = self.label; NSDictionary* d = NSDictionaryOfVariableBindings(button,label); [self.view addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"V:[button]-|" options:0 metrics:nil views:d]]; [self.view addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(>=10)-[label]-[button]-(>=10)-|" options:NSLayoutFormatAlignAllBaseline metrics:nil views:d]]; NSLayoutConstraint* con = [NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeCenterX relatedBy:0 toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]; con.priority = 700; [self.view addConstraint:con]; Behind the scenes, compression resistance and content hugging work like this: Suppose the view’s intrinsic width is 100 points. Then two implicit constraints are generated, an inequality saying that the view’s width should be greater than or equal to 100 points, but with a priority of 750, and an inequality saying that the view’s width should be less than or equal to 100 points, but with a priority of 250. All other things being equal, the view’s width will be exactly 100 points, as this satisfies both inequalities unambiguously. But higher-priority constraints could cause the width to be less or greater. In the preceding example, as the label’s text becomes longer, its intrinsic width grows. The first inequality says we may make the label’s width greater than its intrinsic width, at a priority of 750, but the button’s tenacity to hold its position in the center is even less, at a priority of 700, so the label adopts its intrinsic width and the button shifts right to obey the spacing constraint between them (which is required). But there is also an inequality spacing constraint on the button’s right side (which is also required); eventually the button moves so far to the right that it can move no further without violating that constraint, which is impossible. At that point, since the first inequality cannot be satisfied, the second inequality is consulted; it permits the label to be narrower than its intrinsic content, the label stops growing to match its growing intrinsic width, and its text is truncated instead. Constraints in the Nib In a nib where “Use autolayout” is checked, when you add a view to a superview or move or resize it within its superview, the nib editor adds constraints. A constraint is an object, so these are nib objects. Constraints in the nib are visible in three places: Layout | 393 Figure 14-14. A view’s constraints displayed in the nib In the expanded dock Constraints are listed in a special category, “Constraints”, under the view to which they belong. You’ll have a much easier time distinguishing these constraints if you give your views meaningful labels! (See Chapter 7.) Select a constraint and show the Attributes inspector to view its numeric value, its priority, and so on. In the canvas Constraints appear graphically as dimension lines. Select a constraint and show the Attributes inspector to view its numeric value, its priority, and so on. In the Size inspector When a view involved in any constraints is selected, the Size inspector displays those constraints, along with the view’s content hugging priority and compression re‐ sistance priority in each dimension. For example, in Figure 14-14, I’ve started to set up a view and a subview like v1 and v2 in the earlier code example; the subview is selected, so its constraints are shown in the Size inspector. The nib editor’s automatic creation of constraints in the nib is clever, but it presents two major challenges: • It doesn’t know what you really intend to have happen if a view’s superview is resized at runtime. • It won’t let you create, even temporarily, an ambiguous or conflicted layout — but it will let you create a layout that could generate a conflict if a superview is resized at runtime. As a result, you’ll often find yourself trying to correct a misapprehension on the nib editor’s part, and you’ll find that this can be quite tricky. Figure 14-14 shows a case in point. Of the automatically generated constraints affecting the subview, three are correct 394 | Chapter 14: Views — the left, right, and top space between the subview and its superview — but the fourth is not. Xcode has created a constraint describing the space between the bottom of the subview and the bottom of the superview; I want that space free to change. Instead, I want to fix the subview’s height (at 10 points). But Xcode won’t let me delete the un‐ wanted constraint, because that would cause ambiguous layout. The solution is to create the new constraint first. To do so, select the affected view(s) and choose from the Editor → Align or Editor → Pin menu (or use the first or second pop-up menu in the floating cartouche at the lower right of the canvas). In this case, we want to constrain the subview’s height to its current height, so we select the subview and choose Editor → Pin → Height. This generates an additional constraint. Unfortunately we now have a potential conflict. Our subview has a height constraint of 10 points; meanwhile, its top is still pinned to the top of its superview, and its bottom is still pinned to the bottom of its superview. Xcode permits this situation because it is legal now, but if the superview’s height changes at runtime, it won’t be possible to satisfy all of those constraints; something needs to give. In this situation, you can do one of three things: Delete the unwanted constraint In this case, that’s the simplest solution. We can select the constraint that pins the bottom of the subview to the bottom of its superview and delete it. In more com‐ plicated situations, though, the nib editor might not permit that. Lower the priority of the unwanted constraint If the unwanted constraint has a low enough priority, it will have no effect on the layout. You can lower the constraint’s priority by selecting the constraint and ad‐ justing the Priority slider in the Attributes inspector. Remove the unwanted constraint in code If you’re really desperate, you can make an outlet to the unwanted constraint and use this to remove the constraint in code after the nib loads (but before layout actually takes place). I’ve found myself in situations so complex that this was my only recourse; I simply couldn’t bully the nib editor into letting me do what I wanted, even though that wouldn’t have resulted in an ambiguous layout. Another maddening feature of the nib editor is its tendency to change what’s selected. For example, when you select the subview and choose Editor → Pin → Height, the newly created constraint is selected instead of the subview. If what you’re trying to do is create several constraints having to do with a certain view, Xcode keeps deselecting the view and you have to keep reselecting it. The nib editor, like the visual format syntax, can’t specify every possible constraint. For example, you can’t express a multiplier, or a relationship between one view and another that isn’t its sibling or superview. Sometimes there’s no alternative to adding or adjusting a constraint in code after the nib loads. Layout | 395 Figure 14-15. An equal widths constraint configured in the nib Still, once you get used to it, you’ll find that being able to set up constraints in the nib is really nice. It’s quite easy to construct an interface that keeps working correctly when the app launches on the iPhone 5 (with its taller screen) vs. the iPhone 4, or when the app is rotated. Figure 14-15 shows two subviews with their superview margins set and configured to have their widths equal to one another. This was easily attained by se‐ lecting both views and choosing Editor → Pin → Widths Equally. The result, which looks great both on the iPhone 5 and on the iPhone 4, requires no code; without con‐ straints, only manual layout (in layoutSubviews) could have achieved the same thing. Here’s how to achieve in code the constraints created by the nib in Figure 14-15 (in the view controller’s viewDidLoad). Presume that we are starting with a nib where “Use autolayout” is unchecked, so it contains no constraints; and presume we have outlets to the two subviews, v1 and v2: UIView* sup = self.view; v1.translatesAutoresizingMaskIntoConstraints = NO; v2.translatesAutoresizingMaskIntoConstraints = NO; NSDictionary* d = NSDictionaryOfVariableBindings(sup, v1, v2); [sup addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"|-[v1]-(40)-[v2(==v1)]-|" options:0 metrics:0 views:d]]; [sup addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[v1]-|" options:0 metrics:0 views:d]]; 396 | Chapter 14: Views [sup addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[v2]-|" options:0 metrics:0 views:d]]; I’ll modify that same code to illustrate the notion of removing and adding constraints in code after the nib loads. Presume this time that our nib’s “Use autolayout” is checked. But let’s pretend that we can’t set up the horizontal spacing and width constraints in the nib; instead, both subviews have all four edges pinned to the corresponding edge of the superview. We already have outlets v1 and v2 to the two subviews; in addition, we create outlets cons1 and cons2 to the two unwanted constraints — the left subview’s right constraint and the right subview’s left constraint. Then, in the view controller’s viewDidLoad, we simply remove those constraints and replace them with what we really want: UIView* sup = self.view; [sup removeConstraints:@[cons1, cons2]]; NSDictionary* d = NSDictionaryOfVariableBindings(sup, v1, v2); [sup addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"|-[v1]-(40)-[v2(==v1)]-|" options:0 metrics:0 views:d]]; Another situation in which the nib editor may misunderstand what you intend is when a view has an intrinsic size. Should a label or a button, for example, be assigned an explicit width constraint, or should its width be governed by its intrinsic size? Xcode tries to guess which you want, based on the signals you give it; so it helps to know what signals Xcode is watching for. If you set a view’s size explicitly, Xcode will probably assume that you want an explicit size constraint. If you select a view and choose Editor → Size to Fit Content, Xcode will remove the view’s explicit size constraints, letting the intrinsic size predominate. You can’t turn off autolayout for just part of a nib. Either all views have constraints or all views use autoresizing. There’s no nib equivalent to the translatesAutoresizingMaskIntoConstraints property for an individual view. A workaround, if you’re bent on generating different parts of your interface in nibs, one part with autoresizing, another part with autolayout, is to separate those parts into different nibs and then combine them at runtime. If a nib’s “Use autolayout” is checked, do not load it on any system earlier than iOS 6. If you do, your app will crash, because you’re using a class, NSLayoutConstraint, that doesn’t exist before iOS 6. Unfortunately, “Use autolayout” is checked, by default, in all nibs created in Xcode 4.5 and later. Layout | 397 Order of Layout Events When the moment comes to lay out a view, the following events take place: 1. The view and its subviews are sent updateConstraints, starting at the bottom of the hierarchy (the deepest subview) and working up to the top (the view itself, possibly the root view). This event may be omitted for a view if its constraints have not changed. You can override updateConstraints in a subclass. You might do this, for example, if your subclass is capable of altering its own constraints and you need a signal that now is the time to do so. You must call super or the app will crash (with a helpful error message). You should never call updateConstraints; to trigger an immediate call to updateConstraints, send a view the updateConstraintsIfNeeded message. If you’re not using autolayout, updateConstraints by default won’t be sent to your view as part of the layout process. If you want it to be sent, send setNeedsUpdateConstraints to the view. You’ll then get updateConstraints events from then on, whenever layout is to be performed. 2. The view and its subviews are sent layoutSubviews, starting at the top of the hier‐ archy (the view itself, possibly the root view) and working down to the bottom (the deepest subview). You can override layoutSubviews in a subclass in order to take a hand in the layout process. If you’re not using autolayout, layoutSubviews does nothing by default; layoutSubviews is your opportunity to perform manual layout after autoresizing has taken place. If you are using autolayout, you must call super or the app will crash (with a helpful error message). You should never call layoutSubviews; to trigger an immediate call to layoutSubviews, send a view the layoutIfNeeded message (which may cause layout of the entire view tree, not only below but also above this view), or send setNeedsLayout to trigger a call to layoutSubviews later on, after your code finishes running, when layout would normally take place. When you’re using autolayout, what happens in layoutSubviews? The runtime exam‐ ines all the constraints affecting this view’s subviews, works out values for their frames, and assigns those views those frames. In other words, layoutSubviews performs manual layout! The constraints are merely instructions attached to the views; layoutSubviews reads them and responds accordingly, setting frames in the good oldfashioned way. Knowing this, you might override layoutSubviews when you’re using autolayout, in order to tweak the outcome. First you call super, causing all the subviews to adopt their new frames. Then you examine those frames. If you don’t like the outcome, you can 398 | Chapter 14: Views change the situation, removing subviews, adding or removing constraints, and so on — and then you call super again, to get a new layout outcome. Unless you explicitly demand immediate layout, layout isn’t performed until your code finishes running (and then only if needed). Moreover, ambiguous layout isn’t ambiguous until layout actually takes place. Thus, for example, it’s perfectly reasonable to cause an ambiguous layout temporarily, provided you resolve the ambiguity before layoutSubviews is called. (Your last best opportunity to do this is in updateConstraints!) That’s why it was legal for me, in the code at the end of the preceding section, to remove two constraints before adding some new ones; there was briefly an ambiguous layout situation, but no layout took place during that time. On the other hand, a conflicting constraint conflicts the instant it is added. This code may cause a conflict report to appear in the log: NSDictionary* d = NSDictionaryOfVariableBindings(sup, v1, v2); [sup addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"|-[v1]-(40)-[v2(==v1)]-|" options:0 metrics:0 views:d]]; [sup removeConstraints:@[cons1, cons2]]; If you try it and no conflict report appears, that’s only because this code is in the view controller’s viewDidLoad, which is called when the views in question are not yet part of the visible interface. If that same code were postponed to run at a later time, the addConstraints: call would generate the conflict report. The moral is clear: remove con‐ straints that need to be removed before adding new ones that need to be added. It is also possible to simulate layout of a view in accordance with its constraints and those of its subviews. This is useful for discovering ahead of time what the view’s size would be if layout were performed at this moment. Send the view the systemLayoutSizeFittingSize: message. The system will attempt to reach or at least approach the size you specify, at a very low priority; mostly likely you’ll specify either UILayoutFittingCompressedSize or UILayoutFittingExpandedSize, depending on whether what you’re after is the smallest or largest size the view can legally attain. I’ll show an example in Chapter 21. Autolayout and View Transforms Suppose I apply to a view a transform that shrinks it to half its size: v.transform = CGAffineTransformMakeScale(0.5,0.5); I expect the view to shrink in both dimensions, toward its center. Instead, under auto‐ layout, I might see it shrink just its height, while its width holds steady, and instead of shrinking toward its center, it shrinks toward its bottom; and this could turn out to be because its width and bottom are determined by constraints. Layout | 399 The fact is that autolayout does not play well with view transforms. The reason, appa‐ rently, is that (as I explained in the preceding section) autolayout works by treating the constraints as a to-do list and obeying them in layoutSubviews by applying manual layout. If a constraint describes a view’s frame by pinning one of its edges, then auto‐ layout will set that view’s frame. But setting a view’s frame is exactly what you’re not supposed to do when a view has a nonidentity transform. A further problem is that applying a transform to a view triggers layout immediately. This feels like a bug. One possible solution is this: if a view is to be given a transform, then take it out of autolayout’s influence altogether. In this code, I prepare to apply a transform to a view (self.otherView) by removing its constraints and any constraints of its superview (self.view) that affect it: NSMutableArray* cons = [NSMutableArray array]; for (NSLayoutConstraint* con in self.view.constraints) if (con.firstItem == self.otherView || con.secondItem == self.otherView) [cons addObject:con]; [self.view removeConstraints:cons]; [self.otherView removeConstraints:self.otherView.constraints]; Unfortunately, this won’t quite do, as otherView vanishes from the screen. The reason is that we are still using autolayout, and now otherView has no constraints whatever, so it has neither size nor position! To complete our code, we must prevent autolayout from using constraints as a way of positioning otherView, which we can do by bringing its autoresizing mask back into play: self.otherView.translatesAutoresizingMaskIntoConstraints = YES; The result is that otherView is now treated exactly as it was before autolayout existed, and a transform applied to it works correctly. Perhaps, however, that approach seems too drastic, as we have completely lost the benefit of being able to position our view through constraints. An alternative might be to use only constraints that don’t conflict with the transform we intend to apply. For example, if a view with an internally fixed width and height is positioned solely by pinning its center, then we can freely apply scale and rotation transforms to it, as these are applied around the view’s center and thus don’t conflict with the constraints that position it. Unfortunately, you probably won’t be able to arrange that in a nib, so you’ll have to use code to remove the existing constraints and then apply new ones: // remove constraints affecting otherView's edges NSMutableArray* cons = [NSMutableArray array]; for (NSLayoutConstraint* con in self.view.constraints) if (con.firstItem == self.otherView || con.secondItem == self.otherView) 400 | Chapter 14: Views [cons addObject:con]; [self.view removeConstraints:cons]; // add constraints positioning otherView by its center [self.view addConstraint: [NSLayoutConstraint constraintWithItem:self.otherView attribute:NSLayoutAttributeCenterX relatedBy:0 toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1 constant:self.otherView.center.x]]; [self.view addConstraint: [NSLayoutConstraint constraintWithItem:self.otherView attribute:NSLayoutAttributeCenterY relatedBy:0 toItem:self.view attribute:NSLayoutAttributeTop multiplier:1 constant:self.otherView.center.y]]; A further variant would be to use a host view and a subview. The host view is positioned by constraints, in the normal way: you can use the host view’s edges as part of the overall constraint-based layout. But the host view is also invisible. Now we can apply either of the preceding two solutions to the host view’s subview, which is visible. Either the sub‐ view has a fixed width and height, and is pinned by its center to the host view’s center, in which case scale and rotation transforms can be applied to it, or else we take the subview out of the influence of autolayout altogether, in which case any transform can be applied to it. Still another solution is to use a layer transform (Chapter 16) instead of a view transform, since applying a layer transform doesn’t trigger layout. Layout | 401 CHAPTER 15 Drawing Many UIView subclasses, such as a UIButton or a UITextField, know how to draw themselves; sooner or later, though, you’re going to want to do some drawing of your own. A class like UIImageView will display a static image; you can generate that image dynamically by drawing it in code. And a pure UIView does little or no drawing of its own; you can draw its appearance. Drawing is not difficult, but it is a very large topic. This chapter will make you com‐ fortable with the basic principles, so that you can consult and understand Apple’s doc‐ umentation when you need further details. UIImage and UIImageView The basic general UIKit image class is UIImage. UIImage can read a file from disk, so if an image does not need to be created dynamically, but has already been created before your app runs, then drawing may be as simple as providing an image file as a resource in your app’s bundle. The system knows how to work with many standard image file types, such as TIFF, JPEG, GIF, and PNG. You can also obtain image data in some other way, such as by downloading it, and transform this into a UIImage. Conversely, you can draw your own image for display in your interface or for saving to disk (image file output is discussed in Chapter 36). In the very simplest case, an image file in your app’s bundle can be obtained through the UIImage class method imageNamed:. This method looks at the top level of your app’s bundle for an image file with the supplied name, including the file extension, and reads it as a UIImage instance. A nice thing about this approach is that memory management is handled for you: the image data may be cached in memory, and if you ask for the same image by calling imageNamed: again later, the cached data may be supplied im‐ mediately. You can also read an image file from anywhere in your app’s bundle using the class method imageWithContentsOfFile: or the instance method initWith403 ContentsOfFile:, both of which expect a pathname string; you can get a reference to your app’s bundle with [NSBundle mainBundle], and NSBundle then provides instance methods for getting the pathname of a file within the bundle, such as pathForResource:ofType:. Many built-in Cocoa interface objects will accept a UIImage as part of how they draw themselves; for example, a UIButton can display an image, and a UINavigationBar or a UITabBar can have a background image. I’ll discuss those in Chapter 25. But when you simply want an image to appear in your interface, you’ll probably hand it to a UIImage‐ View, which has the most knowledge and flexibility with regard to displaying images and is intended for this purpose. If a UIImageView instance begins life in a nib and is to display a UIImage from a file in your app’s bundle, you won’t even need any code; the UIImageView can be set to that file directly in the nib. (This mechanism works most easily if the file will be at the top level of the app’s bundle.) A UIImageView can actually have two images, one assigned to its image property and the other assigned to its highlightedImage property; the value of the UIImageView’s highlighted property dictates which of the two is displayed. A UIImageView does not automatically highlight itself, the way a button does, for example, merely because the user taps it. However, there are certain situations where a UIImageView will respond to the highlighting of its surroundings; for example, within a table view cell, a UIImage‐ View will show its highlighted image when the cell is highlighted. You can, of course, also use the notion of UIImageView highlighting yourself however you like. When an image is obtained by name from the bundle, as with imageNamed: or the name you enter in the nib for a UIImageView’s image, a file with the same name extended by ~ipad will automatically be used if the app is running on an iPad. You can use this in a universal app to supply different images automatically depending on whether the app runs on an iPhone or iPod touch, on the one hand, or on an iPad, on the other. This is true not just for images but for any resource obtained by name from the bundle. See Apple’s Resource Programming Guide. Similarly, on a device with a double-resolution screen, when an image is obtained by name from the bundle, a file with the same name extended by @2x, if there is one, will be used automatically, with the resulting UIImage marked as double-resolution by as‐ signing it a scale property value of 2.0. In this way, your app can contain both a singleresolution and a double-resolution version of an image file; on the double-resolution display device, the double-resolution version of the image is used, and is drawn at the same size as the single-resolution image. Thus, on the double-resolution screen, your code continues to work without change, but your images look sharper. A UIImageView is a UIView, so it can have a background color in addition to its image, it can have an alpha (transparency) value, and so forth (see Chapter 14). A UIImageView without a background color is invisible except for its image, so the image simply appears 404 | Chapter 15: Drawing Figure 15-1. Mars appears in my interface in the interface, without the user being aware that it resides in a rectangular host. An image may have areas that are transparent, and a UIImageView will respect this; thus an image of any shape can appear. A UIImageView without an image and without a background color is invisible, so you could start with an empty UIImageView in the place where you will later need an image and subsequently assign the image in code. You can assign a new image to substitute one image for another. How a UIImageView draws its image depends upon the setting of its contentMode property. (The contentMode property is inherited from UIView; I’ll discuss its more general purpose later in this chapter.) For example, UIViewContentModeScaleToFill means the image’s width and height are set to the width and height of the view, thus filling the view completely even if this alters the image’s aspect ratio; UIViewContentModeCenter means the image is drawn centered in the view without altering its size. The best way to get a feel for the meanings of the various contentMode settings is to assign a UIImageView a small image in a nib and then, in the Attributes inspector, change the Mode pop-up menu, and see where and how the image draws itself. When creating a UIImageView in code, you can take advantage of a convenience ini‐ tializer, initWithImage: (or initWithImage:highlightedImage:). The default contentMode is UIViewContentModeScaleToFill, but the image is not initially scaled; rather, the view itself is sized to match to the image. You will still probably need to position the UIImageView correctly in its superview. In this example, I’ll put a picture of the planet Mars in the center of the app’s interface (Figure 15-1): UIImageView* iv = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Mars.png"]]; [self.window.rootViewController.view addSubview: iv]; iv.center = CGPointMake(CGRectGetMidX(iv.superview.bounds), CGRectGetMidY(iv.superview.bounds)); iv.frame = CGRectIntegral(iv.frame); If we have a second image file called [email protected], it will be used on a double-resolution device. Under autolayout (Chapter 14), the size of an image assigned to a UIImageView be‐ comes that UIImageView’s intrinsicContentSize — even if the UIImageView already exists. This can lead to new behavior if your code adopts autolayout. Previously, as‐ UIImage and UIImageView | 405 signing an image to an existing UIImageView (as opposed to creating the UIImageView with initWithImage:) had no effect on the UIImageView’s bounds; under autolayout, it calls setNeedsLayout and, at layout time, the UIImageView’s bounds are changed. Thus, this code, too, will display Mars in the center of the interface: UIImageView* iv = [UIImageView new]; [self.window.rootViewController.view addSubview: iv]; iv.translatesAutoresizingMaskIntoConstraints = NO; [iv.superview addConstraint: [NSLayoutConstraint constraintWithItem:iv attribute:NSLayoutAttributeCenterX relatedBy:0 toItem:iv.superview attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]]; [iv.superview addConstraint: [NSLayoutConstraint constraintWithItem:iv attribute:NSLayoutAttributeCenterY relatedBy:0 toItem:iv.superview attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]]; iv.image = [UIImage imageNamed:@"Mars.png"]; (If a UIImageView is assigned both an image and a highlightedImage, and if they are of different sizes, the view’s intrinsicContentSize adopts the size of image.) A UIImage can be transformed into a resizable image, by sending it the resizableImageWithCapInsets:resizingMode: message. (This method is new in iOS 6, superseding the less flexible resizableImageWithCapInsets: introduced in iOS 5 — which itself superseded the notion of a stretchable image from previous system versions.) The capInsets: argument is a UIEdgeInsets, a struct consisting of four floats representing inset values starting at the top and moving counterclockwise — top, left, bottom, right. They represent distances inwards from the edges of the image. In a context (such as a UIImageView) larger than the image, a resizable image can behave in one of two ways, depending on the resizingMode: value: UIImageResizingModeTile The interior rectangle of the inset area is tiled (repeated) in the interior; each edge is formed by tiling the corresponding edge rectangle outside the inset area. The four corner rectangles outside the inset area are shown unchanged at the four corners. UIImageResizingModeStretch The interior rectangle of the inset area is stretched once to fill the interior; each edge is formed by stretching the corresponding edge rectangle outside the inset area once. The four corner rectangles outside the inset area are shown unchanged at the four corners. Resizable images may seem like a curiosity at first, but in fact they are extremely useful. Some places in the interface require them; for example, a custom image that serves as 406 | Chapter 15: Drawing Figure 15-2. Tiling the entire image of Mars the background of a slider or progress view (Chapter 25) must be resizable, so that it can fill a space of any length. And there can frequently be situations where you want to fill a background by tiling a texture or by extending an existing image. First, I’ll illustrate tiling: UIImage* mars = [UIImage imageNamed:@"Mars.png"]; UIImage* marsTiled = [mars resizableImageWithCapInsets:UIEdgeInsetsZero resizingMode: UIImageResizingModeTile]; UIImageView* iv = [[UIImageView alloc] initWithFrame: CGRectMake(20,5,mars.size.width*2,mars.size.height*4)]; iv.image = marsTiled; The image view is eight times the size of the Mars image, and the inset area is the entire image, so we see eight complete copies of the Mars image (Figure 15-2). Now we’ll tile the interior of the image, changing the capInsets: argument from the previous code (Figure 15-3): UIImage* marsTiled = [mars resizableImageWithCapInsets: UIEdgeInsetsMake(mars.size.height/4.0, mars.size.width/4.0, mars.size.height/4.0, mars.size.width/4.0) resizingMode: UIImageResizingModeTile]; Next, I’ll illustrate stretching. We’ll start by changing just the resizingMode: from the previous code (Figure 15-4): UIImage and UIImageView | 407 Figure 15-3. Tiling the interior of Mars Figure 15-4. Stretching the interior of Mars UIImage* marsTiled = [mars resizableImageWithCapInsets: UIEdgeInsetsMake(mars.size.height/4.0, mars.size.width/4.0, mars.size.height/4.0, mars.size.width/4.0) resizingMode: UIImageResizingModeStretch]; A common stretching strategy is to make almost half the original image serve as a cap inset, leaving just a pixel or two in the center to fill the entire interior of the resulting 408 | Chapter 15: Drawing Figure 15-5. Stretching a single pixel at the interior of Mars image (Figure 15-5); this generates a stretched border whose corners are the corners of the original image: UIImage* marsTiled = [mars resizableImageWithCapInsets: UIEdgeInsetsMake(mars.size.height/2.0 - 1, mars.size.width/2.0 - 1, mars.size.height/2.0 - 1, mars.size.width/2.0 - 1) resizingMode: UIImageResizingModeStretch]; Graphics Contexts UIImageView draws an image for you and takes care of all the details; in many cases, it will be all you’ll need. Eventually, though, you may want to create some drawing yourself, directly, in code. To do so, you will always need a graphics context. A graphics context is basically a place you can draw. Conversely, you can’t draw in code unless you’ve got a graphics context. There are several ways in which you might obtain a graphics context; in this chapter I will concentrate on two, which have proven in my experience to be far and away the most common: You create an image context The function UIGraphicsBeginImageContextWithOptions creates a graphics con‐ text suitable for use as an image. You then draw into this context to generate the image. When you’ve done that, you call UIGraphicsGetImageFromCurrentImageContext to turn the context into a UIImage, and then UIGraphicsEndImageContext to dismiss the context. Now you have a UIImage that you can display in your interface or draw into some other graphics context or save as a file. Graphics Contexts | 409 Cocoa hands you a graphics context You subclass UIView and implement drawRect:. At the time your drawRect: im‐ plementation is called, Cocoa has already created a graphics context and is asking you to draw into it, right now; whatever you draw is what the UIView will display. (A slight variant of this situation is that you subclass a CALayer and implement drawInContext:, or make some object the delegate of a layer and implement drawLayer:inContext:; layers are discussed in Chapter 16.) Moreover, at any given moment there either is or is not a current graphics context: • UIGraphicsBeginImageContextWithOptions not only creates an image context, it also makes that context the current graphics context. • When drawRect: is called, the UIView’s drawing context is already the current graphics context. • Callbacks with a context: argument have not made any context the current graph‐ ics context; rather, that argument is a reference to a graphics context. What beginners find most confusing about drawing is that there are two separate sets of tools with which you can draw, and they take different attitudes towards the context in which they will draw: UIKit Various Objective-C classes know how to draw themselves; these include UIImage, NSString (for drawing text), UIBezierPath (for drawing shapes), and UIColor. Some of these classes provide convenience methods with limited abilities; others are ex‐ tremely powerful. In many cases, UIKit will be all you’ll need. With UIKit, you can draw only into the current context. So if you’re in a UIGraphicsBeginImageContextWithOptions or drawRect: situation, you can use the UIKit convenience methods directly; there is a current context and it’s the one you want to draw into. If you’ve been handed a context: argument, on the other hand, then if you want to use the UIKit convenience methods, you’ll have to make that context the current context; you do this by calling UIGraphicsPushContext (and be sure to restore things with UIGraphicsPopContext later). Core Graphics This is the full drawing API. Core Graphics, often referred to as Quartz, or Quartz 2D, is the drawing system that underlies all iOS drawing — UIKit drawing is built on top of it — so it is low-level and consists of C functions. There are a lot of them! This chapter will familiarize you with the fundamentals; for complete information, you’ll want to study Apple’s Quartz 2D Programming Guide. With Core Graphics, you must specify a graphics context (a CGContextRef) to draw into, explicitly, in every function call. If you’ve been handed a context: argument, 410 | Chapter 15: Drawing then, hey presto, you have a graphics context, and it’s probably the graphics context you want to draw into. But in a UIGraphicsBeginImageContextWithOptions or drawRect: situation, you have no reference to a context; to use Core Graphics, you need to get such a reference. Since the context you want to draw into is the current graphics context, you call UIGraphicsGetCurrentContext to get the needed refer‐ ence. So we have two sets of tools and three ways in which a context might be supplied; that makes six ways of drawing, and in case you’re confused, I’ll now demonstrate all six of them. Without worrying just yet about the actual drawing commands, focus your at‐ tention on how the context is specified and on whether we’re using UIKit or Core Graphics. First, I’ll draw a blue circle by implementing a UIView subclass’s drawRect:, using UIKit to draw into the current context, which Cocoa has already prepared for me: - (void) drawRect: (CGRect) rect { UIBezierPath* p = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0,0,100,100)]; [[UIColor blueColor] setFill]; [p fill]; } Now I’ll do the same thing with Core Graphics; this will require that I first get a reference to the current context: - (void) drawRect: (CGRect) rect { CGContextRef con = UIGraphicsGetCurrentContext(); CGContextAddEllipseInRect(con, CGRectMake(0,0,100,100)); CGContextSetFillColorWithColor(con, [UIColor blueColor].CGColor); CGContextFillPath(con); } Next, I’ll implement a UIView subclass’s drawLayer:inContext:. In this case, we’re handed a reference to a context, but it isn’t the current context. So I have to make it the current context in order to use UIKit: - (void)drawLayer:(CALayer*)lay inContext:(CGContextRef)con { UIGraphicsPushContext(con); UIBezierPath* p = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0,0,100,100)]; [[UIColor blueColor] setFill]; [p fill]; UIGraphicsPopContext(); } To use Core Graphics in drawLayer:inContext:, I simply keep referring to the context I was handed: Graphics Contexts | 411 - (void)drawLayer:(CALayer*)lay inContext:(CGContextRef)con { CGContextAddEllipseInRect(con, CGRectMake(0,0,100,100)); CGContextSetFillColorWithColor(con, [UIColor blueColor].CGColor); CGContextFillPath(con); } Finally, for the sake of completeness, let’s make a UIImage of a blue circle. We can do this at any time (we don’t need to wait for some particular method to be called) and in any class (we don’t need to be in a UIView subclass). First, I’ll use UIKit: UIGraphicsBeginImageContextWithOptions(CGSizeMake(100,100), NO, 0); UIBezierPath* p = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0,0,100,100)]; [[UIColor blueColor] setFill]; [p fill]; UIImage* im = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); // im is the blue circle image, do something with it here ... Here’s the same thing using Core Graphics: UIGraphicsBeginImageContextWithOptions(CGSizeMake(100,100), NO, 0); CGContextRef con = UIGraphicsGetCurrentContext(); CGContextAddEllipseInRect(con, CGRectMake(0,0,100,100)); CGContextSetFillColorWithColor(con, [UIColor blueColor].CGColor); CGContextFillPath(con); UIImage* im = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); // im is the blue circle image, do something with it here ... You may be wondering about the arguments to UIGraphicsBeginImageContextWithOptions. The first argument is obviously the size of the image to be created. The second argument declares whether the image should be opaque; if I had passed YES instead of NO here, my image would have a black background, which I don’t want. The third argument specifies the image scale, corresponding to the UIImage scale property I discussed earlier; by passing 0, I’m telling the system to set the scale for me in accordance with the main screen resolution, so my image will look good on both single-resolution and double-resolution devices. You don’t have to use UIKit or Core Graphics exclusively; on the contrary, you can intermingle UIKit calls and Core Graphics calls to operate on the same graphics context. They merely represent two different ways of talking about the same graphics context. UIImage Drawing A UIImage provides methods for drawing itself into the current context. We now know how to obtain an image context and make it the current context, so we can experiment with these methods. Here, I’ll make a UIImage consisting of two pictures of Mars side by side: 412 | Chapter 15: Drawing Figure 15-6. Two images of Mars combined side by side UIImage* mars = [UIImage imageNamed:@"Mars.png"]; CGSize sz = [mars size]; UIGraphicsBeginImageContextWithOptions( CGSizeMake(sz.width*2, sz.height), NO, 0); [mars drawAtPoint:CGPointMake(0,0)]; [mars drawAtPoint:CGPointMake(sz.width,0)]; UIImage* im = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); The resulting UIImage im is suitable anywhere you would use a UIImage. For instance, you could hand it over to a visible UIImageView, thus causing the image to appear onscreen (Figure 15-6). Additional UIImage methods let you scale an image into a desired rectangle as you draw, and specify the compositing (blend) mode whereby the image should combine with whatever is already present. To illustrate, I’ll create an image showing Mars centered in another image of Mars that’s twice as large, using the Multiply blend mode (Figure 15-7): UIImage* mars = [UIImage imageNamed:@"Mars.png"]; CGSize sz = [mars size]; UIGraphicsBeginImageContextWithOptions( CGSizeMake(sz.width*2, sz.height*2), NO, 0); [mars drawInRect:CGRectMake(0,0,sz.width*2,sz.height*2)]; [mars drawInRect:CGRectMake(sz.width/2.0, sz.height/2.0, sz.width, sz.height) blendMode:kCGBlendModeMultiply alpha:1.0]; UIImage* im = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); There is no UIImage drawing method for specifying the source rectangle — that is, for specifying that you want to extract a smaller region of the original image. You can work around this by specifying a smaller graphics context and positioning the image drawing so that the desired region falls into it. For example, to obtain an image of the right half of Mars, you’d make a graphics context half the width of the mars image, and then draw mars shifted left, so that only its right half intersects the graphics context. There is no harm in doing this, and it’s a perfectly standard device; the left half of mars simply isn’t drawn (Figure 15-8): UIImage Drawing | 413 Figure 15-7. Two images of Mars in different sizes, composited Figure 15-8. Half the original image of Mars UIImage* mars = [UIImage imageNamed:@"Mars.png"]; CGSize sz = [mars size]; UIGraphicsBeginImageContextWithOptions( CGSizeMake(sz.width/2.0, sz.height), NO, 0); [mars drawAtPoint:CGPointMake(-sz.width/2.0, 0)]; UIImage* im = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); CGImage Drawing The Core Graphics version of UIImage is CGImage (actually a CGImageRef). They are easily converted to one another: a UIImage has a CGImage property that accesses its Quartz image data, and you can make a UIImage from a CGImage using imageWithCGImage: or initWithCGImage: (in real life, you are likely to use their more configurable siblings, imageWithCGImage:scale:orientation: and initWithCGImage:scale: orientation:). A CGImage lets you create a new image directly from a rectangular region of the original image, which you can’t do with UIImage. (A CGImage has other powers a UIImage doesn’t have; for example, you can apply an image mask to a CGImage.) I’ll demonstrate by splitting the image of Mars in half and drawing the two halves separately 414 | Chapter 15: Drawing Figure 15-9. Image of Mars split in half (Figure 15-9). Observe that we are now operating in the CFTypeRef world and must take care to manage memory manually; ARC won’t help us here (Chapter 12): UIImage* mars = [UIImage imageNamed:@"Mars.png"]; // extract each half as a CGImage CGSize sz = [mars size]; CGImageRef marsLeft = CGImageCreateWithImageInRect([mars CGImage], CGRectMake(0,0,sz.width/2.0,sz.height)); CGImageRef marsRight = CGImageCreateWithImageInRect([mars CGImage], CGRectMake(sz.width/2.0,0,sz.width/2.0,sz.height)); // draw each CGImage into an image context UIGraphicsBeginImageContextWithOptions( CGSizeMake(sz.width*1.5, sz.height), NO, 0); CGContextRef con = UIGraphicsGetCurrentContext(); CGContextDrawImage(con, CGRectMake(0,0,sz.width/2.0,sz.height), marsLeft); CGContextDrawImage(con, CGRectMake(sz.width,0,sz.width/2.0,sz.height), marsRight); UIImage* im = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); CGImageRelease(marsLeft); CGImageRelease(marsRight); But there’s a problem with that example: the drawing is upside-down! It isn’t rotated; it’s mirrored top to bottom, or, to use the technical term, flipped. This phenomenon can arise when you create a CGImage and then draw it with CGContextDrawImage, and is due to a mismatch in the native coordinate systems of the source and target contexts. There are various ways of compensating for this mismatch between the coordinate sys‐ tems. One is to draw the CGImage into an intermediate UIImage and extract another CGImage from that. Example 15-1 presents a utility function for doing this. Example 15-1. Utility for flipping an image drawing CGImageRef flip (CGImageRef im) { CGSize sz = CGSizeMake(CGImageGetWidth(im), CGImageGetHeight(im)); UIGraphicsBeginImageContextWithOptions(sz, NO, 0); CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, sz.width, sz.height), im); CGImage Drawing | 415 } CGImageRef result = [UIGraphicsGetImageFromCurrentImageContext() CGImage]; UIGraphicsEndImageContext(); return result; Armed with the utility function from Example 15-1, we can now draw the halves of Mars the right way up in the previous example: CGContextDrawImage(con, CGRectMake(0,0,sz.width/2.0,sz.height), flip(marsLeft)); CGContextDrawImage(con, CGRectMake(sz.width,0,sz.width/2.0,sz.height), flip(marsRight)); However, we’ve still got a problem: on a double-resolution device, if there is a highresolution (@2x) version of our image file, the drawing comes out all wrong. The reason is that we are loading our starting Mars image using imageNamed:, which automatically substitutes the high-resolution version of the image on the high-resolution device. The UIImage compensates for the doubled size of the image by setting its own scale prop‐ erty to match. But a CGImage doesn’t have a scale property, and knows nothing of the fact that the image dimensions are doubled! When you call a UIImage’s CGImage method, therefore, you can’t assume that the re‐ sulting CGImage is the same size as the original UIImage; a UIImage’s size property is the same for a single-resolution image and its double-resolution counterpart, because the scale tells it how to compensate, but the CGImage of a double-resolution UIImage is twice as large in both dimensions as the CGImage of the corresponding singleresolution image. So, in extracting a desired piece of the CGImage, we must either multiply all appropriate values by the scale or express ourselves in terms of the CGImage’s dimensions. In this case, as we are extracting the left and right halves of the image, the latter is obviously the simpler course. So here’s a version of our original code that draws correctly on either a single-resolution or a double-resolution device, and compensates for flipping: UIImage* mars = [UIImage imageNamed:@"Mars.png"]; CGSize sz = [mars size]; // Derive CGImage and use its dimensions to extract its halves CGImageRef marsCG = [mars CGImage]; CGSize szCG = CGSizeMake(CGImageGetWidth(marsCG), CGImageGetHeight(marsCG)); CGImageRef marsLeft = CGImageCreateWithImageInRect( marsCG, CGRectMake(0,0,szCG.width/2.0,szCG.height)); CGImageRef marsRight = CGImageCreateWithImageInRect( marsCG, CGRectMake(szCG.width/2.0,0,szCG.width/2.0,szCG.height)); UIGraphicsBeginImageContextWithOptions( CGSizeMake(sz.width*1.5, sz.height), NO, 0); // The rest is as before, calling flip() to compensate for flipping CGContextRef con = UIGraphicsGetCurrentContext(); 416 | Chapter 15: Drawing CGContextDrawImage(con, CGRectMake(0,0,sz.width/2.0,sz.height), flip(marsLeft)); CGContextDrawImage(con, CGRectMake(sz.width,0,sz.width/2.0,sz.height), flip(marsRight)); UIImage* im = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); CGImageRelease(marsLeft); CGImageRelease(marsRight); If this is starting to look rather clumsy and involved, don’t worry; I have up my sleeve another flipping solution that simplifies things considerably. Instead of calling our flip utility, you can wrap your CGImage in a UIImage before drawing. This has two big advantages: • The UIImage compensates for flipping automatically as it draws. • The UIImage can be formed in such a way as to compensate for scale: call imageWithCGImage:scale:orientation: as you form the UIImage from the CGImage. So here’s a self-contained approach that deals with both flipping and scale: UIImage* mars = [UIImage imageNamed:@"Mars.png"]; CGSize sz = [mars size]; // Derive CGImage and use its dimensions to extract its halves CGImageRef marsCG = [mars CGImage]; CGSize szCG = CGSizeMake(CGImageGetWidth(marsCG), CGImageGetHeight(marsCG)); CGImageRef marsLeft = CGImageCreateWithImageInRect( marsCG, CGRectMake(0,0,szCG.width/2.0,szCG.height)); CGImageRef marsRight = CGImageCreateWithImageInRect( marsCG, CGRectMake(szCG.width/2.0,0,szCG.width/2.0,szCG.height)); UIGraphicsBeginImageContextWithOptions( CGSizeMake(sz.width*1.5, sz.height), NO, 0); [[UIImage imageWithCGImage:marsLeft scale:[mars scale] orientation:UIImageOrientationUp] drawAtPoint:CGPointMake(0,0)]; [[UIImage imageWithCGImage:marsRight scale:[mars scale] orientation:UIImageOrientationUp] drawAtPoint:CGPointMake(sz.width,0)]; UIImage* im = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); CGImageRelease(marsLeft); CGImageRelease(marsRight); Yet another solution to flipping is to apply a transform to the graphics context before drawing the CGImage, effectively flipping the context’s internal coordinate system. This is elegant, but can be confusing if there are other transforms in play. I’ll talk more about graphics context transforms later in this chapter. CGImage Drawing | 417 Why Flipping Happens The ultimate source of accidental flipping is that Core Graphics comes from the Mac OS X world, where the coordinate system’s origin is located by default at the bottom left and the positive y-direction is upward, whereas on iOS the origin is located by default at the top left and the positive y-direction is downward. In most drawing situations, no problem arises, because the coordinate system of the graphics context is adjusted to compensate. Thus, the default coordinate system for drawing in a Core Graphics context on iOS has the origin at the top left, just as you expect. But creating and drawing a CGImage exposes the issue. CIFilter and CIImage The “CI” in CIFilter and CIImage stands for Core Image, a technology for transforming images through mathematical filters. Core Image started life on the desktop (Mac OS X), and migrated initially to iOS 5, bringing only a limited subset of the desktop filters, as iOS devices are not suitable for certain heavily intensive mathematical operations. In iOS 6, many more filters are provided; of about 140 filters available on the desktop, only about 40 are absent from iOS 6. To use Core Image, you’ll have to link your target to CoreImage.framework. A filter is a CIFilter. The available filters fall naturally into several categories: Patterns and gradients These filters create CIImages that can then be combined with other CIImages, such as a single color, a checkerboard, stripes, or a gradient. Compositing These filters combine one image with another, using compositing blend modes familiar from image processing programs such as Photoshop. Color These filters adjust or otherwise modify the colors of an image. Thus you can alter an image’s saturation, hue, brightness, contrast, gamma and white point, exposure, shadows and highlights, and so on. Geometric These filters perform basic geometric transformations on an image, such as scaling, rotation, and cropping. Transformation These filters distort, blur, or stylize an image. They are the most intensive filters, so relatively few of them are available on iOS. 418 | Chapter 15: Drawing Transition These filters provide a frame of a transition between one image and another; by asking for frames in sequence, you can animate the full transition. The basic use of a CIFilter is quite simple; it essentially works as if a filter were a kind of dictionary consisting of keys and values. You create the filter by supplying the string name of a filter; to learn what these names are, consult Apple’s Core Image Filter Ref‐ erence, or call the CIFilter class method filterNamesInCategories: with a nil argu‐ ment. Each filter has a small number of keys and values that determine its behavior; for each key that you’re interested in, you supply a key–value pair, either by calling setValue:forKey: or by supplying all the keys and values as you specify the filter name. In supplying values, a number must be wrapped up as an NSNumber, and there are a few supporting classes such as CIVector (like CGPoint and CGRect combined) and CIColor, whose use is easy to grasp. A CIFilter’s keys include any image or images on which the filter is to operate; such an image must be a CIImage. You can obtain a CIImage from a CGImage with initWithCGImage:; we already know how to obtain a CGImage from a UIImage. You can also obtain a CGImage as the output of a filter; thus filters can be chained together. As you build a chain of filters, nothing actually happens. The only calculation-intensive move comes at the very end, when you produce the result of the entire chain as a CGImage. You do this by creating a CIContext (by calling contextWithOptions:) and then calling createCGImage:fromRect:. The only mildly tricky thing here is that a CI‐ Image doesn’t have a frame or bounds; it has an extent. You will often use this as the second argument to createCGImage:fromRect:. The final output CGImage is ready for any purpose, such as for display in your app, for transformation into a UIImage, or for use in further drawing. To illustrate, I’ll start with an ordinary photo of myself (it’s true I’m wearing a motorcycle helmet, but it’s still ordinary) and create a circular vignette effect. We start by generating a clear color. Then we make a radial gradient. Finally, we treat the radial gradient as a mask for blending between the photo of me and the clear color: where the radial gradient is white (everything inside the gradient’s inner radius) we see just me, and where the radial gradient is black (everything outside the gradient’s outer radius) we see just the clear color, with a gradation in between, so that the image fades away in the circular band between the gradient’s radii. The result is the UIImage moi4; displaying it an an image view (Figure 15-10), we see behind it the image view’s background color — or, if the image view’s background is clear, whatever is behind the image view: CIFilter* col = [CIFilter filterWithName:@"CIConstantColorGenerator"]; CIColor* cicol = [[CIColor alloc] initWithColor:[UIColor clearColor]]; [col setValue:cicol forKey:@"inputColor"]; CIImage* colorimage = [col valueForKey: @"outputImage"]; CIFilter and CIImage | 419 Figure 15-10. A photo of me, vignetted CIFilter* grad = [CIFilter filterWithName:@"CIRadialGradient"]; CIVector* center = [CIVector vectorWithX:moi.size.width/2.0 Y:moi.size.height/2.0]; [grad setValue:center forKey:@"inputCenter"]; [grad setValue:@85 forKey:@"inputRadius0"]; [grad setValue:@100 forKey:@"inputRadius1"]; CIImage *gradimage = [grad valueForKey: @"outputImage"]; CIFilter* blend = [CIFilter filterWithName:@"CIBlendWithMask"]; [blend setValue:moi2 forKey:@"inputImage"]; [blend setValue:colorimage forKey:@"inputBackgroundImage"]; [blend setValue:gradimage forKey:@"inputMaskImage"]; CGImageRef moi3 = [[CIContext contextWithOptions:nil] createCGImage:blend.outputImage fromRect:moi2.extent]; moi4 = [UIImage imageWithCGImage:moi3]; CGImageRelease(moi3); In this example, we use the same image of me to generate a kaleidoscopic tile effect (Figure 15-11): CIFilter* tile = [CIFilter filterWithName:@"CIFourfoldRotatedTile"]; [tile setValue:moi2 forKey:@"inputImage"]; CIVector* center = [CIVector vectorWithX:moi.size.width/2.0-60 Y:moi.size.height/2.0-70]; [tile setValue:center forKey:@"inputCenter"]; [tile setValue:@50 forKey:@"inputWidth"]; CGImageRef moi3 = [[CIContext contextWithOptions:nil] createCGImage:tile.outputImage fromRect:moi2.extent]; moi4 = [UIImage imageWithCGImage:moi3]; CGImageRelease(moi3); 420 | Chapter 15: Drawing Figure 15-11. A photo of me, tiled It is also possible to draw a filter’s output directly into an OpenGL context, but OpenGL is outside the scope of this book. Core Image can also perform automatic face detection in an image. Drawing a UIView The most flexible way to draw a UIView is to draw it yourself. As I’ve already said, you don’t actually draw a UIView; you subclass UIView and endow the subclass with the ability to draw itself. When a UIView needs drawing, its drawRect: method is called. Overriding that method is your chance to draw. At the time that drawRect: is called, the current graphics context has already been set to the view’s own graphics context. You can use Core Graphics functions or UIKit convenience methods to draw into that context. Thus, everything I did earlier generating a UIImage and displaying it somehow in the interface could have been done instead by putting into my interface a UIView subclass that knows how to display itself as desired. You should never call drawRect: yourself! If a view needs updating and you want its drawRect: called, send the view the setNeedsDisplay message. This will cause drawRect: to be called at the next proper moment. Also, don’t override drawRect: unless you are as‐ sured that this is legal. For example, it is not legal to override drawRect: in a subclass of UIImageView; you cannot combine your draw‐ ing with that of the UIImageView. So, for example, let’s say we have a UIView subclass called MyView. How this class gets instantiated, and how the instance gets into our view hierarchy, isn’t important. One possibility would be to drag a UIView into a view in the nib and set its class to MyView Drawing a UIView | 421 in the identity inspector; another would be to create the MyView instance and put it into the interface in code. Let’s suppose that MyView’s job is to draw the two halves of Mars, one at each end of the view. We can readily adapt the earlier example of doing this. There is no need for an image context; we just draw directly into the current context, which is the view’s own graphics context: - (void)drawRect:(CGRect)rect { CGRect b = self.bounds; UIImage* mars = [UIImage imageNamed:@"Mars.png"]; CGSize sz = [mars size]; CGImageRef marsCG = [mars CGImage]; CGSize szCG = CGSizeMake(CGImageGetWidth(marsCG), CGImageGetHeight(marsCG)); CGImageRef marsLeft = CGImageCreateWithImageInRect( marsCG, CGRectMake(0,0,szCG.width/2.0,szCG.height)); CGImageRef marsRight = CGImageCreateWithImageInRect( marsCG, CGRectMake(szCG.width/2.0,0,szCG.width/2.0,szCG.height)); [[UIImage imageWithCGImage:marsLeft scale:[mars scale] orientation:UIImageOrientationUp] drawAtPoint:CGPointMake(0,0)]; [[UIImage imageWithCGImage:marsRight scale:[mars scale] orientation:UIImageOrientationUp] drawAtPoint:CGPointMake(b.size.width-sz.width/2.0,0)]; CGImageRelease(marsLeft); CGImageRelease(marsRight); } There is no need to call super, because the superclass here is UIView, whose drawRect: does nothing. The need to draw in real time, on demand, surprises some beginners, who worry that drawing may be a time-consuming operation. Where drawing is extensive and can be compartmentalized into sections, you may be able to gain some efficiency by paying attention to the rect parameter passed into drawRect:. It designates the region of the view’s bounds that needs refreshing. Normally, this is the view’s entire bounds; but if you called setNeedsDisplayInRect:, it will be the CGRect that you passed in as argu‐ ment. You could respond by drawing only what goes into those bounds; but even if you don’t, your drawing will be clipped to those bounds, so, while you may not spend less time drawing, the system will draw more efficiently. In general, however, you should not optimize prematurely. The code for a drawing operation may appear verbose and yet be extremely fast. Moreover, the iOS drawing system is efficient; it doesn’t call drawRect: unless it has to (or is told to, through a call to setNeedsDisplay), and once a view has drawn itself, the result is cached so that the 422 | Chapter 15: Drawing cached drawing can be reused instead of repeating the drawing operation from scratch. (Apple refers to this cached drawing as the view’s bitmap backing store.) You can readily satisfy yourself of this fact with some caveman debugging, logging in your drawRect: implementation; you may be amazed to discover that your code is called only once in the entire lifetime of the app! In fact, moving code to drawRect: is a common way to increase efficiency. This is because it is more efficient for the drawing engine to render directly onto the screen than for it to render offscreen and then copy those pixels onto the screen. When creating a custom UIView subclass instance in code, you may be surprised and annoyed to find that the view has a black background. This can be frustrating if what you expected and wanted was a transparent background; this is a source of considerable confusion among beginners. The black background arises when two things are true: • The view’s backgroundColor is nil. • The view’s opaque is YES. Unfortunately, when creating a UIView in code, both those things are true by default! So if you don’t want the black background, you must do something about one or the other of them (or both). For example, you might eliminate the black background by setting the view’s backgroundColor to [UIColor clearColor]. But then you should still set its opaque to NO, because the view isn’t opaque, and it’s up to you to tell the drawing system this. With a UIView created in the nib, on the other hand, the black background problem doesn’t arise. This is because such a UIView’s backgroundColor is not nil. The nib assigns it some actual background color, even if that color is [UIColor clearColor]. Of course, if a view fills its rectangle with opaque drawing or has an opaque background color, you can leave opaque set to YES and gain some drawing efficiency (see Chap‐ ter 14). Graphics Context Settings When you draw in a graphics context, the drawing obeys the context’s current settings. Thus, the procedure is always to configure the context’s settings first, and then draw. For example, to draw a red line followed by a blue line, you would first set the context’s line color to red, and then draw the first line; then you’d set the context’s line color to blue, and then draw the second line. To the eye, it appears that the redness and blueness are properties of the individual lines, but in fact, at the time you draw each line, line color is a feature of the entire graphics context. This is true regardless of whether you use UIKit methods or Core Graphics functions. Graphics Context Settings | 423 A graphics context thus has, at every moment, a state, which is the sum total of all its settings; the way a piece of drawing looks is the result of what the graphics context’s state was at the moment that piece of drawing was performed. To help you manipulate entire states, the graphics context provides a stack for holding states. Every time you call CGContextSaveGState, the context pushes the entire current state onto the stack; every time you call CGContextRestoreGState, the context retrieves the state from the top of the stack (the state that was most recently pushed) and sets itself to that state. Thus, a common pattern is: call CGContextSaveGState; manipulate the context’s set‐ tings, thus changing its state; draw; call CGContextRestoreGState to restore the state and the settings to what they were before you manipulated them. You do not have to do this before every manipulation of a context’s settings, however, because settings don’t necessarily conflict with one another or with past settings. You can set the context’s line color to red and then later to blue without any difficulty. But in certain situations you do want your manipulation of settings to be undoable, and I’ll point out several such situations later in this chapter. Many of the settings that constitute a graphics context’s state, and that determine the behavior and appearance of drawing performed at that moment, are similar to those of any drawing application. Here are some of them, along with some of the commands that determine them; I provide Core Graphics functions here, but keep in mind that UIKit commands are actually calling these same functions and manipulating the con‐ text’s state in the same ways: Line thickness and dash style CGContextSetLineWidth, CGContextSetLineDash Line end-cap style and join style CGContextSetLineCap, CGContextSetLineJoin, CGContextSetMiterLimit Line color or pattern CGContextSetRGBStrokeColor, CGContextSetGrayStrokeColor, CGContextSetStrokeColorWithColor, CGContextSetStrokePattern Fill color or pattern CGContextSetRGBFillColor, CGContextSetGrayFillColor, CGContextSetFillColorWithColor, CGContextSetFillPattern Shadow CGContextSetShadow, CGContextSetShadowWithColor Blend mode CGContextSetBlendMode (this determines how drawing that you do now will be composited with drawing already present) 424 | Chapter 15: Drawing Overall transparency CGContextSetAlpha (individual colors also have an alpha component) Text features CGContextSelectFont, CGContextSetFont, CGContextSetFontSize, CGContextSetTextDrawingMode, CGContextSetCharacterSpacing Whether anti-aliasing and font smoothing are in effect CGContextSetShouldAntialias, CGContextSetShouldSmoothFonts Additional settings include: Clipping area Drawing outside the clipping area is not physically drawn. Transform (or “CTM,” for “current transform matrix”) Changes how points that you specify in subsequent drawing commands are mapped onto the physical space of the canvas. Many (but not all) of these settings will be illustrated by examples later in this chapter. Paths and Drawing By issuing a series of instructions for moving an imaginary pen, you trace out a path. Such a path does not constitute drawing! First you provide a path; then you draw. Drawing can mean stroking the path or filling the path, or both. Again, this should be a familiar notion from certain drawing applications. A path is constructed by tracing it out from point to point. Think of the drawing system as holding a pen. Then you must first tell that pen where to position itself, setting the current point; after that, you issue a series of commands telling it how to trace out each subsequent piece of the path. Each additional piece of the path starts at the current point; its end becomes the new current point. Here are some path-drawing commands you’re likely to give: Position the current point CGContextMoveToPoint Trace a line CGContextAddLineToPoint, CGContextAddLines Trace a rectangle CGContextAddRect, CGContextAddRects Trace an ellipse or circle CGContextAddEllipseInRect Paths and Drawing | 425 Trace an arc CGContextAddArcToPoint, CGContextAddArc Trace a Bezier curve with one or two control points CGContextAddQuadCurveToPoint, CGContextAddCurveToPoint Close the current path CGContextClosePath. This appends a line from the last point of the path to the first point. There’s no need to do this if you’re about to fill the path, since it’s done for you. Stroke or fill the current path CGContextStrokePath, CGContextFillPath, CGContextEOFillPath, CGContextDrawPath. Stroking or filling the current path clears the path. Use CGContextDrawPath if you want both to fill and to stroke the path in a single command, because if you merely stroke it first with CGContextStrokePath, the path is cleared and you can no longer fill it. There are also a lot of convenience functions that create a path and stroke or fill it all in a single move: CGContextStrokeLineSegments, CGContextStrokeRect, CGContextStrokeRectWithWidth, CGContextFillRect, CGContextFillRects, CGContextStrokeEllipseInRect, CGContextFillEllipseInRect. A path can be compound, meaning that it consists of multiple independent pieces. For example, a single path might consist of two separate closed shapes: a rectangle and a circle. When you call CGContextMoveToPoint in the middle of constructing a path (that is, after tracing out a path and without clearing it by filling, stroking, or calling CGContextBeginPath), you pick up the imaginary pen and move it to a new location without tracing a segment, thus preparing to start an independent piece of the same path. If you’re worried, as you begin to trace out a path, that there might be an existing path and that your new path might be seen as a compound part of that existing path, you can call CGContextBeginPath to specify that this is a different path; many of Apple’s examples do this, but in practice I usually do not find it necessary. There is also a function for erasing an area: CGContextClearRect. This erases all existing drawing in a rectangle; combined with clipping, though, it can erase an area of any shape. The result can “punch a hole” through all existing drawing. The behavior of CGContextClearRect depends on whether the context is transparent or opaque. This is particularly obvious and intuitive when drawing into an image con‐ text. If the image context is transparent — the second argument to UIGraphicsBeginImageContextWithOptions is NO — CGContextClearRect erases to transparent; other‐ wise it erases to black. 426 | Chapter 15: Drawing Figure 15-12. The very strange behavior of CGContextClearRect When drawing directly into a view (as with drawRect: or drawLayer:inContext:), if the view’s background color is nil or a color with even a tiny bit of transparency, the result of CGContextClearRect will appear to be transparent, punching a hole right through the view including its background color; if the background color is completely opaque, the result of CGContextClearRect will be black. This is because the view’s back‐ ground color determines whether the view’s graphics context is transparent or opaque; thus, this is essentially the same behavior that I described in the preceding paragraph. Figure 15-12 illustrates; the blue square on the left has been partly cut away to black, while the blue square on the right has been partly cut away to transparency. Yet these are instances of the same UIView subclass, drawn with exactly the same code! The difference between the views is that the backgroundColor of the first view is set in the nib to solid red with an alpha of 1, while the backgroundColor of the second view is set in the nib to solid red with an alpha of 0.99. This difference is utterly imperceptible to the eye (not to mention that the red color never appears, as it is covered with a blue fill), but it completely changes the effect of CGContextClearRect. The UIView subclass’s drawRect: looks like this: CGContextRef con = UIGraphicsGetCurrentContext(); CGContextSetFillColorWithColor(con, [UIColor blueColor].CGColor); CGContextFillRect(con, rect); CGContextClearRect(con, CGRectMake(0,0,30,30)); To illustrate the typical use of path-drawing commands, I’ll generate the up-pointing arrow shown in Figure 15-13. This might not be the best way to create the arrow, and I’m deliberately avoiding use of the convenience functions, but it’s clear and shows a nice basic variety of typical commands: // obtain the current graphics context CGContextRef con = UIGraphicsGetCurrentContext(); // draw a black (by default) vertical line, the shaft of the arrow CGContextMoveToPoint(con, 100, 100); CGContextAddLineToPoint(con, 100, 19); CGContextSetLineWidth(con, 20); CGContextStrokePath(con); // draw a red triangle, the point of the arrow Paths and Drawing | 427 Figure 15-13. A simple path drawing CGContextSetFillColorWithColor(con, [[UIColor redColor] CGColor]); CGContextMoveToPoint(con, 80, 25); CGContextAddLineToPoint(con, 100, 0); CGContextAddLineToPoint(con, 120, 25); CGContextFillPath(con); // snip a triangle out of the shaft by drawing in Clear blend mode CGContextMoveToPoint(con, 90, 101); CGContextAddLineToPoint(con, 100, 90); CGContextAddLineToPoint(con, 110, 101); CGContextSetBlendMode(con, kCGBlendModeClear); CGContextFillPath(con); Properly speaking, we should probably surround our drawing code with calls to CGContextSaveGState and CGContextRestoreGState, just in case. It probably wouldn’t make any difference in this particular example, as the context does not persist between calls to drawRect:, but it can’t hurt. If a path needs to be reused or shared, you can encapsulate it as a CGPath, which is actually a CGPathRef. You can either create a new CGMutablePathRef and construct the path using various CGPath functions that parallel the graphics path-construction functions, or you can copy the graphics context’s current path using CGContextCopyPath. There are also a number of CGPath functions for creating a path based on simple geometry (CGPathCreateWithRect, CGPathCreateWithEllipseInRect) or based on an existing path (CGPathCreateCopyByStrokingPath, CGPathCreateCopyByDashingPath, CGPathCreateCopyByTransformingPath). A UIKit class, UIBezierPath, wraps CGPath. It provides methods for drawing certain path shapes, as well as for stroking, filling, and for accessing certain settings of the current graphics context state. Similarly, UIColor provides methods for setting the cur‐ rent graphics context’s stroke and fill colors. Thus we could rewrite our arrow-drawing routine like this: UIBezierPath* p = [UIBezierPath bezierPath]; [p moveToPoint:CGPointMake(100,100)]; [p addLineToPoint:CGPointMake(100, 19)]; [p setLineWidth:20]; [p stroke]; 428 | Chapter 15: Drawing [[UIColor redColor] set]; [p removeAllPoints]; [p moveToPoint:CGPointMake(80,25)]; [p addLineToPoint:CGPointMake(100, 0)]; [p addLineToPoint:CGPointMake(120, 25)]; [p fill]; [p [p [p [p [p removeAllPoints]; moveToPoint:CGPointMake(90,101)]; addLineToPoint:CGPointMake(100, 90)]; addLineToPoint:CGPointMake(110, 101)]; fillWithBlendMode:kCGBlendModeClear alpha:1.0]; There’s no savings of code in this particular case, but UIBezierPath still might be useful if you need object features, and it does offer one convenience method, bezierPathWithRoundedRect:cornerRadius:, that is particularly attractive; drawing a rectangle with rounded corners using only Core Graphics functions is rather tedious. Clipping Another use of a path is to mask out areas, protecting them from future drawing. This is called clipping. By default, a graphics context’s clipping region is the entire graphics context: you can draw anywhere within the context. The clipping area is a feature of the context as a whole, and any new clipping area is applied by intersecting it with the existing clipping area; so if you apply your own clip‐ ping region, the way to remove it from the graphics context later is to plan ahead and wrap things with calls to CGContextSaveGState and CGContextRestoreGState. To illustrate, I’ll rewrite the code that generated our original arrow (Figure 15-13) to use clipping instead of a blend mode to “punch out” the triangular notch in the tail of the arrow. This is a little tricky, because what we want to clip to is not the region inside the triangle but the region outside it. To express this, we’ll use a compound path con‐ sisting of more than one closed area — the triangle, and the drawing area as a whole (which we can obtain with CGContextGetClipBoundingBox). Both when filling a compound path and when using it to express a clipping region, the system follows one of two rules: Winding rule The fill or clipping area is denoted by an alternation in the direction (clockwise or counterclockwise) of the path demarcating each region. Even-odd rule (EO) The fill or clipping area is denoted by a simple count of the paths demarcating each region. Clipping | 429 How Big Is My Context? At first blush, it appears that there’s no way to learn a graphics context’s size. Typically, this doesn’t matter, because either you created the graphics context or it’s the graphics context of some object whose size you know, such as a UIView. But in fact, because the default clipping region of a graphics context is the entire context, you can use CGContextGetClipBoundingBox to learn the context’s “bounds” (before changing the clipping re‐ gion, of course). Our situation is extremely simple, so it’s easier to use the even-odd rule. So we set up the clipping area using CGContextEOClip and then draw the arrow: // obtain the current graphics context CGContextRef con = UIGraphicsGetCurrentContext(); // punch triangular hole in context clipping region CGContextMoveToPoint(con, 90, 100); CGContextAddLineToPoint(con, 100, 90); CGContextAddLineToPoint(con, 110, 100); CGContextClosePath(con); CGContextAddRect(con, CGContextGetClipBoundingBox(con)); CGContextEOClip(con); // draw the vertical line CGContextMoveToPoint(con, 100, 100); CGContextAddLineToPoint(con, 100, 19); CGContextSetLineWidth(con, 20); CGContextStrokePath(con); // draw the red triangle, the point of the arrow CGContextSetFillColorWithColor(con, [[UIColor redColor] CGColor]); CGContextMoveToPoint(con, 80, 25); CGContextAddLineToPoint(con, 100, 0); CGContextAddLineToPoint(con, 120, 25); CGContextFillPath(con); Gradients Gradients can range from the simple to the complex. A simple gradient (which is all I’ll describe here) is determined by a color at one endpoint along with a color at the other endpoint, plus (optionally) colors at intermediate points; the gradient is then painted either linearly between two points in the context or radially between two circles in the context. You can’t use a gradient as a path’s fill color, but you can restrict a gradient to a path’s shape by clipping, which amounts to the same thing. 430 | Chapter 15: Drawing To illustrate, I’ll redraw our arrow, using a linear gradient as the “shaft” of the arrow (Figure 15-14): // obtain the current graphics context CGContextRef con = UIGraphicsGetCurrentContext(); CGContextSaveGState(con); // punch triangular hole in context clipping region CGContextMoveToPoint(con, 90, 100); CGContextAddLineToPoint(con, 100, 90); CGContextAddLineToPoint(con, 110, 100); CGContextClosePath(con); CGContextAddRect(con, CGContextGetClipBoundingBox(con)); CGContextEOClip(con); // draw the vertical line, add its shape to the clipping region CGContextMoveToPoint(con, 100, 100); CGContextAddLineToPoint(con, 100, 19); CGContextSetLineWidth(con, 20); CGContextReplacePathWithStrokedPath(con); CGContextClip(con); // draw the gradient CGFloat locs[3] = { 0.0, 0.5, 1.0 }; CGFloat colors[12] = { 0.3,0.3,0.3,0.8, // starting color, transparent gray 0.0,0.0,0.0,1.0, // intermediate color, black 0.3,0.3,0.3,0.8 // ending color, transparent gray }; CGColorSpaceRef sp = CGColorSpaceCreateDeviceGray(); CGGradientRef grad = CGGradientCreateWithColorComponents (sp, colors, locs, 3); CGContextDrawLinearGradient ( con, grad, CGPointMake(89,0), CGPointMake(111,0), 0); CGColorSpaceRelease(sp); CGGradientRelease(grad); CGContextRestoreGState(con); // done clipping // draw the red triangle, the point of the arrow CGContextSetFillColorWithColor(con, [[UIColor redColor] CGColor]); CGContextMoveToPoint(con, 80, 25); CGContextAddLineToPoint(con, 100, 0); CGContextAddLineToPoint(con, 120, 25); CGContextFillPath(con); The call to CGContextReplacePathWithStrokedPath pretends to stroke the current path, using the current line width and other line-related context state settings, but then creates a new path representing the outside of that stroked path. Thus, instead of a thick line we have a rectangular region that we can use as the clip region. Gradients | 431 Figure 15-14. Drawing with a gradient Figure 15-15. A patterned fill We then create the gradient and paint it. The procedure is verbose but simple; everything is boilerplate. We describe the gradient as a set of locations on the continuum between one endpoint (0.0) and the other endpoint (1.0), along with the colors corresponding to each location; in this case, I want the gradient to be lighter at the edges and darker in the middle, so I use three locations, with the dark one at 0.5. We must also supply a color space in order to create the gradient. Finally, we create the gradient, paint it into place, and release the color space and the gradient. Colors and Patterns A color is a CGColor (actually a CGColorRef). CGColor is not difficult to work with, and is bridged to UIColor through UIColor’s colorWithCGColor: and CGColor meth‐ ods. A pattern, on the other hand, is a CGPattern (actually a CGPatternRef). You can create a pattern and stroke or fill with it. The process is rather elaborate. As an extremely simple example, I’ll replace the red triangular arrowhead with a red-and-blue striped triangle (Figure 15-15). To do so, remove this line: CGContextSetFillColorWithColor(con, [[UIColor redColor] CGColor]); In its place, put the following: CGColorSpaceRef sp2 = CGColorSpaceCreatePattern(nil); CGContextSetFillColorSpace (con, sp2); CGColorSpaceRelease (sp2); CGPatternCallbacks callback = { 0, drawStripes, nil }; 432 | Chapter 15: Drawing CGAffineTransform tr = CGAffineTransformIdentity; CGPatternRef patt = CGPatternCreate(nil, CGRectMake(0,0,4,4), tr, 4, 4, kCGPatternTilingConstantSpacingMinimalDistortion, true, &callback); CGFloat alph = 1.0; CGContextSetFillPattern(con, patt, &alph); CGPatternRelease(patt); That code is verbose, but it is almost entirely boilerplate. To understand it, it almost helps to read it backward. What we’re leading up to is the call to CGContextSetFillPattern; instead of setting a fill color, we’re setting a fill pattern, to be used the next time we fill a path (in this case, the triangular arrowhead). The third parameter to CGContextSetFillPattern is a pointer to a CGFloat, so we have to set up the CGFloat itself beforehand. The second parameter to CGContextSetFillPattern is a CGPattern‐ Ref, so we have to create that CGPatternRef beforehand (and release it afterward). So now let’s talk about the call to CGPatternCreate. A pattern is a drawing in a rectan‐ gular “cell”; we have to state both the size of the cell (the second argument) and the spacing between origin points of cells (the fourth and fifth arguments). In this case, the cell is 4×4, and every cell exactly touches its neighbors both horizontally and vertically. We have to supply a transform to be applied to the cell (the third argument); in this case, we’re not doing anything with this transform, so we supply the identity transform. We supply a tiling rule (the sixth argument). We have to state whether this is a color pattern or a stencil pattern; it’s a color pattern, so the seventh argument is true. And we have to supply a pointer to a callback function that actually draws the pattern into its cell (the eighth argument). Except that that’s not what we have to supply as the eighth argument. To make matters more complicated, what we actually have to supply here is a pointer to a CGPattern‐ Callbacks struct. This struct consists of the number 0 and pointers to two functions, one called to draw the pattern into its cell, the other called when the pattern is released. We’re not specifying the second function, however; it is for memory management, and we don’t need it in this simple example. We have almost worked our way backward to the start of the code. It turns out that before you can call CGContextSetFillPattern with a colored pattern, you have to set the context’s fill color space to a pattern color space. If you neglect to do this, you’ll get an error when you call CGContextSetFillPattern. So we create the color space, set it as the context’s fill color space, and release it. Colors and Patterns | 433 But we are still not finished, because I haven’t shown you the function that actually draws the pattern cell! This is the function whose address is taken as drawStripes in our code. Here it is: void drawStripes (void *info, CGContextRef con) { // assume 4 x 4 cell CGContextSetFillColorWithColor(con, [[UIColor redColor] CGColor]); CGContextFillRect(con, CGRectMake(0,0,4,4)); CGContextSetFillColorWithColor(con, [[UIColor blueColor] CGColor]); CGContextFillRect(con, CGRectMake(0,0,4,2)); } As you can see, the actual pattern-drawing code is very simple. The only tricky issue is that the call to CGPatternCreate must be in agreement with the pattern-drawing func‐ tion as to the size of a cell, or the pattern won’t come out the way you expect. We know in this case that the cell is 4×4. So we fill it with red, and then fill its lower half with blue. When these cells are tiled touching each other horizontally and vertically, we get the stripes that you see in Figure 15-15. Note, finally, that the code as presented has left the graphics context in an undesirable state, with its fill color space set to a pattern color space. This would cause trouble if we were later to try to set the fill color to a normal color. The solution, as usual, is to wrap the code in calls to CGContextSaveGState and CGContextRestoreGState. You may have observed in Figure 15-15 that the stripes do not fit neatly inside the triangle of the arrow-head: the bottommost stripe is something like half a blue stripe. This is because a pattern is positioned not with respect to the shape you are filling (or stroking), but with respect to the graphics context as a whole. We could shift the pattern position by calling CGContextSetPatternPhase before drawing. Graphics Context Transforms Just as a UIView can have a transform, so can a graphics context. However, applying a transform to a graphics context has no effect on the drawing that’s already in it; it affects only the drawing that takes place after it is applied, altering the way the coordinates you provide are mapped onto the graphics context’s area. A graphics context’s transform is called its CTM, for “current transformation matrix.” It is quite usual to take full advantage of a graphics context’s CTM to save yourself from performing even simple calculations. You can multiply the current transform by any CGAffineTransform using CGContextConcatCTM; there are also convenience functions for applying a translate, scale, or rotate transform to the current transform. The base transform for a graphics context is already set for you when you obtain the context; this is how the system is able to map context drawing coordinates onto screen coordinates. Whatever transforms you apply are applied to the current transform, so 434 | Chapter 15: Drawing the base transform remains in effect and drawing continues to work. You can return to the base transform after applying your own transforms by wrapping your code in calls to CGContextSaveGState and CGContextRestoreGState. For example, we have hitherto been drawing our upward-pointing arrow with code that knows how to place that arrow at only one location: the top left of its rectangle is hardcoded at {80,0}. This is silly. It makes the code hard to understand, as well as inflexible and difficult to reuse. Surely the sensible thing would be to draw the arrow at {0,0}, by subtracting 80 from all the x-values in our existing code. Now it is easy to draw the arrow at any position, simply by applying a translate transform beforehand, mapping {0,0} to the desired top-left corner of the arrow. So, to draw it at {80,0}, we would say: CGContextTranslateCTM(con, 80, 0); // now draw the arrow at (0,0) A rotate transform is particularly useful, allowing you to draw in a rotated orientation without any nasty trigonometry. However, it’s a bit tricky because the point around which the rotation takes place is the origin. This is rarely what you want, so you have to apply a translate transform first, to map the origin to the point around which you really want to rotate. But then, after rotating, in order to figure out where to draw you will probably have to reverse your translate transform. To illustrate, here’s code to draw our arrow repeatedly at several angles, pivoting around the end of its tail (Figure 15-16). First, we’ll encapsulate the drawing of the arrow as a UIImage. Then we simply draw that UIImage repeatedly: UIGraphicsBeginImageContextWithOptions(CGSizeMake(40,100), NO, 0.0); CGContextRef con = UIGraphicsGetCurrentContext(); // draw the arrow into the image context // draw it at (0,0)! adjust all x-values by subtracting 80 // ... actual code omitted ... UIImage* im = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); con = UIGraphicsGetCurrentContext(); [im drawAtPoint:CGPointMake(0,0)]; for (int i=0; i<3; i++) { CGContextTranslateCTM(con, 20, 100); CGContextRotateCTM(con, 30 * M_PI/180.0); CGContextTranslateCTM(con, -20, -100); [im drawAtPoint:CGPointMake(0,0)]; } A transform is also one more solution for the “flip” problem we encountered earlier with CGContextDrawImage. Instead of reversing the drawing, we can reverse the context into which we draw it. Essentially, we apply a “flip” transform to the context’s coordinate Graphics Context Transforms | 435 Figure 15-16. Drawing rotated with a CTM system. You move the context’s top downward, and then reverse the direction of the ycoordinate by applying a scale transform whose y-multiplier is -1: CGContextTranslateCTM(con, 0, theHeight); CGContextScaleCTM(con, 1.0, -1.0); How far down you move the context’s top depends on how you intend to draw the image. So, for example, we could draw the two halves of Mars (from the example earlier in this chapter) without flipping, like this: CGContextTranslateCTM(con, 0, sz.height); // sz is [mars size] CGContextScaleCTM(con, 1.0, -1.0); CGContextDrawImage(con, CGRectMake(0,0,sz.width/2.0,sz.height), marsLeft); CGContextDrawImage(con, CGRectMake(b.size.width-sz.width/2.0, 0, sz.width/2.0, sz.height), marsRight); Shadows To add a shadow to a drawing, give the context a shadow value before drawing. The shadow position is expressed as a CGSize, where the positive direction for both values indicates down and to the right. The blur value is an open-ended positive number; Apple doesn’t explain how the scale works, but experimentation shows that 12 is nice and blurry, 99 is so blurry as to be shapeless, and higher values become problematic. Figure 15-17 shows the result of the same code that generated Figure 15-16, except that before we start drawing the arrow repeatedly, we give the context a shadow: con = UIGraphicsGetCurrentContext(); CGContextSetShadow(con, CGSizeMake(7, 7), 12); [im drawAtPoint:CGPointMake(0,0)]; // ... and so on However, there’s a subtle cosmetic problem with this approach. It may not be evident from Figure 15-17, but we are adding a shadow each time we draw. Thus the arrows are able to cast shadows on one another. What we want, however, is for all the arrows to cast a single shadow collectively. The way to achieve this is with a transparency layer; 436 | Chapter 15: Drawing Figure 15-17. Drawing with a shadow this is basically a subcontext that accumulates all drawing and then adds the shadow. Our code for drawing the shadowed arrows would thus look like this: CGContextSetShadow(con, CGSizeMake(7, 7), 12); CGContextBeginTransparencyLayer(con, nil); [im drawAtPoint:CGPointMake(0,0)]; for (int i=0; i<3; i++) { CGContextTranslateCTM(con, 20, 100); CGContextRotateCTM(con, 30 * M_PI/180.0); CGContextTranslateCTM(con, -20, -100); [im drawAtPoint:CGPointMake(0,0)]; } CGContextEndTransparencyLayer(con); Points and Pixels A point is a dimensionless location described by an x-coordinate and a y-coordinate. When you draw in a graphics context, you specify the points at which to draw, and this works regardless of the device’s resolution, because Core Graphics maps your drawing nicely onto the physical output (using the base CTM, along with any anti-aliasing and smoothing). Therefore, throughout this chapter I’ve concerned myself with graphics context points, disregarding their relationship to screen pixels. However, pixels do exist. A pixel is a physical, integral, dimensioned unit of display in the real world. Whole-numbered points effectively lie between pixels, and this can mat‐ ter if you’re fussy, especially on a single-resolution device. For example, if a vertical path with whole-number coordinates is stroked with a line width of 1, half the line falls on each side of the path, and the drawn line on the screen of a single-resolution device will seem to be 2 pixels wide (because the device can’t illuminate half a pixel). You will sometimes encounter advice suggesting that if this effect is objectionable, you should try shifting the line’s position by 0.5, to center it in its pixels. This advice may appear to work, but it makes some simple-minded assumptions. A more sophisticated approach is to obtain the UIView’s contentScaleFactor property. This value will be either 1.0 or 2.0, so you can divide by it to convert from pixels to points. Consider also that the most accurate way to draw a vertical or horizontal line is not to stroke a path Points and Pixels | 437 Figure 15-18. Automatic stretching of content but to fill a rectangle. So this UIView subclass code will draw a perfect 1-pixel-wide vertical line on any device: CGContextFillRect(con, CGRectMake(100,0,1.0/self.contentScaleFactor,100)); Content Mode A view that draws something within itself, as opposed to merely having a background color and subviews (as in the previous chapter), has content. This means that its contentMode property becomes important whenever the view is resized. As I mentioned earlier, the drawing system will avoid asking a view to redraw itself from scratch if possible; instead, it will use the cached result of the previous drawing operation (the bitmap backing store). So, if the view is resized, the system may simply stretch or shrink or reposition the cached drawing, if your contentMode setting instructs it to do so. It’s a little tricky to illustrate this point, because I have to arrange for the view to be resized without also causing it to be redrawn (that is, without triggering a call to drawRect:). Here’s how I’ll do that. As the app starts up, I’ll create an instance of a UIView subclass that knows how to draw our arrow. Then I’ll use delayed performance to resize the instance after the window has shown and the interface has been initially displayed: void (^resize) (void) = ^{ CGRect f = mv.bounds; // mv is the MyView instance f.size.height *= 2; mv.bounds = f; }; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC); dispatch_after(popTime, dispatch_get_main_queue(), resize); We double the height of the view without causing drawRect: to be called. The result is that the view’s drawing appears at double its correct height. For example, if our view’s drawRect: code is the same as the code that generated Figure 15-14, we get Figure 15-18. 438 | Chapter 15: Drawing This, however, is almost certainly not what we want. Sooner or later drawRect: will be called, and the drawing will be refreshed in accordance with our code. Our code doesn’t say to draw the arrow at a height that is relative to the height of the view’s bounds; it draws the arrow at a fixed height. Thus, not only has the arrow stretched, but at some future time, it will snap back to its original size. The moral is that our view’s contentMode property needs to be in agreement with how the view draws itself. For example, our drawRect: code dictates the size and position of the arrow relative to the view’s bounds origin, its top left. So we could set its contentMode to UIViewContentModeTopLeft. Alternatively, and more likely, we could set it to UIViewContentModeRedraw; this will cause automatic scaling and repositioning of the cached content to be turned off, and instead the view’s setNeedsDisplay method will be called, ultimately triggering drawRect: to redraw the content. On the other hand, if a view might be resized only momentarily — say, as part of an animation — then stretching behavior might be exactly what you want. Suppose we’re going to animate the view by making it get a little larger for a moment and then returning it to its original size, perhaps as a way of attracting the user’s attention. Then presumably we do want the view’s content to stretch and shrink as the view stretches and shrinks; that’s the whole point of the animation. This is precisely what the default contentMode value, UIViewContentModeScaleToFill, does for us. And remember, it does it efficiently; what’s being stretched and shrunk is just a cached image of our view’s content. Content Mode | 439 CHAPTER 16 Layers The tale told in Chapter 14 and Chapter 15 of how a UIView works and how it draws itself is only half the story. A UIView has a partner called its layer, a CALayer. A UIView does not actually draw itself onto the screen; it draws itself into its layer, and it is the layer that is portrayed on the screen. As I’ve already mentioned, a view is not redrawn frequently; instead, its drawing is cached, and the cached version of the drawing (the bitmap backing store) is used where possible. The cached version is, in fact, the layer. What I spoke of in Chapter 15 as the view’s graphics context is actually the layer’s graphics context. This might seem like a mere implementation detail, but layers are important and in‐ teresting. To understand layers is to understand views more deeply; layers extend the power of views. In particular: Layers have properties that affect drawing. Layers have drawing-related properties beyond those of a UIView. Because a layer is the recipient and presenter of a view’s drawing, you can modify how a view is drawn on the screen by accessing the layer’s properties. In other words, by reaching down to the level of its layer, you can make a view do things you can’t do through UIView methods alone. Layers can be combined within a single view. A UIView’s partner layer can contain additional layers. Since the purpose of layers is to draw, portraying visible material on the screen, this allows a UIView’s drawing to be composited of multiple distinct pieces. This can make drawing easier, with the constituents of a drawing being treated as objects. Layers are the basis of animation. Animation allows you to add clarity, emphasis, and just plain coolness to your interface. Layers are made to be animated (the “CA” in “CALayer” stands for “Core 441 Figure 16-1. A compass, composed of layers Animation”). Animation is the subject of Chapter 17; understanding layers is a prerequisite for reading that chapter. For example, suppose we want to add a compass indicator to our app’s interface. Figure 16-1 portrays a simple version of such a compass. It takes advantage of the arrow that we figured out how to draw in Chapter 15; the arrow is drawn into a layer of its own. The other parts of the compass are layers too: the circle is a layer, and each of the cardinal point letters is a layer. The drawing is thus easy to composite in code (and later in this chapter, that’s exactly what we’ll do); even more intriguing, the pieces can be repositioned and animated separately, so it’s easy to rotate the arrow without moving the circle (and in Chapter 17, that’s exactly what we’ll do). The documentation discusses layers chiefly in connection with animation (in particular, in the Core Animation Programming Guide). This categorization gives the impression that layers are of interest only if you intend to animate. That’s misleading. Layers are the basis of animation, but they are also the basis of view drawing, and are useful and important even if you don’t use them for animation. CALayer is not part of UIKit. It’s part of the Quartz Core framework, which is not linked by default into the project template. If your app contains code that refers to CALayer or related classes, you must link your target to QuartzCore.framework, and you must im‐ port <QuartzCore/QuartzCore.h> into any file containing such code. View and Layer A UIView instance has an accompanying CALayer instance, accessible as the view’s layer property. This layer has a special status: it is partnered with this view to embody all of the view’s drawing. The layer has no corresponding view property, but the view is the layer’s delegate. The documentation sometimes speaks of this layer as the view’s “underlying layer.” 442 | Chapter 16: Layers By default, when a UIView is instantiated, its layer is an instance of CALayer. But if you subclass UIView and you want your subclass’s underlying layer to be an instance of a CALayer subclass (built-in or your own), implement the UIView subclass’s layerClass class method. That, for example, is how the compass in Figure 16-1 is created. We have a UIView subclass, CompassView, and a CALayer subclass, CompassLayer. CompassView con‐ tains these lines: + (Class) layerClass { return [CompassLayer class]; } Thus, when CompassView is instantiated, its underlying layer is a CompassLayer. In this example, there is no drawing in CompassView; its job is to give CompassLayer a place in the visible interface, because a layer cannot appear without a view. Because every view has an underlying layer, there is a tight integration between the two. The layer portrays all the view’s drawing; if the view draws, it does so by contributing to the layer’s drawing. The view is the layer’s delegate. And the view’s properties are often merely a convenience for accessing the layer’s properties. For example, when you set the view’s backgroundColor, you are really setting the layer’s backgroundColor, and if you set the layer’s backgroundColor directly, the view’s backgroundColor is set to match. Similarly, the view’s frame is really the layer’s frame and vice versa. A CALayer’s delegate property is settable, but you must never set the delegate property of a UIView’s underlying layer. To do so would be to break the integration between them, thereby causing drawing to stop working correctly. A UIView must be the delegate of its underlying layer; moreover, it must not be the delegate of any other layer. Don’t do anything to mess this up. The view draws into its layer, and the layer caches that drawing; the layer can then be manipulated, changing the view’s appearance, without necessarily asking the view to redraw itself. This is a source of great efficiency in the drawing system. It also explains such phenomena as the content stretching that we encountered in the last section of Chapter 15: when the view’s bounds size changes, the drawing system, by default, simply stretches or repositions the cached layer image, until such time as the view is told to generate a new drawing of itself (drawRect:) to replace the layer’s content. View and Layer | 443 Figure 16-2. A hierarchy of views and the hierarchy of layers underlying it Mac OS X Programmer Alert On Mac OS X, NSView existed long before CALayer was introduced, so today a view might have no layer, or, if it does have a layer, it might relate to it in various ways. You may be accustomed to terms like layer-backed view or layer-hosting view. On iOS, layers were incor‐ porated from the outset: every UIView has an underlying layer and relates to it in the same way. Layers and Sublayers A layer can have sublayers, and a layer has at most one superlayer. Thus there is a tree of layers. This is similar and parallel to the tree of views (Chapter 14). In fact, so tight is the integration between a view and its underlying layer that these hierarchies are effectively the same hierarchy. Given a view and its underlying layer, that layer’s super‐ layer is the view’s superview’s underlying layer, and that layer has as sublayers all the underlying layers of all the view’s subviews. Indeed, because the layers are how the views actually get drawn, one might say that the view hierarchy really is a layer hierarchy (Figure 16-2). At the same time, the layer hierarchy can go beyond the view hierarchy. A view has exactly one underlying layer, but a layer can have sublayers that are not the underlying layers of any view. So the hierarchy of layers that underlie views exactly matches the hierarchy of views (Figure 16-2), but the total layer tree may be a superset of that hier‐ archy. In Figure 16-3, we see the same view-and-layer hierarchy as in Figure 16-2, but two of the layers have additional sublayers that are theirs alone (that is, sublayers that are not any view’s underlying layers). 444 | Chapter 16: Layers Figure 16-3. Layers that have sublayers of their own From a visual standpoint, there may be nothing to distinguish a hierarchy of views from a hierarchy of layers. For example, in Chapter 14 we drew three overlapping rectangles using a hierarchy of views (Figure 14-1). This code gives exactly the same visible display by manipulating layers: UIView* v = self.window.rootViewController.view; CALayer* lay1 = [CALayer new]; lay1.frame = CGRectMake(113, 111, 132, 194); lay1.backgroundColor = [[UIColor colorWithRed:1 green:.4 blue:1 alpha:1] CGColor]; [v.layer addSublayer:lay1]; CALayer* lay2 = [CALayer new]; lay2.backgroundColor = [[UIColor colorWithRed:.5 green:1 blue:0 alpha:1] CGColor]; lay2.frame = CGRectMake(41, 56, 132, 194); [lay1 addSublayer:lay2]; CALayer* lay3 = [CALayer new]; lay3.backgroundColor = [[UIColor colorWithRed:1 green:0 blue:0 alpha:1] CGColor]; lay3.frame = CGRectMake(43, 197, 160, 230); [v.layer addSublayer:lay3]; There are, indeed, situations in which it is not clear whether a piece of interface should be constructed as a view hierarchy or a layer hierarchy. Several of my apps have an interface that is a rectangular grid of objects of the same type; in some cases, I implement these as layers, in some cases I implement them as views, and sometimes it isn’t clear to me that my choice is much more than arbitrary. A layer on its own is more lightweight than a view; on the other hand, a view is a UIResponder, so it can respond to touches, and layers lack any form of automatic layout. Layers and Sublayers | 445 Manipulating the Layer Hierarchy Layers come with a full set of methods for reading and manipulating the layer hierarchy, parallel to the methods for reading and manipulating the view hierarchy. A layer has a superlayer property and a sublayers property; there are methods addSublayer:, insertSublayer:atIndex:, insertSublayer:below:, insertSublayer:above:, replaceSublayer:with:, and removeFromSuperlayer. Unlike a view’s subviews property, a layer’s sublayers property is writable; thus, you can give a layer multiple sublayers in a single move, by assigning to its sublayers property. To remove all of a layer’s sublayers, set its sublayers property to nil. Although a layer’s sublayers have an order, reflected in the sublayers order and regu‐ lated with the methods I’ve just mentioned, this is not necessarily the same as their backto-front drawing order. By default, it is, but a layer also has a zPosition property, a CGFloat, and this also determines drawing order. The rule is that all sublayers with the same zPosition are drawn in the order they are listed among their sublayers siblings, but lower zPosition siblings are drawn before higher zPosition siblings. (The default zPosition is 0.) Sometimes, the zPosition property is a more convenient way of dictating drawing order than sibling order is. For example, if layers represent playing cards laid out in a solitaire game, it will likely be a lot easier and more flexible to determine how the cards overlap by setting their zPosition than by rearranging their sibling order. Methods are also provided for converting between the coordinate systems of layers within the same layer hierarchy: convertPoint:fromLayer:, convertPoint:toLayer:, convertRect:fromLayer:, and convertRect:toLayer:. Positioning a Sublayer Layer coordinate systems and positioning are similar to those of views. A layer’s own internal coordin">
/
Download
Just a friendly reminder. You can view the document right here. But most importantly, our AI has already read it. It can explain complex things in simple terms, answer your questions in any language, and help you quickly navigate even the longest or most compilcated documents.
Advertisement
Key features
Objective-C fundamentals
Cocoa Touch framework explanation
Interface creation with widgets
Cocoa events
Memory Management techniques
Touch handling
Frequently asked questions
Cocoa Touch is a programming framework adapted from Cocoa for touch-based iOS devices.
Objective-C is the programming language used to develop iOS applications within the Cocoa Touch framework.
UIViewController helps programmer to make entire blocks of interface come and go and supplant one another in a controlled, hierarchical manner.