iOS8的Swift编程基础


MOBILE DEVELOPMENT/IOS iOS 8 Programming Fundamentals with Swift ISBN: 978-1-491-90890-7 US $49.99 CAN $57.99 “ Neuburg is my favorite programming book writer, period.”—John Gruber Daring Fireball Matt Neuburg has a PhD in Classics and has taught at many colleges and universities. He has served as editor of MacTech magazine and as contributing editor for TidBITS. He has written many OS X and iOS applications. Previous books include Programming iOS 7, REALbasic: The Definitive Guide, and AppleScript: The Definitive Guide. Twitter: @oreillymedia facebook.com/oreilly Move into iOS development by getting a firm grasp of its fundamentals, including the Xcode IDE, the Cocoa Touch framework, and Swift—Apple's new programming language. With this thoroughly updated guide, you'll learn Swift’s object-oriented concepts, understand how to use Apple's development tools, and discover how Cocoa provides the underlying functionality iOS apps need to have. ■■ Explore Swift’s object-oriented concepts: variables and functions, scopes and namespaces, object types and instances ■■ Become familiar with built-in Swift types such as numbers, strings, ranges, tuples, Optionals, arrays, and dictionaries ■■ Learn how to declare, instantiate, and customize Swift object types—enums, structs, and classes ■■ Discover powerful Swift features such as protocols and generics ■■ Tour the lifecycle of an Xcode project from inception to App Store ■■ Create app interfaces with nibs and the nib editor, Interface Builder ■■ Understand Cocoa’s event-driven model and its major design patterns and features ■■ Find out how Swift communicates with Cocoa’s C and Objective-C APIs Matt Neuburg Programming iOS 8 DIVE DEEP INTO VIEWS, VIEW CONTROLLERS, AND FRAMEWORKS Covers Swift, iOS 8.1, Xcode 6.1 Once you master the fundamentals, you'll be ready to tackle the details of iOS app development with author Matt Neuburg's companion guide, Programming iOS 8. Programming iOS 8 978-1-491-90873-0 iOS 8 Programming Fundamentals with Swift Neuburg Matt Neuburg iOS 8 Programming Fundamentals with Swift SWIFT, XCODE, AND COCOA BASICS Covers iOS 8.3, Xcode 6.3 & Swift 1.2 MOBILE DEVELOPMENT/IOS iOS 8 Programming Fundamentals with Swift ISBN: 978-1-491-90890-7 US $49.99 CAN $57.99 “ Neuburg is my favorite programming book writer, period.”—John Gruber Daring Fireball Matt Neuburg has a PhD in Classics and has taught at many colleges and universities. He has served as editor of MacTech magazine and as contributing editor for TidBITS. He has written many OS X and iOS applications. Previous books include Programming iOS 7, REALbasic: The Definitive Guide, and AppleScript: The Definitive Guide. Twitter: @oreillymedia facebook.com/oreilly Move into iOS development by getting a firm grasp of its fundamentals, including the Xcode IDE, the Cocoa Touch framework, and Swift—Apple's new programming language. With this thoroughly updated guide, you'll learn Swift’s object-oriented concepts, understand how to use Apple's development tools, and discover how Cocoa provides the underlying functionality iOS apps need to have. ■■ Explore Swift’s object-oriented concepts: variables and functions, scopes and namespaces, object types and instances ■■ Become familiar with built-in Swift types such as numbers, strings, ranges, tuples, Optionals, arrays, and dictionaries ■■ Learn how to declare, instantiate, and customize Swift object types—enums, structs, and classes ■■ Discover powerful Swift features such as protocols and generics ■■ Tour the lifecycle of an Xcode project from inception to App Store ■■ Create app interfaces with nibs and the nib editor, Interface Builder ■■ Understand Cocoa’s event-driven model and its major design patterns and features ■■ Find out how Swift communicates with Cocoa’s C and Objective-C APIs Matt Neuburg Programming iOS 8 DIVE DEEP INTO VIEWS, VIEW CONTROLLERS, AND FRAMEWORKS Covers Swift, iOS 8.1, Xcode 6.1 Once you master the fundamentals, you'll be ready to tackle the details of iOS app development with author Matt Neuburg's companion guide, Programming iOS 8. Programming iOS 8 978-1-491-90873-0 iOS 8 Programming Fundamentals with Swift Neuburg Matt Neuburg iOS 8 Programming Fundamentals with Swift SWIFT, XCODE, AND COCOA BASICS Covers iOS 8.3, Xcode 6.3 & Swift 1.2 Matt Neuburg iOS 8 Programming Fundamentals with Swift Swift, Xcode, and Cocoa Basics iOS 8 Programming Fundamentals with Swift by Matt Neuburg Copyright © 2015 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://safaribooksonline.com). For more information, contact our corporate/ institutional sales department: 800-998-9938 or corporate@oreilly.com. Editor: Rachel Roumeliotis Production Editor: Kristen Brown Proofreader: O’Reilly Production Services Indexer: Matt Neuburg Cover Designer: Karen Montgomery Interior Designer: David Futato Illustrator: Matt Neuburg April 2015: First Edition Revision History for the First Edition: 2015-03-10: First release See http://oreilly.com/catalog/errata.csp?isbn=9781491908907 for release details. The O’Reilly logo is a registered trademark of O’Reilly Media, Inc. iOS 8 Programming Fundamentals with Swift, the image of a harp seal, and related trade dress are trademarks of O’Reilly Media, Inc. While the publisher and the author have used good faith efforts to ensure that the information and instruc‐ tions contained in this work are accurate, the publisher and the author disclaim all responsibility for errors or omissions, including without limitation responsibility for damages resulting from the use of or reliance on this work. Use of the information and instructions contained in this work is at your own risk. If any code samples or other technology this work contains or describes is subject to open source licenses or the intel‐ lectual property rights of others, it is your responsibility to ensure that your use thereof complies with such licenses and/or rights. ISBN: 978-1-491-90890-7 [LSI] Table of Contents Preface. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi Part I. Language 1. The Architecture of Swift. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Ground of Being 3 Everything Is an Object? 5 Three Flavors of Object Type 6 Variables 6 Functions 8 The Structure of a Swift File 9 Scope and Lifetime 11 Object Members 12 Namespaces 13 Modules 14 Instances 14 Why Instances? 16 self 19 Privacy 20 Design 22 Object Types and APIs 22 Instance Creation, Scope, and Lifetime 24 Summary and Conclusion 26 2. Functions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Function Parameters and Return Value 27 Void Return Type and Parameters 30 iii Function Signature 31 External Parameter Names 32 Overloading 34 Default Parameter Values 36 Variadic Parameters 37 Ignored Parameters 37 Modifiable Parameters 38 Function In Function 41 Recursion 43 Function As Value 43 Anonymous Functions 46 Define-and-Call 51 Closures 52 How Closures Improve Code 53 Function Returning Function 55 Closure Setting a Captured Variable 58 Closure Preserving Its Captured Environment 59 Curried Functions 60 3. Variables and Simple Types. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 Variable Scope and Lifetime 63 Variable Declaration 65 Computed Initializer 68 Computed Variables 69 Setter Observers 72 Lazy Initialization 74 Built-In Simple Types 76 Bool 76 Numbers 78 String 86 Character 91 Range 93 Tuple 95 Optional 98 4. Object Types. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 Object Type Declarations and Features 113 Initializers 115 Properties 121 Methods 124 iv | Table of Contents Subscripts 127 Namespaced Object Types 129 Instance References 130 Enums 131 Case With Fixed Value 133 Case With Typed Value 134 Enum Initializers 136 Enum Properties 137 Enum Methods 138 Why Enums? 139 Structs 140 Struct Initializers, Properties, and Methods 140 Struct As Namespace 142 Classes 142 Value Types and Reference Types 143 Subclass and Superclass 147 Class Initializers 152 Class Deinitializer 161 Class Properties and Methods 161 Polymorphism 163 Casting 166 Type Reference 170 Protocols 175 Why Protocols? 177 Protocol Type Testing and Casting 179 Declaring a Protocol 180 Optional Protocol Members 181 Class Protocol 183 Implicitly Required Initializers 183 Literal Convertibles 185 Generics 186 Generic Declarations 188 Type Constraints 190 Explicit Specialization 192 Where Clauses 193 Extensions 196 Umbrella Types 199 AnyObject 199 AnyClass 202 Any 203 Table of Contents | v Collection Types 203 Array 204 Dictionary 217 Set 222 5. Flow Control and More. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225 Flow Control 225 Branching 226 Loops 239 Jumping 243 Aborting 244 Operators 245 Privacy 248 Private Declaration 249 Public Declaration 251 Privacy Rules 252 Introspection 253 Memory Management 254 Weak References 255 Unowned References 257 Weak and Unowned References in Anonymous Functions 258 Memory Management of Protocol-Typed References 261 Part II. IDE 6. Anatomy of an Xcode Project. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265 New Project 265 The Project Window 268 The Navigator Pane 269 The Utilities Pane 274 The Editor 276 The Project File and Its Dependents 279 The Target 282 Build Phases 282 Build Settings 285 Configurations 286 Schemes and Destinations 287 From Project to Running App 289 Build Settings 292 vi | Table of Contents Property List Settings 292 Nib Files 293 Additional Resources 294 Code Files and the App Launch Process 296 Frameworks and SDKs 301 Renaming Parts of a Project 304 Bilingual Targets 305 7. Nib Management. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309 A Tour of the Nib Editor Interface 310 The Document Outline 312 Canvas 314 Inspectors and Libraries 317 Nib Loading 318 When Nibs Are Loaded 319 Manual Nib Loading 320 Connections 322 Outlets 323 The Nib Owner 323 Automatically Configured Nibs 327 Misconfigured Outlets 328 Deleting an Outlet 330 More Ways to Create Outlets 330 Outlet Collections 333 Action Connections 334 More Ways to Create Actions 336 Misconfigured Actions 337 Connections Between Nibs — Not! 338 Additional Configuration of Nib-Based Instances 338 8. Documentation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343 The Documentation Window 344 Class Documentation Pages 346 Sample Code 349 Quick Help 349 Symbols 351 Header Files 352 Internet Resources 353 Table of Contents | vii 9. Life Cycle of a Project. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355 Device Architecture and Conditional Code 355 Backward Compatibility 356 Device Type 358 Version Control 360 Editing and Navigating Your Code 362 Autocompletion 363 Snippets 365 Fix-it and Live Syntax Checking 365 Navigation 366 Finding 368 Running in the Simulator 369 Debugging 370 Caveman Debugging 370 The Xcode Debugger 373 Unit Testing 379 Clean 383 Running on a Device 384 Obtaining a Certificate 386 Obtaining a Development Provisioning Profile 389 Running the App 390 Profile and Device Management 390 Profiling 391 Gauges 391 Instruments 392 Localization 395 Localizing the Info.plist 396 Localizing a Nib File 398 Localizing Code Strings 399 Localizing With XML Files 401 Archiving and Distribution 403 Ad Hoc Distribution 405 Final App Preparations 407 Icons in the App 407 Other Icons 408 Launch Images 409 Screenshots and Video Previews 410 Property List Settings 411 Submission to the App Store 412 viii | Table of Contents Part III. Cocoa 10. Cocoa Classes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417 Subclassing 417 Categories and Extensions 420 How Swift Uses Extensions 421 How You Use Extensions 421 How Cocoa Uses Categories 422 Protocols 423 Informal Protocols 425 Optional Methods 425 Some Foundation Classes 428 Useful Structs and Constants 428 NSString and Friends 429 NSDate and Friends 432 NSNumber 433 NSValue 435 NSData 436 Equality and Comparison 436 NSIndexSet 438 NSArray and NSMutableArray 439 NSDictionary and NSMutableDictionary 440 NSSet and Friends 441 NSNull 442 Immutable and Mutable 443 Property Lists 444 Accessors, Properties, and Key–Value Coding 445 Swift Accessors 446 Key–Value Coding 448 Uses of Key–Value Coding 449 KVC and Outlets 451 Key Paths 451 Array Accessors 452 The Secret Life of NSObject 453 11. Cocoa Events. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457 Reasons for Events 457 Subclassing 458 Notifications 459 Table of Contents | ix Receiving a Notification 460 Unregistering 463 Posting a Notification 464 NSTimer 465 Delegation 465 Cocoa Delegation 466 Implementing Delegation 468 Data Sources 469 Actions 470 The Responder Chain 473 Deferring Responsibility 474 Nil-Targeted Actions 475 Key–Value Observing 476 Swamped by Events 480 Delayed Performance 483 12. Memory Management. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 487 Principles of Cocoa Memory Management 487 Rules of Cocoa Memory Management 488 What ARC Is and What It Does 490 How Cocoa Objects Manage Memory 490 Autorelease Pool 491 Memory Management of Instance Properties 493 Retain Cycles and Weak References 494 Unusual Memory Management Situations 496 Nib Loading and Memory Management 501 Memory Management of CFTypeRefs 502 Property Memory Management Policies 504 Debugging Memory Management Mistakes 506 13. Communication Between Objects. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 509 Visibility by Instantiation 510 Visibility by Relationship 512 Global Visibility 513 Notifications and KVO 514 Model–View–Controller 515 A. C, Objective-C, and Swift. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 519 Index. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 543 x | Table of Contents Preface On June 2, 2014, Apple’s WWDC keynote address ended with a shocking announce‐ ment: “We have a new programming language.” This came as a huge surprise to the developer community, which was accustomed to Objective-C, warts and all, and doubt‐ ed that Apple could ever possibly relieve them from the weight of its venerable legacy. The developer community, it appeared, had been wrong. Having picked themselves up off the floor, developers immediately began to examine this new language — Swift — studying it, critiquing it, and deciding whether to adopt it. My own first move was to translate all my existing iOS apps into Swift; this was enough to convince me that, for all its faults, Swift deserved to be adopted by new students of iOS programming, and that my books, therefore, should henceforth assume that readers are using Swift. The Swift language is designed from the ground up with these salient features: Object-orientation Swift is a modern, object-oriented language. It is purely object-oriented: “Every‐ thing is an object.” Clarity Swift is easy to read and easy to write, with minimal syntactic sugar and few hidden shortcuts. Its syntax is clear, consistent, and explicit. Safety Swift enforces strong typing to ensure that it knows, and that you know, what the type of every object reference is at every moment. Economy Swift is a fairly small language, providing some basic types and functionalities and no more. The rest must be provided by your code, or by libraries of code that you use — such as Cocoa. xi Memory management Swift manages memory automatically. You will rarely have to concern yourself with memory management. Cocoa compatibility The Cocoa APIs are written in C and Objective-C. Swift is explicitly designed to interface with most of the Cocoa APIs. These features make Swift an excellent language for learning to program iOS. The alternative, Objective-C, still exists, and you can use it if you like. Indeed, it is easy to write an app that includes both Swift code and Objective-C code; and you may have reason to do so. Objective-C offers direct compatibility with the Cocoa APIs; Objective- C is C, and is sometimes needed in order to do things with C functions that are required by Cocoa but impossible using Swift alone. Objective-C, however, lacks the very the advantages that Swift offers. Objective-C ag‐ glomerates object-oriented features onto C. It is therefore only partially object-oriented; it has both objects and scalar data types, and its objects have to be slotted into one particular C data type (pointers). Its syntax can be difficult and tricky; reading and writing nested method calls can make one’s eyes glaze over, and it invites hacky habits such as implicit nil-testing. Its type checking can be and frequently is turned off, re‐ sulting in programmer errors where a message is sent to the wrong type of object and the program crashes. It uses manual memory management; the recent introduction of ARC (automatic reference counting) has alleviated some of the programmer tedium and has greatly reduced the likelihood of programmer error, but errors are still possible, and memory management ultimately remains manual. Recent revisions and additions to Objective-C — ARC, synthesis and autosynthesis, improved literal array and dictionary syntax, blocks — have made it easier and more convenient, but such patches have also made the language even larger and possibly even more confusing. Because Objective-C must encompass C, there are limits to how far it can be extended and revised. Swift, on the other hand, is a clean start. If you were to dream of completely revising Objective-C to create a better Objective-C, Swift might be what you would dream of. It puts a modern, rational front end between you and the Cocoa Objective-C APIs. Therefore, Swift is the programming language used throughout this book. Nevertheless, the reader will also need some awareness of Objective-C (including C). There are two chief reasons for this: • The Foundation and Cocoa APIs, the built-in commands with which your code must interact in order to make anything happen on an iOS device, are still written in C and Objective-C. In order to interact with them, you have to know what those languages would expect. For example, in order to pass a Swift array where an xii | Preface NSArray is expected, you need to know what consitutes an object acceptable as an element of an Objective-C NSArray. • Swift can’t do everything that C and Objective-C can do. Apple likes to claim that Swift can “access all of the Cocoa Touch frameworks” and that it constitutes “a complete replacement for both the C and Objective-C languages” — I’m quoting from the Xcode 6 release notes — but the truth is that Swift can’t interface directly with every facet of the Cocoa Touch APIs. Swift can’t form a C function or obtain the address of such a function; Swift can’t declare a property @dynamic in the Objective-C sense; and so on. For these reasons, Objective-C still lurks in the shadows of this edition, and will occa‐ sionally leap out and make its presence known. I do not attempt to teach Objective-C — for that, see the previous edition of this book — but I describe it in enough detail to allow you to read it when you encounter it in the documentation and on the Internet, and I occasionally show some Objective-C code. Chapter 6 describes how your app can be written partly in Swift and partly in Objective-C. Part III, on Cocoa, is really all about learning to think the way Objective-C thinks — because the structure and behavior of the Cocoa APIs are fundamentally based on Objective-C. And the book ends with an appendix that details how Swift and Objective-C communicate with one another. The Scope of This Book This book is actually one of a pair with my Programming iOS 8, which picks up exactly where this book leaves off. They complement and supplement one another. The two- book architecture should, I believe, render the size and scope of each book tractable for readers. Together, they provide a complete grounding in the knowledge needed to begin writing iOS apps; thus, when you do start writing iOS apps, you’ll have a solid and rigorous understanding of what you are doing and where you are heading. If writing an iOS program is like building a house of bricks, this book teaches you what a brick is and how to handle it, while Programming iOS 8 hands you some actual bricks and tells you how to assemble them. When you have read this book, you’ll know about Swift, Xcode, and the underpinnings of the Cocoa framework, and you will be ready to proceed directly to Programming iOS 8. Conversely, Programming iOS 8 assumes a knowledge of this book; it begins, like Homer’s Iliad, in the middle of the story, with the reader jumping with all four feet into views and view controllers, and with a knowledge of the language and the Xcode IDE already presupposed. If you started reading Programming iOS 8 and wondered about such unexplained matters as Swift language basics, the UIApplicationMain function, the nib-loading mechanism, Cocoa patterns of delegation and notification, and retain cycles, wonder no longer — I didn’t explain them there because I do explain them here. The three parts of this book teach the underlying basis of all iOS programming: Preface | xiii • Part I introduces the Swift language, from the ground up — I do not assume that you know any other programming languages. My way of teaching Swift is different from other treatments, such as Apple’s; it is systematic and Euclidean, with peda‐ gogical building blocks piled on one another in what I regard as the most helpful order. At the same time, I have tried to confine myself to the essentials. Swift is not a big language, but it has some subtle and unusual corners. You don’t need to dive deep into all of these, and my discussion will leave many of them unexplored. You will probably never encounter them, and if you do, you will have entered an ad‐ vanced Swift world outside the scope of this discussion. To give an obvious example, readers may be surprised to find that I never mention Swift playgrounds or the REPL. My focus here is real-life iOS programming, and my explanation of Swift therefore concentrates on those common, practical aspects of the language that, in my experience, actually come into play in the course of programming iOS. • Part II turns to Xcode, the world in which all iOS programming ultimately takes place. It explains what an Xcode project is and how it is transformed into an app, and how to work comfortably and nimbly with Xcode to consult the documentation and to write, navigate, and debug code, as well as how to bring your app through the subsequent stages of running on a device and submission to the App Store. There is also a very important chapter on nibs and the nib editor (Interface Builder), including outlets and actions as well as the mechanics of nib loading; however, such specialized topics as autolayout constraints in the nib are postponed to the other book. • Part III introduces the Cocoa Touch framework. 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. Your code will ultimately be almost entirely about communicating with Cocoa. The Cocoa Touch frameworks provide the un‐ derlying functionality that any iOS app needs to have. But to use a framework, 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. To make things even more interesting, Cocoa uses Objective-C, while you’ll be using Swift: you need to know how your Swift code will interface with Cocoa’s features and behaviors. Cocoa provides important foundational classes and adds linguistic and architectural devices such as categories, protocols, delegation, and notifications, as well as the pervasive responsibilities of memory management. Key–value coding and key–value observing are also discussed here. The reader of this book will thus get a thorough grounding in the fundamental knowl‐ edge and techniques that any good iOS programmer needs. The book itself doesn’t show how to write any particularly interesting iOS apps, but it does constantly use my own real apps and real programming situations to illustrate and motivate its explanations. And then you’ll be ready for Programming iOS 8, of course! xiv | Preface Versions This book is geared to Swift 1.2, iOS 8.3, and Xcode 6.3, which were in early beta at the time the book was completed. In general, only very minimal attention is given to earlier versions of iOS and Xcode. It is not my intention to embrace in this book any detailed knowledge about earlier versions of the software, which is, after all, readily and com‐ pendiously available in my earlier books. The book does contain, nevertheless, a few words of advice about backward compatibility (especially in Chapter 9). Xcode 6 has eliminated some of the templates that you choose from when creating a new project. The loss of the Utility Application template is a pity, because it embodied and illustrated the standard patterns of protocol and delegate; but that’s no problem, because I can illustrate them for you (Chapter 11). The loss of the Empty Application template is severe; it is, after all, perfectly reasonable to write an app without a storyboard (several of my own apps are structured in that way). Accordingly, in Chapter 6, I give instructions for turning a Single View Application–based template into something sim‐ ilar to what the Empty Application template would have given you. Also, the Xcode 6 templates are based primarily on storyboards; although I treat storyboards as the pri‐ mary Interface Builder design milieu, I still demonstrate how to make and work with a .xib file. At the time of this writing, Apple was still making frequent adjustments to the Swift language and to the way the Objective-C APIs are bridged to it, and Swift 1.2, which I have documented in this book, was still in beta. I have tried to keep my code up-to-date, but please make allowances, and be prepared to compensate for the possibility that my examples may contain slight occasional impedance mismatches. Acknowledgments My thanks go first and foremost to the people at O’Reilly Media who have made writing a book so delightfully easy: Rachel Roumeliotis, Sarah Schneider, Kristen Brown, Dan Fauxsmith, and Adam Witwer come particularly to mind. And let’s not forget my first and long-standing editor, Brian Jepson, who had nothing whatever to do with this ed‐ ition, but whose influence is present throughout. Some details of the presentation of the Swift language came from suggestions by Andrew Duncan, whose book on Objective-C is a classic in its own right. As in the past, I have been greatly aided by some fantastic software, whose excellences I have appreciated at every moment of the process of writing this book. I should like to mention, in particular: • git (http://git-scm.com) • SourceTree (http://www.sourcetreeapp.com) • TextMate (http://macromates.com) Preface | xv • AsciiDoc (http://www.methods.co.nz/asciidoc) • BBEdit (http://barebones.com/products/bbedit/) • Snapz Pro X (http://www.ambrosiasw.com) • GraphicConverter (http://www.lemkesoft.com) • OmniGraffle (http://www.omnigroup.com) The book was typed and edited entirely on my faithful Unicomp Model M keyboard (http://pckeyboard.com), without which I could never have done so much writing over so long a period so painlessly. For more about my physical work environment, see http:// matt.neuburg.usesthis.com. From the Programming iOS 4 Preface 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 objects was severely and deliberately limited; on the other hand, the power and flexibility of some of those objects, especially such things as UITableView, was greatly enhanced over their OS X counterparts. Even more important, Apple created a particularly brilliant way (UIView‐ Controller) 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. 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 OS X. Apple’s own annual WWDC developer conventions have reflected this trend, with their emphasis shifted from 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 xvi | Preface do so. 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 and elements on which sound iOS programming rests. 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 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 views before you know view controllers for the simple reason that Part I precedes Part II. 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 find 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 de‐ veloped that program. It is this thought process, more than anything else, that I hope you will gain from reading this book. 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 | xvii This element signifies a tip or suggestion. This element signifies a general note. This element indicates a warning or caution. Using Code Examples Supplemental material (code examples, exercises, etc.) is available for download at http://github.com/mattneub/Programming-iOS-Book-Examples. This book is here to help you get your job done. In general, if example code is offered with this book, you may use it 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 ex‐ ample 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: “iOS 8 Programming Fundamentals with Swift by Matt Neuburg (O’Reilly). Copyright 2015 Matt Neuburg, 978-1-491-90890-7.” If you feel your use of code examples falls outside fair use or the permission given above, feel free to contact us at permissions@oreilly.com. Safari® Books Online Safari Books Online is an on-demand digital library that delivers expert content in both book and video form from the world’s leading authors in technology and business. Technology professionals, software developers, web designers, and business and crea‐ tive professionals use Safari Books Online as their primary resource for research, prob‐ lem solving, learning, and certification training. xviii | Preface Safari Books Online offers a range of plans and pricing for enterprise, government, education, and individuals. Members have access to thousands of books, training videos, and prepublication manu‐ scripts in one fully searchable database from publishers like O’Reilly Media, Prentice Hall Professional, Addison-Wesley Professional, Microsoft Press, Sams, Que, Peachpit Press, Focal Press, Cisco Press, John Wiley & Sons, Syngress, Morgan Kaufmann, IBM Redbooks, Packt, Adobe Press, FT Press, Apress, Manning, New Riders, McGraw-Hill, Jones & Bartlett, Course Technology, and hundreds more. For more information about Safari Books Online, please visit us online. 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://bit.ly/ios8-prog-fundamentals. To comment or ask technical questions about this book, send email to bookquestions@oreilly.com. 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 Preface | xix PART I Language This part of the book teaches the Swift language, from the ground up. The description is rigorous and orderly. Here you’ll become sufficiently conversant with Swift to be comfortable with it, so that you can proceed to the practical business of actual pro‐ gramming. • Chapter 1 surveys the structure of a Swift program, both physically and conceptu‐ ally. You’ll learn how Swift code files are organized, and you’ll be introduced to the most important underlying concepts of the object-oriented Swift language: vari‐ ables and functions, scopes and namespaces, object types and their instances. • Chapter 2 explores Swift functions. We start with the basics of how functions are declared and called; then we discuss parameters — external parameter names, de‐ fault parameters, and variadic parameters. Then we dive deep into the power of Swift functions, with an explanation of functions inside functions, functions as first- class values, anonymous functions, functions as closures, and curried functions. • Chapter 3 starts with Swift variables — their scope and lifetime, and how they are declared and initialized, along with important Swift features such as computed variables and setter observers. Then some important built-in Swift types are intro‐ duced, including Booleans, numbers, strings, ranges, tuples, and Optionals. • Chapter 4 is all about Swift object types — classes, structs, and enums. It explains how these three object types work, and how you declare, instantiate, and use them. Then it proceeds to polymorphism and casting, protocols, generics, and extensions. The chapter concludes with a discussion of Swift’s umbrella types (such as Any‐ Object) and collection types (Array, Dictionary, and Set). • Chapter 5 is a miscellany. We start with Swift’s flow control structures for branching and looping. Then I’ll explain how to create your own Swift operators. The chapter concludes by describing Swift access control (privacy), introspection (reflection), and memory management. CHAPTER 1 The Architecture of Swift It will be useful at the outset for you to have a general sense of how the Swift language is constructed and what a Swift-based iOS program looks like. This chapter will survey the overall architecture and nature of the Swift language. Subsequent chapters will fill in the details. Ground of Being A complete Swift command is a statement. A Swift text file consists of multiple lines of text. Line breaks are meaningful. The typical layout of a program is one statement, one line: print("hello ") print("world") However, that’s not a hard and fast rule. You can combine more than one statement on a line, but then you need to put a semicolon between them: print("hello "); print("world") You are free to put a semicolon at the end of a statement that is last or alone on its line, but no one ever does (except out of habit, because C and Objective-C require the sem‐ icolon): print("hello "); print("world"); Conversely, a single statement can be broken into multiple lines, in order to prevent long statements from becoming long lines. But you should try to do this at sensible places so as not to confuse Swift. For example, after an opening parenthesis is a good place: print( "world") 3 Comments are everything after two slashes in a line (so-called C++-style comments): print("world") // this is a comment, so Swift ignores it You can also enclose comments in /*...*/, as in C. Unlike C, C-style comments can be nested. Many constructs in Swift use curly braces as delimiters: class Dog { func bark() { println("woof") } } By convention, the contents of curly braces are preceded and followed by line breaks and are indented for clarity, as shown in the preceding code. Xcode will help impose this convention, but the truth is that Swift doesn’t care, and layouts like this are legal (and are sometimes more convenient): class Dog { func bark() { println("woof") }} Instant feedback in the Xcode console is provided by the print and println commands. The difference is that println appends a linefeed to its output. Swift is a compiled language. This means that your code must build — passing through the compiler and being turned from text into some lower-level form that a computer can understand — before it can run and actually do the things it says to do. The Swift compiler is very strict; in the course of writing a program, you will often try to build and run, only to discover that you can’t even build in the first place, because the compiler will flag some error, which you will have to fix if you want the code to run. Less often, the compiler will let you off with a warning; the code can run, but in general you should take warnings seriously and fix whatever they are telling you about. The strictness of the compiler is one of Swift’s greatest strengths, and provides your code with a large measure of audited correctness even before it ever starts running. As of this writing, the Swift compiler’s error and warning messages range from the insightful to the obtuse to the downright misleading. You will often know that something is wrong with a line of code, but the Swift compiler will not be telling you clearly exactly what is wrong or even where in the line to focus your atten‐ tion. My advice in these situations is to pull the line apart into several lines of simpler code until you reach a point where you can guess what the issue is. Try to love the compiler despite the occasional unhelpful nature of its messages. Remem‐ ber, it knows more than you do, even if it is sometimes rather inarticulate about its knowledge. 4 | Chapter 1: The Architecture of Swift Everything Is an Object? In Swift, “everything is an object.” That’s a boast common to various modern object- oriented languages, but what does it mean? Well, that depends on what you mean by “object” — and what you mean by “everything.” Let’s start by stipulating that an object, roughly speaking, is something you can send a message to. A message, roughly speaking, is an imperative instruction. For example, you can give commands to a dog: “Bark!” “Sit!” In this analogy, those phrases are mes‐ sages, and the dog is the object to which you are sending those messages. In Swift, the syntax of message-sending is dot-notation. We start with the object; then there’s a dot (a period); then there’s the message. (Some messages are also followed by parentheses, but ignore them for now; the full syntax of message-sending is one of those details we’ll be filling in later.) This is valid Swift syntax: fido.bark() rover.sit() The idea of everything being an object is a way of suggesting that even “primitive” lin‐ guistic entities can be sent messages. Take, for example, 1. It appears to be a literal digit and no more. It will not surprise you, if you’ve ever used any programming language, that you can say things like this in Swift: let sum = 1 + 2 But it is surprising to find that 1 can be followed by a dot and a message. This is legal and meaningful in Swift (don’t worry about what it actually means): let x = 1.successor() Similarly, a piece of text expressed as a literal — a string — is an object. For example, "hello" is a literal string, and this is legal Swift (again, never mind what this code means): let y = "hello".generate() But we can go further. Return to that innocent-looking 1 + 2 from our earlier code. It turns out that this is actually a kind of syntactic trickery, a convenient way of expressing and hiding what’s really going on. Just as 1 is actually an object, + is actually a message; but it’s a message with special syntax (operator syntax). In Swift, every noun is an object, and every verb is a message. Perhaps the ultimate acid test for whether something is an object in Swift is whether you can modify it. An object type can be extended in Swift, meaning that you can define your own messages on that type. For example, you can’t normally send the sayHello message to a number. But you can change a number type so that you can: Everything Is an Object? | 5 extension Int { func sayHello() { println("Hello, I'm \(self)") } } 1.sayHello() // outputs: "Hello, I'm 1" I rest my case. In Swift, then, 1 is an object. In some languages, such as Objective-C, it clearly is not; it is a “primitive” or scalar built-in data type. The distinction being drawn here, then, when we say that “everything is an object,” is between object types on the one hand and scalars on the other. In Swift, there are no scalars; all types are ultimately object types. That’s what “everything is an object” really means. Three Flavors of Object Type If you know Objective-C or some other object-oriented language, you may be surprised by Swift’s notion of what kind of object 1 is. In many languages, such as Objective-C, an object is a class or an instance of a class. Swift has classes and instances, and you can send messages to them; but 1 in Swift is neither of those: it’s a struct. And Swift has yet another kind of thing you can send messages to, called an enum. So Swift has three kinds of object type: classes, structs, and enums. I like to refer to these as the three flavors of object type. Exactly how they differ from one another will emerge in due course. But they are all very definitely object types, and their similarities to one another are far stronger than their differences. For now, just bear in mind that these three flavors exist. (The fact that a struct or enum is an object type in Swift will surprise you particularly if you know Objective-C. Objective-C has structs and enums, but they are not objects. Swift structs, in particular, are much more important and pervasive than Objective-C structs. This difference between how Swift views structs and enums and how Objective- C views them can matter when you are talking to Cocoa.) Variables A variable is a name for an object. Technically, it refers to an object; it is an object reference. Nontechnically, you can think of it as a shoebox into which an object is placed. The object may undergo changes, or it may be replaced inside the shoebox by another object, but the name has an integrity all its own. In Swift, no variable comes implicitly into existence; all variables must be declared. If you need a name for something, you must say “I’m creating a name.” You do this with one of two keywords: let or var. In Swift, declaration is usually accompanied by 6 | Chapter 1: The Architecture of Swift initialization — you use an equal sign to give the variable a value, right there as part of the declaration. These are both variable declarations (and initializations): let one = 1 var two = 2 Once the name exists, you are free to use it. For example, we can change the value of what’s in two to be the same as the value of what’s in one: let one = 1 var two = 2 two = one The last line of that code uses both the name one and the name two declared in the first two lines: the name one, on the right side of the equal sign, is used merely to refer to the value inside the shoebox (namely 1); but the name two, on the left side of the equal sign, is used to replace the value inside the shoebox. A statement like that, with a variable name on the left side of an equal sign, is called an assignment, and the equal sign is the assignment operator. The equal sign is not an assertion of equality, as it might be in an algebraic formula; it is a command. It means: “Get the value of what’s on the right side of me, and use it to replace the value inside what’s on the left side of me.” The two kinds of variable declaration differ in that a name declared with let cannot have its object replaced. A variable declared with let is a constant; its value is assigned once and stays. This won’t even compile: let one = 1 var two = 2 one = two // compile error It is always possible to declare a name with var to give yourself the most flexibility, but if you know you’re never going to replace the initial value of a variable, it’s better to use let, as this permits Swift to behave much more efficiently. Variables also have a type. This type is established when the variable is declared and can never change. For example, this won’t compile: var two = 2 two = "hello" Once two is declared and initialized as 2, it is a number (properly speaking, an Int) and it must always be so. You can replace its value with 1 because that’s also an Int, but you can’t replace its value with "hello" because that’s a string (properly speaking, a String) — and a String is not an Int. Variables literally have a life of their own — more accurately, a lifetime of their own. As long as a variable exists, it keeps its value alive. Thus, a variable can be not only a way of conveniently naming something, but also a way of preserving it. I’ll have more to say about that later. Variables | 7 By convention, type names such as String or Int (or Dog or Cat) start with a capi‐ tal letter; variable names start with a small letter. Do not violate this convention. If you do, your code might still compile and run just fine, but I will personally send agents to your house to remove your kneecaps. Functions Executable code, like fido.bark() or one = two, cannot go just anywhere. In general, it must live inside the body of a function. A function is a batch of code, a succession of lines of code that can be told, as a batch, to run. Typically, a function has a name, and it gets that name through a function declaration. Function declaration syntax is another of those details that will be filled in later, but here’s an example: func go() { let one = 1 var two = 2 two = one } That describes a sequence of things to do — declare one, declare two, change the value of two to match the value of one — and it gives that sequence a name, go; but it doesn’t perform the sequence. The sequence is performed when someone calls the function. Thus, we might say, elsewhere: go() That is a command to the go function that it should actually run. But again, that com‐ mand is itself executable code, so it cannot live on its own either. It might live in a different function declaration: func doGo() { go() } But wait! This is getting a little nutty. That, too, is just a function declaration; to run it, someone must call doGo, and that’s executable code too. This seems like some kind of infinite regression; it looks like none of our code will ever run. If all executable code has to live in a function, who will tell any function to run? The initial impetus must come from somewhere. In real life, fortunately, this regression problem doesn’t arise. Remember that your goal is ultimately to write an iOS app. Thus, your app will be run on an iOS device (or the Simulator) by a runtime that already wants to call certain functions. So you start by writing special functions that you know the runtime itself will call. That gives your app a way to get started and gives you places to put functions that will be called by the runtime at key moments — such as when the app launches, or when the user taps a button in your app’s interface. 8 | Chapter 1: The Architecture of Swift Swift also has a special rule that a file called main.swift, exceptionally, can have executable code at its top level, outside any function body, and this is the code that actually runs when the program runs. You can construct your app with a main.swift file, but in general you won’t need to. Also, Xcode allows you to create play‐ grounds. A playground file has the special property that it acts like a main.swift file, so that you are allowed to put executable code at the top level of the file, outside any function body. But playgrounds can’t be part of an iOS app, and are not con‐ sidered in this book. The Structure of a Swift File A Swift program can consist of one file or many files. In Swift, a file is a meaningful unit, and there are definite rules about the structure of the Swift code that can go inside it. (I’m assuming that we are not in a main.swift file or a playground.) Then only certain things can go at the top level of this file: Module import statements A module is an even higher-level unit than a file. A module can consist of multiple files, and in Swift, the files within a module can all see each other automatically; but a module can’t see another module without an import statement. For example, that is how you are able to talk to Cocoa in an iOS program: the first line of your file says import UIKit. Variable declarations A variable declared at the top level of a file is a global variable: it lives as long as the program runs. Function declarations A function declared at the top level of a file is a global function: all code will be able to see and call it, without sending a message to any object. Object type declarations The declaration for a class, a struct, or an enum. For example, this is a legal Swift file containing (just to demonstrate that it can be done) an import statement, a variable declaration, a function declaration, a class declaration, a struct declaration, and an enum declaration: import UIKit var one = 1 func changeOne() { } class Manny { } The Structure of a Swift File | 9 struct Moe { } enum Jack { } That’s a very silly and mostly empty example, but remember, our goal is to survey the parts of the language and the structure of a file, and the example shows them. Furthermore, the curly braces for each of the things in that example can all have variable declarations, function declarations, and object type declarations within them! Indeed, any structural curly braces can contain such declarations. So, for example, the keyword if (which is part of Swift’s flow control, discussed in Chapter 5) is followed by structural curly braces, and they can contain variable declarations, function declarations, and ob‐ ject type declarations. This code, while silly, is legal: func silly() { if true { class Cat {} var one = 1 one = one + 1 } } But only a function declaration, remember, can contain executable code. It can contain executable code at any depth within itself; in the preceding code, the line one = one + 1, which is executable code, is legal because it is inside the if construct, which is inside a function declaration. But the line one = one + 1 cannot go at the top level of the file; and it cannot go directly inside the Cat declaration’s curly braces. Example 1-1 is a legal Swift file, schematically illustrating the structural possibilities. (Ignore the hanky-panky with the name variable declaration inside the enum declaration for Jack; enum top-level variables have some special rules that I’ll explain later.) Example 1-1. Schematic structure of a legal Swift file import UIKit var one = 1 func changeOne() { let two = 2 func sayTwo() { println(two) } class Klass {} struct Struct {} enum Enum {} one = two } class Manny { let name = "manny" func sayName() { println(name) 10 | Chapter 1: The Architecture of Swift } class Klass {} struct Struct {} enum Enum {} } struct Moe { let name = "moe" func sayName() { println(name) } class Klass {} struct Struct {} enum Enum {} } enum Jack { var name : String { return "jack" } func sayName() { println(name) } class Klass {} struct Struct {} enum Enum {} } Obviously, we can recurse down as far we like: we could have a class declaration con‐ taining a class declaration containing a class declaration…and so on. But there’s no point illustrating that. Scope and Lifetime In a Swift program, things have a scope. This refers to their ability to be seen by other things. Things are nested inside of other things, making a nested hierarchy of things. The rule is that things can see things at their own level and higher. The levels are: • A module is a scope. • A file is a scope. • An object declaration is a scope. • Curly braces are a scope. When something is declared, it is declared at some level within that hierarchy. Its place in the hierarchy — its scope — determines whether it can be seen by other things. For example, look again at Example 1-1. Inside the declaration of Manny is a name variable declaration and a sayName function declaration; the code inside sayName’s curly braces can see things outside those curly braces at a higher level, and can therefore see Scope and Lifetime | 11 the name variable. Similarly, the code inside the body of the changeOne function decla‐ ration can see the one variable declared at the top level of the file; indeed, everything throughout this file can see the one variable declared at the top level of the file. Scope is thus a very important way of sharing information. Two different functions declared inside Manny would both be able to see the name declared at Manny’s top level. Code inside Jack and code inside Moe can both see the one declared at the file’s top level. Things also have a lifetime, which is effectively equivalent to their scope. A thing lives as long as its surrounding scope lives. Thus, the variable one lives as long as the file lives — namely, as long the program runs. It is global and permanent. But the variable name declared at the top level of Manny exists only so long as Manny exists (I’ll talk in a moment about what that means). Things declared at a deeper level live even shorter lifetimes; for example, let’s return to this code: func silly() { if true { class Cat {} var one = 1 one = one + 1 } } In that code, the class Cat and the variable one exist only during the brief instant that the path of code execution passes through the if construct. When the function silly is called, Cat is declared and comes into existence; then one is declared and comes into existence; then the executable line one = one + 1 is executed; and then the scope ends and both Cat and one vanish in a puff of smoke. Object Members Inside the three object types (class, struct, and enum), things declared at the top level have special names, mostly for historical reasons. Let’s use the Manny class as an ex‐ ample: class Manny { let name = "manny" func sayName() { println(name) } } In that code: • name is a variable declared at the top level of an object declaration, so it is called a property of that object. 12 | Chapter 1: The Architecture of Swift • sayName is a function declared at the top level of an object declaration, so it is called a method of that object. Things declared at the top level of an object declaration — properties, methods, and any objects declared at that level — are collectively the members of that object. Members have a special significance, because they define the messages you are allowed to send to that object! Namespaces A namespace is a named region of a program. A namespace has the property that the names of things inside it cannot be reached by things outside it without somehow first passing through the barrier of saying that region’s name. This is a good thing because it allows the same name to be used in different places without a conflict. Clearly, name‐ spaces and scopes are closely related notions. Namespaces help to explain the significance of declaring an object at the top level of an object, like this: class Manny { class Klass {} } This way of declaring Klass effectively “hides” it inside Manny. Manny is a namespace! Code inside Manny can see (and say) Klass directly. But code outside Manny can’t do that. It has to specify the namespace explicitly in order to pass through the barrier that the namespace represents. To do so, it must say Manny’s name first, followed by a dot, followed by the term Klass. In short, it has to say Manny.Klass. The namespace does not, of itself, provide secrecy or privacy; it’s a convenience. Thus, in Example 1-1, I gave Manny a Klass class, and I also gave Moe a Klass class. But they don’t conflict, because they are in different namespaces, and I can differentiate them, if necessary, as Manny.Klass and Moe.Klass. It will not have escaped your attention that the syntax for diving explicitly into a name‐ space is the message-sending dot-notation syntax. They are, in fact, the same thing. In effect, message-sending allows you to see into scopes you can’t see into otherwise. Code inside Moe can’t automatically see the Klass declared inside Manny, but it can see it by taking one easy extra step, namely by speaking of Manny.Klass. It can do that because it can see Manny (because Manny is declared at a level that code inside Moe can see). Namespaces | 13 Modules The top-level namespaces are modules. By default, your app is a module and hence a namespace; that namespace’s name is, roughly speaking, the name of the app. For ex‐ ample, if my app is called MyApp, then if I declare a class Manny at the top level of a file, that class’s real name is MyApp.Manny. But I don’t usually need to use that real name, because my code is already inside the same namespace, and can see the name Manny directly. Frameworks are also modules, and hence they are also namespaces. For example, Co‐ coa’s Foundation framework, where NSString lives, is a module. When you program iOS, you will say import Foundation (or, more likely, you’ll say import UIKit, which itself imports Foundation), thus allowing you to speak of NSString without saying Foundation.NSString. But you could say Foundation.NSString, and if you were so silly as to declare a different NSString in your own module, you would have to say Foundation.NSString, in order to differentiate them. You can also create your own frameworks, and these, too, will be modules. Thus, above and beyond the level of the file, as shown in Example 1-1, are any libraries (modules) that the file imports. Your code always implicitly imports Swift itself. You could make this explicit by starting a file with the line import Swift; there is no need to do this, but it does no harm either. That fact is important, because it solves a major mystery: where do things like println come from, and why is it possible to use them outside of any message to any object? println is in fact a function declared at the top level of the Swift.h file — which your file can see exactly because it imports Swift. It is thus an ordinary top-level function like any other. You could say things like Swift.println("hello"), but you probably never will, because there’s no name conflict to resolve. You can actually see the Swift.h file and read it and study it, and this can be a useful thing to do. To do so, Command-click the term println in your code. Alternative‐ ly, explicitly import Swift and Command-click the term Swift. Behold, there it is! You won’t see any executable Swift code here, but you will see the declarations for all the available Swift terms, including top-level functions like println, operators like +, and declarations of built-in types such as Int and String (look for struct Int, struct String, and so on). Instances Object types — class, struct, and enum — have an important feature in common: they can be instantiated. In effect, when you declare an object type, you are only defining a type. To instantiate a type is to make a thing — an instance — of that type. 14 | Chapter 1: The Architecture of Swift So, for example, I can declare a Dog class: class Dog { } And I can give my class a method: class Dog { func bark() { println("woof") } } But I don’t have actually have any Dog objects in my program yet. I have merely described the type of thing a Dog would be if I had one. To get an actual Dog, I have to make one. The process of making an actual Dog object whose type is the Dog class is the process of instantiating Dog. The result is a new object — a Dog instance. In Swift, instances are created by using the object type’s name as a function name and calling the function. This involves using parentheses. When you append parentheses to the name of an object type, you are sending a very special kind of message to that object type: Instantiate yourself! So now I’m going to make a Dog instance: let fido = Dog() There’s a lot going on in that code! I did two things. I instantiated Dog, thus causing me to end up with a Dog instance. I also put that Dog instance into a shoebox called fido — I declared a variable and initialized the variable by assigning my new Dog instance to it. Now fido is a Dog instance. (Moreover, because I used let, fido will always be this same Dog instance. I could have used var instead, but even then, initializing fido as a Dog instance would have meant fido could only be some Dog instance after that.) Now that I have a Dog instance, I can send instance messages to it. And what do you suppose they are? They are Dog’s properties and methods! For example: let fido = Dog() fido.bark() That code is legal. Not only that, it is effective: it actually does cause "woof" to appear in the console. I made a Dog and I made it bark! (See Figure 1-1.) There’s an important lesson here, so let me pause to emphasize it. By default, properties and methods are instance properties and methods. You can’t use them as messages to the object type itself; you have to have an instance to send those messages to. As things stand, this is illegal and won’t compile: Dog.bark() // compile error It is possible to declare a function bark in such a way that saying Dog.bark() is legal, but that would be a different kind of function — a class function or a static function — and you would need to say so when you declare it. Instances | 15 Figure 1-1. Making an instance and calling an instance method The same thing is true of properties. The only respect in which any Dog has had a name up to now has been the name of the variable to which it is assigned. But that name is not intrinsic to the Dog object itself. Let’s give Dog a name property: class Dog { var name = "" } That allows me to set a Dog’s name, but it needs to be an instance of Dog: let fido = Dog() fido.name = "Fido" It is possible to declare a property name in such a way that saying Dog.name is legal, but that would be a different kind of property — a class property or a static property — and you would need to say so when you declare it. Why Instances? Even if there were no such thing as an instance, an object type is itself an object. We know this because it is possible to send a message to an object type: it is possible to treat an object type as a namespace and to dive explicitly into that namespace (the phrase Manny.Klass is a case in point). Moreover, since class and static members exist, it is possible to call a method directly on a class, a struct, or an enum type, and to refer to a property of a class, a struct, or an enum type. Why, then, do instances exist at all? 16 | Chapter 1: The Architecture of Swift The answer has mostly to do with the nature of instance properties. The value of an instance property is defined with respect to a particular instance. This is where instances get their real usefulness and power. Consider again our Dog class. I’ll give it a name property and a bark method; remember, these are an instance property and an instance method: class Dog { var name = "" func bark() { println("woof") } } A Dog instance comes into existence with a blank name (an empty string). But its name property is a var, so once we have any Dog instance, we can assign to its name a new String value: let dog1 = Dog() dog1.name = "Fido" We can also ask for a Dog instance’s name: let dog1 = Dog() dog1.name = "Fido" println(dog1.name) // "Fido" The important thing is that we can make more than one Dog instance, and that two different Dog instances can have two different name property values (Figure 1-2): let dog1 = Dog() dog1.name = "Fido" let dog2 = Dog() dog2.name = "Rover" println(dog1.name) // "Fido" println(dog2.name) // "Rover" Note that a Dog instance’s name property has nothing to do with the name of the variable to which a Dog instance is assigned. The variable is just a shoebox. You can pass an instance from one shoebox to another. But the instance itself maintains its own internal integrity: let dog1 = Dog() dog1.name = "Fido" var dog2 = Dog() dog2.name = "Rover" println(dog1.name) // "Fido" println(dog2.name) // "Rover" dog2 = dog1 println(dog2.name) // "Fido" Why Instances? | 17 Figure 1-2. Two dogs with different property values That code didn’t change Rover’s name; it changed which dog was inside the dog2 shoe‐ box, replacing Rover with Fido. The full power of object-based programming has now emerged. There is a Dog object type which defines what it is to be a Dog. Our declaration of Dog says that a Dog instance — any Dog instance, every Dog instance — has a name property and a bark method. But each Dog instance can have its own name property value. They are different instances and maintain their own internal state. So multiple instances of the same object type behave alike — both Fido and Rover can bark, and will do so when they are sent the bark message — but they are different instances and can have different property values: Fido’s name is "Fido" while Rover’s name is "Rover". (The same thing is true of 1 and 2, though this fact is somewhat more opaque. An Int has a value property. 1 is an Int whose value is 1, and 2 is an Int whose value is 2. However, this fact is of less interest in real life, because obviously you’re not going to change the value of 1!) So an instance is a reflection of the instance methods of its type, but that isn’t all it is; it’s also a collection of instance properties. The object type is responsible for what properties the instance has, but not necessarily for the values of those properties. The values can change as the program runs, and apply only to a particular instance. An instance is a cluster of particular property values. An instance is responsible not only for the values but also for the lifetimes of its prop‐ erties. Suppose we bring a Dog instance into existence and assign to its name property 18 | Chapter 1: The Architecture of Swift the value "Fido". Then this Dog instance is keeping the string "Fido" alive just so long as we do not replace the value of its name with some other value and just so long as this instance lives. In short, an instance is both code and data. The code it gets from its type and in a sense is shared with all other instances of that type, 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 property values. An instance is a device for maintaining state. It’s a box for storage of data. self An instance is an object, and an object is the recipient of messages. Thus, an instance needs a way of sending a message to itself. This is made possible by the magic word self. This word can be used wherever the name of an instance is expected (an instance of the appropriate type, that is). For example, let’s say I want to keep the thing that a Dog says when it barks — namely "woof" — in a property. Then in my implementation of bark I need to refer to that property. I can do it like this: class Dog { var name = "" var whatADogSays = "woof" func bark() { println(self.whatADogSays) } } Similarly, let’s say I want to write an instance method speak which is merely a synonym for bark. My speak implementation can consist of simply calling my own bark method. I can do it like this: class Dog { var name = "" var whatADogSays = "woof" func bark() { println(self.whatADogSays) } func speak() { self.bark() } } Observe that the term self in that example appears only in instance methods. When an instance’s code says self, it is referring to this instance. If the expression self.name appears in a Dog instance method’s code, it means the name of this Dog instance, the one whose code is running at that moment. self | 19 It turns out that every use of the word self I’ve just illustrated is completely optional. You can omit it and all the same things will happen: class Dog { var name = "" var whatADogSays = "woof" func bark() { println(whatADogSays) } func speak() { bark() } } The reason is that if you omit the message recipient and the message you’re sending can be sent to self, the compiler supplies self as the message’s recipient under the hood. However, I never do that (except by mistake). As a matter of style, I like to be explicit in my use of self. I find code that omits self harder to read and understand. And there are situations where you must say self, so I prefer to use it whenever I’m allowed to use it. Privacy Earlier, I said that a namespace is not, of itself, an insuperable barrier to accessing the names inside it. But it can act as a barrier if you want it to. For example, not all data stored by an instance is intended for alteration by, or even visibility to, another instance. And not every instance method is intended to be called by other instances. Any decent object-based programming language needs a way to endow its object members with privacy — a way of making it harder for other objects to see those members if they are not supposed to be seen. Consider, for example: class Dog { var name = "" var whatADogSays = "woof" func bark() { println(self.whatADogSays) } func speak() { println(self.whatADogSays) } } Here, other objects can come along and change my property whatADogSays. Since that property is used by both bark and speak, we could easily end up with a Dog that, when told to bark, says "meow". This seems somehow undesirable: 20 | Chapter 1: The Architecture of Swift let dog1 = Dog() dog1.whatADogSays = "meow" dog1.bark() // meow You might reply: Well, silly, why did you declare whatADogSays with var? Declare it with let instead. Make it a constant! Now no one can change it: class Dog { var name = "" let whatADogSays = "woof" func bark() { println(self.whatADogSays) } func speak() { println(self.whatADogSays) } } That is a good answer, but it is not quite good enough. There are two problems. Suppose I want a Dog instance itself to be able to change self.whatADogSays. Then whatADog- Says has to be a var; otherwise, even the instance itself can’t change it. Also, suppose I don’t want any other object to know what this Dog says, except by calling bark or speak. Even when declared with let, other objects can still read the value of whatADog- Says. Maybe I don’t like that. To solve this problem, Swift provides the private keyword. I’ll talk later about all the ramifications of this keyword, but for now it’s enough to know that it solves the problem: class Dog { var name = "" private var whatADogSays = "woof" func bark() { println(self.whatADogSays) } func speak() { println(self.whatADogSays) } } Now name is a public property, but whatADogSays is a private property: it can’t be seen by other objects. A Dog instance can speak of self.whatADogSays, but a different object with a reference to a Dog instance as, say, dog1 cannot say dog1.whatADogSays. The important lesson here is that object members are public by default, and if you want privacy, you have to ask for it. The class declaration defines a namespace; this namespace requires that other objects use an extra level of dot-notation to refer to what’s inside the namespace, but other objects can still refer to what’s inside the namespace; the name‐ space does not, in and of itself, close any doors of visibility. The private keyword lets you close those doors. Privacy | 21 Design You now know what an object is, and what an instance is. But what object types will your program need, what methods and properties should they have, when and how will they be instantiated, and what should you do with those instances when you have them? Unfortunately I can’t tell you that; it’s an art — the art of object-based programming. What I can tell you is what your chief considerations are going to be as you design and implement an object-based program — the process that I call growing a program. Object-based program design must be founded upon a secure understanding of the nature of objects. You want to design object types that encapsulate the right sort of functionality (methods) accompanied by the right set of data (properties). Then, when you instantiate those object types, you want to make sure that your instances have the right lifetimes, sufficient exposure to one another, and an appropriate ability to com‐ municate with one another. Object Types and APIs Your program files will have very few, if any, top-level functions and variables. Methods and properties of object types — in particular, instance methods and instance properties — will be where most of the action is. Object types give each actual instance its speci‐ alized abilities. They also help to organize your program’s code meaningfully and main‐ tainably. We may summarize the nature of objects in two phrases: encapsulation of functionality, and maintenance of state. (I first used this summary many years ago in my book REALbasic: The Definitive Guide.) 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 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. Often 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 or public property 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 22 | Chapter 1: The Architecture of Swift Figure 1-3. A stack 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 1-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 Design | 23 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. Other objects can get access to that data, but only by virtue of having access to the stack object itself, and only in the manner that the stack object permits. 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. The sum total of messages that each object type is eligible to be sent by other objects — its API (application programming interface) — is like a list or menu of things you can ask this type of object to do. Your object types divide up your code; their APIs form the basis of communication between those divisions. In real life, when you’re programming iOS, the vast majority of object types you’ll be working with will not be yours but Apple’s. Swift itself comes with a few useful object types, such as String and Int; you’ll also import UIKit, which includes a huge number of object types, all of which spring to life in your program. You didn’t create any of those object types, so to learn to use them, you consult the published APIs, also known as the documentation. Apple’s own Cocoa documentation consists largely of pages where each page lists and describes the properties and methods supplied by one object type. For example, to know what messages you can send to an NSString instance, you’d start by studying the NSString class documentation. That page is really just a big list of properties and 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. Thus, in real life, the “wise programmer” of whom I spoke a moment ago will be, in large part, Apple. Your wisdom will lie not in creating new object types but in using the object types that Apple has already given you. You can also create new object types, and you will do so, but proportionately you will do this vastly less than you will use the object types that exist already. Instance Creation, Scope, and Lifetime The important moment-to-moment entities in a Swift program are mostly instances. Object types define what kinds of instances there can be and how each kind of instance behaves. But the actual instances of those types are the state-carrying individual “things” that the program is all about, and instance methods and properties are messages that can be sent to instances. So there need to be instances in order for the program to do anything. 24 | Chapter 1: The Architecture of Swift By default, however, there are no instances! Looking back at Example 1-1, we defined some object types, but we made no instances of them. If we were to run this program, our object types would exist from the get-go, but that’s all that would exist. We’ve created a world of pure potentiality — some types of object that might exist. In that world, nothing would actually happen. Instances do not come into being by magic. You have to instantiate a type in order to obtain an instance. Much of the action of your program, therefore, will consist of in‐ stantiating types. And of course you will want those instances to persist, so you will also assign each newly created instance to a variable as a shoebox to hold it, name it, and give it a lifetime. The instance will persist according to the lifetime of the variable that refers to it. And the instance will be visible to other instances according to the scope of the variable that refers to it. Much of the art of object-based programming turns out to be exactly here, in giving instances a sufficient lifetime and making them visible to one another. You will often put an instance into a particular shoebox — assigning it to a particular variable, declared at a certain scope — exactly so that, thanks to the rules of variable lifetime and scope, this instance will persist long enough to keep being useful to your program while it will still be needed, and so that other code can get a reference to this instance and talk to it later. Planning how you’re going create instances, and working out the lifetimes and com‐ munication between those instances, may sound daunting. Fortunately, in real life, when you’re programming iOS, the Cocoa framework itself will once again provide an initial scaffolding for you. For example, you’ll know from the start that, for an iOS app, you need an app delegate type and a view controller type, and in fact when you create an iOS app project, Xcode will give them to you. Moreover, as your app launches, the runtime will instantiate those object types for you, and will place those instances into a fixed and useful relationship. The runtime will make an app delegate instance and assign it in such a way that it lives for the lifetime of the app; it will create a window instance and assign it to a property of the app delegate; and it will create a view controller instance and assign it to a property of the window. Finally, the view controller instance has a view, which automatically appears in the window. Thus, without your doing any work at all, you already have some objects that will persist for the lifetime of the app, including one that is the basis of your visible interface. Just as important, you have well-defined globally available ways of referring to all these objects. This means that, without writing any code, you already have access to some important objects, and you have an initial place to put any other objects with long lifetimes and any other visible bits of interface that your app may need. Design | 25 Summary and Conclusion As we imagine constructing an object-based program for performing a particular task, we bear in mind the nature of objects. There are types and instances. A type is a set of methods describing what all instances of that type can do (encapsulation of function‐ ality). Instances of the same type differ only in the value of their properties (maintenance of state). We plan accordingly. Objects 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. At the same time, no object is an island. Objects can cooperate with one another, namely by communicating with one another — that is, by sending messages to one another. The ways in which appropriate lines of communication can be arranged are innumer‐ able. Coming up with an appropriate arrangement — an architecture — for the coop‐ erative and orderly relationship between objects is one of the most challenging aspects of object-based programming. In iOS programming, you get a boost from the Cocoa framework, which provides an initial set of object types and a practical basic architec‐ tural scaffolding. Using object-based programming effectively to make a program do what you want it to do while keeping it clear and maintainable is itself an art; your abilities will improve with experience. Eventually, you may want to do some further reading on effective planning and construction of the architecture of an object-based program. I recommend in particular two classic, favorite books. Refactoring, by Martin Fowler (Addison-Wesley, 1999), describes why 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). 26 | Chapter 1: The Architecture of Swift CHAPTER 2 Functions Nothing is so characteristic of Swift syntax as the way you declare and call functions. Probably nothing is so important, either! As I said in Chapter 1, all your code is going to be in functions; they are where the action is. Function Parameters and Return Value A function is like one of those pseudo-scientific machines for processing miscellaneous stuff that you probably drew in your math textbook in elementary school. You know the ones I mean: with a funnel-like “hopper” at the top, and then a bunch of gears and cranks, and then a tube at the bottom where something is produced. A function is a machine like that: you feed some stuff in, the stuff is processed in accordance with what this particular machine does, and something is produced. The stuff that goes in is the input; what comes out is the output. More technically, a function that expects input has parameters; a function that produces output has a re‐ sult. For example, here’s a very silly but perfectly valid function that expects two Int values, adds them together, and produces that sum: func sum (x:Int, y:Int) -> Int { let result = x + y return result } The syntax here is very strict and well-defined, and you can’t use Swift unless you un‐ derstand it perfectly. Let’s pause to appreciate it in full detail; I’ll break the first line into pieces so that I can call them out individually: 27 func sum (x:Int, y:Int) -> Int { let result = x + y return result } The declaration starts with the keyword func, followed by the name of this function; here, it’s sum. This is the name that must be used in order to call the function — that is, in order to run the code that the function contains. The name of the function is followed by its parameter list. It consists, minimally, of parentheses. If this function takes parameters (input), they are listed inside the parentheses, separated by comma. Each parameter has a strict format: the name of the parameter, a colon, and the type of the parameter. Here, our sum function expects two parameters — an Int, to which it gives the name x, and another Int, to which it gives the name y. Observe that these names, x and y, are arbitrary and purely local (internal) to this function. They are different from any other x and y that may be used in other functions or at a higher level of scope. These names are defined so that the parameter values will have names by which they can be referred to in the code within the function body. The parameter declaration is, indeed, a kind of variable declaration: we are declaring variables x and y for use inside this function. After the parentheses is an arrow operator ->, followed by the type of value that this function will return. Then we have curly braces enclosing the body of the function — its actual code. Within the curly braces, in the function body, the variables defined as the parameter names have sprung to life, with the types specified in the parameter list. We know that this code won’t run unless this function is called and is actually passed values in its parameters. Here, the parameters are called x and y, so we can confidently use those values, referring to them by those names, secure in the knowledge that such values will exist and that they will be Int values, as specified by our parameter list. Not only the programmer, but also the compiler can be sure about this. If the function is to return a value, it must do so with the keyword return followed by that value. And, not surprisingly, the type of that value must match the type declared earlier for the return value (after the arrow operator). Here, I return a variable called result; it was created by adding two Int values together, so it is an Int, which is what this function is supposed to produce. If I 28 | Chapter 2: Functions tried to return a String (return "howdy"), or if I were to omit the return statement altogether, the compiler would stop me with an error. Note that the keyword return actually does two things. It returns the accompanying value, and it also halts execution of the function. It is permitted for more lines of code to follow a return statement, but the compiler will warn if this means that those lines of code can never be executed. The function declaration, then, before the curly braces, is a contract about what kinds of values will be used as input and about what kind of output will be produced. Ac‐ cording to this contract, the function expects a certain number of parameters, each of a certain type, and yields a certain type of result. Everything must correspond to this contract. The function body, inside the curly braces, can use the parameters as local variables. The returned value must match the declared return type. The same contract applies to code elsewhere that calls this function. Here’s some code that calls our sum function: let z = sum(4,5) Focus your attention on the right side of the equal sign — sum(4,5). That’s the function call. It uses the name of the function; it has parentheses; and inside those parentheses, separated by comma, are the values to be passed to each of the function’s parameters. Technically, these values are called arguments. Here, I’m using literal Int values, but I’m perfectly free to use Int variables instead; the only requirement is that I use things that have the correct type: let x = 4 let y = 5 let z = sum(y,x) In that code, I purposely used the names x and y for the variables whose values are passed as arguments, and I purposely reversed them in the call, to emphasize that these names have nothing to do with the names x and y inside the function parameter list and the function body. These names do not magically make their way to the function. Their values are all that matter; their values are the arguments. What about the value returned by the function? That value is magically substituted for the function call, at the point where the function call is made. It happens that in the preceding code, the result is 9. So the last line is exactly as if I had said: let z = 9 The programmer and the compiler both know exactly what type of thing this function returns, so they also know where it is and isn’t legal to call this function. It’s fine to call this function as the initialization part of the declaration of the variable z, just as it would Function Parameters and Return Value | 29 be to use 9 as the initialization part of that declaration: in both cases, we have an Int, and so z ends up being declared as an Int. But it would not be legal to write this: let z = sum(4,5) + "howdy" // compile error Because sum returns an Int, that’s the same as trying to add an Int to a String — and by default, you can’t do that in Swift. Observe that it is legal to ignore the value returned from a function call: sum(4,5) That code is legal; it causes neither a compile error nor a runtime error. It is also sort of silly in this particular situation, because we have made our sum function go to all the trouble of adding 4 and 5 for us and we have then thrown away the answer without capturing or using it. However, there are lots of situations where it is perfectly reasonable to ignore the value returned from a function call; in particular, the function may do other things in addition to returning a value, and the purpose of your call to that function may be those other things. If you can call sum wherever you can use an Int, and if the parameters of sum have to be Int values, doesn’t that mean you can call sum inside a call to sum? Of course it does! This is perfectly legal (and reasonable): let z = sum(4,sum(5,6)) The only argument against writing code like that is that you might confuse yourself and that it might make things harder to debug later. But, technically, it’s quite normal. Void Return Type and Parameters Let’s return to our function declaration. With regard to a function’s parameters and return type, there are two degenerate cases that allow us to express a function declaration more briefly: A function without a return type No law says that a function must return a value. A function may be declared to return no value. In that case, there are three ways to write the declaration: you can write it as returning Void; you can write it as returning (), an empty pair of paren‐ theses; or you can omit the arrow operator and the return type entirely. These are all legal: func say1(s:String) -> Void { println(s) } func say2(s:String) -> () { println(s) } func say3(s:String) { println(s) } If a function returns no value, then its body need not contain a return statement. If it does contain a return statement, its purpose will be purely to end execution of the function at that point. 30 | Chapter 2: Functions This return statement will usually consist of return and nothing else. However, Void (the type returned by a function that returns no value) is an actual type in Swift, and a function that returns no value technically does in fact return a value of this type, which may be expressed as the literal (). (I’ll explain in Chapter 3 what the literal () really represents.) Thus, it is legal for such a function to say return (); whether it says that or not, () is what it returns. Writing return () — or return;, with a semicolon — can be useful to disambiguate in case Swift thinks I’m trying to return whatever is on the next line. The call to a function that returns no value will usually be the only thing in its line of code, because no value is being returned that could be used by anything else in the line. Still, it is legal (though unlikely) to capture the returned () value in a variable typed as Void; for example: let pointless : Void = say1("howdy") A function without any parameters No law says that a function must take any parameters. If it doesn’t, the parameter list in the function declaration can contain Void or can be completely empty. But you can’t omit the parameter list parentheses themselves! They will be present in the function declaration, after the function’s name. So, these are both legal: func greet1(Void) -> String { return "howdy" } func greet2() -> String { return "howdy" } Obviously a function can lack both a return value and parameters; these are all ways of expressing the same thing: func greet1(Void) -> Void { println("howdy") } func greet2() -> () { println("howdy") } func greet3() { println("howdy") } I can’t emphasize too strongly that every function call must be accompanied by paren‐ theses. Those parentheses will be empty if the function takes no parameters, but they must be present. For example: greet1() Notice the parentheses! Function Signature If we ignore for a moment the parameter names in the function declaration, we can completely characterize a function by the types of its inputs and its output, using an expression like this: (Int, Int) -> Int Function Parameters and Return Value | 31 That in fact is a legal expression in Swift. It is the signature of a function. In this case, it’s the signature of our sum function. Of course, there can be other functions that take two Int parameters and return an Int — and that’s just the point. This signature char‐ acterizes all functions that have this number of parameters, of these types, and that return a result of this type. A function’s signature is, in effect, its type — the type of the function. The fact that functions have types will be of great importance later on. The signature of a function must include both the parameter list (without parameter names) and the return type, even if one or both of those is empty; so, the signature of a function that takes no parameters and returns no value may be written Void -> Void, or () -> (). External Parameter Names A function can externalize the names of its parameters. This means that the names have to appear in a call to the function, labeling each parameter that has an external name. There are several reasons why this is a good thing: • It clarifies the purpose of each parameter; each parameter name can give a clue as to how that parameter contributes to the behavior of the function. • It distinguishes one function from another; two functions can have the same name and signature but different external parameter names. • It helps Swift to interface with Objective-C and Cocoa, where method parameters have externalized names. To externalize a parameter name, put the external name before the internal parameter name, separated by a space, in the function declaration. The external name can be the same as the internal name, or different; if it is to be the same, a shorthand is provided: put a # before the internal name (and the space is then optional). Here’s the declaration for a function that concatenates a string with itself a given number of times: func repeatString(s:String, #times:Int) -> String { var result = "" for _ in 1...times { result += s } return result } That function’s first parameter has an internal name only, but its second parameter has an external name, which is to be the same as its internal name, namely times. And here’s how to call it: let s = repeatString("hi", times:3) 32 | Chapter 2: Functions In the call, as you can see, the external name precedes the argument, separated by a colon. As I’ve already said, a parameter’s external name can be different from its internal name. Let’s say that in our repeatString function we prefer to use times purely as an external name, with a different name — say, n — as the internal name. Then the declaration would look like this: func repeatString(s:String, times n:Int) -> String { var result = "" for _ in 1...n { result += s} return result } In the body of that function, there is now no times variable available; times is purely an external name, for use in the call. The internal name is n, and that’s the name the code refers to. The existence of external names doesn’t mean that the call can use a different pa‐ rameter order from the declaration. For example, our repeatString expects a String parameter and an Int parameter, in that order. The order can’t be different in the call, even though the label might appear to disambiguate which argument goes with which parameter. (In a moment, though, I’ll give an apparent exception to this rule.) Our repeatString function follows a common convention that the first parameter has no external name, while the others do. One reason for this convention is that the first parameter often doesn’t need an external name, because the function name usually clarifies sufficiently what the first parameter is for — as it does in the case of repeat- String (it repeats a string, which the first parameter should provide). Another reason — much more important in real life — is that this convention allows Swift functions to interface with Objective-C methods, which typically work this way. For example, here’s the Objective-C declaration for a Cocoa NSString method: - (NSString *)stringByReplacingOccurrencesOfString:(NSString *)target withString:(NSString *)replacement This method takes two NSString parameters and returns an NSString. The external name of the second parameter is obvious — it’s withString. But it’s a bit less obvious what the name of the first parameter is. On the one hand, you could argue that it’s string- ByReplacingOccurrencesOfString. On the other hand, that’s not really the name of the parameter; it’s more the name of the method. Actually, the formal name of the method is the whole thing: stringByReplacingOccurrencesOfString:withString:. But Swift function call syntax has parentheses distinguishing the function name from the external parameter names. So when Swift wants to call this Objective-C method, the first thing- External Parameter Names | 33 before-a-colon becomes the name of the function, before the parentheses, and the sec‐ ond thing-before-a-colon becomes the external name of the second parameter, inside the parentheses. A Swift String and a Cocoa NSString are automatically bridged to one another, so you can actually call this Cocoa method on a Swift String, like this: let s = "hello" let s2 = s.stringByReplacingOccurrencesOfString("ell", withString:"ipp") // s2 is now "hippo" The need for Swift to interface readily with Objective-C is so important, in fact, that Swift provides a special shorthand: if a function is a method (that is, if it is declared at the top level of the declaration of an enum, struct, or class), then this convention about which parameter names are externalized is followed automatically. You can declare separate external names for the parameters if you want to, but if you don’t, the internal names are externalized automatically, as if the name had been preceded by #, except for the first parameter. For example, suppose we declare a Dog class like this: class Dog { func say(s:String, times:Int) { for _ in 1...times { println(s) } } } We didn’t externalize any parameters, but times is not the first parameter, so it is au‐ tomatically externalized — because this function is a method. Thus, we can make a dog, and then make it bark three times, like this: let d = Dog() d.say("woof", times:3) If, for some reason, you don’t want a method parameter externalized, you can suppress its external name by preceding it with an underscore and a space: func say(s:String, _ times:Int) { Now this method would have to be called without labeling the second parameter: let d = Dog() d.say("woof", 3) Overloading In Swift, function overloading is legal (and common). This means that two functions with exactly the same name and parameter names can coexist as long as they have different signatures. Thus, for example, these two functions can coexist: 34 | Chapter 2: Functions func say (what:String) { } func say (what:Int) { } This point is particularly striking if you’re coming from Objective-C, where such over‐ loading is not legal. If you tried to declare those two versions of say in Objective-C, you’d get a “Duplicate declaration” compile error. And in fact, if you try to declare those two versions of say in a place where Objective-C can see them (see Appendix A for what that means), you’ll get a Swift compile error — “Method redeclares Objective-C method” — because such overloading is incompatible with Objective-C. The reason overloading works is that Swift has strict typing. A String is not an Int. Swift can tell them apart in the declaration, and Swift can tell them apart in a function call. Thus, Swift knows unambiguously that say("what") is different from say(1). It is also legal to have two functions with the same signature but different external parameter names: func say (what:String) { } func say (# what:String) { } But that’s not really a case of overloading; the functions have different external parameter names, so they are simply two different functions with two different names. Overloading works for the return type as well. Two functions with the same name, the same parameter names, and the same parameter types can have different return types. But the context of the call must disambiguate; that is, it must be clear what return type the caller is expecting. For example, these two functions can coexist (as long as you don’t let Objective-C see them): func say() -> String { return "one" } func say() -> Int { return 1 } But now you can’t call say like this: let result = say() // compile error The call is ambiguous, and the compiler tells you so. The call must be used in a context where the expected return type is clear. There are many ways to do that. For example, suppose we have another function that is not overloaded, and that expects a String parameter: Overloading | 35 func giveMeAString(s:String) { println("thanks!") } Then giveMeAString(say()) is legal, because only a String can go in this spot, so we must be calling the say that returns a String. Similarly: let result = say() + "two" Only a String can be “added” to a String, so this say() must be a String. Default Parameter Values A parameter can have a default value. This means that the caller can omit the parameter entirely, supplying no argument for it; the value will then be the default. To provide a default value, append = and the default value after the parameter type in the declaration: class Dog { func say(s:String, times:Int = 1) { for _ in 1...times { println(s) } } } Now, if you just want to say something once, you can call say plain and simple, and a times: parameter value of 1 will be supplied for you: let d = Dog() d.say("woof") // same as saying d.say("woof", times:1) If you want repetition, call say(times:): let d = Dog() d.say("woof", times:3) With default parameter values, it’s like getting two functions for the price of one. A parameter with a default value doesn’t have to have an external name, but by default it does; if you don’t supply one, the internal name is externalized. If you want the external name suppressed, you can suppress it explicitly by preceding the internal name with an underscore and a space. If multiple parameters with default values have a suppressed external name, then unlabeled arguments are applied to them in left-to-right order. If parameters with external names have default values, the requirement that they be called in order is lifted. For example, if a function at top level is declared like this: func doThing (a:Int = 0, b:Int = 3) {} then it is legal to call it like this: 36 | Chapter 2: Functions doThing(b:5, a:10) However, this might be an oversight — with Swift, it’s always hard to know, and certainly it would be illegal to call it like that if either parameter lacked a default value — so I would recommend that you not do that sort of thing: keep your call’s arguments ordered like the parameters in the declaration. Variadic Parameters The last (or only) parameter can be variadic. This means that the caller can supply as many values of this parameter’s type as desired, separated by comma; the function body will receive these values as an array. To indicate that a parameter is variadic, follow it by three dots, like this: func sayStrings(arrayOfStrings:String ...) { for s in arrayOfStrings { println(s) } } And here’s how to call it: sayStrings("hey", "ho", "nonny nonny no") Unfortunately there’s a hole in the Swift language: there’s no way to convert an array into a comma-separated list of arguments (comparable to splatting in Ruby). If what you’re starting with is an array of some type, you can’t use it where a varia‐ dic of that type is expected. Ignored Parameters A parameter whose local name is an underscore is ignored. The caller must supply an argument, but it has no name within the function body and cannot be referred to there. For example: func say(s:String, #times:Int, loudly _:Bool) { No loudly parameter makes its way into the function body, but the caller must still provide the third parameter: say("hi", times:3, loudly:true) The declaration needn’t have an externalized name for the ignored parameter: func say(s:String, #times:Int, _:Bool) { But the caller must still supply it: say("hi", times:3, true) Variadic Parameters | 37 What’s the purpose of this feature? It isn’t to satisfy the compiler, because the compiler doesn’t complain if a parameter is never referred to in the function body. I use it primarily as a kind of note to myself, a way of saying, “Yes, I know there is a parameter here, and I am deliberately not using it for anything.” Modifiable Parameters In the body of a function, a parameter is essentially a local variable. By default, it’s a variable implicitly declared with let. You can’t assign to it: func say(s:String, #times:Int, #loudly:Bool) { loudly = true // compile error: Cannot assign to 'let' value 'loudly' } If your code needs to assign to a parameter name within the body of a function, declare the parameter name explicitly with var: func say(s:String, #times:Int, var #loudly:Bool) { loudly = true // no problem } In that code, the parameter loudly is still just a local variable. Assigning to it doesn’t change the value of any variable outside the function body. However, it is also possible to configure a parameter in such a way that it does modify the value of a variable outside the function body! One typical use case here is that you want your function to return more than one result. For example, here I’ll write a rather advanced function that removes all occurrences of a given character from a given string and returns the number of occurrences that were removed: func removeFromString(var s:String, character c:Character) -> Int { var howMany = 0 while let ix = find(s,c) { s.removeRange(ix...ix) howMany += 1 } return howMany } And you call it like this: let s = "hello" let result = removeFromString(s, character:Character("l")) // 2 That’s nice, but we forgot one little thing: the original string, s, is still "hello". In the function body, we removed all occurrences of the character parameter from the local copy of the String parameter, but this change didn’t affect the original string. If we want our function to alter the original value passed to it as a parameter, we must make three changes: 38 | Chapter 2: Functions • The parameter we intend to modify must be declared inout. • At the point of the call, the variable holding the value we intend to tell the function to modify must be declared with var, not let. • Instead of passing the variable as an argument, we pass its address. This is done by preceding its name with an ampersand (&). Let’s make those changes. The declaration of removeFromString now looks like this: func removeFromString(inout s:String, character c:Character) -> Int { Our call to removeFromString now looks like this: var s = "hello" let result = removeFromString(&s, character:Character("l")) After the call, result is 2 and s is "heo". Notice the ampersand before name of s as the first argument in our function call! I like this requirement, because it forces us to ac‐ knowledge explicitly to the compiler, and to ourselves, that we’re about to do something potentially dangerous: we’re letting this function modify a value outside of itself. When a function with an inout parameter is called, the variable whose address was passed as argument to that parameter is always set, even if the function makes no changes to that parameter. You will often encounter variations on this pattern when you’re using Cocoa. The Cocoa APIs are written in C and Objective-C, so you probably won’t see the Swift term inout. You’ll probably see some mysterious type such as UnsafeMutablePointer. From your point of view as the caller, however, it’s the same thing. You’ll prepare a var variable and pass its address. For instance, consider the Core Graphics function CGRectDivide. A CGRect is a struct representing a rectangle. You call CGRectDivide when you want to slice a rectangle into two rectangles. CGRectDivide needs to tell you what both resulting rectangles are. So it needs to return two CGRects. Its strategy for doing this is to return no value as a result of the function; instead, it says, “You hand me two CGRects as parameters, and I will modify them for you so that they are the results of this operation.” Here’s how the declaration for CGRectDivide appears in Swift: func CGRectDivide(rect: CGRect, slice: UnsafeMutablePointer, remainder: UnsafeMutablePointer, amount: CGFloat, edge: CGRectEdge) Modifiable Parameters | 39 The second and third parameters are each an UnsafeMutablePointer to a CGRect. Here’s actual code from one of my apps where I call this function; look at how I treat the second and third parameters (and ignore the others): var arrow = CGRectZero var body = CGRectZero CGRectDivide(rect, &arrow, &body, Arrow.ARHEIGHT, .MinYEdge) I have to create two var CGRect variables beforehand, and they have to have some value even though that value will immediately be replaced by the call to CGRectDivide, so I assign them CGRectZero as a placeholder. Swift extends CGRect to provide a rectsByDividing method. This method, being a Swift method, does something that a Cocoa C function cannot do — it returns two values (as a tuple, see Chapter 3)! Thus, in real life, you could avoid calling CGRect- Divide in the first place. Still, you can call CGRectDivide, so it’s worth knowing how to do so. Sometimes, Cocoa will call your function with an UnsafeMutablePointer parameter, and you will want to change its value. To do this, you cannot assign directly to it, as we did with the inout variable s in our implementation of removeFromString. You’re talking to Objective-C, not to Swift, and this is an UnsafeMutablePointer, not an inout param‐ eter. The technique here is to assign to the UnsafeMutablePointer’s memory property. Here (without further explanation) is an example from my own code: func popoverPresentationController( popoverPresentationController: UIPopoverPresentationController, willRepositionPopoverToRect rect: UnsafeMutablePointer, inView view: AutoreleasingUnsafeMutablePointer) { view.memory = self.button2 rect.memory = self.button2.bounds } There is one very common situation where your function can modify a parameter without declaring it as inout — namely, when the parameter is an instance of a class. This is a special feature of classes, as opposed to the other two object type flavors, enum and struct. String isn’t a class; it’s a struct. That’s why we had to use inout in order to modify a String parameter. So I’ll illustrate by declaring a Dog class with a name property: class Dog { var name = "" } Here’s a function that takes a Dog instance parameter and a String, and sets that Dog instance’s name to that String. Notice that no inout is involved: 40 | Chapter 2: Functions func changeNameOfDog(d:Dog, to tostring:String) { d.name = tostring } Here’s how to call it. There’s no inout, so we pass a Dog instance directly: let d = Dog() d.name = "Fido" println(d.name) // "Fido" changeNameOfDog(d, to:"Rover") println(d.name) // "Rover" Observe that we were able to change a property of our Dog instance d, even though it wasn’t passed as an inout parameter, and even though it was declared originally with let, not var. This appears to be an exception to the rules about modifying parameters — but it isn’t really. It’s a feature of class instances, namely that they are themselves mutable. In changeNameOfDog, we didn’t actually attempt to modify the parameter it‐ self. To do that, we would have had to substitute a different Dog instance. That is not what we tried to do, and if we did want to do it, the Dog parameter would need to be declared inout (and d would have to be declared with var and we would have to pass its address as argument). Technically, we say that classes are reference types, whereas the other object type flavors are value types. When you pass an instance of a struct as an argument to a function, you effectively wind up with a separate copy of the struct instance. But when you pass an instance of a class as an argument to a function, you pass a reference to the class instance itself. I’ll discuss this topic in more detail in Chapter 4. Function In Function A function can be declared anywhere, including inside the body of a function. A function declared in the body of a function (also called a local function) is available to be called by later code within the same scope, but is completely invisible outside its scope. This feature is an elegant architecture for functions whose sole purpose is to assist an‐ other function. If only function A ever needs to call function B, function B might as well be packaged inside function A. Here’s a typical example from one of my apps (I’ve omitted everything except the struc‐ ture): func checkPair(p1:Piece, and p2:Piece) -> Path? { // ... func addPathIfValid(midpt1:Point,midpt2:Point) { // ... } for y in -1..._yct { Function In Function | 41 addPathIfValid((pt1.x,y),(pt2.x,y)) } for x in -1..._xct { addPathIfValid((x,pt1.y),(x,pt2.y)) } // ... } What I’m doing in the first for loop (for y) and what I’m doing in the second for loop (for x) are the same — but with a different set of starting values. We could write out the functionality in full inside each for loop, but that would be an unnecessary and confusing repetition. (Such a repetition would violate the principle often referred to as DRY, for “Don’t Repeat Yourself.”) To prevent that repetition, we could refactor the repeated code into an instance method to be called by both for loops, but that exposes publicly an instance method that doesn’t need such broad exposure, as it is called only by these two for loops inside checkPair. A local function is the perfect compromise. Sometimes, it’s worth using a local function even when that function will be called in only one place. Here’s another example from my code (it’s actually another part of the same function): func checkPair(p1:Piece, and p2:Piece) -> Path? { // ... lots of code here ... if arr.count > 0 { func distance(pt1:Point, pt2:Point) -> Double { // utility to learn physical distance between two points let deltax = pt1.0 - pt2.0 let deltay = pt1.1 - pt2.1 return sqrt(Double(deltax * deltax + deltay * deltay)) } for thisPath in arr { var thisLength = 0.0 for ix in 0..<(thisPath.count-1) { thisLength += distance(thisPath[ix],thisPath[ix+1]) } // ... more code ... } } // ... more code ... } Again, the structure is clear (even though the code uses some Swift features I haven’t discussed yet). Deep inside the function checkPair, a moment comes when I have an array (arr) of paths, and I need to know the length of every path. Each path is itself an array of points, so to learn its length, I need to sum the distances between each pair of points. To get the distance between a pair of points, I use the Pythagorean theorem. I could apply the Pythagorean theorem and express the calculation right there inside the for loop (for ix in...). Instead, I’ve expressed it as a separate function, distance, and inside the for loop all I do is call that function. 42 | Chapter 2: Functions There is no savings whatever in the number of lines of code; in fact, declaring distance makes my code longer! Nor, strictly speaking, am I in danger of repeating myself; the application of the Pythagorean theorem is repeated many times, but it occurs at only one spot in my code, namely inside this one for loop. Nevertheless, abstracting the code into a more general distance-calculation utility makes my code much clearer: in effect, I announce in general form what I’m about to do (“Look! I’m going to calculate distances between points now!”), and then I do it. The function name, distance, gives my code meaning; it is more understandable and maintainable than if I had directly written out the steps of the distance calculation inline. Recursion A function can call itself. This is called recursion. Recursion seems a little scary, rather like jumping off a cliff, because there seems to be a danger of creating an infinite loop; but if you write the function correctly, you will always have a “stopper” condition that handles the degenerate case and prevents the loop from being infinite: func countDownFrom(ix:Int) { println(ix) if ix > 0 { // stopper countDownFrom(ix-1) // recurse! } } Swift imposes a restriction on recursion: a function-in-function (a local function) must not call itself. In practice, this restriction will not prove onerous; just put the function at a higher level, such as the top level of the surrounding object declaration or the top level of the file. Function As Value If you’ve never used a programming language where functions are first-class citizens, perhaps you’d better sit down now, because what I’m about to tell you might make you feel a little faint: In Swift, a function is a first-class citizen. This means that a function can be used wherever a value can be used. For example, a function can be assigned to a variable; a function can be passed as an argument in a function call; a function can be returned as the result of a function. Swift has strict typing. You can only assign a value to a variable or pass a value into or out of a function if it is the right type of value. In order for a function to be used as a value, it needs to have a type. And indeed it does! Have you guessed what it is? A func‐ tion’s signature is its type. The chief purpose of using a function as a value is so that this function can later be called without a definite knowledge of what function it is. Recursion | 43 Here’s the world’s simplest (and silliest) example, just to show the syntax and structure: func doThis(f:()->()) { f() } That is a function doThis that takes one parameter (and returns no value). The param‐ eter, f, is itself a function; we know this because the type of the parameter is not given as Int or String or Dog, but is a function signature, ()->(), meaning (as you know) a function that takes no parameters and returns no value. The function doThis then calls the function f that it received as its parameter — that (as you know) is the meaning of the parentheses after the name of the parameter in the function body. How would you call the function doThis? To do so, you’d need to pass it a function as argument. One way to do that is to use the name of a function as the argument, like this: func whatToDo() { println("I did it") } doThis(whatToDo) First, we declare a function of the proper type — a function that takes no parameters and returns no value. Then, we call doThis, passing as argument the name of the function. Notice that we are not calling whatToDo here; we are passing it. Sure enough, this works: we pass whatToDo as argument to doThis; doThis calls the function that it receives as its parameter; and the string "I did it" appears in the console. But what’s the point of being able to do that? If our goal is to call whatToDo, why don’t we just call it? What’s useful about being able to tell some other function to call it? In the example I just gave, there is nothing useful about it; I was just showing you the syntax and structure. But in real life, this is a very valuable thing to do, because the other function may call the parameter function in some special way. For example, it might call it after doing other things, or at some later time. For example, one reason for encapsulating function-calling in a function is that it can reduce repetition and opportunity for error. Here’s a case from my own code. A common thing to do in Cocoa is to draw an image, directly, in code. This involves four steps: let size = CGSizeMake(15,15) UIGraphicsBeginImageContextWithOptions(size, false, 0) let p = UIBezierPath( roundedRect: CGRectMake(0,0,15,15), cornerRadius: 8) p.stroke() let result = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() Open an image context. Draw into the context. 44 | Chapter 2: Functions Extract the image. Close the image context. That’s terribly ugly. The sole purpose of all that code is to obtain result, the image; but that purpose is buried in all the other code. At the same time, the entire structure is boilerplate; every time I do this in any app, step 1, step 3, and step 4 are exactly the same. Moreover, I live in mortal fear of forgetting a step; for example, if I were to omit step 4 by mistake, the universe would explode. The only thing that’s different every time I draw is step 2. Thus, step 2 is the only part I should have to write out! The entire problem is solved by writing a utility function expressing the boilerplate: func imageOfSize(size:CGSize, whatToDraw:() -> ()) -> UIImage { UIGraphicsBeginImageContextWithOptions(size, false, 0) whatToDraw() let result = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return result } My imageOfSize utility is so useful that I declare it at the top level of a file, where all my files can see it. Thus, by default, none of its parameters have external names. To make an image, I perform step 2 (the actual drawing) in a function and pass that function as argument to the imageOfSize utility: func drawing() { let p = UIBezierPath( roundedRect: CGRectMake(0,0,15,15), cornerRadius: 8) p.stroke() } let image = imageOfSize(CGSizeMake(15,15), drawing) Now that is a beautifully expressive and clear way to turn drawing instructions into an image. The Cocoa API is full of situations where you’ll pass a function to be called by the runtime in some special way or at some later time. For example, when one view con‐ troller presents another, the method you’ll call takes three parameters — the view con‐ troller to be presented; a Bool stating whether you want the presentation to be animated; and a function that is to be called after the presentation has finished: let vc = UIViewController() func whatToDoLater() { println("I finished!") } self.presentViewController(vc, animated:true, completion:whatToDoLater) Function As Value | 45 The Cocoa documentation will often describe such a function as a handler, and will refer it as a block, because that’s the Objective-C syntactic construct needed here; in Swift, it’s a function, so just think of it as a function and pass a function. Some common Cocoa situations even involve passing two functions to a function. For instance, when you perform view animation, you’ll often pass one function prescribing the action to be animated and another function saying what to do afterwards: func whatToAnimate() { // self.myButton is a button in the interface self.myButton.frame.origin.y += 20 } func whatToDoLater(finished:Bool) { println("finished: \(finished)") } UIView.animateWithDuration( 0.4, animations: whatToAnimate, completion: whatToDoLater) That means: Change the frame origin (that is, the position) of this button in the interface, but do it over time (four-tenths of a second); and then, when that’s finished, print a log message in the console saying whether the animation was performed or not. To make function type specifiers clearer, take advantage of Swift’s typealias fea‐ ture to create a type alias giving a function type a name. The name can be descrip‐ tive, and the possibly confusing arrow operator notation is avoided. For example, if you say typealias VoidVoidFunction = () -> (), you can then say VoidVoid- Function wherever you need to specify a function type with that signature. Anonymous Functions Consider again the preceding example: func whatToAnimate() { // self.myButton is a button in the interface self.myButton.frame.origin.y += 20 } func whatToDoLater(finished:Bool) { println("finished: \(finished)") } UIView.animateWithDuration( 0.4, animations: whatToAnimate, completion: whatToDoLater) There’s a slight bit of ugliness in that code. I’m declaring functions whatToAnimate and whatToDoLater, just because I want to pass those functions in the last line. I don’t really need the names whatToAnimate and whatToDoLater for anything, except to refer to them in the last line; neither the names nor the functions will ever be used again. Therefore, it would be nice to be able to pass just the body of those functions without a declared name. 46 | Chapter 2: Functions That’s called an anonymous function, and it’s legal and common in Swift. To form an anonymous function, you do two things: 1. Create the function body itself, including the surrounding curly braces, but with no function declaration. 2. If necessary, express the function’s parameter list and return type as the first line inside the curly braces, followed by the keyword in. Let’s practice by transforming our named function declarations into anonymous func‐ tions. Here’s the named function declaration for whatToAnimate: func whatToAnimate() { self.myButton.frame.origin.y += 20 } Here’s an anonymous function that does the same thing. Notice how I’ve moved the parameter list and return type inside the curly braces: { () -> () in self.myButton.frame.origin.y += 20 } Here’s the named function declaration for whatToDoLater: func whatToDoLater(finished:Bool) { println("finished: \(finished)") } Here’s an anonymous function that does the same thing: { (finished:Bool) -> () in println("finished: \(finished)") } Now that we know how to make anonymous functions, let’s use them. In our call to animateWithDuration, the point where we need the functions is the point where we’re passing arguments to animateWithDuration. We can create and pass anonymous func‐ tions right at that point, like this: UIView.animateWithDuration(0.4, animations: { () -> () in self.myButton.frame.origin.y += 20 }, completion: { (finished:Bool) -> () in println("finished: \(finished)") }) Anonymous Functions | 47 Anonymous functions are very commonly used in Swift, so make sure you can read and write that code! Anonymous functions, in fact, are so common and so important, that some shortcuts for writing them are provided: Omission of the return type If the anonymous function’s return type is known to the compiler, you can omit the arrow operator and the specification of the return type: UIView.animateWithDuration(0.4, animations: { () in self.myButton.frame.origin.y += 20 }, completion: { (finished:Bool) in println("finished: \(finished)") }) Omission of the in line when there are no parameters If the anonymous function takes no parameters, and if the return type can be omit‐ ted, the in line itself can be omitted entirely: UIView.animateWithDuration(0.4, animations: { self.myButton.frame.origin.y += 20 }, completion: { (finished:Bool) in println("finished: \(finished)") }) Omission of the parameter types If the anonymous function takes parameters and their types are known to the com‐ piler, the types can be omitted: UIView.animateWithDuration(0.4, animations: { self.myButton.frame.origin.y += 20 }, completion: { (finished) in println("finished: \(finished)") }) Omission of the parentheses If the parameter types are omitted, the parentheses around the parameter list can be omitted: UIView.animateWithDuration(0.4, animations: { self.myButton.frame.origin.y += 20 }, completion: { finished in println("finished: \(finished)") }) Omission of the in line even when there are parameters If the return type can be omitted, and if the parameter types are known to the compiler, you can omit the in line and refer to the parameters directly within the 48 | Chapter 2: Functions body of the anonymous function by using the magic names $0, $1, and so on, in order: UIView.animateWithDuration(0.4, animations: { self.myButton.frame.origin.y += 20 }, completion: { println("finished: \($0)") }) Omission of the parameter names If your anonymous function body doesn’t need the parameters, you can ignore the parameters by substituting an underscore for their names in the in line: UIView.animateWithDuration(0.4, animations: { self.myButton.frame.origin.y += 20 }, completion: { _ in println("finished!") }) But note that if the anonymous function takes parameters, you must use them somehow. You can omit the in line and use the parameters by the magic names $0 and so on, or you can keep the in line and ignore the parameters with under‐ scores, but you can’t omit the in line altogether and not use the parameters by their magic names! If you do, your code won’t compile — and the error message that Swift gives you will be very, very confusing. Omission of the calling function parameter name If, as will just about always by case, your anonymous function is the last parameter being passed in this function call, you can close the function call with a right pa‐ renthesis before this last parameter, and then put just the anonymous function body without any parameter name (this is called a trailing function): UIView.animateWithDuration(0.4, animations: { self.myButton.frame.origin.y += 20 }) { _ in println("finished!") } Omission of the calling function parentheses If you use the trailing function syntax, and if the function you are calling takes no parameters other than the function you are passing to it, you can omit the empty parentheses from the call. To illustrate, I’ll declare and call a different function: Anonymous Functions | 49 func doThis(f:()->()) { f() } doThis { // no parentheses! println("Howdy") } This is the only situation in which you can omit the parentheses from a function call! Omission of the keyword return If the anonymous function body consists of exactly one statement and that statement consists of returning a value with the keyword return, the keyword return can be omitted. To put it another way, in a context that expects a function that returns a value, if an anonymous function body consists of exactly one statement, Swift assumes that this statement is an expression whose value is to be returned from the anonymous function: func sayHowdy() -> String { return "Howdy" } func performAndPrint(f:()->String) { let s = f() println(s) } performAndPrint { sayHowdy() // meaning: return sayHowdy() } When writing anonymous functions, you will frequently find yourself taking advantage of all the omissions you are permitted. In addition, you’ll often shorten the layout of the code (though not the code itself) by putting the whole anonymous function together with the function call on one line. Thus, Swift code involving anonymous functions can be extremely compact. Here’s a typical example. We start with an array of Int values and generate a new array consisting of all those values multiplied by 2, by calling the map instance method. The map method of an array takes a function that takes one parameter, and returns a value, of the same type as the array’s elements; here, our array is made of Int values, so we need to pass to the map method a function that takes one Int parameter and returns an Int. We could write out the whole function, like this: let arr = [2, 4, 6, 8] func doubleMe(i:Int) -> Int { return i*2 } let arr2 = arr.map(doubleMe) // [4, 8, 12, 16] That, however, is not very Swifty. We don’t need the name doubleMe for anything else, so this may as well be an anonymous function. Its return type is known, so we don’t 50 | Chapter 2: Functions need to specify that. Its parameter type is known, so we don’t need to specify that. There’s just one parameter and we are going to use it, so we don’t need the in line as long we refer to the parameter as $0. Our function body consists of just one statement, and it is a return statement, so we can omit return. And map doesn’t take any other parameters, so we can omit the parentheses and follow the name directly with the anonymous func‐ tion parameter: let arr = [2, 4, 6, 8] let arr2 = arr.map {$0*2} Define-and-Call A pattern that’s surprisingly common in Swift is to define an anonymous function and call it, all in one move: { // ... code goes here }() Why would anyone do such a thing? If you want to run some code, you can just run it; why would you embed it in a deeper level as a function body, only to turn around and run that function body immediately? I sometimes do this as a way of defining a deeper scope inside a function body. A deeper scope can be useful, for example, when you want to declare some local variables that you don’t need elsewhere in the surrounding function. Unlike C, Swift won’t let you arbitrarily create a deeper scope with curly braces; but it will let you define and call an anonymous local function: func myFunc() { // ... some code here ... { () -> () in // ... this is a deeper scope ... }() // ... more code here ... } (You might have to put a semicolon at the end of the previous line, so that Swift doesn’t think this is a trailing function.) Also, an anonymous function can be a good way to make your code less imperative and more, well, functional: an action can be taken at the point where it is needed, rather than in a series of preparatory steps. Here’s a common Cocoa example: we create and configure an NSMutableParagraphStyle and then use it in a call to add- Attribute:value:range: (content is an NSMutableAttributedString): Define-and-Call | 51 let para = NSMutableParagraphStyle() para.headIndent = 10 para.firstLineHeadIndent = 10 // ... more configuration of para ... content.addAttribute( NSParagraphStyleAttributeName, value:para, range:NSMakeRange(0,1)) I find that code ugly. We don’t need para except to pass it as the value: argument within the call to addAttribute:..., so it would be much nicer to create and configure it right there within the call to addAttribute:.... Swift lets us do just that. I much prefer this way of writing the same code: content.addAttribute( NSParagraphStyleAttributeName, value: { let para = NSMutableParagraphStyle() para.headIndent = 10 para.firstLineHeadIndent = 10 // ... more configuration of para ... return para }(), range:NSMakeRange(0,1)) Closures Swift functions are closures. This means they can capture references to external variables in scope within the body of the function. What do I mean by that? Well, recall from Chapter 1 that code in curly braces constitutes a scope, and this code can “see” variables and functions declared in a surrounding scope: class Dog { var whatADogSays = "woof" func bark() { println(self.whatADogSays) } } In that code, the body of the function bark refers to a variable whatADogSays that is declared outside the body of the function. It is in scope for the body of the function — the code inside the body of bark can see whatADogSays, and makes an explicit reference to it. So far, so good; but we now know that the function bark can be passed as a value. In effect, it can travel from one environment to another! When it does, what happens to that reference to whatADogSays? Let’s find out: 52 | Chapter 2: Functions func doThis(f : Void -> Void) { f() } let d = Dog() doThis(d.bark) // woof We run that code, and "woof" appears in the console. Perhaps that result doesn’t seem very surprising to you. But think about it. We do not directly call bark. We make a Dog instance and pass its bark function as a value into the function doThis. There, it is called. Now, whatADogSays is an instance property of a particular Dog. Inside the function doThis there no whatADogSays. Indeed, inside the function doThis there is no Dog instance! Nevertheless the call f() still works. The function d.bark, as it is passed around, can still see that variable whatADogSays, declared outside itself, even though it is called in an environment where there is no longer any Dog instance and no longer any instance property whatADogSays. The bark function, it appears, is carrying its original whatADogSays reference with it — even when bark isn’t called until it has been passed into some other environment entirely. So, by “capture” I mean that when a function is passed around as a value, it carries with it any variables outside itself that it refers to inside itself. That is what makes a function a closure. You’ll probably take advantage of the fact that functions are closures without even being conscious of it. Recall this earlier example, where we animate the repositioning of a button in our interface: UIView.animateWithDuration(0.4, animations: { self.myButton.frame.origin.y += 20 }) { _ in println("finished!") } It seems innocent enough; but concentrate on the second line, the anonymous function passed as argument to the animations: parameter. You should be saying: Really? Way off in the land of Cocoa, when this anonymous function is executed at some future time to start the animation, Cocoa is going to be able to find myButton, an object referred to as a property of self, way back over here in my code? Yes, Cocoa will be able to do that, because a function is a closure. The reference to this property is captured and maintained by the anonymous function; thus, when the anonymous function is actually called, it works and the button moves. How Closures Improve Code Once you understand that functions are closures, you can start writing your own code that takes advantage of this fact to improve your code’s syntax. Closures can help make Closures | 53 your code more general, and hence more useful. For instance, recall my earlier example of a function that takes drawing instructions and performs them to generate an image: func imageOfSize(size:CGSize, whatToDraw:() -> ()) -> UIImage { UIGraphicsBeginImageContextWithOptions(size, false, 0) whatToDraw() let result = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return result } Earlier, we called that function like this: func drawing() { let p = UIBezierPath( roundedRect: CGRectMake(0,0,15,15), cornerRadius: 8) p.stroke() } let image = imageOfSize(CGSizeMake(15,15), drawing) We now know, however, that we don’t need to declare the drawing function separately. We can call imageOfSize with an anonymous function: let image = imageOfSize(CGSizeMake(15,15)) { let p = UIBezierPath( roundedRect: CGRectMake(0,0,15,15), cornerRadius: 8) p.stroke() } That’s much neater. There remains, however, an annoying repetition. This is a call to create an image of a given size consisting of a rounded rectangle of that size. We are repeating the size; the pair of numbers 15,15 appears twice. That’s silly. Let’s prevent the repetition by putting the size into a variable at the outset: let sz = CGSizeMake(15,15) let image = imageOfSize(sz) { let p = UIBezierPath( roundedRect: CGRect(origin:CGPointZero, size:sz), cornerRadius: 8) p.stroke() } The variable sz, declared outside our anonymous function at a higher level, is visible inside it. Thus we can refer to it inside the anonymous function — and we do so. The anonymous function is a function. Therefore it is a closure. Therefore the anonymous function captures that reference, and carries it on into the call to imageOfSize. When imageOfSize calls whatToDraw and whatToDraw refers to a variable sz, there’s no prob‐ lem, even though there is no sz anywhere in the neighborhood of imageOfSize. Now let’s go further. So far, we’ve been hard-coding the size of the desired rounded rectangle. Imagine, though, that creating images of rounded rectangles of various sizes 54 | Chapter 2: Functions is something we do often. It would make sense to package this code up as a function, where sz is not a fixed value but a parameter; the function will then return the image: func makeRoundedRectangle(sz:CGSize) -> UIImage { let image = imageOfSize(sz) { let p = UIBezierPath( roundedRect: CGRect(origin:CGPointZero, size:sz), cornerRadius: 8) p.stroke() } return image } Observe that our code still works. Here, sz in the anonymous function refers to the sz parameter that arrives into the surrounding function makeRoundedRectangle. A pa‐ rameter of the surrounding function is a variable external to and in scope within the anonymous function. The anonymous function is a closure, so it captures the reference to that parameter. Our code is becoming beautifully compact. To call makeRoundedRectangle, supply a size; an image is returned. Thus, I can perform the call, obtain the image, and put that image into my interface, all in one move, like this: self.myImageView.image = makeRoundedRectangle(CGSizeMake(45,20)) Function Returning Function But now let’s go even further! Instead of returning an image, our function can return a function that makes rounded rectangles of the specified size. If you’ve never seen a func‐ tion returned as a value from a function, you may now be gasping for breath. But a function, after all, can be used as a value. We have already passed a function into a function as an argument; now we are going to receive a function from a function call as its result: func makeRoundedRectangleMaker(sz:CGSize) -> () -> UIImage { func f () -> UIImage { let im = imageOfSize(sz) { let p = UIBezierPath( roundedRect: CGRect(origin:CGPointZero, size:sz), cornerRadius: 8) p.stroke() } return im } return f } Let’s analyze that code slowly: Closures | 55 The declaration is the hardest part. What on earth is the type (signature) of this function makeRoundedRectangleMaker? It is (CGSize) -> () -> UIImage. That expression has two arrow operators. To understand it, keep in mind that everything after each arrow operator is the type of a returned value. So make- RoundedRectangleMaker is a function that takes a CGSize parameter and returns a () -> UIImage. Okay, and what’s a () -> UIImage? We already know that: it’s a function that takes no parameters and returns a UIImage (an image). So make- RoundedRectangleMaker is a function that takes a CGSize parameter and returns a function — a function that itself, when called with no parameters, will return a UIImage. Now here we are in the body of the function makeRoundedRectangleMaker, and our first step is to declare a function (a function-in-function, or local function) of precisely the type we intend to return, namely, one that takes no parameters and returns a UIImage. Here, we’re naming this function f. The way this function works is simple and familiar: it calls imageOfSize, passing it an anonymous function that makes an image of a rounded rectangle (im) — and then it returns the image. Finally, we return the function we just made (f). We have thus fulfilled our contract: we said we would return a function that takes no parameters and returns a UIImage, and we do so. But perhaps you are still gazing open-mouthed at makeRoundedRectangleMaker, won‐ dering how you would ever call it and what you would get if you did. Let’s try it: let maker = makeRoundedRectangleMaker(CGSizeMake(45,30)) What is the variable maker after that code runs? It’s a function — a function that takes no parameters and that, when called, produces the image of a rounded rectangle of size 45,30. You don’t believe me? I’ll prove it — by calling the function that is now the value of maker: let maker = makeRoundedRectangleMaker(CGSizeMake(45,30)) self.myImageView.image = maker() Now that you’ve gotten over your stunned surprise at the notion of a function that produces a function as its result, turn your attention once again to the implementation of makeRoundedRectangleMaker and let’s analyze it again, a different way. Remember, I didn’t write that function to show you that a function can produce a function. I wrote it to illustrate closures! Let’s think about how the environment gets captured: func makeRoundedRectangleMaker(sz:CGSize) -> () -> UIImage { func f () -> UIImage { let im = imageOfSize(sz) { // * let p = UIBezierPath( roundedRect: CGRect(origin:CGPointZero, size:sz), // * 56 | Chapter 2: Functions cornerRadius: 8) p.stroke() } return im } return f } The function f takes no parameters. Yet, twice within the function body of f (I’ve marked the places with asterisk comments), there are references to a size value sz. The body of the function f can see sz, the incoming parameter to the surrounding function make- RoundedRectangleMaker, because it is in a surrounding scope. The function f cap‐ tures the reference to sz at the time makeRoundedRectangleMaker is called, and keeps that reference when f is returned and assigned to maker: let maker = makeRoundedRectangleMaker(CGSizeMake(45,30)) That is why maker is now a function that, when it is called, creates and returns an image of the particular size 45,30 even though it itself will be called with no parameters. We have baked the knowledge of what size of image to produce into maker. Looking at it another way, makeRoundedRectangleMaker is a factory for creating a whole family of functions similar to maker, each of which produces an image of one particular size. That’s a dramatic illustration of the power of closures. Before I leave makeRoundedRectangleMaker, I’d like to rewrite it in a Swiftier fashion. Within f, there is no need to create im and then return it; we can return the result of calling imageOfSize directly: func makeRoundedRectangleMaker(sz:CGSize) -> () -> UIImage { func f () -> UIImage { return imageOfSize(sz) { let p = UIBezierPath( roundedRect: CGRect(origin:CGPointZero, size:sz), cornerRadius: 8) p.stroke() } } return f } But there is no need to declare f and then return it either; it can be an anonymous function and we can return it directly: func makeRoundedRectangleMaker(sz:CGSize) -> () -> UIImage { return { return imageOfSize(sz) { let p = UIBezierPath( roundedRect: CGRect(origin:CGPointZero, size:sz), cornerRadius: 8) Closures | 57 p.stroke() } } } But our anonymous function consists of just one statement, returning the result of the call to imageOfSize. (The anonymous function parameter to imageOfSize is written over multiple lines, but the imageOfSize call itself is still just one Swift statement.) Thus there is no need to say return: func makeRoundedRectangleMaker(sz:CGSize) -> () -> UIImage { return { imageOfSize(sz) { let p = UIBezierPath( roundedRect: CGRect(origin:CGPointZero, size:sz), cornerRadius: 8) p.stroke() } } } Closure Setting a Captured Variable The power that a closure gets through its ability to capture its environment is even greater than I’ve shown so far. If a closure contains a reference to a variable outside itself, and if that variable is settable, the closure can set the variable. For example, at the top level of my Swift file I’ve declared this simple function. All it does is to accept a function that takes an Int parameter, and to call that function with an argument of 100: func pass100 (f:(Int)->()) { f(100) } Now, look closely at this code and try to guess what will happen when we run it: var x = 0 println(x) func setX(newX:Int) { x = newX } pass100(setX) println(x) The first println call obviously produces 0. The second println call produces 100! The pass100 function has reached into my code and changed the value of my variable x! That’s because the function that I passed to pass100 contains a reference to x; not only does it contain it, but it captures it; not only does it capture it, but it sets its value. That 58 | Chapter 2: Functions x is my x. Thus, pass100 was able to set my x just as readily as I would have set it by calling setX directly. Closure Preserving Its Captured Environment When a closure captures its environment, it preserves that environment even if nothing else does. Here’s an example calculated to blow your mind — a function that modifies a function: func countAdder(f:()->()) -> () -> () { var ct = 0 return { ct = ct + 1 println("count is \(ct)") f() } } The function countAdder accepts a function as its parameter and returns a function as its result. The function that it returns calls the function that it accepts, with a little bit added: it increments a variable and reports the result. So now try to guess what will happen when we run this code: func greet () { println("howdy") } let countedGreet = countAdder(greet) countedGreet() countedGreet() countedGreet() What we’ve done here is to take a function greet, which prints "howdy", and pass it through countAdder. What comes out the other side of countAdder is a new function, which we’ve named countedGreet. We then call countedGreet three times. Here’s what appears in the console: count is 1 howdy count is 2 howdy count is 3 howdy Clearly, countAdder has added to the functionality of the function that was passed into it the ability to report how many times it is called. Now ask yourself: Where on earth is the variable that maintains this count? Inside countAdder, it was a local variable ct. But it isn’t declared inside the anonymous function that countAdder returns. That’s delib‐ erate! If it were declared inside the anonymous function, we would be setting ct to 0 every time countedGreet is called — we wouldn’t be counting. Instead, ct is initialized Closures | 59 to 0 once and then captured by the anonymous function. Thus, this variable is preserved as part of the environment of countedGreet — it is outside countedGreet in some mys‐ terious environment-preserving world, so that it can be incremented every time countedGreet is called. That’s the power of closures. That example, with its maintenance of environmental state, can also help us to demon‐ strate that functions are reference types. To show what I mean, I’ll start with a contrasting situation. Two separate calls to a function factory method produce two different func‐ tions, as you would expect: let countedGreet = countAdder(greet) let countedGreet2 = countAdder(greet) countedGreet() // count is 1 countedGreet2() // count is 1 The two functions countedGreet and countedGreet2, in that code, are maintaining their counts separately. But mere assignment or parameter passing results in a new reference to the same function: let countedGreet = countAdder(greet) let countedGreet2 = countedGreet countedGreet() // count is 1 countedGreet2() // count is 2 Curried Functions Return once more to makeRoundedRectangleMaker: func makeRoundedRectangleMaker(sz:CGSize) -> () -> UIImage { return { imageOfSize(sz) { let p = UIBezierPath( roundedRect: CGRect(origin:CGPointZero, size:sz), cornerRadius: 8) p.stroke() } } } There’s something I don’t like about this method: the size of the rounded rectangle that it creates is a parameter (sz), but the cornerRadius of the rounded rectangle is hard- coded as 8. I’d like the ability to specify a value for the corner radius as well. I can think of two ways to do it. One is to give makeRoundedRectangleMaker itself another param‐ eter: func makeRoundedRectangleMaker(sz:CGSize, rad:CGFloat) -> () -> UIImage { return { imageOfSize(sz) { let p = UIBezierPath( roundedRect: CGRect(origin:CGPointZero, size:sz), 60 | Chapter 2: Functions cornerRadius: rad) p.stroke() } } } And we would then call it like this: let maker = makeRoundedRectangleMaker(CGSizeMake(45,30), rad:20) But there’s another way. The function that we are returning from makeRounded- RectangleMaker takes no parameters. Instead, it could take the extra parameter: func makeRoundedRectangleMaker(sz:CGSize) -> (CGFloat) -> UIImage { return { rad in imageOfSize(sz) { let p = UIBezierPath( roundedRect: CGRect(origin:CGPointZero, size:sz), cornerRadius: rad) p.stroke() } } } Now makeRoundedRectangleMaker returns a function that, itself, takes one parameter, so we must remember to supply that when we call it: let maker = makeRoundedRectangleMaker(CGSizeMake(45,30)) self.myImageView.image = maker(14) If we don’t need to conserve maker for anything, we can of course do all that in one line — a function call that yields a function which we immediately call: self.myImageView.image = makeRoundedRectangleMaker(CGSizeMake(45,30))(14) When a function returns a function that takes a parameter in this way, it is called a curried function (not because of the food or because of a horse comb, but after the computer scientist Haskell Curry). It turns out that there’s a Swift shorthand for writing the declaration of a curried func‐ tion. You can omit the first arrow operator and the top-level anonymous function, like this: func makeRoundedRectangleMaker(sz:CGSize)(rad:CGFloat) -> UIImage { return imageOfSize(sz) { let p = UIBezierPath( roundedRect: CGRect(origin:CGPointZero, size:sz), cornerRadius: rad) p.stroke() } } Curried Functions | 61 The expression (sz:CGSize)(rad:CGFloat) — two parameter lists in a row, with no arrow operator between them — means “Swift, please curry this function for me.” Swift here does all the work of dividing our function into two functions, one (makeRounded- RectangleMaker) taking a CGSize parameter and another (the anonymous result) tak‐ ing a CGFloat. Our code looks as if makeRoundedRectangleMaker returns a UIImage, but it actually returns a function that returns a UIImage just as before. And we can call it in basically just the same two ways as before; in two stages, like this: let maker = makeRoundedRectangleMaker(CGSizeMake(45,30)) self.myImageView.image = maker(rad:14) Or in a single line, like this: self.myImageView.image = makeRoundedRectangleMaker(CGSizeMake(45,30))(rad:14) 62 | Chapter 2: Functions CHAPTER 3 Variables and Simple Types This chapter goes into detail about declaration and initialization of variables. It then discusses all the primary built-in Swift simple types. (I mean “simple” as opposed to collections; the primary built-in collection types are discussed at the end of Chapter 4.) Variable Scope and Lifetime Recall, from Chapter 1, that a variable is a named shoebox of a single well-defined type. Every variable must be explicitly and formally declared. To put an object into the shoe‐ box, thus causing the variable name to refer to that object, you assign the object to the variable. (As we now know from Chapter 2, a function, too, has a type, and can be assigned to a variable.) Aside from the convenience of giving a reference a name, a variable, by virtue of the place where it is declared, endows its referent with a particular scope (visibility) and lifetime; assigning something to a variable is a way of ensuring that it can be seen by code that needs to see it and that it persists long enough to serve its purpose. In the structure of a Swift file (see Example 1-1), a variable can be declared virtually anywhere. It will be useful to distinguish several levels of variable scope and lifetime: Global variables A global variable, or simply a global, is a variable declared at the top level of a Swift file. (In Example 1-1, the variable one is a global.) A global variable lives as long as the file lives. That means it lives forever. Well, not strictly forever, but as long as the program runs. A global variable is visible everywhere — that’s what “global” means. It is visible to all code within the same file, because it is at top level, so any other code in the same file must be at the same level or at a lower, contained level of scope. Moreover, it is 63 visible (by default) to all code within any other file in the same module, because Swift files in the same module can automatically see one another, and hence can see one another’s top levels. Properties A property is a variable declared at the top level of an object type declaration (an enum, struct, or class; in Example 1-1, the three name variables are properties). There are two kinds of properties: instance properties and static/class properties. Instance properties By default, a property is an instance property. Its value can differ for each in‐ stance of this object type. Its lifetime is the same as the lifetime of the instance. Recall from Chapter 1 that an instance comes into existence when it is created (by instantiation); the subsequent lifetime of the instance depends on the life‐ time of the variable to which the instance itself is assigned. Static/class properties A property is a static/class property if its declaration is preceded by the keyword static or class. (I’ll go into detail about those terms in Chapter 4.) Its lifetime is the same as the lifetime of the object type. If the object type is declared at the top level of a file, or at the top level of another object type that is declared at top level, that means it lives forever (as long as the program runs). A property is visible to all code inside the object declaration. For example, an object’s methods can see that object’s properties. Such code can refer to the property using dot-notation with self, and I always do this as a matter of style, but self can usually be omitted except for purposes of disambiguation. An instance property is also visible (by default) to other code, provided the other code has a reference to this instance; in that case, the property can be referred to through dot-notation with the instance reference. A static/class property is visible (by default) to other code that can see the name of this object type; in that case, it can be referred to through dot-notation with the object type. Local variables A local variable is a variable declared inside a function body. (In Example 1-1, the variable two is a local variable.) A local variable lives only as long as its surrounding curly-brace scope lives: it comes into existence when the path of execution passes into the scope and reaches the variable declaration, and it goes out of existence when the path of execution comes to the end of (or otherwise leaves) the scope. Local variables are sometimes called automatic, to signify that they come into and go out of existence automatically. A local variable can be seen only by subsequent code within the same scope (in‐ cluding a subsequent deeper scope within the same scope). 64 | Chapter 3: Variables and Simple Types Variable Declaration As I explained in Chapter 1, a variable is declared with let or var: • With let, the variable becomes a constant — its value can never be changed after the first assignment of a value (initialization). • With var, the variable is a true variable, and its value can be changed by subsequent assignment. A variable’s type, however, can never be changed. A variable declared with var can be given a different value, but that value must conform to the variable’s type. Thus, when a variable is declared, it must be given a type, which it will have forever after. You can give a variable a type explicitly or implicitly: Explicit variable type declaration After the variable’s name in the declaration, add a colon and the name of the type: var x : Int Implicit variable type by initialization If you initialize the variable as part of the declaration, and if you provide no explicit type, Swift will infer its type, based on the value with which it is initialized: var x = 1 // and now x is an Int It is perfectly possible to declare a variable’s type explicitly and assign it an initial value, all in one move: var x : Int = 1 In that example, the explicit type declaration is superfluous, because the type (Int) would have been inferred from the initial value. Sometimes, however, providing an explicit type, even while also assigning an initial value, is not superfluous. Here are the main situations where that’s the case: Swift’s inference would be wrong A very common case in my own code is when I want to provide the initial value as a numeric literal. Swift will infer either Int or Double, depending on whether the literal contains a decimal point. But there are a lot of other numeric types! When I mean one of those, I will provide the type explicitly, like this: let separator : CGFloat = 2.0 Swift warns if you don’t When talking to Cocoa, you will often receive a value as an AnyObject (an Objective-C id; I’ll talk more about this in Chapter 4). If you use such a value to initialize a variable, the Swift compiler warns that this variable will be “inferred to have type AnyObject, which may be unexpected.” Warnings aren’t harmful, but I Variable Declaration | 65 like to be rid of them, so I acknowledge to the compiler that I know this is an AnyObject, by declaring the type explicitly: let n : AnyObject = arr[0] // arr is a Cocoa NSArray Swift can’t infer the type This situation arises for me most often when the initial value itself requires type inference on Swift’s part. In other words, in this situation, type inference runs the other way: the explicit variable type is what allows Swift to infer the type of the initial value. A very common case involves enums, which I haven’t discussed yet. This is legal but long-winded and repetitious: let opts = UIViewAnimationOptions.Autoreverse | UIViewAnimationOptions.Repeat I can make that code shorter and cleaner if Swift knows in advance that opts will be a UIViewAnimationOptions enum: let opts : UIViewAnimationOptions = .Autoreverse | .Repeat The programmer can’t infer the type I frequently include a superfluous explicit type declaration for clarity — that is, as a kind of note to myself. Here’s an example from my own code: let duration : CMTime = track.timeRange.duration In that code, track is an AVAssetTrack. Swift knows perfectly well that the duration property of an AVAssetTrack’s timeRange property is a CMTime. But I don’t! In order to remind myself of that fact, I’ve shown the type explicitly. Because explicit variable typing is possible, a variable doesn’t have to be initialized when it is declared. It is legal to write this: var x : Int Starting with Swift 1.2, that sort of thing is legal even for a constant: let x : Int Now x is an empty shoebox — an Int variable without a value. I strongly urge you, however, not to do that with a local variable if you can possibly avoid it. It isn’t a disaster — the Swift compiler will stop you from trying to use a variable that has never been assigned a value — but it’s not a good habit. The exception that proves the rule is what we might call conditional initialization. Sometimes, we don’t know a variable’s initial value until we’ve performed some sort of conditional test. The variable itself, however, can be declared only once; so it must be declared in advance and conditionally initialized afterwards. We could give the variable a fake initial value as part of its declaration, but this might be misleading — and it won’t work if this variable is a constant, because giving it a fake initial value will prevent us 66 | Chapter 3: Variables and Simple Types from subsequently giving it a real value. So it is actually better to leave the variable momentarily uninitialized. Such code will have a structure similar to this: let timed : Bool if val == 1 { timed = true } else if val == 2 { timed = false } A similar situation arises when a variable’s address is to be passed as argument to a function. Here, the variable must be declared and initialized beforehand, even if the initial value is fake. Recall this real-life example from Chapter 2: var arrow = CGRectZero var body = CGRectZero CGRectDivide(rect, &arrow, &body, Arrow.ARHEIGHT, .MinYEdge) After that code runs, our two CGRectZero values will have been replaced; they were just momentary placeholders, to satisfy the compiler. Here’s a related situation. On rare occasions, you’ll want to call a Cocoa method that returns a value immediately and later uses that value in a function passed to that same method. For example, Cocoa has a UIApplication instance method declared like this: func beginBackgroundTaskWithExpirationHandler(handler: () -> Void) -> UIBackgroundTaskIdentifier That function returns a number (a UIBackgroundTaskIdentifier is just an Int), and will later call the function passed to it (handler) — a function which will want to use the number that was returned at the outset. Swift’s safety rules won’t let you declare the variable that holds this number and use it in an anonymous function all in the same line: let bti = UIApplication.sharedApplication() .beginBackgroundTaskWithExpirationHandler({ UIApplication.sharedApplication().endBackgroundTask(bti) }) // error: variable used within its own initial value Therefore, you need to declare the variable beforehand; but then Swift has another complaint: var bti : UIBackgroundTaskIdentifier bti = UIApplication.sharedApplication() .beginBackgroundTaskWithExpirationHandler({ UIApplication.sharedApplication().endBackgroundTask(bti) }) // error: variable captured by a closure before being initialized The solution is to declare the variable beforehand and give it a fake initial value as a placeholder: Variable Declaration | 67 var bti : UIBackgroundTaskIdentifier = 0 bti = UIApplication.sharedApplication() .beginBackgroundTaskWithExpirationHandler({ UIApplication.sharedApplication().endBackgroundTask(bti) }) Properties of an object (at the top level of an enum, struct, or class declaration) can be initialized in the object’s initializer function rather than by assignment in their declaration. It is legal and common for both constant properties (let) and vari‐ able properties (var) to have an explicit type and no directly assigned initial val‐ ue. I’ll have more to say about that in Chapter 4. Computed Initializer In the examples I’ve given so far, my variables have been initialized as literals or with a single line of code. Sometimes, however, you’d like to run several lines of code in order to compute a variable’s initial value. The simplest and most compact way to express this is with an anonymous function that you call immediately (see “Define-and-Call” on page 51). When the variable you’re initializing is an instance property, a define-and-call anony‐ mous function is usually the only way to compute the initial value with multiple lines of code. The reason is that, when you’re initializing an instance property, you can’t call an instance method, because there is no instance yet — the instance, after all, is what you are in the process of creating. You could call a top-level function, but that seems clumsy and inappropriate. Thus, you’ll use an anonymous function instead. Here’s an example from my own code. In this class, there’s an image (a UIImage) that I’m going to need many times later on. It makes sense to create this image in advance as a constant instance property of the class. To create it means to draw it. That takes several lines of code. So I declare and initialize the property by defining and calling an anonymous function, like this (for my imageOfSize utility, see Chapter 2): let ROWHEIGHT : CGFloat = 44 // global constant class RootViewController : UITableViewController { let cellBackgroundImage : UIImage = { let f = CGRectMake(0,0,320,ROWHEIGHT) return imageOfSize(f.size) { UIColor.blackColor().setFill() UIBezierPath(rect:f).fill() // ... more drawing goes here ... } }() // ... rest of the class declaration goes here ... } 68 | Chapter 3: Variables and Simple Types Computed Variables The variables I’ve been describing so far in this chapter have all been stored variables. The shoebox analogy applies. The variable is a name, like a shoebox; a value can be put into the shoebox, by assigning to the variable, and it then sits there and can be retrieved later, by referring to the variable, for as long the variable lives. Alternatively, a variable can be computed. This means that the variable, instead of having a value, has functions. One function, the setter, is called when the variable is assigned to. The other function, the getter, is called when the variable is referred to. Here’s some code illustrating schematically the syntax for declaring a computed variable: var now : String { get { return NSDate().description } set { println(newValue) } } The variable must be a var (not a let). Its type must be declared explicitly. It is then followed immediately by curly braces. The getter function is called get. Note that there is no formal function declaration; the word get is simply followed immediately by a function body in curly braces. The getter function must return a value of the same type as the variable. The setter function is called set. There is no formal function declaration; the word set is simply followed immediately by a function body in curly braces. The setter behaves like a function taking one parameter. By default, this parameter arrives into the setter function body with the local name newValue. Here’s some code that illustrates the use of a computed variable. You don’t treat it any differently than any other variable! To assign to the variable, assign to it; to use the variable, use it. Behind the scenes, though, the setter and getter functions are called: now = "Howdy" // Howdy println(now) // 2014-11-25 03:31:17 +0000 Assigning to now calls its setter. The argument passed into this call is the assigned value; here, that’s "Howdy". That value arrives in the set function as newValue. Our set function prints newValue to the console. Referring to now calls its getter. Our get function obtains the current date- time and translates it into a string, and returns the string. Our code then prints that string to the console. Computed Variables | 69 Observe that when we set now to "Howdy" in the first line, the string "Howdy" wasn’t stored anywhere. It had no effect, for example, on the value of now in the second line. A set function can store a value, but it can’t store it in this computed variable; a computed variable isn’t storage! It’s a shorthand for calling its getter and setter functions. There are a couple of variants on the basic syntax I’ve just illustrated: • The name of the set function parameter doesn’t have to be newValue. To specify a different name, put it in parentheses after the word set, like this: set (val) { // now you can use "val" inside the setter function body • There doesn’t have to be a setter. If the setter is omitted, this becomes a read-only variable. Attempting to assign to it is a compile error. A computed variable with no setter is the primary way to create a read-only variable in Swift. • There must always be a getter! However, if there is no setter, the word get and the curly braces that follow it can be omitted. Thus, this is a legal declaration of a read- only variable: var now : String { return NSDate().description } A computed variable can be useful in many ways. Here are the ones that occur most frequently in my real programming life: Read-only variable A computed variable is the simplest way to make a read-only variable. Just omit the setter from the declaration. Typically, the variable will be a global variable or a property; there probably wouldn’t be much point in a local read-only variable. Façade for a function When a value can be readily calculated by a function each time it is needed, it often makes for simpler syntax to express it as a read-only calculated variable. Here’s an example from my own code: var mp : MPMusicPlayerController { get { return MPMusicPlayerController.systemMusicPlayer() } } It’s no bother to call MPMusicPlayerController.systemMusicPlayer() every time I want to refer to this object, but it’s so much more compact to refer to it by a simple name, mp. And since mp represents a thing, rather than the performance of an action, it’s much nicer for mp to appear as a variable, so that to all appearances it is the thing, rather than as a function, which returns the thing. 70 | Chapter 3: Variables and Simple Types Façade for other variables A computed variable can sit in front of one or more stored variables, acting as a gatekeeper on how those stored variables are set and fetched. This is comparable to an accessor function in Objective-C. In the extreme case, a public computed variable is backed by a private stored variable: private var _p : String = "" var p : String { get { return self._p } set { self._p = newValue } } That’s a silly example, because we’re not doing anything interesting with our acces‐ sors: we are just setting and getting the private stored variable directly, so there’s really no difference between p and _p. But based on that template, you could now add functionality so that something useful happens during setting and getting. As the preceding example demonstrates, a computed instance property function can refer to other instance properties; it can also call instance methods. This is important, because in general the initializer for a stored property can do neither of those things. The reason this is legal for a computed property is that its functions won’t actually be called until after the instance exists. Here’s a practical example of a computed variable used as a façade for storage. My class has an instance property holding a very large stored piece of data, which can alternatively be nil (it’s an Optional, as I’ll explain later): var myBigDataReal : NSData! = nil When my app goes into the background, I want to reduce memory usage (because iOS kills backgrounded apps that use too much memory). So I plan to save the data of myBig- DataReal as a file to disk, and then set the variable itself to nil, thus releasing its data from memory. Now consider what should happen when my app comes back to the front and my code tries to fetch myBigDataReal. If it isn’t nil, we just fetch its value. But if it is nil, this might be because we saved its value to disk. So now I want to restore its value by reading it from disk, and then fetch its value. This is a perfect use of a computed variable façade: var myBigData : NSData! { set (newdata) { self.myBigDataReal = newdata } get { Computed Variables | 71 if myBigDataReal == nil { // ... get a reference to file on disk, f ... self.myBigDataReal = NSData(contentsOfFile: f) // ... erase the file ... } return self.myBigDataReal } } Setter Observers Computed variables are not needed as a stored variable façade as often as you might suppose. That’s because Swift has another brilliant feature, which lets you effectively inject functionality into the setter of a stored variable — setter observers. These are functions that are called just before and just after other code sets a stored variable. The syntax for declaring a variable with a setter observer is very similar to the syntax for declaring a computed variable; you can write a willSet function, a didSet function, or both: var s : String = "whatever" { willSet { println(newValue) } didSet { println(oldValue) // self.s = "something else" } } The variable must be a var (not a let). Its type must be declared explicitly. It can be assigned an initial value. It is then followed immediately by curly braces. The willSet function, if there is one, is the word willSet followed immediately by a function body in curly braces. It is called when other code sets this variable, just before the variable actually receives its new value. By default, the willSet function receives the incoming new value as new- Value. You can change this name by writing a different name in parentheses after the word willSet. The old value is still sitting in the stored variable, and the willSet function can access it there. The didSet function, if there is one, is the word didSet followed immediately by a function body in curly braces. It is called when other code sets this variable, just after the variable actually receives its new value. By default, the didSet function receives the old value, which has already been replaced as the value of the variable, as oldValue. You can change this name by writing a different name in parentheses after the word didSet. The new value 72 | Chapter 3: Variables and Simple Types is already sitting in the stored variable, and the didSet function can access it there. Moreover, it is legal for the didSet function to set the variable to a different value. Setter observer functions are not called when the variable is initialized or when the didSet function changes the variable’s value. That would be circular! In practice, I find myself using setter observers, rather than a computed variable, in the vast majority of situations where I would have used a setter override in Objective-C. Here’s an example from Apple’s own code (the Master–Detail Application template) illustrating a typical use case — changing the interface as a consequence of a property being set: var detailItem: AnyObject? { didSet { // Update the view. self.configureView() } } This is an instance property of a view controller class. Every time this property changes, we need to change the interface, because the job of the interface is, in part, to display the value of this property. So we simply call an instance method every time the property is set. The instance method reads the property’s value and sets the interface accordingly. In this example from my own code, not only do we change the interface, but also we “clamp” the incoming value within a fixed limit: var angle : CGFloat = 0 { didSet { // angle must not be smaller than 0 or larger than 5 if self.angle < 0 { self.angle = 0 } if self.angle > 5 { self.angle = 5 } // modify interface to match self.transform = CGAffineTransformMakeRotation(self.angle) } } A computed variable can’t have setter observers. But it doesn’t need them! There’s a setter function, so anything additional that needs to happen during setting can be programmed directly into that setter function. Setter Observers | 73 Lazy Initialization The term “lazy” is not a pejorative ethical judgment; it’s a formal description of an important behavior. If a stored variable is assigned an initial value as part of its decla‐ ration, and if it uses lazy initialization, then the initial value is not actually evaluated and assigned until actual code accesses the variable’s value. There are three types of variable that can be initialized lazily in Swift: Global variables Global variables are automatically lazy. This makes sense if you ask yourself when they should be initialized. As the app launches, files and their top-level code are encountered. It would make no sense to initialize globals now, because the app isn’t even running yet. Thus global initialization must be postponed to some moment that does make sense. Therefore, a global variable’s initialization doesn’t happen until other code first refers to that global. Under the hood, this behavior is protected with dispatch_once; this makes initialization both singular (it can happen only once) and thread-safe. Static properties Static properties behave exactly like global variables, and for basically the same reason. (There are no stored class properties in Swift, so class properties can’t be initialized and thus can’t have lazy initialization.) Instance properties An instance property is not lazy by default, but it may be made lazy by marking its declaration with the keyword lazy. This property must be declared with var, not let. The initializer for such a property might never be evaluated, namely if code assigns the property a value before any code fetches the property’s value. Lazy initialization is often used to implement singleton. Singleton is a pattern where all code is able to get access to a single shared instance of a certain class: class MyClass { static let sharedMyClassSingleton = MyClass() } Now other code can obtain a reference to MyClass’s singleton by saying MyClass.shared- MyClassSingleton. The singleton instance is not created until the first time other code says this; subsequently, no matter how many times other code may say this, the instance returned is always that same instance. Now let’s talk about lazy initialization of instance properties. Why might you want this? One reason is obvious: the initial value might be expensive to generate, so you’d like to avoid generating it until and unless it is actually needed. But there’s another reason that might not occur to you at first, but that turns out to be even more important: a lazy initializer can do things that a normal initializer can’t. In particular, it can refer to the 74 | Chapter 3: Variables and Simple Types instance. A normal initializer can’t do that, because the instance doesn’t yet exist at the time that a normal initializer would need to run (ex hypothesi, we’re in the middle of creating the instance, so it isn’t ready yet). A lazy initializer, by contrast, won’t run until some time after the instance has fully come into existence, so referring to the instance is fine. For example, this code would be illegal if the arrow property weren’t declared lazy: class MyView : UIView { lazy var arrow : UIImage = self.arrowImage() func arrowImage () -> UIImage { // ... big image-generating code goes here ... } } A very common idiom is to initialize a lazy instance property with a define-and-call anonymous function: lazy var prog : UIProgressView = { let p = UIProgressView(progressViewStyle: .Default) p.alpha = 0.7 p.trackTintColor = UIColor.clearColor() p.progressTintColor = UIColor.blackColor() p.frame = CGRectMake(0, 0, self.view.bounds.size.width, 20) p.progress = 1.0 return p }() There are some minor holes in the language: lazy instance properties can’t have setter observers, and there’s no lazy let (so you can’t readily make a lazy variable read-only). But these restrictions are not terribly serious, because lazy arguably isn’t doing very much that you couldn’t do with a calculated property backed by a stored property, as Example 3-1 shows. Example 3-1. Implementing a lazy property by hand private var lazyOncer : dispatch_once_t = 0 private var lazyBacker : Int = 0 var lazyFront : Int { get { dispatch_once(&lazyOncer) { self.lazyBacker = 42 // expensive initial value } return self.lazyBacker } set { dispatch_once(&self.lazyOncer) {} // will set self.lazyBacker = newValue // did set } } Lazy Initialization | 75 In Example 3-1, the idea is that only lazyFront is accessed publicly; lazyBacker is its underlying storage, and lazyOncer makes everything happen the right number of times. Since lazyFront is now an ordinary computed property, we can observe it during setting (put additional code into its setter function, at the points I’ve marked by “will set” and “did set”), or we can make it read-only (delete the setter entirely). Built-In Simple Types Every variable, and every value, must have a type. But what types are there? Up to this point, I’ve assumed the existence of some types, such as Int and String, without formally telling you about them. Here’s a survey of the primary simple types provided by Swift. (Collection types will be discussed at the end of Chapter 4.) I’ll also describe the instance methods, global methods, and operators applicable to these primary built-in types. Bool The Bool object type (a struct) has only two values, commonly regarded as true and false (or yes and no). You can represent these values using the literal keywords true and false, and it is natural to think of a Bool value as being either true or false: var selected : Bool = false In that code, selected is a Bool variable initialized to false; it can subsequently be set to false or true, and to no other values. Because of its simple yes-or-no state, a Bool variable of this kind is often referred to as a flag. Cocoa functions very often expect a Bool parameter or return a Bool value. For example, when your app launches, Cocoa calls a method in your code declared like this: func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool You can do anything you like in that function; often, you will do nothing. But you must return a Bool! And in real life, that Bool will always be true. A minimal implementation thus looks like this: func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { return true } A Bool is useful in conditions; as I’ll explain in Chapter 5, when you say if something, the something is the condition, and is a Bool — or an expression that eval‐ uates to a Bool. For example, when you compare two values with the equality compar‐ 76 | Chapter 3: Variables and Simple Types ison operator ==, the result is a Bool — true if they are equal to each other, false if they are not: if meaningOfLife == 42 { // ... (I’ll talk more about equality comparison in a moment, when we come to discuss types that can be compared, such as Int and String.) When preparing a condition, you will sometimes find that it enhances clarity to store the Bool value in a variable beforehand: let comp = self.traitCollection.horizontalSizeClass == .Compact if comp { // ... Observe that, when employing that idiom, we use the Bool variable directly as the con‐ dition. It is silly — and arguably wrong — to say if comp == true, because if comp already means “if comp is true.” There is no need to test explicitly whether a Bool equals true or false; the conditional expression itself is already testing that. Since a Bool can be used as a condition, a call to a function that returns a Bool can be used as a condition. Here’s an example from my own code. I’ve declared a function that returns a Bool to say whether the cards the user has selected constitute a correct answer to the puzzle: func evaluate(cells:[CardCell]) -> Bool { // ... Thus, elsewhere I can say this: let solution = self.evaluate(cellsToTest) if solution { // ... And I can equally collapse that to a single line: if self.evaluate(cellsToTest) { // ... Unlike many computer languages, nothing else in Swift is implicitly coerced to or treated as a Bool. For example, in C, a boolean is actually a number, and 0 is false. But in Swift, nothing is false but false, and nothing is true but true. The type name, Bool, comes from the English mathematician George Boole; Boolean algebra provides operations on logical values. Bool values are subject to these same operations: ! Not. The ! unary operator reverses the truth value of the Bool to which it is applied as a prefix. If ok is true, !ok is false — and vice versa. && Logical-and. Returns true only if both operands are true; otherwise, returns false. If the first operand is false, the second operand is not even evaluated (thus avoiding possible side effects). Built-In Simple Types | 77 || Logical-or. Returns true if either operand is true; otherwise, returns false. If the first operand is true, the second operand is not even evaluated (thus avoiding pos‐ sible side effects). If a logical operation is complicated or elaborate, parentheses around subexpressions can help clarify both the logic and the order of operations. Numbers The main numeric types are Int and Double, meaning that, left to your own devices, these are the types you’ll use. Other numeric types exist mostly for compatibility with the C and Objective-C APIs that Swift needs to be able to talk to when you’re program‐ ming iOS. Int The Int object type (a struct) represents an integer between Int.max and Int.min in‐ clusive. The actual values of those limits might depend on the platform and architecture under which the app runs, so don’t count on them to be absolute; in my testing at this moment, they are 263-1 and -263 respectively (64-bit words). The easiest way to represent an Int value is as a numeric literal. Any numeric literal without a decimal point is taken as an Int by default. Internal underscores are legal; this is useful for making long numbers readable. Leading zeroes are legal; this is useful for padding and aligning values in your code. You can write a numeric literal using scientific notation. Everything after the letter e is the exponent of 10; for example, 3e2 is 3 times 102 (300). You can write a numeric literal using binary, octal, or hexadecimal digits. To do so, start the literal with 0b, 0o, or 0x respectively. Thus, for example, 0x10 is decimal 16. You can use exponentiation here too; everything after the letter p is the exponent of 2. For ex‐ ample, 0x10p2 is decimal 64, because you are multiplying 16 by 22. There are instance methods for converting to a different underlying byte-order repre‐ sentation (bigEndian, littleEndian, byteSwapped) but I have never had occasion to use them. Double The Double object type (a struct) represents a floating-point number to a precision of about 15 decimal places (64-bit storage). The easiest way to represent a Double value is as a numeric literal. Any numeric literal containing a decimal point is taken as a Double by default. Internal underscores and 78 | Chapter 3: Variables and Simple Types leading zeroes are legal. Scientific notation is legal; everything after the letter e is the exponent of 10. A Double literal may not begin with a decimal point! If the value to be represented is between 0 and 1, start the literal with a leading 0. (I stress this because it is significantly different from C and Objective-C.) There’s a static property Double.infinity and an instance property isZero, among others. Coercion Coercion is the conversion of a value from one numeric type to another. Swift doesn’t really have explicit coercion, but it has something that serves the same purpose — in‐ stantiation. To convert an Int explicitly into a Double, instantiate Double with an Int in the parentheses. To convert a Double explicitly into an Int, instantiate Int with a Double in the parentheses; this will truncate the resulting value (everything after the decimal point will be thrown away): let i = 10 let x = Double(i) println(x) // 10.0, a Double let y = 3.8 let j = Int(y) println(j) // 3, an Int When numeric values are assigned to variables or passed as arguments to a function, Swift will perform implicit coercion of literals only. This code is legal: let d : Double = 10 But this code is not legal, because what you’re assigning is a variable (not a literal) of a different type; the compiler will stop you: let i = 10 let d : Double = i // compile error The solution is to coerce explicitly as you assign or pass the variable: let i = 10 let d : Double = Double(i) The same rule holds when numeric values are combined by an arithmetic operation. Swift will perform implicit coercion of literals only. The usual situation is an Int com‐ bined with a Double; the Int is treated as a Double: let x = 10/3.0 println(x) // 3.33333333333333 But variables of different numeric types must be coerced explicitly so that they are the same type if you want to combine them in an arithmetic operation. Thus, for example: Built-In Simple Types | 79 let i = 10 let n = 3.0 let x = i / n // compile error; you need to say Double(i) These rules are evidently a consequence of Swift’s strict typing; but (as far as I am aware) they constitute very unusual treatment of numeric values for a modern computer lan‐ guage, and will probably drive you mad in short order. The examples I’ve given so far were easily solved, but things can become more complicated if an arithmetic expression is longer, and the problem is compounded by the existence of other numeric types that are needed for compatibility with Cocoa, as I shall now proceed to explain. Other numeric types If you weren’t programming iOS — if you were using Swift in some isolated, abstract world — you could probably do all necessary arithmetic with Int and Double alone. Unfortunately, to program iOS you need Cocoa, which is full of other numeric types; and Swift has types that match every one of them. Thus, in addition to Int, there are signed integers of various sizes — Int8, Int16, Int32, Int64 — plus the unsigned integer UInt along with UInt8, UInt16, UInt32, and UInt64. In addition to Double, there is the lower-precision Float (32-bit storage, about 6 or 7 decimal places of precision) and the extended-precision Float80; plus, in the Core Graphics framework, CGFloat (whose size can be that of Float or Double, depending on the bitness of the surrounding archi‐ tecture). You may also encounter a C numeric type when trying to interface with a C API. These types, as far as Swift is concerned, are just type aliases, meaning that they are alternate names for another type; for example, a CDouble (corresponding to C’s double) is just a Double by another name, a CLong (C’s long) is an Int, and so on. Many other numeric type aliases will arise in various Cocoa frameworks; for example, an NSTimeInterval is merely a type alias for Double. Here’s the problem. I have just finished telling you that you can’t assign, pass, or combine values of different numeric types using variables; you have to coerce those values ex‐ plicitly to the correct type. But now it turns out that you’re being flooded by Cocoa with numeric values of many types! Cocoa will often hand you a numeric value that is neither an Int nor a Double — and you won’t necessarily realize this, until the compiler stops you dead in your tracks for some sort of type mismatch. You must then figure out what you’ve done wrong and coerce everything to the same type. Here’s a typical example from one of my apps. We have a UIImage, we extract its CGImage, and now we want to express the size of that CGImage as a CGSize: 80 | Chapter 3: Variables and Simple Types let mars = UIImage(named:"Mars")! let marsCG = mars.CGImage let szCG = CGSizeMake( // compile error CGImageGetWidth(marsCG), CGImageGetHeight(marsCG) ) The trouble is that CGImageGetWidth and CGImageGetHeight return UInts, but CGSize- Make expects CGFloats. This is not an issue in C or Objective-C, where there is implicit coercion from the former to the latter. But in Swift, you have to coerce explicitly: var szCG = CGSizeMake( CGFloat(CGImageGetWidth(marsCG)), CGFloat(CGImageGetHeight(marsCG)) ) Here’s another real-life example. A slider, in the interface, is a UISlider, whose minimum- Value and maximumValue are Floats. In this code, s is a UISlider, g is a UIGesture‐ Recognizer, and we’re trying to use the gesture recognizer to move the slider’s “thumb” to wherever the user tapped within the slider: let pt = g.locationInView(s) let percentage = pt.x / s.bounds.size.width let delta = percentage * (s.maximumValue - s.minimumValue) // compile error That won’t compile. pt is a CGPoint, and therefore pt.x is a CGFloat. Luckily, s.bounds.size.width is also a CGFloat, so the second line compiles — and percentage is now inferred to be a CGFloat. In the third line, however, we try to combine percentage with s.maximumValue and s.minimumValue — and they are Floats, not CGFloats. We must coerce explicitly: let delta = Float(percentage) * (s.maximumValue - s.minimumValue) The problem is particularly infuriating when Cocoa itself is responsible for the impe‐ dance mismatch. In Objective-C, you specify that a view controller’s view should appear in portrait orientation only like this: -(NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskPortrait; } However, it turns out that UIInterfaceOrientationMaskPortrait is an NSInteger, not an NSUInteger. In Objective-C, it’s fine to return an NSInteger where an NSUInteger is expected; implicit coercion is performed in good order. But in Swift, you can’t do that; the equivalent code doesn’t compile: override func supportedInterfaceOrientations() -> Int { return UIInterfaceOrientationMask.Portrait.rawValue // compile error } You have to perform the coercion explicitly: Built-In Simple Types | 81 Figure 3-1. Quick Help displays a variable’s type override func supportedInterfaceOrientations() -> Int { return Int(UIInterfaceOrientationMask.Portrait.rawValue) } The good news here — perhaps the only good news — is that if you can get enough of your code to compile, Xcode’s Quick Help feature will tell you what type Swift has inferred for a variable (Figure 3-1). This can assist you in tracking down your issues with numeric types. In the rare circumstance where you need to assign or pass an integer type where another integer type is expected and you don’t actually know what that other integer type is, you can get Swift to coerce dynamically by calling numericCast. For example, if i and j are previously declared variables of different integer types, i = numericCast(j) coerces j to the integer type of i. Arithmetic operations Swift’s arithmetic operators are as you would expect; they are familiar from other com‐ puter languages as well as from real arithmetic: + Addition operator. Add the second operand to the first and return the result. - Subtraction operator. Subtract the second operand from the first and return the result. A different operator (unary minus), used as a prefix, looks the same; it returns the additive inverse of its single operand. (There is, in fact, also a unary plus oper‐ ator, which returns its operand unchanged.) * Multiplication operator. Multiply the first operand by the second and return the result. / Division operator. Divide the first operand by the second and return the result. 82 | Chapter 3: Variables and Simple Types As in C, division of one Int by another Int yields an Int; any remaining frac‐ tion is stripped away. 10/3 is 3, not 3-and-one-third. % Remainder operator. Divide the first operand by the second and return the re‐ mainder. The result can be negative, if the first operand is negative; if the second operand is negative, it is treated as positive. Floating-point operands are legal. Integer types can be treated as binary bitfields and subjected to binary bitwise opera‐ tions: & Bitwise-and. A bit in the result is 1 if and only if that bit is 1 in both operands. | Bitwise-or. A bit in the result is 0 if and only if that bit is 0 in both operands. ^ Bitwise-or, exclusive. A bit in the result is 1 if and only if that bit is not identical in both operands. ~ Bitwise-not. Precedes its single operand; inverts the value of each bit and returns the result. << Shift left. Shift the bits of the first operand leftward the number of times indicated by the second operand. >> Shift right. Shift the bits of the first operand rightward the number of times indicated by the second operand. The bitwise-or operator arises surprisingly often in real life, because Cocoa often uses bits as switches when multiple options are to be specified simultaneously. For example, when specifying how a UIView is to be animated, you are allowed to pass an options: argument whose value comes from the UIViewAnimationOptions enumeration, whose definition (in Objective-C) begins as follows: typedef NS_OPTIONS(NSUInteger, UIViewAnimationOptions) { UIViewAnimationOptionLayoutSubviews = 1 << 0, UIViewAnimationOptionAllowUserInteraction = 1 << 1, UIViewAnimationOptionBeginFromCurrentState = 1 << 2, UIViewAnimationOptionRepeat = 1 << 3, UIViewAnimationOptionAutoreverse = 1 << 4, // ... }; Built-In Simple Types | 83 Pretend that an NSUInteger is 8 bits (it isn’t, but let’s keep things simple and short). Then this enumeration means that (in Swift) the following name–value pairs are de‐ fined: UIViewAnimationOptions.LayoutSubviews 0b00000001 UIViewAnimationOptions.AllowUserInteraction 0b00000010 UIViewAnimationOptions.BeginFromCurrentState 0b00000100 UIViewAnimationOptions.Repeat 0b00001000 UIViewAnimationOptions.Autoreverse 0b00010000 These values can be combined into a single value — a bitmask — that you pass as the options: argument for this animation. All Cocoa has to do to understand your inten‐ tions is to look to see which bits in the value that you pass are set to 1. So, for example, 0b00011000 would mean that UIViewAnimationOptions.Repeat and UIView- AnimationOptions.Autoreverse are both true (and that the others, by implication, are all false). The question is how to form the value 0b00011000 in order to pass it. You could form it directly as a literal and set the options: argument to UIViewAnimation- Options(0b00011000); but that’s not a very good idea, because it’s error-prone and makes your code incomprehensible. Instead, you use the bitwise-or operator to combine the desired options: let opts : UIViewAnimationOptions = .Autoreverse | .Repeat The bitwise-and operator arises less often; when it does, it’s used for the inverse of the operation we just performed. Cocoa hands you a bitmask, and you want to know whether a certain bit is set. In this example from a UITableViewCell subclass, the cell’s state comes to us as a bitmask; we want to know whether one particular bit is set: override func didTransitionToState(state: UITableViewCellStateMask) { let editing = UITableViewCellStateMask.ShowingEditControlMask.rawValue if state.rawValue & editing != 0 { // ... the ShowingEditControlMask bit is set ... } } Integer overflow or underflow — for example, adding two Int values so as to exceed Int.max — is a runtime error (your app will crash). In simple cases the compiler will stop you, but you can get away with it easily enough: let i = Int.max - 2 let j = i + 12/2 // crash Under certain circumstances you might want to force such an operation to succeed, so special overflow/underflow methods are supplied. These methods return a tuple; I’ll show you an example even though I haven’t discussed tuples yet: let i = Int.max - 2 let (j, over) = Int.addWithOverflow(i,12/2) 84 | Chapter 3: Variables and Simple Types Now j is Int.min + 3 (because the value has wrapped around from Int.max to Int.min) and over is true (to report the overflow). If you don’t care to hear about whether or not there was an overflow/underflow, special arithmetic operators let you suppress the error: &+, &-, &*. You will frequently want to combine the value of an existing variable arithmetically with another value and store the result in the same variable. Remember that to do so, you will need to have declared the variable as a var: var i = 1 i = i + 7 As a shorthand, operators are provided that perform the arithmetic operation and the assignment all in one move: var i = 1 i += 7 The shorthand (compound) assignment arithmetic operators are +=, -=, *=, /=, %=, &=, |=, ^=, ~=, <<=, >>=. It is often desirable to increase or decrease a numeric value by 1, so there are unary increment and decrement operators ++ and --. These differ depending on whether they are prefixed or postfixed. If prefixed (++i, --i) the value is incremented (or decremen‐ ted), stored back in the same variable, and then used within the surrounding expression; if postfixed (i++, i--), the current value of the variable is used within the surrounding expression, and then the value is incremented (or decremented) and stored back in the same variable. Obviously, the variable must be declared with var. Operation precedence is largely intuitive: for example, * has a higher precedence than +, so x+y*z multiplies y by z first, and then adds the result to x. Use parentheses to disambiguate when in doubt; for example, (x+y)*z performs the addition first. Global functions include abs (absolute value), max, and min: let i = -7 let j = 6 println(abs(i)) // 7 println(max(i,j)) // 6 Other mathematical functions, such as square roots, rounding, pseudorandom num‐ bers, trigonometry, and so forth, come from the C standard libraries that are visible because you’ve imported UIKit. You still have to be careful about numeric types, and there is no implicit coercion, even for literals. For example, sqrt expects a C double, which is a CDouble, which is a Double. So you can’t say sqrt(2); you have to say sqrt(2.0). Similarly, arc4random returns a UInt32. Built-In Simple Types | 85 So if n is an Int and you want to get a random number between between 0 and n-1, you can’t say arc4random()%n; you have to coerce the result of calling arc4random to an Int. Comparison Numbers are compared using the comparison operators, which return a Bool. For ex‐ ample, the expression i==j tests whether i and j are equal; when i and j are numbers, “equal” means numerically equal. So i==j is true only if i and j are “the same number,” in exactly the sense you would expect. The comparison operators are: == Equality operator. Returns true if its operands are equal. != Inequality operator. Returns false if its operands are equal. < Less-than operator. Returns true if the first operand is less than the second operand. <= Less-than-or-equal operator. Returns true if the first operand is less than or equal to the second operand. > Greater-than operator. Returns true if the first operand is greater than the second operand. >= Greater-than-or-equal operator. Returns true if the first operand is greater than or equal to the second operand. Keep in mind that, because of the way computers store numbers, equality comparison of Double values may not succeed where you would expect. To test whether two Doubles are effectively equal, it can be more reliable to compare the difference between them to a very small value (usually called an epsilon): let isEqual = abs(x - y) < 0.000001 String The String object type (a struct) represents text. The easiest way to represent a String value is with a literal, which is delimited by double quotes: let greeting = "hello" A Swift string is thoroughly modern; under the hood, it’s Unicode, and you can include any character directly in a string literal. If you don’t want to bother typing a Unicode 86 | Chapter 3: Variables and Simple Types character whose codepoint you know, use the notation \u{...}, where what’s between the curly braces is two, four, or eight hex digits: let checkmark = "\u{21DA}" The backslash in that string representation is the escape character; it means, “I’m not really a backslash; I indicate that the next character gets special treatment.” Various nonprintable and ambiguous characters are entered as escaped characters; the most important are: \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 (escaped because a lone backslash is the escape character) One of Swift’s coolest features is string interpolation. This permits you to embed any value that can be output with print (or println) inside a literal string as a string, even if it is not itself a string. The notation is escaped parentheses: \(...). For example: var n = 5 let s = "You have \(n) widgets." Now s is the string "You have 5 widgets." The example is not very compelling, be‐ cause we know what n is and could have typed 5 directly into our string; but imagine that we don’t know what n is! Moreover, the stuff in escaped parentheses doesn’t have to be the name of a variable; it can be almost any expression that evaluates as legal Swift. If you don’t know how to add, this example is more compelling: var m = 4 var n = 5 let s = "You have \(m + n) widgets." One thing that can’t go inside escaped parentheses is double quotes. This is disappoint‐ ing, but it’s not much of a hurdle; just assign to a variable and use the variable instead. For example, you can’t say this: let ud = NSUserDefaults.standardUserDefaults() let s = "You have \(ud.integerForKey("widgets")) widgets." // compile error Escaping the double quotes doesn’t help. You have to write it as multiple lines, like this: let ud = NSUserDefaults.standardUserDefaults() let n = ud.integerForKey("widgets") let s = "You have \(n) widgets.)" Built-In Simple Types | 87 To combine (concatenate) two strings, the simplest approach is to use the + operator (and its += assignment shortcut): let s = "hello" let s2 = " world" let greeting = s + s2 This convenient notation is possible because the + operator is overloaded: it does one thing when the operands are numbers (numeric addition) and another when the operands are strings (concatenation). As I’ll explain in Chapter 5, all operators can be overloaded, and you can overload them to operate in some appropriate way on your own types. As an alternative to +=, you can call the extend instance method: var s = "hello" let s2 = " world" s.extend(s2) // or: s += s2 Another way of concatenating strings is with the join method. It takes an array (yes, I know we haven’t gotten to arrays yet) of strings to be concatenated, and is an instance method of the string that is to be inserted between all of them: let s = "hello" let s2 = "world" let space = " " let greeting = space.join([s,s2]) The comparison operators are also overloaded so that they all work with String operands, and work as you would expect. Two String values are equal (==) if they are, in the natural sense of the words, “the same text.” A String is less than another if it is alphabetically prior. A few additional convenient instance methods and properties are provided. isEmpty returns a Bool reporting whether this string is the empty string (""). hasPrefix and hasSuffix report whether this string starts or ends with another string; for example, "hello".hasPrefix("h") is true. The uppercaseString and lowercaseString prop‐ erties provide uppercase and lowercase versions of the original string. Coercion between a String and an Int is possible. To make a string that represents an Int, it is sufficient to use string interpolation; alternatively, use the Int as a String ini‐ tializer, just as if you were coercing between numeric types: let i = 7 let s = String(i) Your string can also represent an Int in some other base; supply a radix: argument expressing the base: let i = 31 let s = String(i, radix:16) // "1f" 88 | Chapter 3: Variables and Simple Types A String that might represent an Int can be converted to the actual Int with the toInt instance method. The conversion might fail, because the String might not represent an Int; so the result is not an Int but an Optional wrapping an Int (I haven’t talked about Optionals yet, so you’ll have to trust me for now): let s = "31" let i = s.toInt() // Optional(31) The length of a String, in characters, is given by the global count method: let s = "hello" let length = count(s) // 5 Why isn’t there simply a length property of a String? It’s because a String doesn’t really have a simple length. The String is stored as a sequence of Unicode codepoints, but multiple Unicode codepoints can combine to form a character; so, in order to know how many characters are represented by such a sequence, we actually have to walk through the sequence and resolve it into the characters that it represents. You, too, can walk through a String. The simplest way is with the for...in construct (see Chapter 5). What you get when you do this are Character objects; I’ll talk more about Character objects later: let s = "hello" for c in s { println(c) // print each Character on its own line } There is more to a Swift String object, but most of it would take us off into the weeds of Unicode representation, which in real life you won’t need to know about. The curious thing is that there aren’t more methods for standard string manipulation. How, for example, do you capitalize a string, or find out whether a string contains a given sub‐ string? Most modern programming languages have a compact, convenient way of doing things like that; Swift doesn’t. The reason for this curious shortcoming appears to be that missing features are provided by the Foundation framework, to which you’ll always be linked in real life (importing UIKit imports Foundation). A Swift String is bridged to a Foundation NSString. This means that, to a large extent, Foundation NSString methods magically spring to life whenever you are using a Swift String. For example: let s = "hello, world" let s2 = s.capitalizedString // "Hello, World" The capitalizedString property comes from the Foundation framework; it’s provided by Cocoa, not by Swift. It’s an NSString property; it appears tacked on to String “for free.” Similarly, here’s how to locate a substring of a string: let s = "hello" let range = s.rangeOfString("ell") // Optional(Range(1..<4)) Built-In Simple Types | 89 I haven’t explained yet what an Optional is or what a Range is (I’ll talk about them later in this chapter), but that innocent-looking code has made a remarkable round-trip from Swift to Cocoa and back again: the Swift String s becomes an NSString, the NSString rangeOfString method is called, a Foundation NSRange struct is returned, and the NSRange is converted to a Swift Range and wrapped up in an Optional. It will often happen, however, that you don’t want this round-trip conversion. For var‐ ious reasons, you might want to stay in the Foundation world and receive the answer as a Foundation NSRange. To accomplish that, you have to cast your string explicitly to an NSString, using the as operator (I’ll discuss casting formally in Chapter 4): let s = "hello" let range = (s as NSString).rangeOfString("ell") // (1,3), an NSRange Here’s another example, also involving NSRange. Suppose you want to derive the string "ell" from "hello" by its range — the second, third, and fourth characters. Founda‐ tion’s NSString method substringWithRange: requires that you supply a range — meaning an NSRange. You can readily form the NSRange directly, using a Foundation function; but when you do, your code doesn’t compile: let s = "hello" let ss = s.substringWithRange(NSMakeRange(1,3)) // compile error The reason for the compile error is that Swift has absorbed NSString’s substringWith- Range:, and expects you to supply a Swift Range here. So you have to tell Swift to stay in the Foundation world, by casting: let s = "hello" let ss = (s as NSString).substringWithRange(NSMakeRange(1,3)) Swift also comes with a number of built-in general top-level functions that can be applied to strings. I’ve already mentioned count, which gives the length of the string in char‐ acters. contains returns a Bool, reporting whether a certain character (not substring) is found in a string: let s = "howdy" let ok = contains(s,"o") // true Instead of a character, contains can take a function that takes a character and returns a Bool. This code reports whether the target string contains a vowel: let s = "howdy" let ok = contains(s){contains("aeiou",$0)} // true find reports the index of a character (as an Optional): let s = "howdy" let ix = find(s,"o") // 1, wrapped in an Optional All Swift indexes are numbered starting with 0, so 1 means the second element; thus, that code is telling you that "o" is found in "howdy" as its second character. 90 | Chapter 3: Variables and Simple Types dropFirst and dropLast take a string and return (in effect) a new string without the first or last character, respectively. prefix and suffix extract the string of the given length from the start or end of the original string: let s = "hello" let s2 = prefix(s,4) // "hell" split breaks a string up into an array of strings according to a function that takes a character and returns a Bool. In this example, I obtain all stretches of a string that don’t contain vowels or spaces: let s = "hello world" let arr = split(s, {contains("aeiou ",$0)}) // ["h", "ll", "w", "rld"] Optional parameters allow split to do things such as limit the number of partitions: let s = "hello world" let arr = split(s, {contains("aeiou ",$0)}, maxSplit:1) // ["h", "llo world"] Character The Character object type (a struct) represents a single Unicode grapheme cluster — what you would naturally think of as one character of a string. A String object is formally a sequence of Character objects; that is why, as I mentioned earlier, you can walk through a string with for...in — what you are walking through are its Characters, one by one: let s = "hello" for c in s { println(c) // print each Character on its own line } It isn’t common to encounter Character objects outside of some String of which they are a part. There isn’t even a way to write a literal Character. To make a Character from scratch, initialize it with a single-character String: let c = Character("h") (By the same token, you can initialize a String from a Character.) Alternatively, to make a Character from a Unicode codepoint integer, pass through the UnicodeScalar class: let c = Character(UnicodeScalar(0x68)) Characters can be compared for equality; “less than” means what you would expect it to mean. An array initialized with a String is an array of Character. A String can be initialized from an array of Character. Thus, it is possible to break a String into characters, ma‐ nipulate the characters by manipulating the array, and reassemble into a new string: Built-In Simple Types | 91 let s = "hello" var arr = Array(s) arr.removeLast() let s2 = String(arr) // "hell" That’s not a very persuasive example, as we could have used the dropLast global function on the original string directly. However, a particularly nice thing about breaking a String into an array of Character is that the array is indexed by ordinary Int values. For example, what’s the second character of "hello"? Here’s one way to find out (recall that 1 means the second element): let s = "hello" var arr = Array(s) let c = arr[1] You can do the same thing directly with a String, but not so easily. This doesn’t compile: let s = "hello" let c = s[1] // compile error The reason is that the indexes on a String are a special type, an Index. In particular, they are the type defined by the Index struct inside the String struct, which must thus be referred to from outside as String.Index. You can’t convert an Int to a String.Index. The only way to make a String.Index from scratch is to start with a String’s startIndex or endIndex. You can then call advance to derive the index you want: let s = "hello" let ix = s.startIndex let ix2 = advance(ix,1) let c = s[ix2] // "e" The reason for this clumsy circumlocution is that Swift doesn’t know where the char‐ acters of a string actually are until it walks the string; calling advance is how you make Swift do that. Once you’ve done the work to obtain a desired String.Index, you can use it to modify the string (provided your reference to the string is a var, of course). The splice(at- Index:) instance method inserts a string into a string: var s = "hello" let ix = s.startIndex let ix2 = advance(ix,1) s.splice("ey, h", atIndex: ix2) // "hey, hello" Similarly, removeAtIndex deletes a single character (and returns that character). String manipulations involving longer stretches of the original string require use of a Range, which is the subject of the next section. 92 | Chapter 3: Variables and Simple Types The String–NSString Element Mismatch Swift and Cocoa have different ideas of what the elements of a string are. The Swift conception involves characters. The NSString conception involves UTF-16 codepoints. Each approach has its advantages. The NSString way makes for great speed and effi‐ ciency in comparison to Swift, which must walk the string to investigate how the char‐ acters are constructed; but the Swift way gives what you would intuitively think of as the right answer. To emphasize this difference, a nonliteral Swift string has no length property; instead, its utf16 property exposes its codepoints, and the global count func‐ tion then gives the same result as the NSString length property. Fortunately, the element mismatch doesn’t arise very often in practice; but it can arise. Here’s a good test case: let s = "Ha\u{030A}kon" println(count(s)) // 5 let length = (s as NSString).length // or: let length = count(s.utf16) println(length) // 6 We’ve created our string (the Norwegian name Håkon) using a Unicode codepoint that combines with the previous codepoint to form a character with a ring over it. Swift walks the whole string, so it normalizes the combination and reports 5 characters. Cocoa just sees at a glance that this string contains 6 16-bit codepoints. Range The Range object type (a struct) represents a pair of endpoints. There are two operators for forming a Range literal; you supply a start value and an end value, with one of the Range operators between them: ... Closed interval operator. The notation a...b means “everything from a up to b, including b.” ..< Half-open interval operator. The notation a.. Piece { let (i,j) = p // ... error-checking goes here ... return self.grid[i][j] } Built-In Simple Types | 97 The similarity between tuple element name syntax and function parameter lists is not a coincidence. A parameter list is a tuple! The truth is that every function takes one tuple parameter and returns one tuple. Thus, you can pass a single tuple to a function that takes multiple parameters. For example, suppose you have a top-level function like this: func f (i1:Int, i2:Int) -> () {} Then you can call it like this: let p = (1,2) f(p) In that example, f is a top-level function, so it has no external parameter names. If a function does have external parameter names, you can pass it a tuple with named ele‐ ments. So, again, let this be a top-level function: func f2 (#i1:Int, #i2:Int) -> () {} Then you can call it like this: let p2 = (i1:1, i2:2) f2(p2) To sum up, there are actually four ways to pick up the individual element values from a tuple: • Assign to a tuple of variable names. • Use index numbers. • Use names; if the tuple lacks names, assign to a tuple of the same type with names. • Pass it to a function and pick up the elements as local parameter names. Similarly, Void, the type of value returned by a function that doesn’t return a value, is actually a type alias for an empty tuple. That’s why it is also notated as (). Optional The Optional object type (an enum) wraps another object of any type. A single Optional object can wrap only one object. Alternatively, an Optional object might wrap no other object. This is what makes an Optional optional: it might wrap another object, but then again it might not. Think of an Optional as itself being a kind of shoebox — a shoebox which can quite legally be empty. Let’s start by creating an Optional that does wrap an object. Suppose we want an Optional wrapping the String "howdy". One way to create it is with the Optional initializer: var stringMaybe = Optional("howdy") If we log stringMaybe to the console with println, we’ll see an expression identical to the corresponding initializer: Optional("howdy"). 98 | Chapter 3: Variables and Simple Types After that declaration and initialization, stringMaybe is typed, not as a String, nor as an Optional plain and simple, but as an Optional wrapping a String. This means that any other Optional wrapping a String, and only another Optional wrapping a String, can be assigned to it. This code is legal: var stringMaybe = Optional("howdy") stringMaybe = Optional("farewell") This code, however, is not legal: var stringMaybe = Optional("howdy") stringMaybe = Optional(123) // compile error Optional(123) is an Optional wrapping an Int, and you can’t assign an Optional wrap‐ ping an Int where an Optional wrapping a String is expected. Optionals are so important to Swift that special syntax for working with them is baked into the language. The usual way to make an Optional is not to use the Optional ini‐ tializer (though you can certainly do that), but to assign or pass a value of some type to a reference that is already typed as an Optional wrapping that type. For example, once stringMaybe is typed as an Optional wrapping a String, it is legal to assign a String directly to it. This seems as if it should not be legal — but it is. The outcome is that the assigned String is wrapped in an Optional for us, automatically: var stringMaybe = Optional("howdy") stringMaybe = "farewell" // now stringMaybe is Optional("farewell") We also need a way of typing something explicitly as an Optional wrapping a String. Otherwise, we cannot declare a variable with an Optional type, and we cannot declare a parameter with an Optional type. Formally, an Optional is a generic, so an Optional wrapping a String is an Optional (I’ll explain that syntax in Chapter 4). How‐ ever, you don’t have to write that. The Swift language supports syntactic sugar for ex‐ pressing an Optional type: use the name of the wrapped type, followed by a question mark. For example: var stringMaybe : String? Thus I don’t need to use the Optional initializer at all. I can type the variable as an Optional wrapping a String and assign a String into it for wrapping, all in one move: var stringMaybe : String? = "howdy" That, in fact, is the normal way to make an Optional in Swift. Once you’ve got an Optional wrapping any particular type, you can use it wherever an Optional wrapping that particular type is expected — just like any other value. If a function expects an Optional wrapping a String as its parameter, you can pass string- Maybe as argument to that parameter: Built-In Simple Types | 99 func optionalExpecter(s:String?) {} let stringMaybe : String? = "howdy" optionalExpecter(stringMaybe) Moreover, where an Optional wrapping a certain type of value is expected, you can pass a value of that wrapped type instead. That’s because parameter passing is just like as‐ signment: an unwrapped value will be wrapped implicitly for you. For example, if a function expects an Optional wrapping a String, you can pass a String argument, which will be wrapped into an Optional in the received parameter: func optionalExpecter(s:String?) { // ... here, s will be an Optional wrapping a String ... println(s) } optionalExpecter("howdy") // console prints: Optional("howdy") But you cannot do the opposite — you cannot use an Optional wrapping a type where the wrapped type is expected. This won’t compile: func realStringExpecter(s:String) {} let stringMaybe : String? = "howdy" realStringExpecter(stringMaybe) // compile error The error message reads: “Value of optional type String? not unwrapped; did you mean to use ! or ??” You’re going to be seeing that sort of message a lot in Swift, so get used to it! As that message suggests, if you want to use an Optional where the type of thing it wraps is expected, you must unwrap the Optional — that is, you must reach inside it and retrieve the actual thing that it wraps. Now I’m going to talk about how to do that. Unwrapping an Optional We have seen more than one way to wrap an object in an Optional. But what about the opposite procedure? How do we unwrap an Optional to get at the object wrapped inside it? One way is to use the unwrap operator (or forced unwrap operator), which is a postfixed exclamation mark. For example: func realStringExpecter(s:String) {} let stringMaybe : String? = "howdy" realStringExpecter(stringMaybe!) In that code, the stringMaybe! syntax expresses the operation of reaching inside the Optional stringMaybe, grabbing the wrapped value, and substituting it at that point. Since stringMaybe is an Optional wrapping a String, the thing inside it is a String. That is exactly what the realStringExpecter function wants as its parameter! Thus, we are able to pass the unwrapped Optional as argument to realStringExpecter. string- Maybe is an Optional wrapping the String "howdy", but stringMaybe! is the String "howdy". 100 | Chapter 3: Variables and Simple Types If an Optional wraps a certain type, you cannot send it a message expected by that type. You must unwrap it first. For example, let’s try to get an uppercase version of string- Maybe: let stringMaybe : String? = "howdy" let upper = stringMaybe.uppercaseString // compile error The solution is to unwrap stringMaybe to get at the String inside it. We can do this directly, in place, using the unwrap operator: let stringMaybe : String? = "howdy" let upper = stringMaybe!.uppercaseString If an Optional is to be used several times where the unwrapped type is expected, and if you’re going to be unwrapping it with the unwrap operator each time, your code can quickly start to look like the dialog from a 1960s Batman comic. For example, in iOS programming, an app’s window is an Optional UIWindow property of the app delegate (self.window): // self.window is an Optional wrapping a UIWindow self.window = UIWindow(frame:UIScreen.mainScreen().bounds) self.window!.rootViewController = RootViewController() self.window!.backgroundColor = UIColor.whiteColor() self.window!.makeKeyAndVisible() That sort of thing soon gets old (or silly). One obvious alternative is to assign the un‐ wrapped value once to a variable of the wrapped type and then use that variable: // self.window is an Optional wrapping a UIWindow self.window = UIWindow(frame:UIScreen.mainScreen().bounds) let window = self.window! // now window (not self.window) is a UIWindow, not an Optional window.rootViewController = RootViewController() window.backgroundColor = UIColor.whiteColor() window.makeKeyAndVisible() However, there’s another way, as I shall now explain. Implicitly unwrapped Optional Swift provides another way of using an Optional where the wrapped type is expected: you can declare the Optional type itself as being implicitly unwrapped. This is actually another type — ImplicitlyUnwrappedOptional. An ImplicitlyUnwrappedOptional is an Optional, but the compiler permits some special magic associated with it: its value can be used directly where the wrapped type is expected. You can unwrap an ImplicitlyUn‐ wrappedOptional explicitly, but you don’t have to, because it is already implicitly un‐ wrapped (hence the name). For example: func realStringExpecter(s:String) {} var stringMaybe : ImplicitlyUnwrappedOptional = "howdy" realStringExpecter(stringMaybe) // no problem Built-In Simple Types | 101 As with Optional, Swift provides syntactic sugar for expressing an implicitly unwrapped Optional type. Just as an Optional wrapping a String can be expressed as String?, an implicitly unwrapped Optional wrapping a String can be expressed as String!. Thus, we can rewrite the preceding code like this (and this is how you would in fact write it): func realStringExpecter(s:String) {} var stringMaybe : String! = "howdy" realStringExpecter(stringMaybe) Bear in mind that an implicitly unwrapped Optional is still an Optional. It’s just a con‐ venience. By declaring something as an implicitly unwrapped Optional, you are asking the compiler, if you happen to use this value where the wrapped type is expected, to forgive you and to unwrap the value for you. By the same token, as far as their types are concerned, a normal Optional wrapping a certain type (such as a String?) and an implicitly unwrapped Optional wrapping that same type (such as a String!) are considered interchangeable: you can pass either one where either one is expected. The magic word nil I have talked so far about Optionals that contain a wrapped value. But what about an Optional that doesn’t contain any wrapped value? Such an Optional is, as I’ve already said, a perfectly legal entity; that, indeed, is the whole point of Optionals. You are going to need a way to ask whether an Optional contains a wrapped value, and a way to specify an Optional without a wrapped value. Swift makes both of those things easy, through the use of a special keyword, nil: To learn whether an Optional contains a wrapped value Test the Optional for equality against nil. If the test succeeds, the Optional is empty. An empty Optional is also reported in the Console as nil. To specify an Optional with no wrapped value Assign or pass nil where the Optional type is expected. The result is an Optional of the expected type, containing no wrapped value. For example: var stringMaybe : String? = "Howdy" println(stringMaybe) // Optional("Howdy") if stringMaybe == nil { println("it is empty") // does not print } stringMaybe = nil println(stringMaybe) // nil if stringMaybe == nil { println("it is empty") // prints } 102 | Chapter 3: Variables and Simple Types The magic word nil lets you express the concept “An Optional wrapping the appropriate type, but not actually containing any object of that type.” Clearly, that’s very convenient magic; you’ll want to take advantage of it. It is very important to understand, however, that it is magic: nil in Swift is not a thing and is not a value. It is a shorthand. It is natural to think and speak as if this shorthand were real. For example, I will say that something “is nil.” But in reality, nothing “is nil”; nil isn’t a thing. What I mean is that this thing is equatable with nil (because it is an Optional not wrapping anything). The real value of an Optional that contains no wrapped object is Optional.None, and the real value of an Optional wrapping a String that contains no wrapped String is Optional.None. But you’ll probably never actually need to say those things in your code, because it’s so much easier to say nil. I’ll explain in Chapter 4 what those expressions signify. Because a variable typed as an Optional can be nil, Swift follows a special initialization rule: a variable (var) typed as an Optional is nil, automatically. This is legal: func optionalExpecter(s:String?) {} var stringMaybe : String? optionalExpecter(stringMaybe) That code is interesting because it looks as if it should be illegal. We declared a variable stringMaybe, but we never assigned it a value. Nevertheless we are now passing it around as if it were an actual thing. That’s because it is an actual thing. This variable has been implicitly initialized — to nil. In Swift 1.2, the implicit initialization rule for Optional-typed variables applies to true variables (var) but not to constants (let). That’s because, in Swift 1.2, a let variable that isn’t initialized in its declaration might be initialized subsequently. We come now to perhaps the most important rule in all of Swift: You cannot unwrap an Optional containing nothing (an Optional equatable with nil). Such an Optional con‐ tains nothing; there’s nothing to unwrap. Like Oakland, there’s no there there. In fact, explicitly unwrapping an Optional containing nothing will crash your program at run‐ time: var stringMaybe : String? let s = stringMaybe! // crash The crash message reads: “Fatal error: unexpectedly found nil while unwrapping an Optional value.” Get used to seeing it, because you’re going to be seeing it a lot. This is an easy mistake to make. Unwrapping an Optional that contains no value is, in fact, probably the most common way to crash a Swift program. You should look upon this Built-In Simple Types | 103 kind of crash as a blessing. Very often, in fact, you will want to crash if your Optional contains no value, because it should contain a value, and the fact that it doesn’t indicates that you’ve made a mistake elsewhere. To eliminate such a crash, you need to ensure that your Optional contains a value, and don’t unwrap it if it doesn’t. One obvious way to do that is to test against nil first: var stringMaybe : String? // ... stringMaybe might be assigned a real value here ... if stringMaybe != nil { let s = stringMaybe! // ... } Optional chains A common situation is that you want to send a message to the value wrapped inside an Optional. To do so, you can unwrap the Optional in place. I gave an example earlier: let stringMaybe : String? = "howdy" let upper = stringMaybe!.uppercaseString That form of code is called an Optional chain. In the middle of a chain of dot-notation, you have unwrapped an Optional. You cannot send a message to an Optional without unwrapping it. Optionals themselves don’t respond to any messages. (Well, they do respond to some messages, but very few, and you are unlikely to use them — and in any case they are not the messages to which the thing inside them responds.) If you try to send to an Optional a message intended for the thing inside it, you will get an error message from the compiler: let stringMaybe : String? = "howdy" let upper = stringMaybe.uppercaseString // compile error The error message reads: “String? does not have a member named…” When you see that message, the type name will of course differ, depending on the type of thing wrapped by your Optional. But the gist will always be the same. The question mark in the name of the type tells you that you have tried to send a message to an Optional. You can’t do that. You need to unwrap the Optional to reach the thing inside; that is something you can send a message to. We have already seen, however, that if you unwrap an Optional that contains no wrapped object, you’ll crash. So what if you’re not sure whether this Optional contains a wrapped object? How can you send a message to an Optional in that situation? Swift provides a special shorthand for exactly this purpose. To send a message, safely, to an Optional that might be empty, you can unwrap the Optional optionally. To do so, unwrap the Optional with the question mark postix operator instead of the exclamation mark: 104 | Chapter 3: Variables and Simple Types var stringMaybe : String? // ... stringMaybe might be assigned a real value here ... let upper = stringMaybe?.uppercaseString That’s an Optional chain in which you used a question mark to unwrap the Optional. By using that notation, you have unwrapped the Optional optionally — meaning con‐ ditionally. The condition in question is one of safety; a test for nil is performed for us. Our code means: “If stringMaybe contains a String, unwrap it and send it the uppercase- String message. If it doesn’t (that is, if it equates to nil), do not send it any messages!” Such code is a double-edged sword. On the one hand, if stringMaybe is nil, you won’t crash at runtime. On the other hand, if stringMaybe is nil, that line of code won’t do anything useful — you won’t get any uppercase string. But now there’s a new question. In that code, we initialized a variable upper. Now it turns out that the uppercaseString message might or not even be sent. So what, exactly, is upper initialized to? To handle this situation, Swift has a special rule. If an Optional chain contains an op‐ tionally unwrapped Optional, and if this Optional chain produces a value, that value is itself wrapped in an Optional. This rule works brilliantly, because it covers both possible cases. Here’s what I mean. Let’s say, first, that stringMaybe contains a String: var stringMaybe : String? stringMaybe = "howdy" let upper = stringMaybe?.uppercaseString After that code, upper is not a String; it is not "HOWDY". It is an Optional wrapping "HOWDY"! You can see now why I say this covers both possible cases: if the attempt to unwrap the Optional fails, the Optional chain can return nil instead: var stringMaybe : String? let upper = stringMaybe?.uppercaseString // now upper is nil Consider the consequences. On the one hand, even if stringMaybe is nil, we won’t crash at runtime. On the other hand, we’ve ended up with yet another Optional on our hands! Whether stringMaybe is nil or not, upper is typed as an Optional wrapping a String, and in order to use that String, we’re going to have to unwrap upper. And we don’t know whether upper is nil, so we have exactly the same problem we had before — we need to make sure that we unwrap upper safely, and that we don’t accidentally unwrap an empty Optional. Longer Optional chains are legal. They work just as you would expect: no matter how many Optionals are unwrapped in the course of the chain, if any of them is unwrapped optionally, the entire expression produces an Optional wrapping the type it would have produced if the Optionals were unwrapped normally. For example: // self.window is a UIWindow? let f = self.window?.rootViewController?.view.frame Built-In Simple Types | 105 The frame property of a view is a CGRect. But after that code, f is not a CGRect. It’s an Optional wrapping a CGRect. The reason is that, in this way, if any of the optional unwrapping along the chain fails (because the Optional we proposed to unwrap is nil), the entire chain can return nil to indicate failure. This provides an additional measure of safety, but again, you must remember to check whether this resulting Op‐ tional is itself nil before you can use it — and if it isn’t nil, you will need to unwrap it before you can do anything useful with it. Observe that the preceding code does not end up nesting Optionals; it doesn’t produce a CGRect wrapped in an Optional wrapped in an Optional, merely because there are two Optionals being optionally unwrapped in the chain. However, it is possible, for other reasons, to end up with an Optional wrapped in an Optional. I’ll give an example in Chapter 4. If an Optional chain containing optional unwrapping produces a result, you can learn whether all the Optionals in the chain were safely unwrapped by examining that result: if it isn’t nil, everything was unwrapped successfully. But what if an Optional chain containing optional unwrapping produces no result? For example: self.window?.rootViewController = UIViewController() Now we’re in a quandary. It’s true that we won’t crash; if self.window is nil, it won’t be unwrapped, so we’re safe. But if self.window is nil, we didn’t succeed in giving our window a root view controller either! It would be nice to know whether the unwrapping in this Optional chain succeeded. Fortunately, there’s a trick for finding out. Every statement in Swift that doesn’t otherwise return a value returns Void. Therefore, an assignment into an Optional chain with optional unwrapping returns an Optional wrapping Void! And you can capture that Optional. That means you can test the Op‐ tional against nil; if it isn’t nil, the assignment worked. For example: let ok : Void? = self.window?.rootViewController = UIViewController() if ok != nil { // it worked } Naturally, you don’t need to capture the Optional wrapping Void explicitly in a variable; you can capture and test it against nil in a single move: if (self.window?.rootViewController = UIViewController()) != nil { // it worked } If a function call returns an Optional, you can unwrap the result and use it. You don’t necessarily have to capture the result in order to do that; you can unwrap it in place, by putting an exclamation mark or a question mark after the function call (that is, after the 106 | Chapter 3: Variables and Simple Types closing parenthesis). This is really no different from what we did in the preceding code with window?, except that instead of a property that returns an Optional, this is a function call that returns an Optional. For example: class Dog { var noise : String? = nil func speak() -> String? { return self.noise } } let d = Dog() let bigname = d.speak()?.uppercaseString After that, don’t forget, bigname is not a String — it’s an Optional wrapping a String. I’ll discuss some additional Swift syntax for checking whether an Optional is nil when I come to flow control in Chapter 5. The ! and ? postfix operators, which respectively unconditionally and condition‐ ally unwrap an Optional, have basically nothing to do with the ! and ? used with type names as syntactic sugar for expressing Optional types (such as String? to mean an Optional wrapping a String, and String! to mean an implicitly unwrap‐ ped Optional wrapping a String). The outward similarity has confused many a beginner. Comparison with Optional In a comparison with something other than nil, an Optional gets special treatment: the wrapped value, not the Optional itself, is compared. So, for example, this works: let s : String? = "Howdy" if s == "Howdy" { // ... they _are_ equal! That shouldn’t work, but it does — mercifully so, since it would be maddening to have to unwrap an Optional just to compare its wrapped value with something (especially as you’d have to check first whether the Optional is nil). Instead of comparing the Optional itself with "Howdy", Swift automagically (and safely) compares its wrapped value (if there is one) with "Howdy", and the comparison succeeds. If the wrapped value is not "Howdy", the comparison fails. If there is no wrapped value (s is nil), the comparison fails too — safely! Thus, you can compare s to nil or to a String, and the comparison works correctly in all cases. In the same way, if an Optional wraps a type of value that can be compared using the greater-than and less-than operators, those operators can be applied directly to the Optional: Built-In Simple Types | 107 let i : Int? = 2 if i < 3 { // ... it _is_ less! Why Optionals? Now that you know how to use an Optional, you are probably wondering why to use an Optional. Why does Swift have Optionals at all? What are they good for? One very important purpose of Optionals is to provide interchange of object values with Objective-C. In Objective-C, any object reference can be nil. You thus need a way to send nil to Objective-C and to receive nil from Objective-C. Swift Optionals provide your only way to do that. From Swift’s point of view, strictly speaking, all Objective-C objects are Optionals! Swift will typically assist you by a judicious use of appropriate types in the Cocoa APIs. For example, consider a UIView’s backgroundColor property. This can be nil, and you are allowed to set it to nil. Thus, it is typed as a UIColor?. You don’t need to work directly with Optionals in order to set such a value! Remember, assigning the wrapped type to an Optional is legal, as the assigned value will be wrapped for you. Thus, you can set myView.backgroundColor to a UIColor — or to nil! But if you get a UIView’s backgroundColor, you now have an Optional wrapping a UIColor, and you must be conscious of this fact, for all the reasons I’ve already discussed: if you’re not, surprising things can happen: let v = UIView() let c = v.backgroundColor let c2 = c.colorWithAlphaComponent(0.5) // compile error You’re trying to send the colorWithAlphaComponent message to c, as if it were a UIColor. It isn’t a UIColor. It’s an Optional wrapping a UIColor. Xcode will brilliantly and des‐ perately try to help you in this situation; if you use code completion to enter the name of the colorWithAlphaComponent method, Xcode will insert a question mark after c, thus (optionally) unwrapping the Optional and giving you legal code: let v = UIView() let c = v.backgroundColor let c2 = c?.colorWithAlphaComponent(0.5) In the vast majority of situations, however, a Cocoa object type will not be marked as an Optional. That’s because, although in theory it could be nil (because any Objective- C object reference can be nil), in practice it won’t be. Swift thus saves you a step by treating the value as the object type itself. This magic is performed by hand-tweaking the Cocoa APIs. In the very first public version of Swift (in June of 2014), all object values received from Cocoa were in fact typed as Optionals — usually, implicitly un‐ wrapped Optionals. But then Apple embarked on the massive project of hand-tweaking the APIs to eliminate Optionals that didn’t need to be Optionals. 108 | Chapter 3: Variables and Simple Types In a few cases, you will still encounter implicitly unwrapped Optionals coming from Cocoa. That simply means that Apple hasn’t gotten around to hand-tweaking this corner of the API yet. For example, as of this writing, the API for the CALayer drawIn- Context: method looks like this: func drawInContext(ctx: CGContext!) The chances that ctx would ever actually be nil are zero; this value shouldn’t be an Optional. In the future — perhaps by the time you read this — it won’t be. But in the meantime, the implicitly unwrapped Optional does no harm, because it’s implicitly un‐ wrapped, which means that in your code you can treat ctx as if it were a CGContext rather than as an Optional, and all will be well. Occasionally, Apple hand-tweaks a Cocoa API incorrectly and unwraps an Optional that should have remained an Optional. That’s a bug, and you should report it. If this is a received value, you can work around the bug by immediately assigning the received value to an Optional wrapping the appropriate type, and working with the Optional. In any situation where you have a legitimate reason to be passing nil to Cocoa, the API should express the value as an Optional (as in the case of backgroundColor). If it doesn’t, then if you want to pass nil, you can’t. You’ll have to write an Objective- C helper method (and you should report this to Apple as a bug). Another important use of Optionals is to defer initialization of a variable — typically, of an instance property. If a variable is typed as an Optional, it has a value even if you don’t initialize it — namely nil. That comes in very handy in situations where you know something will have a value, but not right away. A typical example in real-life iOS pro‐ gramming is an outlet, which is a reference to something in your interface such as a button: class ViewController: UIViewController { @IBOutlet var myButton: UIButton! // ... } Ignore, for now, the @IBOutlet designation, which is an internal hint to Xcode (as I’ll explain in Chapter 7). The important thing is that this property, myButton, won’t have a value when our ViewController instance first comes into existence, but shortly there‐ after the view controller’s view will be loaded and myButton will be set so that it points to an actual UIButton object in the interface. Therefore, the variable is typed as an implicitly unwrapped Optional. It’s an Optional because we need a placeholder value for myButton when the ViewController instance first comes into existence. It’s implicitly unwrapped so that in our code we can just treat self.myButton as a reference to an actual UIButton, passing through the Optional without noticing that it is an Optional. Built-In Simple Types | 109 A closely related situation is when a variable, again typically an instance property, rep‐ resents data that will take time to acquire. For example, in my Albumen app, as we launch, I create an instance of my root view controller. I also want to gather a bunch of data about the user’s music library and store that data in instance properties of the root view controller instance. But gathering that data will take time. Therefore I must in‐ stantiate the root view controller first and gather the data later, because if we pause to gather the data before instantiating the root view controller, the app will take too long to launch — the delay will be perceptible, and we might even crash (because iOS forbids long launch times). Therefore the data properties are all typed as Optionals; they are nil until the data are gathered, at which time they are assigned their “real” values: class RootViewController : UITableViewController { var albums : [MPMediaItemCollection]! = nil // ... Finally, one of the most important uses of Optionals is to permit a value to be marked as empty or erroneous. The preceding code is a good illustration. When my Albumen app launches, it displays a table listing all the user’s music albums. At launch time, however, that data has not yet been gathered. My table-display code tests albums to see whether it’s nil and, if it is, displays an empty table. After gathering the data, I tell my table to display its data again. This time, the table-display code finds that albums is not nil, but rather consists of actual data — and it now displays that data. The use of an Optional allows one and the same value, albums, to store the data or to state that there is no data. Many built-in Swift functions use an Optional in a similar way. I referred earlier to the String toInt instance method: let s = "31" let i = s.toInt() // Optional(31) The toInt method returns an Optional because the conversion can fail. If s is "howdy", it isn’t a number. Thus the type returned cannot be an Int, because there is no Int that can be taken to mean, “I didn’t find any Int.” Returning an Optional solves the problem neatly: nil means “I didn’t find any Int,” and otherwise the actual Int result is sitting there wrapped up in the Optional. Swift is cleverer than Objective-C in this regard. If a reference is an object, Objective- C can return nil to report failure; but not everything in Objective-C is an object. Thus, many important Cocoa methods return a special value to indicate failure, and you have to know this and remember to test for it. For example, NSString’s rangeOfString: might not find the given substring in the target string; in that case, it returns an NSRange whose length is zero and whose location (index) is a special value, NSNotFound, which is actually just a very large negative number. Fortunately, a knowledge of this special value is built into the Swift bridge to the Cocoa API: Swift types the returned value as 110 | Chapter 3: Variables and Simple Types an Optional wrapping a Range, and if rangeOfString: does return an NSRange whose location is NSNotFound, Swift expresses it as nil! Not every part of the Swift–Cocoa bridge is so helpful, however. If you call NSArray’s indexOfObject:, the result is an Int, not an Optional wrapping an Int; that result can be NSNotFound, and you have to remember to test for this: let arr = [1,2,3] let ix = (arr as NSArray).indexOfObject(4) if ix == NSNotFound { // ... An alternative in this case might be to stay in Swift and call the built-in find function, which returns an Optional: let arr = [1,2,3] let ix = find(arr,4) if ix == nil { // ... Built-In Simple Types | 111 CHAPTER 4 Object Types In the preceding chapter, I discussed some built-in object types. But I have not yet described how object types in general really work. As I mentioned in Chapter 1, Swift object types come in three flavors: enum, struct, and class. What are the differences between them? And how would you create your own object type? That’s what this chap‐ ter is about. I’ll describe object types in general, and then each of the three flavors. Then I’ll explain three Swift ways of giving an object type greater flexibility: protocols, ge‐ nerics, and extensions. Finally, the survey of Swift’s built-in types will come to an end with three umbrella types and three collection types. Object Type Declarations and Features Object types are declared with the flavor of the object type (enum, struct, or class), the name of the object type (which should start with a capital letter), and curly braces: class Manny { } struct Moe { } enum Jack { } An object type declaration can appear anywhere: at the top level of a file, at the top level of another object type declaration, or in the body of a function. The visibility (scope), and hence the usability, of this object type by other code depends upon where it appears (see Chapter 1): • Object types declared at the top level of a file will, by default, be visible to all files in your project (module). This is the usual place for object type declarations. • Sometimes it’s useful to declare a type inside the declaration of another type, thus giving it a namespace. 113 • An object type declared within the body of a function will exist only inside the scope of the curly braces that surround it; such declarations are legal but rare. Declarations for any object type may contain within their curly braces the following things: Initializers An object type is merely the type of an object. The purpose of declaring an object type will usually (though not always) be so that you can make an actual object — an instance — that has this type. An initializer is a special function, declared and called in a special way, allowing you to do that. Properties A variable declared at the top level of an object type declaration is a property. By default, it is an instance property. An instance property is scoped to an instance: it is accessed through a particular instance of this type, and its value can be different for every instance of this type. Alternatively, a property can be a static/class property. For an enum or struct, it is declared with the keyword static; for a class, it may instead be declared with the keyword class. Such a property belongs to the object type itself: it is accessed through the name of the type, and it has just one value, associated with the type. Methods A function declared at the top level of an object type declaration is a method. By default, it is an instance method: it is called by sending a message to a particular instance of this type. Inside an instance method, self is the instance. Alternatively, a function can be a static/class method. For an enum or struct, it is declared with the keyword static; for a class, it may be declared instead with the keyword class. It is called by sending a message to the type. Inside a static/class method, self is the type. Subscripts A subscript is a special kind of instance method. It is called by appending square brackets to an instance reference. Object type declarations An object type declaration can contain an object type declaration. From inside the containing object type, the contained object type is in scope; from outside the con‐ taining object type, the contained object type must be referred to through the con‐ taining object type. Thus, the containing object type is a namespace for the con‐ tained object type. 114 | Chapter 4: Object Types Initializers An initializer is a function called in order to bring an instance of an object type into existence. Strictly speaking, it is a static/class method, because it is called by talking to the object type. It is called using special syntax: a reference to the type is followed directly by parentheses, as if the type itself were a function. When you use that syntax, a new instance is created, the corresponding initializer function is called, and the new instance is returned as a result. You will need to do something with the returned instance, such as assigning it to a variable, in order to work with it further. For example, suppose we have a Dog class: class Dog { } Then we can make a Dog instance like this: Dog() That code, however, though legal, is silly. We have created a Dog instance, but there is no reference to that instance. Without such a reference, the Dog instance comes into existence and then immediately vanishes in a puff of smoke. The usual sort of thing is more like this: let fido = Dog() Now our Dog instance will persist as long as the variable fido persists (see Chapter 3) — and the variable fido gives us a reference to our Dog instance, so that we can use it. Observe that Dog() calls an initializer even though our Dog class doesn’t declare any initializers! The reason is that object types may have implicit initializers. These are a convenience that save you from the trouble of writing your own initializers. But you can write your own initializers, and you will often do so. An initializer is kind of function, and its declaration syntax is rather like that of a func‐ tion. To declare an initializer, you use the keyword init followed by a parameter list, followed by curly braces containing the code. What distinguishes one initializer from another is the parameter list; an object type can have multiple initializers, distinguished by their parameters. The parameter names are externalized by default (though of course you can prevent this by putting an underscore before a parameter name). A frequent use of the parameters is to set the values of instance properties. For example, here’s a Dog class with two instance properties, name (a String) and license (an Int). We give these instance properties default values that are effectively placeholders — an empty string and the number zero. Then we declare three initializers, so that the caller can create a Dog instance in three different ways: by supplying a name, by sup‐ plying a license number, or by supplying both. In each initializer, the parameters sup‐ plied are used to set the values of the corresponding properties: Object Type Declarations and Features | 115 class Dog { var name = "" var license = 0 init(name:String) { self.name = name } init(license:Int) { self.license = license } init(name:String, license:Int) { self.name = name self.license = license } } Observe that in that code, in each initializer, I’ve given each parameter the same name as the property to which it corresponds. There’s no reason to do that apart from stylistic clarity. In the code for each initializer, I can distinguish the local variable supplied as the parameter from the property by using self to access the property. The result of that declaration is that I can create a Dog in three different ways: let fido = Dog(name:"Fido") let rover = Dog(license:1234) let spot = Dog(name:"Spot", license:1357) What I can’t do is to create a Dog with no initializer parameters. I wrote initializers, so my implicit initializer went away. This code is no longer legal: let puff = Dog() // compile error Of course, I could make that code legal by explicitly declaring an initializer with no parameters: class Dog { var name = "" var license = 0 init() { } init(name:String) { self.name = name } init(license:Int) { self.license = license } init(name:String, license:Int) { self.name = name self.license = license } } 116 | Chapter 4: Object Types Now, the truth is that we don’t need those four initializers, because an initializer is a function, and a function’s parameters can have default values. Thus, I can condense all that code into a single initializer, like this: class Dog { var name = "" var license = 0 init(name:String = "", license:Int = 0) { self.name = name self.license = license } } I can still make an actual Dog instance in four different ways: let fido = Dog(name:"Fido") let rover = Dog(license:1234) let spot = Dog(name:"Spot", license:1357) let puff = Dog() Now comes the Really Interesting Part. In my property declarations, I can eliminate the assignment of default initial values (as long as I declare explicitly the type of each prop‐ erty): class Dog { var name : String // no default value! var license : Int // no default value! init(name:String = "", license:Int = 0) { self.name = name self.license = license } } That code is legal (and common) — because an initializer initializes! In other words, I don’t have to give my properties initial values in their declarations, provided I give them initial values in all initializers. That way, I am guaranteed that all my instance properties have values when the instance comes into existence, which is what matters. Conversely, an instance property without an initial value when the instance comes into existence is illegal. A property must be initialized either as part of its declaration or by every ini‐ tializer, and the compiler will stop you otherwise. The Swift compiler’s insistence that all instance properties be properly initialized is a valuable feature of Swift. (Contrast Objective-C, where instance properties can go un‐ initialized — and often do, leading to mysterious errors later.) Don’t fight the compiler; work with it. The compiler will help you by giving you an error message (“Return from initializer without initializing all stored properties”) until all your initializers initialize all your instance properties: Object Type Declarations and Features | 117 class Dog { var name : String var license : Int init(name:String = "") { self.name = name // compile error } } Because setting an instance property in an initializer counts as initialization, it is legal even if the instance property is a constant declared with let: class Dog { let name : String let license : Int init(name:String = "", license:Int = 0) { self.name = name self.license = license } } In our artificial examples, we have been very generous with our initializer: we are letting the caller instantiate a Dog without supplying a name argument or a license argument. Usually, however, the purpose of an initializer is just the opposite: we want to force the caller to supply all needed information at instantiation time. Thus, in real life, it is much more likely that our Dog class would look like this: class Dog { let name : String let license : Int init(name:String, license:Int) { self.name = name self.license = license } } In that code, our Dog has a name and a license, and values for these must be supplied at instantiation time (there are no default values), and those values can never be changed thereafter (these properties are constants). In this way, we enforce a rule that every Dog must have a meaningful name and license. There is now only one way to make a Dog: let spot = Dog(name:"Spot", license:1357) Optional properties Sometimes, there is no meaningful default value that can be assigned to an instance property during initialization. For example, perhaps the initial value of this property will not be obtained until some time has elapsed after this instance has come into exis‐ tence. This situation conflicts with the requirement that all instance properties be ini‐ tialized either in their declaration or through an initializer. You could, of course, just circumvent the problem by assigning a default initial value anyway; but this fails to communicate to your own code the fact that this isn’t a “real” value. 118 | Chapter 4: Object Types A sensible and common solution, as I explained in Chapter 3, is to declare your instance property as a var having an Optional type. An Optional has a value, namely nil, sig‐ nifying that no “real” value has been supplied; and an Optional var is initialized to nil automatically. Thus, your code can test this instance property against nil and, if it is nil, it won’t use the property. Later, the property will be given its “real” value. Of course, that value is now wrapped in an Optional; but if you declare this property as an implicitly unwrapped Optional, you have the additional advantage of being able to use the wrapped value directly, without explicitly unwrapping it — as if this weren’t an Optional at all — once you’re sure it is safe to do so: // this property will be set automatically when the nib loads @IBOutlet var myButton: UIButton! // this property will be set after time-consuming gathering of data var albums : [MPMediaItemCollection]! Referring to self Except in order to set an instance property, an initializer may not refer to self, explicitly or implicitly, until after all instance properties are initialized. This rule guarantees that the instance is fully formed before it is used. This code, for example, is illegal: struct Cat { var name : String var license : Int init(name:String, license:Int) { self.name = name meow() // too soon - compile error self.license = license } func meow() { println("meow") } } The call to the instance method meow is implicitly a reference to self — it means self.meow(). The initializer can say that, but not until it has fulfilled its primary contract of initializing all uninitialized properties. The call to the instance method meow simply needs to be moved down one line, so that it comes after both name and license have been initialized. Delegating initializers Initializers within an object type can call one another by using the special syntax self.init(...). This is the only situation in which init can be used explicitly as the name of a called method. An initializer that calls another initializer is called a delegating initializer. When an initializer delegates, the other initializer — the one that it delegates to — must completely initialize the instance first, and then the delegating initializer can work with the fully initialized instance, possibly setting again a var property that was Object Type Declarations and Features | 119 already set by the initializer that it delegated to. A delegating initializer cannot refer to self, not even to set a property, until after the call to the other initializer. For example: struct Digit { var number : Int var meaningOfLife : Bool init(number:Int) { self.number = number self.meaningOfLife = false } init() { self.init(number:42) self.meaningOfLife = true } } Moreover, a delegating initializer cannot set an immutable property (a let variable) at all. That is because it cannot refer to the property until after it has called the other initializer, and at that point the instance is fully formed — initialization proper is over, and the door for initialization of immutable properties has closed. Thus, the preceding code would be illegal if meaningOfLife were declared with let, because the second initializer is a delegating initializer and cannot set an immutable property. Be careful not to let an initializer delegate to itself, or to create a vicious circle of dele‐ gating initializers; the compiler won’t stop you (I regard that as a bug), but your running app will hang. For example, don’t say this: struct Digit { // do not do this! var number : Int = 100 init(value:Int) { self.init(number:value) } init(number:Int) { self.init(value:number) } } Failable initializers An initializer can return an Optional wrapping the new instance. In this way, nil can be returned to signal failure. An initializer that behaves this way is a failable initializer. To mark an initializer as failable when declaring it, put a question mark (or, for an implicitly unwrapped Optional, an exclamation mark) after the keyword init. If your failable initializer needs to return nil, explicitly write return nil. It is up to the caller to test the resulting Optional for equivalence with nil, unwrap it, and so forth, as with any Optional. Here’s a version of Dog with an initializer that returns an implicitly unwrapped Optional, returning nil if the name: or license: arguments are invalid: 120 | Chapter 4: Object Types class Dog { let name : String let license : Int init!(name:String, license:Int) { self.name = name self.license = license if name.isEmpty { return nil } if license <= 0 { return nil } } } The resulting value is typed as Dog! — the Optional is implicitly unwrapped — so the caller who instantiates a Dog in this way can use the result directly as if it were simply a Dog instance. But if nil was returned, any attempt on the caller’s part to access mem‐ bers of the Dog instance without testing for nil will result in a crash at runtime: let fido = Dog(name:"", license:0) let name = fido.name // crash Cocoa and Objective-C conventionally return nil from initializers to signal failure; the API for such initializers has been hand-tweaked as a Swift failable initializer if initiali‐ zation really might fail. For example, the UIImage initializer init?(named:) is a failable initializer, because there might be no image with the given name. It is not implicitly unwrapped, so the resulting value is a UIImage? and must be unwrapped before you can use it. (Most Objective-C initializers, however, are not bridged as failable initializers, even though in theory any Objective-C initializer might return nil.) Properties A property is a variable — one that happens to be declared at the top level of an object type declaration. That means that everything said about variables in Chapter 3 applies. A property has a fixed type; it can be declared with var or let; it can be stored or computed; it can have setter observers. An instance property can also be declared lazy. A stored instance property must be given an initial value. But, as I explained a moment ago, this doesn’t have to be through assignment in the declaration; it can be through an initializer instead. Setter observers are not called during initialization of properties. Code that initializes a property cannot fetch an instance property or call an instance method. Such behavior would require a reference, explicit or implicit, to self; and during initialization, there is no self yet — self is exactly what we are in the process of initializing. For example, this is illegal (and removing the explicit references to self doesn’t make it legal): Object Type Declarations and Features | 121 class Moi { let first = "Matt" let last = "Neuburg" let whole = self.first + " " + self.last // compile error } One solution in that situation would be to make whole a computed property: class Moi { let first = "Matt" let last = "Neuburg" var whole : String { return self.first + " " + self.last } } That’s legal because the computation won’t actually be performed until after self exists. Another solution is to declare whole as lazy: class Moi { let first = "Matt" let last = "Neuburg" lazy var whole : String = self.first + " " + self.last } Again, that’s legal because the reference to self won’t be performed until after self exists. Similarly, a property initializer can’t call an instance method: class Moi { let first = "Matt" let last = "Neuburg" var whole : String = self.wholeName() // compile error func wholeName() -> String { return self.first + " " + self.last } } But a computed property can: class Moi { let first = "Matt" let last = "Neuburg" var whole : String {return self.wholeName()} func wholeName() -> String { return self.first + " " + self.last } } And so can a lazy property: class Moi { let first = "Matt" let last = "Neuburg" lazy var whole : String = self.wholeName() 122 | Chapter 4: Object Types func wholeName() -> String { return self.first + " " + self.last } } As I demonstrated in Chapter 3, a variable’s initializer can consist of multiple lines of code if you write it as a define-and-call anonymous function. If this variable is a property, and if that code is to refer to self, the variable must be declared lazy: class Moi { let first = "Matt" let last = "Neuburg" lazy var whole : String = { var s = self.first s.extend(" ") s.extend(self.last) return s }() } If a property is an instance property (the default), it can be accessed only through an instance, and its value is separate for each instance. For example, let’s start once again with a Dog class: class Dog { let name : String let license : Int init(name:String, license:Int) { self.name = name self.license = license } } Our Dog class has a name instance property. Then we can make two different Dog in‐ stances with two different name values, and we can access each Dog instance’s name through the instance: let fido = Dog(name:"Fido", license:1234) let spot = Dog(name:"Spot", license:1357) let aName = fido.name // "Fido" let anotherName = spot.name // "Spot" A static/class property, on the other hand, is accessed through the type, and is scoped to the type, which usually means that it is global and unique. I’ll use a struct as an example: struct Greeting { static let friendly = "hello there" static let hostile = "go away" } Object Type Declarations and Features | 123 Now code elsewhere can fetch the values of Greeting.friendly and Greeting.hostile. That example is neither artificial nor trivial; immutable static/class properties are a convenient and effective way to supply your code with nicely name‐ spaced constants. Unlike instance properties, static properties can be initialized with reference to one another; the reason is that static property initializers are lazy (see Chapter 3): struct Greeting { static let friendly = "hello there" static let hostile = "go away" static let ambivalent = friendly + " but " + hostile } Notice the lack of self in that code. In static/class code, self means the type itself. I like to use self explicitly wherever it would be implicit, but here I can’t use it without arousing the ire of the compiler (I regard this as a bug). To clarify the status of the terms friendly and hostile, I can use the name of the type, just as any other code would do: struct Greeting { static let friendly = "hello there" static let hostile = "go away" static let ambivalent = Greeting.friendly + " but " + Greeting.hostile } On the other hand, if I write ambivalent as a computed property, I can use self: struct Greeting { static let friendly = "hello there" static let hostile = "go away" static var ambivalent : String { return self.friendly + " but " + self.hostile } } On the other other hand, I’m not allowed to use self when the initial value is a called anonymous function (again, I regard this as a bug): struct Greeting { static let friendly = "hello there" static let hostile = "go away" static var ambivalent : String = { return self.friendly + " but " + self.hostile // compile error }() } Methods A method is a function — one that happens to be declared at the top level of an object type declaration. That means that everything said about functions in Chapter 2 applies. 124 | Chapter 4: Object Types By default, a method is an instance method. This means that it can be accessed only through an instance. Within the body of an instance method, self is the instance. To illustrate, let’s continue to develop our Dog class: class Dog { let name : String let license : Int let whatDogsSay = "Woof" init(name:String, license:Int) { self.name = name self.license = license } func bark() { println(self.whatDogsSay) } func speak() { self.bark() println("I'm \(self.name)") } } Now I can make a Dog instance and tell it to speak: let fido = Dog(name:"Fido", license:1234) fido.speak() // Woof I'm Fido In my Dog class, the speak method calls the instance method bark by way of self, and obtains the value of the instance property name by way of self; and the bark instance method obtains the value of the instance property whatDogsSay by way of self. This is because instance code can use self to refer to this instance. Such code can omit self if the reference is unambiguous; thus, for example, I could have written this: func speak() { bark() println("I'm \(name)") } But I never write code like that (except by accident). Omitting self, in my view, makes the code harder to read and maintain; the loose terms bark and name seem mysterious and confusing. Moreover, sometimes self cannot be omitted. For example, in my im‐ plementation of init(name:license:), I must use self to disambiguate between the incoming local parameter name and the property self.name. Therefore, I prefer to write self explicitly wherever it can be written. Recall that the default rules for externalization of method parameter names are special: by default, the name of the first parameter is not externalized and the names of the other parameters are. This is the example I gave in Chapter 2: Object Type Declarations and Features | 125 class Dog { func say(s:String, times:Int) { for _ in 1...times { println(s) } } } That method’s name is say(times:), and here’s how to call it: let d = Dog() d.say("woof", times:3) A static/class method is accessed through the type, and self means the type. I’ll use our Greeting struct as an example: struct Greeting { static let friendly = "hello there" static let hostile = "go away" static var ambivalent : String { return self.friendly + " but " + self.hostile } static func beFriendly() { println(self.friendly) } } And here’s how to call the static beFriendly method: Greeting.beFriendly() // hello there There is a kind of conceptual wall between static/class members, on the one hand, and instance members on the other; even though they may be declared within the same object type declaration, they inhabit different worlds. A static/class method can’t refer to “the instance” because there is no instance; thus, a static/class method cannot directly refer to any instance properties or call any instance methods. An instance method, on the other hand, can refer to the type by name, and can thus access static/class properties and can call static/class methods. (I’ll talk later in this chapter about another way in which an instance method can refer to the type.) For example, let’s return to our Dog class and grapple with the question of what dogs say. Presume that all dogs say the same thing. We’d prefer, therefore, to express what- DogsSay not at instance level but at class level. This would be a good use of a static property. Here’s a simplified Dog class that illustrates: class Dog { static var whatDogsSay = "Woof" func bark() { println(Dog.whatDogsSay) } } 126 | Chapter 4: Object Types The Secret Life of Instance Methods Here’s a secret: instance methods are actually static/class methods. For example, this is legal (but strange): class MyClass { var s = "" func store(s:String) { self.s = s } } let m = MyClass() let f = MyClass.store(m) // what just happened!? Even though store is an instance method, we are able to call it as a class method — with a parameter that is an instance of this class! The reason is that an instance method is actually a curried static/class method composed of two functions — one function that takes an instance, and another function that takes the parameters of the instance meth‐ od. Thus, after that code, f is the second of those functions, and can be called as a way of passing a parameter to the store method of the instance m: f("howdy") println(m.s) // howdy Now we can make a Dog instance and tell it to bark: let fido = Dog() fido.bark() // Woof Subscripts A subscript is an instance method that is called in a special way — by appending square brackets to an instance reference. The square brackets can contain arguments to be passed to the subscript method. You can use this feature for whatever you like, but it is suitable particularly for situations where this is an object type with elements that can be appropriately accessed by key or by index number. I have already described (in Chap‐ ter 3) the use of this syntax with strings, and it is familiar also from dictionaries and arrays; you can use square brackets with strings and dictionaries and arrays exactly because Swift’s String and Dictionary and Array types declare subscript methods. The syntax for declaring a subscript method is somewhat like a function declaration and somewhat like a computed property declaration. That’s no coincidence! A subscript is like a function in that it can take parameters: arguments can appear in the square brackets when a subscript method is called. A subscript is like a computed property in that the call is used like a reference to a property: you can fetch its value or you can assign into it. Object Type Declarations and Features | 127 To illustrate, I’ll write a struct that treats an integer as if it were a string, returning a digit that can be specified in square brackets; for simplicity, I’m deliberately omitting any sort of error-checking: struct Digit { var number : Int init(_ n:Int) { self.number = n } subscript(ix:Int) -> Int { get { let s = String(self.number) return String(Array(s)[ix]).toInt()! } } } After the keyword subscript we have a parameter list stating what parameters are to appear inside the square brackets; by default, their names are not externalized. Then, after the arrow operator, we have the type of value that is passed out (when the getter is called) or in (when the setter is called); this is parallel to the type declared for a computed property, even though the syntax with the arrow operator is like the syntax for the returned value in a function declaration. Finally, we have curly braces whose contents are exactly like those of a computed property. You can have get and curly braces for the getter, and set and curly braces for the setter. If there’s a getter and no setter, the word get and its curly braces can be omitted. The setter receives the new value as newValue, but you can change that name by supplying a different name in parentheses after the word set. Here’s an example of calling the getter; the instance with appended square brackets containing the arguments is used just as you were getting a property value: var d = Digit(1234) let aDigit = d[1] // 2 Now I’ll expand my Digit struct so that its subscript method includes a setter (and again I’ll omit error-checking): struct Digit { var number : Int init(_ n:Int) { self.number = n } subscript(ix:Int) -> Int { get { let s = String(self.number) 128 | Chapter 4: Object Types return String(Array(s)[ix]).toInt()! } set { var arr = Array(String(self.number)) arr[ix] = Character(String(newValue)) self.number = String(arr).toInt()! } } } And here’s an example of calling the setter; the instance with appended square brackets containing the arguments is used just as if you were setting a property value: var d = Digit(1234) d[0] = 2 // now d.number is 2234 An object type can declare multiple subscript methods, provided their signatures dis‐ tinguish them as different functions. Namespaced Object Types An object type may be declared inside an object type declaration: class Dog { struct Noise { static var noise = "Woof" } func bark() { println(Dog.Noise.noise) } } Such an object type is no different from any other object type, but the rules for referring to it from the outside are changed; the surrounding object type acts as a namespace, and must be referred to explicitly in order to access the embedded object type: Dog.Noise.noise = "Arf" The Noise struct is thus namespaced inside the Dog class. This namespacing provides clarity: the name Noise does not float free, but is explicitly associated with the Dog class to which it belongs. Namespacing also allows more than one Noise struct to exist, without any clash of names. Swift built-in object types often take advantage of name‐ spacing; for example, the String struct is one of several structs that contain an Index struct, with no clash of names. (It is also possible, through Swift’s privacy rules, to hide an embedded object type, in such a way that it cannot be referenced from the outside at all. This is useful for orga‐ nization and encapsulation when one object type needs a second object type as a helper, but no other object type needs to know about the second object type. Privacy is discussed in Chapter 5.) Object Type Declarations and Features | 129 Instance References On the whole, the names of object types will be global, and you will be able to refer to them simply by using their names. Instances, however, are another story. Instances must be deliberately created, one by one. That is what instantiation is for. Once you have created an instance, you can cause that instance to persist, by storing the instance in a variable with sufficient lifetime; using that variable as a reference, you can send instance messages to that instance, accessing instance properties and calling instance methods. Direct instantiation of an object type is the act of creating a brand new instance of that type, directly, yourself. It involves you calling an initializer. In many cases, though, some other object will create or provide the instance for you. A simple example is what happens when you manipulate a String, like this: let s = "Hello, world" let s2 = s.uppercaseString In that code, we ended up with two String instances. The first one, s, we created using a string literal. The second one, s2, was created for us when we accessed the first string’s uppercaseString property. Thus we have two instances, and they will persist inde‐ pendently as long as our references to them persist; but we didn’t get either of them by calling an initializer. In other cases, the instance you are interested in will already exist in some persistent fashion; the problem will then be to find a way of getting a reference to that instance. Let’s say, for example, that this is a real-life iOS app. You will certainly have a root view controller, which will be an instance of some type of UIViewController. Let’s say it’s an instance of the ViewController class. Once your app is up and running, this instance already exists. It would then be utterly counterproductive to attempt to speak to the root view controller by instantiating the ViewController class: let theVC = ViewController() All that code does is to make a second, different instance of the ViewController class, and your messages to that instance will be wasted, as it is not the particular already existing instance that you wanted to talk to. That is a very common beginner mistake; don’t make it. Getting a reference to an already existing instance can be, of itself, an interesting prob‐ lem. Instantiation is definitely not how to do it. But how do you do it? Well, it depends. In this particular situation, the goal is to obtain, from any code, a reference to your app’s root view controller instance. I’ll describe, just for the sake of the example, how you would do it. 130 | Chapter 4: Object Types Getting a reference always starts with something you do have a reference to. Often, this will be a class. In iOS programming, the app itself is an instance, and there is a class that holds a reference to that instance and will hand it to you whenever you ask for it. That class is the UIApplication class, and the way to get a reference to the app instance is to call its sharedApplication class method: let app = UIApplication.sharedApplication() Now we have a reference to the application instance. The application instance has a key- Window property: let window = app.keyWindow Now we have a reference to our app’s key window. That window owns the root view controller, and will hand us a reference to it, as its own rootViewController property; the app’s keyWindow is an Optional, so to get at its rootViewController we must unwrap the Optional: let vc = window?.rootViewController And voilà, we have a reference to our app’s root view controller. In this case, we don’t need to worry about the persistence of the resulting instance; it persists as part of the app itself. To obtain the reference to this persistent instance, we created, in effect, a chain of method calls and properties leading from the known to the unknown, from a globally available class to the particular desired instance: let app = UIApplication.sharedApplication() let window = app.keyWindow let vc = window?.rootViewController Clearly, we can write that chain as a single chain, using repeated dot-notation: let vc = UIApplication.sharedApplication().keyWindow?.rootViewController You don’t have to chain your instance messages into a single line — chaining through multiple let assignments is completely efficient, possibly more legible, and certainly easier to debug — but it’s a handly formulaic convenience and is particularly charac‐ teristic of dot-notated object-oriented languages like Swift. The general problem of getting a reference to a particular already existing instance is so interesting and pervasive that I will devote much of Chapter 13 to it. Enums An enum is an object type whose instances represent distinct predefined alternative val‐ ues. Think of it as a list of known possibilities. An enum is the Swift way to express a set of constants that are alternatives to one another. For example, in my Albumen app, different instances of the same view controller can list any of four different sorts of music library contents: albums, playlists, podcasts, or Enums | 131 audiobooks. The view controller’s behavior is slightly different in each case. So I need a sort of four-way switch that I can set once when the view controller is instantiated, saying which sort of contents this view controller is to display. That sounds like an enum! Here’s the basic declaration for that enum: enum ListType { case Albums case Playlists case Podcasts case Books } The enum declaration includes case statements. Each case is the name of one of the alternatives. Every instance of a ListType will represent exactly one alternative, which cannot be changed. Observe that my ListType enum doesn’t have an initializer. You can write an initializer for an enum, but there is a default mode of initialization that you’ll probably use instead most of the time: use the name of the enum followed by dot-notation and one of the cases. For example, here’s how to make an instance of ListType representing the Albums case: let type = ListType.Albums As a shortcut, if the type is known in advance, you can omit the name of the enum; the bare case must still be preceded by a dot. For example: let type : ListType = .Albums You can’t say .Albums just anywhere out of the blue, because Swift doesn’t know what enum it belongs to. But in that code, the variable is explicitly declared as a ListType, so Swift knows what .Albums means. A similar thing happens when passing an enum instance as an argument in a function call: func listTypeExpecter(type:ListType) {} listTypeExpecter(.Albums) In the second line, I create an instance of ListType and pass it, all in one move, and without having to include the name of the enum. That’s because Swift knows from the function declaration that a ListType is expected here. In real life, the space savings when omitting the enum name can be considerable — especially because, when talking to Cocoa, the enum type names are often long. For example: let v = UIView() v.autoresizingMask = .None 132 | Chapter 4: Object Types Figure 4-1. An enum value displayed in the debugger A UIView’s autoresizingMask property is typed as a UIViewAutoresizing enum. Our code is neater and simpler because we don’t have to include the name UIViewAutore‐ sizing explicitly here. .None is nicer than UIViewAutoresizing.None. But either is legal. Code inside an enum declaration can use a case name without dot-notation. The enum is a namespace; code inside the declaration is inside the name‐ space, so it can see the case names directly. Instances of an enum with the same case are regarded as equal. Thus, you can compare an enum instance for equality against a case. Again, the type of enum is known from the first term in the comparison, so the second term can omit the enum name: func listTypeExpecter(type:ListType) { if type == .Albums { println("it's albums") } } listTypeExpecter(.Albums) // "it's albums" In the console, logging an enum with println yields, by default, an opaque, unhelpful description — (Enum Value). But the Xcode debugger’s variables list displays the actual case name (Figure 4-1). Case With Fixed Value Optionally, when you declare an enum, you can add a type declaration. The cases then all carry with them a fixed (constant) value of that type. If the type is an integer numeric type, the values can be implicitly assigned, and will start at zero automatically: enum ListType : Int { case Albums case Playlists case Podcasts case Books } In that code, .Albums carries a value of 0, .Playlists carries of a value of 1, and so on. Alternatively, you can assign values as part of the case declarations, and if the type is not an integer type, you must do so: Enums | 133 enum ListType : String { case Albums = "Albums" case Playlists = "Playlists" case Podcasts = "Podcasts" case Books = "Audiobooks" } The types attached to an enum in this way are limited to numbers and strings, and the values assigned must be literals. The values carried by the cases are called their raw values. An instance of this enum has just one case, so it has just one raw value, which can be retrieved with its rawValue property: let type = ListType.Albums println(type.rawValue) // Albums Having each case carry a value with it can be quite useful. In my Albumen app, the ListType cases really do have those String values, and so when the view controller wants to know what title string to put at the top of the screen, it simply retrieves the current type’s rawValue. The raw value associated with each case must be unique within this enum; the compiler will enforce this rule. Therefore, the mapping works the other way: given a raw value, you can derive the case. For example, you can instantiate an enum that has raw values by using its rawValue: initializer: let type = ListType(rawValue:"Albums") However, the attempt to instantiate the enum in this way might fail, because you might supply a raw value corresponding to no case; therefore, this is a failable initializer, and the value returned is an Optional. In that code, type is not a ListType; it’s an Optional wrapping a ListType. This might not be terribly important, however, because the thing you are most likely to want to do with an enum is to compare it for equality with a case of the enum; you can do that with an Optional without unwrapping it. This code is legal and works correctly: let type = ListType(rawValue:"Albums") if type == .Albums { // ... Other uses of an Optional wrapping an enum, however, may require that you unwrap it first. Case With Typed Value The raw values discussed in the preceding section are fixed in advance: a given case carries with it a certain raw value, and that’s that. Alternatively, you can construct a case whose constant value can be set when the instance is created. To do so, do not declare any type for the enum as a whole; instead, append a tuple type to the name of the case. There will usually be just one type in this tuple, so what you’ll write will look like a type name in parentheses. Any type may be declared. Here’s an example: 134 | Chapter 4: Object Types enum Error { case Number(Int) case Message(String) case Fatal } That code means that, at instantiation time, an Error instance with the .Number case must be assigned an Int value, an Error instance with the .Message case must be assigned a String value, and an Error instance with the .Fatal case can’t be assigned any value. Instantiation with assignment of a value is really a way of calling an initialization func‐ tion, so to supply the value, you pass it as an argument in parentheses: let err : Error = .Number(4) The attached value here is called an associated value. What you are supplying here is actually a tuple, so it can contain literal values or value references; this is legal: let num = 4 let err : Error = .Number(num) The tuple can contain more than one value, with or without names; if the values have names, they must be used at initialization time: enum Error { case Number(Int) case Message(String) case Fatal(n:Int, s:String) } let err : Error = .Fatal(n:-12, s:"Oh the horror") Now let’s talk about how to extract the associated value from an actual instance of the enum later on. This requires an elaborate dance using a switch statement to distinguish each case along with a variable binding to capture the associated value in a variable name. I’ll explain about switch statements with variable bindings in Chapter 5; until then, you’ll just have to trust me. The typical syntax will have this form: switch err { case .Number(let theNumber): println("number: \(theNumber)") case .Message(let theMessage): println("message: \(theMessage)") case .Fatal(let theNumber, let theMessage): println("number: \(theNumber), message: \(theMessage)") } At the risk of sounding like a magician explaining his best trick, I will now reveal how an Optional works. An Optional is simply an enum with two cases: .None and .Some. If it is .None, it carries no associated value, and it equates to nil. If it is .Some, it carries the wrapped value as its associated value. Thus, we can unwrap an Optional using exactly the same switch syntax: Enums | 135 let s : String? = "howdy" switch s { case .Some(let theString): println(theString) // howdy case .None: println("it's nil") } Enum Initializers An explicit enum initializer must do what the built-in initialization syntax does: it must return a particular case of this enum. To do so, set self to the case. In this example, I’ll expand my ListType enum so that it can be initialized with a numeric argument: enum ListType : String { case Albums = "Albums" case Playlists = "Playlists" case Podcasts = "Podcasts" case Books = "Audiobooks" static var cases : [ListType] = [Albums, Playlists, Podcasts, Books] init(_ ix:Int) { self = ListType.cases[ix] } } Now there are three ways to make a ListType instance: let type1 = ListType.Albums let type2 = ListType(rawValue:"Playlists")! let type3 = ListType(2) // .Podcasts In that example, we’ll crash in the third line if the caller passes a number that’s out of range (less than 0 or greater than 3). If we want to avoid that, we can make this a failable initializer and return nil if the number is out of range: enum ListType : String { case Albums = "Albums" case Playlists = "Playlists" case Podcasts = "Podcasts" case Books = "Audiobooks" static var cases : [ListType] = [Albums, Playlists, Podcasts, Books] init!(_ ix:Int) { if !(0...3).contains(ix) { return nil } self = ListType.cases[ix] } } An enum can have multiple initializers. Enum initializers can delegate to one another by saying self.init(...). The only requirement is that, at some point in the calling chain, self must be set to a case; if that doesn’t happen, your enum won’t compile. 136 | Chapter 4: Object Types In this example, I improve my ListType enum so that it can be initialized with a String raw value without having to say rawValue: in the call. To do so, I declare a failable initializer with no parameters that delegates to the built-in failable rawValue: initializer: enum ListType : String { case Albums = "Albums" case Playlists = "Playlists" case Podcasts = "Podcasts" case Books = "Audiobooks" static var cases : [ListType] = [Albums, Playlists, Podcasts, Books] init!(_ ix:Int) { if !(0...3).contains(ix) { return nil } self = ListType.cases[ix] } init!(_ rawValue:String) { self.init(rawValue:rawValue) } } Now there are four ways to make a ListType instance: let type1 = ListType.Albums let type2 = ListType(rawValue:"Playlists") let type3 = ListType(2) // .Podcasts let type4 = ListType("Playlists") Enum Properties An enum can have properties, but there’s a limitation: an enum instance property can’t be a stored property. This makes sense, because if two instances of the same case could have different stored instance property values, they would no longer be equal to one another — which would undermine the nature and purpose of enums. Computed properties are fine, however. For example, you’ll often implement a description read-only instance property, so as to be able to log something other than an opaque value: enum ListType : String { case Albums = "Albums" case Playlists = "Playlists" case Podcasts = "Podcasts" case Books = "Audiobooks" var description : String { return self.rawValue } } That gives us a way to learn, in the console, what case we’ve actually got: let type = ListType.Albums println(type.description) // "Albums" Enums | 137 Later, I’ll show how to make println fetch our description property value automati‐ cally, so that simply calling println(type) will log "Albums". If an enum instance property is a computed variable with a setter, other code can assign to this property. However, that code’s reference to the enum instance must be a variable (var), not a constant (let). If you try to assign to an enum instance property through a let reference, you’ll get a compile error. Enum Methods Writing an enum method is straightforward. Here’s an example from my own code. In a card game, the cards draw themselves as rectangles, ellipses, or diamonds. I’ve ab‐ stracted the drawing code into an enum that draws itself as a rectangle, an ellipse, or a diamond, depending on its case: enum ShapeMaker { case Rectangle case Ellipse case Diamond func drawShape (p: CGMutablePath, inRect r : CGRect) -> () { switch self { case Rectangle: CGPathAddRect(p, nil, r) case Ellipse: CGPathAddEllipseInRect(p, nil, r) case Diamond: CGPathMoveToPoint(p, nil, r.minX, r.midY) CGPathAddLineToPoint(p, nil, r.midX, r.minY) CGPathAddLineToPoint(p, nil, r.maxX, r.midY) CGPathAddLineToPoint(p, nil, r.midX, r.maxY) CGPathCloseSubpath(p) } } } An enum instance method that modifies the enum itself in any way must be marked as mutating. For example, an enum instance method might assign to an instance property of self; even though this is a computed property, such assignment is illegal unless the method is marked as mutating. An enum instance method can even change the case of self, by assigning to self; but again, the method must be marked as mutating. The caller of a mutating instance method must have a variable reference to the instance (var), not a constant reference (let). In this example, I add an advance method to my ListType enum. The idea is that the cases are a sequence, and the sequence can cycle. By calling advance, I transform a ListType instance into an instance of the next case in the sequence: 138 | Chapter 4: Object Types enum ListType : String { case Albums = "Albums" case Playlists = "Playlists" case Podcasts = "Podcasts" case Books = "Audiobooks" static var cases : [ListType] = [Albums, Playlists, Podcasts, Books] mutating func advance() { var ix = find(ListType.cases, self)! ix = (ix + 1) % 4 self = ListType.cases[ix] } } And here’s how to call it: var type = ListType.Books type.advance() // type is now ListType.Albums (A subscript setter is always considered mutating and does not have to be specially marked.) Why Enums? An enum is a switch whose states have names. There are many situations where that’s a desirable thing. You could implement a multistate value yourself; for example, if there are five possible states, you could use an Int whose values can be 0 through 4. But then you would have to provide a lot of additional overhead — making sure that no other values are used, and interpreting those numeric values correctly. A list of five named cases is much better! Even when there are only two states, an enum is often better than, say, a mere Bool, because the enum’s states have names. With a Bool, you have to know what true and false signify in a particular usage; with an enum, the name of the enum and the names of its cases tell you its significance. Moreover, you can store extra infor‐ mation in an enum’s associated value or raw value; you can’t do that with a mere Bool. For example, in my LinkSame app, the user can play a real game with a timer or a practice game without a timer. At various places in the code, I need to know which type of game this is. The values are an enum whose cases are .Timed and .Practice: enum InterfaceMode : Int { case Timed = 0 case Practice = 1 } The current game type is stored in an instance property interfaceMode, whose value is an InterfaceMode. Thus, it’s easy to set the game type by case name: // ... initialize new game ... self.interfaceMode = .Timed And it’s easy to examine the game type by case name: Enums | 139 // notify of high score only if user is not just practicing if self.interfaceMode == .Timed { // ... So what are the raw value integers for? That’s the really clever part. They correspond to the segment indexes of a UISegmentedControl in the interface! Whenever I change the interfaceMode property, a setter observer also selects the corresponding segment of the UISegmentedControl, simply by fetching the rawValue of the current enum case: var interfaceMode : InterfaceMode = .Timed { willSet (mode) { self.timedPractice.selectedSegmentIndex = mode.rawValue } } Structs A struct is the Swift object type par excellence. An enum, with its fixed set of cases, is a reduced, specialized kind of object. A class, at the other extreme, will often turn out to be overkill; it has some features that a struct lacks, but if you don’t need those features, a struct may be preferable. Nearly all the built-in object types provided by Swift itself are structs. Of the numerous object type declarations in the Swift header, only three are class declarations. A String is a struct. An Int is a struct. A Range is a struct. An Array is a struct. And so on. That shows how powerful a struct can be. Struct Initializers, Properties, and Methods A struct that doesn’t have an explicit initializer and that doesn’t need an explicit initializer — because it has no stored properties, or because all its stored properties are assigned default values as part of their declaration — automatically gets an implicit initializer with no parameters, init(). For example: struct Digit { var number = 42 } That struct can be initialized by saying Digit(). But if you add any explicit initializers of your own, you lose the implicit initializer: struct Digit { var number = 42 init(number:Int) { self.number = number } } Now you can say Digit(number:42), but you can’t say Digit() any longer. Of course, you can add an explicit initializer that does the same thing: 140 | Chapter 4: Object Types struct Digit { var number = 42 init() {} init(number:Int) { self.number = number } } Now you can say Digit() once again, as well as Digit(number:42). A struct that has stored properties and that doesn’t have an explicit initializer automat‐ ically gets an implicit initializer derived from its instance properties. This is called the memberwise initializer. For example: struct Digit { var number : Int } That struct is legal, even though it seems we have not fulfilled the contract requiring us to initialize all its stored properties in their declaration or in an initializer. The reason is that this struct automatically has a memberwise initializer which does initialize all its properties. In this case, the memberwise initializer is called init(number:). The memberwise initializer exists even if the stored properties are assigned a default value in their declaration; this struct has a memberwise initializer init(number:) as well (in addition to its implicit init() initializer): struct Digit { var number : Int = 42 } But if you add any explicit initializers of your own, you lose the memberwise initializer (though of course you can write an explicit initializer that does the same thing). If a struct has any explicit initializers, then they must fulfill the contract that all stored properties must be initialized either by direct initialization in the declaration or by all initializers. If a struct has multiple explicit initializers, they can delegate to one another by saying self.init(...). (See the discussion of delegating initializers earlier in this chapter.) A struct can have instance properties and static properties, and they can be stored or computed variables. If other code wants to set a property of a struct instance, its refer‐ ence to that instance must be a variable (var), not a constant (let). A struct can have instance methods and static methods. If an instance method sets a property, it must be marked as mutating, and the caller’s reference to the struct instance must be a variable (var), not a constant (let). A mutating instance method can even replace this instance with another instance, by setting self to a different instance of the Structs | 141 same struct. (A subscript setter is always considered mutating and does not have to be specially marked.) Struct As Namespace I very often use a degenerate struct as a handy namespace for constants. I call such a struct “degenerate” because it consists entirely of static members; I don’t intend to use this object type to make any instances. Nevertheless, there is absolutely nothing wrong with this use of a struct. For example, let’s say I’m going to be storing user preference information in Cocoa’s NSUserDefaults. NSUserDefaults is a kind of dictionary: each item is accessed through a key. The keys are typically strings. A common programmer mistake is to write out these string keys literally every time a key is used; if you then misspell a key name, there’s no penalty at compile time, but your code will mysteriously fail to work correctly. The proper approach is to embody these keys as constant strings and use the names of the strings; that way, if you make a mistake typing the name of a string, the compiler can catch you. A struct with static members is a great way to define those constant strings and clump their names into a namespace: struct Default { static let Size = "Size" static let Style = "Style" static let HazyStripy = "HazyStripy" } That code means that I can now refer to an NSUserDefaults key with a name, such as Default.HazyStripy. If a struct declares static members whose values are instances of the same struct type, you can omit the struct name when supplying a static member where an instance of this struct type is expected — as if the struct were an enum: struct Thing { var val : Int = 0 static var One : Thing = Thing(val:1) static var Two : Thing = Thing(val:2) } let thing : Thing = .One // no need to say Thing.One here The example is artificial, but the situation is not; many Objective-C enums are bridged to Swift as that kind of struct. Classes A class is similar to a struct, with the following key differences: 142 | Chapter 4: Object Types Reference type Classes are reference types. This means, among other things, that a class instance has two remarkable features that are not true of struct instances or enum instances: Mutability A class instance is mutable in place. Even if your reference to an instance of a class is a constant (let), you can change the value of an instance property through that reference. An instance method of a class never has to be marked mutating (and cannot be). Multiple references When a given instance of a class is assigned to multiple variables or passed as argument to a function, you get multiple references to one and the same object. Inheritance A class can have a superclass. A class that has a superclass is a subclass of that superclass. Class types can thus form a hierarchical tree. In Objective-C, classes are the only object type. Some built-in Swift struct types are magically bridged to Objective-C class types, but your custom struct types don’t have that magic. Thus, in Swift, a primary reason for declaring a class, rather than a struct, is as a form of interchange with Objective-C and Cocoa. Value Types and Reference Types A major difference between enums and structs, on the one hand, and classes, on the other hand, is that enums and structs are value types, whereas classes are reference types. When an enum instance or a struct instance is assigned to a variable, or passed to or from a function, what is assigned or passed is essentially a new copy of that instance. But when a class instance is assigned to a variable, or passed to or from a function, what is assigned or passed is a reference to the same instance. An easy way to encounter this difference in practice is with a constant reference. Con‐ sider a variable declared with let. As you know, a variable declared with let cannot be assigned to. Now let’s talk about what happens when the variable refers to a struct in‐ stance, and that struct instance has a property — and we try to assign to that property. Even if the property is declared with var, we can’t assign to it through a let reference: struct Digit { var number : Int init(_ n:Int) { self.number = n } } let d = Digit(123) d.number = 42 // compile error: cannot assign to 'number' in 'd' Classes | 143 The reason is that a struct is a value type. This means that the only way to change a property of a struct instance is, behind the scenes, to make a new struct instance and replace the first struct instance with it. But we can’t replace the Digit instance pointed to by d with another Digit instance, because that would mean assigning into d — which the let declaration forbids us to do. To prove to yourself that what I’m saying is true, try putting a setter observer on a reference to a struct; you will see that setting a property of that struct calls the setter observer: var d : Digit = Digit(123) { didSet { println("d was set") } } d.number = 42 // "d was set" In that code, we didn’t actually set d; we set a property of d. But it amounts to the same thing, because d refers to a struct instance, a value type. To set a property of the instance referred to by d requires us to set d to another struct instance — which, as the setter observer shows, is what we are doing when we set the number property by way of d. That is why an instance method of a struct or enum that sets a property of the instance must be marked explicitly with the mutating keyword. For example: struct Digit { var number : Int init(_ n:Int) { self.number = n } mutating func changeNumberTo(n:Int) { self.number = n } } Without the mutating keyword, that code won’t compile. The mutating keyword as‐ sures the compiler that you understand what’s really happening here: if that method is called, it mutates the instance, and so it can be called only on a reference declared with var, not let. (A subscript setter is always a mutating method; you don’t need to, and cannot, declare a subscript with the mutating keyword.) None of what I’ve just said, however, applies to class instances! Class instances are ref‐ erence types, not value types. An instance property of a class, to be settable, must be declared with var, obviously; but the reference to a class instance does not have to be declared with var in order to set that property through that reference: 144 | Chapter 4: Object Types class Dog { var name : String = "Fido" } let rover = Dog() rover.name = "Rover" // fine In the last line of that code, the class instance pointed to by rover is being mutated in place. No implicit assignment to rover is involved, and so the let declaration is pow‐ erless to prevent the mutation. A setter observer on a Dog variable is not called when a property is set: var rover : Dog = Dog() { didSet { println("did set rover") } } rover.name = "Rover" // nothing in console The setter observer would be called if we were to set rover explicitly (to another Dog instance), but it is not called merely because we change a property of the Dog instance already pointed to by rover. Those examples involve a declared variable reference. Exactly the same difference be‐ tween a value type and a reference type may be seen with an argument passed as pa‐ rameter to a function call. The compiler will stop us in our tracks if we try to assign into an enum parameter’s instance property or a struct parameter’s instance property. This doesn’t compile: func digitChanger(d:Digit) { d.number = 42 // compile error: cannot assign to 'number' in 'd' } To make that code compile, we must declare the parameter with var: func digitChanger(var d:Digit) { d.number = 42 } But this compiles even without the var declaration: func dogChanger(d:Dog) { d.name = "Rover" } The underlying reason for these differences between value types and reference types is that, with a reference type, there is in effect a concealed level of indirection between your reference to the instance and the instance itself; the reference actually refers to a pointer to the instance. This, in turn, has another important implication: it means that when a class instance is assigned to a variable or passed as an argument to a function, you can wind up with multiple references to the same object. That is not true of structs and enums. Classes | 145 To prove it, I’ll assign one reference to another and then mutate the second reference — and then I’ll examine what happened to the first reference. Let’s start with the struct: var d = Digit(123) println(d.number) // 123 var d2 = d // assignment! d2.number = 42 println(d.number) // 123 In that code, we changed the number property of d2, a struct instance; but nothing happened to the number property of d. Now let’s try the class: var fido = Dog() println(fido.name) // Fido var rover = fido // assignment! rover.name = "Rover" println(fido.name) // Rover In that code, we changed the name property of rover, a class instance — and the name property of fido was changed as well! That’s because, after the assignment in the third line, fido and rover refer to one and the same instance. When an enum or struct instance is assigned, it is effectively copied; a fresh, separate instance is created. But when a class instance is assigned, you get a new reference to the same instance. The same thing is true of parameter passing. Let’s start with the struct: func digitChanger(var d:Digit) { d.number = 42 } var d = Digit(123) println(d.number) // 123 digitChanger(d) println(d.number) // 123 We passed our Digit struct instance d to the function digitChanger, which set the number property of its local parameter d to 42. Nevertheless, the number property of our Digit d remains 123. That’s because the Digit that arrives inside digitChanger is quite literally a different Digit. The act of passing a Digit as a function parameter creates a separate copy. But with a class instance, what is passed is a reference to the same instance: func dogChanger(d:Dog) { // no "var" needed d.name = "Rover" } var fido = Dog() println(fido.name) // "Fido" dogChanger(fido) println(fido.name) // "Rover" The change made to d inside the function dogChanger affected our Dog instance fido! Handing a class instance to a function does not copy that instance; it is more like lending that instance to the function. 146 | Chapter 4: Object Types Recursive References Another consequence of the difference between value types and reference types is that a value type cannot be structurally recursive: an instance property of a value type cannot be an instance of the same type. This code won’t compile: struct Dog { // compile error var puppy : Dog? } (More complex circular chains, such as a Dog with a Puppy property and a Puppy with a Dog property, are similarly illegal.) But if Dog is a class instead of a struct, there’s no error. This is a consequence of the nature of memory management of value types as opposed to reference types. I’ll talk more about reference type memory management in Chapter 5, and Chapter 12 will be entirely devoted to it. The ability to generate multiple references to the same instance is significant particularly in a world of object-based programming, where objects persist and can have properties that persist along with them. If object A and object B are both long-lived objects, and if they both have a Dog property (where Dog is a class), and if they have each been handed a reference to one and the same Dog instance, then either object A or object B can mutate its Dog, and this mutation will affect the other’s Dog. You can thus be holding on to an object, only to discover that it has been mutated by someone else behind your back. The problem is even more acute in a multithreaded app, where one and the same object can be mutated differently, in place, by two different threads. None of these issues arise with a value type. The fact that class instances are reference types can thus be bad. But it is also good! It’s good because it means that passing a class instance is extremely simple and efficient: all you’re doing is passing a pointer. No matter how big and complicated a class instance may be, no matter how many properties it may have containing vast amounts of data, passing the instance is incredibly fast and efficient, because no new data is generated. Subclass and Superclass Two classes 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. Classes | 147 Figure 4-2. Part of the Cocoa class hierarchy as shown in Xcode As far as the Swift language itself is concerned, there is no requirement that a class should have any superclass, or that, if it does have a superclass, it should ultimately be descended from any particular base class. Thus, a Swift program can have many classes that have no superclass, and it can have many independent hierarchical subclass trees, each de‐ scended from a different base class. Cocoa, however, doesn’t work that way. In Cocoa, there is effectively just one base class — NSObject, which embodies all the functionality necessary for a class to be a class in the first place — and all other classes are subclasses, at some level, of that one base class. Cocoa thus consists of one 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 diagram‐ ming this tree as an outline. And in fact Xcode will show you this outline (Figure 4-2): in an iOS project window, choose View → Navigators → Show Symbol Navigator and click Hierarchical, with the first and third icons in the filter bar selected (blue). The Cocoa classes are the part of the tree descending from NSObject. The reason for having a superclass–subclass relationship in the first place is to allow related classes to share functionality. Suppose, for example, we have a Dog class and a Cat class, and we are considering declaring 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 declare walk as a method of the Quadruped 148 | Chapter 4: Object Types class, and make both Dog and 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 superclass that does have a walk method. We say that a subclass inherits the methods of its superclass. To declare that a certain class is a subclass of a certain superclass, add a colon and the superclass name after the class’s name in its declaration. So, for example: class Quadruped { func walk () { println("walk walk walk") } } class Dog : Quadruped {} class Cat : Quadruped {} Now let’s prove that Dog has indeed inherited walk from Quadruped: let fido = Dog() fido.walk() // walk walk walk Observe that, in that code, the walk message can be sent to a Dog instance just as if the walk instance method were declared in the Dog class, even though the walk instance method is in fact declared in a superclass of Dog. That’s inheritance at work. The purpose of subclassing is not merely so that a class can inherit another class’s meth‐ ods; it’s so that it can also declare 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, after all, 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 declare 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: class Quadruped { func walk () { println("walk walk walk") } } class Dog : Quadruped { func bark () { println("woof") } } Again, let’s prove that it works: let fido = Dog() fido.walk() // walk walk walk fido.bark() // woof Classes | 149 Within a class, it is a matter of indifference whether that class has an instance method because that method is declared in that class or because the method is declared in a superclass and inherited. A message to self works equally well either way. In this code, we have declared a barkAndWalk instance method that sends two messages to self, without regard to where the corresponding methods are declared (one is native to the subclass, one is inherited from the superclass): class Quadruped { func walk () { println("walk walk walk") } } class Dog : Quadruped { func bark () { println("woof") } func barkAndWalk() { self.bark() self.walk() } } And here’s proof that it works: let fido = Dog() fido.barkAndWalk() // woof walk walk walk 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 declares bark, but NoisyDog also declares bark, and defines it differently from how Dog defines it. This is called over‐ riding. 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. In Swift, when you override something inherited from a superclass, you must explicitly acknowledge this fact by preceding its declaration with the keyword override. So, for example: class Quadruped { func walk () { println("walk walk walk") } } class Dog : Quadruped { func bark () { println("woof") } } class NoisyDog : Dog { 150 | Chapter 4: Object Types override func bark () { println("woof woof woof") } } And let’s try it: let fido = Dog() fido.bark() // woof let rover = NoisyDog() rover.bark() // woof woof woof Observe that a subclass function by the same name as a superclass’s function is not necessarily, of itself, an override. Recall that Swift can distinguish two functions with the same name, provided they have different signatures. Those are different functions, and so an implementation of one in a subclass is not an override of the other in a superclass. An override situation exists only when the subclass redefines the same func‐ tion that it inherits from a superclass — using the same name, the same signature, and the same external parameter names. It often happens that we want to override something in a subclass and yet access the thing overridden in the superclass. This is done by sending a message to the keyword super. Our bark implementation in NoisyDog is a case in point. What NoisyDog really does when it barks is the same thing Dog does when it barks, but more times. We’d like to express that relationship in our implementation of NoisyDog’s bark. To do so, we have NoisyDog’s bark implementation send the bark message, not to self (which would be circular), but to the keyword super; this causes the search for a bark instance method implementation to start in the superclass rather than in our own class: class Dog : Quadruped { func bark () { println("woof") } } class NoisyDog : Dog { override func bark () { for _ in 1...3 { super.bark() } } } And it works: let fido = Dog() fido.bark() // woof let rover = NoisyDog() rover.bark() // woof woof woof A subscript function is a method. If a superclass declares a subscript, the subclass can declare a subscript with the same signature, provided it designates it with the override Classes | 151 keyword. To call the superclass subscript implementation, the subclass can use square brackets after the keyword super (e.g. super[3]). Along with methods, a subclass also inherits its superclass’s properties. Naturally, the subclass may also declare additional properties of its own. It is possible to override an inherited property (with some restrictions that I’ll talk about later). A class declaration can prevent the class from being subclassed by preceding the class declaration with the final keyword. A class declaration can prevent a class member from being overridden by a subclass by preceding the member’s declaration with the final keyword. Class Initializers Initialization of a class instance is considerably more complicated than initialization of a struct or enum instance, because of the existence of class inheritance. The chief task of an initializer is to ensure that all properties have an initial value, thus making the instance well-formed as it comes into existence; and an initializer may have other tasks to perform that are essential to the initial state and integrity of this instance. A class, however, may have a superclass, which may have properties and initializers of its own. Thus we must somehow ensure that when a subclass is initialized, its superclass’s prop‐ erties are initialized and the tasks of its initializers are performed in good order, in addition to initializing the properties and performing the initializer tasks of the subclass itself. Swift solves this problem coherently and reliably — and ingeniously — by enforcing some clear and well-defined rules about what a class initializer must do. These rules begin with a distinction between the kinds of initializer that a class can have: No initializer A class with no stored properties, or with stored properties all of which are initial‐ ized as part of their declaration, and that has no explicit initializers, has an implicit initializer init(). Designated initializer A class initializer, by default, is a designated initializer. A class with any stored properties that are not initialized as part of their declaration must have at least one designated initializer, and when the class is instantiated, exactly one of its designated initializers must be called, and must see to it that all stored properties are initialized. A designated initializer may not delegate to another initializer in the same class; it is illegal for a designated initializer to use the phrase self.init(...). Convenience initializer A convenience initializer is marked with the keyword convenience. It is a delegating initializer; it must contain the phrase self.init(...). Moreover, a convenience 152 | Chapter 4: Object Types initializer’s delegation must end with a designated initializer. In other words, a convenience initializer must call a designated initializer in the same class — or else it must call another convenience initializer in the same class, thus forming a chain of convenience initializers which ends by calling a designated initializer in the same class. Here are some examples. This class has no stored properties, so it has an implicit init() initializer: class Dog { } let d = Dog() This class’s stored properties have default values, so it has an implicit init() initializer too: class Dog { var name = "Fido" } let d = Dog() This class has stored properties without default values; all of those properties are ini‐ tialized in all of its initializers: class Dog { var name : String var license : Int init(name:String, license:Int) { self.name = name self.license = license } } let d = Dog(name:"Rover", license:42) This class is similar to the previous example, but it also has two convenience initializers. The caller doesn’t have to supply any parameters, because a convenience initializer with no parameters calls through a chain of convenience initializers ending with a designated initializer: class Dog { var name : String var license : Int init(name:String, license:Int) { self.name = name self.license = license } convenience init(license:Int) { self.init(name:"Fido", license:license) } convenience init() { Classes | 153 self.init(license:1) } } let d = Dog() Note that the rules about what else an initializer can say and when it can say it, as I described them earlier in this chapter, are still in force. A designated initializer cannot, except in order to initialize a property, say self until all of this class’s properties have been initialized. A convenience initializer is a delegating initializer, so it cannot say self until after it has called, directly or indirectly, a designated initializer (and cannot set an immutable property at all). Having defined and distinguished between designated initializers and convenience in‐ itializers, we are ready for the rules about what happens with regard to initializers when a class has a superclass: No initializers If a subclass doesn’t have to have any initializers of its own, and if it declares no initializers of its own, then its initializers consist of the initializers inherited from its superclass. Convenience initializers only If a subclass doesn’t have to have any initializers of its own, it is eligible to have convenience initializers, and these work exactly as convenience initializers always do, because inheritance provides the missing designated initializers in self that the convenience initializers must call. Designated initializers If a subclass has any designated initializers of its own, the entire game changes drastically. Now, no initializers are inherited! The existence of an explicit designated initializer blocks initializer inheritance. The only initializers the subclass now has are the initializers that you explicitly write. (However, there’s an exception, which I’ll come to in a moment.) Every designated initializer in the subclass now has an extra requirement: it must call one of the superclass’s designated initializers, by saying super.init(...). More‐ over, the rules about saying self continue to apply. A subclass designated initializer must do things in this order: 1. It must ensure that all properties of this class (the subclass) are initialized. 2. It must call super.init(...), and the initializer that it calls must be a desig‐ nated initializer. 3. Only then may this initializer say self for any other reason — to call an instance method, say, or to access an inherited property. 154 | Chapter 4: Object Types Convenience initializers in the subclass are still subject to the rules I’ve already outlined. They must call self.init(...), calling a designated initializer directly or (through a chain of convenience initializers) indirectly. In the absence of inher‐ ited initializers, the initializer that a convenience initializer calls must be explicitly present in the subclass. Override initializers Superclass initializers can be overridden in the subclass, in accordance with these restrictions: • An initializer whose signature matches a convenience initializer of the super‐ class must be a convenience initializer and is not marked override. • An initializer whose signature matches a designated initializer of the superclass can be a designated initializer or a convenience initializer, and must be marked override. Override initializers are subject to the rules I’ve already outlined; the fact that this is an override initializer changes nothing. A designated initializer marked override must still call super.init(...) on a superclass designated initializer (and the su‐ perclass designated initializer that it calls can even be the one that it overrides). As I said a moment ago, if a subclass has any designated initializers, no initializers are inherited. But here’s the exception: If a subclass overrides all of its superclass’s designated initializers, then the subclass does inherit the superclass’s convenience initializers. Failable initializers A failable class initializer cannot say return nil until after it has completed all of its own initialization duties. Thus, for example, a failable subclass designated ini‐ tializer must see to it that all the subclass’s properties are initialized and must call super.init(...) before it can say return nil. (There is a certain delicious irony here: before it can tear the instance down, the initializer must finish building the instance up.) If an initializer called by a failable initializer is failable, the calling syntax does not change, and no additional test is needed — if a called failable initializer fails, the whole initialization process will fail (and will be aborted) immediately. A failable initializer that returns an implicitly unwrapped Optional (init!) is treat‐ ed just like a normal initializer (init) for purposes of overriding and delegation. For a failable initializer that returns an ordinary Optional (init?), there are some additional restrictions: Classes | 155 • init can override init?, but not vice versa. • init? can call (delegate to) init, but not vice versa. At no time can a subclass initializer set a constant (let) property of a superclass. This is because, by the time the subclass is allowed to do anything other than initialize its own properties and call another initializer, the superclass has finished its own initialization and the door for initializing its constants has closed. Here are some basic examples. We start with a class whose subclass has no explicit initializers of its own: class Dog { var name : String var license : Int init(name:String, license:Int) { self.name = name self.license = license } convenience init(license:Int) { self.init(name:"Fido", license:license) } } class NoisyDog : Dog { } Given that code, you can make a NoisyDog like this: let nd1 = NoisyDog(name:"Fido", license:1) let nd2 = NoisyDog(license:2) That code is legal, because NoisyDog inherits its superclass’s initializers as its own. However, you can’t make a NoisyDog like this: let nd3 = NoisyDog() // compile error That code is illegal. Even though a NoisyDog has no properties of its own, it has no implicit init() initializer; its initializers are its inherited initializers, and its superclass, Dog, has no implicit init() initializer to inherit. Now here is a class whose subclass’s only explicit initializer is a convenience initializer: class Dog { var name : String var license : Int init(name:String, license:Int) { self.name = name self.license = license } convenience init(license:Int) { 156 | Chapter 4: Object Types self.init(name:"Fido", license:license) } } class NoisyDog : Dog { convenience init(name:String) { self.init(name:name, license:1) } } Observe how NoisyDog’s convenience initializer fulfills its contract by calling self.init(...) to call a designated initializer — which it happens to have inherited. Given that code, there are three ways to make a NoisyDog, just as you would expect: let nd1 = NoisyDog(name:"Fido", license:1) let nd2 = NoisyDog(license:2) let nd3 = NoisyDog(name:"Rover") Next, here is a class whose subclass declares a designated initializer: class Dog { var name : String var license : Int init(name:String, license:Int) { self.name = name self.license = license } convenience init(license:Int) { self.init(name:"Fido", license:license) } } class NoisyDog : Dog { init(name:String) { super.init(name:name, license:1) } } NoisyDog’s explicit initializer is now a designated initializer. It fulfills its contract by calling a designated initializer in super. NoisyDog has now cut off inheritance of all initializers; the only way to make a NoisyDog is like this: let nd1 = NoisyDog(name:"Rover") Finally, here is a class whose subclass overrides its designated initializers: class Dog { var name : String var license : Int init(name:String, license:Int) { self.name = name self.license = license } convenience init(license:Int) { self.init(name:"Fido", license:license) } Classes | 157 } class NoisyDog : Dog { override init(name:String, license:Int) { super.init(name:name, license:license) } } NoisyDog has overridden all of its superclass’s designated initializers, so it inherits its superclass’s convenience initializers. There are thus two ways to make a NoisyDog: let nd1 = NoisyDog(name:"Rover", license:1) let nd2 = NoisyDog(license:2) Those examples illustrate the main rules that you should keep in your head. You prob‐ ably don’t need to memorize the remaining rules, because the compiler will enforce them, and will keep slapping you down until you get them right. Surprises from Cocoa The initializer inheritance rules can cause some rude surprises to pop up when you’re subclassing one of Cocoa’s classes. For example, when programming iOS, you will surely declare a UIViewController subclass. Let’s say you give your subclass a designated ini‐ tializer. A designated initializer in the superclass, UIViewController, is init(nib- Name:bundle:), so, in obedience to the rules, you call that from your designated ini‐ tializer: class ViewController: UIViewController { override init() { super.init(nibName:"MyNib", bundle:nil) } } So far, so good; but you are then surprised to find that code elsewhere that makes a ViewController instance no longer compiles: let vc = ViewController(nibName:"MyNib", bundle:nil) // compile error That code was legal until you wrote your designated initializer; now it isn’t. The reason is that by implementing a designated initializer in your subclass, you have blocked in‐ itializer inheritance! Your ViewController class used to inherit the init(nib- Name:bundle:) initializer from UIViewController; now it doesn’t. You need to override that initializer as well, even if all your implementation does is to call the overridden initializer: class ViewController: UIViewController { override init() { super.init(nibName:"MyNib", bundle:nil) } 158 | Chapter 4: Object Types override init(nibName: String?, bundle: NSBundle?) { super.init(nibName:nibName, bundle:bundle) } } Here’s an even more insidious surprise. Let’s say you subclass UIBarButtonItem and give it a designated initializer that calls the UIBarButtonItem designated initializer init(customView:), like this: class LabelBarButtonItem: UIBarButtonItem { init(text: String) { let label = UILabel() label.text = text super.init(customView: label) } } And then elsewhere in your code, you make an instance of your UIBarButtonItem subclass: let lbbi = LabelBarButtonItem(text:"Howdy") Here’s the insidious part: that code compiles just fine. Nevertheless, you are headed for a train wreck; your program crashes when that line is executed. The reason is that, unbeknownst to you, Cocoa’s implementation of UIBarButtonItem’s designated initial‐ izer init(customView:) calls another designated initializer, namely init(). That would be illegal in Swift, but Cocoa is written in Objective-C. The result is that the init() message is sent to your LabelBarButtonItem class. But your LabelBarButtonItem class doesn’t implement init(), because you didn’t know that this was necessary — and the inherited init() is now no longer inherited, because the existence of a designated in‐ itializer has blocked initializer inheritance. This is not an easy problem to solve — a private implementation of init() that calls super.init() is probably the most satisfactory resolution — and the frustrating part is that it isn’t your fault and the compiler didn’t help you. (I regard this as a bug, but I’m undecided as to whether to call it a bug in Cocoa or a bug in Swift.) For reasons having nothing to do with class initializer inheritance, neither the ViewController code nor the LabelBarButtonItem code that I’ve just shown you will actually compile. That’s because there are some additional complications hav‐ ing to do with protocols; I’ll talk about them later in this chapter. Required initializers There’s one more thing to know about class initializers: a class initializer may be pre‐ ceded by the keyword required. This means that a subclass may not lack it. This, in Classes | 159 turn, means that if a subclass implements designated initializers, thus blocking inheri‐ tance, it must override this initializer. Here’s a (rather pointless) example: class Dog { var name : String required init(name:String) { self.name = name } } class NoisyDog : Dog { var obedient = false init(obedient:Bool) { self.obedient = obedient super.init(name:"Fido") } } // compile error That code won’t compile. The reason is that, having implemented a designated initializer init(obedient:) in NoisyDog, we have blocked inheritance of init(name:). But init(name:) is marked required. Thus, our code won’t compile unless we inherit or override init(name:) in NoisyDog. We cannot inherit it, because we have blocked inheritance. Therefore we must override it: class Dog { var name : String required init(name:String) { self.name = name } } class NoisyDog : Dog { var obedient = false init(obedient:Bool) { self.obedient = obedient super.init(name:"Fido") } required init(name:String) { super.init(name:name) } } Observe that our overridden required intializer is not marked with override, but is marked with required, thus guaranteeing that the requirement continues drilling down to any further subclasses. I have explained what declaring an initializer as required does, but I have not explained why you’d need to do it. I’ll give an example later in this chapter. 160 | Chapter 4: Object Types Class Deinitializer A class, and only a class (not the other flavors of object type), can have a deinitializer. This is a function declared with the keyword deinit followed by curly braces containing the function body. You never call this function yourself; it is called by the runtime when an instance of this class goes out of existence. If a class has a superclass, the subclass’s deinitializer (if any) is called before superclass’s deinitializer (if any). The idea of a deinitializer is that you might want to perform some cleanup, or just log to the console to prove to yourself that your instance is going out of existence in good order. I’ll take advantage of deinitializers when I discuss memory management issues in Chapter 5. Class Properties and Methods A subclass can override its inherited properties. The override must have the same name and type as the inherited property, and must be marked with override. (A property cannot have the same name as an inherited property but a different type, as there is no way to distinguish them.) The following additional rules apply: • The subclass property cannot be stored (because that would be the very same prop‐ erty, not a distinctive override). • If the superclass property is stored, the subclass’s computed variable override must have both a getter and a setter. • If the superclass property is computed, the subclass’s computed variable override must reimplement all the accessors that the superclass implements. Thus, if the superclass property has both a getter and a setter, the override must have both a getter and a setter; however, if the superclass property is read-only (it has just a getter), the override can have a setter. • Regardless of whether the superclass property is stored or computed, provided it is writable (a stored property or a computed property with a setter), the subclass’s override can consist of adding setter observers to this property. The overriding property’s functions may refer to — and may read from and write to — the inherited property, through the super keyword. A class can have static members, marked static, just like a struct or an enum. It can also have class members, marked class. Both static and class members are inherited by subclasses (as static and class members). The chief difference between static and class methods from the programmer’s point of view is that a static method cannot be overridden; it is as if static were a synonym for class final. Classes | 161 Here, for example, I’ll use a static method to express what dogs say: class Dog { static func whatDogsSay() -> String { return "woof" } func bark() { println(Dog.whatDogsSay()) } } A subclass now inherits whatDogsSay, but can’t override it. No subclass of Dog may contain any implementation of a class method or a static method whatDogsSay with this same signature. Now I’ll use a class method to express what dogs say: class Dog { class func whatDogsSay() -> String { return "woof" } func bark() { println(Dog.whatDogsSay()) } } A subclass inherits whatDogsSay, and can override it, either as a class function or as a static function: class NoisyDog : Dog { override class func whatDogsSay() -> String { return "WOOF" } } The difference between static properties and class properties is similar, but with an additional, rather dramatic qualification: static properties can be stored, but class prop‐ erties can only be computed. Here, I’ll use a static class property to express what dogs say: class Dog { static var whatDogsSay = "woof" func bark() { println(Dog.whatDogsSay) } } A subclass inherits whatDogsSay, but can’t override it; no subclass of Dog can declare a class or static property whatDogsSay. Now I’ll use a class property to express what dogs say. It cannot be a stored property, so I’ll have to use a computed property instead: 162 | Chapter 4: Object Types class Dog { class var whatDogsSay : String { return "woof" } func bark() { println(Dog.whatDogsSay) } } A subclass inherits whatDogsSay and can override it either as a class property or as a static property. But even as a static property the subclass’s override cannot be a stored property, in keeping with the rules of property overriding that I outlined earlier: class NoisyDog : Dog { override static var whatDogsSay : String { return "WOOF" } } Polymorphism When a computer language has a hierarchy of types and subtypes, it must resolve the question of what such a hierarchy means for the relationship between the type of an object and the declared type of a reference to that object. Swift obeys the principles of polymorphism. In my view, it is polymorphism that turns an object-based language into a full-fledged object-oriented language. We may summarize Swift’s polymorphism principles as follows: Substitution Wherever a certain type is expected, a subtype of that type may be used instead. Internal identity An object’s type is a matter of its internal nature, regardless of how the object is referred to. To see what these principles mean in practice, imagine we have a Dog class, along with its subclass, NoisyDog: class Dog { } class NoisyDog : Dog { } let d : Dog = NoisyDog() The substitution rule says that the last line is legal: we can assign a NoisyDog instance to a reference, d, that is typed as a Dog. The internal identity rule says that, under the hood, d now is a NoisyDog. Polymorphism | 163 The substitution rule works for Optionals as well — that is, it works for the type wrapped by an Optional. For example, if an Optional wrapping a Dog is expected (a Dog?), an Optional wrapping a NoisyDog (a NoisyDog?) can be used. The rea‐ son has to do with the mechanism by which an Optional has a specific wrapped type in the first place: an Optional is a generic, as I’ll explain later in this chapter, and a type used by a generic is subject to substitution just like any other type. You may be asking: How is the internal identity rule manifested? If a reference to a NoisyDog is typed as a Dog, in what sense is this “really” a NoisyDog? I have several very good answers to that question. Let’s start with what happens when a subclass over‐ rides an inherited method. Let me redefine Dog and NoisyDog to demonstrate: class Dog { func bark() { println("woof") } } class NoisyDog : Dog { override func bark() { super.bark(); super.bark() } } Now look at this code and tell me whether it compiles and, if so, what happens when it runs: func tellToBark(d:Dog) { d.bark() } var d : Dog d = NoisyDog() tellToBark(d) let d2 : NoisyDog = NoisyDog() tellToBark(d2) That code does compile. We create a NoisyDog instance and assign it to a variable typed as Dog. This is permitted because NoisyDog is a Dog subclass (substitution). Moreover, we pass both a variable typed as Dog and a variable typed as NoisyDog to a function that expects a Dog parameter. This is permitted, again, because NoisyDog is a Dog subclass (substitution). A NoisyDog can be used wherever a Dog is expected. Typolog‐ ically, a NoisyDog is a kind of Dog. But when the code actually runs, how does the object referred to by the local variable d inside the tellToBark function react to being told to bark each time? On the one hand, d is typed as Dog, and a Dog barks by saying "woof" once. On the other hand, in our code, both times tellToBark is called, what is really passed is a NoisyDog instance, and a NoisyDog barks by saying "woof" twice. What will happen? 164 | Chapter 4: Object Types func tellToBark(d:Dog) { d.bark() } var d : Dog d = NoisyDog() tellToBark(d) // woof woof let d2 : NoisyDog = NoisyDog() tellToBark(d2) // woof woof Both times, the result is "woof woof". The internal identity rule says that what matters when a message is sent is not how the recipient of that message is typed through this or that reference, but what that recipient actually is. What arrives inside tellToBark in both calls is a NoisyDog, regardless of the type of variable that holds it, or the type declared by the parameter that receives it; thus, the bark message causes this object to say "woof" twice. It is a NoisyDog! Here’s another important consequence of polymorphism — the meaning of the keyword self. It means the actual instance, and thus its meaning depends upon the actual type of the actual instance — even if the word self appears in a superclass’s code. For example: class Dog { func bark() { println("woof") } func speak() { self.bark() } } class NoisyDog : Dog { override func bark() { super.bark(); super.bark() } } What happens when we tell a NoisyDog to speak? Let’s try it: let d : NoisyDog = NoisyDog() d.speak() // woof woof let d2 : Dog = NoisyDog() d2.speak() // woof woof First, observe that we are allowed to tell a NoisyDog to speak. The speak method is declared only in Dog, but of course this means that it is inherited by NoisyDog. Even if a reference to a NoisyDog is typed as a NoisyDog, we are allowed to send the speak message to that reference. Next, what happens when we do tell a NoisyDog to speak? This is the really interesting part. The speak method is declared in Dog, the superclass — not in NoisyDog. The speak method calls the bark method. It does this by way of the keyword self. (I could have omitted the explicit reference to self here, but self would still be involved im‐ Polymorphism | 165 plicitly, so I’m not cheating by making self explicit.) There’s a bark method in Dog, and an override of the bark method in NoisyDog. Which bark method will be called? The word self is encountered within the Dog class’s implementation of speak. But what matters is not where the word self appears but what it means. It means this instance. And the internal identity principle tells us that, in both speak calls, this instance is a NoisyDog! Thus, it is NoisyDog’s override of bark that is called, both times. Thanks to polymorphism, you can take advantage of subclasses to add power and cus‐ tomization to existing classes. This is important particularly in the world of iOS pro‐ gramming, where most of the classes are defined by Cocoa and don’t belong to you. The UIViewController class, for example, is defined by Cocoa; it has lots of built-in methods that Cocoa will call, and these methods perform various important tasks — but in a generic way. In real life, you’ll make a UIViewController subclass and override those methods to do the tasks appropriate to your particular app. This won’t bother Cocoa in the slightest, because (substitution principle) wherever Cocoa expects to receive or to be talking to a UIViewController, it will accept without question an instance of your UIViewController subclass. And this substitution will also work as expected, because whenever Cocoa calls one of those UIViewController methods on your subclass, it is your subclass’s override that will be called (internal identity principle). Casting The Swift compiler, with its strict typing, imposes severe restrictions on what messages can be sent to an object reference. The messages that the compiler will permit to be sent to an object reference are those permitted by the reference’s declared type, including its inheritance. This means that, thanks to the internal identity principle of polymorphism, an object may be capable of receiving messages that the compiler won’t permit us to send. This puts us in a serious bind. For example, let’s give NoisyDog a method that Dog doesn’t have: class Dog { func bark() { println("woof") } } class NoisyDog : Dog { override func bark() { super.bark(); super.bark() } func beQuiet() { self.bark() } } 166 | Chapter 4: Object Types In that code, we configure a NoisyDog so that we can tell it to beQuiet. Now look at what happens when we try to tell an object typed as a Dog to be quiet: func tellToHush(d:Dog) { d.beQuiet() // compile error } let d: NoisyDog = NoisyDog() tellToHush(d) Our code doesn’t compile. We can’t send the beQuiet message to this object, even though it is in fact a NoisyDog and has a beQuiet method. That’s because the reference, d inside the function body, is typed as a Dog — and a Dog has no beQuiet method. There is a certain irony here: for once, we know more than the compiler does! We know that our code would run correctly — because d really is a NoisyDog — if only we could get our code to compile in the first place. We need a way to say to the compiler, “Look, compiler, just trust me: this thing is going to turn out to be a NoisyDog when the program actually runs, so let me send it this message.” There is in fact a way to do this — casting. To cast, you use a form of the keyword as followed by the name of the type you claim something really is. Swift will not let you cast just any old type to any old other type — for example, you can’t cast a String to an Int — but it will let you cast a superclass to a subclass. This is called casting down. When you cast down, the form of the keyword as that you must use is as! with an exclamation mark. The exclamation mark reminds you that you are forcing the compiler to do some‐ thing it would rather not do: func tellToHush(d:Dog) { (d as! NoisyDog).beQuiet() } let d: NoisyDog = NoisyDog() tellToHush(d) That code compiles, and works. A useful way to rewrite the example is like this: func tellToHush(d:Dog) { let d2 = d as! NoisyDog d2.beQuiet() d2.beQuiet() } let d: NoisyDog = NoisyDog() tellToHush(d) The reason that way of rewriting the code is useful is in case we have other NoisyDog messages to send to this object. Instead of casting every time we want to send a message to it, we cast the object once to its internal identity type, and assign it to a variable. Now that variable’s type — inferred, in this case, from the cast — is that internal identity type, and we can send multiple messages to the variable. Casting | 167 A moment ago, I said that the as! operator’s exclamation mark reminds you that you are forcing the compiler’s hand. It also serves as a warning: your code can now crash! The reason is that you might be lying to the compiler. Casting down is a way of telling the compiler to relax its strict type checking and to let you call the shots. If you use casting to make a false claim, the compiler may permit it, but you will crash when the app runs: func tellToHush(d:Dog) { (d as! NoisyDog).beQuiet() // compiles, but prepare to crash...! } let d: Dog = Dog() tellToHush(d) In that code, we told the compiler that this object would turn out to be a NoisyDog, and the compiler obediently took its hands off and allowed us to send the beQuiet message to it. But in fact, this object was a Dog when our code ran, and so we ultimately crashed when the cast failed because this object was not a NoisyDog. To prevent yourself from lying accidentally, you can test the type of an instance at run‐ time. One way to do this is with the keyword is. You can use is in a condition; if the condition passes, then cast, in the knowledge that your cast is safe: func tellToHush(d:Dog) { if d is NoisyDog { let d2 = d as! NoisyDog d2.beQuiet() } } The result is that we won’t cast d to a NoisyDog unless it really is a NoisyDog. An alternative way to solve the same problem is to use Swift’s as? operator. This casts down, but with the option of failure; therefore what it casts to is (you guessed it) an Optional — and now we are on familiar ground, because we know how to deal safely with an Optional: func tellToHush(d:Dog) { let noisyMaybe = d as? NoisyDog // an Optional wrapping a NoisyDog if noisyMaybe != nil { noisyMaybe!.beQuiet() } } That doesn’t look much cleaner or shorter than our previous approach. But remember that we can safely send a message to an Optional by optionally unwrapping the Optional! Thus we can skip the assignment and condense to a single line: func tellToHush(d:Dog) { (d as? NoisyDog)?.beQuiet() } 168 | Chapter 4: Object Types First we use the as? operator to obtain an Optional wrapping a NoisyDog (or nil). Then we optionally unwrap that Optional and send a message to it. If d isn’t a NoisyDog, the Optional will be nil and the message won’t be sent. If d is a NoisyDog, the Optional will be unwrapped and the message will be sent. Thus, that code is safe. Recall (from Chapter 3) that comparison operators applied to an Optional are auto‐ matically applied to the object wrapped by the Optional. The as!, as?, and is operators work the same way. Consider an Optional d wrapping a Dog (that is, d is a Dog? object). This might, in actual fact, be wrapping either a Dog or a NoisyDog. To find out which it is, you might be tempted to use is. But can you? After all, an Optional is neither a Dog nor a NoisyDog — it’s an Optional! Well, the good news is that Swift knows what you mean; when the thing on the left side of is is an Optional, Swift pretends that it’s the value wrapped in the Optional. Thus, this works just you would hope: let d : Dog? = NoisyDog() if d is NoisyDog { // it is! When using is with an Optional, the test fails in good order if the Optional is nil. Thus our is test really does two things: it checks whether the Optional is nil, and if it is not, it then checks whether the wrapped value is the type we specify. What about casting? You can’t really cast an Optional to anything. But you can use the as! operator with an Optional, because Swift knows what you mean; when the thing on the left side of as! is an Optional, Swift treats it as the wrapped type. Moreover, the consequence of applying the as! operator is that two things happen: Swift unwraps first, and then casts. This code works, because d is unwrapped to give us d2, which is a Noisy‐ Dog: let d : Dog? = NoisyDog() let d2 = d as! NoisyDog d2.beQuiet() That code, however, is not automatically safe. You shouldn’t cast like that, without testing first, unless you are very sure of your ground. If d were nil, you’d crash in the second line because you’re trying to unwrap a nil Optional. And if d were a Dog, not a Noisy‐ Dog, you’d still crash in the second line when the cast fails. That’s why there’s also an as? operator, which is safe — but yields an Optional: let d : Dog? = NoisyDog() let d2 = d as? NoisyDog d2?.beQuiet() Another way you’ll using casting is during a value interchange between Swift and Objective-C when two types are equivalent. For example, you can cast a Swift String to a Cocoa NSString, and vice versa. That’s not because one is a subclass of the other, but because they are bridged to one another; in a very real sense, they are the same type. When you cast from String to NSString, you’re not casting down, and what you’re doing Casting | 169 is not dangerous, so you use the as operator, with no exclamation mark. I gave an example, in Chapter 3, of a situation where you might need to do that: let s = "hello" let range = (s as NSString).rangeOfString("ell") // (1,3), an NSRange The cast from String to NSString tells Swift to stay in the Cocoa world as it calls range- OfString, and thus causes the result to be the Cocoa result, an NSRange, rather than a Swift Range. A number of common classes are bridged in this way between Swift and Objective-C. Often, you won’t need to cast as you cross the bridge from Swift to Objective-C, because Swift will automatically cast for you. For example, a Swift Int and a Cocoa NSNumber are two very different things; nevertheless, you can often use an Int where an NSNumber is expected, without casting, like this: let ud = NSUserDefaults.standardUserDefaults() ud.setObject(1, forKey: "Test") In that code, we used an Int (1) where Objective-C expects an NSObject instance. An Int is not an NSObject instance; it isn’t even a class instance (it’s a struct instance). But Swift sees that an NSObject is expected, decides that an NSNumber would best represent an Int, and crosses the bridge for you. Thus, what winds up being stored in NSUser‐ Defaults is an NSNumber. Coming back the other way, however, when you call objectForKey:, Swift has no in‐ formation about what this value really is, so you have to cast explicitly if you want an Int — and now you are casting down (as I’ll explain in more detail later): let i = ud.objectForKey("Test") as! Int That cast works because ud.objectForKey("Test") yields an NSNumber wrapping an integer, and casting that to a Swift Int is permitted — the types are bridged. But if ud.objectForKey("Test") were not an NSNumber, you’d crash. If you’re not sure of your ground, use is or as? to be safe. Type Reference It can be useful for an instance to be able to refer to its own type — for example, to send a message to that type. In an earlier example, a Dog instance method fetched a Dog class property by sending a message to the Dog type explicitly — by using the word Dog: class Dog { class var whatDogsSay : String { return "Woof" } 170 | Chapter 4: Object Types func bark() { println(Dog.whatDogsSay) } } This seems clumsy and inflexible. Why should we have to hard-code into Dog a knowl‐ edge of what class it is? It has a class; it should just know what it is. In Objective-C, you may be accustomed to using the class instance method to deal with this situation. In Swift, an instance might not have a class (it might be a struct instance or an enum instance); what a Swift instance has is a type. The instance method that Swift provides for this purpose is the dynamicType method. An instance can access its type through this method. Thus, if you don’t like the notion of a Dog instance calling a Dog class method by saying Dog explicitly, there’s another way: class Dog { class var whatDogsSay : String { return "Woof" } func bark() { println(self.dynamicType.whatDogsSay) } } An important thing about using dynamicType instead of hard-coding a class name is that it obeys polymorphism: class Dog { class var whatDogsSay : String { return "Woof" } func bark() { println(self.dynamicType.whatDogsSay) } } class NoisyDog : Dog { override class var whatDogsSay : String { return "Woof woof woof" } } That code works correctly: let nd = NoisyDog() nd.bark() // Woof woof woof If we tell a NoisyDog instance to bark, it says "Woof woof woof". The reason is that dynamicType means, “The type that this instance actually is, right now.” That’s what makes this type dynamic. We send the bark message to a NoisyDog instance. The bark implementation refers to self.dynamicType; self means this instance, which is a NoisyDog, and so self.dynamicType is the NoisyDog class, and it is NoisyDog’s version Type Reference | 171 of whatDogsSay that is fetched. (Compare what I said about polymorphism and self earlier.) You can also use dynamicType for learning the name of an object’s type, as a string — typically for debugging purposes. When you say println(myObject.dynamicType), you’ll see something legible in the console; it will be namespaced, so it will have the module name (and possibly some other information) attached to it, but the name of this object’s type will be plain to see. In some situations, you may want to pass an object type as a value. This is legal; an object type is itself an object. Here’s what you need to know: • To specify an object type as acceptable — for example, to declare the type of a variable or parameter — use dot-notation with the name of the type and the keyword Type. • To use an object type as a value — for example, to assign something to a variable or pass it as a parameter — use a reference to the type (the type’s name, or some instance’s dynamicType), possibly followed by the keyword self using dot-notation. For example, here’s a function that accepts a Dog type as its parameter: func typeExpecter(whattype:Dog.Type) { } And here’s an example of calling that function: typeExpecter(Dog) // or: typeExpecter(Dog.self) Or you could call it like this: let d = Dog() // or: let d = NoisyDog() typeExpecter(d.dynamicType) // or: typeExpecter(d.dynamicType.self) Why might you want to do something like that? A typical situation is that your function is a factory for instances: given a type, it creates an instance of that type, possibly prepares it in some way, and returns it. For example, here’s a Dog class with an init(name:) initializer, and its NoisyDog subclass: class Dog { var name : String init(name:String) { self.name = name } } class NoisyDog : Dog { } And here’s a factory method that creates a Dog or a NoisyDog, as specified, gives it a name, and returns it: 172 | Chapter 4: Object Types func dogMakerAndNamer(whattype:Dog.Type) -> Dog { let d = whattype(name:"Fido") // compile error return d } As you can see, since whattype is a type, we can call its initializer to make an instance of that type. However, there’s a problem. The code doesn’t compile. The reason is that the compiler is in doubt as to whether the init(name:) initializer is implemented by every possible subtype of Dog. To reassure it, we must declare that initializer with the required keyword: class Dog { var name : String required init(name:String) { self.name = name } } class NoisyDog : Dog { } That reassures the compiler. Now our code compiles, and we can call our function: let d = dogMakerAndNamer(Dog) // d is a Dog named Fido let d2 = dogMakerAndNamer(NoisyDog) // d2 is a NoisyDog named Fido In a class method, self stands for the class — polymorphically. This means that, in a class method, you can put parentheses after self to call an initializer polymorphically. Here’s an example. Let’s say we want to move our instance factory method into Dog itself, as a class method. Let’s call this class method makeAndName. We want this class method to create and return a named Dog of whatever class we send the makeAndName message to. If we say Dog.makeAndName(), we should get a Dog. If we say NoisyDog.make- AndName(), we should get a NoisyDog. That type is the polymorphic self class, so our makeAndName class method initializes self: class Dog { var name : String required init(name:String) { self.name = name } class func makeAndName() -> Dog { let d = self(name:"Fido") return d } } class NoisyDog : Dog { } It works as expected: let d = Dog.makeAndName() // d is a Dog named Fido let d2 = NoisyDog.makeAndName() // d2 is a NoisyDog named Fido Type Reference | 173 But there’s a problem with that code. Although d2 is in fact a NoisyDog, it is typed as a Dog. This is because our makeAndName class method is declared as returning a Dog. That isn’t what we meant to say. What we want to say is that this method returns an instance of the same type as the class to which the makeAndName message was originally sent. In other words, we need a polymorphic type declaration! In the declaration of a method, Self (notice the capitalization) is the polymorphic return type. Thus: class Dog { var name : String required init(name:String) { self.name = name } class func makeAndName() -> Self { let d = self(name:"Fido") return d } } class NoisyDog : Dog { } Now when we call NoisyDog.makeAndName() we get a NoisyDog typed as a NoisyDog. Self also works for instance method declarations. Therefore, we can write an instance method version of our factory method. Here, we start with a Dog or a NoisyDog and tell it to have a puppy of the same type as itself: class Dog { var name : String required init(name:String) { self.name = name } func havePuppy(#name:String) -> Self { return self.dynamicType(name:name) } } class NoisyDog : Dog { } And here’s some code to test it: let d = Dog(name:"Fido") let d2 = d.havePuppy(name:"Fido Junior") let nd = NoisyDog(name:"Rover") let nd2 = nd.havePuppy(name:"Rover Junior") As expected, d2 is a Dog, but nd2 is a NoisyDog (and is typed as a NoisyDog). All this terminology can get a bit confusing, so here’s a quick summary: 174 | Chapter 4: Object Types .dynamicType In code, sent to an instance: the polymorphic (internal) type of this instance, re‐ gardless of how the instance reference is typed. Static/class members are accessible through an instance’s dynamicType. .Type In declarations, sent to a type: the type (as opposed to an instance of the type). For example, in a function declaration, Dog means a Dog instance is expected, but Dog.Type means that the Dog type itself is expected. .self In code, sent to a type: the type. For example, to pass the Dog type where Dog.Type is expected, you can pass Dog.self. (It is not illegal to send .self to an instance, but it is pointless.) self In instance code, this instance, polymorphically. In static/class code, this type, polymorphically; self(...) instantiates this type. Self In a method declaration, when specifying the return type, this class or this instance’s class, polymorphically. Protocols A protocol is a way of expressing commonalities between otherwise unrelated types. 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. Thus, it might be useful to define a Flier type. The question is: In what sense can both Bee and Bird be Fliers? One possibility, of course, is class inheritance. If Bee and Bird are both classes, there’s a class hierarchy of superclasses and subclasses. So Flier could be the superclass of both Bee and Bird. The problem is that there may be other reasons why Flier can’t be the superclass of both Bee and Bird. A Bee is an Insect; a Bird isn’t. Yet they both have the power of flight — independently. We need a type that cuts across the class hierarchy somehow, tying remote classes together. Moreover, what if Bee and Bird are not both classes? In Swift, that’s a very real possibility. Important and powerful objects can be structs instead of classes. But there is no struct hierarchy of superstructs and substructs! That, after all, is one of the major differences between structs and classes. Yet structs need the ability to possess and express formal commonalities every bit as much as classes do. How can a Bee struct and a Bird struct both be Fliers? Protocols | 175 Swift solves this problem through the use of protocols. Protocols are tremendously important in Swift; the Swift header defines over 70 of them! Moreover, Objective-C has protocols as well; Swift protocols correspond roughly to these, and can interchange with them. Cocoa makes heavy use of protocols. A protocol is an object type, but it doesn’t make any objects of its own. You can’t in‐ stantiate a protocol. A protocol is much more lightweight than that. A protocol decla‐ ration is just a list of properties and methods. The properties have no values, and the methods have no code! The idea is that a “real” object type can formally declare that it belongs to a protocol type; this is called adopting or conforming to the protocol. An object type that adopts a protocol is signing a contract stating that it actually implements the properties and methods listed by the protocol. For example, let’s say that being a Flier consists of no more than implementing a fly method. Then a Flier protocol could specify that there must be a fly method; to do so, it lists the fly method with no function body, like this: protocol Flier { func fly() } Any type — an enum, a struct, a class, or even another protocol — can then adopt this protocol. To do so, it lists the protocol after a colon after its name in its declaration. (If the adopter is a class with a superclass, the protocol comes after the superclass specifi‐ cation; in other words, if there is a superclass specification, it must come first after the colon in the declaration.) Let’s say Bird is a struct. Then it can adopt Flier like this: struct Bird : Flier { } // compile error So far, so good. But that code won’t compile. The Bird struct has made a promise to implement the features listed in the Flier protocol. Now it must keep that promise! To satisfy that requirement, I’ll just give Bird an empty fly method: protocol Flier { func fly() } struct Bird : Flier { func fly() { } } That’s all there is to it! We’ve defined a protocol, and we’ve made a struct adopt that protocol. Of course, in real life you’ll probably want to make the adopter’s implemen‐ tation of the protocol’s methods do something; but the protocol says nothing about that. 176 | Chapter 4: Object Types Why Protocols? Perhaps at this point you’re scratching your head over why this is a useful thing to do. We made a Bird a Flier, but so what? If we wanted a Bird to know how to fly, why didn’t we just give Bird a fly method without adopting any protocol? The answer has to do with types. Don’t forget, a protocol is a type. Our protocol, Flier, is a type. Therefore, I can use Flier wherever I would use a type — to declare the type of a variable, for example, or the type of a function parameter: func tellToFly(f:Flier) { f.fly() } Think about that code for a moment, because it embodies the entire point of protocols. A protocol is a type — so polymorphism applies. Protocols give us another way of ex‐ pressing the notion of type and subtype. This means that, by the substitution principle, a Flier here could be an instance of any object type — an enum, a struct, or a class. It doesn’t matter what object type it is, as long as it adopts the Flier protocol. If it adopts the Flier protocol, then it must have a fly method, because that’s exactly what it means to adopt the Flier protocol! Therefore the compiler is willing to let us send the fly message to this object. A Flier is, by definition, an object that can be told to fly. The converse, however, is not true: an object with a fly method is not automatically a Flier. It isn’t enough to obey the requirements of a protocol; the object type must adopt the protocol. This code won’t compile: struct Bee { func fly() { } } let b = Bee() tellToFly(b) // compile error A Bee can be sent the fly message, qua Bee. But tellToFly doesn’t take a Bee parameter; it takes a Flier parameter. Formally, a Bee is not a Flier. To make a Bee a Flier, simply declare formally that Bee adopts the Flier protocol. This code does compile: struct Bee : Flier { func fly() { } } let b = Bee() tellToFly(b) Enough of birds and bees; we’re ready for a real-life example! As I’ve already said, Swift is chock full of protocols already. Let’s make one of our own object types adopt one. One of the most useful Swift protocols is Printable. The Printable protocol requires that we implement a description String property. If we do that, a wonderful thing happens: Protocols | 177 when an instance of this type is used in string interpolation or println, the description property value is used automatically to represent it. Recall this example, the ListType enum, from earlier in this chapter: enum ListType : String { case Albums = "Albums" case Playlists = "Playlists" case Podcasts = "Podcasts" case Books = "Audiobooks" var description : String { return self.rawValue } } Wait — what are the chances? By an amazing coincidence, this enum already has a description property! Previously, though, in order to learn, in the console, what case we’ve actually got, we had to fetch the description property ourselves (otherwise, the enum prints in the console as an opaque Enum Value): let type = ListType.Albums println(type.description) // Albums But now we’re going to make one tiny change in our declaration of the ListType enum: we’re going to adopt the Printable protocol formally. There is already a colon and a type in the ListType declaration; the rule is that in that case any adopted protocols must come last, using a comma separator, like this: enum ListType : String, Printable { case Albums = "Albums" case Playlists = "Playlists" case Podcasts = "Podcasts" case Books = "Audiobooks" var description : String { return self.rawValue } } We have now made ListType formally adopt the Printable protocol. The Printable pro‐ tocol requires that we implement a description String property; we do implement a description String property, so our code compiles. Now we can hand a ListType to println and its description will be printed automatically: let type = ListType.Albums println(type) // Albums Behold the power of protocols. You can give any object type the power of printability in exactly the same way. Note that a type can adopt more than one protocol! For example, the built-in Double type adopts Printable, Hashable, Comparable, and other built-in protocols. One way to declare adoption of multiple protocols is to put the names of the adopted protocols as a list separated by comma after the colon. For example: 178 | Chapter 4: Object Types struct MyType : Printable, Hashable, Comparable { // ... } (Of course, that code won’t compile unless I also declare the required methods in My‐ Type, so that MyType really does adopt those protocols.) Protocol Type Testing and Casting A protocol is a type, and an adopter of a protocol is its subtype. Therefore, the operators for working with an object’s real type work with an object declared as a protocol type. For example, given a protocol Flier that is adopted by both Bird and Bee, we can use the is operator to test whether a particular Flier is in fact a Bird: func isBird(f:Flier) -> Bool { return f is Bird } Similarly, as! and as? can be used to cast an object declared as a protocol type down to its actual type. This is important to be able to do, because the adopting object will typ‐ ically be able to receive messages that the protocol can’t receive. For example, let’s say that a Bird can get a worm: struct Bird : Flier { func fly() { } func getWorm() { } } A Bird can fly qua Flier, but it can getWorm only qua Bird. Thus, you can’t tell just any old Flier to get a worm: func tellGetWorm(f:Flier) { f.getWorm() // compile error } But if this Flier is a Bird, clearly it can get a worm. This is exactly what casting is all about: func tellGetWorm(f:Flier) { (f as? Bird)?.getWorm() } That’s precisely parallel to what we did earlier with Dog and NoisyDog. In real life, testing or casting an object typed as a protocol arises most commonly with regard to AnyObject, a catch-all protocol used for interchange with Objective-C. I’ll give examples later in this chapter. Protocols | 179 Declaring a Protocol Protocol declaration can take place only at the top level of a file. To declare a protocol, use the keyword protocol followed by the name of the protocol, which, being an object type, should start with a capital letter. Then come curly braces which may contain the following: Properties A property declaration in a protocol consists of var (not let), the property name, a colon, its type, and curly braces containing the word get or the words get set. The syntax is rather like declaring a computed property with a getter or both a getter and a setter, but without any implementation of that getter and setter. However, that’s just a matter of syntax; the adopter has many more options: • The adopter can implement this property as a stored property. • If the protocol specifies get only, the adopter can declare this property as a stored property with let. • Even if the protocol specifies get only, the adopter can make this property a read-write property. What the adopter can’t do is to implement this property as a read-only computed property or a constant (let) stored property if the protocol specifies get set; in other words, if the protocol says that this property must be writable, it must be writable. To declare a static/class property, precede it with the keyword static. A class adopter is free to implement this as a class property. Methods A method declaration in a protocol is a function declaration without a function body — that is, it has no curly braces and thus it has no code. Any object function type is legal, including init and subscript. (The syntax for declaring a subscript in a protocol is the same as the syntax for declaring a subscript in an object type, except that there will be no function bodies, so the curly braces, like those of a property declaration in a protocol, will contain get or get set.) To declare a static/class method, precede it with the keyword static. A class adopter is free to implement this as a class method. If a method, as implemented by an enum or struct, might need to be declared mutating, the protocol must specify the mutating designation; the adopter cannot add mutating if the protocol lacks it. However, the adopter can omit mutating if the protocol has it. 180 | Chapter 4: Object Types Type alias A protocol can introduce a local synonym for a type that it mentions in its decla‐ rations by declaring a type alias. For example, typealias Time = Double allows the Time type to be referred to inside the protocol’s curly braces; elsewhere (such as in an adopting object type), the Time type doesn’t exist, but the Double type is a match for it. There are other ways to use a type alias in a protocol, which I’ll discuss later. Protocol adoption A protocol can itself adopt one or more protocols; the syntax is just as you would expect — a colon after the protocol’s name in the declaration, followed by a comma- separated list of the protocols it adopts. In effect, this gives you a way to create an entire secondary hierarchy of types! The Swift headers make heavy use of this. A protocol that adopts another protocol may repeat the contents of the adopted protocol’s curly braces, for clarity; but it doesn’t have to, as this repetition is implicit. An object type that adopts such a protocol must satisfy the requirements of this protocol and all protocols that the protocol adopts. If the only purpose of a protocol would be to combine other protocols by adopt‐ ing all of them, without adding any new requirements, and if this combination is used in just one place in your code, you can avoid formally declaring the protocol in the first place by creating the combining protocol on the fly. To do so, use a type name protocol<..., ...>, where the contents of the angle brackets is a comma- separated list of protocols. For example, in a function declaration, a parameter type could be specified as protocol, meaning that this value must be an object type that adopts Printable and DebugPrintable. Optional Protocol Members In Objective-C, a protocol member can be declared optional, meaning that this member doesn’t have to be implemented by the adopter, but it may be. For compatibility with Objective-C, Swift allows optional protocol members, but only in a protocol explicitly bridged to Objective-C by preceding its declaration with the @objc attribute. In such a protocol, an optional member — meaning a method or property — is declared by pre‐ ceding its declaration with the keyword optional: @objc protocol Flier { optional var song : String {get} optional func sing() } Protocols | 181 Only a class can adopt such a protocol, and this feature will work only if the class is an NSObject subclass, or the class is marked with the @objc attribute, or the optional member is marked with the @objc attribute: @objc class Bird : Flier { func sing() { println("tweet") } } An optional member is not guaranteed to be implemented by the adopter, so Swift doesn’t know whether it’s safe to send a Flier either the song message or the sing message. In the case of an optional property like song, Swift solves the problem by wrapping its value in an Optional. If the Flier doesn’t implement the property, the result is nil and no harm done: let f : Flier = Bird() let s = f.song // s is an Optional wrapping a String This is one of those rare situations where you can wind up with a double- wrapped Optional. For example, if the value of the optional property song were a String?, then fetching its value from a Flier would yield a String??. In the case of an optional method like sing, things are more elaborate. If the method is not implemented, we must not be permitted to call it in the first place. To handle this situation, the method itself is automatically typed as an Optional version of its declared type. To send the sing message to a Flier, therefore, you must unwrap it. The safe ap‐ proach is to unwrap it optionally, with a question mark: let f : Flier = Bird() f.sing?() That code compiles — and it also runs safely. The effect is to send the sing message to f only if this adopter implements sing. If the actual type of this adopter doesn’t implement sing, nothing happens. You could have force-unwrapped the call — f.sing!() — but then your app would crash if the adopter doesn’t implement sing. If an optional method returns a value, that value is wrapped in an Optional as well. For example: @objc protocol Flier { optional var song : String {get} optional func sing() -> String } If we now call sing?() on a Flier, the result is an Optional wrapping a String: 182 | Chapter 4: Object Types let f : Flier = Bird() let s = f.sing?() // s is an Optional wrapping a String If we force-unwrap the call — sing!() — the result is either a String (if the adopter implements sing) or a crash (if it doesn’t). Many Cocoa protocols have optional members. For example, your iOS app will have an app delegate class that adopts the UIApplicationDelegate protocol; this protocol has many methods, all of them optional. An optional property can be declared {get set} by its protocol, but there is no legal syntax for setting such a property in an object of that protocol type. For example, if f is a Flier and song is declared {get set}, you can’t set f.song. I regard this as a bug in the language. Class Protocol A protocol declared with the keyword class after the colon after its name is a class protocol, meaning that it can be adopted only by class object types: protocol SecondViewControllerDelegate : class { func acceptData(data:AnyObject!) } Like the @objc attribute, this feature is provided for compatibility with Objective-C. (In fact, the @objc attribute implies that this is also a class protocol.) A typical reason for declaring a class protocol is to take advantage of special memory management features that apply only to classes. I haven’t discussed memory manage‐ ment yet, but I’ll continue the example anyway (and I’ll repeat it when I do talk about memory management, in Chapter 5): class SecondViewController : UIViewController { weak var delegate : SecondViewControllerDelegate? // ... } The keyword weak marks the delegate property as having special memory manage‐ ment. Only a class instance can participate in this kind of special memory management. The delegate property is typed as a protocol, and a protocol might be adopt by a struct or an enum type. So to satisfy the compiler that this object will in fact be a class instance, and not a struct or enum instance, the protocol is declared as a class protocol. Implicitly Required Initializers Suppose that a protocol declares an initializer. And suppose that a class adopts this protocol. By the terms of this protocol, this class and any subclass it may ever have must Protocols | 183 implement this initializer. Therefore, the class must not only implement the initializer, but it must also mark it as required. An initializer declared in a protocol is thus implicitly required, and the class is forced to make that requirement explicit. Consider this simple example, which won’t compile: protocol Flier { init() } class Bird : Flier { init() {} // compile error } That code generates an elaborate but perfectly informative compile error message: “In‐ itializer requirement init() can only be satisfied by a required initializer in non-final class Bird.” To compile our code, we must designate our initializer as required: protocol Flier { init() } class Bird : Flier { required init() {} } The alternative, as the compile error message informs us, would be to mark the class Bird as final. This would mean that it cannot have any subclasses — thus guaranteeing that the problem will never arise in the first place. If Bird were marked final, there would be no need to mark its init as required. In the above code, Bird is not marked as final, and its init is marked as required. This, as I’ve already explained, means in turn that any subclass of Bird that implements any designated initializers — and thus loses initializer inheritance — must implement the required initializer and mark it required as well. That fact is responsible for one of the strangest and most annoying features of real-life iOS programming with Swift. Let’s say you subclass the built-in Cocoa class UIView‐ Controller — something that you are extremely likely to do. And let’s say you give your subclass an initializer — something that you are also extremely likely to do: class ViewController: UIViewController { override init() { super.init(nibName: "ViewController", bundle: nil) } } That code won’t compile. The compile error says: “required initializer init(coder:) must be provided by subclass of UIViewController.” What on earth is going on? Well, it turns out that UIViewController adopts a protocol, NSCoding. And this protocol requires an initializer init(coder:). None of that is your doing; UIViewController and NSCoding are declared by Cocoa, not by you. But that doesn’t matter! This is the same 184 | Chapter 4: Object Types situation I was just describing. In order to adopt NSCoding, UIViewController must not only implement init(coder:), but also it must mark it required. Therefore, be‐ cause your subclass has implemented a designated initializer of its own — thus cutting off initializer inheritance — it must also implement init(coder:) and mark it required! But that makes no sense, especially if you are not expecting init(coder:) ever to be called on your UIViewController subclass. You are being asked to write an initializer for which you can provide no meaningful functionality. Fortunately, Xcode’s Fix-It fea‐ ture will offer to write the initializer for you, like this: required init(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } That code satisfies the compiler. (I’ll explain in Chapter 5 why it’s a legal initializer even though it doesn’t fulfill an initializer’s contract.) It also deliberately crashes if it is ever called. If you do have functionality for this initializer, you will delete the fatalError line and insert your own functionality in its place. Not only UIViewController but lots of built-in Cocoa classes adopt NSCoding. You will encounter this problem if you subclass any of those classes and implement your own initializer. It’s just something you’ll have to get used to. Literal Convertibles One of the wonderful things about Swift is that so many of its features, rather than being built-in and accomplished by magic, are implemented in Swift and are exposed to view in the Swift header. Literals are a case in point. The reason you can say 5 to make an Int whose value is 5, instead of formally initializing Int by saying Int(5), is not because of magic (or at least, not entirely because of magic). It’s because Int adopts a protocol, IntegerLiteralConvertible. Not only Int literals, but all literals work this way. The fol‐ lowing literal convertible protocols are declared in the Swift header: • NilLiteralConvertible • BooleanLiteralConvertible • IntegerLiteralConvertible • FloatLiteralConvertible • StringLiteralConvertible • ExtendedGraphemeClusterLiteralConvertible • UnicodeScalarLiteralConvertible Protocols | 185 • ArrayLiteralConvertible • DictionaryLiteralConvertible Your own object type can adopt a literal convertible protocol as well. This means that a literal can appear where an instance of your object type is expected! For example, here we declare a Nest type that contains some number of eggs (its eggCount): struct Nest : IntegerLiteralConvertible { var eggCount : Int = 0 init() {} init(integerLiteral val: Int) { self.eggCount = val } } Because Nest adopts IntegerLiteralConvertible, we can pass an Int where a Nest is ex‐ pected, and our init(integerLiteral:) will be called automatically, causing a new Nest object with the specified eggCount to come into existence at that moment: func reportEggs(nest:Nest) { println("this nest contains \(nest.eggCount) eggs") } reportEggs(4) // this nest contains 4 eggs Generics A generic is a sort of placeholder for a type, into which an actual type will be slotted later. This is useful because of Swift’s strict typing. Without sacrificing that strict typing, there are situations where you can’t or don’t want to specify too precisely in a certain region of your code what the exact type of something is going to be. It is important to understand that generics do not in any way relax Swift’s strict typing. In particular, they do not postpone resolution of a type until runtime. When you use a generic, your code will still specify its real type; that real type is known with complete specificity at compile time! The particular region of your code where the type is expect‐ ed uses a generic so that it doesn’t have to specify the type fully, but at the point where that code is used by other code, the type is fully resolved. An Optional is a good example. Any type of value can be wrapped up in an Optional. Yet you are never in any doubt as to what type is wrapped up in a particular Optional. How can this be? It’s because Optional is a generic type. Here’s how an Optional works. I have already said that an Optional is an enum, with two cases: .None and .Some. If an Optional’s case is .Some, it has an associated value — the value that is wrapped by this Optional. But what is the type of that associated value? On the one hand, one wants to say that it can be any type; that, after all, is why anything can be wrapped up in an Optional. On the other hand, any given Optional that wraps a value wraps a value of 186 | Chapter 4: Object Types some specific type. When you unwrap an Optional, that unwrapped value needs to be typed as what it is, so that it can be sent messages appropriate for that type. The solution to this sort of problem is a Swift generic. The declaration for the Optional enum in the Swift header starts like this: enum Optional { // ... } That syntax means: “In the course of this declaration, I’m going to be using a made-up type — a type placeholder — that I call T. It’s a real and individual type, but I’m not going to say more about it right now. All you need to know is that whenever I say T, I mean this one particular type. When an actual Optional is created, it will be perfectly clear what type T stands for, and then, wherever I say T, you should substitute the type that it stands for.” Let’s look at more of the Optional declaration: enum Optional { case None case Some(T) init(_ some: T) // ... } Having declared that T is a placeholder, we proceed to use it. That code says: “There’s a case .None. There’s also a case .Some, which has an associated value — of type T. We also have an initializer which takes a parameter of type T. Thus, the type with which we are initialized — whatever type that may be — is type T, and thus is the type of value that is associated the .Some case.” It is this identity between the type of the initializer parameter and the type of the .Some associated value that allows the latter to be resolved. In the declaration of the Optional enum, T is a placeholder. But in real life, when an actual Optional is created, it will be initialized with an actual value of some definite type. Usually, we’ll use the question-mark syntactic sugar (type String?) and the initializer will be called for us behind the scenes, but let’s call the initializer explicitly for the sake of clarity: let s = Optional("howdy") That code resolves the type of T for this particular Optional instance! Obviously, "howdy" is a String. Thus, the compiler knows — at compile time, before any code runs — that for this particular Optional, T is String. Under the hood, wherever T appears in the declaration of the Optional enum, the compiler substitutes String. Thus, the declaration for the particular Optional referred to by the variable s looks, in the com‐ piler’s mind, like this: Generics | 187 enum Optional { case None case Some(String) init(_ some: String) // ... } That is the pseudo-code declaration of an Optional whose T placeholder has been re‐ placed everywhere with the String type. We can summarize this by saying that s is an Optional. In fact, that is legal syntax! We can create the same Optional like this: let s : Optional = "howdy" A great many of the built-in Swift types involve generics. In fact, this feature of the language seems to be designed with the Swift types in mind; generics exist exactly so that the Swift types can do what they need to do. Generic Declarations Here’s a list of the places where generics, in one form or another, can actually be declared in Swift: Generic protocol with Self In a protocol, use of the keyword Self (note the capitalization) turns the protocol into a generic. Self is a placeholder meaning the type of the adopter. This is parallel to Self as a return type in method declarations in classes; but in a protocol, it is not confined to return types. For example, here’s a Flier protocol that declares a method that takes a Self parameter: protocol Flier { func flockTogetherWith(f:Self) } That means that if, for example, the Bird object type were to adopt the Flier protocol, its implementation of flockTogetherWith would need to declare its f parameter as a Bird. Generic protocol with empty type alias A protocol can declare a type alias without any assignment defining what the type alias stands for. This turns the protocol into a generic, and the alias name (also called an associated type) is a placeholder. For example: protocol Flier { typealias Other func flockTogetherWith(f:Other) func mateWith(f:Other) } 188 | Chapter 4: Object Types An adopter will declare some particular type where the generic uses the type alias name, and this resolves, by inference, the type alias for this particular adopter. Here, for example, the Bird struct adopts the Flier protocol and declares a Bird as the f parameter of flockTogetherWith; that declaration resolves Other to Bird for this particular adopter, so now Bird must declare Bird as the f parameter for mate- With as well: struct Bird : Flier { func flockTogetherWith(f:Bird) {} func mateWith(f:Bird) {} } Generic functions A function declaration can use a generic placeholder type for any of its parameters, for its return type, and within its body. Declare the placeholder name in angle brackets after the function name: func takeAndReturnSameThing (t:T) -> T { return t } The caller will use some particular type where the placeholder appears in the func‐ tion declaration; that usage resolves the placeholder type by inference. In this ex‐ ample, the type of the argument "howdy" used in the call resolves T to String; there‐ fore this call to takeAndReturnSameThing will also return a String, and the variable capturing the result, thing, is inferred to String as well: let thing = takeAndReturnSameThing("howdy") Generic object types An object type declaration can use a generic placeholder type anywhere within its curly braces. Declare the placeholder name in angle brackets after the object type name: struct HolderOfTwoSameThings { var firstThing : T var secondThing : T init(thingOne:T, thingTwo:T) { self.firstThing = thingOne self.secondThing = thingTwo } } A user of this object type will use some particular type where the placeholder ap‐ pears in the object type declaration; that usage resolves the placeholder. In this example, the type of the thingOne argument, "howdy", used in the initializer call, resolves T to String; therefore thingTwo must also be a String, and the properties firstThing and secondThing are Strings as well: var holder = HolderOfTwoSameThings(thingOne:"howdy", thingTwo:"getLost") Generics | 189 For generic functions and object types, which use the angle bracket syntax, the angle brackets can contain multiple placeholder names, separated by comma. For example: func flockTwoTogether(f1:T, f2:U) {} After that declaration, the two parameters can be resolved to two different types (though they do not have to be different). Type Constraints All our examples so far have permitted any type to be substituted for the placeholder; but you can limit the types that are eligible to be used for resolving a particular place‐ holder. This is called a type constraint. The simplest form of type constraint is to put a colon and a type name after the placeholder’s name when it first appears. The type name after the colon can be a class name or a protocol name. For example, let’s return to our Flier and its flockTogetherWith function. Suppose we want to say that the parameter of flockTogetherWith should be declared by the adopter as a type that adopts Flier. You would not do that by declaring the type of that parameter as Flier in the protocol, like this: protocol Flier { func flockTogetherWith(f:Flier) } That code says: You can’t adopt this protocol unless you declare a function flock- TogetherWith whose f parameter is declared as Flier, like this: struct Bird : Flier { func flockTogetherWith(f:Flier) {} } That isn’t what we want to say! We want to say that Bird should be able to adopt Flier while declaring f as being of some Flier adopter type, such as Bird. The way to say that is to use a placeholder constrained as a Flier. For example, we could do it like this: protocol Flier { typealias Other : Flier func flockTogetherWith(f:Other) } Now Bird can be a legal adopter like this: struct Bird : Flier { func flockTogetherWith(f:Bird) {} } (You may be thinking that since Other is used in only one place in the protocol Flier’s declaration, we could dispense with the type alias and just have Flier declare a generic function instead. That’s not true, because that would mean something else entirely. If a 190 | Chapter 4: Object Types protocol declares a generic function, it is saying that adopters must declare that same generic function, which is a very different thing.) In a generic function or a generic object type, the type constraint appears in the angle brackets. For example: func flockTwoTogether(f1:T, f2:T) {} That code means that, if Bird and Insect both adopt Flier, flockTwoTogether can be called with two Bird parameters or with two Insect parameters — but not with a Bird and an Insect, because T is just one type. And it must be a type of Flier; you can’t call flockTwoTogether with two String parameters, because a String is not a Flier. A type constraint on a placeholder is often useful as a way of assuring the compiler that some message can be sent to an instance of the placeholder type. For example, let’s say we want to implement a function myMin that returns the smallest from a list of the same type. Here’s a promising implementation as a generic function, but there’s one problem — it doesn’t compile: func myMin(things:T ...) -> T { var minimum = things[0] for ix in 1..(things:T ...) -> T { // ... Now myMin compiles, because it cannot be called except by resolving T to an object type that adopts Comparable and hence can be compared with the less-than operator. Nat‐ urally, built-in object types that you think should be comparable, such as Int, Double, String, and Character, do in fact adopt the Comparable protocol! If you look in the Swift headers, you’ll find that the built-in min function is declared in just this way, and for just this reason. A generic protocol (a protocol whose declaration mentions Self or has an empty type alias) can be used as a type only in a generic, as a type constraint. This won’t compile: Generics | 191 protocol Flier { typealias Other func fly() } func flockTwoTogether(f1:Flier, f2:Flier) { // compile error f1.fly() f2.fly() } To use a generic Flier protocol as a type, we must write a generic and use Flier as a type constraint. For example: protocol Flier { typealias Other func fly() } func flockTwoTogether(f1:T1, f2:T2) { f1.fly() f2.fly() } Explicit Specialization In the examples so far, the user of a generic resolves the placeholder’s type through inference. But there’s another way to perform resolution: the user can resolve the type manually. This is called explicit specialization. In some situations, explicit specialization is mandatory — namely, if the placeholder type cannot be resolved through inference. There are two forms of explicit specialization: Generic protocol with empty type alias The adopter of a protocol can resolve the protocol’s empty alias type manually through a typealias declaration using the protocol’s alias name with an explicit type assignment. For example: protocol Flier { typealias Other } struct Bird : Flier { typealias Other = String } Generic object type The user of a generic object type can resolve the object’s placeholder type(s) man‐ ually using the same angle bracket syntax used to declare the generic in the first place, with actual type names in the angle brackets. (That explains the Optional type declaration I showed a moment ago.) For example: class Dog { var name : T? = nil } let d = Dog() 192 | Chapter 4: Object Types You cannot explicitly specialize a generic function. You can, however, declare a generic type with a nongeneric function that uses the generic type’s placeholder; explicit spe‐ cialization of the generic type resolves the placeholder, and thus resolves the function: protocol Flier { init() } struct Bird : Flier { init() {} } struct FlierMaker { static func makeFlier() -> T { return T() } } let f = FlierMaker.makeFlier() // returns a Bird When a class is generic, it is quite tricky to subclass it in a way that’s acceptable to the compiler (I regard this as a bug in Swift itself). My solution is to declare the subclass as a generic subclass of a manually resolved version of the superclass, even if the subclass’s placeholder isn’t used for anything: class Dog { var name : T? = nil } class NoisyDog : Dog { } To use the subclass, you have to resolve the placeholder manually, even if your resolution is pointless: let d = NoisyDog() // the Int is pointless d.name = "Fido" Where Clauses The angle brackets of a generic function or object type declaration can contain a where clause, which can solve some knotty expressive problems by honing further the con‐ straints on the placeholder type. For example, what if you want to put multiple constraints on a placeholder’s type? For a generic protocol, you can use a comma-separated list of protocols or classes when you constrain the type alias: protocol Flier { } protocol Walker { } protocol FlierWalker { typealias T : Flier, Walker // T must adopt Flier and Walker } Generics | 193 For a generic function or object type, the solution is a where clause after the placeholder name(s) in the angle brackets, consisting of the word where and one or more comma- separated clauses consisting of an already defined placeholder and a constraint. For example: protocol Flier { } protocol Walker { } func flyAndWalk (f:T) {} Another powerful use of where clauses is to constrain further a generic protocol type used as a constraint in a generic function or object type. For example: protocol Flier { typealias Other } func flockTogether (f:T) {} The generic protocol’s placeholder is its empty type alias (its associated type), so what you’re constraining here is that associated type. The goal, then, is to restrict what sort of thing Other must resolve to. The name Other exists only in the namespace of Flier, and here is to be applied to the placeholder T. So the syntax is: protocol Flier { typealias Other } func flockTogether (f:T) {} (If Other were itself constrained to a generic protocol type, the dot-notation could be extended to its type alias. I’ll show an example in a moment.) The missing part of the where clause may be one of the following: • A colon and a protocol type. The resolved type alias is constrained to be an adopter of this protocol. • An equality operator and an object type. The resolved type alias is constrained to be of this type. • An equality operator and another placeholder-plus-type-alias. The resolved type aliases are constrained to be the same type as one another. Here’s a (silly) example where the type alias is constrained to a protocol: protocol Flier { typealias Other } struct Bird : Flier { typealias Other = String } 194 | Chapter 4: Object Types struct Insect : Flier { typealias Other = Bird } func flockTogether (f:T) {} In that example, the function flockTogether can be called with a Bird parameter, be‐ cause a Bird’s Other type alias is resolved to String, and String adopts the built-in Equat‐ able protocol — but the function flockTogether can’t be called with an Insect param‐ eter, because an Insect’s Other type alias is resolved to Bird, and Bird doesn’t adopt the Equatable protocol. The Swift header makes extensive use of where clauses of this kind. For example, here’s the declaration of the built-in find function: func find (domain: C, value: C.Generator.Element) -> C.Index? The Find function returns the index number of a requested object within a given col‐ lection; I gave some examples in Chapter 3, such as find("howdy","o"). Observe the chaining of the type alias names in C.Generator.Element. A CollectionType is some‐ thing like a String or an Array; it has an empty type alias Generator, which is constrained to be a GeneratorType, which in turn has an empty type alias Element. That’s fancy talk for a simple concept — it means, “The kind of thing this is a collection of.” The where clause then says that the kind of thing the placeholder C is a collection of must be an Equatable — very sensibly, because there is no way to find an object in a collection if there is no way to know whether two objects are equal! You can’t find a needle in a haystack unless you have a way of identifying a needle when you see it. Based on that model, we can write a where clause specifying that we want a collection of some specific element type, such as Character; this is an object type, not a protocol, so we use == and not a colon: func printc(c:C) { for char in c { println(char) } } Either of these two calls to printc is legal, because a String is a collection of Character and an array of Character is a collection of Character: printc("howdy") printc(["h" as Character, "i" as Character]) Finally, here’s an example (again silly) of a where clause constraining two type aliases to be the same type as one another: Generics | 195 protocol Flier { typealias Other } struct Bird : Flier { typealias Other = String } struct Insect : Flier { typealias Other = Int } func flockTwoTogether (f1:T, f2:U) {} In that code, the function flockTwoTogether can be called with a Bird and a Bird, and it can be called with an Insect and an Insect, but it can’t be called with an Insect and a Bird because their Other type aliases are not resolved to the same type. (Interestingly, the type of a generic protocol’s resolved type alias can also be referred to outside a where clause. I’ll give an example later in this chapter.) Extensions An extension is a way of injecting your own code into an object type that has already been declared elsewhere. This could be one of your own object types; in that case, you could have put this functionality into the original object type declaration, and the ex‐ tension is merely a device to allow you to organize your code more clearly and conven‐ iently. However, it could be one of Swift’s object types or one of Cocoa’s Objective-C object types; in that case, you are adding functionality to a type that doesn’t belong to you! To declare an extension, put the keyword extension followed by the name of an existing object type, then optionally a colon plus the names of any protocols you want to add to the list of those adopted by this type, and finally curly braces containing the usual things that go inside an object type declaration — with the following restrictions: • An extension can’t redefine (override) an existing member. • An extension can’t declare a stored property (but it can declare a computed prop‐ erty). • An extension of a class can’t declare a designated initializer or a deinitializer (but it can declare a convenience initializer). In my real programming life, I sometimes extend a built-in Swift or Cocoa type just to encapsulate some missing functionality by expressing it as a property or method. Here are a couple of examples from actual apps. 196 | Chapter 4: Object Types In a card game, I need to shuffle the deck, which is stored in an array. I extend Swift’s built-in Array type to give it a shuffle method (I’ll discuss the stride function in Chapter 5): extension Array { mutating func shuffle () { for i in stride(from:self.count-1, to:0, by:-1) { let ix1 = i let ix2 = Int(arc4random_uniform(UInt32(i+1))) (self[ix1], self[ix2]) = (self[ix2], self[ix1]) } } } Cocoa’s Core Graphics framework has many useful functions associated with the CGRect struct, and Swift itself extends CGRect to add some helpful properties and methods; but there’s no shortcut for getting the center point (a CGPoint) of a CGRect, something that in practice one very often needs. I extend CGRect to give it a center property: extension CGRect { var center : CGPoint { return CGPointMake(self.midX, self.midY) } } An extension can declare a static or class method; since an object type is usually globally available, this can often be an excellent way to slot a global function into an appropriate namespace. For example, in one of my apps, I find myself frequently using a certain color (a UIColor). Instead of creating that color repeatedly, it makes sense to encapsulate the instructions for generating it in a global function. But instead of making that func‐ tion completely global, I make it — appropriately enough — a class method of UIColor: extension UIColor { class func myGolden() -> UIColor { return self(red:1.000, green:0.894, blue:0.541, alpha:0.900) } } Now I can use that color throughout my code simply by saying UIColor.myGolden(), completely parallel to built-in class methods such as UIColor.redColor(). A frequent use of extensions is to make an object type adopt a protocol. Of course, you then also have to implement the members required by that protocol, if they are not implemented already. For example, the Core Graphics CGAffineTransform struct isn’t logged nicely in the console with println; it isn’t a Printable. It’s easy to make it a Printable, though, because there’s a Cocoa function for representing a CGAffineTransform as a string: Extensions | 197 extension CGAffineTransform : Printable { public var description : String { return NSStringFromCGAffineTransform(self) } } As I mentioned earlier, extensions on one’s own object types can help to organize one’s code. A frequently used convention is to add an extension for each protocol one’s object type needs to adopt, like this: class ViewController: UIViewController { // ... UIViewController method overrides go here ... } extension ViewController : UIPopoverPresentationControllerDelegate { // ... UIPopoverPresentationControllerDelegate methods go here ... } extension ViewController : UIToolbarDelegate { // ... UIToolbarDelegate methods go here ... } An extension on your own object type is also a good way to spread your definition of that object type over multiple files, if you feel that several shorter files are better than one long file. When you extend a generic object type, you cannot add new placeholders to this object type, and you cannot add new constraints to its existing placeholder types. However, the existing placeholder type names are in scope inside your extension declaration. That’s good, because you might need to use them; but it makes your code a little mys‐ tifying, because you seem to be using some undefined type names out of the blue. It might be a good idea to add a comment, to remind yourself what you’re up to. Here’s an artificial example (and I’ll give a real example later in this chapter): class Dog { var name : T? = nil } extension Dog { func sayYourName() -> T? { // T is the type of self.name return self.name } } When you extend a Swift struct, a curious thing happens with initializers: it becomes possible to declare an initializer and keep the implicit initializers: struct Digit { var number : Int } extension Digit { init() { self.init(number:42) } } 198 | Chapter 4: Object Types That code means that you can instantiate a Digit by calling the explicitly declared ini‐ tializer — Digit() — or by calling the implicit memberwise initializer — Digit(number:7). Thus, the explicit declaration of an initializer through an extension did not cause us to lose the implicit memberwise initializer, as would have happened if we had declared the same initializer inside the original struct declaration. Umbrella Types Swift provides a few built-in types as general umbrella types, capable of embracing multiple real types under a single heading. AnyObject The umbrella type most commonly encountered in real-life iOS programming is Any‐ Object. It is actually a protocol; as a protocol, it is completely empty, requiring no prop‐ erties or methods. It has the special feature that all class types conform to it automatically. Thus, it is possible to assign or pass any class instance where an AnyObject is expected, and to cast in either direction: class Dog { } let d = Dog() let any : AnyObject = d let d2 = any as! Dog The common way to encounter an AnyObject is in the course of interchange with Objective-C. Swift’s ability to cast any class type to and from an AnyObject parallels Objective-C’s ability to cast any class type to and from an id. In effect, AnyObject is the Swift version of id. Certain basic Swift types, which are not class types — such as String and the numeric types — are bridged to Objective-C types, which are class types, defined by the Foun‐ dation framework. This means that, in the presence of the Foundation framework, a Swift bridged type can be assigned, passed, or cast to an AnyObject, even if it is not a class type — because it will be cast first to its Objective-C bridged class type automati‐ cally, behind the scenes — and an AnyObject can be cast down to a Swift bridged type. For example: let s = "howdy" let any : AnyObject = s // implicitly casts to NSString let s2 = any as! String let i = 1 let any2 : AnyObject = i // implicitly casts to NSNumber let i2 = any2 as! Int Many Cocoa values are typed as id in the APIs, and such values will arrive from Cocoa into Swift typed as AnyObject. If you know what such a value really is, you’re probably Umbrella Types | 199 going to want to cast it down to that type, so that you can work with it as that type. The Swift compiler will prompt you, by warning whenever AnyObject is used as an implicit type. For example: let vc = self.storyboard!.instantiateViewControllerWithIdentifier("vc") The compiler warns that vc is “inferred to have type AnyObject!, which may be unex‐ pected.” This is not an error — your code will compile and run — but the compiler is trying to be helpful, and it’s a good idea to deal with all compiler warnings. There are two ways to quiet the compiler’s warning. One is to declare vc as AnyObject explicitly, thus acknowledging to the compiler that you’re aware of what’s going on: let vc : AnyObject = self.storyboard!.instantiateViewControllerWithIdentifier("vc") The other way is to cast down. We happen to know that instantiateViewController- WithIdentifier will return a UIViewController, so casting is probably a better solution: let vc = self.storyboard!.instantiateViewControllerWithIdentifier("vc") as! UIViewController That cast is permitted, because AnyObject can be cast to just about any Cocoa object type. Of course, you’d better be telling the truth when you cast, or you will crash when the code runs and the cast turns out to be impossible. You can use the is and as? operators, if you’re in doubt, to make sure your cast is safe. That might be a good idea here, because instantiateViewControllerWithIdentifier can return nil to indicate that no view controller in this storyboard matches this identifier. The need to cast here is somewhat surprising, because it seems obvious that, with a name like instantiateViewControllerWithIdentifier, this method is going to return a UIViewController. But the fault lies in the Cocoa API, not with Swift. The API declares the return type here as an id — in Swift, an AnyObject — and that’s all Swift can know about the matter. In the future, perhaps this API will be hand-tweaked to return a UIView- Controller?, which in my view is how this value should be typed. Until then, Swift provides a helpful warning, and the rest is up to you. (A particularly common way to receive values typed as AnyObject from Cocoa is when it hands you an array. All Objective-C arrays arrive into Swift as arrays of AnyObject. I’ll have more to say about that when I discuss arrays later in this chapter.) Suppressing type checking A surprising feature of AnyObject is that it can be used to suspend the compiler’s judg‐ ment as to whether a certain message can be sent to an object. This convenience delib‐ erately mimics Objective-C, where typing something as an id causes the compiler to suspend judgment about what messages can be sent to it. Thus, you can do in Swift what 200 | Chapter 4: Object Types you could have done in Objective-C, namely, send a message to an AnyObject without bothering to cast to its real type. (Nevertheless, if you know the object’s real type, you probably will cast to that type.) You can’t send just any old message to an AnyObject; the message must correspond to a class member that meets one of the following criteria: • It is part of an Objective-C class. • It is declared in your own Swift subclass of an Objective-C class. • It is declared in your own Swift extension of an Objective-C class. • It is declared in a Swift class marked @objc. • It is declared in a Swift class, and is itself marked @objc (or dynamic). This feature is fundamentally parallel to optional protocol members, which I discussed earlier in this chapter — with some slight differences. To see what I mean, let’s start with two classes: class Dog { @objc var noise : String = "woof" @objc func bark() -> String { return "woof" } } class Cat {} The Dog property noise and the Dog method bark are marked @objc, so they are visible as potential messages to be sent to an AnyObject. To prove it, I’ll type a Cat as an AnyObject and send it one of these messages. Let’s start with the noise property: let c : AnyObject = Cat() let s = c.noise That code, amazingly, compiles. Moreover, it doesn’t crash when the code runs! The noise property has been typed as an Optional wrapping its original type. Here, that’s an Optional wrapping a String. If the object typed as AnyObject doesn’t implement noise, the result is nil and no harm done. Moreover, unlike an optional protocol prop‐ erty, the Optional in question is implicitly unwrapped. Therefore, if the AnyObject turns out to have a noise property (for example, if it had been a Dog), the resulting implicitly unwrapped String can be treated directly as a String. Now let’s try it with a method call: let c : AnyObject = Cat() let s = c.bark?() Again, that code compiles and is safe. If the Object typed as AnyObject doesn’t imple‐ ment bark, no bark() call is performed; the method result type has been wrapped in Umbrella Types | 201 an Optional, so s is typed as String? and has been set to nil. If the AnyObject turns out to have a bark method (for example, if it had been a Dog), the result is an Optional wrapping the returned String. If you call bark!() on the AnyObject instead, the result will be a String, but you’ll crash if the AnyObject doesn’t implement bark. There’s another difference between AnyObject members and optional protocol mem‐ bers. With AnyObject, you can send the message with no unwrapping. This is legal: let c : AnyObject = Cat() let s = c.bark() That’s just like force-unwrapping the call: the result is a String, but it’s possible to crash. Object identity Sometimes, what you want to know is not what type an object is, but whether an object itself is the particular object you think it is. If an object type adopts AnyObject, you can use the identity operator (===) to compare one object reference with another. This is not a comparison of values for equality, like the equality operator (==); you’re asking whether two object references refer to one and the same object. There is also a negative version of the identity operator (!==). A typical use case is that an object arrives from Cocoa, and you need to know whether it is in fact a particular object to which you already have a reference. For example, an NSNotification has an object property that helps identify the notification (usually, it is the original sender of the notification). When a notification is sent to you, you can use the identity operator to make sure that its object property is the object you expect: func changed(n:NSNotification) { let player = MPMusicPlayerController.applicationMusicPlayer() if n.object === player { // ... A class is an object, and each class object is a singleton. So the identity operator is also a way of comparing the classes of two objects with one another (by comparing their dynamicType). AnyClass AnyClass is the class of AnyObject. It corresponds to the Objective-C Class type. It arises typically in declarations where a Cocoa API wants to say that a class is expected. For example, the UIView layerClass class method is declared, in its Swift translation, like this: class func layerClass() -> AnyClass 202 | Chapter 4: Object Types That means: if you override this method, implement it to return a class. This will pre‐ sumably be a CALayer subclass. To return an actual class in your implementation, send the self message to the name of the class: override class func layerClass() -> AnyClass { return CATiledLayer.self } Any The Any type is a type alias for an empty protocol that is automatically adopted by all types. Thus, where an Any object is expected, absolutely any object can be passed: func anyExpecter(a:Any) {} anyExpecter("howdy") // a struct instance anyExpecter(String) // a struct anyExpecter(Dog()) // a class instance anyExpecter(Dog) // a class anyExpecter(anyExpecter) // a function An object typed as Any can be tested against, or cast down to, any object or function type. To illustrate, here’s a protocol with an empty type alias, and two adopters who explicitly resolve it: protocol Flier { typealias Other } struct Bird : Flier { typealias Other = Insect } struct Insect : Flier { typealias Other = Bird } Now here’s a function that takes a Flier along with a second parameter typed as Any, and tests whether that second parameter’s type is the same as the Flier’s resolved Other type; the test is legal because Any can be tested against any type: func flockTwoTogether(flier:T, other:Any) { if other is T.Other { println("they can flock together") } } If we call flockTwoTogether with a Bird and an Insect, the console says “they can flock together.” If we call it with a Bird and an object of any other type, it doesn’t. Collection Types Swift, in common with most modern computer languages, has built-in collection types, Array and Dictionary. They are sufficiently important that the language accommodates Collection Types | 203 them with some special syntax. At the same time, like most Swift types, they are quite thinly provided with related functions; some missing functionality is provided by Co‐ coa’s NSArray and NSDictionary, to which they are respectively bridged. New in Swift 1.2, a third collection type, Set, has been added, which is bridged to Cocoa’s NSSet. Array An array (Array, a struct) is an ordered collection of object instances (the elements of the array) accessible by index number, where an index number is an Int numbered from 0. Thus, if an array contains four elements, the first has index 0 and the last has index 3. A Swift array cannot be sparse: if there is an element with index 3, there is also an element with index 2 and so on. The most salient feature of Swift arrays is their strict typing. Unlike some other computer languages, a Swift array’s elements must be uniform — that is, the array must consist solely of elements of the same definite type. Even an empty array must have a definite element type, despite the fact that it happens to lack elements at this moment. An array is itself typed in accordance with its element type. Arrays whose elements are of different types are considered, themselves, to be of two different types: an array of Int elements is of a different type from an array of String elements. Array types are polymorphic in accordance with their element types: if NoisyDog is a subclass of Dog, then an array of NoisyDog can be used where an array of Dog is expected. If all this reminds you of Optionals, it should. Like an Optional, a Swift array is a generic. It is declared as Array, where the placeholder T is the type of a particular array’s elements. The uniformity restriction is not as severe as it might seem at first glance. An array must have elements of just one type, but types are very flexible. By a clever choice of type, you can have an array whose elements are of different types internally. For example: • If there’s a Dog class with a NoisyDog subclass, an array of Dog can contain both Dog objects and NoisyDog objects. • If both Bird and Insect adopt the Flier protocol, an array of Flier can contain both Bird objects and Insect objects. • An array of AnyObject can contain instances of any class and of any Swift bridged type — such as an Int, a String, and a Dog. • A type might itself be a carrier of different possible types. My Error enum, earlier in this chapter, is an example; its associated value might be an Int or it might be a String, so an array of Error elements can carry both Int values and String values within itself. 204 | Chapter 4: Object Types To declare or state the type of a given array’s elements, you could explicitly resolve the generic placeholder; an array of Int elements would thus be an Array. However, Swift offers syntactic sugar for stating an array’s element type, using square brackets around the name of the element type, like this: [Int]. That’s the syntax you’ll use most of the time. A literal array is represented as square brackets containing a list of its elements separated by comma (and optional spaces): for example, [1,2,3]. The literal for an empty array is empty square brackets: []. An array’s default initializer init(), called by appending empty parentheses to the ar‐ ray’s type, yields an empty array of that type. Thus, you can create an empty array of Int like this: var arr = [Int]() Alternatively, if a reference’s type is known in advance, the empty array [] can be inferred to that type. Thus, you can also create an empty array of Int like this: var arr : [Int] = [] If you’re starting with a literal array containing elements, you won’t usually need to declare the array’s type, because Swift will infer it by looking at the elements. For ex‐ ample, Swift will infer that [1,2,3] is an array of Int. If the array element types consist of a class and its subclasses, like Dog and NoisyDog, Swift will infer the common su‐ perclass as the array’s type. Even [1, "howdy"] is a legal array literal; it is inferred to be an array of NSObject. However, in some cases you will need to declare an array refer‐ ence’s type explicitly even while assigning a literal to that array: let arr : [Flier] = [Insect(), Bird()] An array also has an initializer whose parameter is a sequence. This means that if a type is a sequence, you can split an instance of it into the elements of an array. Array(1...3) generates the array of Int [1,2,3]. Array("hey") generates the array of Character ["h","e","y"]. Array(d), where d is a Dictionary, generates an array of tuples of the key–value pairs of d. (There is also a global reverse method that turns a sequence into an array in reverse order.) Another array initializer, init(count:repeatedValue:), lets you populate an array with the same value. In this example, I create an array of 100 Optional strings initialized to nil: let strings : [String?] = Array(count:100, repeatedValue:nil) That’s the closest you can get in Swift to a sparse array; we have 100 slots, each of which might or might not contain a string (and to start with, none of them do). Collection Types | 205 Array casting and type testing When you assign, pass, or cast one array type to another array type, you are operating on the individual elements of the array. Thus, for example: let arr : [Int?] = [1,2,3] That code is actually a shorthand: to treat an array of Int as an array of Optionals wrap‐ ping Int means that each individual Int in the original array must be wrapped in an Optional. And that is exactly what happens: let arr : [Int?] = [1,2,3] println(arr) // [Optional(1), Optional(2), Optional(3)] Similarly, suppose we have a Dog class and its NoisyDog subclass; then this code is legal: let dog1 : Dog = NoisyDog() let dog2 : Dog = NoisyDog() let arr = [dog1, dog2] let arr2 = arr as! [NoisyDog] In third line, we have an array of Dog. In the fourth line, we cast this array down to an array of NoisyDog, meaning that we cast each individual Dog in the first array to a NoisyDog (and we won’t crash when we do that, because each element of the first array really is a NoisyDog). You can test all the elements of an array with the is operator by testing the array itself. For example, given the arr array of Dog from the previous code, you can say: if arr is [NoisyDog] { // ... That will be true if each element of the array is in fact a NoisyDog. Similarly, the as? operator will cast an array to an Optional wrapping an array, which will be nil if the underlying cast cannot be performed: let dog1 : Dog = NoisyDog() let dog2 : Dog = NoisyDog() let dog3 : Dog = Dog() let arr = [dog1, dog2] let arr2 = arr as? [NoisyDog] // Optional wrapping an array of NoisyDog let arr3 = [dog2, dog3] let arr4 = arr3 as? [NoisyDog] // nil The reason for casting down an array is exactly the same as the reason for casting down any value — it’s so that you can send appropriate messages to the elements of that array. If NoisyDog declares a method that Dog doesn’t have, you can’t send that message to an element of an array of Dog. Somehow, you need to cast that element down to a NoisyDog so that the compiler will let you send it that message. You can cast down an individual element, or you can cast down the entire array; you’ll do whichever is safe and makes sense in a particular context. 206 | Chapter 4: Object Types Array comparison Array equality works just as you would expect: two arrays are equal if they contain the same number of elements and all the elements are pairwise equal in order: let i1 = 1 let i2 = 2 let i3 = 3 if [1,2,3] == [i1,i2,i3] { // they are equal! Two arrays don’t have to be of the same type to be compared against one another for equality, but the test won’t succeed unless they do in fact contain objects that are equal to one another. Here, I compare a Dog array against a NoisyDog array; they are in fact equal because the dogs they contain are the same dogs in the same order: let nd1 = NoisyDog() let d1 = nd1 as Dog let nd2 = NoisyDog() let d2 = nd2 as Dog if [d1,d2] == [nd1,nd2] { // they are equal! Arrays are value types Because an array is a struct, it is a value type, not a reference type. This means that every time an array is assigned to a variable or passed as argument to a function, it is effectively copied. I do not mean to imply, however, that merely assigning or passing an array is expensive, or that a lot of actual copying takes place every time. If the reference to an array is a constant, clearly no copying is actually necessary; and even operations that yield a new array derived from another array, or that mutate an array, may be quite efficient. You just have to trust that the designers of Swift have thought about these problems and have implemented arrays efficiently behind the scenes. Nevertheless, some inefficiencies may still be encountered; bear in mind that Swift is a relatively new language and that such inefficiences may be dealt with in the future as it evolves further. Although an array itself is a value type, its elements are treated however those elements would normally be treated. In particular, an array of class instances, assigned to multiple variables, results in multiple references to the same instances. Array subscripting The Array struct implements subscript methods to allow access to elements using square brackets after a reference to an array. You can use an Int inside the square brackets. For example, in an array consisting of three elements, if the array is referred to by a variable arr, then arr[1] accesses the second element. You can also use a Range of Int inside the square brackets. For example, if arr is an array with three elements, then arr[1...2] signifies the second and third elements. Techni‐ cally, an expression like arr[1...2] yields something called a Slice. However, a Slice is Collection Types | 207 very similar to an array; for example, you can subscript a Slice in just the same ways you would subscript an array, and a Slice can be passed where an array is expected. In general, therefore, you will probably pretend that a Slice is an array. If the reference to an array is mutable (var, not let), then a subscript expression can be assigned to. This alters what’s in that slot. Of course, what is assigned must accord with the type of the array’s elements: var arr = [1,2,3] arr[1] = 4 // arr is now [1,4,2] If the subscript is a range, what is assigned must be an array. This can change the length of the array being assigned to: var arr = [1,2,3] arr[1..<2] = [7,8] // arr is now [1,7,8,3] arr[1..<2] = [] // arr is now [1,8,3] It is a runtime error to access an element by a number larger than the largest element number or smaller than the smallest element number. If arr has three elements, speaking of arr[-1] or arr[3] is not illegal linguistically, but your program will crash. Nested arrays It is legal for the elements of an array to be arrays. For example: let arr = [[1,2,3], [4,5,6], [7,8,9]] That’s an array of arrays of Int. Its type declaration, therefore, is [[Int]]. (No law says that the contained arrays have to be the same length; that’s just something I did for clarity.) To access an individual Int inside those nested arrays, you can chain subscript opera‐ tions: let arr = [[1,2,3], [4,5,6], [7,8,9]] let i = arr[1][1] // 5 If the outer array reference is mutable, you can also write into a nested array: var arr = [[1,2,3], [4,5,6], [7,8,9]] arr[1][1] = 100 You can modify the inner arrays in other ways as well; for example, you can insert additional elements into them. Basic array properties and methods An array’s count read-only property reports the number of elements it contains. If an array’s count is 0, its isEmpty property is true. 208 | Chapter 4: Object Types An array’s largest accessible index is one less than its count. You will often find yourself calculating index values with reference to the count; for example, to refer to the last two elements of arr, you can say: let arr = [1,2,3] let arr2 = arr[arr.count-2...arr.count-1] // [2,3] Swift doesn’t adopt the modern convention of letting you use negative numbers as a shorthand for that calculation. On the other hand, for the common case where you want the last n elements of an array, you can use the global suffix method: let arr = [1,2,3] let arr2 = suffix(arr,2) // [2,3] An array’s first and last read-only properties return its first and last elements, but they are wrapped in an Optional because the array might be empty and so these prop‐ erties would need to be nil. This is one of those rare situations in Swift where you can wind up with an Optional wrapping an Optional. For example, consider an array of Optionals wrapping Ints, and what happens when you get the last property of such an array: let arr : [Int?] = [1,2,3] let i = arr.last After that code, i is an Optional wrapping an Optional wrapping an Int. That’s because the last property wraps the last element of the array in an Optional, and the last element of the array was itself an Optional wrapping an Int. This changes nothing about how you work with i; it’s just something to be aware of. You’ll test i against nil to find out whether there was a last element and whether it’s safe to unwrap the Optional; then you’ll unwrap the Optional to get the Optional wrapping an Int that’s inside it. If the reference to an array is mutable, the append and extend instance methods add elements to the end of it. The difference between them is that append takes a single value of the element type, while extend takes an array (actually, a sequence) of the element type. For example: var arr = [1,2,3] arr.append(4) arr.extend([5,6]) arr.extend(7...8) // arr is now [1,2,3,4,5,6,7,8] The + operator is overloaded to behave like extend (not append!) when the left-hand operand is an array, except that it generates a new array, so it works even if the reference to the array is a constant. If the reference to the array is mutable, you can extend it in place with the += operator. Thus: Collection Types | 209 let arr = [1,2,3] let arr2 = arr + [4] // arr2 is now [1,2,3,4] var arr3 = [1,2,3] arr3 += [4] // arr3 is now [1,2,3,4] If the reference to an array is mutable, the instance method insert(atIndex:) inserts a single element at the given index. To insert multiple elements at once, use assignment into a range-subscripted array, as I described earlier. If the reference to an array is mutable, the instance method removeAtIndex removes the element at that index; the instance methods removeFirst and removeLast remove the first and last elements. These methods also return the value that was removed from the array; you can ignore the returned value if you don’t need it. These methods do not wrap the returned value in an Optional, and accessing an out-of-range index will crash your program. If the reference is not mutable, you can use the global dropFirst and dropLast functions to return an array with the end element removed. The join instance method takes an array of arrays. It extracts their individual elements, and interposes the elements of this array repeatedly between each sequence of extracted elements, returning the result as a single array. For example: let arr = [[1,2], [3,4], [5,6]] let arr2 = [10,11].join(arr) // [1, 2, 10, 11, 3, 4, 10, 11, 5, 6] Calling join on an empty array is thus a way to flatten the parameter array: let arr = [[1,2], [3,4], [5,6]] let arr2 = [].join(arr) // [1, 2, 3, 4, 5, 6] The reverse instance method yields a new array whose elements are in the opposite order from the original. The sort and sorted instance methods respectively sort the original array (if the ref‐ erence to it is mutable) and yield a new sorted array based on the original. They both take a function as their parameter; this function must take two parameters of the correct element type and return a Bool stating whether the first parameter is ordered before the second in accordance with your criterion for order. For example: var arr = [4,3,5,2,6,1] arr.sort {$0 < $1} // [1, 2, 3, 4, 5, 6] In that example, I provided the function as an anonymous function, omitting the parentheses according to the standard shortcut. Alternatively, of course, you can pass as argument the name of a declared function. In Swift, operators such as the less-than comparison operator are the names of functions. Therefore, I can do the same thing more briefly, like this: var arr = [4,3,5,2,6,1] arr.sort(<) // [1, 2, 3, 4, 5, 6] 210 | Chapter 4: Object Types The global contains function reports whether an array (of Equatables) contains an element: let arr = [1,2,3] let ok = contains(arr,2) The global find function reports the index of the first occurrence of an element in an array (of Equatables), but it is wrapped in an Optional so that nil can be returned if the element doesn’t appear in the array: let arr = [1,2,3] let ix = find(arr,2) // Optional wrapping 1 The global startsWith and endsWith functions report whether the starting or ending elements of an array match the elements of a second array; you supply a function that takes two values of the element type and returns a Bool stating whether they match: let arr = [1,2,3] let ok = startsWith(arr, [1,2]) {$0 == $1} As in the sort example a moment ago, I can shorten that code because the equality comparison operator is the name of a function: let arr = [1,2,3] let ok = startsWith(arr, [1,2], ==) The minElement and maxElement global functions return the smallest or largest element in an array (of Comparables): let arr = [3,1,2] let min = minElement(arr) // 1 The global split function breaks an array into an array of arrays at the elements that pass a specified test, which is a function that takes a value of the element type and returns a Bool; the elements passing the test are eliminated: let arr = [1,2,3,4,5,6] let arr2 = split(arr) {$0 % 2 == 0} // split at evens: [[1], [3], [5]] Array enumeration and transformation The simplest way to enumerate an array, and thus to inspect or operate with each element in turn, is by means of a for...in loop; I’ll have more to say about this construct in Chapter 5: let pepboys = ["Manny", "Moe", "Jack"] for pepboy in pepboys { println(pepboy) // prints Manny, then Moe, then Jack } Collection Types | 211 If you need the index numbers as well as the elements, wrap the array in a call to the built-in enumerate function and use a for...in loop on that; what you get on each iteration is a tuple: let pepboys = ["Manny", "Moe", "Jack"] for (ix,pepboy) in enumerate(pepboys) { println("Pep boy \(ix) is \(pepboy)") // Pep boy 0 is Manny, etc. } In Swift, however, you will not be using for...in enumeration on an array as much as you might suppose. Instead, you’ll prefer one of three powerful array transformation instance methods. These methods all enumerate the array for you, so that the loop is buried implicitly inside the method call, making your code tighter and cleaner. Let’s start with the map instance method. It yields a new array, each element of which is the result of passing the corresponding element of the old array through a function that you supply. This function accepts a parameter of the element type and returns a result which may be of some other type; Swift can usually infer the type of the resulting array elements by looking at the type returned by the function. For example, here’s how to multiply every element of an array by 2: let arr = [1,2,3] let arr2 = arr.map {$0 * 2} // [2,4,6] Here’s another example, to illustrate the fact that map can yield an array with a different element type: let arr = [1,2,3] let arr2 = arr.map {Double($0)} // [1.0, 2.0, 3.0] Here’s a real-life example showing how neat and compact your code can be when you use map. In order to remove all the table cells in a section of a UITableView, I have to specify the cells as an array of NSIndexPath objects. If sec is the section number, I can form those NSIndexPath objects individually like this: let path0 = NSIndexPath(forRow:0, inSection:sec) let path1 = NSIndexPath(forRow:1, inSection:sec) // ... Hmmm, I think I see a pattern here! I could generate my array of NSIndexPath objects by looping through the row values using for...in. But with map, there’s a much tighter way to express the same loop (ct is the number of rows in the section): let paths = Array(0.. 0} 214 | Chapter 4: Object Types After the first two lines, setting up the sample data, what remains is a single command — a map call, whose function consists of a filter call, with a filter call chained to it. If that code doesn’t prove to you that Swift is cool, nothing will. In addition to these Array instance methods, there are global map, filter, and reduce functions that operate on sequences in general. I’ll give an example later. Swift Array and Objective-C NSArray When you’re programming iOS, you import the Foundation framework (or UIKit, which imports it) and thus the Objective-C NSArray type. Swift’s Array type is bridged to Objective-C’s NSArray type. But in Objective-C, an NSArray is just an NSArray; it has no further element type information. In theory, any NSArray can contain elements of any type, and they can be of different types; the only requirement is that they must be objects, which means, in Objective-C’s mind, that they are class instances. Thus, the typological medium of exchange between a Swift array and an NSArray is the [Any- Object] type. In Swift’s rendering of the Cocoa APIs, you’ll see [AnyObject] wherever an NSArray is expected or provided by Objective-C. Passing a Swift array to Objective-C is usually easy, provided your Swift array consists of things that can be cast up to AnyObject. You’ll just pass the array, either by assignment or as an argument in a function call, and it will be accepted because your array’s element type is acceptable where an AnyObject is expected, as this artificial example demon‐ strates: let arr = [UIBarButtonItem(), UIBarButtonItem()] self.navigationItem.leftBarButtonItems = arr self.navigationItem.setLeftBarButtonItems(arr, animated: true) To call an NSArray method on a Swift array, you have to cast to NSArray: let arr = ["Manny", "Moe", "Jack"] let s = (arr as NSArray).componentsJoinedByString(", ") // s is "Manny, Moe, Jack" A Swift Array seen through a var reference is mutable, but an NSArray isn’t mutable no matter how you see it. For mutability in Objective-C, you need an NSMutableArray, a subclass of NSArray. You can’t cast, assign, or pass a Swift array to an NSMutableArray; you have to coerce. The best way is with the NSMutableArray initializer init(array:), to which you can pass a Swift array directly: let arr = ["Manny", "Moe", "Jack"] let arr2 = NSMutableArray(array:arr) arr2.removeObject("Moe") You can’t pass just any old Swift array to Objective-C. Your Swift array must consist of an element type that can itself be bridged to Objective-C as an AnyObject; otherwise, Collection Types | 215 the compiler will stop you. Swift will bridge for you wherever it can. For example, a Swift array of Int is fine, because each Int will be bridged to NSNumber; and a Swift array of String is fine, because each String will be bridged to NSString. But many Swift arrays can’t cross the bridge. In such cases, you’ll need to transform the array before bridging it. Here, for example, I have a Swift array of CGPoint. That’s perfectly fine in Swift, but CGPoint is a struct, which Objective-C doesn’t see as an object, so you can’t put one in an NSArray. The solution is to wrap each CGPoint in an NSValue, an Objective-C object type specifically designed to act as a carrier for various nonobject types; now we have a Swift array of NSValue, which can subsequently be handed to Objective-C: let arrNSValues = arrCGPoints.map { NSValue(CGPoint:$0) } Similarly, recall the sparse array of strings from earlier in this chapter. I implemented it as an array of Optionals wrapping strings. But now let’s say I want to hand this array over to Cocoa. I have to prepare the array before I can do that. An Optional can’t be cast to an AnyObject, so I need to unwrap all the Optionals. That’s fine for the Optionals that wrap Strings; I end up with a String. But what about the Optionals that are nil? I can’t just unwrap them; if you try to unwrap a nil Optional, you’ll crash at runtime: let arr2 = arr.map{$0!} // crash if an element is nil Moreover, an Objective-C NSArray can’t contain nil; to Objective-C, nil isn’t an object. So for the nil Optionals, I substitute the special object NSNull(), which is designed to represent nil in an Objective-C collection. But now my code doesn’t compile: let arr2 = arr.map{if $0 == nil {return NSNull()} else {return $0!}} // error The problem is that Swift can’t infer this array’s type! I have to declare it explicitly as an [AnyObject], a Swift array capable of holding both String objects and NSNull objects: let arr2 : [AnyObject] = arr.map{if $0 == nil {return NSNull()} else {return $0!}} Now let’s talk about what happens when an NSArray arrives from Objective-C into Swift. What you’ll get will typically be a Swift array of AnyObject — an [AnyObject]. You can leave it at that, but usually you’ll want to cast down to an array of the type of object actually contained in the array, or a Swift type to which it is bridged. For example, this Cocoa class method call returns a Swift array of AnyObject: let arr = UIFont.familyNames() But you know very well that these AnyObject objects are all NSString objects, so it’s reasonable to cast this array down to a String array immediately: let arr = UIFont.familyNames() as! [String] Similarly, a UIView’s subviews arrives as an [AnyObject]. But you know perfectly well that it’s really an array of UIView objects, so you’ll cast down: 216 | Chapter 4: Object Types let views = self.view.subviews as! [UIView] You’ll find yourself casting down from [AnyObject] in this way very frequently in working with Cocoa, and it’s a little infuriating. One wants to slap Cocoa on the side of the head and say, “You knucklehead! Of course this is an array of UIViews! What else could a view’s subviews possibly be?” However, you’ll just have to get over it. Some day, perhaps, the APIs will be tweaked so that all such obvious casts are performed for you; until then, you’ll have to perform them yourself. As with any cast, though, be sure you don’t lie! An Objective-C array can contain more than one type of object. Don’t force such an array to be cast down to a type to which not all the elements can be cast, or you’ll crash when the cast fails. If you want to cast from a mixed bag of AnyObject elements to a more specific Swift type, you’ll need a strategy. In this example from my own code, arr contains both NSString and NSNull objects. I know that none of the NSString objects are the empty string, so I substitute the empty string for all the NSNull objects, thus giving me an array of strings only, which Swift can deal with: let arr2 : [String] = arr.map { if $0 is String { return $0 as! String } else { return "" } } Now arr2 is a pure Swift [String] array. (That code can be shortened considerably by using the ?? operator, as I’ll explain in Chapter 5.) Dictionary A dictionary (Dictionary, a struct) is an unordered collection of object pairs. In each pair, the first object is the key; the second object is the value. The idea is that you use a key to access a value. Keys are usually strings, but they don’t have to be; the formal requirement is that they be types that adopt the Hashable protocol, meaning that they adopt Equatable and also have a hashValue property (an Int) such that two equal keys have equal hash values and two unequal keys do not. Thus, the hash values can be used behind the scenes for rapid key access. Swift numeric types, strings, and enums are Hashables. As with arrays, a given dictionary’s types must be uniform. The key type and the value type don’t have to be the same type, and they often will not be. But within any dictionary, all keys must be of the same type, and all values must be of the same type. Formally, a dictionary is a generic, and its placeholder types are ordered key type, then value type: Dictionary. As with arrays, however, Swift provides syntactic sugar for expressing a dictionary’s type, which is what you’ll usually use: [KeyType: Value- Collection Types | 217 Type]. That’s square brackets containing a colon (and optional spaces) separating the key type from the value type. This code creates an empty dictionary whose keys (when they exist) will be Strings and whose values (when they exist) will be Strings: var d = [String:String]() The colon is used also between each key and value in the literal syntax for expressing a dictionary. The key–value pairs appear between square brackets, separated by comma, just like an array. This code creates a dictionary by describing it literally (and the dic‐ tionary’s type of [String:String] is inferred): var d = ["CA": "California", "NY": "New York"] The literal for an empty dictionary is square brackets containing just a colon: [:]. This notation can be used provided the dictionary’s type is known in some other way. Thus, this is another way to create an empty [String:String] dictionary: var d : [String:String] = [:] If you try to fetch a value through a nonexistent key, there is no error, but Swift needs a way to report failure; therefore, it returns nil. This, in turn, implies that the value returned when you successfully access a value through a key must be an Optional wrap‐ ping the real value! It is also possible to access a dictionary’s pairs by index number. Each pair accessed in this way is a tuple consisting of a key and its corresponding value. Keep in mind, how‐ ever, that a dictionary is unordered! This means that there are no guarantees, and you should have no expectations, about the order in which successive index numbers will access key–value pairs. Moreover, the index numbers are not Ints; they are of a special DictionaryIndex type. Thus, this feature is rarely used explicitly (though it is used im‐ plicitly in enumerating a dictionary, as I’ll explain later). Access to a dictionary’s contents is usually by subscripting. To fetch a value by key, subscript the key to the dictionary reference: let d = ["CA": "California", "NY": "New York"] let state = d["CA"] Bear in mind, however, that after that code, state is not a String — it’s an Optional wrapping a String! Forgetting this is a common beginner mistake. If the reference to a dictionary is mutable, you can also assign into a key subscript expression. If the key already exists, its value is replaced. If the key doesn’t already exist, it is created and the value is attached to it: var d = ["CA": "California", "NY": "New York"] d["CA"] = "Casablanca" d["MD"] = "Maryland" // d is now ["MD": "Maryland", "NY": "New York", "CA": "Casablanca"] 218 | Chapter 4: Object Types Alternatively, call updateValue(forKey:); it has the advantage that it returns the old value wrapped in an Optional, or nil if the key wasn’t already present. By a kind of shorthand, assigning nil into a key subscript expression removes that key– value pair if it exists: var d = ["CA": "California", "NY": "New York"] d["NY"] = nil // d is now ["CA": "California"] Alternatively, call removeValueForKey; it has the advantage that it returns the removed value before it removes the key–value pair. The removed value is returned wrapped in an Optional, so a nil result tells you that this key was never in the dictionary to begin with. As with arrays, a dictionary type is legal for casting down with as!; typically, only the value types will differ: let dog1 : Dog = NoisyDog() let dog2 : Dog = NoisyDog() let d = ["fido": dog1, "rover": dog2] let d2 = d as! [String : NoisyDog] As with arrays, is can be used to test the actual types in the dictionary, and as? can be used to test and cast safely. Dictionary equality, like array equality, works as you would expect. Native utility methods involving dictionaries in Swift are disappointingly thin on the ground — in fact, there really aren’t any. Swift Dictionary is bridged to Cocoa NSDic‐ tionary — the intermediate Swift type, as I’ll explain in a moment, is [NSObject:Any- Object] — so you can drop into Cocoa in order to use NSDictionary methods. As with NSArray and NSMutableArray, if you want Cocoa to mutate a dictionary, you must coerce to NSMutableDictionary. In this example, I want to do a join between two dic‐ tionaries, so I harness the power of NSMutableDictionary, which has an addEntries- FromDictionary: method: var d1 = ["NY":"New York", "CA":"California"] let d2 = ["MD":"Maryland"] let mutd1 = NSMutableDictionary(dictionary:d1) mutd1.addEntriesFromDictionary(d2) d1 = mutd1 as [NSObject:AnyObject] as! [String:String] // d1 is now ["MD": "Maryland", "NY": "New York", "CA": "California"] That sort of thing is needed quite often. On the one hand, it’s annoying; on the other hand, Apple could reply that Cocoa and the Foundation framework are right there, so there’s no point duplicating in Swift the functionality that already exists in Foundation. If having to drop into Cocoa really bothers you, you can write your own library of replacement functions; for example, addEntriesFromDictionary: is easily reimple‐ mented as a Swift Dictionary instance method through an extension: Collection Types | 219 extension Dictionary { mutating func addEntriesFromDictionary(d:[Key:Value]) { for (k,v) in d { self[k] = v } } } (In that code, the Key and Value types are the placeholder types from the original generic Dictionary declaration; recall that these are in scope in an extension.) Basic dictionary properties and enumeration A dictionary has a count property reporting the number of key–value pairs it contains, and an isEmpty property reporting whether that number is 0. A dictionary has a keys property reporting all its keys, and a values property reporting all its values. They are effectively opaque structs (a LazyForwardCollection, if you must know), but you can enumerate them with for...in: var d = ["CA": "California", "NY": "New York"] for s in d.keys { println(s) } You can extract all a dictionary’s keys or values at once, with the keys or values prop‐ erty’s array property: var d = ["CA": "California", "NY": "New York"] var keys = d.keys.array You can also enumerate a dictionary itself. As you might expect from what I’ve already said, each iteration provides a key–value tuple: var d = ["CA": "California", "NY": "New York"] for (abbrev, state) in d { println("\(abbrev) stands for \(state)") } You can extract a dictionary’s entire contents at once as an array (of key–value tuples) by coercing the dictionary to an array: var d = ["CA": "California", "NY": "New York"] let arr = Array(d) // [("NY", "New York"), ("CA", "California")] A dictionary and its keys and values properties are all sequences. Thus, you can often operate directly on them without converting them to an array. For example, as I men‐ tioned earlier, there’s a global reduce function that generalizes the array reduce instance method; so if a dictionary d has Int values, you can sum them without converting d.values to an array first: let sum = reduce(d.values,0,+) 220 | Chapter 4: Object Types Swift Dictionary and Objective-C NSDictionary The Foundation framework dictionary type is NSDictionary, and Swift’s Dictionary type is bridged to it. Considerations for passing a dictionary across the bridge are parallel to those I’ve already discussed for arrays. The bridged API characterization of an NSDic‐ tionary will be [NSObject:AnyObject], using the Objective-C Foundation object base class for the keys; there are various reasons for this choice, but from Swift’s point of view the main one is that AnyObject is not a Hashable. NSObject, on the other hand, is extended by the Swift APIs to adopt Hashable; and since NSObject is the base class for Cocoa classes, any Cocoa class type will be Hashable. Thus, any NSDictionary can cross the bridge. The most common key type in a real-life Cocoa NSDictionary is NSString, which ac‐ cords with the fact that you’ll usually use String keys in a Swift dictionary. Unlike an array, however, dictionaries that you pass to and receive from Cocoa will very often have values of different types. It is not at all surprising to have a dictionary whose keys are strings but whose values include a string, a number, a color, and an array. For this reason, you will usually not cast down the entire dictionary’s type; instead, you’ll work with the dictionary as having AnyObject values, and cast when fetching an individual value from the dictionary. Since the value returned from subscripting a key is itself an Optional, you will typically unwrap and cast the value as a standard single move. Here’s an example. A Cocoa NSNotification object comes with a userInfo property. It is an NSDictionary that might itself be nil, so the Swift API characterizes it like this: var userInfo: [NSObject : AnyObject]? { get } Let’s say I’m expecting this dictionary to be present and to contain a "progress" key whose value is an NSNumber containing a Double. My goal is to extract that NSNumber and assign the Double that it contains to a property, self.progress. Here’s one way to do that safely, using optional unwrapping and optional casting (n is the NSNotification object): let prog = n.userInfo?["progress"] as? NSNumber if prog != nil { self.progress = prog!.doubleValue } That code is safe, because if there is no userInfo dictionary, or if it doesn’t contain a "progress" key, or if that key’s value isn’t an NSNumber, nothing happens. In Chap‐ ter 5 I’ll describe another syntax for accomplishing the same goal, arguably more legibly (using conditional binding). Finally, just for the sake of completeness, I’ll show a typical example of creating a dic‐ tionary and handing it off to Cocoa. This dictionary is a mixed bag: its values are a UIFont, a UIColor, and an NSShadow. Its keys are all strings, which I obtain as constants Collection Types | 221 from Cocoa. I form the dictionary as a literal and pass it, all in one move, with no need to cast anything: let shad = NSShadow() shad.shadowOffset = CGSizeMake(1.5,1.5) UINavigationBar.appearance().titleTextAttributes = [ NSFontAttributeName : UIFont(name: "ChalkboardSE-Bold", size: 20)!, NSForegroundColorAttributeName : UIColor.darkTextColor(), NSShadowAttributeName : shad ] Set A set (Set, a struct, new in Swift 1.2) is an unordered collection of unique objects. It is rather like the keys of a dictionary! Its elements must be all of one type; it has a count and an isEmpty property; it can be initialized from any sequence; you can cycle through its elements with for...in; you can even use subscripting with it (though you probably won’t, because it is indexed with SetIndex, not with Int). But the order of elements is not guaranteed, and you should make no assumptions about it. The uniqueness of set elements is implemented by constraining their type to adopt the Hashable protocol, just like the keys of a Dictionary. Thus, the hash values can be used behind the scenes for rapid access. Checking whether a set contains a given element, which you can do with the contains instance method, is very efficient — far more efficient than doing the same thing with an array. Therefore, if element uniqueness is acceptable (or desirable) and you don’t need indexing or a guaranteed order, a set can be a much better choice of collection than an array. There are no set literals in Swift, but you won’t need them because you can pass an array literal where a set is expected. There is no syntactic sugar for expressing a set type, but the Set struct is generic, so you can express the type by explicitly specializing the generic: let set : Set = [1, 2, 3, 4, 5] It sometimes happens (more often than you might suppose) that you want to examine one element of a set as a kind of sample. You won’t fetch the element by index, because order is meaningless; it’s sufficient to obtain any element, such as the first element. For this purpose, a first instance property is provided; it returns an Optional, just in case the set is empty and has no first element. The special and distinctive feature of a set is the uniqueness of its objects. If an object is added to a set and that object is already present, it isn’t added a second time. Con‐ version from an array to a set and back to an array is thus a quick and reliable way of uniquing the array — though of course order is not preserved: let arr = [1,2,1,3,2,4,3,5] let set = Set(arr) let arr2 = Array(set) // [5,2,3,1,4] perhaps 222 | Chapter 4: Object Types If the reference to a set is mutable, a number of instance methods spring to life. You can add an object with insert; if the object is already in the set, nothing happens, but there is no penalty. You can remove an object and return it by specifying the object itself (or something equatable to it), with the remove method; it returns nil if the object was not present. You can remove and return the first object (whatever “first” may mean) with removeFirst; it crashes if the set is empty, so take precautions. Equality comparison (==) is defined for sets as you would expect; two sets are equal if every element of each is also an element of the other. If the notion of a set brings to your mind visions of Venn diagrams from elementary school, that’s good, because sets have instance methods giving you all those set opera‐ tions you remember so fondly. The parameter can be a set, or it can be any sequence, which will be converted to a set; for example, it might an array, a range, or even a string: intersect, intersectInPlace Yields the elements of this set that also appear in the parameter. union, unionInPlace Yields the elements of this set along with the (unique) elements of the parameter. exclusiveOr, exclusiveOrInPlace Yields the elements of this set that don’t appear in the parameter, plus the (unique) elements of the parameter that don’t appear in this set. subtract, subtractInPlace Yields the elements of this set except for those that appear in the parameter. isSubsetOf, isStrictSubsetOf isSupersetOf, isStrictSupersetOf Returns a Bool reporting whether the elements of this set are respectively embraced by or embrace the elements of the parameter. The “strict” variant yields false if the two sets consist of the same elements. A set doesn’t have map, filter, and reduce instance methods, but it is a sequence, so it can be used with the global versions of those methods. The result is an array, but of course you can turn this right back into a set if you need to: let set : Set = [1,2,3,4,5] let set2 = Set(map(set) {$0+1}) // {6, 5, 2, 3, 4}, perhaps A Swift Set is bridged to an Objective-C NSSet. The medium of interchange is Set, because NSObject is seen as Hashable. Of course, the same rules apply as for arrays. An Objective-C NSSet expects its elements to be class instances, and Swift will help by bridging where it can. In real life, you’ll probably start with an array and coerce it to a set, as in this example from my own code: Collection Types | 223 let types : UIUserNotificationType = .Alert | .Sound let category = UIMutableUserNotificationCategory() category.identifier = "coffee" // ... let categories = Set([category]) let settings = // second parameter is an NSSet UIUserNotificationSettings(forTypes: types, categories: categories) Coming back from Objective-C, you’ll get a Set of NSObject and you’ll probably cast down as needed: override func touchesBegan( touches: Set, withEvent event: UIEvent) { let set = touches as! Set // ... } 224 | Chapter 4: Object Types CHAPTER 5 Flow Control and More This chapter presents the miscellaneous remaining aspects of the Swift language. I’ll start by describing the syntax of Swift’s flow control constructs for branching and loop‐ ing. Then I’ll talk about how to override operators and how to create your own operators. The chapter ends with a survey of Swift’s privacy and introspection features and some specialized modes of reference type memory management. Flow Control A computer program has a path of execution through its code statements. Normally, this path follows a simple rule: execute each statement in succession. But there is another possibility. Flow control can be used to make the path of execution skip some code statements, or repeat some code statements. Flow control is what makes a computer program “intelligent,” and not merely a simple fixed sequence of steps. By testing the truth value of a condition — an expression that evaluates to a Bool and is thus true or false — the program decides at that moment how to proceed. Flow control based on testing a condition may be divided into two general types: Branching The code is divided into alternative chunks, like roads that diverge in a wood, and the program is presented with a choice of possible ways to go: the truth of a con‐ dition is used to determine which chunk will actually be executed. A compact form of branching is conditional evaluation. In determining a value, such as the value to be assigned to a variable, the code is divided into two expres‐ sions: the truth of a condition is used to determine which expression will be eval‐ uated and used as the value. Looping A chunk of code is marked off for possible repetition: the truth of a condition is used to determine whether the chunk should be executed, and then whether it 225 should be executed again. Each repetition is called an iteration. Typically, some feature of the environment (such as the value of a variable) is changed on each iteration, so that the repetitions are not identical, but are successive stages in pro‐ gressing through an overall task. The chunks of code in flow control, which I refer to as blocks, are demarcated by curly braces. These curly braces constitute a scope. New local variables can be declared here, and go out of existence automatically when the path of execution exits the curly braces. For a loop, this means that local variables come into existence and go out of existence on each iteration. As with any scope, code inside the curly braces can see the surround‐ ing, higher scope. Swift flow control is fairly simple, and by and large is similar to flow control in C and related languages. There are two fundamental syntactic differences between Swift and C, both of which make Swift simpler and clearer: in Swift, a condition does not have to be wrapped in parentheses, and the curly braces can never be omitted. Moreover, Swift adds some specialized flow control features to help you grapple more conveniently with Optionals, and boasts a particularly powerful form of switch statement. Branching Swift has two forms of branching: the if construct, and the switch statement. Conditional evaluation is a compact form of if construct. If construct The Swift branching construct with if is similar to C. Many examples of if constructs have appeared already in this book. The construct may be formally summarized as shown in Example 5-1. Example 5-1. The Swift if construct if condition { statements } if condition { statements } else { statements } if condition { statements } else if condition { statements } else { statements } 226 | Chapter 5: Flow Control and More The third form, containing else if, can have as many else if blocks as needed, and the final else block may be omitted. Here’s a real-life if construct that lies at the heart of one of my apps: // okay, we've tapped a tile; there are three cases if self.selectedTile == nil { // no other selected tile: select and play self.selectTile(v) let url = v.layer.valueForKey("song") as! NSURL let item = AVPlayerItem(URL:url) self.player = AVPlayer(playerItem:item) self.player!.play() } else if self.selectedTile == v { // selected tile was tapped: deselect self.deselectAll() } else { // there was one selected tile and another was tapped: swap let v1 = self.selectedTile! self.selectedTile = nil let v2 = v self.swap(v1, with:v2, check:true, fence:true) } Conditional binding In Swift, if can be followed immediately by a variable declaration and assignment — that is, by let or var and a new local variable name, possibly followed by a colon and a type declaration, then an equal sign and a value. This syntax, called a conditional binding, is actually a shorthand for conditionally unwrapping an Optional. The assigned value is expected to be an Optional — the compiler will stop you if it isn’t — and this is what happens: • If the Optional is nil, the condition fails and the block is not executed. • If the Optional is not nil, then: 1. The Optional is unwrapped. 2. The unwrapped value is assigned to the declared local variable. 3. The block is executed with the local variable in scope. Thus, a conditional binding is a convenient shorthand for safely passing an unwrapped Optional into a block. The Optional is unwrapped, and the block is executed, only if the Optional can be unwrapped. It is perfectly reasonable and common for the local variable in a conditional binding to have the same name as an existing variable in the surrounding scope. It can even have the same name as the Optional being unwrapped! Indeed, giving the local variable the same name as the Optional is a good thing to do, because there is no need to make up Flow Control | 227 a new name, and inside the block the unwrapped value of the Optional overshadows the original Optional, which thus cannot be accessed accidentally. Here’s an example of a conditional binding. Recall this code from Chapter 4, where I optionally unwrap an NSNotification’s userInfo dictionary, attempt to fetch a value from the dictionary using the "progress" key, and proceed only if that value turns out to be an NSNumber: let prog = n.userInfo?["progress"] as? NSNumber if prog != nil { self.progress = prog!.doubleValue } I’ll rewrite that code with the help of conditional bindings. The result is somewhat more verbose and is rather deeply indented — Swift programmers like to call this the “pyramid of doom” — but in my view it is also considerably more legible, because the structure reflects perfectly the successive stages of testing: if let ui = n.userInfo { if let prog : AnyObject = ui["progress"] { if prog is NSNumber { self.progress = (prog as! NSNumber).doubleValue } } } In that example, we can actually eliminate one level of nesting, and in my real code, I would do so. Recall that the as? operator yields an Optional. This means that the result of the as? operator can be assigned into a conditional binding. Thus, we can safely unwrap and cast a value in a single move: if let ui = n.userInfo { if let prog = ui["progress"] as? NSNumber { self.progress = prog.doubleValue } } If an AnyObject is an NSNumber, you can cast all the way down from AnyObject to a Swift numeric type in a single move, avoiding any mention of NSNumber: if let ui = n.userInfo { if let prog = ui["progress"] as? Double { self.progress = prog } } New in Swift 1.2, the “pyramid of doom” can be flattened still further: successive con‐ ditional bindings can be combined into a list, separated by comma: if let ui = n.userInfo, prog = ui["progress"] as? Double { self.progress = prog } 228 | Chapter 5: Flow Control and More A binding in the list can even be followed by a where clause whose content can be any Bool expression at all, thus effectively folding yet another condition into the line. And the entire list can start with a condition, before the word let or var is encountered. Here’s a real-life example from my own code (which I’ll explain further in Chapter 11). Before the Swift 1.2 extended conditional binding syntax, I had four nested conditions: override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<()>) { if keyPath == "readyForDisplay" { if let obj = object as? AVPlayerViewController { if let ok = change[NSKeyValueChangeNewKey] as? Bool { if ok { // ... } } } } } With the extended conditional binding syntax, those four conditions can be combined into one: override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<()>) { if keyPath == "readyForDisplay", let obj = object as? AVPlayerViewController, let ok = change[NSKeyValueChangeNewKey] as? Bool where ok { // ... } } Switch statement A switch statement is a neater way of writing an extended if...else if...else con‐ struct. In C (and Objective-C), a switch statement contains hidden traps; Swift elimi‐ nates those traps, and adds power and flexibility. As a result, switch statements are commonly used in Swift (whereas they are relatively rare in my Objective-C code). In a switch statement, the condition consists in the comparison of different possible values, called cases, against a single value, called the tag. The case comparisons are performed successively in order. As soon as a case comparison succeeds, that case’s code is executed and the entire switch statement is exited. The schema is shown in Example 5-2; there can be as many cases as needed, and the default case can be omitted (subject to restrictions that I’ll explain in a moment). Flow Control | 229 Example 5-2. The Swift switch statement switch tag { case pattern1: statements case pattern2: statements default: statements } Here’s an actual example: switch i { case 1: println("You have 1 thingy!") case 2: println("You have 2 thingies!") default: println("You have \(i) thingies!") } In that code, a variable i functions as the tag. The value of i is first compared to the value 1. If it is 1, that case’s code is executed and that’s all. If it is not 1, it is compared to the value 2. If it is 2, that case’s code is executed and that’s all. If the value of i matches neither of those, the default case’s code is executed. In Swift, a switch statement must be exhaustive. This means that every possible value of the tag must be covered by a case. The compiler will stop you if you try to violate this rule. The rule makes intuitive sense when a value’s type allows only a limited number of possibilities; the usual example is an enum, which itself has a small, fixed set of cases as its possible values. But when, as in the preceding example, the tag is an Int, there is an infinite number of possible individual cases. Thus, a “mop-up” case must appear, to mop up all the cases that you didn’t write explicitly. A common way to write a “mop- up” case is to use a default case. Each case’s code can consist of multiple lines; it doesn’t have to be a single line, as the cases in the preceding example happen to be. However, it must consist of at least a single line; it is illegal for a Swift switch case to be completely empty. It is legal for the first (or only) line of a case’s code to appear on the same line as the case, after the colon; thus, I could have written the preceding example like this: switch i { case 1: println("You have 1 thingy!") case 2: println("You have 2 thingies!") default: println("You have \(i) thingies!") } The minimum single line of case code is the keyword break; used in this way, break acts as a placeholder meaning, “Do nothing.” It is very common for a switch statement 230 | Chapter 5: Flow Control and More to include a default (or other “mop-up” case) consisting of nothing but the keyword break; in this way, you exhaust all possible values of the tag, but if the value is one that no case explicitly covers, you do nothing. Now let’s focus on the comparison between the tag value and the case value. In the preceding example, it works like an equality comparison (==); but that isn’t the only possibility. In Swift, a case value is actually a special expression called a pattern, and the pattern is compared to the tag value using a “secret” pattern-matching operator, ~=. The more you know about the syntax for constructing a pattern, the more powerful your case values and your switch statements will be. A pattern can include an underscore (_) to absorb all values without using them. An underscore case is thus an alternative to a default case: switch i { case 1: println("You have 1 thingy!") case _: println("You have many thingies!") } A pattern can include a declaration of a local variable name (an unconditional binding) to absorb all values and use the actual value. This is another alternative to a default case: switch i { case 1: println("You have 1 thingy!") case let n: println("You have \(n) thingies!") } When the tag is a Comparable, a case can include a Range; the test involves sending the Range the contains message: switch i { case 1: println("You have 1 thingy!") case 2...10: println("You have \(i) thingies!") default: println("You have more thingies than I can count!") } When the tag is an Optional, a case can test it against nil. Thus, a possible way to unwrap an Optional safely is to test against nil first and then unwrap in a subsequent case, since we’ll never reach the unwrapping if the nil test succeeds. In this example, i is an Op‐ tional wrapping an Int: Flow Control | 231 switch i { case nil: break default: switch i! { case 1: println("You have 1 thingy!") case let n: println("You have \(n) thingies!") } } When the tag is a Bool, a case can test it against a condition. Thus, by a clever perversion, you can use the cases to test any conditions you like — by using true as the tag! A switch statement thus becomes a genuine substitute for an extended if...else if construct. In this example from my own code, I could have used if...else if, but each case is just one line, so a switch statement seems clearer: func positionForBar(bar: UIBarPositioning) -> UIBarPosition { switch true { case bar === self.navbar: return .TopAttached case bar === self.toolbar: return .Bottom default: return .Any } } In that code, we cannot accomplish the same thing by using bar as the tag, because the comparison would not be an === (identity) comparison. Using true as the tag solves the problem very neatly. A pattern can include a where clause adding a condition. This is often, though not necessarily, used in combination with a binding; the condition limits the truth value of the case, and can refer to the variable declared in the binding: switch i { case let j where j < 0: println("i is negative") case let j where j > 0: println("i is positive") case 0: println("i is 0") default:break } In that example, we don’t really need the binding at all; it was just to illustrate that the syntax works and that the binding is captured in the condition. We could just as well have used an underscore and involved the tag itself in the condition; this is an alternative to my switch true trick: 232 | Chapter 5: Flow Control and More switch i { case _ where i < 0: println("i is negative") case _ where i > 0: println("i is positive") case 0: println("i is 0") default:break } A pattern can include the is operator to test the tag’s type. In this example, assume that we have a Dog class and its NoisyDog subclass, and that d is typed as Dog: switch d { case is NoisyDog: println("You have a noisy dog!") case _: println("You have a dog.") } A pattern can include a cast with the as (not as?) operator. Typically, you’ll combine this with a binding that declares a local variable; despite the use of unconditional as, the value is conditionally cast and, if the cast succeeds, the local variable carries the cast value into the case code. Assume that Dog implements bark and that NoisyDog imple‐ ments beQuiet: switch d { case let nd as NoisyDog: nd.beQuiet() case let d: d.bark() } In that pattern, the tag can be an Optional. The as test is applied to the value wrapped inside the Optional, and the assignment to the local variable, if the test passes, unwraps the Optional. Thus, we can test the wrapped value’s type, unwrap the Optional, and assign the unwrapped value to a local variable, all in one move. Here is yet another rewrite of my code for fetching a value from an NSNotification’s userInfo dictionary: switch n.userInfo?["progress"] { case let prog as Double: self.progress = prog default:break } You can also use as (not as!) to cast down the tag (and possibly unwrap it) conditionally as part of a test against a specific match; in this example, i is an AnyObject: Flow Control | 233 switch i { case 0 as Int: println("It is 0") default:break } You can perform multiple tests at once by expressing the tag as a tuple and wrapping the corresponding tests in a tuple. The case passes only if every test in the test tuple succeeds against the corresponding member of the tag tuple. In this example, we start with a dictionary d that comes from Cocoa, so that it is typed as [NSObject:Any- Object]. Using a tuple, we can safely attempt to extract and cast two values at once: switch (d["size"], d["desc"]) { case let (size as Int, desc as String): println("You have size \(size) and it is \(desc)") default:break } When a tag is an enum, the cases can be cases of the enum. A switch statement is thus an excellent way to handle an enum. Here’s an enum: enum ListType { case Albums case Playlists case Podcasts case Books } And here’s a switch statement, where the tag, type, is a ListType: switch type { case .Albums: println("Albums") case .Playlists: println("Playlists") case .Podcasts: println("Podcasts") case .Books: println("Books") } No “mop-up” is needed, because I exhausted the cases. In that example, where the code is outside the enum’s own declaration, the dot before the case names is needed. But if the code is inside the enum’s declaration, the dot can be omitted: enum ListType : Printable { case Albums case Playlists case Podcasts case Books var description : String { switch self { case Albums: 234 | Chapter 5: Flow Control and More return "Albums" case Playlists: return "Playlists" case Podcasts: return "Podcasts" case Books: return "Books" } } } A switch statement is the only way to extract an associated value from an enum case. Recall this enum from Chapter 4: enum Error { case Number(Int) case Message(String) case Fatal } To extract the error number from an Error whose case is .Number, or the message string from an Error whose case is .Message, I have to use a switch statement. Recall that the associated value is actually a tuple. A tuple of patterns after the matched case name is applied to the associated value. If a pattern is a binding variable, it captures the associated value. The let (or var) can appear inside the parentheses or after the case keyword; this code illustrates both alternatives: switch err { case .Number(let theNumber): println("It is a .Number: \(theNumber)") case let .Message(theMessage): println("It is a .Message: \(theMessage)") case .Fatal: println("It is a .Fatal") } If the let (or var) appears after the case keyword, I can add a where clause: switch err { case let .Number(n) where n > 0: println("It's a positive error number \(n)") case let .Number(n) where n < 0: println("It's a negative error number \(n)") case .Number(0): println("It's a zero error number") default:break } If I don’t want to extract the error number but just want to match against it, I can use some other pattern inside the parentheses: Flow Control | 235 switch err { case .Number(1...Int.max): println("It's a positive error number") case .Number(Int.min...(-1)): println("It's a negative error number") case .Number(0): println("It's a zero error number") default:break } To combine case tests (with an implicit logical-or), separate them with a comma: switch i { case 1,3,5,7,9: println("You have a small odd number of thingies.") case 2,4,6,8,10: println("You have a small even number of thingies.") default: println("You have too many thingies for me to count.") } In this example, i is declared as an AnyObject: switch i { case is Int, is Double: println("It's some kind of number.") default: println("I don't know what it is.") } But you can’t use a comma to combine patterns that declare binding variables, presum‐ ably because it isn’t clear what variable should be set to what value. Another way of combining cases is to fall through from one case to the next by using a fallthrough statement. It is not uncommon for a case to consist entirely of a fallthrough statement, though it is perfectly legal for a case to execute some code and then fall through: switch pep { case "Manny": fallthrough case "Moe": fallthrough case "Jack": println("\(pep) is a Pep boy") default: println("I don't know who \(pep) is") } Note that fallthrough evades the test of the next case; it simply starts executing the next case’s code, directly. Therefore, the next case can’t declare any binding variables, because they would never be set. 236 | Chapter 5: Flow Control and More Conditional evaluation An interesting problem arises when you’d like to decide what value to use — for example, what value to assign to a variable. This seems like a good use of a branching construct. You can, of course, declare the variable first using var without initializing it, and then set it within a subsequent branching construct. It would be nice, however, to use a branching construct as the variable’s value. Here, for example, I try (and fail) to write a variable assignment where the equal sign is followed directly by a branching construct: let title = switch type { // compile error case .Albums: "Albums" case .Playlists: "Playlists" case .Podcasts: "Podcasts" case .Books: "Books" } There are languages that let you talk that way, but Swift is not one of them. However, an easy workaround does exist — use a define-and-call anonymous function: let title : String = { switch type { case .Albums: return "Albums" case .Playlists: return "Playlists" case .Podcasts: return "Podcasts" case .Books: return "Books" } }() In the special case where a value can be decided by a two-pronged condition, Swift provides the C ternary operator (:?). Its scheme is as follows: condition ? exp1 : exp2 If the condition is true, the expression exp1 is evaluated and the result is used; otherwise, the expression exp2 is evaluated and the result is used. Thus, you can use the ternary operator while performing an assignment, using this schema: let myVariable = condition ? exp1 : exp2 What myVariable gets initialized to depends on the truth value of the condition. I use the ternary operator heavily in my own code. Here’s an example: cell.accessoryType = ix.row == self.currow ? .Checkmark : .DisclosureIndicator Flow Control | 237 The context needn’t be an assignment; here, we’re deciding what value to pass as a function argument: CGContextSetFillColorWithColor( context, self.hilite ? purple.CGColor : beige.CGColor) In the version of C used by modern Objective-C, there’s a collapsed form of the ternary operator that allows you to test a value against nil. If it is nil, you get to supply a substitute value to be used. If it isn’t nil, the tested value itself is used. That’s a very common and convenient thing to do. In Swift, the analogous operation would involve testing an Optional: if the tested Op‐ tional is nil, use the substitute value; if it isn’t nil, unwrap the Optional and use the unwrapped value. Swift has such an operator — the ?? operator (called the nil- coalescing operator). Recall this example from Chapter 4, where arr is a Swift array of Optional strings and I’m converting it to a form that can be handed over to Objective-C as an NSArray: let arr2 : [AnyObject] = arr.map{if $0 == nil {return NSNull()} else {return $0!}} We can write the same thing much more neatly using the ternary operator: let arr2 = arr.map{ $0 == nil ? NSNull() : $0! } But the nil-coalescing operator is even neater: let arr2 = arr.map{ $0 ?? NSNull() } The as? operator yields an Optional, so it’s a great candidate for use with the ?? operator. Recall this example from Chapter 4: let arr2 : [String] = arr.map { if $0 is String { return $0 as! String } else { return "" } } That code is literally the inverse of the previous example: I’ve received from Cocoa an array of AnyObject, arr, which is a mixed bag of NSString and NSNull objects, and now I want to turn it into an array of String by substituting the empty string for all the NSNull objects. I promised I’d shorten that code; now I’ll do it: let arr2 = arr.map { $0 as? String ?? "" } Expressions using ?? can be chained: let someNumber = i1 as? Int ?? i2 as? Int ?? 0 238 | Chapter 5: Flow Control and More That code tries to cast i1 to an Int and use that Int. If that fails, it tries to cast i2 to an Int and use that Int. If that fails, it gives up and uses 0. Loops The usual purpose of a loop is to repeat a block of code with some simple difference on each iteration. This difference will typically serve also as a signal for when to stop the loop. Swift provides two basic loop structures: while loops and for loops. While loops A while loop comes in two forms, schematized in Example 5-3. Example 5-3. The Swift while loop while condition { statements } do { statements } while condition The chief difference between the two forms is the timing of test. In the second form, the condition is tested after the block has executed — meaning that the block will be executed at least once. Usually, the code inside the block will change something that alters both the environ‐ ment and the condition, thus eventually bringing the loop to an end. Here’s a typical example from my own code (movenda is an array): while self.movenda.count > 0 { let p = self.movenda.removeLast() // ... } Each iteration removes an element from movenda, so eventually its count falls to 0 and the loop is no longer executed; execution then proceeds to the next line after the closing curly braces. Another common use of while loops in my code is to walk my way up or down a hier‐ archy. In this example, I start with a subview (textField) of some table view cell, and I want to know which table view cell it is a subview of. So I keep walking up the view hierarchy, investigating each superview in turn, until I reach a table view cell: var v : UIView = textField do { v = v.superview! } while !(v is UITableViewCell) After that code, v is the desired table view cell. Flow Control | 239 The condition in the first form of while loop can be a conditional binding of an Optional. This provides a compact way of safely unwrapping an Optional and looping until the Optional is nil; the local variable containing the unwrapped Optional is in scope inside the curly braces. In this example, I walk up the view hierarchy until I reach the top — the first superview whose superview is nil: var vv : UIView = self.button while let v = vv.superview {vv = v} For loops A Swift for loop comes in two forms, as schematized in Example 5-4. Example 5-4. The Swift for loop for variable in sequence { statements } for before-all; condition; after-each { statements } The first form — the for...in construct — is similar to Objective-C’s for...in con‐ struct. In Objective-C, this syntax is available whenever a class conforms to the NSFast‐ Enumeration protocol. In Swift, it is available whenever a type adopts the SequenceType protocol. In the for...in construct, the variable is implicitly declared with let on each iteration; it is thus immutable. It is also local to the block. On each iteration, a successive element of the sequence is used to initialize the variable, which is then in scope inside block. This is the form of for loop you’ll use most often, especially because it is so easy in Swift to create a sequence on the fly if you don’t have one already. In C, for example, the way to iterate through the numbers 1 to 5 is to use the second form, and you can certainly do the same in Swift: for var i = 1; i < 6; i++ { println(i) } But in Swift, you can create a sequence of the numbers 1 through 5 on the fly — a Range — and that’s what you’ll usually do: for i in 1...5 { println(i) } A SequenceType has a generate method which yields a “generator” object which, itself, has a mutating next method that returns the next object in the sequence wrapped in an 240 | Chapter 5: Flow Control and More Optional, or nil if there is no next object. Under the hood, therefore, for...in is ac‐ tually a kind of while loop: var g = (1...5).generate() while let i = g.next() { println(i) } Sometimes you may find that writing out the while loop explicitly in that way makes the loop easier to control and to customize. You can also make your own object type adopt SequenceType; in that case, it, too, can be enumerated with for...in. This will rarely be necessary, however, and ex‐ plaining how to do it is outside the scope of this discussion. The sequence will often be an existing value. It might be a String, in which case the variable values are the successive Characters. It might be an array, in which case the variable values are the successive elements of the array. It might be a dictionary, in which case the variable values are a key–value tuple, and you will probably express the variable as a tuple of two names in order to capture them. Many examples have already appeared in earlier chapters. As I explained in Chapter 4, an array coming from Cocoa will usually need its elements cast down from AnyObject. It is quite typical to do this as part of the sequence specifi‐ cation: for v in self.boardView.subviews as [UIView] { v.removeFromSuperview() } The global enumerate method takes a sequence and yields a sequence of tuples preced‐ ing each element of the original sequence with its index number: for (i,v) in enumerate(self.tiles) { v.center = self.centers[i] } If the desired sequence is not a simple iteration — if, for example, you need to count backwards, or if you need to skip some values — you have two choices. One is to generate the sequence by calling the global stride function. It has two forms: • stride(from:through:by:) • stride(from:to:by:) Which form you use depends on whether you want the sequence to include the final value or not. The by: argument can be negative: Flow Control | 241 for i in stride(from: 10, through: 0, by: -2) { println(i) // 10, 8, 6, 4, 2, 0 } The other possibility is to feed a sequence to the global lazy function. Now you have something called a LazyRandomAccessCollection to which you can apply map, filter, and reverse instance methods, thus modifying the original sequence: let range = lazy(0...10).reverse().filter{$0 % 2 == 0} for i in range { println(i) // 10, 8, 6, 4, 2, 0 } You can cycle through two sequences simultaneously using the global zip function, which takes two sequences and yields a Zip2 struct, which is itself a sequence. The value on each iteration through a Zip2 is a tuple of the corresponding elements from both original sequences; if one of the original sequences is longer than the other, the extra elements are ignored: let arr1 = ["CA", "MD", "NY", "AZ"] let arr2 = ["California", "Maryland", "New York"] var d = [String:String]() for (s1,s2) in zip(arr1,arr2) { d[s1] = s2 } // now d is ["MD": "Maryland", "NY": "New York", "CA": "California"] The second form of for loop is a clone of the C for loop (refer to Example 5-4). The idea here is usually to increment or decrement a counter. The before-all statement is ex‐ ecuted 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 executed; the condition will usually test whether the counter has reached some limit. The after-each statement is then executed, and will usually increment or decrement 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 standard formula (if you’re going to use this kind of for loop) is: var i : Int for i = 1; i < 6; i++ { println(i) } To limit the scope of the counter to the inside of the curly braces, declare it as part of the before-all statement: for var i = 1; i < 6; i++ { println(i) } No law says that this kind of for loop must be about counting or incrementing. Recall this earlier example of a while loop, where we cycle up the view hierarchy looking for a table view cell: 242 | Chapter 5: Flow Control and More var v : UIView = textField do { v = v.superview! } while !(v is UITableViewCell) Here’s another way to express that, using a for loop whose block is empty: var v : UIView for v = textField; !(v is UITableViewCell); v = v.superview! {} As in C, each statement in the declaration (separated by semicolon) may consist, itself, of more than one code statement (separated by comma). This can be a handy, elegant way to clarify your intentions. In this example from my own code, I declare two variables in the before-all statement, and change both of them in the after-each statement; there are other ways to accomplish this same end, certainly, but this seems cleanest and clearest: var values = [0.0] for (var i = 20, direction = 1.0; i < 60; i += 5, direction *= -1) { values.append( direction * M_PI / Double(i) ) } Jumping The Swift language has no provision for full-fledged jumping from one location in code to another; there is no goto command (notoriously “considered harmful”). The Swift modes of jumping are all effectively ways of shortcircuiting the flow of branch and loop constructs: fallthrough A fallthrough statement in a switch case aborts execution of the current case code and immediately begins executing the code of the next case. There must be a next case or the compiler will stop you. continue A continue statement in a loop construct aborts execution of the current iteration and proceeds to the next iteration: • In a while loop, continue means to perform immediately the conditional test. • In a for loop of the first type (for...in), continue means to proceed imme‐ diately to the next iteration if there is one. • In a for loop of the second type (C for loop), continue means to perform immediately the after-each statement and then the conditional test. break A break statement aborts the current construct: • In a loop, break aborts the loop completely. • In the code of a switch case, break aborts the entire switch construct. Flow Control | 243 When constructs are nested, you may need to specify which construct you want to continue or break. Therefore, Swift permits you to put a label before the start of a switch statement, a while loop, or a for loop. The label is an arbitrary name followed by a colon. You can then use that label name as a second term in a continue or break statement within the labeled construct at any depth, to specify that this is the construct you are referring to. That will probably cover any real-life situation where you would have wished for a goto. Here’s an artifical example to illustrate the syntax. First, I’ll nest two for loops with no label: for i in 1...5 { for j in 1...5 { println("\(i), \(j);") break } } // 1, 1; 2, 1; 3, 1; 4, 1; 5, 1; As you can see from the output, that code keeps aborting the inner loop after one iteration, while the outer loop proceeds normally through all five iterations. But what if you wanted to abort the entire nested construct? The solution is a label: outer: for i in 1...5 { for j in 1...5 { println("\(i), \(j);") break outer } } // 1, 1; Aborting Aborting is an extreme form of flow control; the program stops dead in its tracks. In effect, you have deliberately crashed your own program. This is an unusual thing to do, but it can be useful as a way of raising a very red flag: you don’t really want to abort, so that if you do abort, things must be so bad that you’ve no choice. One way to abort is by calling the global function fatalError. It takes a String parameter permitting you to provide a message to appear in the console. I’ve already given this example: required init(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } That code says, in effect, that execution should never reach this point. We have no real implementation of init(coder:), and we do not expect to be initialized this way. If we 244 | Chapter 5: Flow Control and More are initialized this way, something has gone very wrong, and we want to crash, because our program has a serious bug. An initializer containing a fatalError call does not have to initialize any properties. This is because fatalError is declared with the @noreturn attribute, which causes to the compiler to abandon any contextual requirements. Similarly, a function that returns a value does not have to return any value if a fatalError call is encountered. You can also abort conditionally by calling the assert function. Its first parameter is a condition — something that evaluates as a Bool. If the condition is false, we will abort; the second parameter is a String message to appear in the console if we do abort. The idea here is that you are making a bet (an assertion) that the condition is true — a bet that you feel so strongly about that if the condition is false, there’s a serious bug in your program and you want to crash so you can learn of this bug and fix it. By default, assert works only when you’re developing your program. When your pro‐ gram is to be finalized and made public, you throw a different build switch, telling the compiler that assert should be ignored. In effect, the conditions in your assert calls are then disregarded; they are all seen as true. This means that you can safely leave assert calls in your code. By the time your program ships, of course, none of your assertions should be failing in any case; any bugs that caused them to fail should already have been ironed out. The disabling of assertions in shipping code is performed in an interesting way. The condition parameter is given an extra layer of indirection by declaring it as an @autoclosure function. This means that, even though the parameter is not in fact a function, the compiler will wrap it in a function; thus, the runtime needn’t call that function unless it has to. In shipping code, the runtime will not call that function. This mechanism averts expensive and unnecessary evaluation: an assert condition test may involve side effects, but the test won’t even be performed when assertions are turned off in your shipping program. Operators Swift operators such as + and > are not magically baked into the language. They are, in fact, functions; they are explicitly declared and implemented just like any other function. That is why, as I pointed out in Chapter 4, the term + can be passed as the last parameter in a reduce call; reduce expects a function taking two parameters and returning a value whose type matches that of the first parameter, and + is in fact the name of such a function. It also explains how Swift operators can be overloaded for different value types. You can use + with numbers, strings, or arrays — with a different meaning in each case — because two functions with the same name but different parameter types (different Operators | 245 signatures) are two different functions; from the parameter types, Swift is able to deter‐ mine which + function you are calling. These facts are not merely an intriguing behind-the-scenes implementation detail. They have practical implications for you and your code. You are free to overload existing operators to apply to your object types. You can even invent new operators! In this section, we’ll do both. First, we must talk about how operators are declared. Clearly there is some sort of syntactical hanky-panky (a technical computer science term), because you don’t call an operator function in the same way as a normal function. You don’t say +(1,2); you say 1+2. Even so, 1 and 2 in that second expression are the parameters to a + function call. How does Swift know that the + function uses this special syntax? To see the answer, look in the Swift header: infix operator + { associativity left precedence 140 } That is an operator declaration. An operator declaration announces that this symbol is an operator, and tells how many parameters it has and what the usage syntax will be in relation to those parameters. The really important part is the stuff before the curly braces: the keyword operator, preceded by an operator type — here, infix — and followed by the name of the operator. The types are: infix This operator takes two parameters and appears between them. prefix This operator takes one parameter and appears before it. postfix This operator takes one parameter and appears after it. An operator is also a function, so you also need a function declaration stating the type of the parameters and the result type of the function. Again, the Swift header shows us an example: func +(lhs: Int, rhs: Int) -> Int That is one of many declarations for the + function in the Swift header. In particular, it is the declaration for when the parameters are both Int. In that situation, the result is itself an Int. (The local parameter names lhs and rhs, which don’t affect the calling syntax, presumably mean “left-hand side” and “right-hand side.”) Both an operator declaration and its corresponding function declaration(s) must appear at top level. If the operator is a prefix or postfix operator, the function declaration 246 | Chapter 5: Flow Control and More must start with the word prefix or postfix; the default is infix and can therefore be omitted. We now know enough to override an operator to work with an object type of our own! As a simple example, imagine a Vial full of bacteria: struct Vial { var numberOfBacteria : Int init(_ n:Int) { self.numberOfBacteria = n } } When two Vials are combined, you get a Vial with all the bacteria from both of them. So the way to add two Vials is to add their bacteria: func +(lhs:Vial, rhs:Vial) -> Vial { let total = lhs.numberOfBacteria + rhs.numberOfBacteria return Vial(total) } And here’s code to test our new + operator override: let v1 = Vial(500_000) let v2 = Vial(400_000) let v3 = v1 + v2 println(v3.numberOfBacteria) // 900000 In the case of a compound assignment operator, the first parameter is the thing being assigned to. Therefore, to implement such an operator, the first parameter must be declared inout. Let’s do that for our Vial class: func +=(inout lhs:Vial, rhs:Vial) { let total = lhs.numberOfBacteria + rhs.numberOfBacteria lhs.numberOfBacteria = total } Here’s code to test our += override; Vial is a struct, so the first operand must be a mutable reference: var v1 = Vial(500_000) let v2 = Vial(400_000) v1 += v2 println(v1.numberOfBacteria) // 900000 It might be useful also to override the equality comparison operator == for our Vial class. This satisfies the requirement for Vial to adopt the Equatable protocol, but of course it won’t actually adopt it unless we tell it to: func ==(lhs:Vial, rhs:Vial) -> Bool { return lhs.numberOfBacteria == rhs.numberOfBacteria } extension Vial:Equatable{} Operators | 247 Now that Vial is an Equatable, it becomes a candidate for use with global functions such as find: let v1 = Vial(500_000) let v2 = Vial(400_000) let arr = [v1,v2] let ix = find(arr,v1) // Optional wrapping 0 What’s more, the complementary inequality operator != has sprung to life for Vials automatically! That’s because it’s already defined for any Equatable in terms of the == operator. By the same token, if we now override < for Vial and tell it to adopt Compa‐ rable, the other three comparison operators spring to life automatically. Next, let’s implement a completely new operator. As an example, I’ll inject an operator into Int that raises one number to the power of another. As my operator symbol, I’ll use ^^ (I’d like to use ^ but it’s already in use for something else). For simplicity, I’ll omit error-checking for edge cases (such as exponents less than 1): infix operator ^^ { } func ^^(lhs:Int, rhs:Int) -> Int { var result = lhs for _ in 1.. & | ^ ? ~ An operator name can also contain many other symbol characters (that is, characters that can’t be mistaken for some sort of alphanumeric) that are harder to type; see the manual for a formal list. Privacy Privacy (also known as access control) refers to the explicit modification of the normal scope rules. I gave an example in Chapter 1: 248 | Chapter 5: Flow Control and More class Dog { var name = "" private var whatADogSays = "woof" func bark() { println(self.whatADogSays) } func speak() { println(self.whatADogSays) } } The intention here is to limit how other objects can see the Dog property whatADog- Says. It is a private property, intended primarily for the Dog class’s own internal use: a Dog can speak of self.whatADogSays, but other objects should not be aware that it even exists. Swift has three levels of privacy: internal The default rule is that declarations are internal, meaning that they are globally visible to all code in all files within the containing module. That is why Swift files within the same module can see one another’s top-level contents automatically, with no effort on your part. (That’s different from C and Objective-C, where files can’t see each other at all unless you explicitly show them to one another through include or import statements.) private (narrower than internal) A thing declared private is visible only within its containing file. The formulation of this rule may not be quite what you were expecting from the notion of privacy. In some languages, private means private to an object declaration. In Swift, private is not as private as that; two classes in the same file can see one another even if both are declared private. This could be a good reason for breaking your code into multiple files, following the usual convention of one class per file. public (wider than internal) A thing declared public is visible even outside its containing module. Another mod‐ ule must first import this module before it can see anything at all. But once another module has imported this module, it still won’t be able to see anything in this module that hasn’t been explicitly declared public. If you don’t write any modules, you might never need to declare anything public. If you do write a module, you must declare something public, or your module is useless. Private Declaration By declaring object members private, you specify by inversion what the public API of this object is. Here’s an example from my own code: Privacy | 249 class CancelableTimer: NSObject { private var q = dispatch_queue_create("timer",nil) private var timer : dispatch_source_t! = nil private var firsttime = true private var once : Bool private var handler : () -> () init(once:Bool, handler:()->()) { // ... } func startWithInterval(interval:Double) { // ... } func cancel() { // ... } } The initializer init(once:handler:) and the startWithInterval: and cancel meth‐ ods, which are not marked private, are this class’s public API. They say, “Please feel free to call me!” The properties, however, are all private; no other code (that is, no code outside this file) can see them, either to get them or to set them. They are purely for the internal use of the methods of this class. They maintain state, but it is not a state that any other code needs to know about. Bear in mind that privacy can be restricted only to the level of the current file. For example: class Cat { private var secretName : String? = nil } class Dog { func nameCat(cat:Cat) { cat.secretName = "Lazybones" } } Why is that code legal? I said that a Cat’s secretName was private, so why is a Dog allowed to come along and change it? It’s because privacy is not at the level of the individual object type; it’s at the level of the file. I’ve defined Cat and Dog in the same file, so they (if you’ll pardon the expression) can see one another’s private members. It happens that a convenient real-life convention is to define each class in its own file. In fact, the file is very often named after the class that’s defined within it; a file containing the declaration for the ViewController class will typically be named View‐ Controller.swift. But there is no rule governing any of that. File names are not meaningful in Swift, and Swift files within the same module can all see inside one another auto‐ matically, without being told one another’s names. File names are mostly a convenience for the programmer: in Xcode, I see a list of my program’s files, so it’s helpful, when I 250 | Chapter 5: Flow Control and More want to find the declaration for the ViewController class, to see the name View‐ Controller.swift giving me a hint as to which file to look in. The formal reason for dividing your code into files is to make privacy work. Let’s say I have two files, Cat.swift and Dog.swift: // Cat.swift: class Cat { private var secretName : String? = nil } // Dog.swift: class Dog { func nameCat(cat:Cat) { cat.secretName = "Lazybones" // compile error } } Now that code won’t compile: the compiler says, “Cat does not have a member named secretName.” Cat does have a member named secretName, but not as far as code in a different file is concerned. And Dog now is in a different file, so privacy works. It may be that on some occasions you will want to draw a distinction between the privacy of a variable regarding setting and its privacy regarding getting. To draw this distinction, put the word get or set in parentheses after the privacy declaration to which it applies. Here’s an example from my code: private(set) var bitmapContext : CGContext! = nil That says: the setting of this variable is restricted to code within this same file. It says nothing about restricting the getting of this variable; other code in other files in this module can read this variable, but cannot write to it. (You can use this same syntax with a subscript function.) Public Declaration If you write a module, you’ll need to specify at least some object declarations as public, or code that imports your module won’t be able to see it. Other declarations that are not declared public are internal, meaning that they are private to the module. Thus, judicious use of public declarations configures the public API of your module. For example, in my Zotz app, which is a card game, the object types for creating and portraying cards and for combining them into a deck are bundled into a framework called ZotzDeck. Many of these types, such as Card and Deck, are declared public. Many utility object types, however, are not; the classes within the ZotzDeck module can see and use them, but code outside the module doesn’t need to be aware of them at all. For instance, to create a card, I have a factory class, CardFactory; it is not public, because a Deck of Cards comes into the hands of other code full-blown when Deck is initialized Privacy | 251 — the fact that a CardFactory class was used to assist in the process is a private imple‐ mentation detail. The members of a public object type are not, themselves, automatically public. If you want a method to be public, you have to declare it public. This is an excellent default behavior, because it means that these members are not shared outside the module unless you want them to be. (As Apple puts it, you must “opt in to publishing” object members.) For example, in the ZotzDeck module, the Card class is declared public but its initializer is not. Why? Because it doesn’t need to be. The way you (meaning the importer of the ZotzDeck module) get cards is by initializing a Deck; the initializer for Deck is declared public, so you can do that. There is never any reason to make a card independently of a Deck, and thanks to the privacy rules, you can’t. Privacy Rules It took time for Apple to add access control to Swift in the early months of the language’s release, mostly because the compiler had to be taught an extensive set of rules for en‐ suring that the privacy level of related things is coherent. For example: • A variable can’t be public if its type is private, because other code wouldn’t be able to use such a variable. • A public protocol’s members must be declared public when they are implemented by an adopter. • A subclass can’t be public unless the superclass is public. • A subclass can change an overridden member’s access level, but it cannot even see its superclass’s private members unless they are declared in the same file together. And so on. I could proceed to list all the rules, but I won’t. There is no need for me to enunciate them formally. They are spelled out in great detail in the Swift manual, which you can consult if you need to. In general, you probably won’t need to; they make in‐ tuitive sense, and you can rely on the compiler to help you with useful error messages if you violate one. For example, recall this code from Chapter 4: extension CGAffineTransform : Printable { public var description : String { return NSStringFromCGAffineTransform(self) } } Why do I declare description public? Because if I don’t, my code won’t compile. I’m extending a Cocoa type to adopt a Swift protocol. Swift and Cocoa are two different modules; their types are all public. I must declare this property public to carry it across 252 | Chapter 5: Flow Control and More the barrier between them, in accordance with the rule that a public protocol’s members must be declared public by the adopter. Introspection Swift provides limited ability to introspect an object — that is, to see the names and values of its properties. The Xcode debugger takes advantage of this to summarize an object in the Debug pane. In general, you probably won’t need to introspect any values directly; but this feature could be useful, for example, as a shortcut in implementing description. To introspect an object, pass it through the global reflect function. This returns a new object typed with the MirrorType protocol, which can be examined like an array: it has a count property and Int subscripts, each of which yields a tuple of a name and a Mir‐ rorType value. A MirrorType also has a summary string property, suitable for printing in the console. Here, for example, is the implementation of a Dog class with a simple description property that takes advantage of introspection. Instead of hard-coding a list of the class’s instance properties, we introspect the instance to obtain the names and values of the properties. This means that we can later add more properties without having to modify our description implementation: struct Dog : Printable { var name = "Fido" var license = 1 var description : String { var desc = "Dog:\n" var properties = reflect(self) for ix in 0 ..< properties.count { let (s,m) = properties[ix] desc.extend(s); desc.extend(" : ") desc.extend(m.summary); desc.extend("\n") } return desc } } If we now instantiate Dog and pass that instance to println, this is what we see in the console: Dog: name : Fido license : 1 Introspection | 253 Memory Management Swift memory management is handled automatically, and you will usually be unaware of it. Objects come into existence when they are instantiated and go out of existence as soon as they are no longer needed. Memory management of reference type objects, however, is quite tricky under the hood; I’ll devote Chapter 12 to a discussion of the underlying mechanism. Even for the Swift user, things can occasionally go wrong in this regard. (Value types do not require the sort of complex memory management that reference types do, so no memory management issues can arise for them.) Trouble typically arises when two class instances have references to one another. When that’s the case, you can have a retain cycle which will result in a memory leak, meaning that the two instances never go out of existence. Some computer languages solve this sort of problem with a periodic “garbage collection” phase that detects retain cycles and cleans them up, but Swift doesn’t do that; you have to fend off retain cycles manually. The way to test for and observe a memory leak is to implement a class’s deinit. This method is called when the instance goes out of existence. If the instance never goes out of existence, deinit is never called. That’s a bad sign, if you were expecting that the instance should go out of existence. Here’s an example. First, I’ll make two class instances and watch them go out of existence: func testRetainCycle() { class Dog { deinit { println("farewell from Dog") } } class Cat { deinit { println("farewell from Cat") } } let d = Dog() let c = Cat() } testRetainCycle() // farewell from Cat, farewell from Dog When we run that code, both “farewell” messages appear in the console. We created a Dog instance and a Cat instance, but the only references to them are automatic (local) variables inside the testRetainCycle function. When execution of that function’s body comes to an end, all automatic variables are destroyed; that is what it means to be an automatic variable. There are no other references to our Dog and Cat instances that might make them persist, and so they are destroyed in good order. Now I’ll change that code by giving the Dog and Cat objects references to each other: 254 | Chapter 5: Flow Control and More func testRetainCycle() { class Dog { var cat : Cat? = nil deinit { println("farewell from Dog") } } class Cat { var dog : Dog? = nil deinit { println("farewell from Cat") } } let d = Dog() let c = Cat() d.cat = c // create a... c.dog = d // ...retain cycle } testRetainCycle() // nothing in console When we run that code, neither “farewell” message appears in the console. The Dog and Cat objects have references to one another. Those are persisting references (also called strong references). A persisting reference sees to it that, for example, as long as our Dog has a reference to a particular Cat, that Cat will not be destroyed. That’s a good thing, and is a fundamental principle of sensible memory management. The bad thing is that the Dog and the Cat have persisting references to one another. That’s a retain cycle! Neither the Dog instance nor the Cat instance can be destroyed, because neither of them can “go first” — it’s like Alphonse and Gaston who can never get through the door because each requires the other to precede him. The Dog can’t be destroyed first because the Cat has a persisting reference to him, and the Cat can’t be destroyed first because the Dog has a persisting reference to him. These objects are therefore now leaking. Our code is over; both d and c are gone. There are no further references to either of these objects; neither object can ever be referred to again. No code can mention them; no code can reach them. But they live on, floating, useless, and taking up memory. Weak References One solution to a retain cycle is to mark the problematic reference as weak. This means that the reference is not a persisting reference. It is a weak reference. The object referred to can now go out of existence even while the referrer continues to exist. Of course, this presents a terrible danger, because now the object referred to may be destroyed behind the referrer’s back. But Swift has a solution for that, too: only an Optional reference can be marked as weak. That way, if the object referred to is destroyed behind the referrer’s back, the referrer will see something coherent, namely nil. Also, the reference must be a var reference, precisely because it can change spontaneously to nil. Memory Management | 255 Thus, this code breaks the retain cycle and prevents the memory leak: func testRetainCycle() { class Dog { weak var cat : Cat? = nil deinit { println("farewell from Dog") } } class Cat { weak var dog : Dog? = nil deinit { println("farewell from Cat") } } let d = Dog() let c = Cat() d.cat = c c.dog = d } testRetainCycle() // farewell from Cat, farewell from Dog I’ve gone overboard in that code. To break the retain cycle, there’s no need to make both Dog’s cat and Cat’s dog weak references; making just one of the two a weak reference is sufficient to break the cycle. That, in fact, is the usual solution when a retain cycle threatens. One of the pair will be more of an “owner” than the other; the one that is not the “owner” will have a weak reference to its “owner.” Although, as I mentioned earlier, value types are not subject to the same memory man‐ agement issues as reference types, a struct instance (which is a value type) can still be involved in a retain cycle with a class instance. In my retain cycle example, if Dog is a class and Cat is a struct, we still get a retain cycle. The solution is the same: make Cat’s dog a weak reference. (You can’t make Dog’s cat a weak reference, because Cat is a struct, and only references to a class type can be declared weak.) Do not use weak references unless you have to! Memory management is not to be toyed with lightly. Nevertheless, there are real-life situations in which weak references are the right thing to do, even when no retain cycle appears to threaten. For example, a view controller’s references to subviews of its own view are usually weak, because the view itself already has persisting references to those subviews, and we would not typically want those subviews to persist in the absence of the view itself: class HelpViewController: UIViewController { weak var wv : UIWebView? = nil override func viewWillAppear(animated: Bool) { super.viewWillAppear(animated) let wv = UIWebView(frame:self.view.bounds) // ... further configuration of wv here ... self.view.addSubview(wv) 256 | Chapter 5: Flow Control and More self.wv = wv } // ... } In that code, self.view.addSubview(wv) causes the UIWebView wv to persist; our own reference to it, self.wv, can thus be weak. Unowned References There’s another Swift solution for retain cycles. Instead of marking a reference as weak, you can mark it as unowned. This approach is useful in special cases where one object absolutely cannot exist without a reference to another, but where this reference need not be a persisting reference. For example, let’s pretend that a Boy may or may not have a Dog, but every Dog must have a Boy — and so I’ll give Dog an init(boy:) initializer. The Dog needs a reference to its Boy, and the Boy needs a reference to his Dog if he has one; that’s potentially a retain cycle: func testUnowned() { class Boy { var dog : Dog? = nil deinit { println("farewell from Boy") } } class Dog { let boy : Boy init(boy:Boy) { self.boy = boy } deinit { println("farewell from Dog") } } let b = Boy() let d = Dog(boy: b) b.dog = d } testUnowned() // nothing in console We can solve this by declaring Dog’s boy property unowned: func testUnowned() { class Boy { var dog : Dog? = nil deinit { println("farewell from Boy") } } class Dog { unowned let boy : Boy // * Memory Management | 257 init(boy:Boy) { self.boy = boy } deinit { println("farewell from Dog") } } let b = Boy() let d = Dog(boy: b) b.dog = d } testUnowned() // farewell from Boy, farewell from Dog An advantage of an unowned reference is that it doesn’t have to be an Optional — in fact, it cannot be an Optional — and it can be a constant (let). But an unowned reference is also dangerous, because the object referred to can go out of existence behind the refer‐ rer’s back, and an attempt to use that reference will cause a crash, as I can demonstrate by this rather forced code: var b = Optional(Boy()) let d = Dog(boy: b!) b = nil // destroy the Boy behind the Dog's back println(d.boy) // crash Thus, you should use unowned only if you are absolutely certain that the object referred to will outlive the referrer. Weak and Unowned References in Anonymous Functions A subtle variant of a retain cycle arises when an instance property’s value is a function referring to the instance: class FunctionHolder { var function : (Void -> Void)? = nil deinit { println("farewell from FunctionHolder") } } func testFunctionHolder() { let f = FunctionHolder() f.function = { println(f) } } testFunctionHolder() // nothing in console Oooops! I’ve created a retain cycle, by referring, inside the anonymous function, to the object that is holding a reference to it. Because functions are closures, f is captured by the anonymous function as a persisting reference. But the function property of Func‐ tionHolder is a persisting reference too, so that’s a retain cycle: f persistently refers to the function, which persistently refers to f. 258 | Chapter 5: Flow Control and More In this situation, I cannot break the retain cycle by declaring the function property as weak or unowned. Only a reference to a class type can be declared weak or unowned, and a function is not a class. Thus, I must declare the captured value f inside the anonymous function as weak or unowned instead. Swift provides an ingenious syntax for doing that. At the very start of the anonymous function body, where the in line would go (and before the in line if there is one), you put square brackets containing a comma-separated list of any problematic class type references that will be captured from the surrounding environment, each reference preceded by weak or unowned. This list is called a capture list. If you have a capture list, you must follow it by the keyword in if you are not already including the keyword in for other reasons. Thus: class FunctionHolder { var function : (Void -> Void)? = nil deinit { println("farewell from FunctionHolder") } } func testFunctionHolder() { let f = FunctionHolder() f.function = { [weak f] in println(f) } } testFunctionHolder() // farewell from FunctionHolder This syntax solves the problem. But marking a reference as weak in a capture list has a mild side effect that you will need to be aware of: such a reference passes into the anonymous function as an Optional. This is good, because it means that nothing bad can happen: if the object referred to goes out of existence behind our back, the value of the Optional is nil. But of course you must also adjust your code accordingly, unwrap‐ ping the Optional as needed in order to use it. The usual technique is to perform the weak–strong dance: you unwrap the Optional once, right at the start of the function, in a conditional binding, thus creating a new scope in which there is a normal (non- Optional) reference. Everything else in the anonymous function is embedded in that scope: class FunctionHolder { var function : (Void -> Void)? = nil deinit { println("farewell from FunctionHolder") } } func testFunctionHolder() { let f = FunctionHolder() f.function = { // here comes the weak–strong dance Memory Management | 259 [weak f] in // weak if let f = f { // strong println(f) } } } testFunctionHolder() // farewell from FunctionHolder The conditional binding let f = f accomplishes two goals. First, it unwraps the Op‐ tional version of f that arrived into the anonymous function. Second, it is a normal (strong) reference. So if the unwrapping succeeds, this new f will persist for the rest of the embedded scope. In that particular example, there is no way on earth that this FunctionHolder instance, f, can go out of existence while the anonymous function lives on. There are no other references to the anonymous function; it persists only as a property of f. Therefore I can avoid some behind-the-scenes bookkeeping overhead, as well as the weak–strong dance, by declaring f as unowned in my capture list instead. In real life, my own most frequent use of unowned is precisely in this context. Very often, the reference marked as unowned in the capture list will be self. Here’s an example from my own code: class MyDropBounceAndRollBehavior : UIDynamicBehavior { let v : UIView init(view v:UIView) { self.v = v super.init() } override func willMoveToAnimator(anim: UIDynamicAnimator!) { if anim == nil { return } let sup = self.v.superview! let grav = UIGravityBehavior() grav.action = { [unowned self] in let items = anim.itemsInRect(sup.bounds) as [UIView] if find(items, self.v) == nil { anim.removeBehavior(self) self.v.removeFromSuperview() } } self.addChildBehavior(grav) grav.addItem(self.v) // ... } // ... } There’s a potential (and rather elaborate) retain cycle here: self.addChild- Behavior(grav) causes a persistent reference to grav, grav has a persistent reference 260 | Chapter 5: Flow Control and More to grav.action, and the anonymous function assigned to grav.action refers to self. To break the retain cycle, I declare the reference to self as unowned in the anonymous function’s capture list. Memory Management of Protocol-Typed References Only a reference to an instance of a class type can be declared weak or unowned. A reference to an instance of a struct or enum type cannot be so declared, because its memory management doesn’t work the same way (and is not subject to retain cycles). A reference that is declared as a protocol type, therefore, has a problem. A protocol might be adopted by a struct or an enum. Therefore you cannot wantonly declare such a reference weak or unowned. You can only declare a protocol-typed reference weak or unowned if it is a class protocol — that is, if it is marked with @objc or class. In this code, SecondViewControllerDelegate is a protocol that I’ve declared. This code won’t compile unless SecondViewControllerDelegate is declared as a class protocol: class SecondViewController : UIViewController { weak var delegate : SecondViewControllerDelegate? // ... } Here’s the actual declaration of SecondViewControllerDelegate; it is declared as a class protocol, and that’s why the preceding code is legal: protocol SecondViewControllerDelegate : class { func acceptData(data:AnyObject!) } A protocol declared in Objective-C is implicitly marked as @objc and is a class protocol. Thus, this declaration from my real-life code is legal: weak var delegate : WKScriptMessageHandler? WKScriptMessageHandler is a protocol declared by Cocoa (in particular, by the Web Kit framework). Thus, it is implicitly marked @objc; only a class can adopt WKScript‐ MessageHandler, and so the compiler is satisfied that the delegate variable will be an instance of a class, and thus the reference can be treated as weak. Memory Management | 261 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 used 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 used in two ways. It’s the name of the application in which you edit and build your app, and it’s the name of an entire suite of utilities that accom‐ panies it — in the latter sense, Instruments and the Simulator are part of Xcode. This ambiguity should generally present little difficulty. 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 Over‐ view); 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. 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 find that it isn’t empty at all. 265 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 Xcode.app/Contents/ Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Templates/ Project Templates/iOS/Application. 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 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 throughout your project. You are not locked into the name of your project forever, though, and there’s a separate setting allowing you to change at any time the name of the app that it produces. I’ll talk later about name changes (“Renaming Parts of a Project” on page 304). 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. But do not use any other punc‐ tuation in your project name! Such punctuation can cause Xcode features to break in subtle ways. (For example, a question mark in a project name causes nib editor previews not to work.) 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 iden‐ tifying you or your company. 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. Every app on a device or submitted to the App Store needs a unique bundle identifier. 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; if you give every project a unique name within your personal world, the bundle identifier will uniquely iden‐ tify this project and the app that it produces (or you can change the bundle identifier manually later if necessary). 5. New in Xcode 6, the Language pop-up menu lets you choose between Swift and Objective-C. This choice is not positively binding; it dictates the initial structure 266 | Chapter 6: Anatomy of an Xcode Project and code of the project template, but you are free to add Swift files to an Objective- C project, or Objective-C files to a Swift project. You can even start with an Objective-C project and decide later to convert it completely to Swift. (See “Bilin‐ gual Targets” on page 305.) For now, choose Swift. 6. Make sure the Devices pop-up menu is set to iPhone. Again, this choice is not positively binding; but for now, let’s assume that our app is to run on iPhone only. 7. Make sure Use Core Data is not checked. Click Next. 8. 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/iOS/ 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. 9. 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. 10. 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 and destination in the project window’s toolbar are listed as Empty Window → iPhone 6. (The scheme and destination are actually pop-up menus, so you can click on them to change their values if needed.) Choose Product → Run. After some delay, the iOS Simulator application eventually opens and displays your app running. At first, you’ll see a launch screen displaying the name of the app (Empty Window). This will then fade to show our app’s actual interface — an empty white 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 wheth‐ er your code compiles and your project is consistently and correctly constructed, you’ll build the project (Product → Build). Alternatively, you can compile an indi‐ vidual file (choose Product → Perform Action → Compile [Filename]). 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 (Prod‐ uct → Run), which automatically builds first if necessary. New Project | 267 Figure 6-1. The project window 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 .storyboard or .xib files, graphically expressing interface objects to be instan‐ tiated as your app runs • Any resources, such as icons, images, or sound files, that are to be part of the app • All settings (instructions to the compiler, to the linker, and so on) that are to be obeyed as the app is built • Any frameworks that the code will need when it runs A single Xcode project window presents all of this information, as well as letting you access, edit, and navigate your code, plus reporting the progress and results of such procedures as building or debugging an app and more. This window displays a lot of information and embodies a lot of functionality! A project window is powerful and elaborate; learning to navigate and understand it takes time. Let’s pause to explore this window and see how it is constructed. A project window has four main parts (Figure 6-1): 1. On the left is the Navigator pane. Show and hide it with View → Navigators → Show/ Hide Navigator (Command-0) or with the first View button at the right end of the toolbar. 268 | Chapter 6: Anatomy of an Xcode Project 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 an Editor pane, and can display multiple Editor panes simultaneously. 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 View button at the right end of the toolbar. 4. At the bottom is the Debugger pane. Show and hide it with View → Show/Hide Debug Area (Command-Shift-Y) or with the second View button at the right end of 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 project window. Among other things, it’s your primary mechanism for controlling what you see in the main area of the project window (the editor). An important use pattern for Xcode is: you select something in the Navigator pane, and that thing is displayed in the editor. 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 eight different sets of information; thus, there are actually eight navigators. These are represented by the eight 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. 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: The Project Window | 269 Figure 6-2. The Project navigator 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.swift 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 navi‐ gator 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. Among other things, this can be useful for navigating your code. For example, highlight the first two icons in the filter bar (the first two are blue, the third is dark), and see how quickly you can reach the definition of AppDelegate’s applicationDidBecomeActive: method. 270 | Chapter 6: Anatomy of an Xcode Project Figure 6-3. The Search navigator 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. When the second filter bar is not highlighted, you are shown all symbols, in‐ cluding those defined by Swift and those defined by Cocoa (Figure 4-2). This is a great way to learn what object types exist, and to reach the headers where those types are declared (an important form of documentation: see Chapter 8). 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 Find → Find in Project (Command-Shift-F). The words above the search field show what options are currently in force; they are pop-up menus, so click one to change the options. Try searching for “delegate” (Figure 6-3). Click a search result to jump to it in your code. Below the search field, at the left, is the current search scope. This limits what files will be searched. Click it to see the Search Scopes panel. You can limit the search to a group (folder) within your project. You can also define a new scope: click New Scope to summon the scope configuration popover, where you can examine your options. Scopes are defined per user, not per project; scopes that you create here will appear in other projects. 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.) The Project Window | 271 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. Navigate (as you already know how to do, in at least three different ways) to the file App‐ Delegate.swift, and in the blank line after the last comment at the top of the file’s contents, above the import line, type howdy. Build the project (Command-B). The Issue navigator will display some error messages, showing that the compiler is un‐ able 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 (Command-Control-M). Now that you’ve made Xcode miserable, select “howdy” and delete it; save and build again, and your issues will be gone. If only real life were this easy! Test navigator (Command-5) This navigator lists test files and individual test methods and permits you to run your tests and see whether they succeeded or failed. A test is code that isn’t part of your app; rather, it calls a bit of your app’s code to see whether it behaves as expected. By default, a new project has one test file containing a couple of test methods to get you started. I’ll talk more about tests in Chapter 9. Debug navigator (Command-6) 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 Chapter 9). To see the Debug navigator in action, you’ll need to give your code a breakpoint. Navigate once more to the file AppDelegate.swift, select in the line that says return true, and choose Debug → Breakpoints → Add Breakpoint at Current Line to make a blue breakpoint arrow appear on that line. Run the project. 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 starts with four numeric and graphical displays of profiling information (CPU, Memory, Disk, and Network); click one to see extensive graph‐ ical information in the editor. This information allows you to track possible mis‐ behavior of your app as you run it, without the added complexity of running the Instruments utility (discussed in Chapter 9). To toggle the visibility of the profiling 272 | Chapter 6: Anatomy of an Xcode Project Figure 6-4. The Debug layout information at the top of the Debug navigator, click the “gauge” icon (to the right of the process’s name). The Debug navigator also displays the call stack, with the names of the nested methods in which a 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 first button in the filter bar at the bottom of the navigator. The second icon to the right of the process’s name lets you toggle between display by thread and display by queue. The Debug pane, which can be shown or hidden at will (View → Debug Area → Hide/Show Debug Area, or Command-Shift-Y), consists of two subpanes: The variables list (on the left) It is populated with the variables in scope for the selected method in the call stack. The console (on the right) Here the debugger displays text messages; that’s how you learn of exceptions thrown by your running app, plus you can have your code deliberately send you log messages describing your app’s progress and behavior. Such messages are important, so keep an eye on the console as your app runs. You can also use the console to enter commands to the debugger. This can often be a better way to explore values during a pause than the variables list. Either the variables list or the console can be hidden using the two buttons at the bottom right of the pane. The console can also be summoned by choosing View → Debug Area → Activate Console. The Project Window | 273 New in Xcode 6 is view debugging, which displays, and allows you to explore, your app’s view hierarchy. To switch to view debugging, choose Debug → View Debug‐ ging → Capture View Hierarchy (or click the Debug View Hierarchy button in the bar at the top of the Debug pane). Breakpoint navigator (Command-7) 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-8) This navigator lists your recent major actions, such as building or running (de‐ bugging) your project. Click a listing to see (in the editor) 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 console 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 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 Option-Shift-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 Navigation 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; if those settings can be changed, this is where you change them. 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 editing a .storyboard or .xib file (Chapter 7). But it can be useful also while editing code, because Quick Help, a form of documentation (Chapter 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 → 274 | Chapter 6: Anatomy of an Xcode Project Figure 6-5. Viewing a log Hide/Show Utilities (Command-Option-0). You can change the Utilities pane’s width by dragging the vertical line at its left edge. The Utilities pane consists of numerous palettes, which are clumped into multiple sets, which are themselves divided into two major groups: the top half of 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 four 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 because it displays documentation (Chapter 8). The File inspector consists of multiple sections, each of which can be expanded or collapsed by clicking its header. A .storyboard or .xib 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 Project Window | 275 the Connections inspector (Command-Option-6). These can consist of mul‐ tiple sections, each of which can be expanded or collapsed by clicking its header. An asset catalog is being edited In addition to the File inspector and Quick Help, the Attributes inspector lets you determine which variants of an image are listed, along with information about the selected image. The view hierarchy is being debugged In addition to the File inspector and Quick Help, the Object inspector describes the currently selected view, and the Size inspector displays the currently selected view’s size, position, and constraints. 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-Option- Control-4). The Object library is the most important; you’ll use it heavily when editing a .storyboard or .xib file. 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 .storyboard or .xib file (Chapter 7). The editor is the core of the project window. You can hide 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 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. 276 | Chapter 6: Anatomy of an Xcode Project The symbol at the left end of the jump bar (Control-1) summons a hierarchical menu (the Related Files menu) allowing navigation to files related to the current one. What appears here depends not only on what file is currently being edited but on the current selection within that file. This is an extremely powerful and convenient menu, and you should take time to explore it. You can navigate to related class files and header files (Superclasses, Subclasses, and Siblings; siblings are classes with the same superclass); you can view methods called by the currently selected method, and that call the currently selected method. The editor remembers the history of things it has displayed, and you can return to previously viewed content with the Back button in the jump bar, which is also a pop- up menu from which you can choose. Alternatively, choose Navigate → Go Back (Command-Control-Left). It is likely, as you develop a project, that you’ll want to edit more than one file simulta‐ neously, 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 win‐ dows. Assistants You can split the editor into multiple editors by summoning an assistant pane. To do so, click the second Editor button in the toolbar (“Show the Assistant editor”), or choose View → Assistant Editor → Show Assistant Editor (Command-Option- Return). 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 Editor button 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. You can determine how assistant panes are to be arranged. To do so, choose from the View → Assistant Editor submenu. I usually prefer All Editors Stacked Verti‐ cally, but it’s purely a matter of taste. 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 configure the tracking behavior of an assistant pane, use the first component in its jump bar (Control-4). This is the Tracking menu; it’s like the Related Files menu that I discussed a moment ago, but The Project Window | 277 selecting a category determines automatic tracking behavior. If a category has mul‐ tiple files, a pair of arrow buttons appears at the right end of the assistant’s jump bar, with which you can navigate between them (or use the second jump bar com‐ ponent, Control-5). You can turn off tracking by setting the assistant’s first jump bar component to Manual. If you want to close the assistant pane but continue to edit its contents without any assistant pane present, move the assistant pane’s contents to the main editor pane first (Navigate → Open In Primary Editor). 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 then 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. 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. Tabs and windows come in handy in connection with custom behaviors. For example, as I mentioned before, it’s important to be able to view the console while debugging; I like to see it at the full size of the project window, but I also want to be able to switch back to viewing my code. So I’ve created a custom behavior (click the Plus button at the bottom of the Behaviors pane of the Preferences window) that performs two actions: Show tab named Console in active window, and Show debugger with Console View. Moreover, I’ve given that behavior a keyboard shortcut. Thus at any time I can press my keyboard shortcut, and we switch to the Console tab (creating it if it doesn’t exist), 278 | Chapter 6: Anatomy of an Xcode Project Figure 6-6. The Project navigator and the project folder displaying nothing but the console. This is just a tab, so I can switch between it and my code with Command-Shift-}. There are many ways to change what appears in an editor, and the navigators don’t automatically stay in sync with those changes. To select in the Project nav‐ igator the file displayed in the current editor, choose Navigate → Reveal in Project Navigator. There are also Navigate menu items Reveal in Symbol Navigator and Reveal in Debug Navigator. The Project File and Its Dependents The first item in the Project navigator (Command-1) represents the project itself. (In the Empty Window project that we created earlier in this chapter, it is called Empty Window.) Hierarchically dependent upon it are items that contribute to the building of the project. Many of these items, as well as the project itself, correspond to items on disk in the project folder. To survey this correspondence, let’s examine the project folder in the Finder simulta‐ neously with the Xcode project window. Select the project listing in the Project navigator and choose File → Show in Finder (Figure 6-6). The Finder displays the contents of your project folder. The most important of these is Empty Window.xcodeproj. This is the project file, corresponding to the project listed in the Project navigator. 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. Alternatively, you can drag the project folder onto Xcode’s The Project File and Its Dependents | 279 icon (in the Finder, in the Dock, or in the application switcher) and Xcode will locate the project file and open it for you; thus, you might never need to open the project folder at all! Never, never, never touch anything in a project folder by way of the Finder, ex‐ cept for double-clicking the project file to open the project. Don’t put anything directly into a project folder. Don’t remove anything 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.) 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, be‐ hind the project’s back, you can upset those expectations and break the project. When you work in the project window, it is Xcode itself that makes any necessa‐ ry changes in the project folder, and all will be well. Let’s consider how the groups and files displayed hierarchically down from the project in the Project navigator correspond to reality on disk as portrayed in the Finder (Figure 6-6). Recall that group is the technical term for the folder-like objects shown in the Project navigator. 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 corre‐ spond to groups in the Project navigator: • The Empty Window group corresponds directly to the Empty Window folder on disk. Files within the Empty Window group, such as AppDelegate.swift, correspond to real files on disk that are inside the Empty Window folder. If you were to create additional code 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, and they, too, would then be in the Empty Window folder on disk. (That, however, is not a requirement; your files can live anywhere and your project will still work fine.) Similarly, the Empty WindowTests group corresponds to the Empty WindowTests folder on disk, and the file Empty_WindowTests.swift listed inside the Empty Win‐ dowTests group lives inside the Empty WindowTests folder. These two group–folder pairs correspond to the two targets of your project. I’ll talk in the next section about what a target is. There is no law requiring that a target have a corresponding group in the Project navigator and a corresponding folder in the project folder, but the project template sets things up that way as an organiza‐ tional convenience: it clarifies the project’s structure in the Project navigator, and it prevents a lot of files from appearing at the top level of the project folder. 280 | Chapter 6: Anatomy of an Xcode Project • The Supporting Files group inside the Empty Window 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. Things inside this group are real, however; you can see that the file Info.plist does exist on disk — it’s just not inside anything called Supporting Files. (The Sup‐ porting Files group inside the Empty WindowTests group is similar.) • Two files in the Empty Window group, Main.storyboard and LaunchScreen.xib, ap‐ pear in the Finder inside a folder that doesn’t visibly correspond to anything in the Project navigator, called Base.lproj. This arrangement has to do with localization, which I’ll discuss in Chapter 9. • The item Images.xcassets in the Project navigator corresponds to a specially struc‐ tured folder Images.xcassets on disk. This is an asset catalog; you add images to the asset catalog in Xcode, which maintains that folder on disk for you. This makes it easy for you to have multiple related images, such as app icons of different sizes, without having to see them all listed directly in the Project navigator. I’ll talk more about the asset catalog later in this chapter, and 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. You’ve seen it; you know that it has contents; you know that they bear some relationship to the Project navigator; now forget about them. Keep your attention on the Project navigator, make your mod‐ ifications to the project there, and all will be well. Feel free, as you develop your project and add files to it, to add further groups to the Project navigator. The purpose of groups is to make the Project navigator work well for you! They don’t affect how the app is built, and by default they don’t correspond to any folder on disk; they are just an organizational convenience within the Project navigator. 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. For example, if some of your code files have to do with a login screen that your app sometimes presents, you might clump them together in a Login group. If your app is to contain some sound files, you might put them into a Sounds group. And so on. The things in the Products group don’t correspond to anything in the project folder. Xcode generates a reference to the executable bundle generated by building each target in your project, and by convention these references appear in the Products group. Another conventional group is the Frameworks group, listing frameworks on which your code depends. Your code does depend on some frameworks, but by default they are not listed in the Project navigator, and the Project navigator has no Frameworks group, because these frameworks are not explicitly linked into your build; instead, your code uses modules, which means that the import statements at the top of your files are sufficient to cause linkage to take place implicitly. However, if you were to link explic‐ The Project File and Its Dependents | 281 itly to a framework, it would be listed in the Project navigator, and you might then create a Frameworks group, just to give that listing a nice place to live. I’ll discuss frameworks later in this chapter. The Target A target is a collection of parts along with rules and settings for how to build a product from them. Whenever you build, what you’re really building is a target (possibly more than one 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. Our Empty Window project comes with two targets: the app target, called Empty Window (just like the project itself), and the tests target, called Empty WindowTests. Under certain circumstances, you might add further targets to a project. For example, new in Xcode 6 and iOS 8, you can write a framework as part of your iOS app; with a custom framework, you can factor common code into a single locus, and you can con‐ figure its privacy details as a namespace. A custom framework needs to be built, so it, too, is a target. Also new to Xcode 6 and iOS 8 are application extensions, such as today extensions (content to appear in the notification center) and photo editing extensions (custom photo editing interface to appear in the Photos app). These, too, are targets. The project name and the list of targets can appear in two ways (Figure 6-7): either as a column on the left side of the editor, or, if that column is collapsed to save space, as a pop-up menu at the top left of the editor. If, in the column or pop-up menu, you select the project, you edit the project; if you select a target, you edit the target. I’ll use those expressions a lot in later instructions. Let’s concentrate on the app target, Empty Window. This is the target that you use to build and run your app. Its settings are the settings that tell Xcode how your app is to be built; its product is the app itself. (The tests target, Empty WindowTests, creates a special executable whose purpose is to test your app’s code. I’ll talk more about testing in Chapter 9.) Build Phases Edit the Empty Window target and click Build Phases at the top of the editor (Figure 6-8). These are the stages by which your app is built. 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. Click each build phase to see a list of the files in your target to which that build phase will apply. 282 | Chapter 6: Anatomy of an Xcode Project Figure 6-7. Two ways of showing the project and targets Figure 6-8. The app target’s build phases Two of the build phases have contents. The meanings of these build phases are pretty straightforward: Compile Sources Certain files (your code) are compiled, and the resulting compiled code is copied into the app. This build phase typically applies to all of the target’s .swift files; those are the code files that constitute the target. Sure enough, it currently contains View‐ The Target | 283 Controller.swift and AppDelegate.swift. If you add a new Swift file to your project (typically in order to declare another class), you’ll specify that it should be part of the app target, and it will automatically be added to the Compile Sources build phase. 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. This build phase currently applies to the asset catalog; any images you add to the asset catalog will be copied into your app as part of the catalog. It also currently lists your launch nib file, LaunchScreen.xib, and your app’s .storyboard file. Copying doesn’t necessarily mean making an identical copy. Certain types of file are automatically treated in special ways as they are copied into the app bundle. For example, copying the asset catalog means that icons in the catalog are written out to the top level of the app bundle, and the asset catalog itself is transformed into a .car file; copying the .storyboard file means that it is transformed into a .story‐ boardc file, which is itself a bundle containing nib files. You can alter these lists manually, and sometimes you may need to do so. For instance, if something in your project, such as a sound file, 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. Conversely, if something in your project was in Copy Bundle Resources and you didn’t want it copied into 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. It is possible that you might need to alter the Link Binary With Libraries build phase. Certain libraries, usually frameworks, are linked to the compiled code (now referred to, following compilation, as the binary), thus telling your code to expect those libraries to be present on the device when the app runs. Our Empty Window project does link to some frameworks, but it doesn’t use this build phase to do it; instead, it imports the frameworks as modules and the frameworks are linked automatically. However, in some cases you would need to link the binary with additional frameworks explicitly; I’ll talk about that later in this chapter. A useful trick is to add a Run Script build phase, which runs a custom shell script late in the build process. To do so, choose Editor → Add Build Phase → Add Run Script Build Phase. Open the newly added Run Script build phase to edit the custom shell script. A minimal shell script might read: echo "Running the Run Script build phase" 284 | Chapter 6: Anatomy of an Xcode Project Figure 6-9. Target build settings The “Show environment variables in build log” checkbox causes the build process’s environment variables and their values to be listed in the build log during the Run Script build phase. This alone can be a reason to add a Run Script build phase; you can learn a lot about how the build process works by examining the environment variables. 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 of the editor (Figure 6-9). 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-9, 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 The Target | 285 (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. 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. You can change a value at the project level or at the target level. You can select a build setting and show Quick Help in the Utilities pane to learn more about it. For further details on what the various build settings are, consult Apple’s documen‐ tation, especially the Xcode Build Setting Reference. Configurations There are actually multiple lists of build setting values — though only one such list applies when a particular 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, and for archiving the app to be submitted to the App Store. 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-10). 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-9) and type “Optim” into the search field. Now you can look at the Optimization Level build setting (Figure 6-11). 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 con‐ figuration, 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. 286 | Chapter 6: Anatomy of an Xcode Project Figure 6-10. Configurations Figure 6-11. How configurations affect build settings Schemes and Destinations So far, I have not said how Xcode knows which configuration to use during a particular build. This is 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. Thus the Empty Window project’s single scheme is currently called Empty Window. To see it, choose Product → Scheme → Edit Scheme. The scheme editor dialog opens. 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 com‐ mon to all of them — the other actions all implicitly involve building. The Build action merely determines what target(s) will be built when each of the other actions is per‐ formed. For our project this means that the app target is always to be built, regardless of the action you perform. The Target | 287 Figure 6-12. The scheme editor Figure 6-13. The Scheme pop-up menu The second action, the Run action, determines the settings that will be used when you build and run (Figure 6-12). The Build Configuration pop-up menu is set to Debug. That explains where the current build configuration comes from: at the moment, when‐ ever you build and run (Product → Run, or click the Run button in the toolbar), 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. You can edit an existing scheme, though it is not likely that you would need to do so. Another possibility is that you might create an additional scheme. One way to do this is by choosing Manage Schemes from the Scheme pop-up menu in the project window toolbar. Your schemes are all listed in this pop-up menu (Figure 6-13), and thus you can easily switch between them before you build and run. 288 | Chapter 6: Anatomy of an Xcode Project Hierarchically appended to each scheme listed in the Scheme pop-up menu are the destinations. A destination is effectively a machine that can run your app. On any given occasion, you might want to run the app on a physical device or in the Simulator — and, if in the Simulator, you might want to specify that a particular type of device should be simulated. To make that choice, pick a destination in the Scheme pop-up menu. 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 pop- up menu to choose either a scheme or a destination, or both, in a single move. To switch easily among destinations without changing schemes, click the destination name in the Scheme pop-up menu. To switch among schemes, possibly also determining the desti‐ nation (as shown in Figure 6-13), click the scheme name in the Scheme pop-up menu. You can also switch among schemes or among destinations by using the scheme editor or the Product menu. Each simulated device has a system version that is installed on that device. At the mo‐ ment, all our simulated devices are running iOS 8.3; thus, there is no distinction to be drawn, and the system version is not shown. However, you can download additional SDKs (systems) in Xcode’s Downloads preference pane. If you do, and if your app can run under more than one system version, you might also see a system version listed in the Scheme pop-up menu as part of a Simulator destination name. For example, if your project’s deployment target (see Chapter 9) is 7.1, the Scheme pop-up menu in the project window toolbar might say “iOS 8.3” or “iOS 7.1” after the destination name. (I’ll discuss SDKs further at the end of this chapter.) If you have downloaded additional SDKs, and if your app is configured to run on multiple systems, and you still don’t see, among the destinations, any simulated devices with those systems, choose Window → Device to summon the Devices window. This is where you manage what simulated devices exist. Here you can create, delete, and rename simulated devices, and specify whether a simulated de‐ vice actually appears as a destination in the Scheme pop-up menu. From Project to Running 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. From Project to Running App | 289 Figure 6-14. The built app, in the Finder Figure 6-15. Contents of the app package 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. In the Finder, Control-click the Empty Window app, and choose Show Package Contents from the contextual menu. Here you can see the results of the build process (Figure 6-15). 290 | Chapter 6: Anatomy of an Xcode Project Think of the app bundle as a transformation of the project folder: Empty Window Our app’s compiled code. The build process has compiled ViewController.swift and AppDelegate.swift into this single file, our app’s binary. This is the heart of the app, its actual executable material. When the app is launched, the binary is linked to the various frameworks, and the code begins to run. (Later in this chapter, I’ll explain in detail what “begins to run” involves.) Main.storyboardc Our app’s storyboard file. The project’s Main.storyboard is where our app’s interface comes from — in this case, an empty white view occupying the entire window. The build process has compiled Main.storyboard (using the ibtool command-line tool) into a tighter format, resulting in a .storyboardc file, which is actually a bundle of nib files to be loaded as required while the app runs. One of these nib files, loaded as our app launches, will be the source of the white view displayed in the interface. Main.storyboardc occupies the same subfolder location (inside Base.lproj) as Main.storyboard does in the project folder; as I said earlier, this folder structure has to do with localization (to be discussed in Chapter 9). Assets.car and AppIcon60x60.png An asset catalog and a pair of icon files. In preparation for this build, I added some icon images and some other image resources to the original asset catalog, Images.xcassets. This file has been processed (using the actool command-line tool), resulting in a compiled asset catalog file (.car) containing any images that have been added to the catalog. At the same time, the icon files have been written out to the top level of the app bundle, where the system can find them. Info.plist A configuration file in a strict text format (a property list file). It is derived from, but is not identical to, the project’s Info.plist. It contains instructions to the system about how to treat and launch the app. For example, the project’s Info.plist has a calculated bundle name derived from the product name, $(PRODUCT_NAME); in the built app’s Info.plist, this calculation has been performed, and the value reads Empty Window. Also, in conjunction with the asset catalog writing out our icon files to the app bundle’s top level, a setting has been added to the built app’s Info.plist telling the system the name of those icon files. Frameworks Nine frameworks have been added to the built app. Our app uses Swift; these frameworks contain the entirety of the Swift language! Other frameworks used by our app are built into the system, but not Swift. This packaging of the Swift frame‐ works into the app bundle permits Apple to evolve the Swift language rapidly and independently of any system version, and allows Swift to be backward compatible to iOS 7. The downside is that these frameworks add about 5 MB to the size of our From Project to Running App | 291 app; but this is a small price to pay for the power and flexibility of Swift. (Perhaps in the future, when the Swift language has settled down, it will be built into the system instead of the individual app, and Swift-based apps will become smaller.) 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. In real life, an app bundle may contain more files, but the difference will be mostly one of degree, not kind. For example, our project might have additional .storyboard or .xib files, additional frameworks, or additional resources such as sound files. All of these would make their way into the app bundle. In addition, an app bundle built to run on a device will contain some security-related files. You are now in a position to appreciate, in a general sense, how the components of a 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 section outlines what goes into the building of an app from a project, as well as how the con‐ stituents of that app are used at launch time to get the app up and running. 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 specified a scheme; the scheme determines the build configuration, meaning 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 file in the project does not have to be named Info.plist! The app 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 app target’s Info.plist File build setting has been set to Empty Window/Info.plist. (Take a look at the build settings and see!) The property list file is a collection of key–value pairs. You can edit it, and you may need to do so. There are three 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: click in the editor and then choose Editor → Show Raw Keys & Values, or use the contextual menu. 292 | Chapter 6: Anatomy of an Xcode Project In addition, you can see and edit the Info.plist file in its true XML form: Control- click the Info.plist file in the Project navigator and choose Open As → Source Code from the contextual menu. (But editing an Info.plist as raw XML is risky, because if you make a mistake you can invalidate the XML, causing things to break with no warning.) • Edit the target, and click Info at the top of the editor. The Custom iOS Target Properties section shows effectively the same information as editing the Info.plist in the editor. • Edit the target, and click General at the top of the editor. Some of the settings here are effectively ways of editing the Info.plist. For example, when you click a Device Orientation checkbox here, you are changing the value of the “Supported interface orientations” key in the Info.plist. (Other settings here are effectively ways of editing build settings. For example, when you change the Deployment Target here, you are changing the value of the iOS Deployment Target build setting.) Some values in the project’s Info.plist are processed to transform them into their final values in the built app’s Info.plist. This step is performed late in the build process. For example, the “Executable file” key’s value in the project’s Info.plist is $(EXECUTABLE_NAME); for this will be substituted the value of the EXECUTABLE_NAME build environment variable (which, as I mentioned earlier, you can discover by means of a Run Script build phase). Also, some additional key–value pairs are injected into the Info.plist during processing. For a complete list of the possible keys and their meanings, consult Apple’s document Information Property List Key Reference. I’ll talk more in Chapter 9 about Info.plist settings that you’re particularly likely to edit. Nib Files A nib file is a description of a piece of user interface in a compiled format contained in a file with the extension .nib. Every app that you write is likely to contain at least one nib file. You prepare these nib files by editing a .storyboard or .xib file graphically in Xcode; in effect, you are designing some objects that you want instantiated when the app runs and the nib file loads. A nib file is generated during the build process by compilation (using the ibtool command-line tool) either from a .xib file, which results in a single nib file, or from a .storyboard file, which results in a .storyboardc bundle containing multiple nib files. This compilation takes place by virtue of the .storyboard or .xib file being listed in the app target’s Copy Bundle Resources build phase. Our Empty Window project generated from the Single View Application template con‐ tains a single .storyboard file, called Main.storyboard. This one file is subject to special treatment as the app’s main storyboard, not because of its name, but because it is pointed From Project to Running App | 293 Figure 6-16. Options when adding a resource to a project to in the Info.plist file by the key “Main storyboard file base name” (UIMainStoryboard- File), using its name (“Main”) without the .storyboard extension — edit the Info.plist file and see! The result is that as the app launches, the first nib generated from this .storyboard file is loaded automatically to help create the app’s initial interface. I’ll talk more about the app launch process and the main storyboard later in this chapter. See Chapter 7 for more about editing .storyboard and .xib files and how they create instances when your code runs. Additional Resources Resources are ancillary files embedded in your app bundle, to be fetched as needed when the app runs, such as images you want to display or sounds you want to play. A real-life app is likely to involve many such additional resources. You’ll add these resources to the project, ensuring that they appear in the Copy Bundle Resources build phase. Mak‐ ing such resources available when your app runs will usually be up to your code (or to the code implied by the loading of a nib file): basically, the runtime simply reaches into your app bundle and pulls out the desired resource. In effect, your app bundle is being treated as a folder full of extra stuff. To add a resource to your project, start in the Project navigator and choose File → Add Files to [Project], or drag the resource from the Finder into the Project navigator. A dialog appears (Figure 6-16) in which you make the following settings: Destination You should almost certainly check this checkbox (“Copy items if needed”). 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, where you might delete or change it unintentionally. Keeping everything your project needs inside the project folder is far safer. Added folders This choice matters only if what you’re adding to the project is a folder; the differ‐ ence is in how the project references the folder contents: 294 | Chapter 6: Anatomy of an Xcode Project Create groups The folder name becomes the name of an ordinary group within the Project navigator; the folder contents appear in this group, but they are listed individ‐ ually in the Copy Bundle Resources build phase, so by default they will all be copied individually into the top level of the app bundle. Create folder references The folder is shown in blue in the Project navigator (a folder reference); more‐ over, it is listed as a folder in the Copy Bundle Resources build phase, meaning that 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 app bundle, but in a subfolder within it. Such an arrangement can be valuable if you have many resources and you want to separate them into cate‐ gories (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. The downside of this arrangement is that the code you write for accessing a resource will have to be specific about what subfolder of the app bundle contains that resource. Add to targets Checking the checkbox for a target causes the resource to be added to that target’s Copy Bundle Resources build phase. Thus you will almost certainly want to check it for the app target; why else would you be adding this resource to the project? If this checkbox accidentally goes unchecked and you realize later that a resource listed in the Project navigator needs to be added to the Copy Bundle Resources build phase for a particular target, you can add it manually, as I described earlier. Image resources for an iOS program tend to come in sets, to match the resolution of the screen. Because iOS 8 can run on single-resolution, double-resolution, and triple- resolution devices, you need up to three sizes of every image. In order to work properly with the framework’s image-loading methods, such resources employ a special naming convention: for example, listen.png, listen@2x.png, and listen@3x.png. The resulting proliferation of image files in the Project navigator can be overwhelming and error- prone. Asset catalogs alleviate the problem. Instead of tediously naming the multiple versions of listen.png manually as I add them to my project, I can let an asset catalog help me. I’ll use the default catalog, Images.xcassets. I edit the default catalog, click the Plus button at the bottom of the first column, and choose New Image Set. The result is a placeholder called Image with slots for three images at three different sizes. I drag the images into their proper slots. The names of the original image files don’t matter! The images are automatically copied into the project folder (inside the asset catalog folder), and there is no need for me to specify the target membership of these image files, because they are part of an asset catalog which already has correct target membership. I can rename the placeholder to some‐ thing more descriptive than Image — let’s call it listen. The result is that my code can From Project to Running App | 295 now load the correct image for the current screen resolution by referring to it as "listen", without regard to the original name (or extension) of the images. The entries in an asset catalog can be inspected by selecting an image and using the Attributes inspector (Command-Option-4). This shows the original name and (more important) the pixel size of the image. Code Files and the App Launch Process The build process knows what code files to compile to form the app’s binary because they are listed in the app target’s Compile Sources build phase. In the case of our Empty Window project, these are ViewController.swift and AppDelegate.swift. As development of your app proceeds, you will probably add further code files to the project, and you will ensure they are part of the target and thus that they, too, are listed in its Compile Sources build phase. What typically happens is that you want to add a new object type declaration to your code; you will often do so by adding a new file to the project, because this makes your object type declaration easier to find, and because Swift privacy depends upon code being isolated in individual files (Chapter 5). When you choose File → New → File to create a new file, you can specify either the Cocoa Touch Class template or the Swift File template. The Swift File template is just a blank file. If your goal is to subclass a Cocoa class, the Cocoa Touch Class template will usually be more suitable; Xcode will write the initial class declaration for you, and in the case of some commonly subclassed superclasses such as UIViewController and UITableViewController, it provides stub declarations of some commonly implemented methods. When the app launches, the system knows where to find the binary inside the app’s bundle because the app bundle’s Info.plist file has an “Executable file” key (CFBundle- Executable) whose value is the name of the binary; by default, the binary’s name comes from the EXECUTABLE_NAME environment variable (here, “Empty Window”). The entry point The trickiest part of the app launch process is getting started. Having located and loaded the binary, the system must call into it. But where? If this app were an Objective-C program, the answer would be clear. Objective-C is C, so the entry point is the main function. Our project would have a main.m file containing the main function, like this: int main(int argc, char *argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } 296 | Chapter 6: Anatomy of an Xcode Project The main function does just two things: • It sets up a memory management environment — the @autoreleasepool and the curly braces that follow it. • It calls the UIApplicationMain function, which does the heavy lifting of helping your app pull itself up by its bootstraps and get running. Our app, however, is a Swift program. It has no main function! Instead, Swift has a special attribute: @UIApplicationMain. If you look in the AppDelegate.swift file, you can see it, attached to the declaration of the AppDelegate class: @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { This attribute essentially does everything that the Objective-C main.m file was doing: it creates an entry point that calls UIApplicationMain to get the app started. Under certain circumstances, you might like to remove the @UIApplicationMain at‐ tribute and substitute a main file. You are free to do this. Your file can be an Objective- C file or a Swift file. Let’s say it’s to be a Swift file. You would create a main.swift file and make sure it is added to the app target. The name is crucial, because a file called main.swift gets a special dispensation: it is allowed to put executable code at the top level of the file. The file should contain essentially the Swift equivalent of the Objective-C call to UIApplicationMain, like this: import UIKit UIApplicationMain( Process.argc, Process.unsafeArgv, nil, NSStringFromClass(AppDelegate)) Why might you do that sort of thing? Presumably, it would be because you want to do other things in the main.swift file, or because you want to customize the call to UIApplicationMain. UIApplicationMain Regardless of whether you write your own main.swift file or you rely on the Swift @UIApplicationMain attribute, you are calling UIApplicationMain. This one function call is the primary thing your app does. Your entire app is really nothing but a single gigantic call to UIApplicationMain! Moreover, UIApplicationMain is responsible for solving some tricky problems as your app gets going. Where will your app get its initial instances? What instance methods will initially be called on those instances? Where will your app’s initial interface come from? Let’s pause to understand what UIApplication- Main does: 1. UIApplicationMain creates your app’s first instance — the shared application in‐ stance, which subsequently is to be accessible in code by calling From Project to Running App | 297 UIApplication.sharedApplication(). The third argument in the call to UIApplicationMain specifies, as a string, what class the shared application instance should be an instance of. If this argument is nil, which will usually be the case, the default class is UIApplication. If, however, you needed to subclass UIApplication, you would specify that subclass here, by substituting an explicit value, such as NSStringFromClass(MyUIApplicationSubclass) (depending on what the sub‐ class is called) as the third argument in the call to UIApplicationMain. 2. UIApplicationMain also creates your app’s second instance — the application in‐ stance’s delegate. Delegation is an important and pervasive Cocoa pattern, described in detail in Chapter 11. It is crucial that every app you write have an app delegate instance. The fourth argument in the call to UIApplicationMain specifies, as a string, what class the app delegate instance should be. In our manual version of main.swift, that specification is NSStringFromClass(AppDelegate). If we use the @UIApplicationMain attribute, that attribute is attached, by default, to the App‐ Delegate class declaration in AppDelegate.swift (which was created for us by the Single View Application template); the attribute means: “This is the application delegate class!” 3. If the Info.plist file specifies a main storyboard file, UIApplicationMain loads it and looks inside it to find the view controller that is designated as this storyboard’s initial view controller (or storyboard entry point); it instantiates this view controller, thus creating your app’s third instance. In the case of our Empty Window project, as constructed for us from the Single View Application template, that view con‐ troller will be an instance of the class called ViewController; the code file defining this class, ViewController.swift, was also created by the template. 4. If there was a main storyboard file, UIApplicationMain now creates your app’s window — this is your app’s fourth instance, an instance of UIWindow (or your app delegate can substitute an instance of a UIWindow subclass). It assigns this window instance as the app delegate’s window property; it also assigns the initial view con‐ troller instance as the window instance’s root view controller (rootView- Controller property). 5. UIApplicationMain now turns to the app delegate instance and starts calling some of its code — in particular, it calls application:didFinishLaunchingWith- Options: (or application:willFinishLaunchingWithOptions: if it exists). This is an opportunity for your own code to run! Thus, application:didFinish- LaunchingWithOptions: is a good place to put your code that initializes values and performs startup tasks; but you don’t want anything time-consuming to happen here, because your app’s interface still hasn’t appeared. 6. If there was a main storyboard, UIApplicationMain now causes your app’s interface to appear. It does this by calling the UIWindow instance method makeKeyAnd- Visible. 298 | Chapter 6: Anatomy of an Xcode Project 7. The window is now about to appear. This, in turn, causes the window to turn to its root view controller and tell it to obtain its main view, which will occupy and appear in the window. If this view controller gets its view from a .storyboard or .xib file, the corresponding nib is now loaded; its objects are instantiated and initialized, and they become the objects of the initial interface. The app is now launched and visible to the user! It has an initial set of instances — at a minimum, the shared application instance, the window, the initial view controller, and the initial view controller’s view and whatever interface objects it contains. Some of your code (the app delegate’s application:didFinishLaunchingWithOptions:) has run, and we are now off to the races: UIApplicationMain is still running (like Charlie on the M.T.A., UIApplicationMain never returns), and is just sitting there, watching for the user to do something, maintaining the event loop, which will respond to user actions as they occur. App without a storyboard In my description of the app launch process, I used several times the phrase “if there is a main storyboard.” In the Xcode 6 app templates, such as the Single View Application template that we used to generate the Empty Window project, there is a main storyboard. It is possible, though, not to have a main storyboard. In that case, things like creating a window instance, giving it a root view controller, assigning it to the app delegate’s window property, and calling makeKeyAndVisible on the window to show the interface, must be done by your code. To see what I mean, make a new iPhone project starting with the Single View Application template; let’s call it Truly Empty. Now follow these steps: 1. Edit the target. In the General pane, select “Main” in the Main Interface field and delete it (and press Tab to set this change). 2. Delete Main.storyboard and ViewController.swift from the project. 3. Select and delete the entire code content of AppDelegate.swift. You now have a project with an app target but no storyboard and no code! To make a minimal working app, you need to edit AppDelegate.swift in such a way as to recreate the AppDelegate class with just enough code to create and show the window, as shown in Example 6-1. Example 6-1. An App Delegate class with no storyboard import UIKit @UIApplicationMain class AppDelegate : UIResponder, UIApplicationDelegate { var window : UIWindow? func application(application: UIApplication, From Project to Running App | 299 didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { self.window = UIWindow(frame:UIScreen.mainScreen().bounds) self.window!.backgroundColor = UIColor.whiteColor() self.window!.makeKeyAndVisible() return true } } The result is a minimal working app with an empty white window; you can prove to yourself that your code is creating the window by changing its backgroundColor to something else (such as UIColor.redColor()) and running the app again. This is a working app, but it’s kind of useless. It doesn’t do anything, and it can’t really do much of anything, because it doesn’t have a view controller. In fact, you will see a warning about that in the console: “Application windows are expected to have a root view controller at the end of application launch.” We could silence the warning by making a generic view controller and making it the window’s root view controller. Just before the call to makeKeyAndVisible, insert this line: self.window!.rootViewController = UIViewController() This silences the warning, but the app remains more or less useless. What we need here is an instance of our own view controller — one that has a view that we can configure in a nib. So let’s now make a UIViewController subclass along with a .xib file containing its view: 1. Choose File → New → File. In the “Choose a template” dialog, under iOS, click Source on the left and select Cocoa Touch Class. Click Next. 2. Name the class MyViewController and specify that it is a subclass of UIView‐ Controller. Check the “Also create XIB file” checkbox! Specify Swift as the language. Click Next. 3. The Save dialog appears. Make sure you are saving into the Truly Empty folder, that the Group pop-up menu is set to Truly Empty as well, and that the Truly Empty target is checked — we want these files to be part of the app target. Click Create. Xcode has created two files for us: MyViewController.swift, defining MyView‐ Controller as a subclass of UIViewController, and MyViewController.xib, the source of the nib from which a MyViewController instance will obtain its view. 4. Now go back to the app delegate’s application:didFinishLaunchingWith- Options:, in AppDelegate.swift, and change the root view controller’s class to My‐ ViewController, associating it with its nib, like this: 300 | Chapter 6: Anatomy of an Xcode Project self.window!.rootViewController = MyViewController(nibName:"MyViewController", bundle:nil) We have now created a perfectly usable minimal app project without a storyboard. Our code does some of the work that is done automatically by UIApplicationMain when there is a main storyboard: we instantiate UIWindow, we set the window instance as the app delegate’s window property, we instantiate an initial view controller, we set that view controller instance as the window’s rootViewController property, and we cause the window to appear. Moreover, the appearance of the window automatically causes the MyViewController instance to fetch its view from the MyViewController nib, which has been compiled from MyViewController.xib; thus, we can use MyViewController.xib to customize the app’s initial interface. Besides illustrating explicitly what it is that UIApplicationMain does for you implicitly, this is also a perfectly reasonable way to construct an app. Frameworks and SDKs A framework is a library of compiled code used by your code. Most of the frameworks you are likely to use when programming iOS will be Apple’s built-in frameworks. These frameworks are already 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. Your compiled code also needs to be connected to those frameworks when the project is being built and run on your computer. To make this possible, the iOS device’s System/ Library/Frameworks is duplicated on your computer, inside Xcode itself. This duplicated subset of the device’s system is called an SDK (for “software development kit”). What SDK is used depends upon what destination you’re building for. Linking is the process of hooking up your compiled code with the frameworks that it needs, even though those frameworks are in one place at build time and in another place at runtime. Thus, for example: When you build your code to run on a device: A copy of any needed frameworks is used. This copy lives in System/Library/Frame‐ works/ inside the iPhone SDK, which is located at Xcode.app/Contents/Developer/ Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk. When your code runs on a device: The code, as it starts running, looks in the device’s top-level /System/Library/Frame‐ works/ folder for the frameworks that it needs. Used in this way, the frameworks are part of an ingenious mechanism whereby Apple’s code is effectively incorporated dynamically into your app when the app runs. The frameworks are the locus of all the stuff that every app might need to do; they are Cocoa. From Project to Running App | 301 That’s a lot of stuff, and a lot of compiled code. Your app gets to share in the goodness and power of the frameworks because it is linked to them. Your code works as if the framework code were incorporated into it. Yet your app is relatively tiny; it’s the frame‐ works that are huge. Linking takes care of connecting your compiled code to any needed frameworks, but it isn’t sufficient to allow your code to compile in the first place. The frameworks are full of classes (such as NSString) and methods (such as rangeOfString:) that your code will call. To satisfy the compiler, the frameworks do exactly what any C or Objective-C code would do: they publish their interface in header files, which your code can import. Thus, for example, your code can speak of NSString and can call rangeOfString: because it imports the NSString header. Actually, what your code imports is the UIKit header, which in turn imports the Foundation header, which in turn imports the NSString header. And you can see this happening at the top of any of your own code’s header files: import UIKit If you Command-click UIKit, you are taken to Swift’s rendering of the UIKit header. There at the top is import Foundation. If you look at the Foundation header and scroll down, you’ll see import Foundation.NSString. And if you look in the NSString header, you’ll see the declaration of the rangeOfString: method. Thus, using a framework is a two-part process: Import the framework’s header Your code needs this information in order to compile successfully. Your code im‐ ports a framework’s header by using the import keyword, specifying either that framework or a framework that itself imports the desired framework. In Swift, you specify a framework by using its module name. Link to the framework The compiled executable binary needs to be connected to the frameworks it will use while running, effectively incorporating the compiled code from those frame‐ works. As your code is built, it is linked to any needed frameworks, in accordance with the list of frameworks in the target’s Link Binary With Libraries build phase. However, it appears that our project does not do any explicit linking. If you look in the app target’s Link Binary With Libraries build phase, it is empty. This is because Swift uses modules, and modules can perform autolinking. In Objective-C, both those features are optional, and are governed by build settings. But in Swift, use of modules and au‐ tolinking is automatic. Modules are cached information stored on your computer at Library/Developer/Xcode/ DerivedData/ModuleCache. Merely opening a Swift project causes any imported mod‐ ules to be cached here. If you drill down into the ModuleCache folder, you’ll see the 302 | Chapter 6: Anatomy of an Xcode Project modules for over a dozen frameworks and headers (.pcm files). Swift’s use of modules simplifies the importing and linking process, and improves compilation times. Modules are ingenious and convenient, but they also have some aspects that might be considered disadvantages as opposed to the old regime of explicit importing and linking. For example, when a framework is explicitly linked into your project, you know it, because it is listed in the Link Binary With Libraries build phase and in the Project navigator. With modules, you don’t know what frameworks you’re using; there’s no list of your autolinked frameworks. Moreover, because autolinked frameworks are not listed in the Project navigator, their headers are not navigable in the Project navigator (whereas the headers of explicitly linked frameworks are), and their headers are not searchable in the Project navigator (whereas the headers of explicitly linked frameworks are, by using a search scope of “within workspace and frameworks”). Fortunately, if you miss those features, there’s no harm in linking to a framework man‐ ually, to create a listing for it in the Project navigator, even if that framework is also being autolinked. Moreover, it is sometimes necessary to link to a framework manually. For example, let’s say you want to use an MKMapView (Map Kit View) in your interface. You can configure this in a .storyboard or .xib file, but when you build and run your app, it crashes, com‐ plaining: “Could not instantiate class named MKMapView.” The reason is that the nib, as it loads, finds that it contains an MKMapView but doesn’t know what an MKMapView is. Adding import MapKit at the top of your code doesn’t solve the problem; you do need to do that if your code wants to talk to the MKMapView, but it doesn’t help the nib understand what an MKMapView is when it loads. The solution is to link to the MapKit framework manually: 1. Edit the target and look at the Build Phases pane. 2. Under Link Binary With Libraries, click the Plus button. 3. A list of available frameworks appears (along with dynamic libraries). Scroll down to MapKit.framework, select it, and click Add. This solves the problem; your app now builds and runs. New in iOS 8 and Xcode 6, you can also create your own framework as part of your project. A framework is a module, so this can be a useful way to structure your code, as I described in Chapter 5 when discussing Swift privacy. To make a new framework: 1. Edit the target and choose Editor → Add Target. 2. On the left of the dialog, under iOS, select Framework & Library; on the right, select Cocoa Touch Framework. Click Next. From Project to Running App | 303 3. Give your framework a name; let’s call it Coolness. You can pick a language, but I’m not sure this makes any difference, as no code files will be created. The Project and Embed pop-up menus should be correctly set by default. Click Finish. A new Coolness framework target is created in your project, along with a corresponding test target. If you now add a .swift file to the Coolness target, and inside it define an object type and declare it public, and if you import Coolness back in one of your main app target’s files, such as AppDelegate.swift, that file will be able to see the public members of the Coolness framework. Embedded frameworks of this kind are not backward-compatible to iOS 7. Renaming Parts of a Project 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! The project name is not a name that users will ever see — it is not, for example, the name that appears visibly associated with the app on the device — and you are free to change it. 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 app target, the test target, the built app, the label in the launch screen — and, by implication, various relevant build settings. You should feel free to accept. Because of a bug in Xcode, renaming your project can break your test target, thus preventing your app from building. See “Unit Testing” on page 379. 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. It’s fine to change 304 | Chapter 6: Anatomy of an Xcode Project the group name, but beginners should not change the name of that folder on disk, as it is hard-coded into several build settings. 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. Bilingual Targets It is legal for a target to be a bilingual target — one and the same target that contains both Swift files and Objective-C files. A bilingual target can be useful for various reasons. Here are some reasons that have arisen in my own real programming life: Swift is limited The API might contain a method or function that you need to call, or a class or struct that you need to use, that Swift cannot deal with. So you need to switch momentarily into Objective-C. Swift is slow You may find that, for certain intensive repeated operations, Swift is unacceptably slow, whereas the same code written in Objective-C is fast. Swift is new Perhaps you already have an app written in Objective-C, and you want to migrate it into Swift. You are unlikely to want to rewrite all the code from scratch simulta‐ neously. More probably, you will rewrite just one file (class) at a time. During this rewriting process, you’ll have a bilingual target. A common variant of this situation is: Your code is written in Swift, but a third-party library that you want to use is written in Objective-C. Bilingual targets are not difficult to use. Communication between the two languages is generally straightforward (see Appendix A). The key question is how Swift and Objective-C hear about one another’s code in the first place. Recall that Objective-C, unlike Swift, has a visibility problem already: Objective-C files cannot automatically see one another. Instead, each Objective-C file that needs to see another Objective-C file must be instructed explicitly to see that file, usually with an #import directive at the top of the first file. In order to prevent unwanted exposure of private information, an Objective-C class declaration is conventionally spread over two files: a header file (.h) containing the @interface section, and a code file (.m) containing the @implementation section. Also conventionally, only .h files are ever imported. Thus, if declarations of class members, constants, and so forth are to be public, they are placed in a .h file. Bilingual Targets | 305 Visibility of Swift and Objective-C to one another depends upon this convention: it works through .h files. There are two directions of visibility, and they must be considered separately: How Swift sees Objective-C When you add a Swift file to an Objective-C target, or an Objective-C file to a Swift target, Xcode offers to create a bridging header. This is a .h file in the project. Its default name is derived from the target name — for example, Empty Window- Bridging-Header.h — but the name is arbitrary and can be changed, provided you change the target’s Objective-C Bridging Header build setting to match. (Similarly, if you decline the bridging header and you decide later that you want one, create a .h file manually and point to it in the app target’s Objective-C Bridging Header build setting.) An Objective-C .h file will then be visible to Swift provided you #import it in this bridging header. How Objective-C sees Swift If you have a bridging header, then when you build your target, the appropriate top-level declarations of all your Swift files are automatically translated into Objective-C and are used to construct a hidden bridging header inside the Inter‐ mediates build folder for this target, deep inside your DerivedData folder. The easi‐ est way to see this is with the following Terminal command: $ find ~/Library/Developer/Xcode/DerivedData -name "*Swift.h" This will reveal the name of the hidden bridging header. For example, for our Empty Window project, the hidden bridging header for the app target is called Empty_Window-Swift.h; note that the space in the target name has been translated into an underscore. Alternatively, examine (or change) the target’s Product Module Name build setting; the hidden bridging header’s name is derived from this. Your Objective-C files will be able to see your Swift declarations, provided you #import this hidden bridging header into each Objective-C file that needs to see it. For simplicity, I will refer to these two bridging headers as the visible and invisible bridging headers, respectively. For example, let’s say that I’ve added to my Empty Window app target a Thing class written in Objective-C. It is distributed over two files, Thing.h and Thing.m. Then: • For Swift code to see the Thing class, I need to #import "Thing.h" in the visible bridging header (Empty Window-Bridging-Header.h). • For Thing class code to see my Swift declarations, I need to import the invisible bridging header (#import "Empty_Window-Swift.h") at the top of Thing.m. Exactly where at the top of a .m file you #import the invisible bridging header can make a difference. The usual sign of trouble is that you get an “Unknown type name” compile 306 | Chapter 6: Anatomy of an Xcode Project error, where the “unknown” type is a class declared in Objective-C. You get this error even though you are importing the .h file containing this class declaration in the visible bridging header, thus making it known to Swift. The solution is to #import the .h file containing the declaration for the “unknown” type in your Objective-C files as well, before you #import the invisible bridging header. For example, if my Empty Window bilingual target suddenly started generating a com‐ pile error complaining of an unknown type name Thing, I would find all the Objective- C files where I say #import "Empty_Window-Swift.h" and say #import "Thing.h" before that line. Having to do this can be an annoyance, especially if the Objective-C file in question has no need to know about Thing, but it resolves the issue and allows com‐ pilation to proceed. Having translated numerous iOS apps from Objective-C to Swift, I will end by outlining my procedure: 1. Pick a .m file to be translated into Swift. Objective-C cannot subclass a Swift class, so if you have defined both a class and its subclass in Objective-C, start with the subclass. Leave the app delegate class for last. 2. Remove that .m file from the target. To do so, select the .m file and use the File inspector. 3. In every Objective-C file that #imports the corresponding .h file, remove that #import statement and import in its place the invisible bridging header. (If you’re already importing the invisible bridging header in this file, you don’t need to import it again.) 4. If you were importing the corresponding .h file in the visible bridging header, re‐ move the #import statement. 5. Create the .swift file for this class. Make sure it is added to the target. 6. In the .swift file, declare the class and provide stub declarations for all members that were being made public in the .h file. If this class needs to adopt Cocoa protocols, adopt them; you may have to provide stub declarations of required protocol meth‐ ods as well. If this file needs to refer to any other classes that your target still declares in Objective-C, import their .h files in the visible bridging header. 7. The project should now compile! It doesn’t work, of course, because you have not written any real code in the .swift file. But who cares about that? Time for a beer! 8. Now fill out the code in the .swift file. My technique is to translate more or less line- by-line from the original Objective-C code, even though the outcome is not par‐ ticularly idiomatic (Swifty). 9. When the code for this .m file is completely translated into Swift, build and run and test. If the runtime complains (probably accompanied by crashing) that it can’t find Bilingual Targets | 307 this class, find all references to it in the nib editor and reenter the class’s name in the Identity inspector (and press Tab to set the change). Save and try again. 10. On to the next .m file! Repeat all of the above steps. 11. When all of the other files have been translated, translate the app delegate class. At this point, if there are no Objective-C files left in the target, you can delete the main.m file (replacing it with a @UIApplicationMain attribute in the app delegate class declaration) and the .pch (precompiled header) file. Your app should now run, and is now written in pure Swift (or is, at least, as pure as you intend to make it). Now go back and think about the code, making it more Swifty and idiomatic. You may well find that things that were clumsy or tricky in Objective-C can be made much neater and clearer in Swift. 308 | Chapter 6: Anatomy of an Xcode Project CHAPTER 7 Nib Management In Chapter 4, I talked about ways of obtaining an instance. You can directly instantiate an object type: let v = UIView() Or you can obtain a reference to an already existing instance: let v = self.view.subviews[0] as! UIView But there is a third way: you can load a nib. A nib is a file, in a special format, filled with instructions for creating and configuring instances. To load a nib means, in effect, to tell that nib to follow those instructions: it does create and configure those instances. My example of a UIView instance is apt, because a UIView is just the kind of instance a nib is likely to create. Nibs are edited in Xcode using a graphical interface, much like a drawing program. The idea is that you are designing some interface objects — mostly instances of UIView and UIView subclasses — that you want to use in your app when it runs. When your app does run, and when the moment comes where you actually need those interface objects (typically because you’re about to display them in your visible interface), you load the nib, the nib-loading process creates and configures the instances, and you receive the instances and insert them into your app’s actual interface. You do not have to use nibs to create your interface objects. The loading of a nib does nothing that you could not have done directly, in code. You can instantiate a UIView or UIView subclass, you can configure it, you can construct a hierarchy of views, you can place that view hierarchy into your interface — manually, step by step, entirely in code. A nib is just a device for making that process simpler and more convenient. You design the nib beforehand, graphically; when the app runs, your code doesn’t have to instantiate or configure any views. It has merely to load the nib and retrieve the resulting instances and put them into your interface. And in fact, because you’ll mostly be using view 309 Are Nibs Necessary? Since nibs are ultimately just sources of instances, you might wonder whether it is pos‐ sible to do without them. Those same instances could be generated in code, so wouldn’t it be possible to dispense with nibs altogether? The simple answer is: Yes, it would. It’s quite possible to write a complex app that lacks a single .storyboard or .xib file (I’ve done it). The practical question, however, is one of balance. Most apps use nib files as a source of at least some interface objects; but there are some aspects of interface objects that can be customized only in code, and sometimes it’s easier to generate those interface objects entirely in code at the outset. In real life your projects will probably involve some code- generated interface objects and some nib-generated interface objects (which may them‐ selves be further modified or configured in code). controllers (UIViewController), which are themselves designed with nibs in mind, you won’t even have to do that! The view controller will load the nib and retrieve the resulting instances and put them into your interface for you, automatically. Nibs are a simple and ingenious device for making the process of designing and con‐ figuring your app’s interface simpler and more convenient than it would be if you had to do the same thing in code. But they are also probably the least understood aspect of iOS programming. Many beginners discover nibs the first day they start programming iOS, and proceed to use nibs for years, without knowing what they really are or how they really work. This is a huge mistake. Nibs are not magic. They are not hard to un‐ derstand. It is crucial that you know what nibs are, how they work, and how to manip‐ ulate them in your code. Failure to understand nibs opens you up to all kinds of ele‐ mentary, confusing mistakes that can be avoided or corrected merely by grasping a few basic facts. Those facts are the subject of this chapter. The name nib, or nib file, has nothing to do with fountain pens or bits of choco‐ late; it originated as an acronym for “NeXTStep Interface Builder,” which was used for the .nib file extension. This, in turn, is because the graphical nib-design as‐ pect of Xcode, which I call the nib editor, was itself (up through Xcode 3.2.x) a separate application called Interface Builder. (The nib editor environment with‐ in Xcode is still often referred to as Interface Builder.) Nowadays, the file you edit directly in the nib editor will be either a .storyboard file or a .xib file; when the app is built, such files are compiled into nib files (see Chapter 6). A Tour of the Nib Editor Interface Let’s explore Xcode’s nib editor interface. In Chapter 6, we created a simple iPhone project, Empty Window, directly from the Single View Application template; it contains 310 | Chapter 7: Nib Management Figure 7-1. Editing a nib file a storyboard file, so we’ll use that. In Xcode, open the Empty Window project, locate Main.storyboard in the Project navigator, and click to edit it. Figure 7-1 shows the project window after selecting Main.storyboard. (I’ve made some additional adjustments to make the screenshot fit on the page.) The interface may be considered in four pieces: 1. The bulk 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 con‐ trollers, which are represented in the canvas even though they are not drawn in your app’s interface; a view controller isn’t a view, but it has a view (and controls it). 2. At the left of the editor is the document outline, listing the storyboard’s contents hierarchically by name. It can be hidden by dragging its right edge or by clicking the button at the bottom left corner of the canvas. 3. The inspectors in the Utilities pane let you edit details of the currently selected object. 4. The libraries in the Utilities pane, especially the Object library, are your source of interface objects to be added to the nib. A Tour of the Nib Editor Interface | 311 Figure 7-2. A view controller selected in a storyboard The Document Outline The document outline portrays hierarchically the relationships between the objects in the nib. This structure differs slightly depending on whether you’re editing a .story‐ board file or a .xib file. In a storyboard file, the primary constituents are scenes. A scene is, roughly speaking, a single view controller, along with some ancillary material; every scene has a single view controller at its top level. A view controller isn’t an interface object, but it manages an interface object, namely its view (or main view). A view controller in a nib doesn’t have to have its main view in the same nib, but it usually does, and in that case, in the nib editor, the view usually appears inside the view controller in the canvas. Thus, in Figure 7-1, the large highlighted rec‐ tangle in the canvas is a view controller’s main view, and is actually inside a view con‐ troller. The view controller itself can be readily seen and selected in the document outline. It is also represented as an icon in the scene dock, which appears above the view controller in the canvas when anything in this scene is selected (Figure 7-2). Each view controller in a storyboard file, shown in the canvas together with its view and its scene dock, constitutes one scene. This scene is also portrayed as a hierarchical collection of names in the document outline. At the top level of the document outline are the scenes them‐ selves. At the top level of each scene are (more or less) the same objects that appear in the view controller’s scene dock: the view controller itself, along with two proxy ob‐ jects, the First Responder token and the Exit token. These objects — the ones displayed as icons in the scene dock, and shown at the top level of the scene in the document outline — are the scene’s top-level objects. (New in Xcode 6.2 is the Storyboard Entry Point. This supersedes the older notion of a storyboard’s initial view controller, in preparation for a day when one storyboard will be able to “contain” another. If this view controller is the storyboard’s entry point, the Storyboard Entry Point icon is listed with it in the document outline.) Objects listed in the document outline are of two kinds: 312 | Chapter 7: Nib Management Nib objects The view controller, along with its main view and any subviews that we care to place in that view, are real objects — potential objects that will be turned into actual instances when the nib is loaded by the running app. Such real objects to be in‐ stantiated from the nib are also called nib objects. Proxy objects The proxy objects (here, the First Responder and Exit tokens) do not represent instances that will come from the nib when it is loaded. Rather, they represent other objects, and are present to facilitate communication between nib objects and other objects (I’ll give examples later in this chapter). You can’t create or delete a proxy object; the nib editor shows them automatically. Aside from the top-level objects, most objects listed in a storyboard’s document outline will depend hierarchically upon a scene’s view controller. For example, in Figure 7-2, the view controller has a main view; that view is listed as hierarchically dependent on the view controller. That makes sense, because this view belongs to this view controller. Moreover, any further interface objects that we drag into the main view in the canvas will be listed in the document outline as hierarchically dependent on the view. That makes sense, too. A view can contain other views (its subviews) and can be contained by another view (its 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 document outline portrays that tree as an outline — hence the name. In a .xib file, there are no scenes. What would be, in a .storyboard file, the top-level objects of a scene become, in a .xib file, the top-level objects of the nib itself. Nor is there any requirement that one of these top-level objects be a view controller; it can be, but more often the top-level interface object of a .xib file is a view. It might well be a view that is to serve as a view controller’s main view, but that’s not a requirement either. Figure 7-3 shows a .xib with a structure parallel to the single scene of Figure 7-2. The document outline in Figure 7-3 lists three top-level objects. Two of them are proxy objects, termed Placeholders in the document outline: the File’s Owner, and the First Responder. The third is a real object, a view; it will be instantiated when the nib is loaded as the app runs. The document outline in a .xib file can’t be completely hidden; instead, it is collapsed into a set of icons representing the nib’s top-level objects, similar to a scene dock in a storyboard file, and often referred to simply as the dock (Figure 7-4). At present, the document outline may seem unnecessary, because there is very little hierarchy; all objects in Figures 7-2 and 7-3 are readily accessible in the canvas. But when a storyboard contains many scenes, and when a view contains many levels of hierarchically arranged objects (along with their autolayout constraints), you’re going to be very glad of the document outline, which lets you survey the contents of the nib A Tour of the Nib Editor Interface | 313 Figure 7-3. A .xib file containing a view Figure 7-4. The dock in a .xib file in a nice hierarchical structure, and where you can locate and select the object you’re after. 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: the last jump bar path component (Control-6) is a hierarchical pop-up menu similar to the document outline. If the names of nib objects in the document outline seem generic and uninformative, you can change them. The name is technically a label, and has no special meaning, so feel free to assign nib objects labels that are useful to you. Select a nib object’s label in the document outline and press Return to make it editable, or select the object and edit the Label field in the Document section of the Identity inspector (Command-Option-3). Canvas The canvas provides a graphical representation of a top-level interface nib object along with its subviews, similar to what you’re probably accustomed to in any drawing pro‐ 314 | Chapter 7: Nib Management Figure 7-5. Dragging a button into a view gram. The canvas is scrollable and automatically accommodates however many graph‐ ical representations it contains; a storyboard canvas can also be zoomed (choose Editor → Canvas → Zoom, or use the contextual menu). (In a .xib file, you can remove the canvas representation of a top-level nib object, without deleting the object, by clicking the X at its top left — see Figure 7-3) — and you can restore the graphical representation to the canvas by clicking that nib object in the document outline.) Our simple Empty Window project’s Main.storyboard contains just one scene, so it represents graphically in the canvas just one top-level nib object — the scene’s view controller. Inside this view controller, and generally indistinguishable from it in the canvas, is its main view. It happens that this view controller will become our app’s win‐ dow’s root view controller when the app runs; therefore its view will occupy the entire window, and will effectively be our app’s initial interface (see Chapter 6). That gives us an excellent opportunity to experiment: any visible changes we make within this view should be visible when we subsequently build and run the app. To prove this, let’s add a subview: 1. Start with the canvas looking more or less like Figure 7-1. 2. Look at the Object library (Command-Option-Control-3). If it’s in icon view (a grid of icons without text), click the button at the left of the filter bar to put it into list view. Click in the filter bar (or choose Edit → Filter → Filter in Library, Command- Option-L) and type “button” so that only button objects are shown in the list. The Button object is listed first. 3. Drag the Button object from the Object library into the view controller’s main view in the canvas (Figure 7-5), and let go of the mouse. A Tour of the Nib Editor Interface | 315 A button is now present 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. 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 the button: resizing handles appear. (If you accidentally select it twice and the resizing handles disappear, select the view and then the button again.) • Using the resizing handles, resize the button to make it wider: dimension infor‐ mation appears. • Drag the button near an 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 cen‐ tered. • 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.) • Control-Shift-click on the button: a menu appears, letting you select the button or whatever’s behind it (in this case, the view, as well as the view controller because the view controller acts as a sort of top-level background to everything we’re doing here). • Double-click the button’s title. The title becomes editable. Give it a new title, such as “Howdy!” Hit Return to set the new title. To prove that we really are designing our app’s interface, we’ll run the app: 1. Drag the button to a position near the top left corner of the canvas. (If you don’t do this, the button could be off the screen when the app runs.) 2. Examine the Debug → Activate / Deactivate Breakpoints menu item. If it says De‐ activate Breakpoints, choose it; we don’t want to pause at any breakpoints you may have created while reading the previous chapter. 3. Make sure the destination in the Scheme pop-up menu is iPhone 6. 4. 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-6); it contains a button! You can tap this button with the mouse, emulating what the user would do with a finger; the button highlights as you tap it. 316 | Chapter 7: Nib Management Figure 7-6. The Empty Window app’s window is empty no longer Inspectors and Libraries Four inspectors appear in conjunction with the nib editor, and apply to whatever object is selected in the document outline, dock, or canvas: Identity inspector (Command-Option-3) The first section of this inspector, Custom Class, is the most important. Here you learn, and can change, the selected 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, selecting our view and choosing from the Back‐ ground pop-up menu in the Attributes inspector corresponds to setting the view’s backgroundColor property in code. Similarly, selecting our button and typing in the Title field 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: in addition to a Button section, there’s a Control section (because a UIButton is also a UIControl) and a View section (because a UIControl is also a UIView). Size inspector (Command-Option-5) The X, Y, Width, and Height fields determine the object’s 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. If autolayout is turned on (the default for new .storyboard and .xib files), the rest of the Size inspector has to do with the selected object’s autolayout constraints, plus the four buttons at the lower right of the canvas help you manage alignment, po‐ sitioning, and constraints. Connections inspector (Command-Option-6) I’ll discuss and demonstrate use of the Connections inspector later in this chapter. Two libraries are of particular importance when you’re editing a nib: A Tour of the Nib Editor Interface | 317 Object library (Command-Option-Control-3) This library is your source for objects that you want to add to the nib. Media library (Command-Option-Control-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. I’ve now mentioned autolayout and constraints a couple of times, but I’m not go‐ ing to explain here what they are. Nor am I going to discuss size classes and con‐ ditional constraints (the “Any” buttons at the bottom of the canvas). These are large topics having to do with views and view controllers, and are outside the scope of this book. I deal with these matters in full detail, including how to work with constraints and size classes in the nib editor, in Programming iOS 8. Nib Loading A nib file is a collection of potential instances — its nib objects. Those instances become real only if, while your app is running, the nib is loaded. At that moment, the nib objects contained in the nib are transformed into instances that are available to your app. This architecture is a source of great efficiency. A nib usually contains interface; interface is relatively heavyweight stuff. A nib isn’t loaded until it is needed; indeed, it might never be loaded. Thus this heavyweight stuff won’t come into existence until and unless it is needed. In this way, 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 — enough to generate just the app’s initial interface — makes launching faster. Nib loading is a one-way street: there’s no such thing as “unloading” a nib. As a nib is loaded, its instances come into existence, and the nib’s work, for that moment, is done. Henceforward it’s up to the running app to decide what to do with the instances that just sprang to life. It must hang on to them for as long as it needs them, and will let them go out of existence when they are needed no longer. Think of the nib file as a set of instructions for generating instances; those instructions are followed each time the nib is loaded. The same nib file can thus be loaded multiple times, generating a new set of instances each time. For example, a nib file might contain a piece of interface that you intend to use in several different places in your app. A nib file representing a single row of a table might be loaded a dozen times in order to generate a dozen visible rows of that table. 318 | Chapter 7: Nib Management When Nibs Are Loaded Here are some of the chief circumstances under which a nib file is commonly loaded while an app is running: A view controller is instantiated from a storyboard A storyboard is a collection of scenes. Each scene starts with a view controller. When that view controller is needed, it is instantiated from the storyboard. This means that a nib containing the view controller is loaded. Most commonly, a view controller will be instantiated from a storyboard automat‐ ically. For example, as your app launches, if it has a main storyboard, the runtime looks for that storyboard’s initial view controller (entry point) and instantiates it (see Chapter 6). Similarly, a storyboard typically contains several scenes connected by segues; when a segue is performed, the destination scene’s view controller is instantiated. It is also possible for your code to instantiate a view controller from a storyboard manually. To do so, you start with a UIStoryboard instance, and then: • You can instantiate the storyboard’s initial view controller by calling instantiateInitialViewController. • You can instantiate any view controller whose scene is named within the story‐ board by an identifier string by calling instantiateViewControllerWith- Identifier:. A view controller loads its main view from a nib A view controller has a main view. But a view controller is a lightweight object (it’s just some code), whereas its main view is a relatively heavyweight object. Therefore, a view controller, when it is instantiated, lacks its main view. It generates its main view later, when that view is needed because it is to be placed into the interface. A view controller can obtain its main view in several ways; one way is to load its main view from a nib. If a view controller belongs to a scene in a storyboard, and if, as will usually be the case, it contains its view in that storyboard’s canvas (as in our Empty Window example project), then there are two nibs involved: the nib containing the view controller, and the nib containing its main view. The nib containing the view con‐ troller was loaded when the view controller was instantiated, as I just described; now, when that view controller instance needs its main view, the main view nib is loaded automatically, and the whole interface connected with that view controller springs to life. In the case of a view controller instantiated in some other way, there may be a .xib- generated nib file associated with it, containing its main view. Once again, the view Nib Loading | 319 controller will automatically load this nib and extract the main view when it’s need‐ ed. This association between a view controller and its main view nib file is made through the nib file’s name. In Chapter 6, we configured this association in code using the UIViewController initializer init(nibName:bundle:), when we said this: self.window!.rootViewController = MyViewController(nibName:"MyViewController", bundle:nil) That code caused the view controller to set its own nibName property to "MyView- Controller". This, in turn, means that when the view controller needs its view, it gets it by loading the nib that comes from MyViewController.xib. Your code explicitly loads a nib file If a nib file comes from a .xib file, your code can load it manually, by calling one of these methods: loadNibNamed:owner:options: An NSBundle instance method. Usually, you’ll direct it to NSBundle.main- Bundle(). instantiateWithOwner:options: A UINib instance method. The nib in question was specified when UINib was instantiated and initialized with init(nibName:bundle:). To specify a nib file while the app is running actually requires two pieces of infor‐ mation — its name and the bundle containing it. And indeed, a view controller has not only a nibName property but also a nibBundle property, and the methods for specifying a nib, such as init(nibName:bundle:), have a bundle: parameter that allows you specify the bundle. In real life, however, the bundle will be the app bundle (or NSBundle.mainBundle(), which is the same thing); this is the default, so there will be no need to specify a bundle — and you’ll pass nil instead of supplying an explicit bundle. Manual Nib Loading In real life, you’ll probably configure your app so that most nib loading takes place automatically, in accordance with the various mechanisms and situations I’ve just out‐ lined. But in order to understand the nib-loading process, it will be useful for you to practice loading a nib manually. Let’s do that. First we’ll create and configure a .xib file in our Empty Window project: 1. In the Empty Window project, choose File → New → File and specify an iOS → User Interface → View file. This will be a .xib file containing a UIView instance. Click Next. 320 | Chapter 7: Nib Management Figure 7-7. Designing a view in a .xib file 2. In the Save dialog, accept the default name, View, for the new .xib file. Click Create. 3. We are now back in the Project navigator; our View.xib file has been created and selected, and we’re looking at its contents in the editor. Those contents consist of a single UIView. It’s too large, so select it and, in the Attributes inspector, change the Size pop-up menu, under Simulated Metrics, to Freeform. Handles appear around the view in the canvas; drag them to make the view smaller. 4. Populate the view with some arbitrary subviews, dragging them into it from the Object library. You can also configure the view itself; for example, in the Attributes inspector, change its background color (Figure 7-7). Our goal now is to load this nib file, manually, in code, when the app runs. Edit View‐ Controller.swift and, in the viewDidLoad method body, insert this line of code: NSBundle.mainBundle().loadNibNamed("View", owner: nil, options: nil) Build and run the app. Hey, what happened? Where’s the designed view from View.xib? Did our nib fail to load? No. Our nib did not fail to load. We loaded it! But we’ve omitted two further steps. Remember, there are three tasks you have to perform when you load a nib: 1. Load the nib. 2. Obtain the instances that it creates as it loads. 3. Do something with those instances. We performed the first task — we loaded the nib — but we didn’t obtain any instances from it. Thus, those instances were created and then vanished in a puff of smoke! In order to prevent that, we need to capture those instances somehow. The call to loadNib- Named:owner:options: returns an array of the top-level nib objects instantiated from the loading of the nib. Those are the instances we need to capture! We have only one Nib Loading | 321 Figure 7-8. A nib-loaded view appears in our interface top-level nib object — the UIView — so it is sufficient to capture the first (and only) element of this array. Rewrite our code to look like this: let arr = NSBundle.mainBundle().loadNibNamed("View", owner: nil, options: nil) let v = arr[0] as! UIView We have now performed the second task: we’ve captured the instances that we created by loading the nib. The variable v now refers to a brand-new UIView instance. But still nothing seems to happen when we build and run the app, because we aren’t doing anything with that UIView. That’s the third task. Let’s fix that by doing something clear and dramatic with the UIView: we’ll put it into our interface! Rewrite our code once again: let arr = NSBundle.mainBundle().loadNibNamed("View", owner: nil, options: nil) let v = arr[0] as! UIView self.view.addSubview(v) Build and run the app. There’s our view! This proves that our loading of the nib worked: we can see, in our running app’s interface, the view that we designed in the nib (Figure 7-8). Connections A connection is something in a nib file. It unites two nib objects, running from one to the other. The connection has a direction: that’s why I use the words “from” and “to” to describe it. I’ll call the two objects the source and the destination of the connection. There are two kinds of connection: outlet connections and action connections. The rest of this section describes them, explains how to create and configure them, and explains the nature of the problems that they are intended to solve. 322 | Chapter 7: Nib Management Outlets When a nib loads and its instances come into existence, there’s a problem: those in‐ stances are useless unless you can get a reference to them. In the preceding section, we solved that problem by capturing the array of top-level objects instantiated by the load‐ ing of the nib. But there’s another way: use an outlet. This approach is more complicated — it requires some advance configuration, which can easily go wrong. But it is also more common, especially when nibs are loaded automatically. An outlet is a connection that has a name, which is effectively just a string. When the nib loads, something unbelievably clever happens. The source object and the destination object are no longer just potential objects in a nib; they are now real, full-fledged in‐ stances. The outlet’s name is now immediately used to locate an instance property of the same name in the outlet’s source object, and the destination object is assigned to that property. For example, suppose there’s a Dog object and a Person object in a nib, and suppose a Dog has a master instance property. Then if we make an outlet from the Dog object to the Person object in the nib, and if that outlet is named "master", then when the nib loads and the Dog instance and the Person instance are created, that Person instance will be assigned as the value of that Dog instance’s master property (Figure 7-9). The nib-loading mechanism can’t magically create an instance property — that is, it doesn’t cause the source object, once instantiated, to have an instance property of the correct name if it didn’t have one before. The class of the source object has to have been defined with this instance property already. Thus, for an outlet to work, preparation must be performed in two different places: in the class of the source object, and in the nib. This is a bit tricky; Xcode does try to help you get it right, but it is still possible to mess it up. (I will discuss ways of messing it up, in detail, later in this chapter.) The Nib Owner To use an outlet to capture a reference to an instance created from a nib, we need an outlet that runs from an object outside the nib to an object inside the nib. This seems metaphysically impossible — but it isn’t. The nib editor permits such an outlet to be created, using the nib owner object. First, I’ll tell you where to find the nib owner object in the nib editor; then I’ll explain what it is: • In a storyboard scene, the nib owner is the top-level view controller. It is the first object listed for that scene in the document outline, and the first object shown in the scene dock. Connections | 323 Figure 7-9. How an outlet provides a reference to a nib-instantiated object • In a .xib file, the nib owner is a proxy object. It is the first object shown in the document outline or dock, and is listed under Placeholders as the File’s Owner. The nib owner object in the nib editor represents an instance that already exists out‐ side the nib at the time that the nib is loaded. When the nib is loaded, the nib-loading mechanism doesn’t instantiate this object; it is already an instance. Instead, the nib- loading mechanism substitutes the real, already existing instance for the nib owner object, using it to fulfill any connections that involve the nib owner. But wait! How does the nib-loading mechanism know which real, already existing in‐ stance to substitute for the nib owner object in the nib? It knows because it is told, in one of two ways, at nib-loading time: • If your code loads the nib either by calling loadNibNamed:owner:options: or by calling instantiateWithOwner:options:, you specify an owner object as the owner: argument. 324 | Chapter 7: Nib Management • If a view controller instance loads a nib automatically in order to obtain its main view, the view controller instance specifies itself as the owner object. For example, return to our Dog object and Person object. Suppose there is a Person nib object in our nib, but no Dog nib object. Instead, the nib owner object is a Dog. A Dog has a master instance property. We configure an outlet in the nib from the Dog nib owner object to the Person object — an outlet called "master". We then load the nib with an existing Dog instance as owner. The nib-loading mechanism will match the Dog nib owner object with this already existing actual Dog instance, and will set the newly instantiated Person instance as that Dog instance’s master (Figure 7-10). Return now to Empty View, and let’s reconfigure things to demonstrate this mechanism. We’re already loading the View nib in code in ViewController.swift. This code is running inside a ViewController instance. So we’ll use that instance as the nib owner. This will be a little tedious to configure, but bear with me, because understanding how to use this mechanism is crucial. Here we go: 1. First, we need an instance property in ViewController. At the start of the body of the ViewController class declaration, insert the property declaration, like this: class ViewController: UIViewController { @IBOutlet var v : UIView! = nil The var declaration you already understand; we’re making an instance property called v. It is declared as an Optional because it won’t have a “real” value when the ViewController instance is created; it’s going to get that value through the loading of the nib, later. The @IBOutlet attribute is a hint to Xcode to allow us to create the outlet in the nib editor. 2. Edit View.xib. Our first step must be to ensure that the nib owner object is designated as a ViewController instance. Select the File’s Owner proxy object and switch to the Identity inspector. In the first text field, under Custom Class, set the Name value as ViewController. Tab out of the text field and save. 3. Now we’re ready to make the outlet! In the document outline, hold down the Con‐ trol key and drag from the File’s Owner object to the View; a little line follows the mouse as you drag. Release the mouse. A little HUD (heads-up display) appears, listing possible outlets we are allowed to create (Figure 7-11). There are two of them: view and v. Click v (not view!). 4. Finally, we need to modify our nib-loading code. We no longer need to capture the top-level array of instantiated objects. That’s the whole point of this exercise! In‐ stead, we’re going to load the nib with ourself as owner. This will cause our v instance property to be set automatically, so we can proceed to use it immediately: NSBundle.mainBundle().loadNibNamed("View", owner: self, options: nil) self.view.addSubview(self.v) Connections | 325 Figure 7-10. An outlet from the nib owner object Figure 7-11. Creating an outlet 326 | Chapter 7: Nib Management Build and run. It works! The first line loaded the nib and set our v instance property to the view instantiated from the nib. Thus, the second line can display self.v in the interface, because self.v now is that view. Let’s sum up what we just did. Our preparatory configuration was a little tricky, because it was performed in two places — in code, and in the nib: • In code, there must be an instance property in the class whose instance will act as owner when the nib loads. (Not only did we create the property, but we also marked it as @IBOutlet.) • In the nib editor, the class of the nib owner object must be set to the class whose instance will act as owner when the nib loads. • In the nib editor, an outlet must be created, with the same name as the property, from the nib owner to some nib object. (This will be possible only if the other two configurations were correctly performed.) If all those things are true, then, when the nib loads, if it is loaded with an owner of the correct class, that owner’s instance property will be set to the outlet destination. Automatically Configured Nibs In some situations, the configuration of the owner class and the nib is performed for us. Now that we’ve gone through the work of configuring the owner and the nib man‐ ually, we can understand and appreciate those automatic configurations. An important example is how a view controller gets its main view. A view controller has a view property. The actual view will typically come from a nib. So the view controller instance needs to act as owner when that nib loads, and there needs to be a view outlet from the nib owner object to that view. If you examine an actual nib that holds a view controller’s main view, you’ll see that this is, in fact, the case. Look at our Empty Window project. Edit Main.storyboard. It has one scene, whose nib owner object is the View Controller object. Select the View Controller in the document outline. Switch to the Identity inspector. It tells us that the nib owner object’s class is indeed ViewController! Now, still with the View Controller in the document outline selected, switch to the Connections inspector. It tells us that there is indeed an outlet connection from the View Controller to the View object, and that this is outlet is indeed named "view"! If you hover the mouse over that outlet connection, the View object in the canvas is highligh‐ ted, to help you identify it. That explains completely how this view controller gets its main view! The storyboard scene associates this view controller instance with the view nib containing this view. When the view controller needs its main view (because that view is about to be displayed Connections | 327 in the interface), the view nib loads — with the view controller as owner. Thus, the view controller’s view property is set to the view that we design here. The view is then dis‐ played in the interface — and that’s why the design that you construct here actually appears in the running app. The same sort of thing is true in our Truly Empty project from Chapter 6. Edit My‐ ViewController.xib. The nib owner object is the File’s Owner proxy object. Select the File’s Owner object. Switch to the Identity inspector. It tells us that the nib owner object’s class is MyViewController! Switch to the Connections inspector. It tells us that there is an outlet connection to the View object, called "view"! That explains how this view controller gets its main view. We told this view controller where to find its nib when we instantiated it by saying MyViewController(nibName:"My- ViewController", bundle:nil). But the nib itself was already correctly configured, because Xcode set it up that way when we created the MyViewController class and checked the “Also create XIB file” checkbox. The view controller loads the nib with itself as owner, and the outlet works: the view from the nib file becomes the view controller’s view, and appears in the interface. Misconfigured Outlets Setting up an outlet to work correctly involves several things being true at the same time. I guarantee that at some point in the future you will fail to get this right, and your outlet won’t work properly. Don’t be offended, and don’t be afraid; be prepared! This happens to everyone. The important thing is to recognize the symptoms so that you know what’s gone wrong. We’re deliberately going to make things go wrong, so that we can explore the main ways that an outlet can be incorrectly configured: Outlet name doesn’t match a property name in the source class Start with our working Empty Window example. Run the project to prove that all is well. Now, in ViewController.swift, change the property name to vv: @IBOutlet var vv : UIView! = nil In order to get the code to compile, you’ll also have to change the reference to this property in viewDidLoad: self.view.addSubview(self.vv) The code compiles just fine. But when you run it, the app crashes with this message in the console: “This class is not key value coding-compliant for the key v.” That message is just a technical way of saying that the name of the outlet in the nib (which is still v) doesn’t match the name of a property of the nib’s owner when the nib loads — because we changed the name of that property to vv and thus wrecked the configuration. In effect, we had everything set up correctly, but then we went behind the nib editor’s back and removed the corresponding instance property from 328 | Chapter 7: Nib Management the outlet source’s class. When the nib loads, the runtime can’t match the outlet’s name with any property in the outlet’s source — the ViewController instance — and we crash. There are other ways to bring about this same misconfiguration. For example, you could change things so that the nib owner is an instance of the wrong class: NSBundle.mainBundle().loadNibNamed("View", owner: nil, options: nil) We made the owner argument nil, so a generic NSObject instance is supplied. The effect is the same: the NSObject class has no property with the same name as the outlet, so the app crashes when the nib loads, complaining about the owner not being “key value coding-compliant.” No outlet in the nib Fix the problem from the previous example by changing both references to the property name from vv back to v in ViewController.swift. Run the project to prove that all is well. Now we’re going to mess things up at the other end! Edit View.xib. Select the File’s Owner and switch to the Connections inspector, and disconnect the v outlet by clicking the X at the left end of the second cartouche. Run the project. We crash with this error message in the console: “Fatal error: unexpectedly found nil while unwrapping an Optional value.” We removed the outlet from the nib. So when the nib loaded, our ViewController instance property v, which is typed as an implicitly unwrapped Optional wrapping a UIView (UIView!), was never set to anything. Thus, it kept its initial value, which is nil. We then tried to use the implicitly unwrapped Optional by putting it into the interface: self.view.addSubview(self.v) Swift tries to obey by unwrapping the Optional for real, but you can’t unwrap nil, so we crash. No view outlet For this one, you’ll have to use the Truly Empty example from Chapter 6, where we load a view controller’s main view from a .xib file; I can’t demonstrate the problem using a .storyboard file, because the storyboard editor guards against it. In the Truly Empty project, edit the MyViewController.xib file. Select the File’s Owner object, switch to the Connections inspector, and disconnect the view outlet. Run the project. We crash at launch time: “Loaded the ‘MyViewController’ nib but the view outlet was not set.” The console message says it all. A nib that is to serve as the source of a view con‐ troller’s main view must have a connected view outlet from the view controller (the nib owner object) to the view. Connections | 329 Deleting an Outlet Deleting an outlet coherently — that is, without causing one of the problems described in the previous section — involves working in several places at once, just as creating an outlet does. I recommend proceeding in this order: 1. Disconnect the outlet in the nib. 2. Remove the outlet declaration from the code. 3. Attempt compilation and let the compiler catch any remaining issues for you. Let’s suppose, for example, that you decide to delete the v outlet from the Empty Window project. You would follow the same three-step procedure that I just outlined: 1. Disconnect the outlet in the nib. To do so, edit View.xib, select the source object (the File’s Owner proxy object), and disconnect the v outlet in the Connections inspector by clicking the X. 2. Remove the outlet declaration from the code. To do so, edit ViewController.swift and delete or comment out the @IBOutlet declaration line. 3. Remove other references to the property. The easiest way is to attempt to build the project; the compiler issues an error on the line referring to self.v in View‐ Controller.swift, because there is now no such property. Delete or comment out that line, and build again to prove that all is well. More Ways to Create Outlets Earlier, we created an outlet by first declaring an instance property in a class file, and then, in the nib editor, by control-dragging from the source (an instance of that class) to the destination in the document outline and choosing the desired outlet property from the HUD (heads-up display). Xcode provides many other ways to create outlets — too many to list here. I’ll survey some of the most interesting. We’ll continue to use the Empty Window project and the View.xib file. Keep in mind that all of this works exactly the same way for a .storyboard file. To prepare, delete the outlet in View.xib using the Connections inspector (if you haven’t already done so). In ViewController.swift, create (or uncomment) the property declara‐ tion, and save: @IBOutlet var v : UIView! = nil Drag from source Connections inspector You can drag from a circle in the Connections inspector in the nib editor to connect the outlet. In View.xib, select the File’s Owner and switch to the Connections in‐ spector. The v outlet is listed here, but it isn’t connected: the circle at its right is 330 | Chapter 7: Nib Management open. Drag from the circle next to v to the UIView object in the nib. You can drag to the view in the canvas or in the document outline. You don’t need to hold the Control key as you drag from the circle, and there’s no HUD because you’re dragging from a specific outlet, so Xcode knows which one you mean. Drag from destination Connections inspector Now let’s make that same move the other way round. Delete the outlet in the nib. Select the View and look at the Connections inspector. We want an outlet that has this view as its destination: that’s a “referencing outlet.” Drag from the circle next to New Referencing Outlet to the File’s Owner object. The HUD appears: click v to make the outlet connection. Drag from source HUD You can summon a HUD that effectively is the same as the Connections inspector. Let’s start with that HUD. Again delete the outlet in the Connections inspector. Control-click the File’s Owner. A HUD appears, looking a lot like the Connections inspector! Drag from the circle at the right of v to the UIView. Drag from destination HUD Again, let’s make that same move the other way round. Delete the outlet in the Connections inspector. Either in the canvas or in the document outline, Control- click the view. There’s the HUD showing its Connections inspector. Drag from the New Referencing Outlet circle to the File’s Owner. A second HUD appears, listing possible outlets; click v. Again, delete the outlet. Now we’re going to create the outlet by dragging between the code and the nib editor. This will require that you work in two places at once: you’re going to need an assistant pane. In the main editor pane, show ViewController.swift. In the assistant pane, show View.xib, in such a way that the view is visible. Drag from property declaration to nib Next to the property declaration in the code, in the gutter, is an empty circle. What do you think it’s for? Drag from it right across the barrier to the View in the nib editor (Figure 7-12). The outlet connection is formed in the nib; you can see this by looking at the Connections inspector, and also because, back in the code, the circle in the gutter is now filled in. Hover over the filled circle, or click it, to learn what the outlet in the nib is connected to. You can click the little menu that appears when you click in the filled circle to navigate to the destination object. Here’s one more way — the most amazing of all. Keep the two-pane arrangement from the preceding example. Again, delete the outlet (you will probably need to use the Con‐ nections inspector or HUD in the nib editor pane to do this). Also delete the @IBOutlet line from the code! We’re going to create the property declaration and connect the outlet, all in a single move! Connections | 331 Figure 7-12. Connecting an outlet by dragging from code to nib editor Figure 7-13. Creating an outlet by dragging from nib editor to code Drag from nib to code Control-drag from the view in the nib editor across the pane boundary to just inside the body of the class ViewController declaration. A HUD offers to Insert Outlet or Outlet Collection (Figure 7-13). Release the mouse. A popover appears, where you can configure the declaration to be inserted into your code. Configure it as shown in Figure 7-14: you want an outlet, and this property should be named v. Click Connect. The property declaration is inserted into your code, and the outlet is connected in the nib, in a single move. 332 | Chapter 7: Nib Management Figure 7-14. Configuring a property declaration Making an outlet by connecting directly between code and the nib editor is ex‐ tremely cool and convenient, but don’t be fooled: there’s no such direct connec‐ tion. There are always, if an outlet is to work properly, two distinct and separate things — an instance property 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 and classes that allows the two to be matched at runtime when the nib loads, so that the instance property is properly set at that moment. Xcode tries to help you get everything set up correctly, but it is not in fact magically connecting the code to the nib. Outlet Collections An outlet collection is an array instance property (in code) matched (in a nib) by multiple connections to objects of the same type. For example, suppose a class contains this property declaration: @IBOutlet var arr: [UIView]! The outcome is that, in the nib editor, using an instance of this class as a source object, you find that the Connections inspector lists arr — not under Outlets, but under Outlet Collections. This means that you can form multiple arr outlets, each one connected to a different UIView object in the nib. When the nib loads, those UIView instances become the elements of the array arr; the order in which the outlets are formed is the order of the elements in the array. The advantage of this arrangement is that your code can refer to multiple interface objects instantiated from the nib by number (the index into the array) instead of your having to devise and manipulate a separate name for each one. This turns out to be particularly useful when forming outlets to such things as autolayout constraints and gesture recognizers. Connections | 333 Action Connections In addition to outlet connections in a nib, there are also action connections. An action connection, like an outlet connection, is a way of giving one object in a nib a reference to another. It’s not a property reference; it’s a message-sending reference. An action is a message emitted automatically by a Cocoa UIControl interface object (a control), and sent to another object, 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 mes‐ sage are called events. To see a list of possible events, look at the UIControl class docu‐ mentation, under “Control Events.” For example, in the case of a UIButton, the user tapping the button corresponds to the UIControlEvents.TouchUpInside event. For this architecture to work, the control object must know three things: • What control event to respond to • What message to send (method to call) when that control event occurs (the action) • What object to send that message to (the target) An action connection in a nib builds the knowledge of those three things into itself. It has the control object as its source; its destination is the target; and you tell the action connection, as you form it, what the control event and action message should be. To form the action connection, you need first to configure the class of the destination object so that it has a method suitable as an action message. To experiment with action connections, we’ll need a UIControl object in a nib, such as a button. You may already have such a button in the Empty Window project’s Main.storyboard file. However, it’s probable that, when the app runs, we’ve been covering the button with the view that we’re loading from View.xib. So first clear out the View- Controller class declaration body in ViewController.swift, so that there is no outlet property and no manual nib-loading code; this should be all that’s left: class ViewController: UIViewController { } Now let’s arrange to use the view controller in our Empty Window project as a target for an action message emitted by the button’s UIControlEvents.TouchUpInside event (meaning that the button was tapped). We’ll need a method in the view controller that will be called by the button when the button is tapped. To make this method dramatic and obvious, we’ll have the view controller put up an alert window. Insert this method into the ViewController.swift declaration body: class ViewController: UIViewController { @IBAction func buttonPressed(sender:AnyObject) { let alert = UIAlertController( title: "Howdy!", message: "You tapped me!", preferredStyle: .Alert) alert.addAction( 334 | Chapter 7: Nib Management UIAlertAction(title: "OK", style: .Cancel, handler: nil)) self.presentViewController(alert, animated: true, completion: nil) } } The @IBAction attribute is like @IBOutlet: it’s a hint to Xcode itself, asking Xcode to make this method available in the nib editor. And indeed, if we look in the nib editor, we find that it is now available: edit Main.storyboard, select the View Controller object and switch to the Connections inspector, and you’ll find that buttonPressed: is now listed under Received Actions. In Main.storyboard, in the single scene that it contains, the top-level View Controller’s View should contain a button. (We created it earlier in this chapter: see Figure 7-5.) If it doesn’t, add one, and position it in the upper left corner of the view. Our goal now is to connect that button’s Touch Up Inside event, as an action, to the buttonPressed: method in ViewController. As with an outlet connection, there is a source and a destination. The source here is the button; the destination is the representative of ViewController in the storyboard — View Controller, the owner of the nib containing the button. There are many ways to form this outlet connection, all of them completely parallel to the formation of an action connection. The difference is that we must configure both ends of the connection. At the button (source) end, we must specify that the control event we want to use is Touch Up Inside; fortunately, this is the default for a UIButton, so we might be able to skip this step. At the view controller (destination) end, we must specify that the action method to be called is buttonPressed:. For example, let’s form the action connection by simply Control-dragging from the button to the view controller in the nib editor: 1. Control-drag from the button (in the canvas or in the document outline) to the View Controller listing in the document outline (or to the view controller icon in the scene dock above the view in the canvas). 2. A HUD listing possible connections appears (Figure 7-15); it lists mostly segues, but it also lists Sent Events, and buttonPressed: in particular. 3. Click the buttonPressed: listing in the HUD. The action connection has now been formed. This means that when the app runs, any time the button gets a Touch Up Inside event — meaning that it was tapped — it will send the action message buttonPressed: to the target, which is the view controller instance. We know what that method should do: it should put up an alert. Try it! Build and run the app, and when the app appears in the Simulator, tap the button. It works! Connections | 335 Figure 7-15. A HUD showing an action method More Ways to Create Actions Other ways in which you can form the action connection in the nib, having created the action method in ViewController.swift, include the following: • Control-click the view controller. A HUD appears, similar to the Connections in‐ spector. Drag from buttonPressed: (under Received Actions) to the button. An‐ other HUD appears, listing possible control events. Click Touch Up Inside. • Select the button and use the Connections inspector. Drag from the Touch Up Inside circle to the view controller. A HUD appears, listing the known action methods in the view controller; click buttonPressed:. • Control-click the button. A HUD appears, similar to the Connections inspector. Proceed as in the previous case. • Arrange to see ViewController.swift in one pane and the storyboard in the other. The buttonPressed: method in ViewController.swift has a circle to its left, in the gutter. Drag from that circle across the pane boundary to the button in the nib. As with an outlet connection, the most impressive way to make an action connection is to drag from the nib editor to your code, inserting the action method and forming the action connection in the nib in a single move. To try this, first delete the button- Pressed: method in your code and delete the action connection in the nib. Arrange to see ViewController.swift in one pane and the storyboard in the other. Now: 1. Control-drag from the button in the nib editor to an empty area in the View‐ Controller class declaration’s body. A HUD offering to create an outlet or an ac‐ tion appears in the code. Release the mouse. 2. The popover view appears. This is the tricky part. By default, the popover view is offering to create an outlet connection. That isn’t what you want; you want an action connection! Change the Connection pop-up menu to Action. Now you can enter 336 | Chapter 7: Nib Management Figure 7-16. Configuring an action method declaration the name of the action method (buttonPressed) and configure the rest of the dec‐ laration (the defaults are probably good enough: see Figure 7-16). Xcode forms the action connection in the nib, and inserts a stub method into your code: @IBAction func buttonPressed(sender: AnyObject) { } The method is just a stub (Xcode can’t read your mind and guess what you want the method to do), so in real life, at this point, you’d insert some functionality between those curly braces. As with an outlet connection, the filled circle next to the code in an action method tells you that Xcode believes that this connection is correctly configured, and you can click the filled circle to learn, and navigate to, the object at the source of the connection. Misconfigured Actions As with an outlet connection, an action configuration involves setting things up cor‐ rectly at both ends (the nib and the code) so that they match. Thus, you can wreck an action connection’s configuration and crash your app. The typical misconfiguration is that the name of the action method as embedded in the action connection in the nib no longer matches the name of the action method in the code. To see this, change the name of the function in the code from buttonPressed to some‐ thing else, like buttonPushed. Now run the app and tap the button. Your app crashes, displaying in the console the dreaded error message, “Unrecognized selector sent to instance.” A selector is a message — the name of a method. The runtime tried to send a message to an object, but that object turned out to have no corresponding method (because we renamed it). If you look a little earlier in the error message, it even tells you the name of this method: -[Empty_Window.ViewController buttonPressed:] Connections | 337 The runtime is telling you that it tried to call the buttonPressed: method in your Empty Window module’s ViewController class, but the ViewController class has no button- Pressed: method. Connections Between Nibs — Not! You cannot draw an outlet connection or an action connection between an object in one nib and an object in another nib. For example: • You can’t open nib editors on two different .xib files and Control-drag a connection from one to the other. • In a .storyboard file, you cannot Control-drag a connection between an object in one scene and an object in another scene. If you expect to be able to do this, you haven’t understood what a nib is (or what a scene is, or what a connection is). The reason is simple: objects in a nib together will become instances together, at the moment when the nib loads, so it makes sense to connect them in the nib, because we know what instances we’ll be talking about when the nib loads. The two objects may both be instantiated from the nib, or one of them may be a proxy object (the nib owner), but they must both be represented in the same nib, so that the actual instances can be configured in relation to one another on a particular occasion when this nib loads. If an outlet connection or an action connection were drawn from an object in one nib to an object in another nib, there would be no way to understand what actual future instances the connection is supposed to connect, because they are different nibs and will be loaded at different times (if ever). The problem of communicating between an instance generated from one nib and an instance generated from another nib is a special case of the more general problem of how to communicate between instances in a pro‐ gram, discussed in Chapter 13. Additional Configuration 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 properties. Nevertheless, you might want to append your own code to the initi‐ alization process as an object is instantiated from a loading nib. This section describes some ways you can do that. A common situation is that a view controller, functioning as the owner when a nib containing its main view loads (and therefore represented in the nib by the nib owner object), has an outlet to an interface object instantiated from the nib. In this architecture, 338 | Chapter 7: Nib Management the view controller can perform further configuration on that interface object, because it has a reference to it after the nib loads — the corresponding instance property. The earliest place where it can perform such configuration is its viewDidLoad method. At the time viewDidLoad is called, the view controller’s view has loaded — that is, the view controller’s view property has been set to its actual main view, instantiated from the nib — and all outlets have been connected; but the view is not yet in the visible interface. Another possibility is that you’d like the nib object to configure itself, over and above whatever configuration has been performed in the nib. Often, this will be because you’ve got a custom subclass of a built-in interface object class — in fact, you might want to create a custom class, just so you have a place to put this self-configuring code. The problem you’re trying to solve might be that the nib editor doesn’t let you perform the configuration you’re after, or that you have many objects that need to be configured in some identical, elaborate way, so that it makes more sense for them to configure them‐ selves by virtue of sharing a common class than to configure each one individually in the nib editor. One approach is to implement awakeFromNib in your custom class. The awakeFrom- Nib message is sent to all nib-instantiated objects just after they are instantiated by the loading of the nib: the object has been initialized and configured and its connections are operational. For example, let’s make a button whose background color is always red, regardless of how it’s configured in the nib. (This is a nutty example, but it’s dramatically effective.) In the Empty Window project, we’ll create a button subclass, RedButton: 1. In the Project navigator, choose File → New → File. Specify iOS → Source → Cocoa Touch Class. Click Next. 2. Call the new class RedButton. Make it a subclass of UIButton. Click Next. 3. Make sure you’re saving into the project folder, with the Empty Window group, and make sure the Empty Window app target is checked. Click Create. Xcode creates RedButton.swift. 4. In RedButton.swift, inside the body of the RedButton class declaration, implement awakeFromNib: override func awakeFromNib() { super.awakeFromNib() self.backgroundColor = UIColor.redColor() } We now have a UIButton subclass that turns itself red when it’s instantiated from a nib. But we have no instance of this subclass in any nib. Let’s fix that. Edit the storyboard, select the button that’s already in the main view, and use the Identity inspector to change this button’s class to RedButton. Additional Configuration of Nib-Based Instances | 339 Figure 7-17. Rounding a button’s corners with a runtime attribute Now build and run the project. Sure enough, the button is red! A further possibility is to take advantage of the User Defined Runtime Attributes in the nib object’s Identity inspector. This can allow you to configure, in the nib editor, aspects of a nib object for which the nib editor itself provides no built-in interface. What you’re actually doing here is sending the nib object, at nib-loading time, a setValue:forKey- Path: message; key paths are discussed in Chapter 10. Naturally, the object needs to be prepared to respond to the given key path, or your app will crash when the nib loads. For example, one of the disadvantages of the nib editor is that it provides no way to configure layer attributes. Let’s say we’d like to use the nib editor to round the corners of our red button. In code, we would do that by setting the button’s layer.corner- Radius property. The nib editor gives no access to this property. Instead, we can select the button in the nib editor and use the User Defined Runtime Attributes in the Identity inspector. We set the Key Path to layer.cornerRadius, the Type to Number, and the Value to whatever value we want — let’s say 10 (Figure 7-17). Now build and run; sure enough, the button’s corners are now rounded. New in Xcode 6, you can configure a custom property of a nib object by making that property inspectable. To do so, add the @IBInspectable attribute to the property’s dec‐ laration in your code. This causes the property to be listed in the nib object’s Attributes inspector. For example, let’s make it possible to configure our button’s border in the nib editor. At the start of the RedButton class declaration body, add this code: @IBInspectable var borderWidth : CGFloat { get { return self.layer.borderWidth } 340 | Chapter 7: Nib Management Figure 7-18. An inspectable property in the nib editor set { self.layer.borderWidth = newValue } } That code declares a RedButton property, borderWidth, and makes it a façade in front of the layer’s borderWidth property. It also causes the nib editor to display that property in the Attributes inspector for any button that is an instance of the RedButton class (Figure 7-18). The result is that when we give this property a value in the nib editor, that value is sent to the setter for this property at nib-loading time, and the button border appears with that width. To intervene with a nib object’s initialization even earlier, if the object is a UIView (or a UIView subclass), you can implement init(coder):. Note that, for a UIView, init(frame:) is not called during instantiation by the loading of a nib — init(coder:) is called instead. (Implementing init(frame:), and then wondering why your code isn’t called when the view is instantiated from a nib, is a common beginner mistake.) A minimal implementation would look like this: required init(coder aDecoder: NSCoder) { super.init(coder:aDecoder) // your code here } Additional Configuration of Nib-Based Instances | 341 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 CHAPTER 8 Documentation No aspect of iOS programming is more important than a fluid and nimble relationship with the documentation. There is a huge number of built-in Cocoa 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 doc set; you subscribe to it, so that when Apple releases a documentation update, 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) may require an Internet connection, so that you can see the online docs at Apple’s site. This situation is untenable; you’re going to want a copy of the documen‐ tation locally, on your own machine. Therefore, you should start up Xcode immediately after installation to let it download and install your initial doc sets. The process can be controlled and monitored, to some extent, in the Downloads pane of the Preferences window (under Documentation); 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 also where you specify which doc sets you want; I believe that the iOS 8 doc set and the Xcode 6 doc set are all you need for iOS development, but it can’t hurt to install the OS X 10.10 doc 343 set as well. You may have to provide your machine’s admin password when a doc set is first installed. Doc sets are installed in your home Library/Developer/Shared/Documen‐ tation/DocSets directory. The Documentation Window Your primary access to the documentation is in Xcode, through the documentation window (Window → Documentation and API Reference, or Help → Documentation and API Reference, Command-Shift-0). Within the documentation window, the pri‐ mary way into the documentation is to do a search; for example, press Command-Shift-0 (or Command-L if you’re already in the documentation window), type NSString, and press Return to select the top hit, which is the NSString Class Reference. Click the magnifying glass icon to limit the results to the iOS-related doc sets if desired. There are two ways to see the results of a search in the documentation window: Pop-up results window If you’re actively typing in the search field, a dozen or so primary results are listed in a pop-up window. Click with the mouse, or navigate with arrow keys and press Return, to specify which result you want to view. You can also summon and hide this pop-up window by pressing Esc whenever the search field has focus. Full results page When the search field has focus and the pop-up results window is not showing, press Return to see a page listing all results of the search; these results are listed on four separate pages, by category: API Reference, SDK Guides, Tools Guides, and Sample Code. You can also perform a documentation window search starting from within your code. You’ll very often want to do this: you’re looking directly at a symbol (a class name, a method name, a property name, and so on) at its point of use in your code, and you want to know more about it. Hold Option and hover the mouse over a term in your code until a blue dotted underline appears; then (still holding Option) double-click the term. The documentation window opens, and you are taken directly to the explanation of that term within its class documentation page. (Similarly, during code completion — discussed in Chapter 9 — you can click the More link to make this same move, jumping directly to the documentation on the current symbol.) Alternatively, you can select text in your code (or anywhere else) and choose Help → Search Documentation for Selected Text (Command-Option-Control-/). This is the equivalent of typing that text into the search field in the documentation window and asking to see the full results page. The documentation window behaves basically as a glorified web browser, because the documentation consists essentially of web pages. Multiple pages can appear simultane‐ 344 | Chapter 8: Documentation ously as tabs in the documentation window. To navigate to a new tab, hold Command as you navigate — for example, Command-click a link, or Command-click your choice in the pop-up results window — or choose Open Link in New Tab from the contextual menu. You can navigate between tabs (Window → Show Next Tab), and each tab re‐ members its navigation history (Navigate → Go Back, or use the Back button in the window toolbar, which is also a pop-up menu). A documentation page may be accompanied by a list of related items. The start of the list is shown in a pane above the page; the full list appears in a popover when you click the “More related items” link (Figure 8-1). For example, the related items pane for the NSString Class Reference page includes links to NSString’s class inheritance and its adopted protocols, with further information and links in the popover. I’ll talk more about a class’s related items later in this chapter. A documentation page may be accompanied by a table of contents, displayed in a pane to the left of the documentation page (Figure 8-1); to see it if it isn’t showing, choose Editor → Show Table of Contents, or click the Table of Contents icon in the window toolbar. For example, the NSString Class Reference page has a table of contents pane linking to all the topics and methods listed within the page. Some documentation pages may use the table of contents to show the page’s place within a larger group of pages; for example, the String Programming Guide consists of multiple pages, and when you’re viewing one, the Table of Contents pane lists all the pages of the String Programming Guide along with each page’s main topics. A full hierarchical table of contents for all doc sets (the library) appears at the far left of the documentation window; to see it if it isn’t showing, choose Editor → Show Library, or click the Navigator button in the window toolbar. The hierarchy shows all reference documents, along with guides and sample code, clumped together by subject. When viewing a documentation page, to show it in its place within the full hierarchical table of contents, choose Editor → Reveal in Library (or choose Reveal in Library from the contextual menu). When you encounter a documentation page to which you’re likely to want to return, make it a bookmark: choose Editor → Share → Add Bookmark, or click the Share button in the toolbar and choose Add Bookmark, or choose Add Bookmark from the contextual menu, or (easiest of all) click the bookmark icon in the left margin of the documentation page. Bookmarks are displayed at the left of the documentation window, sharing space in the navigator with the full hierarchical table of contents; to see the bookmarks pane if it isn’t showing, choose Editor → Show Bookmarks. Icons at the top of the navigator let you switch between the library pane and the bookmarks pane. Click a bookmark in the bookmarks pane to jump to it in the documentation window. Bookmark manage‐ ment is simple but effective: you can rearrange bookmarks or delete a bookmark, and that’s all. The Documentation Window | 345 Figure 8-1. The start of the UIButton class documentation page To search for text within the current documentation page, use the Find menu com‐ mands. Find → Find (Command-F) summons a find bar, as in Safari. A third-party documentation viewer application, such as Dash (http://kapeli.com/ dash), may provide better searchability and a better view of your local doc sets than the documentation window does. Also, most of the documentation can be accessed using a real web browser at http://developer.apple.com, Apple’s develop‐ er site; this web browser display allows sections to be shown and hidden, it in‐ cludes an alphabetic searchable index of methods and properties, and it may even show information that the documentation window omits. Class Documentation Pages In the vast majority of cases, your target documentation page will be the documentation for a class. It’s important to be comfortable and conversant with the typical features and information provided by a class documentation page, so let’s pause to notice them (Figure 8-1). It’s important to keep an eye on the related items information when you’re studying a class (click the “More related items” link to see it): 346 | Chapter 8: Documentation Inherits from Lists, and links to, the chain of superclasses. One of the biggest beginner mistakes is failing to consult 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 adopted by this class. Failing to consult the docu‐ mentation for adopted protocols is a serious beginner mistake. For example, you won’t find out that UIViewController gets a viewWillTransitionToSize:with- TransitionCoordinator: event by looking at the UIViewController class docu‐ mentation page: you have to look in the documentation for the UIContentCon‐ tainer protocol, which UIViewController adopts. Framework Tells what framework this class is part of. Your code must link to this framework, and import this framework’s header, in order to use this class; in Swift, it will typi‐ cally be sufficient to import the framework by its module name (see Chapter 6). Availability States the earliest version of the operating system where this class is implement‐ ed. For example, UIAlertController wasn’t invented until iOS 8. So if you want to use this feature in your app, you must make sure either that your app targets only iOS 8 or later, or that your code never uses this class when your app is running on an earlier system. 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 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 the project window, as explained later in this chapter. Related documents If a class documentation page lists a related guide, you might want to click that link and read that guide. For example, the UIView class documentation page lists (and links to) the View Programming Guide for iOS. Guides are broad surveys of a topic; they provide important information (including, often, useful code examples), and they can serve to orient your thinking and make you aware of your options. Class Documentation Pages | 347 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.) The body of the class documentation page is divided into sections, which are listed in the table of contents pane: 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 documentation page for an example.) Tasks This section lists, clumped into categories, the properties and methods of this class. Constants Many classes define constants that accompany particular methods. For example, to create a UIButton instance in code, you can 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.) Finally, let’s talk about how a class documentation page lists and explains individual properties and methods. In recent years, this part of the documentation has become quite splendid, with good hyperlinks. Note the following subsections, after the property or method name: Description A short summary of what the property or method does. Formal declaration Read this to learn things like the method’s parameters and return type. Parameters and Return Value Precise information on the meaning and purpose of these. Discussion Often contains extremely important further details about how this method behaves. Always pay attention to this section! Import Statement Shows the module that must be imported to access this method or property. 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. 348 | Chapter 8: Documentation See Also Links to related methods and properties. Very helpful for giving you a larger per‐ spective on how this method fits into the overall behavior of this class. 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, awake- FromNib (discussed in Chapter 7) isn’t mentioned in the documentation for UI‐ Button or for any of its superclasses or protocols. This is a major weakness in Apple’s organization and display of the documentation. 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 file at a time, so it’s difficult to get an overview. The alternative is to open the sample code project in Xcode; click the Open Project link at the top of a sample code page in the documentation window. If you’re looking at the sample code in your browser at http:// developer.apple.com, there’s a Download Sample Code button. With the sample code project open as a project window, you can read the code, navigate it, edit it, and of course run the project. 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 uneven. Some of it is a bit careless or even faulty, while some of it is astoundingly well-written. It is generally thoughtful and instructive, though, and is definitely a major component of the documentation; it de‐ serves 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. 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 Sample Code | 349 insertion point automatically in the Quick Help inspector (Command-Option-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 in the nib editor, for build settings while editing a project or target, and so forth. Quick Help documentation can also be displayed as a popover window, without the Quick Help inspector. Select a term and choose Help → Quick Help for Selected Item (Command-Control-Shift-?). 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. When you’re developing Swift code, Quick Help is of increased importance. If you click in the name of a Swift variable whose type is inferred, Quick Help shows the inferred type (see Figure 3-1). This can help you understand compile errors and other surprises. 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. You can inject documentation for your own Swift code into Quick Help. To do so, pre‐ cede a declaration with a comment enclosed in /**...*/. The comment becomes the Description field for Quick Help. Within the comment, some paragraph formatting can be used, and some additional fields can be specified, but unfortunately the syntax has not been formally documented, so you have to use guesswork and trial-and-error; it appears to be a form of reStructuredText (see http://docutils.sourceforge.net/docs/ user/rst/quickref.html). For example, here’s a function declaration with a preceding comment: /** Many people would like to dog their cats. So it is perfectly reasonable to supply a convenience method to do so: * Because it's cool. * Because it's there. :param: cats A string containing cats :returns: A string containing dogs */ 350 | Chapter 8: Documentation Figure 8-2. Custom documentation injected into Quick Help func dogMyCats(cats:String) -> String { return "Dogs" } The double asterisk in the opening comment delimiter denotes that this is documen‐ tation, and the comment’s location automatically associates it with the dogMyCats method whose definition follows. The asterisked paragraphs will become bulleted para‐ graphs; the colon-delimited expressions :param: and :returns: correspond to addi‐ tional Quick Help fields. The outcome is that when dogMyCats is selected anywhere in my code, its documentation is displayed in Quick Help (Figure 8-2). The first part of the description is also displayed as part of code completion (see Chapter 9). Symbols A symbol is a declared term, such as the name of a function, object type, or variable. If you can see the name of a symbol in your code in an editor in Xcode, you can jump quickly to the declaration of the symbol. Select text and choose Navigate → Jump to Definition (Command-Control-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 decla‐ ration for that symbol. When you do: • If the symbol is declared in your code, you jump to that declaration in your code; this can be helpful not only for understanding your code but also for navigating it. • If the symbol is declared in a framework, you jump to the declaration in the header file. If you started in a .swift file, the header file that you jump to is translated into Swift. (I’ll talk more about header files in the next section.) Symbols | 351 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 Navigation pane of Xcode’s preferences. By default, Command-click jumps in the same editor, Command-Option- click jumps in an assistant pane, and Command-double-click jumps in a new window. Similarly, Command-Option-Control-J jumps in an assistant pane to the declaration of the selected term. Another way to see a list of your project’s symbols, and to navigate to a symbol decla‐ ration, is through the Symbol navigator (Chapter 6). If the second icon in the filter bar is highlighted, these are symbols declared in your project; if not, symbols from imported frameworks are listed as well. To jump to the declaration of a symbol whose name you know, even if you don’t see the name in the code before you, choose File → Open Quickly (Command-Shift-O). In the search field, type key letters from the name, which will be interpreted intelligently; for example, to search for application:didFinishLaunchingWithOptions:, you might type appdidf. Possible matches are shown in a scrolling list below the search field; you can navigate this list with the mouse or by keyboard alone. Besides declarations from the framework headers, declarations in your own code are listed as well, so this, too, can be a rapid way of navigating your code. Header Files Often, a header file can be a useful form of documentation — possibly the most useful form of documentation. The header is, of necessity, accurate, up-to-date, and complete; the class documentation is not. A header consists chiefly of declarations, but it may also contain comments with helpful information; this, too, can tell you things that the class documentation might not. Also, a single header file can contain declarations for multiple classes and protocols. So it can be an excellent quick reference. The simplest way to reach a header file is to jump to the declaration of a symbol there. For example, to reach NSString.h — the Foundation.NSString header file — Command-click on the term NSString wherever it may appear in your code. See the previous section for the various ways of jumping to a symbol declaration; since most symbols are declared in header files, these are ways of reaching header files. When you jump to a header file from your code, if the code that you started from was a Swift file, the header file, if it is written in Objective-C, is spontaneously translated into Swift. That’s good because it tells you what you can say in Swift. But it’s bad if you were hoping to get a look at the actual Objective-C header! I sometimes add an Objective-C class to my Swift project for the sole purpose of providing a jumping-off place so that I can reach a Cocoa header without passing through the Swift translation. In the case of the Swift language itself, the Swift header file is crucial. It’s full of numerous object types and functions that you can’t find out about any other way. For example, in 352 | Chapter 8: Documentation Chapter 3, I mentioned the global contains function. How did I find out about this? Not from Apple’s Swift Standard Library Reference; it isn’t listed there. I found out from the Swift header file. There are also special Swift header files for Core Graphics and Foundation. A useful trick is to write an import statement just so that you can Command-click it to reach a header. For example, if you import Swift at the top of a .swift file, the word Swift itself is a symbol that you can Command-click to jump to the Swift header. 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. For example, you can download iTunes videos, including the videos for all WWDC 2014 sessions (as well as for some earlier years). Apple also 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). 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 ar‐ chives the lists. Apple has not added a mailing list devoted to iOS programming; that’s what the Apple developer forums are supposed to be for (https://devforums.apple.com). As a registered iOS developer, you have access to these. Some interesting discussions certainly do take place here, and they are patrolled by some very helpful Apple employees; but the inter‐ face 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. Internet Resources | 353 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: configuring your build settings and your Info.plist; editing, debugging, and testing your code; run‐ ning your app on a device; profiling; localization; and final preparations for the App Store. 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. You can change this setting later, using the Devices pop-up menu in the General tab when you edit the app target; but your life will be simpler if you decide correctly here, at the outset, because your decision can affect the details of the template on which your new project will be based. Your choice in the Devices pop-up menu also affects your project’s Targeted Device Family build setting: iPad The app will run only on an iPad. 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 (Universal in the Devices pop-up menu) The app will run natively on both kinds of device. Two additional project-level build settings determine what systems your device will run on: 355 Base SDK The latest system your app can run on. As of this writing, in Xcode 6.3, you have just two choices, iOS 8.3 and Latest iOS (iOS 8.3). They sound the same, but the latter is better (and is the default for a new project). 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 most recent SDK as their Base SDK automatically, without your also having to update their Base SDK setting. iOS Deployment Target The earliest system your app can run on: in Xcode 6.3, this can be any major iOS system all the way back to iOS 4.3. To change the project’s iOS Deployment Target setting easily, edit the project and switch to the Info tab, and choose from the iOS Deployment Target pop-up menu. To test your app on an earlier system, you’ll need a device, real or simulated, run‐ ning an earlier system. You can download an iOS 7 SDK through Xcode’s Down‐ loads preference pane (see Chapter 6), but to test on a system earlier than that, you’ll need an older version of Xcode, or preferably an older device. Backward Compatibility Writing an app whose Deployment Target differs from its Base SDK — that is, an app that is backward compatible to an earlier system — 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 on which it is actually running. Thus, if you were to set the project’s Deployment Target to iOS 7, your project would compile and your app would run on iOS 7 even if it contained iOS 8–only features, but your app would crash on iOS 7 if any of those features were actually encountered. Changed behavior With each new system, Apple permits itself to change the way some features work. The result is that some features that exist on different systems may work differently depending what system it is. In some cases, the very same method may do two quite different things, depending on what system the app runs on. In other cases, an entire area of functionality may be handled differently on different systems, requiring you to implement or call a whole different set of methods or use a completely different set of classes. 356 | Chapter 9: Life Cycle of a Project Thus, backward compatibility will probably require that you write conditional code — that is, code such that one set of code executes when running on one system, another when running on another. There are various ways in which your app’s code can be executed conditionally based on the runtime environment: Explicit environment test The UIDevice class lets you query the current device (currentDevice) to learn its system version (systemVersion). Thus, for example: let v = UIDevice.currentDevice().systemVersion You could then run code conditionally based on whether the resulting version string is greater than or equal to "8.0". Member safety You can ask an object whether it is safe to send it a certain message. For example, there’s no point asking a UIViewController for its traitCollection on iOS 7; you’ll just crash if you do, because the traitCollection property was introduced in iOS 8. To find out if this is a safe move, you can use NSObject’s respondsTo- Selector: method (see also Chapter 10): if self.respondsToSelector("traitCollection") { let tc = self.traitCollection // ... } Class safety You’ll crash if you refer to a class that doesn’t exist. To learn whether a class exists, call the NSClassFromString function. It takes a string, so it’s safe — you’re not actually referring to the class — and it will return nil if the class doesn’t exist: if NSClassFromString("UITraitCollection") != nil { // safe to use UITraitCollection here ... } Constant safety Testing constant names is tricky, because it can’t be done using Swift alone. You’ll have to use an Objective-C helper method. You can then take the address of the name; if it is nil, it isn’t safe to use. For example: + (BOOL) safeToUseSettingsString { return &UIApplicationOpenSettingsURLString != nil; } I’ve implemented that class method in a category on UIApplication. Now I can call it from Swift: if UIApplication.safeToUseSettingsString() { // safe to refer to UIApplicationOpenSettingsURLString... } Device Architecture and Conditional Code | 357 Figure 9-1. Weak-linking a framework Framework safety If a framework doesn’t exist, it isn’t enough to refrain from referring to any of its classes and methods in code; you mustn’t try to link to the framework in the first place, or you’ll crash. The framework is autolinked, because you imported it by its module name (see Chapter 6), but you can solve the problem by weak-linking the framework. This means that the framework won’t really be linked unless code that needs it is encountered. To weak-link a framework, link to it explicitly in the target’s Link Binary With Libraries build phase, and then change the Required pop-up menu item in the Status column of its listing to Optional (Figure 9-1). A project can also contain other resources, such as a nib file, that might not be compatible with earlier systems. For example, a nib file that uses size classes will misbehave on iOS 7, because size classes were not introduced until iOS 8. Similarly, setting an image’s rendering mode in an asset catalog won’t have any effect in iOS 7, because that feature of asset catalogs was introduced in iOS 8. And the rules for required icon sizes and launch image configuration, discussed later in this chapter, have changed greatly from system to system. Device Type It can be useful, in the case of a universal app, to react to whether your code is running on an iPad, on the one hand, or an iPhone or iPod, on the other. The UIDevice — or, on iOS 8, the current trait collection — will tell you the current device’s type as its user- InterfaceIdiom, which will be a UIUserInterfaceIdiom, either .Phone or .Pad. You can load resources conditionally depending on the device type or screen resolution. The most common case is that of images. If an image is loaded from the top level of your app bundle, name suffixes can be used, such as @2x and @3x (to indicate screen resolution) or ~iphone and ~ipad (to indicate device type). In iOS 8, a better approach is to use the asset catalog. If an image set’s Devices pop-up menu is set to Universal, you get three slots for the image, 1x, 2x, and 3x, corresponding to the three possible screen resolutions; if it is set to Device Specific, you get two sets of slots, one for iPhone and one for iPad. By preparing your images in this way, a particular version of an image will 358 | Chapter 9: Life Cycle of a Project be loaded automatically when you call UIImage’s init(named:), appropriate to the current device’s screen resolution or type. Similarly, certain Info.plist settings come in multiple sets with name suffixes, so you can adopt one setting on one device type and another setting on another. It is quite common, for example, for a universal app to adopt one set of possible orientations on iPhone and another set on iPad: typically, the iPhone version permits a limited set of orientations and the iPad version permits all orientations. You can configure this in the General pane when you edit the target: 1. Switch the Devices pop-up menu to iPhone and check the desired Device Orien‐ tation checkboxes for the iPhone. 2. Switch the Devices pop-up menu to iPad and check the desired Device Orientation checkboxes for the iPad. 3. Switch the Devices pop-up menu to Universal. Even though you’re now seeing just one set of orientations, both sets are remembered. What you’ve really done is to configure two groups of “Supported interface orientations” settings in the Info.plist, a general set (UISupportedInterfaceOrientations) and an iPad-only set that overrides the general case when the app launches on an iPad (UISupportedInterfaceOrientations~ipad). Examine the Info.plist file to see that this is so. In the same way, your app can load different nib files, and thus different interfaces, depending on the device type. For example, you can have two main storyboards, loading one of them at launch if this is an iPhone and the other if this is an iPad. Again, you can configure this in the General pane when you edit the target, and again, what you’re really doing is telling the Info.plist setting “Main storyboard file base name” to appear twice, once for the general case (UIMainStoryboardFile) and once for iPad only (UIMain- StoryboardFile~ipad). If your app loads a nib file by name, the naming of that nib file works like that of an image file: if there is an alternative nib file by the same name with ~ipad appended, it will load automatically if we are running on an iPad. For example, if you load a nib by the name "View" and there’s a file View~ipad.xib in your project, that nib will load on iPad. If your app runs only on iOS 8 or later, however, you are less likely than in the past to need to distinguish one device type from another. In iOS 7 and before, entire interface object classes (such as popovers) were available only on the iPad; in iOS 8, there are no iPad-only classes, and the interface classes themselves adapt if your code is running on an iPhone. Similarly, in iOS 7 and before, a universal app might need a completely different interface, and hence a different set of nib files, depending on the device type; in iOS 8, size classes allow a single nib file to be configured conditionally depending on the device type. And in general the physical distinction between an iPad and an iPhone Device Architecture and Conditional Code | 359 is not so sharp as in the past: thanks to the intermediate iPhone 6 and (especially) the iPhone 6 Plus, it’s more of a continuum. Version Control Sooner rather than later in the life of any real app, you should consider putting your project under version control. Version control is a way of taking periodic snapshots (technically called commits) of your project. Its purpose might be: Security Version control can help 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. Collaboration Version control affords multiple developers ready, rational access to the same code. Freedom from fear A project is a complicated thing; often, changes must be made experimentally, sometimes in many files, possibly over a period of many days, before a new feature can be tested. Version control means that I can easily retrace my steps (to some previous commit) if things go badly; this gives me confidence to start down some tentative programmatic road whose outcome may not be apparent until much later. Also, if I’m confused about what programmatic road I seem to be taking, I can ask a version control system to list the changes I’ve made recently. If an ancillary bug is introduced, I can use version control to pinpoint when it happened and help discover the cause. Xcode provides various version control facilities, which are geared chiefly to git (http:// git-scm.com) and Subversion (http://subversion.apache.org, also called svn). 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. That’s no disaster; there are many other ways to use version control, and even with git and Subversion, it is perfectly possible to ignore Xcode’s integrated version control and rely on the command line in Terminal, or use a specialized third-party GUI front end such as svnX for Subversion (http://www.lachoseinteractive.net/en/products) or SourceTree for git (http://www.sourcetreeapp.com). If you don’t want to use Xcode’s integrated version control, you can turn it off more or less completely. If you uncheck Enable Source Control in the Source Control preference pane, the only thing you’ll be able to do is choose Check Out from the Source Control menu, to fetch code from a remote server. If you check Enable Source Control, three additional checkboxes let you select which automatic behaviors you want. Personally, I like to check Enable Source Control along with “Refresh local status automatically,” so 360 | Chapter 9: Life Cycle of a Project that Xcode displays a file’s status in the Project navigator; I leave the two additional checkboxes unchecked, because I’m a manual control kind of person. 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. This can be purely local to your computer, or you can choose a remote server. If you have no reason to decide otherwise, I suggest that you check that checkbox! When you open an existing project, if that project is already managed with Subversion or git, Xcode detects this and is ready instantly to display version control information in its interface. If a remote repository is involved, Xcode automatically enters informa‐ tion for it in the Accounts preference pane, which is the unified interface for repository management. To use a remote server without having a working copy checked out from it, enter its information manually in the Accounts preference pane. Source control actions are available in two places: the Source Control menu and the contextual menu in the Project navigator. To check out and open a project stored on a remote server, choose Source Control → Check Out. Other items in the Source Control menu are obvious, such as Commit, Push, Pull (or Update), Refresh Status, and Discard Changes. Note particularly the first item in the Source Control menu, which lists all open working copies by name and branch; its hierarchical menu items let you perform rudimentary branch management. Files in the Project navigator are marked with their status. For example, if you’re using git, you can distinguish modified files (M), new untracked files (?), and new files added to the index (A). (If you’ve unchecked “Refresh local status automatically,” those mark‐ ings may not appear until you choose Source Control → Refresh Status.) When you choose Source Control → Commit, you’re shown a comparison view of all changes in all changed files. Each change can be excluded from this commit (or reverted entirely), so it’s possible to group related file hunks into meaningful commits. A similar comparison view is available for any commit by choosing Source Control → History. (But Xcode has nothing like the visual branch representation of git’s own gitk tool.) Merge conflicts are also presented in a useful graphical comparison interface. You can also see a comparison view for the file being currently edited, at any time, through the Version editor; choose View → Version Editor → Show Version Editor, or click the third Editor button in the project window toolbar. The Version editor actually has three modes: Comparison view, Blame view, and Log view (choose from View → Version Editor, or use the pop-up menu from the third Editor button in the toolbar when the Version editor is showing). For example, in Figure 9-2, I can see that in the more recent version of this file (on the left) I’ve changed my supportedInterfaceOrientations implementation (because the Swift language changed). If I choose Editor → Copy Source Changes, the corresponding diff text (a patch file) is placed on the clipboard. If I switch to Blame view I can see my Version Control | 361 Figure 9-2. Version comparison own commit message. The jump bar at the bottom of the Version editor permits me to view any commit’s version of the current file in the editor. Another way to learn how a line was changed is to select within that line (in the normal editor) and choose Editor → Show Blame For Line. A popover appears, describing the commit where this line changed to its current form; using buttons in that popover, you can switch to Blame view or Comparison view. 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 renaming a project may offer to take a snapshot first). 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 pur‐ pose of giving confidence in advance of performing some change that might subse‐ quently engender regret. Snapshots are managed in the Projects tab of the Organizer window; here you can export a snapshot, thus resurrecting an earlier state of your project folder. Editing and Navigating Your Code Many aspects of Xcode’s editing environment can be modified to suit your tastes. Your first step should be to pick a Source Editor font face and size you like in Xcode’s 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 Menlo or Consolas, or the freeware Inconsolata (http://levien.com/type/ myfonts/) or Source Code Pro (https://github.com/adobe-fonts/source-code-pro). Xcode has some automatic formatting, autotyping, and text selection features. 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 code to be excellent with these settings. 362 | Chapter 9: Life Cycle of a Project 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, choose Editor → Structure → Re- Indent (Control-I), which autoindents the current line or selection. With “Enable type-over completions” checked, Xcode helps balance delimiters. For ex‐ ample, suppose I intend to make a UIView by calling its initializer init(frame:). I type as far as this: let v = UIView(fr Xcode automatically appends the closing right parenthesis, with the insertion point still positioned before it: let v = UIView(fr) // I have typed ^ That closing right parenthesis, however, is tentative; it’s in gray. Now I finish typing the parameter; the right parenthesis is still gray: let v = UIView(frame:r) // I have typed ^ I can now confirm the closing right parenthesis in any of several ways: I can actually type a right parenthesis, or I can type Tab or Right arrow. The tentative right parenthesis is replaced by a real right parenthesis, and the insertion point is now positioned after it, ready for me to continue typing. Xcode behaves similarly with double quotes, right curly braces, right square brackets, and so on. Autocompletion As you write code, you’ll take advantage of Xcode’s autocompletion feature. Cocoa type names and method names are astonishingly verbose, and whatever reduces your time and effort typing will be a relief. However, I personally do not check “Suggest comple‐ tions 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 I want my code to create an alert. I type as far as UIAlert- Controller( and press Esc. A menu pops up, listing the four initializers appropriate to a UIAlertController (Figure 9-3). 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 title:... with the Down arrow key, and press Return to accept the selected choice. When I choose an alternative from the autocompletion menu, the template for the method call is entered in my code (I’ve broken it into multiple lines here): Editing and Navigating Your Code | 363 Figure 9-3. The autocompletion menu let alert = UIAlertController( title: <#String?#>, message: <#String?#>, preferredStyle: <#UIAlertControllerStyle#>) The expressions in <#...#> are placeholders, showing the type of each parameter. They appear in Xcode as cartouche-like “text tokens” (see Figure 9-3) to prevent them from being edited accidentally. You can select the next placeholder with Tab or by choosing Navigate → Jump to Next Placeholder (Control-/). Thus I can select a placeholder and type over it, entering the actual argument I wish to pass, select the next placeholder and type that argument, and so forth. To convert a placeholder to a normal string without the delimiters, select it and press Return, or double-click it. Autocompletion and its contextual intelligence works for object type names, method calls, and property names. It also works when you’re entering a declaration for a function that’s inherited or defined in an adopted protocol. You don’t need to type even the initial func; just type the first few letters of the method’s name. For example, in my app delegate class I might type: applic If I then press Esc, I see a list of methods such as application:didFinishLaunchWith- Options:; 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 entire declaration is filled in for me, including the curly braces: func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool { <#code#> } A placeholder for the code appears between the curly braces, and it is selected, ready for me to start entering the body of the function. If a function needs an override designation, Xcode’s code completion provides it. 364 | Chapter 9: Life Cycle of a Project 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 (Command- Option-Control-2), but a code snippet’s abbreviation is globally available to code com‐ pletion, so you can use a snippet without showing the library: you type the abbreviation and the snippet’s name is included among the possible completions. For example, to enter a class declaration at the top level of a file, I would type class and press Esc, to get autocompletion, and select “Swift Class” or “Swift Subclass.” When I press Return, the template appears in my code: the class name and superclass name are placeholders, the curly braces are provided, and the body of the declaration (between the curly braces) is another placeholder. 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. The filter bar (Edit → Filter → Filter in Library, Command-Option-L) helps you reach a snippet by name quickly. 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; the Completion Scopes pop-up menu lets you narrow the contexts in which the snippet will be available through code completion. In the text of the snippet, use the <#...#> construct to form any desired placeholders. For example, I’ve created an outlet snippet defined like this: @IBOutlet var <#name#> : <#type#>! And I’ve created an action snippet defined like this: @IBAction func <#name#> (sender:AnyObject!) { <#code#> } My other snippets constitute a personal library of utility functions that I’ve developed. For example, my delay snippet inserts my dispatch_after wrapper function (see “Delayed Performance” on page 483). Fix-it and Live Syntax Checking Xcode’s Fix-it feature can make and implement positive suggestions 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, Figure 9-4, at the top, shows that I’ve accidentally forgotten the parentheses after a method call. This causes a compile error, because the backgroundColor property Editing and Navigating Your Code | 365 Figure 9-4. A compile error with a Fix-it suggestion that I’m trying to set is a UIColor, not a function. But the stop-sign icon next to the error tells me that Fix-it has a suggestion. I click the stop-sign icon, and Figure 9-4, at the bottom, shows what happens: a Fix-It dialog pops up, telling me how it proposes to fix the problem — by inserting the parentheses. Moreover, Xcode is showing me what my code would look like if Fix-It did fix the problem in this way. If I press Return, or double-click the “Fix-it” button in the dialog, Xcode really inserts the parentheses — and the error vanishes, because the problem is solved. If you’re confident that Xcode will do the right thing, choose Editor → Fix All in Scope (Command-Option-Control-F), and Xcode will implement all near‐ by Fix-it suggestions without your even having to show the dialog. Live syntax checking is like a form of continual 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 find live syntax checking intrusive. My code is almost never valid while I’m in the middle of typing, because the terms and parentheses 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 corre‐ sponding right parenthesis); I hate that. So I’ve got “Show live issues” unchecked. Navigation Developing an Xcode project involves editing code in many files at once. Fortunately, Xcode provides numerous ways to navigate your code, many of which have been men‐ tioned in previous chapters. Here are some of Xcode’s chief forms of navigation: 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 366 | Chapter 9: Life Cycle of a Project example, type story to see just your .storyboard 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 blue, the third is dark), the Symbol navigator lists your project’s object types and their members. Click on a symbol to navigate to its declaration in the editor. As with the Project navigator, the filter bar’s search field can help get you where you want to go. The jump bar Every path component of the code editor’s 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 object and member declarations, 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. You can inject bold section titles into this bottom-level menu using a comment whose first word is MARK:. For example, try modifying ViewController.swift in our Empty Window project: // MARK: - view lifecycle override func viewDidLoad() { super.viewDidLoad() } The result is that the viewDidLoad item in the bottom-level menu is preceded by view lifecycle. To make a divider line in the menu, type a MARK: comment whose value is a hyphen; in the preceding example, both a hyphen (to make a divider line) and a title (to make a bold title) are used. Similarly, comments starting with TODO: and FIXME: 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, Command-Control-Left and Command-Control-Right). Related items The leftmost button in the jump bar summons the Related Items menu, a hi‐ erarchical menu of files related to the current file, such as superclasses and Editing and Navigating Your Code | 367 adopted protocols. This list even includes functions that call or are called by the currently selected function. A path component menu in the jump bar can be filtered! Start typing while a jump bar menu is open, to filter what the menu displays. This filtering uses an “intelli‐ gent” search, not a strict text containment search; for example, typing “adf” will find application:didFinishLaunchingWithOptions: (if it’s present in the menu). The Assistant pane The Assistant pane lets you be in two places at once (see Chapter 6). Hold Option while navigating to open something in an Assistant pane instead of the primary editor pane. The Tracking menu in an Assistant pane’s jump bar sets its automatic relationship to the main pane. Tabs and windows You can also be in two places at once by opening a tab or a separate window (again, see Chapter 6). Jump to definition Navigate → Jump to Definition (Command-Control-J) lets you jump to the decla‐ ration of the symbol already selected in your code. Open quickly File → Open Quickly (Command-Shift-O) opens a dialog where you can search for a symbol in your code and in the framework headers. 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 (Find → Find in Project, Command-Shift-F), which is the same as using the Search navigator, and an editor-level find (Find → Find, Command-F); don’t confuse them. Find options are all-important. Additional options and capabilities appear in a pop-up menu when you click the magnifying glass icon in the search field. The global find options include a scope, allowing you to specify in sophisticated ways which files will be searched: click the current scope to see the Search Scopes panel, where you can select a different scope or create a custom scope. You can also find using regular expressions. There’s a lot of power lurking here. 368 | Chapter 9: Life Cycle of a Project 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. You can replace all occurrences (Replace All), or select particular find results in the Search navigator and replace only those (Replace); you can also delete find results from the Search navigator, to protect them from being affected by Replace All. The Search navigator’s Preview button summons a dialog that shows you the effect of each possible replacement, and lets you accept or reject 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 selec‐ tion. A sophisticated form of editor-level find is Editor → Edit All In Scope, which finds simultaneously all occurrences of the currently selected term within the same scope; you can use this to change the name of a variable or function throughout its scope, or just to survey how the name is used. 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. Depending on your app target’s Base SDK, Deployment Target, and Targeted Device Family build settings, and on what SDKs you have installed, you may have choices about the device and system to be represented by the Simulator as you choose your destination before running (see Chapter 6). The Simulator window can be displayed at one-quarter, one-third, half, three-quarter, or full size (choose from Window → Scale). This is a matter of display merely, compa‐ rable to zooming the window. For example, you might run a double-resolution device in the Simulator at full size to see every 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 moving symmetrically around their common center, and Option-Shift to represent two fingers moving in parallel. To click the Home button, choose Hardware → Home (Command-Shift-H). (Because of multitasking, clicking the Home button to switch from the app you’re running in Xcode to the home screen does not stop your app running, in Xcode or on the Simulator. To quit your app in the Sim‐ ulator, quit the Simulator, or switch to Xcode and choose Product → Stop.) Items in the Hardware menu 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. The Debug menu in the Simulator is useful for detecting problems with animations and drawing. Toggle Slow Animations makes animations unfold in slow motion so that you can see in detail what’s happening. The next four menu items (their names begin with Running in the Simulator | 369 Color) are similar to features available when running using Instruments, under the Core Animation instrument, revealing possible sources of inefficiency in screen drawing. The Debug menu also lets you open the log in the Console application, and lets you set the simulated device’s location (useful when testing a Core Location app). 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. You can view the console in the Debug pane; Chapter 6 describes a technique for displaying the console in a tab of its own. The standard Swift command for sending a message to the console is the println function (or print if you don’t want a final linebreak). Using Swift’s string interpolation and the Printable protocol (which requires a description property; see Chapter 4), you can pack a lot of useful information into a println call. Cocoa objects generally have built-in description property implementations. For example: println(self.view) The output in the console reads something like this (I’ve formatted it for clarity here): > We learn the object’s class, its address in memory (useful for confirming whether two instances are in fact the same instance), and the values of some additional properties. If you’re importing Foundation — and in real life iOS programming, you are — you also have access to the NSLog C function. It takes an NSString which operates as a format string, followed by the format arguments. A format string is a string containing symbols called format specifiers, 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 specifiers are %@ (an object reference), %d (an int), %ld (a long), and %f (a double). For example: 370 | Chapter 9: Life Cycle of a Project NSLog("the view: %@", self.view) In that example, self.view 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: 2015-01-26 10:43:35.314 Empty Window[23702:809945] the view: > I like NSLog’s output because it provides the current time and date, along with the process name, process ID, and thread ID (useful for determining whether two logging state‐ ments are called on the same thread). Also, NSLog is thread-safe, whereas it appears that println is not. For the complete repertory of format specifiers available in a format string, read Apple’s document String Format Specifiers (in the String Programming Guide). The format specifiers are largely based on those of the C printf standard library function. 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 %d but the value of the corresponding argument was a float. Another common mistake is treating an NSNumber as if it were the type of number it contains; an NSNumber isn’t any kind of number — it’s an object (%@). Problems with signed vs. unsigned integers, or 32-bit vs. 64-bit numbers, can be tricky as well. C structs are not objects, so they cannot provide a description. But Swift extends some of the most common C structs as Swift structs, and thus allows them to be printed with println. Thus, for example, this works: println(self.view.frame) // (0.0,0.0,320.0,480.0) However, you can’t do the same thing with NSLog. For this reason, common Cocoa structs are usually accompanied by convenience functions that render them as strings. For example: NSLog("%@", NSStringFromCGRect(self.view.frame)) // {{0, 0}, {320, 480}} If a C struct is not extended as a Swift struct, then you’ll need to use the convenience function even with println. For example: let edges : UIEdgeInsets = UIEdgeInsetsMake(6,0,6,0) println(edges) // C.UIEdgeInsets println(NSStringFromUIEdgeInsets(edges)) // {6, 0, 6, 0} Debugging | 371 Figure 9-5. Defining a Swift flag Swift defines four special literals, particularly useful when logging because they describe their own position in the surrounding file: __FILE__, __LINE__, __COLUMN__, and __FUNCTION__. You will probably want to remove your logging calls before shipping your app, as you won’t want your finished app to dump unnecessary messages into the console. A useful trick is to put your own global function in front of Swift’s println function: func println(object: Any) { Swift.println(object) } When it’s time to stop logging, just comment out the second line: func println(object: Any) { // Swift.println(object) } If you prefer this to be automatic, you can use conditional compilation. Swift’s conditional compilation is rudimentary, but it’s sufficient for this task. For example, we can make the body of our function depend upon a DEBUG flag: func println(object: Any) { #if DEBUG Swift.println(object) #endif } That code depends upon a DEBUG flag that doesn’t actually exist. To make it exist, create it in your target’s build settings, under Other Swift Flags. The value that defines a flag called DEBUG is -D DEBUG. If you define this for the Debug configuration but not for the Release configuration (Figure 9-5), then a debug build (build and run in Xcode) will log with println, but a release build (archive and submit to the App Store) will not. Another useful form of caveman debugging is deliberately aborting your app because something has gone seriously wrong. See the discussion of assert and fatalError in Chapter 5. fatalError works even in a Release build, and should be used only if it will never be encountered by the path of execution. By default, assert never fails in a Release build, so it is safe to leave it in your code when your app is ready to ship; by that time, 372 | Chapter 9: Life Cycle of a Project of course, you should be confident that the bad situation your assert was intended to detect has been debugged and will never actually occur. 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, console logging works with any build configuration (Debug or Release) and wherever your app runs (in the Simulator 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: for example, the tester can connect the device to a computer and view its log in Xcode’s Devices window or with Apple’s iPhone Configuration Utility. The Xcode Debugger When you’re building and running in Xcode, you can pause in the debugger and use Xcode’s debugging facilities. The important thing, if you want to use the debugger, is that the app should be built with the Debug build configuration (the default for a scheme’s Run action). 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. Breakpoints There isn’t a strong difference between running and debugging in Xcode; the main distinction is whether breakpoints are effective or ignored. The effectiveness of break‐ points can be toggled at two levels: Globally (active vs. inactive) Breakpoints as a whole are either active or inactive. If breakpoints are inactive, we won’t pause at any breakpoints. Individually (enabled vs. disabled) 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. To create a breakpoint (Figure 9-6), select in the editor the line where you want to pause, and choose Debug → Breakpoints → Add Breakpoint at Current Line (Command-\). This keyboard shortcut toggles between adding and removing a breakpoint for the cur‐ rent line. The breakpoint is symbolized by an arrow in the gutter. Alternatively, a simple click in the gutter adds a breakpoint; to remove a breakpoint gesturally, drag it out of the gutter. Debugging | 373 Figure 9-6. A breakpoint Figure 9-7. 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-7). To toggle the active status of breakpoints as a whole, click the Breakpoints button in the bar at the top of the Debug pane, or choose Debug → Activate/Deactivate Breakpoints (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. 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 a println or 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 actively debug‐ ging the project; it won’t dump any messages into the console when the app runs on a user’s device, because there are no breakpoints on a user’s device. 374 | Chapter 9: Life Cycle of a Project Certain special kinds of breakpoint can be created in the Breakpoint navigator — click the Plus button at the bottom of the navigator and choose from its pop-up menu — or by choosing from the Debug → Breakpoints hierarchical 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 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. Sometimes Apple’s code will throw an exception and catch it, deliberately. This isn’t a crash, and nothing has gone wrong; but if you’ve created an exception break‐ point, your app will pause at it, which can be confusing. 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. A method may be specified in one of two ways: Using Objective-C notation The instance method or class method symbol (- or +) followed by square brackets containing the class name and the method name. For example: -[UIApplication beginReceivingRemoteControlEvents] By method name The method name alone. The debugger will resolve this for you into all possible class–method pairs, as if you had entered them using the Objective-C notation that I just described. For example: beginReceivingRemoteControlEvents Paused at a breakpoint 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-8). Depending on the settings for Debugging | 375 Figure 9-8. Paused at a breakpoint Running → Pauses in the Behaviors preference pane, the Debug navigator and the Debug pane may also appear. Here are some things you might like to do while paused at a breakpoint: 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. Functions listed in the call stack in the Debug navigator with a User icon, with the text in black, are yours; click one to see where you are paused in that function. (Listings with the text in gray are functions and methods for which you have no source code, so there would be little point clicking one unless you know something about assembly language.) You can also view and navigate the call stack using the jump bar at the top of the Debug pane. Study variable values 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, properties, and even some private informa‐ tion, by opening triangles. (Local variable values are shown even if, at the point where are paused, those variables have not yet been initialized; such values are meaningless, so ignore them.) You can use the search field to filter variables by name or value. If a formatted summary isn’t sufficiently helpful, you can send description (or, if this object adopts DebugPrintable, debugDescription) to an object variable and view the output in the console: choose Print Description of [Variable] from the contextual menu, or select the variable and click the Info button below the variables list. You can also view a variable’s value graphically: select the variable and click the Quick Look button (an eye icon) below the variables list, or press Spacebar. For example, in the case of a CGRect, the graphical representation is a correctly pro‐ portioned rectangle. You can make instances of your own custom class viewable in the same way; declare the following method and return an instance of one of the permitted types (see Apple’s Quick Look for Custom Types in the Xcode Debugger): @objc func debugQuickLookObject() -> AnyObject { // ... create and return your graphical object here ... } You can also inspect a variable’s value in place in your code, by examining its data tip. To see a data tip, hover the mouse over the name of a variable in your code. The 376 | Chapter 9: Life Cycle of a Project Figure 9-9. A data tip data tip is much like the display of this value in the variables list: there’s a flippy triangle that you can open to see more information, plus an Info button that displays the value description here and in the console, and a Quick Look button for showing a value graphically (Figure 9-9). Inspect your view hierarchy New in Xcode 6, you can study the view hierarchy while paused in the debugger. Click the Debug View Hierarchy button in the debug bar, or choose Debug → View Debugging → Capture View Hierarchy. Views are listed in an outline in the Debug navigator. The editor displays your views; this is a three-dimensional projection that you can rotate. The Object inspector and Size inspector display information about the currently selected view. 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. Talk to the debugger You can communicate directly with the debugger through the console. Xcode’s de‐ bugger interface is a front end to the real debugger, LLDB (http://lldb.llvm.org); by talking directly to LLDB, you can do everything that you can do through the Xcode debugger interface, and more. A common command is expression (or expr, or simply e), which evaluates an expression in the current language — Swift or Objective-C, depending on the language of the source file where you’re paused in the call stack. The expression is evaluated in the current context. Any LLDB console command is also eligible to be used as a breakpoint’s Debugger Command action. Debugging | 377 Fiddle with breakpoints You are free to create, destroy, edit, enable and disable, and otherwise manage breakpoints dynamically even while 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 de‐ bugging. 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 pro‐ duces the wrong results, you can add a breakpoint to the action handler and tap the button again; you pass through the same code, and this time 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 (Debug → Continue) or take one step and pause again. Also, you can select in a line and choose Debug → Continue to Current Line (or Continue to Here from the contextual menu), which effectively sets a breakpoint at the chosen line, continues, and removes the breakpoint. The stepping commands (in the Debug menu) are: Step Over Pause at the next line. Step Into Pause in your function that the current line calls, if there is one; otherwise, pause at the next line. Step Out Pause when we return from the current function. You can access these commands through convenient buttons in the bar at the top of the Debug pane. Even if the Debug pane is collapsed, the bar containing the buttons appears while running. Start over, or abort To kill the running app, click Stop in the toolbar (Product → Stop, Command- Period). Clicking the Home button in the Simulator (Hardware → Home) or on the device does not stop the running app in the multitasking world of iOS 4 and later. To kill the running app and relaunch it without rebuilding it, Control-click Run in the toolbar (Product → Perform Action → Run Without Building, Command- Control-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 programming 378 | Chapter 9: Life Cycle of a Project milieus where that sort of thing is possible, but Xcode is not among them. You must stop the app and run in the normal way (which includes building) to see your changes in action. Unit Testing A unit test is code that isn’t part of your app target, whose purpose is to exercise code that is part of your app target, making sure that it works as expected. For example, a unit test might call some method in your app target code, handing it various parameters and looking to see if the expected result is returned each time, not just under normal conditions but also when incorrect or extreme inputs are supplied. It can even be useful to write unit tests before writing the real code, as a way of developing a working algo‐ rithm. In addition, having initially ascertained that your code passes your tests, you continue to run those tests to detect whether a bug has been introduced during the course of development. Unit tests are not a means of exercising your app as a whole, guiding it through use case scenarios by effectively tapping buttons with a ghost finger to make sure that the interface behaves as expected. Unit tests are for probing your code’s business logic, not for verifying its interface. Tests are bundled in a target of your project (see Chapter 6). The application templates generate projects with a test target in addition to the app target. You can easily create a new test target at any time: just make a new target and specify iOS → Other → Cocoa Touch Testing Bundle. By default, test code is recompiled every time you build and run your app (as specified in the scheme’s Build action); thus, you won’t be able to build and run your app unless it is also possible to build your tests. However, your tests do not run until you explicitly run them. Tests can be managed and run easily from the Test navigator (Command-5) as well as from within a test class file. When you rename a project that contains a test target (“Renaming Parts of a Project” on page 304), the test target breaks, because its Bundle Loader and Test Host build settings are not revised to refer to the built app and its binary by their new names. And, because the scheme’s Build action is configured to build the test target whenever you build, now you can’t build your app! This is a serious bug in the renaming process. If you’re reluctant to fix the build settings by hand, delete the test target and its files and create a new test target. (If you have written test code in the test target files, don’t forget to preserve it somehow.) A test class is a subclass of XCTestCase (which is itself a subclass of XCTest). A test method is an instance method of a test class, returning no value and taking no param‐ Unit Testing | 379 eters, whose name starts with test. The test target depends upon the app target, meaning that before a test class can be compiled and built, the app target must be compiled and built. Running a test also runs the app; the test target’s product is a bundle, which is loaded into the app as it launches. Each test method will call one or more test asserts; in Swift, these are global functions whose names begin with XCTAssert. For a list of these functions, see Apple’s document Testing With Xcode, in the “Writing Test Classes and Methods” chapter, under “Assertions Listed by Category.” Unlike the corresponding Objective-C macros, the Swift test assert functions do not take format strings (the way NSLog does); each takes a single, simple message string. Test assert functions marked as being “for scalars” are not really for scalars in Swift, because in Swift there are no scalars (as opposed to objects): they apply to any types that adopt Equatable or Comparable. A test class may also contain utility methods that are called by the test methods. In addition, you can override any of four special methods inherited from XCTestCase: setUp class method Called once before all test methods in the class. setUp instance method Called before each test method. tearDown instance method Called after each test method. tearDown class method Called once after all test methods in the class. The test target is a target, and what it produces is a bundle, with build phases like an app target. This means that resources, such as test data, can be included in the bundle. You might use setUp to load such resources; you can get a reference to the bundle by way of the test class: NSBundle(forClass: self.dynamicType). The test target is also a module, just as the app target is a module. In order to see into the app target, therefore, the test target must import the app target as a module, and app target members that are to be visible to the test target must be declared public. As an example of writing and running a test method, let’s use our Empty Window project. Give the ViewController class a (nonsensical) instance method dogMyCats: func dogMyCats(s:String) -> String { return "" } The method dogMyCats is supposed to receive any string and return the string "dogs". At the moment, though, it doesn’t; it returns an empty string instead. That’s a bug. Now we’ll write a test method to ferret out this bug. 380 | Chapter 9: Life Cycle of a Project Empty Window comes with a single test class, Empty_WindowTests. Find it in the file Empty_WindowTests.swift. I don’t like the underline, so please rename the class so that it is called simply EmptyWindowTests. Now, delete the existing test method test- Example. We’re going to replace it with a test method that calls dogMyCats and makes an assertion about the result. Since dogMyCats is a ViewController instance method, we’re going to need a ViewController instance. But how will EmptyWindowTests know about the ViewController class? It won’t, unless we make preparations: 1. At the top of Empty_WindowTests.swift, where are importing UIKit and XCTest, we must also import the app target: import Empty_Window 2. Back in ViewController.swift, we must declare ViewController as public. This means that any overrides in ViewController of members inherited from UIView‐ Controller must also be declared public. Finally, we must remember to declare dog- MyCats as public as well! 3. In Empty_WindowTests.swift, prepare an instance property in the declaration of the EmptyWindowTests class to store our ViewController instance: var viewController = ViewController() 4. Now, at long last, we can write our test method. Remember that its name must start with test! Call it testDogMyCats. It has access to a ViewController instance as self.viewController: func testDogMyCats() { let input = "cats" let output = "dogs" XCTAssertEqual(output, self.viewController.dogMyCats(input), "Failed to produce \(output) from \(input)") } We are now ready to run our test. There are many ways to do this. Switch to the Test navigator, and you’ll see that it lists our test target, our test class, and our test method. Hover the mouse over any name, and a button appears to its right. By clicking the appropriate button, you can thus run all tests in every test class, all tests in the Empty‐ WindowTests class, or just the testDogMyCats test. But wait, there’s more! Back in Empty_WindowTests.swift, there’s also a diamond-shaped indicator in the gutter to the left of the class declaration and the test method name; you can also click one of those to run, respectively, all tests in this class or an individual test. Or, to run all tests, you can choose Product → Test. So now let’s run testDogMyCats. The app target is compiled and built; the test target is compiled and built. (If any of those steps fails, we can’t test, and we’ll be back on familiar Unit Testing | 381 ground with a compile error or a build error.) The app launches in the Simulator, and the test runs. The test fails! (Well, we knew that was going to happen, didn’t we?) The app stops running in the Simulator. The error is described in a banner next to the assert that failed in our code, as well as in the Issue navigator and the Log navigator. Moreover, red X marks appear everywhere — in the Test navigator next to testDogMyCats, in the Issue navigator, in the Log navigator, and in Empty_WindowTests.swift next to the class dec‐ laration and the first line of testDogMyCats. Now let’s fix our code. In ViewController.swift, modify dogMyCats to return "dogs" instead of an empty string. Now run the test again. It passes! When a test failure occurs, you might like to pause at the point where the assertion is about to fail. To do so, in the Breakpoint navigator, click the Plus button at the bottom and choose Add Test Failure Breakpoint. This is like an Exception breakpoint, pausing on the assert line in your test method just before it reports failure. You could then switch to the method being tested, for example, and debug it, examining its variables and so forth, to work out the reason for the impending failure. There’s a helpful feature allowing you to navigate between a method and a test that calls it: when the selection is within a method, the Related Files menu in the jump bar includes Test Callers. The same is true of the Tracking menu in an assistant pane situation. In our example, we made a new ViewController instance in order to initialize Empty‐ WindowTests’s self.viewController. But what if our test required us to get a reference to the existing ViewController instance? This is the same problem of getting a reference to an instance that crops up so often in iOS programming (see “Instance References” on page 130, and Chapter 13). The test code runs inside a bundle that is effectively injected into your running app. This means that it can see app globals such as UIApplication.sharedApplication(). From there, you can work your way to the de‐ sired reference: var viewController = UIApplication.sharedApplication() .delegate?.window??.rootViewController as ViewController Organization of your test methods into test targets (suites) and test classes is largely a matter of convenience: it makes a difference to the layout of the Test navigator and which tests will be run together, plus each test class has its own properties, its own setUp method, and so on. To make a new test target or a new test class, click the Plus button at the bottom of the Test navigator. New in Xcode 6 is asynchronous testing, allowing a test method to be called back after a time-consuming operation. In your test method, you create an XCTestExpectation object by calling expectationWithDescription; then you initiate an operation that 382 | Chapter 9: Life Cycle of a Project takes a completion handler, and call waitForExpectationsWithTimeout:handler:. One of two things will happen: The operation completes The completion handler is called. In the completion handler, you perform any as‐ serts having to do with the result of the operation, and then call fulfill on the XCTestExpectation object. This causes the timeout handler to be called. The operation times out The timeout handler is called. Thus, the timeout handler is called either way, allowing you to clean up as necessary. Also new in Xcode 6 is performance testing, allowing you to test that the speed of an operation has not fallen off. In your test method, you call measureBlock and, in the block, do something (possibly many times, so as to get a reasonable time measurement sample). If the block involves setup and teardown that you don’t want included in the measurement, call measureMetrics:automaticallyStartMeasuring:forBlock: in‐ stead, and wrap the heart of the block with calls to startMeasuring and stopMeasuring. The performance test runs your block several times, recording how long each run takes. The first time you run a performance test, it fails, but you establish a baseline meas‐ urement. On subsequent runs, it fails if the standard deviation of the runs is too far from the baseline, or if the average time has grown too much. 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 you can build your app from scratch. Cleaning removes the cruft, quite literally. For example, suppose you have been includ‐ ing 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. This sort of leftover resource can cause all kinds of mysterious trouble. The wrong version of a nib may seem to appear in your interface; code that you’ve edited may seem to behave as it did before the edit. Cleaning removes the built app, and very often solves the problem. I think of cleaning as having several levels or degrees: Shallow clean Choose Product → Clean, which removes the built app and some of the intermediate information in the build folder. Clean | 383 Deeper clean Hold Option and choose Product → Clean Build Folder, which removes the entire build folder. Complete clean Close the project. Open the Organizer window (Window → Organizer) and switch to the Projects tab. Find your project listed at the left side; click it. On the right, click Delete. This removes the project’s entire folder inside your user Library/Devel‐ oper/Xcode/DerivedData folder. Insanely clean Quit Xcode. Open your user Library/Developer/Xcode/DerivedData folder and move all its contents to the trash. This is a complete clean for every project you’ve opened recently — plus the module cache. Removing the module cache can reset Swift itself, thus causing occasional mysterious compilation, code-completion, or syntax coloring issues to go away. In addition to cleaning your project, you should also remove your app from the Simu‐ lator. This is for the same reason as cleaning the project: when the app is built and copied to the Simulator, existing resources inside the built app may not be removed (in order to save time), and this may cause the app to behave oddly. To clean out the Simulator while running the Simulator, choose iOS Simulator → Reset Content and Settings. Running on a Device Sooner or later, you’ll want to progress 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. Submit‐ ting 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 384 | Chapter 9: Life Cycle of a Project device. You’ll go to the iOS Developer Program web page (http://developer.apple.com/ programs/ios). When you’re starting out, 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 merely in order to distribute your built app to other users for testing. Your iOS Developer Program membership involves two things: An Apple ID The user ID that identifies you at Apple’s site (along with the corresponding pass‐ word). You’ll use your Developer Program Apple ID for all kinds of things. In addition to letting you prepare an app to run on a device, this same Apple ID lets you enter Apple’s development forums, download Xcode beta versions, and so forth. A team name You, under the same Apple ID, can belong to more than one team. On each team, you will have a role dictating your privileges. If you are the head (or sole member) of the team, your role is Agent, meaning that you can do everything: you can develop apps, run them on your device, submit apps to the App Store, and receive the money for any paid apps that sell any copies there. Having established your Developer Program Apple ID, you should enter it into the Accounts preference pane in Xcode. Click the Plus button at the bottom left and choose Add Apple ID. Provide the Apple ID and password. From now on, Xcode will identify you through the team name(s) associated with this Apple ID; you shouldn’t need to tell Xcode this password again. To run an app on a device, you will need to sign the app as you build it. An app that is not properly signed for a device will not run on that device (assuming you haven’t jailbroken the device). Signing an app requires two things: An identity An identity represents Apple’s permission for a given team to develop, on a partic‐ ular computer, apps that can run on a device. It consists of two parts: A private key The private key is stored in the keychain on your computer. Thus, it identifies a computer where this team can potentially develop device-targeted apps. A certificate A certificate is a virtual permission slip from Apple. It contains the public key matching the private key (because you told Apple the public key when you asked for the certificate). With a copy of this certificate, any machine holding the private key can actually be used to develop device-targeted apps under the name of this team. Running on a Device | 385 A provisioning profile A provisioning profile is a virtual permission slip from Apple, uniting four things: • An identity. • An app, identified by its bundle id. • A list of eligible devices, identified by their UDIDs (unique device identifiers). • A list of entitlements. An entitlement is a special privilege that not every app needs, such as the ability to talk to iCloud. You won’t concern yourself with entitlements unless you write an app that needs one. Thus, a provisioning profile is sufficient for signing an app as you build it. It says that on this Mac it is permitted to build this app such that it will run on these devices. There are two types of identity, and hence two types of certificate, and hence two types of provisioning profile: development and distribution (a distribution certificate is also called a production certificate). We are concerned here with the development identity, certificate, and profile; I’ll talk about the distribution side later in this chapter. Apple is the ultimate keeper of all information: your certificates, your provisioning profiles, what apps and what devices you’ve registered. Your communication with Apple, when you need to verify or obtain a copy of this information, will take place through one of two means: The Member Center A set of web pages. You need a Developer Program membership to log in. At the Member Center page (https://developer.apple.com/membercenter) or at the iOS Dev Center page (https://developer.apple.com/devcenter/ios/) click Certificates, Identifi‐ ers, & Profiles. You’ll have access to all features and information to which you are entitled by your membership type and role. (This is the area of Apple’s site formerly referred to as the Portal.) Xcode Except for obtaining a distribution provisioning profile, just about everything you would need to do at the Member Center can be done through Xcode instead. When all goes well, using Xcode is a lot simpler! If there’s a problem, you can head for the Member Center to iron it out. Obtaining a Certificate Setting up an identity and obtaining a certificate is something you only have to do once (or, perhaps, once a year at most; you might have to do it again when your annual Developer Program membership approaches expiration and needs to be renewed). The certificate, you remember, depends upon a private–public key pair. The private key will live in your keychain; the public key will be handed over to Apple, to be built into the 386 | Chapter 9: Life Cycle of a Project certificate. The way you give Apple your public key is through a request for the certificate. Thus, the full manual procedure for obtaining a certificate is as follows: 1. Through the Keychain Access program on your computer, you generate the private– public key pair. Your keychain keeps the private key. 2. You embed the public key in a certificate request, and submit the request to Apple at the Member Center, identifying yourself through your Apple ID and (if neces‐ sary) your team, and specifying a development or distribution certificate. 3. Apple provides the certificate itself, which also contains the public key. 4. The certificate is downloaded, and is imported by the keychain, which uses the public key to match it up with the correct private key. Your keychain keeps the certificate. 5. Henceforward, Xcode can see the certificate in the keychain, and thus grants you an identity for development or distribution under the appropriate team name. In Xcode, however, all of those steps are performed for you automatically when you request a certificate! Here’s what to do: 1. Open Xcode’s Accounts preference pane. 2. If you haven’t entered your developer Apple ID and password, do so now. 3. On the left, select your Apple ID. On the right, select your team. Click View Details. 4. If you had a certificate and it was revoked from the Member Center but is still valid, you may see a dialog offering to request and download the certificate. Click Request. Otherwise, click the Plus button and choose iOS Development (at the lower left under the Signing Identities column). Everything then happens automatically: the private–public key pair is generated, and the certificate is requested, generated, downloaded, stored in your keychain, and listed under Signing Identities in the View Details dialog. (Moreover, a universal team development provisioning profile may also be generated, as shown in Figure 9-11. Thus you may now have everything you need to run on a device!) If that works, then skip the rest of this section. Just in case it doesn’t, I’ll now describe the more elaborate manual procedure for generating the private–public key pair and the certificate request. Instructions are also available at the Member Center as you ini‐ tiate the process (go to the Certificates page and click the Plus button at the top right). 1. You launch Keychain Access and choose Keychain Access → Certificate Assistant → Request a Certificate from a Certificate Authority. Using your name and email address as identifiers, you generate and save to disk a 2048-bit RSA certificate re‐ Running on a Device | 387 Figure 9-10. A valid development certificate, as shown in Keychain Access quest file. Your private key is stored in your keychain then and there; the certificate request containing your public key has been saved temporarily onto your computer. (For example, you might save it to the desktop.) 2. At the Member Center, you are presented with an interface allowing you to upload the saved certificate request file. You upload it, and the certificate is generated; click its listing at the Member Center to expose the Download button, and click Down‐ load. 3. Locate and double-click the file you just downloaded; Keychain Access automati‐ cally imports the certificate and stores it in your keychain. You do not need to keep the certificate request file or the downloaded certificate file; your keychain now contains all the needed credentials. If this has worked, you can see the certificate in your keychain, read its details, and observe that it is valid and linked to your private key (Figure 9-10). Moreover, you should be able to confirm that Xcode now knows about this certificate: in the Accounts preference pane, click your Apple ID on the left and your team name on the right, and click View Details; a dialog opens where you should see an iOS Development signing identity listed at the top, with a Valid status. If this is your very, very first time obtaining any certificate from the Member Center, you will need another certificate: the WWDR Intermediate Certificate. This is the certificate that certifies that certificates issued by WWDR (the Apple Worldwide Developer Relations Certification Authority) are to be trusted. (You can’t make this stuff up.) Xcode should automatically install this in your key‐ chain; if not, you can obtain a copy of it manually by clicking a link at the bot‐ tom of the page at the Member Center where you begin the process of adding a certificate. 388 | Chapter 9: Life Cycle of a Project Figure 9-11. A universal development profile Obtaining a Development Provisioning Profile A provisioning profile, as I’ve already mentioned, unites an identity, a device, and an app bundle id. If things go well, in the simplest case, you’ll be able to obtain a develop‐ ment provisioning profile in a single step from within Xcode. If an app doesn’t require special entitlements or capabilities, a single development profile associated with your team is sufficient for all your apps, so you might only have to do this step once. You already have a development identity, from the previous section. You may also have a universal development provisioning profile, from the previous section! If not, the simplest solution is to connect your device to your computer with Xcode running and, after passing through any necessary delays (such as telling the device to trust the com‐ puter), choose the device as a destination and try to run your project on it. Xcode will register the device at the Member Center for you, and will create and download a uni‐ versal provisioning profile for this device. To confirm that the device has been added to the Member Center, go there in your browser and click Devices. To confirm that you have the universal development provisioning profile, click View Details in the Accounts preference pane (for the appropriate team). Certificates and profiles are listed here. The universal development profile, in addition to the title “iOS Team Provisioning Profile,” will have a nonspecific app bundle id associated with it, indicated by an asterisk (Figure 9-11). The universal development profile allows you to run any app on the targeted device for testing purposes, provided that the app doesn’t require special entitlements (such as using iCloud). It is also possible to register a device manually at the Member Center. Under Devices, click the Plus button and enter a name for this device along with its UDID. You can copy the device’s UDID from its listing in Xcode’s Devices window. If necessary, you can make a provisioning profile for a specific app at the Member Center: 1. Make sure your app is registered at the Member Center under Identifiers → App IDs. If it isn’t, add it. Click Plus. Enter a name for this app. Don’t worry about the nonsense letters and numbers that the Member Center adds as a prefix to your Running on a Device | 389 bundle identifier; use the Team ID. Enter the bundle identifier under Explicit App ID exactly as shown in Xcode, in the Bundle Identifier field under General when you edit the app target. 2. Under Provisioning Profiles, click Plus. Ask for an iOS App Development profile. On the next screen, choose the App ID. On the next screen, check your development certificate. On the next screen, select the device(s) you want to run on. On the next screen, give this profile a name, and click Generate. Click the Download button. 3. Find the downloaded profile, and double-click it to open it in Xcode. You can then throw the downloaded profile away; Xcode has made a copy. Running the App Once you have a development profile applicable to an app and a device (or, in the case of the universal team profile, all apps and all registered devices), connect the device, choose it as the destination in the Scheme pop-up menu, and build and run the app. If you’re asked for permission to access your keychain, grant it. If necessary, Xcode will install the associated provisioning profile onto the device. The app is built, loaded onto your device, and runs there. 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 (tethered physically to your com‐ puter), not the Simulator. Running the app from Xcode on the device can also be used simply as a way of copying the current version of the app to the device. You can then stop the app (in Xcode), disconnect the device from your computer, and launch the app on the device and play with it. This is a good way of testing. You are not debugging, so you can’t get any feedback in Xcode, but messages are written to the console internally and can be retrieved later. Profile and Device Management The central location for surveying identities and provisioning profiles is Xcode’s Accounts preference pane. Select an Apple ID and a team and choose View Details. An important feature of the Accounts preference pane is the ability to export account information. You’ll need this if you want to be able to develop on a different computer. Select an Apple ID and use the Gear menu at the bottom of the pane to choose Export Accounts. You’ll be asked for a file name and a place to save, along with a password; this password is associated solely with this file, and is needed only to open the file later on another computer. On the other computer, to which you have copied the exported file, run Xcode and double-click the exported file; Xcode asks for its password. When you 390 | Chapter 9: Life Cycle of a Project provide it, like magic the entire suite of teams and identities and certificates and pro‐ visioning profiles springs to life in that other copy of Xcode, including the entries in your keychain. Alternatively, you might need to export just an identity, without any provisioning pro‐ files. You can do that with the gear menu in the Accounts preference pane’s View Details dialog. If the provisioning profiles listed in the Accounts preference pane’s View Details dialog get out of sync with the Member Center, click the Refresh button at the bottom left. If that doesn’t help, quit Xcode and, in the Finder, open your user Library/MobileDevice/ Provisioning Profiles folder, and delete everything that’s in there. Relaunch Xcode. In Accounts, your provisioning profiles are gone! Now click the refresh button. Xcode will download fresh copies of all your provisioning profiles, and you’ll be back in sync with the Member Center. When a device is attached to the computer, it appears in Xcode’s Devices window. Click its name to access information on the device. You can see (and copy) the device’s UDID. You can see (and delete) apps that have been installed for development using Xcode. You can view the device’s console log in real time. (The interface for this is a little obscure in Xcode 6: click the tiny up-arrow at the bottom left of the main pane of the Devices window.) Using the Gear menu (or the contextual menu), you can see provisioning profiles that have been installed on the device. 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. Profiling Xcode provides tools for probing the internal behavior of your app graphically and numerically, and you should keep an eye on those tools. The gauges in the Debug nav‐ igator allow you to monitor key indicators, such as CPU and memory usage, any time you run your app. And Instruments, a sophisticated and powerful utility application, collects profiling data that can help track down problems and provide the numeric information you need to improve your app’s performance and responsiveness. You’ll probably want to spend some time with Instruments as your app approaches completion (optimizing prematurely is notoriously a waste of time and effort). Gauges The gauges in the Debug navigator are operating whenever you build and run your app. Click on a gauge to see further detail displayed in the editor. The gauges do not provide highly detailed information, but they are extremely lightweight and always active, so they provide an easy way to get a general sense of your running app’s behavior at any time. In particular, if there’s a problem, such as a prolonged period of unexpectedly high Profiling | 391 Figure 9-12. The Debug navigation gauges CPU usage or a relentless unchecked increase in memory usage, you can spot it in the gauges and then use Instruments to help track it down. In Figure 9-12, I’ve been heavily exercising my app for a few moments, repeatedly per‐ forming the most memory-intensive actions I expect the user to perform. These actions do cause some spikes in memory usage, but my app’s memory usage then always settles back down and levels off, so I don’t suspect any memory issues. Note that Figure 9-12 is the result of running on a device. Running in the Simulator gives completely different — and therefore misleading — results. Instruments You can use Instruments on the Simulator or the device. The device is where you’ll do your ultimate testing, for maximum verisimilitude. To get started with Instruments, set the desired destination in the Scheme pop-up menu in the project window toolbar, and choose Product → Profile. 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 validation 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. 392 | Chapter 9: Life Cycle of a Project Figure 9-13. Instruments graphs memory usage over time Alternatively, click Profile In Instruments in a Debug navigator gauge editor; this is convenient when the gauges have suggested a possible problem, and you want to re‐ produce that problem under the more detailed monitoring of Instruments. Instruments launches, selecting the appropriate trace template for you. A dialog offers two options: Restart stops your app and relaunches it with Instruments, whereas Transfer keeps your app running and hooks Instruments into it. When the Instruments main window appears, 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. You may have to click the Record button, or choose File → Record Trace, to get your app running. Now you should interact with your app like a user; Instruments will record its statistics. Use of Instruments is an advanced topic, which is largely 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 Reference and Instruments User Guide. Also, many WWDC videos from current and prior years are about Instruments; look particularly for sessions with “Instruments” or “Performance” in their names. Here, I’ll just demonstrate, without much explanation, the sort of thing Instruments can do. Figure 9-13 shows me doing much the same thing in Instruments that I did with the Debug navigator gauges in Figure 9-12. I’ve set the destination to my device. I choose Product → Profile; when Instruments launches, I choose the Allocations trace template. With my app running under Instruments, I exercise it for a while and then pause In‐ struments, which meanwhile has charted my memory usage. Examining the chart, I find that there are spikes up to about 10MB, but the app in general settles down to a much lower level (less than 4MB). Those are very gentle and steady memory usage figures, so I’m happy. Another field of Instruments expertise is the ability to detect memory leaks. In Figure 9-14, I’ve run the retain cycle code from Chapter 5: I have a Dog class instance and a Cat class instance with persisting references to one another. There are no other references to either instance, so they are both leaking. I’ve profiled the app using the Leaks trace template. Instruments has detected the leak, and has even drawn me a dia‐ gram showing me the structure of my mistake! Profiling | 393 Figure 9-14. Instruments describes a retain cycle Figure 9-15. Drilling down into the time profile 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’ve set the destination to a device, because that’s where speed matters and needs to be measured. I choose Product → Profile. Instruments launches, and I choose the Time Profiler trace template. When the app launches under Instruments on the device, the master view appears; I tap a cell in the table view, and after a significant delay, the detail view appears. I navigate back and repeat the procedure several times. In Figure 9-15, I’ve paused Instruments, and am looking at what it’s telling me. Opening the triangles in the lower portion of the window, it turns out that much of the time is spent in routines that don’t belong to me; this is Cocoa, laying out the table view. How‐ ever, by drilling down far enough, I eventually arrive at my own code, indicated by the appearance of my app’s name, Albumen, as a module name. 394 | Chapter 9: Life Cycle of a Project Figure 9-16. My code, time-profiled Here’s the amazing part: by double-clicking the listing of that line, I can see my own code, time-profiled (Figure 9-16)! The profiler is drawing my attention to the call to drawAtPoint:blendMode:alpha:. Compositing with a blend mode takes time, and I’m doing it for every row of the table. It may be that I can shave off some time here by drawing in another way, and I’ll probably spend a little time tweaking that line and trying the Time Profiler again. This is just the sort of focused quantified analysis that Instruments is good at. 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. You will probably want to implement localization relatively late in the lifetime of the app, after the app has achieved its final form, in preparation for distribution. Localization operates through localization folders in your project folder 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. Any type of resource can live in these localization folders; for example, you can have one version of an image to be loaded for one language, and another version of that image for another language. You will be most concerned, however, with text that is to appear in your interface. Such text must be maintained in specially formatted .strings files, with special names. For example: Localization | 395 • To localize your Info.plist file, use InfoPlist.strings. • To localize your Main.storyboard, use Main.strings. • To localize your code strings, use Localizable.strings. New in Xcode 6, you don’t have to create or maintain these files manually. Instead, you can work with exported XML files in the standard .xliff format. Xcode will generate these files automatically, based on the structure and content of your project; it will also read these files and will turn them automatically into the various localized .strings files. To help you understand how the .xliff export and import process works, I’ll start by explaining what you would have to do in order to create and maintain your .strings files manually. Then I’ll describe how to do the same thing using .xliff files. Localizing the Info.plist I’ll begin by localizing the string that appears in the Springboard under the app’s icon — the visible title of the app. This string is the value of the CFBundleDisplayName key in our Info.plist file. Our Info.plist file doesn’t have a CFBundleDisplayName key, so the first step is to make one: 1. Edit the Info.plist file. 2. Select “Bundle name” and click the Plus button that appears to its right. 3. A new entry appears. From the pop-up menu, choose “Bundle display name.” 4. For the value, enter “Empty Window” and save. Now we’re going to localize that string: we’re going to make a different string appear in the Springboard when the device’s language is French. How is the Info.plist file localized? It depends on another file, which by default is not created by the app template — InfoPlist.strings. So we need to create that file: 1. Choose File → New → File. 2. Select iOS → Resource → Strings File. Click Next. 3. Make sure this file is part of our app target, and name it InfoPlist. Get the name and capitalization exactly right! Click Create. 4. A file called InfoPlist.strings has appeared in the project navigator. Select it and, in the File inspector, click Localize. 5. A dialog appears offering us a choice of initial languages. The default is Base, which is fine. Click Localize. We are now ready to add a language! Here’s how to do it: 396 | Chapter 9: Life Cycle of a Project 1. Edit the project. Under Info, the Localizations table lists our app’s localizations. We are initially localized only for the development language (English in my case). 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. 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 InfoPlist.strings, one for Base (namely English) and one for French. Thus we can now edit either one individually. Now let’s edit our InfoPlist.strings files. A .strings file is 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 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"; That’s all there is to it! Now let’s try it out: 1. Build and run Empty Window in the 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 (perhaps truncated). 4. In the Simulator, launch the Settings app and change the language to French (Gen‐ eral → Language & Region → iPhone Language → Français). Click Done. An action sheet asks to confirm that we want to Change to French. Do so. 5. After a pause, the Springboard appears. Look at our app. Its 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. Localization | 397 Localizing a Nib File Now let’s talk about how nib files are localized. Once upon a time, it was necessary to localize a copy of the entire nib. So, for example, if you wanted a French version of a nib file, you were constantly maintaining two separate nib files. If you created a button in one nib file, you had to create the same button in the other — except that in one, the title was in English, while in the other, the title was in French. And so on, for every interface object and every localization language. It doesn’t sound like fun, does it? Nowadays, happily, there’s a better way. If a project uses base internationalization, then a correspondence can be created between a nib file in a Base.lproj folder and a .strings file in a localization folder. Thus the developer has just one copy of the nib file to main‐ tain. If the app runs on a device that’s localized for a language for which a .strings file exists, the strings in the .strings file are substituted for the strings in the nib file. By default, our Empty Window project does use base internationalization, and its Main.storyboard file is in a Base.lproj folder. So we’re ready to localize the storyboard file for French. You’re going to need something in the storyboard file to localize: 1. Edit Main.storyboard and make sure that the initial main view contains a button whose title is "Hello". If there isn’t one, add one. Make the button about 100 pixels wide, and save (that’s important). 2. Still editing Main.storyboard, look at the File inspector. Under Localization, Base should be checked already. In addition, check French. 3. In the Project navigator, examine the listing for Main.storyboard. It now has a flippy triangle. Flip it open. Sure enough, there is now a base-localized Main.storyboard and a French-localized Main.strings. 4. Edit the French Main.strings. It has been created automatically, with keys corre‐ sponding to every interface item in Main.storyboard that has a title. You have to deduce, from comments and the key names, how this correspondence works. In our case, there’s just one interface item in Main.storyboard, and anyway it’s pretty easy to guess what interface item the key represents. It looks something like this: /* Class = "UIButton"; normalTitle = "Hello"; ObjectID = "PYn-zN-WlH"; */ "PYn-zN-WlH.normalTitle" = "Hello"; 5. In the second line, containing the key–value pair, change the value to "Bonjour". Don’t change the key! It has been generated automatically, and correctly, so as to specify the correspondence between this value and the title of the button. Run the project and view the interface on an English device and on a French device, as we did before. Sure enough, the button’s title appears as "Bonjour" on a French device! What happens if we now modify the nib? Suppose, for example, we add another button to the view in Main.storyboard. There’s no automatic change to any .strings files corre‐ 398 | Chapter 9: Life Cycle of a Project sponding to nibs; such files must instead be regenerated manually. (That’s why, in real life, it’s a good idea not to start localizing your nib files until your interface is pretty much finished.) But all is not lost: 1. Select Main.storyboard and choose File → Show in Finder. 2. Run Terminal. Type ibtool --export-strings-file output.strings followed by a space, and drag Main.storyboard from the Finder into the Terminal window. Press Return. The result is that a new file called output.strings based on Main.storyboard is generated in your home directory (or whatever the current directory is). Merging this information with the existing localized .strings files based on Main.storyboard is up to you. In that example, I made you widen the "Hello" button in advance, to make room for a longer localized title, "Bonjour". In real life, you’ll probably use autolayout; this allows buttons and labels to grow and shrink automatically, while shifting other parts of the interface to compensate. New in Xcode 6, to test your interface under different localizations, you can preview your localized nib files within Xcode, without running the app. Edit a .storyboard or .xib file and open an assistant pane, and switch the Tracking menu to Preview. A menu at the lower right lists localiza‐ tions; choose from the menu to switch between them. A “double-length pseudo- language” stress-tests your interface with really long localized replacement text. Localizing Code Strings What about localizing strings whose value is generated in code? In the Empty Window app, an example would be the alert summoned by tapping the button. It displays text — the title and message of the alert, and the title of the button that dismisses it: @IBAction func buttonPressed(sender:AnyObject) { let alert = UIAlertController( title: "Howdy!", message: "You tapped me!", preferredStyle: .Alert) alert.addAction( UIAlertAction(title: "OK", style: .Cancel, handler: nil)) self.presentViewController(alert, animated: true, completion: nil) } How is that text to be localized? The approach is the same — a .strings file — but your code must be modified to use it explicitly. Your code calls the global NSLocalized- String function; the first parameter is a key into a .strings file, and the comment param‐ eter provides an explanatory comment, such as the original text to be translated. NSLocalizedString takes several additional, optional parameters; if you omit them, the default is to use a file called Localizable.strings. So, for example, we might modify our buttonPressed: method to look like this: Localization | 399 @IBAction func buttonPressed(sender:AnyObject) { let alert = UIAlertController( title: NSLocalizedString("ATitle", comment:"Howdy!"), message: NSLocalizedString("AMessage", comment:"You tapped me!"), preferredStyle: .Alert) alert.addAction( UIAlertAction(title: NSLocalizedString("Accept", comment:"OK"), style: .Cancel, handler: nil)) self.presentViewController(alert, animated: true, completion: nil) } Our code is now broken, of course, because there is no Localizable.strings file. Let’s make one. The procedure is just as before: 1. Choose File → New → File. 2. Select iOS → Resource → Strings File. Click Next. 3. Make sure this file is part of our app target, and name it Localizable. Get the name and capitalization exactly right! Click Create. 4. A file called Localizable.strings has appeared in the project navigator. Select it and, in the File inspector, click Localize. 5. A dialog appears offering us a choice of initial languages. The default is Base, which is fine. Click Localize. 6. In the File inspector, check French. The Localizable.strings file now exists in two localizations, Base (meaning English) and French. We must now provide these files with content. Just as we did with ibtool earlier, we can generate the initial content automatically using the genstrings tool. For exam‐ ple, on my machine I would now, in the Terminal, type genstrings followed by space. Then I drag ViewController.swift from the Finder into the Terminal window, and press Return. The result is a file Localizable.strings in the current directory, reading as follows: /* OK */ "Accept" = "Accept"; /* You tapped me! */ "AMessage" = "AMessage"; /* Howdy! */ "ATitle" = "ATitle"; Now you copy and paste that content into the English and French versions of our project’s Localizable.strings files, and go through those pairs, changing the value in each pair so that it reads correctly for the given localization. For example, in the English Localizable.strings file: /* Howdy! */ "ATitle" = "Howdy!"; 400 | Chapter 9: Life Cycle of a Project And in the French Localizable.strings file: /* Howdy! */ "ATitle" = "Bonjour!"; And so forth. Localizing With XML Files New in Xcode 6, there’s another way do everything we just did. The surface mechanics of text localization can be made to revolve around the exporting and importing of .xliff files. This means that you typically won’t actually have to press any Localize buttons or edit any .strings files! Instead, you edit the target and choose Editor → Export For Localization; when you save, a folder is created containing .xliff files for your various localizations. You then edit these files (or get a translation house to edit them for you) and import the edited files: edit the target and choose Editor → Import Localizations. Xcode reads the edited .xliff files and does the rest, automatically creating localizations and modifying .strings files as needed. To demonstrate, let’s add another language — namely, Spanish — to our localizations: 1. Edit the target and choose Editor → Export For Localization. 2. We are offered a chance to export strings in our existing localizations as well as our base language. If we were planning to edit our French localization further, we would export it, but I’m not going to do that in this example. Instead, switch the Include pop-up menu to Development Language Only. 3. Specify a good place to save (such as the Desktop). You’re creating a folder, so don’t use the name of an existing folder in the same place. For example, if you’re saving to the same folder that contains the project folder, you might call it Empty Window Localizations. Click Save. 4. In the Finder, open the folder you just created. It contains an .xliff file in your project’s base language. For example, my file is called en.xliff because my develop‐ ment language is English. Examine this .xliff file, and you will see that Xcode has done for us everything that we did manually. No .strings files need be present initially! Xcode does all the work: • For every Info.plist file in your project, Xcode has created a corresponding element. When imported, these elements will be turned into localized Info‐ Plist.strings files. • For every .storyboard and .xib file, Xcode has run ibtool to extract the text, and has created a corresponding element. When imported, these elements will be turned into eponymous localized .strings files. Localization | 401 • For every code file containing a call to NSLocalizedString, Xcode has run genstrings, and has created a corresponding element. When imported, these elements will be turned into localized Localizable.strings files. We now proceed to translate some or all of the strings in this file into some other lan‐ guage, save the edited .xliff file, and import it: 1. Open the .xliff file in a decent text editor (or an XML editor if you have one). 2. Just for the sake of this example, I’m going to localize only the "Hello" button in the storyboard. So delete (carefully, so as not to mess up the XML) all the ... element groups except the one whose original attribute is "Empty Window/Base.lproj/Main.storyboard". And delete (carefully) all the ... elements except the one whose is "Hello". 3. To specify Spanish as the target language, add an attribute to the element: target-language="es". 4. To provide an actual translation, add a element after the ele‐ ment, and give it some text, such as "Hola". Save. The file should now look some‐ thing like this:
Hello Hola Class = "UIButton"; normalTitle = "Hello"; ObjectID = "PYn-zN-WlH";
5. Back in Xcode, edit the target and choose Editor → Import Localizations. In the Open dialog, select the edited en.xliff and click Open. 402 | Chapter 9: Life Cycle of a Project 6. Xcode complains that we didn’t translate everything there was to translate. Ignore that complaint and click Import. Amazing things have now happened! With no visible prompting, Xcode has added Spanish to our localizations, and has created an additional InfoPlist.strings file, an ad‐ ditional Main.strings file, and an additional Localizable.strings file, all localized to Span‐ ish. If you examine Main.strings, you’ll see that it looks just as it would have looked if we had edited it manually: /* Class = "UIButton"; normalTitle = "Hello"; ObjectID = "PYn-zN-WlH"; */ "PYn-zN-WlH.normalTitle" = "Hola"; Clearly, the round-trip to and from an .xliff file is an extremely convenient way to create and maintain your localizations. The structure of the localization within your project is exactly the same as I described earlier in this section, but the .xliff file externalizes that same information in a format that can be readily edited in a single file. The .xliff export process runs ibtool and genstrings for you, so your localized content is easy to main‐ tain as you add interface and code. Archiving and Distribution By distribution is meant providing to others who are not developers on your team your built app for running on their devices. 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 specific 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. To create a copy of your app for distribution, you need first to build an archive of your app. It is this archive that will subsequently be exported for Ad Hoc or App Store dis‐ tribution. An archive is basically a preserved build. It has three main purposes: Distribution An archive will serve as the basis for an Ad Hoc distribution or an App Store dis‐ tribution. Reproduction Every time you build, conditions can vary, so the resulting app might behave slightly differently. But an archive preserves a specific built binary; every distribution from a particular archive is guaranteed to contain an identical binary, and thus will behave the same way. This fact is important for testing: if a bug report comes in based on an app distributed from a particular archive, you can Ad Hoc distribute that archive to yourself and run it, knowing that you are testing exactly the same app. Archiving and Distribution | 403 Symbolication The archive includes a .dSYM file which allows Xcode to accept a crash log and report the crash’s location in your code. This allows you to deal with crash reports from users. Here’s how to build an archive of your app: 1. Set the destination in the Scheme pop-up menu in the project window toolbar to iOS Device. 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 saving an archive that will run on some device. 2. If you like, edit the scheme to confirm that the Release build configuration will be used for the Archive action. This is the default, but it does no harm to double-check. 3. Choose Product → Archive. The app is compiled and built. The archive itself is stored in a date folder within your user Library/Developer/Xcode/Archives folder. Also, it is listed in Xcode’s Organizer window (Window → Organizer) under Archives; this window may open spontaneously to show the archive you’ve just created. You can add a comment here; you can also change the archive’s name (this won’t affect the name of the app). To perform any kind of distribution based on your archive, you will also need a distri‐ bution identity (a private key and a distribution certificate in your computer’s keychain) and a distribution profile especially for this app. If you’re doing an Ad Hoc distribution and an App Store distribution, you’ll need a separate distribution profile for each. You can obtain a distribution identity from within Xcode in exactly the same way as I described obtaining a development identity: in the Accounts preference pane, in the View Details dialog for your team, click the Plus button and choose iOS Distribution. If that doesn’t work, obtain the distribution certificate manually, just as I described for a development certificate. In theory, Xcode can also create an appropriate distribution profile for you when you export your archive. However, I have never found this to work reliably; I always create my distribution profiles manually, at the Member Center, in a web browser. Here’s how to do that: 1. If this is to be an Ad Hoc distribution profile, collect the UDIDs of all the devices where this build is to run, and add each of them at the Member Center under Devices. (For an App Store distribution profile, omit this step.) 2. Make sure that the app is registered at the Member Center, as I described earlier in this chapter. 3. At the Member Center, under Provisioning Profiles, click the Plus button to ask for a new profile. In the Add iOS Provisioning Profile form, specify an Ad Hoc profile 404 | Chapter 9: Life Cycle of a Project or an App Store profile. On the next screen, choose your app from the pop-up menu. On the next screen, choose your distribution certificate. On the next screen, for an Ad Hoc profile only, specify the devices you want this app to run on. On the next screen, give the profile a name. Be careful about the profile’s name, as you will need to be able to recognize it later from within Xcode! My own practice is to assign a name containing the term “Ad‐ Hoc” or “AppStore” and the name of the app. 4. Click Generate to generate the profile. To obtain the profile, either click Download and then find the downloaded profile and double-click it to get Xcode to see it, or else open the View Details dialog in Xcode’s Accounts preference pane and click the Refresh button at the bottom left to make Xcode download it. Ad Hoc Distribution 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, though it does work, 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. Here are the steps for creating an Ad Hoc distribution file: 1. If necessary, create an archive of your app, as described in the previous section. If necessary, create, download, and install an Ad Hoc distribution profile for this app. 2. In the Organizer window, under Archives, select the archive and click the Export button at the upper right of the window. A dialog appears. Here, you are to specify a method; choose Save for Ad Hoc Deployment. Click Next. 3. You are now asked to select a Development Team. Select the correct team and click Choose. 4. The archive is prepared, and a summary window is displayed. The name of the provisioning profile is shown, so you can tell that the right thing is happening (Figure 9-17). For a Swift app, the embedded Swift dynamic libraries are also listed. Click Export. 5. A Save dialog appears. Give the file a useful name; this won’t affect the name of the app. Save the file to disk in a good place, such as the Desktop. It will have the suffix .ipa (“iPhone app”). 6. Locate in the Finder the file you just saved. Provide this file to your users with instructions. Ad Hoc Distribution | 405 Figure 9-17. Exporting an Ad Hoc build 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 (or double- click the .ipa file). Then the user should connect the device to the computer, make certain the app is present in the list of apps for this device and that it will be installed on the next sync, and finally sync the device to cause the app to be 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 (you can do that through the Devices window in Xcode). 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. Because you are not privileged over your other Ad Hoc testers, what works for you should work for them. There is a registration limit of 100 devices per year per developer (not per app), which limits your number of Ad Hoc testers. Devices used for development are counted against 406 | Chapter 9: Life Cycle of a Project this limit. You can work around this limit, and provide your betas more conveniently to testers, by using TestFlight beta testing instead. TestFlight beta testing is new in iOS 8. It lifts the limit of 100 devices to a limit of 1000 testers, and is more convenient than Ad Hoc distribution because your users download and install prelease versions of your app directly from the App Store onto their devices through the TestFlight app (acquired by Apple in 2014 by buying Burstly, http:// www.testflightapp.com). Configuration is performed at the iTunes Connect site; a pre‐ release version uploaded to iTunes Connect must be archived as if for App Store dis‐ tribution (see the discussion of App Store submission later in this chapter). Prerelease versions of your app intended for distribution to beta testers (as opposed to internal testers who have direct access to your iTunes Connect account) require review by Apple. See the “TestFlight Beta Testing” chapter of Apple’s iTunes Connect Developer Guide. 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 and massive profits hasten you past the all- important final stages of app preparation. Apple has a lot of requirements, and failure to meet them can cause your app to be rejected. Take your time. Make a checklist and go through it carefully. See Apple’s App Distribution Guide as well as the “Icon and Image Design” chapter of the Human Interface Guidelines for full details. Icons in the App The simplest way to provide your app with icons is to use the Asset Catalog. If you’re not using an asset catalog for icons and you’d like to switch to using one, edit the target and, in the General pane, under App Icons and Launch Images, next to App Icons Source, click the Use Asset Catalog button. The Use Asset Catalog button then changes to a pop-up menu listing the asset catalog’s name and the name of the image set within the catalog to be used for icons. The image sizes needed are listed in the asset catalog itself. Select an image slot and look in the Attributes inspector, under Expected Size. Confusingly, “2x” or “3x” means that the image should be double or triple the listed dimensions for an icon; thus, for example, an iPhone app icon listed as “60pt” but “3x” means that you should provide an image measuring 180×180. To determine which slots should be displayed, use the checkboxes in the Attributes inspector when you select an icon set or launch image set (Figure 9-18). To add an image, drag it from the Finder into the appropriate slot. An icon file must be a PNG file, without alpha transparency. It should be a full square; the rounding of the corners will be added for you. Apple seems nowadays to prefer simple, cartoony images with a few bright colors and possibly a gentle gradient back‐ ground. Final App Preparations | 407 Figure 9-18. Icon slots in the asset catalog When your app is built and the app catalog is processed, the icons are written out to the top level of the app bundle and are given appropriate names; at the same time, an ap‐ propriate entry is written into the app’s Info.plist, enabling the system to find and display the icon on a device. The details are complicated, but you won’t have to worry about them — which is exactly why you’re using the asset catalog! App icon sizes have changed over the years. If your app is to be backward-compatible to systems earlier than iOS 8, you will need additional icons in additional sizes, corre‐ sponding to the expectations of those earlier systems. Again, this is exactly the sort of thing the asset catalog will help you with. 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. (That’s what the first two slots are for in Figure 9-18.) However, I never include those icons. Other Icons When you submit an app to the App Store, you will be asked to supply a 1024×1024 PNG or high-quality JPEG icon to be displayed at the App Store. 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 bitter 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. 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 an iTunesArtwork icon for Ad Hoc distribution, you may wish to delete it from the Copy Bundle Resources build phase now. 408 | Chapter 9: Life Cycle of a Project 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 a visible indication that something is happening, a launch image needs to be displayed during that interval. The launch image needn’t be detailed. It might be just a blank depiction of the main elements or regions of the interface that will be present when the app has finished launching. In this way, when the app does finish launching, the transition from the launch image to the real app will be a matter of those elements or regions being filled in. In iOS 7 and before, the launch image was literally an image (a PNG file). It had to be included in your app bundle, and it had to obey certain naming conventions. As the variety of screen sizes and resolutions of iOS devices proliferated, so did the number of required launch images. The asset catalog, introduced in iOS 7, was helpful in this re‐ gard. But in iOS 8, which runs on the iPhone 6 and iPhone 6 Plus, the entire situation threatens to become unmanageable. For this reason, iOS 8 introduces a better solution. Instead of a set of launch images, you provide a launch nib file — a single .xib or .storyboard file containing a single view to be displayed as a launch image. You construct this view using subviews and autolay‐ out. Thus, the view is automatically reconfigured to match the screen size and orienta‐ tion of the device on which the app is launching. By default, a new app project comes with a LaunchScreen.xib file. This is where you design your launch image. The Info.plist points to this file as the value of its “Launch screen interface file base name” key (UILaunchStoryboardName). You can configure the Info.plist easily, if necessary, by editing the target and setting the Launch Screen File field (under App Icons and Launch Images). You should take advantage of this feature — and not merely because it is convenient. The presence of a “Launch screen interface file base name” key in your Info.plist is how the system knows that your app runs natively on the iPhone 6 and iPhone 6 Plus. If you don’t have this key, your app will be displayed zoomed, as if the iPhone 6 were just a big iPhone 5S — in effect, you won’t be getting all the pixels you’re entitled to (and the display will be somewhat fuzzy). The bad news is that if your app is to be backward-compatible to earlier systems, you’ll have to supply old-fashioned launch images in addition to the launch nib file. You need the launch nib file because your app won’t be fully iOS 8–native without it. You need the launch images because systems prior to iOS 8 have never heard of a launch nib file! The requirements for launch images in iOS 7 and before are complicated — and are made more complicated by the fact that the rules have changed over the years, so that Final App Preparations | 409 the more systems you want to be compatible with, the more requirements you’ll have to satisfy. I have covered these requirements in earlier editions of this book, and I’m not going to repeat them here. Apple provides an extremely helpful sample code project called Application Icons and Launch Images for iOS. It provides icons and launch images of all sizes and demonstrates the proper naming conventions. Screenshots and Video Previews When you submit your app to the App Store, you will be asked for one or more screen‐ shots 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, in the appendix “iTunes Connect App Properties.” The dimensions of a screenshot depend on its orientation and the screen size. You must provide at least one screenshot corre‐ sponding to the screen size of every device on which your app can run, in the corre‐ sponding resolution. You can obtain screenshots either from the Simulator or from a device connected to the computer: Simulator Run the app in the Simulator, first setting the destination to get the desired device type and resolution. Choose File → Save Screen Shot. Device In Xcode, in the Devices window, locate your connected device under Devices and click Take Screenshot. Alternatively, choose Debug → View Debugging → Take Screenshot of [Device]. In both cases, the screenshot file is saved to wherever screenshots are normally saved on your computer (usually the Desktop). You can also take a screenshot on a device by clicking the screen lock button and the Home button simultaneously. Now the screenshot is in the Camera Roll in the Photos app, and you can communicate it to your computer in any convenient way (such as by emailing it to yourself). New in iOS 8, you can also submit to the App Store a video preview showing your app in action. It can be up to 30 seconds long, in H.264 or Apple ProRes format. Your computer can capture video of your device if it is running OS X 10.10 (“Yosemite”) or later. Your device must be sufficiently modern to have a Lightning connector: 410 | Chapter 9: Life Cycle of a Project 1. Connect the device to the computer and launch QuickTime Player. Choose File → New Movie Recording. 2. If necessary, set the Camera and Microphone to the device, using the pop-up menu from the down-pointing chevron button next to the Record button that appears when you hover the mouse over the QuickTime Player window. 3. Start recording, and exercise the app on the device. When you’re finished, stop recording and save. The resulting movie file can be edited in iMovie or Final Cut Pro to prepare it for submission to the App Store. For example, in iMovie: 1. After importing the movie file, choose File → New App Preview. 2. Edit! When you’re done editing, choose File → Share → App Preview. This ensures the correct resolution and format. For more details, see the “App Preview” section of the “First Steps” chapter of Apple’s iTunes Connect Developer Guide. Property List Settings A number of settings in the 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. I talked earlier in this chapter about how to localize the display name. Supported interface orientations (UISupportedInterfaceOrientations) This key designates the totality of orientations in which the app is ever permitted to appear. You can perform this setting with checkboxes in the General tab of the target editor. 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. But don’t use this key unless it makes no sense for your app to run at all on a device lacking the specified capabilities. Final App Preparations | 411 Bundle version (CFBundleVersion) Your app needs a version number. The best place to set it is the General tab of the target editor. Things are a little confusing here because there is both a Version field and a Build field; the former corresponds in the Info.plist to “Bundle versions string, short” (CFBundleShortVersionString), while the latter corresponds 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 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 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 web site. 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 sooner or later 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. Apple recommends that this be 25 characters or fewer, though it can be longer. 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 necessitate a certain amount of last-minute scrambling on your part. 412 | Chapter 9: Life Cycle of a Project 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 web site 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 arbitrary, 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. When you’re ready to upload the app for which you’ve already submitted the informa‐ tion at iTunes Connect, you can perform the upload using Xcode. Select the archived build in the Organizer and click Submit. The upload will be performed, and the app will be validated 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 | 413 PART III Cocoa The Cocoa Touch frameworks provide the general capabilities required by any iOS application. Buttons can be tapped, text can be read, screens of interface can succeed one another, because Cocoa makes it so. To use the framework, you must learn to let the framework use you. You must put your code in the right place so that it will be called at the right time. You must fulfill certain obligations that Cocoa expects of you. You master Cocoa by being Cocoa’s obedient servant. In this part of the book, that’s what you’ll learn to do. • Chapter 10 describes how Cocoa is organized and structured through such Objective-C language features as subclassing, categories, and protocols. Then some important built-in Cocoa object types are introduced. The chapter concludes with a description of Cocoa key–value coding and a look at how the root NSObject class is organized. • Chapter 11 presents Cocoa’s event-driven model of activity, along with its major design patterns and event-related features — notifications, delegation, data sources, target–action, the responder chain, and key–value observing. The chapter con‐ cludes with some words of wisdom about managing the barrage of events Cocoa will be throwing at you, and how to escape that barrage momentarily with delayed performance. • Chapter 12 is about Cocoa memory management. I’ll explain how memory man‐ agement of reference types works. Then some special memory management situa‐ tions are described: autorelease pools, retain cycles, notifications and timers, nib loading, and CFTypeRefs. The chapter concludes with a discussion of Cocoa prop‐ erty memory management, and advice on how to debug memory management issues. • Chapter 13 discusses the question of how your objects are going to see and com‐ municate with one another within the confines of the Cocoa-based world. It con‐ cludes with some advice about adhering to the model–view–controller architecture. Finally, don’t forget to read Appendix A for more detail about how Objective-C and Swift interact and cooperate. CHAPTER 10 Cocoa Classes When you program iOS, you’re programming Cocoa. So you need to be acquainted with Cocoa; you have to know, as it were, who you’re talking to when you talk to Cocoa, and what sort of behavior Cocoa is likely to expect from you. Cocoa is a big framework, subdivided into many smaller frameworks, and it takes time and experience to become reasonably familiar with it. (For full details, see my other book, Programming iOS 8.) Nevertheless, Cocoa has certain chief conventions and primary components that can serve as guideposts from the outset. The Cocoa API is written mostly in Objective-C, and Cocoa itself consists mostly of Objective-C classes, derived from the root class, NSObject. When programming iOS, you’ll be using mostly the built-in Cocoa classes. Objective-C classes are comparable to and compatible with Swift classes, but the other two Swift object type flavors, structs and enums, are not matched by anything in Objective-C. Structs and enums declared originally in Swift cannot generally be handed across the bridge from Swift to Objective- C and Cocoa. Fortunately, some of the most important native Swift object types are also bridged to Cocoa classes. (See Appendix A for more details about the Objective-C lan‐ guage and how communications work between Swift and Objective-C.) This chapter introduces Cocoa’s class structure. It discusses how Cocoa is conceptually organized, in terms of its underlying Objective-C features, and then surveys some of the most commonly encountered Cocoa utility classes, concluding with a discussion of the Cocoa root class and its features, which are inherited by all Cocoa classes. 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, and how to accept keyboard input. 417 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. This does not necessarily mean that you need to subclass! Cocoa classes are heavily endowed with methods that you can call, and properties that you can set, precisely in order to customize an instance, 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 documen‐ tation for UIButton shows that you can set a button’s title, title color, internal image, background image, and many other features and behaviors, without subclassing. 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 source code for 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. Certain Cocoa Touch classes are subclassed routinely. For example, a plain vanilla UIViewController, not subclassed, is very rare, and an iOS app without at least one UIViewController subclass would be practically impossible. Another case in point is UIView. Cocoa Touch is full of built-in UIView subclasses that behave and draw themselves as needed (UIButton, UITextField, and so on), and you will rarely need to subclass any of them. On the other hand, you might create your own UIView subclass, whose job would be to draw itself in some completely new way. 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 that … draw their view’s content should override this method and implement their drawing code there.” The documen‐ tation is saying that you need to subclass UIView in order to draw content that is com‐ pletely your own. 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 iOS → Source → Cocoa Touch Class, and in particular a subclass of UIView. Call the class MyHorizLine. Xcode creates MyHorizLine.swift. Make sure it’s part of the app target. 2. In MyHorizLine.swift, replace the contents of the class declaration with this (without further explanation): 418 | Chapter 10: Cocoa Classes required init(coder aDecoder: NSCoder) { super.init(coder:aDecoder) self.backgroundColor = UIColor.clearColor() } override func drawRect(rect: CGRect) { let c = UIGraphicsGetCurrentContext() CGContextMoveToPoint(c, 0, 0) CGContextAddLineToPoint(c, self.bounds.size.width, 0) CGContextStrokePath(c) } 3. Edit the storyboard. Find UIView in the Object library (it is called simply “View”), 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 nib. 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‐ class to modify the way it already draws itself. For example, the UILabel 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, automatically, by Cocoa, as a label draws itself; thus, we can subclass UILabel and implement these methods 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 over‐ ridden method, you can configure the current 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; call the class MyBoundedLabel. 2. In MyBoundedLabel.swift, insert this code into the body of the class declaration: override func drawTextInRect(rect: CGRect) { let context = UIGraphicsGetCurrentContext() CGContextStrokeRect(context, CGRectInset(self.bounds, 1.0, 1.0)) super.drawTextInRect(CGRectInset(rect, 5.0, 5.0)) } Subclassing | 419 3. Edit the storyboard, add a UILabel to the interface, 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. Oddly enough, however (and you might be particularly surprised by this if you’ve used another object-oriented application framework), subclassing is one of the rarer ways in which your code will relate to Cocoa. Knowing when to subclass can be somewhat tricky, but the general rule is that you probably shouldn’t subclass unless you’re explicitly invited to do so. Most built-in Cocoa Touch classes will never need subclassing (and some, in their documentation, downright forbid it). One reason why subclassing is rare in Cocoa is that so many built-in classes use dele‐ gation (Chapter 11) as the preferred way of letting you customize their behavior. For example, you wouldn’t subclass UIApplication (the class of the singleton shared appli‐ cation instance) just in order to respond when the application has finished launching, because the delegate mechanism provides a way to do that (application:didFinish- LaunchingWithOptions:). That’s why the templates give us an AppDelegate class, which is not a UIApplication subclass, but which does adopt the UIApplicationDelegate pro‐ tocol. On the other hand, if you needed to perform certain tricky customizations of your app’s fundamental event messaging behavior, you might subclass UIApplication in order to override sendEvent:. The documentation has a special “Subclassing Notes” section that tells you this, and also tells you, rightly, that doing so would be “very rare.” (See Chap‐ ter 6 on how to ensure that your UIApplication subclass is instantiated as the app launches.) Categories and Extensions A category is an Objective-C language feature that allows code to reach right into an existing class and inject additional methods. This is comparable to a Swift extension (see Chapter 4). Using a Swift extension, you can add class or instance methods to a Cocoa class; the Swift headers make heavy use of extensions, both as a way of organizing Swift’s own object types and as a way of modifying Cocoa classes. In the same way, Cocoa uses categories to organize its own classes. Objective-C categories have names, and you may see references to these names in the headers, the documentation, and so forth. However, the names are effectively meaningless, so don’t worry about them. 420 | Chapter 10: Cocoa Classes How Swift Uses Extensions If you look in the main Swift header, you’ll see that many native object type declarations consist of an initial declaration followed by a series of extensions. For example, after declaring the generic struct Array, the header proceeds to declare no fewer than eight extensions on the Array struct. Some of these add protocol adoptions; most of them don’t. All of them add declarations of properties or methods to Array; that’s what extensions are for. These extensions are not, of themselves, functionally significant; the header could have declared the Array struct with all of those properties and methods within the body of a single declaration. Instead, it breaks things up into multiple extensions. The extensions are simply a way of clumping related functionality together, organizing this object type’s members so as to make them easier for human readers to understand. In the Swift Core Graphics header, just about everything is an extension. Here Swift is adapting types defined elsewhere — adapting Swift numeric types for use with Core Graphics and the CGFloat numeric type, and adapting Cocoa structs such as CGPoint and CGRect as Swift object types. CGRect, in particular, is provided with numerous additional properties, initializers, and methods so that you can work with it directly as a Swift struct rather than having to call the Cocoa Core Graphics C utility functions that manipulate a CGRect. How You Use Extensions Swift permits you to write global functions, and there is nothing formally wrong with doing so. Nevertheless, for the sake of object-oriented encapsulation, you will often want to write a function as part of an existing object type. It will often be simplest and most sensible for you to inject such functions into an existing object type with an extension. Subclassing merely to add a method or two is heavy-handed — and besides, it often wouldn’t help you do what you need to do. (Besides, extensions work on all three flavors of Swift object type, whereas you can’t subclass a Swift enum or struct.) For example, suppose you wanted to add a method to Cocoa’s UIView class. You could subclass UIView and declare your method, but then it would be present only in your UIView subclass and in subclasses of that subclass: it would not be present in UIButton, UILabel, and all the other built-in UIView subclasses — because they are subclasses of UIView, not of your subclass, and you can’t do anything to change that! An extension, on the other hand, solves the problem beautifully: you inject your method into UIView, and it is inherited by all built-in UIView subclasses as well. Chapter 4 provides some examples of extensions I’ve written in my real iOS program‐ ming life (see “Extensions” on page 196). Also, as I explain there, I often use extensions in the same way as the Swift headers do, organizing my code for a single object type into multiple extensions simply for clarity. Categories and Extensions | 421 How Cocoa Uses Categories Cocoa uses categories as an organizational tool very much as Swift uses extensions. The declaration of a class will often be divided by functionality into multiple categories, and these will often appear in separate header files. 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, aside from its initializers, has just two methods, length and characterAtIndex:, because these are regarded as the minimum functionality that a string needs in order to be a string. Additional NSString methods — those that create a string, deal with a string’s encoding, split a string, search in a string, and so on — are clumped into categories. These are shown in the Swift translation of the header as extensions. So, for example, after the declaration for the String class itself, we find this in the Swift translation of the header: extension NSString { func getCharacters( buffer: UnsafeMutablePointer, range aRange: NSRange) func substringFromIndex(from: Int) -> String // ... } That, as it turns out, is actually Swift’s translation of this Objective-C code: @interface NSString (NSStringExtensionMethods) - (void)getCharacters:(unichar *)buffer range:(NSRange)aRange; - (NSString *)substringFromIndex:(NSUInteger)from; // ... @end That notation — the keyword @interface, followed by a class name, followed by an‐ other name in parentheses — is an Objective-C category. Moreover, although the declarations for some of Cocoa’s NSString categories appear in this same file, NSString.h, many of them appear elsewhere. For example: • A string may serve as a file pathname, so we also find a category on NSString in NSPathUtilities.h, where methods and properties such as pathComponents are de‐ clared for splitting a pathname string into its constituents and the like. • In NSURL.h, which is primarily devoted to declaring the NSURL class (and its categories), there’s also another NSString category, declaring methods for dealing with percent-escaping in a URL string, such as stringByAddingPercentEscapes- UsingEncoding. 422 | Chapter 10: Cocoa Classes • Off in a completely different framework (UIKit), NSStringDrawing.h adds two fur‐ ther NSString categories, with methods like drawAtPoint: having to do with draw‐ ing 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 together in the NSString class documentation page. But the NSString methods declared in NSStringDrawing.h are not; instead, they appear in a separate document, NSString UIKit Additions Reference. (Presumably, this is because because they originate in a different framework.) As a result, the string drawing methods can be difficult to discover, especially as the NSString class documentation page doesn’t link to the other document. I regard this as a major flaw in the structure of the Cocoa documentation. Protocols Objective-C has protocols, and these are generally comparable to and compatible with Swift protocols (see Chapter 4). Since classes are the only Objective-C object type, all Objective-C protocols are seen by Swift as class protocols. Conversely, Swift protocols marked as @objc (which are implicitly class protocols) can be seen by Objective-C. Cocoa makes extensive use of protocols. For example, let’s talk about how Cocoa objects are copied. 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 requred method, copyWith- Zone:. Here’s how the NSCopying protocol is declared in Objective-C (in NSObject.h): @protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end That’s translated into Swift as follows: protocol NSCopying { func copyWithZone(zone: NSZone) -> AnyObject } The NSCopying protocol declaration in NSObject.h, however, is not a statement that NSObject conforms to NSCopying. Indeed, NSObject does not conform to NSCopying! This doesn’t compile: let obj = NSObject().copyWithZone(nil) But this does compile, because NSString does conform to NSCopying (the literal "howdy" is implicitly bridged to NSString): Protocols | 423 let s = "howdy".copyWithZone(nil) A typical Cocoa pattern is that Cocoa wants to say: “An instance of any class will do here, provided it implements the following methods.” That, obviously, is a protocol. For example, consider how a protocol is used in connection with a table view (UITableView). A table view gets its data from a data source. For this purpose, UITableView declares a dataSource property, like this: @property (nonatomic, assign) id dataSource That’s translated into Swift as follows: unowned(unsafe) var dataSource: UITableViewDataSource? (Ignore, for the moment, the memory management attributes of this property; I’ll talk about them in Chapter 12.) UITableViewDataSource is a protocol. The table view is saying: “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. When you use a UITableView, and you want to provide it with a data source object, the class of that object will adopt UITableViewDataSource and will implement its required methods; otherwise, your code won’t compile: let mc = MyClass() let tv = UITableView() tv.dataSource = mc // compile error: Type 'MyClass'... // ...does not conform to protocol 'UITableViewDataSource' Far and away the most pervasive use of protocols in Cocoa is in connection with the delegation pattern. I’ll discuss this pattern in detail in Chapter 11, but you can readily see an example in our handy Empty Window project: the AppDelegate class provided by the project template is declared like this: class AppDelegate: UIResponder, UIApplicationDelegate { // ... AppDelegate’s chief purpose on earth is to serve as the shared application’s delegate. The shared application object is a UIApplication, and UIApplication’s delegate property is declared like this: unowned(unsafe) var delegate: UIApplicationDelegate? The UIApplicationDelegate type is a protocol. This is how the shared UIApplication object knows that its delegate might be capable of receiving messages such as application:didFinishLaunchingWithOptions:. So the AppDelegate class officially announces its role by explicitly adopting the UIApplicationDelegate protocol. A Cocoa protocol has its own documentation page. When the UIApplication class doc‐ umentation tells you that the delegate property is typed as a UIApplicationDelegate, 424 | Chapter 10: Cocoa Classes 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 docu‐ mentation. You won’t find application:didFinishLaunchingWithOptions: men‐ tioned anywhere on the UIApplication class documentation page! It’s documented in the UIApplicationDelegate protocol documentation page. This separation of information can be particularly confusing when a class adopts a protocol. When a class’s documentation mentions that the class conforms to a protocol, don’t forget to examine that protocol’s documentation! The latter might contain im‐ portant 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; you also need to look at any protocols that this object’s class (or superclass) conforms to. For example, as I already mentioned in Chapter 8, you won’t find out that UIViewController gets a viewWillTransitionToSize:withTransitionCoordinator: event by looking at the UIViewController class documentation page: you have to look in the documentation for the UIContentContainer protocol, which UIViewController adopts. 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, messages listed in the protocol are sent only to objects typed as id (AnyObject), thus suppressing any possible objections from the compiler. These techniques were widespread before protocols could declare methods as optional; now they are largely unnecessary, and are also mildly dangerous. In iOS 8, very few informal protocols remain — but they do exist. For example, NSKeyValueCoding (dis‐ cussed later in this chapter) is an informal protocol; you may see the term NSKey‐ ValueCoding in the documentation and elsewhere, but there isn’t actually any NSKey‐ ValueCoding type: it’s a category on NSObject. Optional Methods Objective-C protocols, and Swift protocols marked as @objc, can have optional mem‐ bers (see “Optional Protocol Members” on page 181). The question thus arises: How, in practice, is 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 Protocols | 425 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 both dynamic and introspective. Objective-C can ask an object whether it can really deal with a message without actually sending it that message. The key method here is NSObject’s respondsToSelector: method, which takes a selector parameter and returns a Bool. (A selector is basically a method name expressed independently of any method call; see Appendix A.) Thus it is possible to send a message to an object only if it would be safe to do so. Demonstrating respondsToSelector: in Swift is generally a little tricky, because it’s hard to get Swift to throw away its strict type checking long enough to let us send an object a message to which it might not respond. In this artificial example, I start by defining, at top level, two classes: one that derives from NSObject, because otherwise we can’t send respondsToSelector: to it, and another to declare the message that I want to send conditionally: class MyClass : NSObject { } class MyOtherClass { @objc func woohoo() {} } Now I can say this: let mc = MyClass() if mc.respondsToSelector("woohoo") { (mc as AnyObject).woohoo() } Note the cast of mc to AnyObject. This causes Swift to abandon its strict type checking (see “Suppressing type checking” on page 200); we can now send this object any message that Swift knows about, provided it is susceptible to Objective-C introspection — that’s why I marked my woohoo declaration as @objc to start with. As you know, Swift provides a shorthand for sending a message conditionally — append a question mark to the name of the message: let mc = MyClass() (mc as AnyObject).woohoo?() Behind the scenes, those two approaches are exactly the same; the latter is syntactic sugar for the former. In response to the question mark, Swift is calling respondsTo- Selector: for us, and will refrain from sending woohoo to this object if it doesn’t respond to this selector. That explains also how optional protocol members work. It is no coincidence that Swift treats optional protocol members like AnyObject members. Here’s the example I gave in Chapter 4: 426 | Chapter 10: Cocoa Classes @objc protocol Flier { optional var song : String {get} optional func sing() } When you call sing?() on an object typed as a Flier, respondsToSelector: is called behind the scenes to determine whether this call is safe. You wouldn’t want to send a message optionally, or call respondsToSelector: explicitly, before sending just any old message, because it isn’t generally necessary except with optional methods, and it slows things down a little. But Cocoa does in fact call responds- ToSelector: 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: override func respondsToSelector(aSelector: Selector) -> Bool { println(aSelector) return super.respondsToSelector(aSelector) } 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: application:didChangeStatusBarFrame: application:deviceAccelerated: application:deviceChangedOrientation: applicationDidBecomeActive: applicationWillResignActive: applicationDidEnterBackground: applicationWillEnterForeground: applicationWillSuspend: application:didResumeWithOptions: application:handleWatchKitExtensionRequest:reply: application:shouldSaveApplicationState: application:supportedInterfaceOrientationsForWindow: application:performFetchWithCompletionHandler: application:didReceiveRemoteNotification:fetchCompletionHandler: 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 Protocols | 427 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 one- time 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. Some Foundation Classes The Foundation classes of Cocoa provide basic data types and utilities that will form the basis of your communication with Cocoa. Obviously I can’t list all of them, let alone describe them fully, but I can survey those that you’ll probably want to be aware of before writing even the simplest iOS program. For more information, start with Apple’s list of the Foundation classes in the Foundation Framework Reference. Useful Structs and Constants NSRange is a C struct (see Appendix A) of importance in dealing with some of the classes I’m about to discuss. Its components are integers, location and length. For example, an NSRange 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 supplies various convenience functions for dealing with an NSRange; for exam‐ ple, you can create an NSRange from two integers by calling NSMakeRange. (Note that the name, NSMakeRange, is backward compared to names like CGPointMake and CGRect- Make.) Swift helps out by bridging NSRange as a Swift struct. Moreover, you can coerce between an NSRange and a Swift Range whose endpoints are Ints: Swift gives NSRange an initializer that takes a Swift Range, along with a toRange method. NSNotFound is a constant integer indicating that some requested element was not found. The true numeric value of NSNotFound is of no concern to you; always compare against NSNotFound itself, to learn whether a result is meaningful. For example, if you ask for the index of a certain object in an NSArray and the object isn’t present, the result is NSNotFound: let arr = ["hey"] as NSArray let ix = arr.indexOfObject("ho") if ix == NSNotFound { println("it wasn't found") } Why does Cocoa resort to an integer value with a special meaning in this way? Because it has to. The result could not be 0 to indicate the absence of the object, because 0 would 428 | Chapter 10: Cocoa Classes indicate the first element of the array. Nor could it be -1, because an NSArray index value is always positive. Nor could it be nil, because Objective-C can’t return nil when an integer is expected (and even if it could, it would be seen as another way of saying 0). Contrast Swift, whose find global method returns an Int wrapped in an Optional, allowing it to return nil to indicate that the target object wasn’t found. If a search returns a range and the thing sought is not present, the location component of the resulting NSRange will be NSNotFound. As I mentioned in Chapter 3, Swift will sometimes do some clever automatic bridging for you, thus saving you the trouble of comparing with NSNotFound. The canonical example is NSString’s rangeOfString: method. As defined in Cocoa, it returns an NSRange; Swift reconfigures it to return a Swift Range (of String.Index) wrapped in an Optional, returning nil if the NSRange’s location is NSNotFound: let s = "howdy" let r = s.rangeOfString("ha") // nil; an Optional wrapping a Swift Range That’s great if what you wanted is a Swift Range, suitable for further slicing a Swift String; but if you wanted an NSRange, suitable for handing back to Cocoa, you’ll need to cast your original Swift String to an NSString to start with — thus causing the result to remain in the Cocoa world: let s = "howdy" as NSString let r = s.rangeOfString("ha") // an NSRange if r.location == NSNotFound { println("it wasn't found") } NSString and Friends NSString is the Cocoa object version of a string. NSString and Swift String are bridged to one another, and you will often move between them without thinking, passing a Swift String to Cocoa where an NSString is expected, calling Cocoa NSString methods on a Swift String, and so forth. For example: let s = "hello" let s2 = s.capitalizedString In that code, s is a Swift String and s2 is a Swift String, but the capitalizedString property actually belongs to Cocoa. In the course of that code, a Swift String has been bridged to NSString and passed to Cocoa, which has processed it to get the capitalized string; the capitalized string is an NSString, but it has been bridged back to a Swift String. In all likelihood, you are not conscious of the bridging; capitalizedString feels like a native String property, but it isn’t — as you can readily prove by trying to use it in an environment where Foundation is not imported (you can’t do it). Some Foundation Classes | 429 In some cases, you will need to cross the bridge yourself by casting explicitly. The prob‐ lem typically arises where you need to provide an index on a string. For example: let s = "hello" let s2 = s.substringToIndex(4) // compile error The problem here is that the bridging is in your way. Swift has no objection to your calling the substringToIndex: method on a Swift String, but then the index value must be a String.Index, which is rather tricky to construct (see Chapter 3): let s2 = s.substringToIndex(advance(s.startIndex,4)) If you don’t want to talk that way, you must cast the String to an NSString beforehand; now you are in Cocoa’s world, where string indexes are integers: let s2 = (s as NSString).substringToIndex(4) As I explained in Chapter 3, however, those two calls are not equivalent: they can give different answers! The reason is that String and NSString have fundamentally different notions of what constitutes an element of a string (see “The String–NSString Element Mismatch” on page 93). A String is a Swift sequence, and must resolve its elements into characters, which means that it must walk the string, coalescing any combining code‐ points; an NSString behaves as if it were an array of UTF16 codepoints. On the Swift side, each increment in a String.Index corresponds to a true character, but access by index or range requires walking the string; on the Cocoa side, access by index or range is extremely fast, but might not correspond to character boundaries. (See the “Charac‐ ters and Grapheme Clusters” chapter of Apple’s String Programming Guide.) Another important difference between a Swift String and a Cocoa NSString is that an NSString is immutable. This means that, with NSString, you can do things such as obtain a new string based on the first — as capitalizedString and substringToIndex: do — but you can’t change the string in place. To do that, you need another class, a subclass of NSString, NSMutableString. NSMutableString has many useful methods, and you’ll probably want to take advantage of them; but Swift String isn’t bridged to NSMutable‐ String, so you can’t get from String to NSMutableString merely by casting. To obtain an NSMutableString, you’ll have to make one. The simplest way is with NSMutableString’s initializer init(string:), which expects an NSString — meaning that you can pass a Swift String. Coming back the other way, you can cast all the way from NSMutableString a Swift String in one move: let s = "hello" let ms = NSMutableString(string:s) ms.deleteCharactersInRange(NSMakeRange(ms.length-1,1)) let s2 = (ms as String) + "ion" // now s2 is a Swift String As I said in Chapter 3, native Swift String methods are thin on the ground. All the real string-processing power lives over on the Cocoa side of the bridge. So you’re going to 430 | Chapter 10: Cocoa Classes be crossing that bridge a lot! And this will not be only for the power of the NSString and NSMutableString classes. Many other useful classes are associated with them. For example, suppose you want to search a string for some substring. All the best ways come from Cocoa: • An NSString can be searched using various rangeOfString:... methods, with numerous options such as ignoring diacriticals, ignoring case, starting at the end, and insisting that the substring occupy the start or end of the searched string. • Perhaps you don’t know exactly what you’re looking for: you need to describe it structurally. 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. • By specifying the option .RegularExpressionSearch, you can search using a reg‐ ular expression. Regular expressions are also supported as a separate class, NSRegularExpression, which in turn uses NSTextCheckingResult to describe match results. • 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. In this example, our goal is to replace all occurrences of the word “hell” with the word “heaven.” We don’t want to replace mere occurrences of the substring “hell” — for ex‐ ample, “hello” should be left intact. Thus our search needs some intelligence as to what constitutes a word boundary. That sounds like a job for a regular expression. Swift doesn’t have regular expressions, so everything has to be done by Cocoa: var s = NSMutableString(string:"hello world, go to hell") let r = NSRegularExpression( pattern: "\\bhell\\b", options: .CaseInsensitive, error: nil)! r.replaceMatchesInString( s, options: nil, range: NSMakeRange(0,s.length), withTemplate: "heaven") NSString also 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. In addition, NSString — like some other classes discussed in this section — pro‐ vides methods for writing out to a file’s contents or reading in a file’s contents; the file can be specified either as an NSString file path or as an NSURL. 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 Some Foundation Classes | 431 font and size in which the string will display. If you want styled text — where different runs of text have different style attributes (size, font, color, and so forth) — you need to use NSAttributedString, along with its supporting classes NSMutableAttributedString, NSParagraphStyle, and NSMutableParagraphStyle. These allow you to style text and paragraphs easily in sophisticated ways. The built-in interface objects that display text can display an NSAttributedString. String drawing in a graphics context can be performed with methods provided through the NSStringDrawing category on NSString (see the String UIKit Additions Reference) and on NSAttributedString (see the NSAttributedString UIKit Additions Reference). 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’s initializer init() — i.e., saying NSDate() — gives you a date object for the current date and time. Date operations involving anything simpler than a count of seconds will involve the use of NSDate‐ Components, and conversions between NSDate and NSDateComponents require that you pass through an NSCalendar. Here’s an example of constructing a date based on its calendrical values: let greg = NSCalendar(calendarIdentifier:NSGregorianCalendar)! let comp = NSDateComponents() comp.year = 2015 comp.month = 8 comp.day = 10 comp.hour = 15 let d = greg.dateFromComponents(comp) // Optional wrapping NSDate Similarly, NSDateComponents provides the correct way to do date arithmetic. Here’s how to add one month to a given date: let d = NSDate() // or whatever let comp = NSDateComponents() comp.month = 1 let greg = NSCalendar(calendarIdentifier:NSGregorianCalendar)! let d2 = greg.dateByAddingComponents(comp, toDate:d, options:nil) You will also likely be concerned with dates represented as strings. If you don’t take explicit charge of a date’s string representation, it is represented by a string whose format may surprise you. For example, if you simply println an NSDate, you are shown the date in the GMT timezone, which can be confusing if that isn’t where you live. A simple solution is to call descriptionWithLocale:; the locale comprises the user’s current time zone, language, region format, and calendar settings: println(d) // 2015-02-02 16:36:41 +0000 println(d.descriptionWithLocale(NSLocale.currentLocale())) // Optional("Monday, February 2, 2015 at 8:36:41 AM Pacific Standard Time") 432 | Chapter 10: Cocoa Classes For exact creation and parsing of date strings, use NSDateFormatter, which uses a format string similar to NSLog (and NSString’s stringWithFormat:). In this example, we sur‐ render completely to the user’s locale by generating an NSDateFormatter’s format with dateFormatFromTemplate:options:locale: and the current locale. The “template” is a string listing the date components to be used, but their order, punctuation, and lan‐ guage are left up to the locale: let df = NSDateFormatter() let format = NSDateFormatter.dateFormatFromTemplate( "dMMMMyyyyhmmaz", options:0, locale:NSLocale.currentLocale()) df.dateFormat = format let s = df.stringFromDate(NSDate()) // just now The result is the date shown in the user’s time zone and language, using the correct linguistic conventions. It involves a combination of region format and language, which are two separate settings. Thus: • On my device, the result might be “February 2, 2015, 8:36 AM PST.” • If I change my device’s region to France, it might be “2 February 2015 8:36 am GMT-8.” • If I also change my device’s language to French, it might be “2 février 2015 8:36 AM UTC−8.” NSNumber An NSNumber is an object that wraps a numeric value. The wrapped value can be any standard Objective-C numeric type (including BOOL, the Objective-C equivalent of Swift Bool). It comes as a surprise to Swift users that NSNumber is needed. But an ordinary number in Objective-C is not an object (it is a scalar; see Appendix A), so it cannot be used where an object is expected. Thus, NSNumber solves an important problem, converting a number into an object and back again. Swift does its best to shield you from having to deal directly with NSNumber. It bridges Swift numeric types to Objective-C in two different ways: • If an ordinary number is expected, a Swift number is bridged to an ordinary number (a scalar). • If an object is expected, a Swift number is bridged to an NSNumber. Here’s an example: let ud = NSUserDefaults.standardUserDefaults() ud.setInteger(0, forKey: "Score") ud.setObject(0, forKey: "Score") Some Foundation Classes | 433 The second and third lines look alike, but Swift treats the literal 0 differently: In the second line, setInteger:forKey: expects an integer (a scalar) as its first parameter, so Swift turns the Int struct value 0 into an ordinary Objective-C number. In the third line, setObject:forKey: expects an object as its first parameter, so Swift turns the Int struct value 0 into an NSNumber. Naturally, if you need to cross the bridge explicitly, you can. You can cast a Swift number to an NSNumber: let n = 0 as NSNumber For more control over what numeric type an NSNumber will wrap, you can call one of NSNumber’s initializers: let n = NSNumber(float:0) Coming back from Objective-C to Swift, a value will typically arrive as an AnyObject and you will have to cast down. NSNumber comes with properties for accessing the wrapped value by its numeric type. Recall this example from Chapter 5, involving an NSNumber extracted as a value from an NSNotification’s userInfo dictionary: if let ui = n.userInfo { if let prog = ui["progress"] as? NSNumber { self.progress = prog.doubleValue } } If an AnyObject is actually an NSNumber, you can cast all the way down to a Swift numeric type. Thus, the same example can be rewritten like this, without explicitly mentioning NSNumber: if let ui = n.userInfo { if let prog = ui["progress"] as? Double { self.progress = prog } } In the second version, Swift is actually doing behind the scenes exactly what we did in the first version — treating an AnyObject as an NSNumber and getting its double- Value property to extract the wrapped number. An NSNumber object is just a wrapper and no more. It can’t be used directly for numeric calculations; it isn’t a number. It wraps a number. One way or another, if you want a number, you have to extract it from the NSNumber. An NSNumber subclass, NSDecimalNumber, on the other hand, can be used in calcu‐ lations, thanks to a bunch of arithmetic methods: 434 | Chapter 10: Cocoa Classes let dec1 = NSDecimalNumber(float: 4.0) let dec2 = NSDecimalNumber(float: 5.0) let sum = dec1.decimalNumberByAdding(dec2) // 9.0 NSDecimalNumber is useful particularly for rounding, because there’s a handy way to specify the desired rounding behavior. Underlying NSDecimalNumber is the NSDecimal struct (it is an NSDecimalNumber’s decimalValue). NSDecimal comes with C functions that are faster than NSDecimal‐ Number methods. NSValue NSValue is NSNumber’s superclass. It is used for wrapping nonnumeric C values, such as C structs, where an object is expected. The problem being solved here is parallel to the problem solved by NSNumber: a Swift struct is an object, but a C struct is not, so a struct cannot be used in Objective-C where an object is expected. Convenience methods provided through the NSValueUIGeometryExtensions category on NSValue (see the NSValue UIKit Additions Reference) allow easy wrapping and un‐ wrapping of CGPoint, CGSize, CGRect, CGAffineTransform, UIEdgeInsets, and UIOffset; additional categories allow easy wrapping and unwrapping of NSRange, CATransform3D, 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. Swift will not magically bridge any of these C struct types to or from an NSValue. You must manage them explicitly, exactly as you would do if your code were written in Objective-C. In this example from my own code, we use Core Animation to animate the movement of a button in the interface from one position to another; the button’s starting and ending positions are each expressed as a CGPoint, but an animation’s from- Value and toValue must be objects. A CGPoint is not an Objective-C object, so we must wrap the CGPoint values in NSValue objects: let ba = CABasicAnimation(keyPath:"position") ba.duration = 10 ba.fromValue = NSValue(CGPoint:self.oldButtonCenter) ba.toValue = NSValue(CGPoint:goal) self.button.layer.addAnimation(ba, forKey:nil) Similarly, you can make an array of CGPoint in Swift, because CGPoint becomes a Swift object type (a Swift struct), and a Swift Array can have elements of any type; but you can’t hand such an array to Objective-C, because an Objective-C NSArray must have objects as its elements, and a CGPoint, in Objective-C, is not an object. Thus you must wrap the CGPoints in NSValue objects first. This is another animation example, where I set the values array (an NSArray) of a keyframe animation by turning an array of CGPoints into an array of NSValues: Some Foundation Classes | 435 anim.values = [oldP,p1,p2,newP].map{NSValue(CGPoint:$0)} 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, NSURLConnection and NSURLSession supply whatever they retrieve from the Internet as NSData. Trans‐ forming 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: let ud = NSUserDefaults.standardUserDefaults() let c = UIColor.blueColor() let cdata = NSKeyedArchiver.archivedDataWithRootObject(c) ud.setObject(cdata, forKey: "myColor") Equality and Comparison In Swift, the equality and comparison operators can be overridden for an object type that adopts Equatable and Comparable (“Operators” on page 245). But Objective-C operators can’t do that; they are applicable only to scalars. To permit determination of whether two objects are “equal” — whatever that may mean for this object type — an Objective-C class must implement isEqual:, which is inherited from NSObject. Swift will help out by treating NSObject as Equatable and by permitting the use of the == operator, implicitly converting it to an isEqual: call. Thus, if a class does implement isEqual:, ordinary Swift comparison will work. For example: let n1 = NSNumber(integer:1) let n2 = NSNumber(integer:2) let n3 = NSNumber(integer:3) let ok = n2 == 2 // true let ok2 = n2 == NSNumber(integer:2) // true let ix = find([n1,n2,n3], 2) // Optional wrapping 1 That code seems to do three impossible things before breakfast: We directly compare an Int to an NSNumber, and we get the right answer, as if we were comparing the Int to the integer wrapped by that NSNumber. 436 | Chapter 10: Cocoa Classes We directly compare two NSNumber objects to one another, and we get the right answer, as if we were comparing the integers that they wrap. We treat an array of NSNumber objects as an array of Equatables and pass it to the find function, and we successfully determine which NSNumber object is “equal” to an actual number. There are two parts to this apparent magic: • The numbers are being wrapped in NSNumber objects for us. • The == operator (also used behind the scenes by the find function) is being con‐ verted to an isEqual: call. NSNumber implements isEqual: to compare two NSNumber objects by comparing the numeric values that they wrap; therefore the equality comparisons all work correctly. If an NSObject subclass doesn’t implement isEqual:, it inherits NSObject’s implemen‐ tation, which compares the two objects for identity (like Swift’s === operator). For ex‐ ample, these two Dog objects can be compared with the == operator, even though Dog does not adopt Equatable, because they derive from NSObject — but Dog doesn’t im‐ plement isEqual:, so == defaults to NSObject’s identity comparison: class Dog : NSObject { var name : String init(_ name:String) {self.name = name} } let d1 = Dog("Fido") let d2 = Dog("Fido") let ok = d1 == d2 // false A number of classes that implement isEqual: also implement more specific and effi‐ cient tests. The usual Objective-C way to determine whether two NSNumber objects are equal (in the sense of wrapping identical numbers) is by calling isEqualTo- Number:. Similarly, NSString has isEqualToString:, NSDate has isEqualToDate:, and so forth. However, these classes do also implement isEqual:, so I don’t think there’s any reason not to use the Swift == operator. Similarly, in Objective-C it is up to individual classes to supply ordered comparison methods. The standard method is called compare:, and returns one of three NSComparisonResult cases: .OrderedAscending The receiver is less than the argument. .OrderedSame The receiver is equal to the argument. Some Foundation Classes | 437 .OrderedDescending The receiver is greater than the argument. Swift comparison operators (< and so forth) do not magically call compare: for you. You can’t compare two NSNumber values directly: let n1 = NSNumber(integer:1) let n2 = NSNumber(integer:2) let ok = n1 < n2 // compile error You will typically fall back on calling compare: yourself, exactly as in Objective-C: let n1 = NSNumber(integer:1) let n2 = NSNumber(integer:2) let ok = n1.compare(n2) == .OrderedAscending // true NSIndexSet NSIndexSet represents 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. 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 this NSIndexSet might consist of two NSRange structs, {1,4} and {8,3}, and NSIndex‐ Set’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: var arr = ["zero", "one", "two", "three", "four", "five"] arr.extend(["six", "seven", "eight", "nine", "ten"]) let ixs = NSMutableIndexSet() ixs.addIndexesInRange(NSRange(1...4)) ixs.addIndexesInRange(NSRange(8...10)) let arr2 = (arr as NSArray).objectsAtIndexes(ixs) To walk through (enumerate) the index values specified by an NSIndexSet, you can use for...in; alternatively, you can walk through an NSIndexSet’s indexes or ranges by calling enumerateIndexesUsingBlock: or enumerateRangesUsingBlock: or their var‐ iants. 438 | Chapter 10: Cocoa Classes NSArray and NSMutableArray NSArray is Objective-C’s array object type. It is fundamentally similar to Swift Array, and they are bridged to one another; but when crossing the bridge, certain restrictions must be obeyed: • NSArray elements must be Objective-C objects. That means, in effect, that they must be class instances, or instances of Swift types that are bridged to Objective-C class types. • NSArray has no information as to the type of its elements. Unlike Swift, different elements can be of different types. Therefore, any NSArray arriving from Objective- C into Swift is typed as [AnyObject]. For a full discussion of how to bridge back and forth between Swift Array and Objective- C NSArray, implicitly and by casting, see “Swift Array and Objective-C NSArray” on page 215. An NSArray’s length is its count, and a particular object can be obtained by index number using objectAtIndex:. The index of the first object, as with a Swift Array, is zero, so the index of the last object is count minus one. Instead of calling objectAtIndex:, you can use subscripting with an NSArray. This is not because NSArray is bridged to Swift Array, but because NSArray implements object- AtIndexedSubscript:. This method is the Objective-C equivalent of a Swift subscript getter, and Swift knows this. In fact, by a kind of trickery, when you examine the NSArray header file translated into Swift, this method is shown as a subscript declaration! Thus, the Objective-C version of the header file shows this declaration: - (id)objectAtIndexedSubscript:(NSUInteger)idx; But the Swift version of the same header file shows this: subscript (idx: Int) -> AnyObject { get } You can seek an object within an array with indexOfObject: or indexOfObject- IdenticalTo:; the former’s idea of equality is to call isEqual:, whereas the latter uses object identity (like Swift’s ===). As I mentioned earlier, if the object is not found in the array, the result is NSNotFound. Unlike a Swift Array, and like an Objective-C NSString, 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 while staying in the Objective-C world, you can derive a new array consisting of the original array plus or minus some objects, or use NSArray’s subclass, NSMutableArray. Swift Array is not bridged to NSMutable‐ Some Foundation Classes | 439 Array; if you want an NSMutableArray, you must create it. The simplest way is with the NSMutableArray initializers, init() or init(array:). Once you have an NSMutableArray, you can call methods such as NSMutableArray’s addObject: and replaceObjectAtIndex:withObject:. You can also assign into an NSMutableArray using subscripting. Again, this is because NSMutableArray imple‐ ments a special method, setObject:atIndexedSubscript:; Swift recognizes this as equivalent to a subscript setter. Coming back the other way, you cannot cast directly from NSMutableArray to a Swift Array of any type other than [AnyObject]; the usual approach is to cast up from NSMutableArray to NSArray and then down to a specific type of Swift Array: let marr = NSMutableArray() marr.addObject(1) // an NSNumber marr.addObject(2) // an NSNumber let arr = marr as NSArray as! [Int] Cocoa provides ways to search or filter an array using a block. You can also derive a sorted version of an array, supplying the sorting rules in various ways, or if it’s a mutable array, you can sort it directly. You might prefer to perform those kinds of operation in the Swift Array world, but it can be useful to know how to do them the Cocoa way. For example: let pep = ["Manny", "Moe", "Jack"] as NSArray let ems = pep.objectsAtIndexes( pep.indexesOfObjectsPassingTest { obj, idx, stop in return (obj as! NSString).rangeOfString( "m", options:.CaseInsensitiveSearch ).location == 0 } ) // ["Manny", "Moe"] NSDictionary and NSMutableDictionary NSDictionary is Objective-C’s dictionary object type. It is fundamentally similar to Swift Dictionary, and they are bridged to one another; but when crossing the bridge, certain restrictions must be obeyed: • NSDictionary keys will usually be an NSString, but they don’t have to be; the formal requirement is that they be Objective-C objects whose classes adopt NSCopying. NSDictionary uses hashing under the hood, but it does not formally require hash‐ ability, because NSObject itself is hashable. Therefore, the Swift equivalent is to see NSDictionary keys as a form of NSObject, which Swift extends to adopt Hashable. • NSDictionary values must be Objective-C objects. 440 | Chapter 10: Cocoa Classes • NSDictionary has no information as to the type of its keys and values. Unlike Swift, different keys can be of different types, and different values can be of different types. Therefore, any NSDictionary arriving from Objective-C into Swift is typed as [NSObject:AnyObject]. See “Swift Dictionary and Objective-C NSDictionary” on page 221 for a full discussion of how to bridge back and forth between Swift Dictionary and Objective-C NSDiction‐ ary, including casting. An NSDictionary is immutable; its mutable subclass is NSMutableDictionary. Swift Dictionary is not bridged to NSMutableDictionary; you can most easily make an NSMutableDictionary with an initializer, init() or init(dictionary:). The keys of an NSDictionary 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 replaced. This is parallel to the behavior of Swift Dictionary. 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. In Objective-C, nil is not an object, and thus cannot be a value in an NSDictionary; the meaning of this response is thus unambiguous. Swift handles this by treating the result of objectForKey: as an Any- Object? — that is, an Optional wrapping an AnyObject. Subscripting is possible on an NSDictionary or an NSMutableDictionary for similar reasons to why subscripting is possible on an NSArray or an NSMutableArray. NSDic‐ tionary implements objectForKeyedSubscript:, and Swift understands this as equiv‐ alent to a subscript getter. In addition, NSMutableDictionary implements set- Object:forKeyedSubscript:, and Swift understands this as equivalent to a subscript setter. You can get from an NSDictionary a list of keys (allKeys), a list of values (all- Values), or a list of keys sorted by value. You can also walk through the key–value pairs together using a block, and you can even filter an NSDictionary by a test against its values. NSSet and Friends An NSSet is an unordered collection of distinct objects. “Distinct” means that no two objects in a set can return true 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 NSArray. Indeed, much of what you can Some Foundation Classes | 441 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 — you can even fetch an element by subscripting (because it implements objectAtIndexedSubscript:). But an ordered set’s elements must be distinct. 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 worthwhile to use NSOrderedSet instead of NSArray wherever possible. 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 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 you can insert into by subscripting, because it 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 often referred to as a bag). It is imple‐ mented as a set plus a count of how many times each element has been added. In Swift 1.2, Set is bridged to NSSet, with restrictions similar to NSArray. Nothing in Swift is bridged to NSMutableSet, NSCountedSet, NSOrderedSet, or NSMutable‐ OrderedSet, but they are easily formed by coercion from a set or an array using an initializer. Coming back the other way, Swift receives an NSSet as a Set; you can cast an NSSet down to a specific type of Swift Set, and thus you can cast an NSMutableSet or NSCountedSet up to NSSet and down to a Swift Set (similar to an NSMutableArray). NSOrderedSet comes with “façade” properties that present it as an array or a set. Because of their special behaviors, however, you are much more likely to leave an NSCountedSet or an NSOrderedSet in its Objective-C form for as long you’re working with it. NSNull The NSNull class does nothing but supply a pointer to a singleton object, NSNull(). This singleton object is used to stand for nil in situations where an actual Objective-C 442 | Chapter 10: Cocoa Classes 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), and Objective- C knows nothing about Swift Optionals, so you’d use NSNull() instead. You can test an object for equality against NSNull() using the ordinary equality operator (==), because it falls back on NSObject’s isEqual:, which is identity comparison. This is a singleton instance, and therefore identity comparison works. Immutable and Mutable Beginners sometimes have difficulty with the Cocoa Foundation notion of class pairs where the superclass is immutable and the subclass is mutable. This notion is itself reminiscent of the Swift distinction between a constant (let) and a true variable (var), and has similar consequences. For example, the fact that NSArray is “immutable” means much the same thing as the fact that a Swift Array is referred to with let: you can’t append