ios-11-programming-fundamentals-swift


Чтобы посмотреть этот PDF файл с форматированием и разметкой, скачайте его и откройте на своем компьютере.
Matt Neuburg
Fundamentals with Swift
Xcode, and Cocoa Basics
Boston
[LSI]
by Matt Neuburg
Copyright € 2018 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://oreilly.com/safari
). For more information, contact our corporate/insti‚
tutional sales department: 800-998-9938 or corporate@oreilly.com.
Rachel Roumeliotis
OReilly Production Services
Matt Neuburg
Karen Montgomery
David Futato
Matt Neuburg
April 2015:
Fourth Edition
2017-09-26: First release
http://oreilly.com/catalog/errata.csp?isbn=0636920107415
, 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
instructions 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 intellectual property rights of others, it is your responsibility to ensure that your use
thereof complies with such licenses and/or rights.
Preface. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii
Part I. Language
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
Functions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Variables and Simple Types. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Object Types. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
Object Type Declarations and Features 119
Initializers 121
Properties 127
iv | Table of Contents
Table of Contents | v
Extensions 211
Extending Object Types 211
Extending Protocols 213
Extending Generics 215
Umbrella Types 217
Any 217
AnyObject 219
AnyClass 221
Collection Types 222
Array 222
Dictionary 238
Flow Control and More. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
Flow Control 251
Branching 252
Loops 264
Jumping 268
Key Paths 284
Operators 286
Privacy 290
Private and Fileprivate 291
Public and Open 292
Privacy Rules 293
Introspection 293
Memory Management 294
Memory Management of Reference Types 295
Exclusive Access to Value Types 302
Part II. IDE
Anatomy of an Xcode Project. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
New Project 307
The Project Window 309
The Navigator Pane 311
The Utilities Pane 316
The Editor 318
The Project File and Its Dependents 320
vi | Table of Contents
Configurations 326
Schemes and Destinations 327
From Project to Running App 330
Nib Management. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347
The Nib Editor Interface 348
Document Outline 350
Canvas 352
Inspectors and Libraries 355
Nib Loading 356
When Nibs Are Loaded 356
Manual Nib Loading 358
Connections 360
Documentation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381
The Documentation Window 381
Class Documentation Pages 383
Quick Help 386
Symbol Declarations 388
Table of Contents | vii
Header Files 389
Sample Code 390
Life Cycle of a Project. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393
Runtime Environment 393
Backward Compatibility 394
Device Type 396
Version Control 397
Editing and Navigating Your Code 400
Signing an App 427
Automatic Signing 428
Obtaining a Development Certificate Manually 430
Obtaining a Development Provisioning Profile Manually 431
Running the App 434
Managing Development Certificates and Devices 434
Profiling 435
Gauges 435
Memory Debugging 436
Instruments 437
Localization 440
Distribution 445
Making an Archive 445
Obtaining a Distribution Certificate 446
Obtaining a Distribution Profile 447
Ad Hoc Distribution 448
Final App Preparations 450
viii | Table of Contents
Screenshots and video previews 453
Cocoa Classes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461
Subclassing 461
Categories and Extensions 464
How Swift Uses Extensions 464
How You Use Extensions 465
How Cocoa Uses Categories 466
Protocols 467
Informal Protocols 469
Table of Contents | ix
Cocoa Events. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 507
Reasons for Events 508
Subclassing 508
Notifications 510
Receiving a Notification 511
Unregistering 513
Posting a Notification 514
Timer 515
Delegation 517
Cocoa Delegation 517
Implementing Delegation 519
Data Sources 521
Actions 522
The Responder Chain 525
Deferring Responsibility 526
Memory Management. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 537
Principles of Cocoa Memory Management 537
Rules of Cocoa Memory Management 538
What ARC Is and What It Does 539
How Cocoa Objects Manage Memory 540
Autorelease Pool 541
Memory Management of Instance Properties 543
x | Table of Contents
Notifications and Key„Value Observing 563
Model„View„Controller 563
A.C, Objective-C, and Swift. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 567
Index. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 601
Table of Contents | xi
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
doubted 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 consider
this new language ƒ Swift
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
and no more. The rest must be provided by your code, or by libraries of code that
Memory management
Swift manages memory automatically. You will rarely have to concern yourself
with memory management.
Cocoa compatibility
The Cocoa APIs are written primarily 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, however, lacks the very advantages that Swift
offers. Objective-C agglomerates 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
xiv | Preface
Therefore, although I do not attempt to teach Objective-C in this book, I do describe
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 differ‚
ent from other treatments, such as Apples; it is systematic and Euclidean, with
pedagogical 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 advanced Swift world outside the scope of this discussion. To
give an obvious example, readers may be surprised to find that I never mention
Preface | xv
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
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 documenta‚
tion 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
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,
xvi | Preface
earlier books. The book does contain, nevertheless, a few words of advice about back‚
ward compatibility (especially in
Chapter 9
http://git-scm.com
TextMate (
http://macromates.com
http://www.methods.co.nz/asciidoc
http://asciidoctor.org
http://barebones.com/products/bbedit/
http://www.devontechnologies.com/products/freeware.html
Preface | xvii
Snapz Pro X (
http://www.ambrosiasw.com
GraphicConverter (
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
A programming framework has a kind of personality, an overall flavor that provides
xviii | Preface
and elements on which sound iOS programming rests. My hope, as with my previous
Preface | xix
This element signifies a tip or suggestion.
This element signifies a general note.
This element indicates a warning or caution.
by Matt Neuburg (OReilly). Copyright 2018 Matt Neuburg,
978-1-491-99931-8.†
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
is an on-demand digital library that
content
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,
problem solving, learning, and certification training.
xx | Preface
Safari Books Online offers a range of
enterprise
government
education
Members have access to thousands of books, training videos, and prepublication
manuscripts 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 Kauf‚
mann, IBM Redbooks, Packt, Adobe Press, FT Press, Apress, Manning, New Riders,
Preface | xxi
This part of the book teaches the Swift language, from the ground up. The descrip‚
tion 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
Chapter 1
surveys the structure of a Swift program, both physically and concep‚
tually. 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:
Chapter 2
explores Swift functions. We start with the basics of how functions are
Chapter 3
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
extensions. The chapter concludes with a discussion of Swifts umbrella types,
Chapter 5
is a miscellany. We start with Swifts flow control structures for branch‚
ing, looping, and jumping, including error handling. Then I discuss a new Swift 4
feature, key paths, and explain to create your own Swift operators. The chapter
concludes by describing Swift access control (privacy), introspection (reflection),
and memory management.
The Architecture of Swift
Comments are everything after two slashes in a line (so-called C++-style comments):
You can also enclose comments in
, as in C. Unlike C, C-style comments can
Many constructs in Swift use curly braces as delimiters:
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
something
is wrong
with a line of code, but the Swift compiler will not be telling you clearly exactly
what
where
in the line to focus your attention. 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. Remember, it knows
4 | Chapter 1: The Architecture of Swift
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.†
Everything Is an Object? | 5
it is a …primitive† or
scalar
built-in data type. So the distinction being drawn here is
emerge in due course. But they are all very definitely object types, and their similari‚
ties 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
6 | Chapter 1: The Architecture of Swift
Once the name exists, you are free to use it. For example, we can change the value of
Variables | 7
By convention, type names such as String or Int (or Dog or Cat) start with a capi‚
8 | Chapter 1: The Architecture of Swift
runtime at key moments ƒ such as when the app launches, or when the user taps a
button in your apps interface.
Swift also has a special rule that a file called
, 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
file, but in general you wont need to.
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
go at the top level of a Swift file ƒ chiefly the following:
Module
statements
A module is an even higher-level unit than a file. A module can consist of multi‚
ple files, and these can all see each other automatically; but a module cant see
statement. For example, that is how you are
able to talk to Cocoa in an iOS program: the first line of your file says
Variable declarations
A variable declared at the top level of a file is a
global
able to see and access it, without explicitly sending a message to any object, and it
Function declarations
A function declared at the top level of a file is a
global
able to see and call it, without explicitly 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
statement, a variable declaration, a function declaration, a class dec‚
laration, a struct declaration, and an enum declaration:
The Structure of a Swift File | 9
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 vari‚
able declarations, function declarations, and object type declarations within them!
any
structural curly braces can contain such declarations.
Youll notice that I did
not
say that executable code can go at the top level of a file.
Thats because it cant!
Only a function body can contain executable code.
A statement
is executable code, and cant go at the top level of a
file. But in our previous example,
is a function declaration, so exe‚
can
go inside its curly braces, because they constitute a function body:
var one = 1
func changeOne() {
10 | Chapter 1: The Architecture of Swift
struct Struct {}
enum Enum {}
one = two
}
class Manny {
12 | Chapter 1: The Architecture of Swift
Inside the three object types (class, struct, and enum), things declared at the top level
is a variable declared at the top level of an object declaration, so it is called a
property
of that object.
is a function declared at the top level of an object declaration, so it is
method
of that object.
Object Members | 13
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 differenti‚
ate them, if necessary, as
It will not have escaped your attention that the syntax for diving explicitly into a
namespace is the message-sending dot-notation syntax. They are, in fact, the same
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
. It can do
that
because it
can
see Manny (because Manny is declared at a level that code inside Moe
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
example, if my app is called
, then if I declare a class Manny at the top level of a
file, that classs
real
. 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
directly.
import a module, all the top-level declarations of that module become visible to your
code, without your having to use the modules namespace explicitly to refer to them.
For example, Cocoas Foundation framework, where NSString lives, is a module.
When you program iOS, you will say
(or, more likely, youll say
, which itself imports Foundation), thus allowing you to speak of
NSString without saying
could
say
, and if you were so silly as to declare a different NSString in
have
to say
tiate them. You can also create your own frameworks, and these, too, will be modules.
Swift itself is defined in a module ƒ the Swift module. Your code
always implicitly
imports the
module
. You could make this explicit by starting a file with the line
; 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
come from, and why is it possible to use them outside of any message to any object?
is in fact a function declared at the top level of the Swift module, and your code
can see the Swift modules top-level declarations because it imports Swift. The
function thus becomes, as far as your code is concerned, an ordinary top-level func‚
14 | Chapter 1: The Architecture of Swift
tion like any other; it is global to your code, and your code can speak of it without
specifying its namespace. You
can
specify its namespace ƒ it is perfectly legal to say
ƒ but you probably never will, because theres no
You can actually
see
the Swift top-level declarations and read and study them,
and this can be a useful thing to do. For example, to see the declaration of
Command-Control-click the term
in your code. Alternatively, explicitly
and Command-Control-click the term
. Behold, there are
the Swift top-level declarations! You wont see any executable Swift
code
here, but
you will see the declarations for all the available Swift terms, including top-level
, operators like
, and built-in types such as Int and String
Object types ƒ class, struct, and enum ƒ have an important feature in common: they
instantiated
type
. To instantiate a type is to make a thing ƒ an
instance
ƒ of that type.
Instances | 15
Figure 1-1. Making an instance and calling an instance method
as a Dog instance would have meant
instance after that.)
Now that I have a Dog instance, I can send
instance messages
to it. And what do you
16 | Chapter 1: The Architecture of Swift
var name = ""
}
Why Instances? | 17
Figure 1-2. Two dogs with
property values
The important thing is that we can make more than one Dog instance, and that two
different Dog instances can have two different
18 | Chapter 1: The Architecture of Swift
what it is to be a Dog
. Our declaration of Dog says that a Dog
any
every
ent
instances and maintain their own internal
state
. So multiple instances of the same
behave
are sent the
message ƒ but they are different instances and can have different
property values: Fidos
while Rovers
The Keyword self | 19
20 | Chapter 1: The Architecture of Swift
privacy
ƒ a way of making it harder for other objects to see those
Consider, for example:
Here, other objects can come along and change my property
that property is used by both
and
, we could easily end up with a Dog that,
, says
Privacy | 21
and
and
and
ƒ as the name of a class, a function, or a variable, for example. If you try to
Now
is a public property, but
is a private property: it cant be seen
, but a Cat
cannot say
The important lesson here is that object members are public by default, and if you
want privacy, you have to ask for it.
To sum up: A 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 name‚
can
still refer to whats inside the namespace; the namespace
does not, in and of itself, close any doors of visibility. The
22 | Chapter 1: The Architecture of Swift
In real life, when youre programming iOS, many 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
huge
number of object
types, all of which spring to life in your program. You didnt create any of those object
types, so their design is not your problem; instead, you must learn to use them.
Apples object types are aimed at enabling the
general
functionality that any app might
need. At the same time, your app will probably have
functionality, unique to
its purpose, and you will have to design object types to serve that purpose.
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
Guide
Encapsulation of functionality
Each object does its own job, and presents to the rest of the world ƒ to other
Design | 23
Figure 1-3. A stack
24 | Chapter 1: The Architecture of Swift
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.
The sum total of messages that each object type is eligible to be sent by other objects
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
instantiating 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,
Design | 25
26 | Chapter 1: The Architecture of Swift
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
The declaration starts with the keyword
name
tion; here, its
. 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.
parameter list
It consists, minimally,
This particular function declaration also has an underscore (
Then we have curly braces enclosing the
body
Within the curly braces, in the function body, the variables defined as the param‚
28 | Chapter 2: Functions
Observe that these names,
and
, are arbitrary and purely local (
internal
function. They are different from any other
that may be used in other
functions or at a higher level of scope. These names are defined purely so that the
30 | Chapter 2: Functions
It clarifies the purpose of each argument; each argument label can give a clue as
to how that argument contributes to the behavior of the function.
It distinguishes one function from another; two functions with the same name
(before the parentheses) and the same signature but different externalized
32 | Chapter 2: Functions
Change the name of an external parameter
The existence of external names doesnt mean that the call can use a different
34 | Chapter 2: Functions
36 | Chapter 2: Functions
Whats the purpose of this feature? It isnt to satisfy the compiler, because the compiler
If we want our function to alter the
original
value of an argument passed to it, we
must do the following:
When we call the function, the variable holding the value we intend to tell it to
modify must be declared with
Instead of passing the variable as an argument, we must pass its
address
done by preceding its name with an ampersand (
38 | Chapter 2: Functions
var name = ""
}
Dog
instance
40 | Chapter 2: Functions
What Im doing in the first for loop (
) and what Im doing in the second for
Again, the structure is clear (even though the code uses some Swift features I havent
Function In Function | 41
Ive expressed the Pythagorean theorem as a local function,
Inside the for loop I call that function.
There is no savings whatever in the number of lines of code; in fact, declaring
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
42 | Chapter 2: Functions
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
}
doThis(whatToDo)
of the proper type
ƒ a function that takes
, passing as argument a
function reference
bare name of the function. Notice that we are not
calling
passing
as argument to
Function As Value | 43
syntax and structure. But in real life, this is a very valuable thing to do. Encapsulating
Open an image context.
Draw into the context.
Close the image context.
Thats terribly ugly. The sole purpose of all that code is to obtain
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
44 | Chapter 2: Functions
Anonymous Functions | 45
To make function type specifiers clearer, we can take advantage of Swifts
feature to give a function type a name. The name can be descriptive, and the possibly
confusing arrow operator notation is avoided. For example, if we say
, we can then say
specify a function type with that signature.
Thus, earlier we declared a function like this:
We could have declared it like this:
}
UIView.animate(withDuration:0.4,
Create the function body itself, including the surrounding curly braces, but with
no function declaration.
46 | Chapter 2: Functions
Heres an anonymous function that does the same thing. Notice how Ive moved the
Anonymous Functions | 47
48 | Chapter 2: Functions
Omission of the parentheses
Anonymous Functions | 49
right parenthesis
before
this last argument, and then put just the anonymous
without a label
trailing function
Omission of the calling function parentheses
If you use the trailing function syntax, and if the function you are calling takes no
50 | Chapter 2: Functions
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
A pattern thats surprisingly common in Swift is to define an anonymous function
Notice the parentheses after the curly braces! The curly braces
an anonymous
function body; the parentheses
call
that anonymous function.
| 51
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?
For one thing, 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 as an argument
52 | Chapter 2: Functions
In that code, the body of the function
That variable is
external
to the body of the function, because it is declared outside the
body of the function. It is
in scope
for the body of the function, because the code
refers
to it ƒ it says, explicitly,
So far, so good; but we now know that the function
effect, it can travel from one environment to another! When it does, what happens to
that reference to
into our variable
Closures | 53
into
proves that
is maintaining its reference to this actual Dog, the one that
function, as it is passed around, is carrying its environment with it
54 | Chapter 2: Functions
now
. Everything inside the curly braces is just a function body. It wont be
exe
cuted
until
calls it. Nevertheless, the value of
persists. The anony‚
mous function is a function. Therefore it is a closure. Therefore the anonymous
function captures the reference to
, and carries it on into the call to
that image, all in one move, like this (
is a UIImageView in the interface):
size
. If youve never seen a
Closures | 55
p.stroke()
}
The declaration is the hardest part. What on earth is the type (signature) of this
? It is
. That
two
arrow operators. To understand it, keep in mind that every‚
Now here we are in the body of the function
Finally, we
return
). We have thus fulfilled our con‚
56 | Chapter 2: Functions
makeRoundedRectangleMaker
Closures | 57
}
58 | Chapter 2: Functions
print(x)
Closures | 59
Clearly,
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
. But it isnt declared inside the anonymous function that
60 | Chapter 2: Functions
Curried Functions | 61
image:
self.iv.image = makeRoundedRectangleMaker(CGSize(width:45, height:20))(8)
62 | Chapter 2: Functions
func bark() {
print("woof")
}
func bark(_ loudly:Bool) {
if loudly {
print("WOOF")
} else {
self.bark()
}
}
func test() {
Function References and Selectors | 63
doesn†t
solve the problem if the function to which we want a
reference is the one that takes
no
64 | Chapter 2: Functions
the compiler would force you to use
to call a function; in those situations, you
will have to use
Function References and Selectors | 65
66 | Chapter 2: Functions
When you use that notation, two wonderful things happen:
compiler validates the function reference
If your function reference isnt valid, your code wont even compile. The compiler
also checks that this function is exposed to Objective-C; theres no point forming
compiler forms the Objective-C selector for you
Function References and Selectors | 67
A variable is a named …shoebox† whose contained value must be of a single well-
defined type. Every variable must be explicitly and formally declared. To put a value
into the shoebox, thus causing the variable name to
refer
to that value, you
assign
reference
to that value.
70 | Chapter 3: Variables and Simple Types
class Dog {
With
With
quent assignment.
Variable Declaration | 71
A variable declaration is usually accompanied by
initialization
sign to assign the variable a value, as part of the declaration. That, however, is not a
requirement; it is legal to declare a variable without immediately initializing it.
What is
not
must
have
inference would be wrong
A very common case in my own code is when I want to provide the initial value
can†t infer the type
72 | Chapter 3: Variables and Simple Types
The problem is that the name
), but Swift doesnt know that
unless we tell it. Explicitly typing the variable is an elegant way of doing that:
programmer can†t infer the type
I frequently include a superfluous explicit type declaration as a kind of note to
myself. Heres an example from my own code:
Variable Declaration | 73
When a variables
address
is to be passed as argument to a function, the variable must
and initialized
example from
Chapter 2
complaint:
placeholder:
(Alternatively, declaring
as an Optional, discussed later in this chapter, might be
considered a slightly cleaner approach.)
74 | Chapter 3: Variables and Simple Types
Computed Initializer | 75
}
The variable must be declared with
now

76 | Chapter 3: Variables and Simple Types
makes for simpler syntax to express it as a read-only computed variable, which
effectively acts a shorthand for a longer expression. Heres an example from my
Computed Variables | 77
78 | Chapter 3: Variables and Simple Types
As the preceding examples have demonstrated, a computed instance property func‚
tion can refer to other instance members. This is important, because in general the
for a computed property is that its functions wont be called until the instance actually
The variable must be declared with
By default, the
By default, the
value
80 | Chapter 3: Variables and Simple Types
Static properties
Static properties are
automatically lazy
. They behave exactly like global variables,
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
. This property must be declared with
Lazy Initialization | 81
A very common idiom is to initialize a lazy instance property with a define-and-call
anonymous function:
82 | Chapter 3: Variables and Simple Types
Built-In Simple Types | 83
Not. The
unary operator reverses the truth value of the Bool to which it is
applied as a prefix. If
vice versa
84 | Chapter 3: Variables and Simple Types
The easiest way to represent a Double value is as a numeric literal. Any numeric lit‚
eral containing a decimal point is taken as a Double by default. Internal underscores
A Double literal may
not
begin with a decimal point (unlike C and Objective-C). If
Built-In Simple Types | 85
86 | Chapter 3: Variables and Simple Types
Figure 3-1. Quick Help displays a variable†s type
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. A slider, in the interface, is a UISlider,
and
are Floats. In this code,
is a UISlider,
is a
UIGestureRecognizer, and were trying to use the gesture recognizer to move the slid‚
ers …thumb† to wherever the user tapped within the slider:
That wont compile. Heres why:
is a CGPoint, and therefore
is a CGFloat.
Luckily,
is also a CGFloat, so the second line compiles;
is now inferred to be a CGFloat.
We now try to combine
ƒ and they are Floats, not CGFloats. Thats a compile error.
This sort of thing is not an issue in C or Objective-C, where there is implicit coercion;
but in Swift, a CGFloat cant be combined with Floats. We must coerce explicitly:
Built-In Simple Types | 87
88 | Chapter 3: Variables and Simple Types
Built-In Simple Types | 89
Now
(because the value has wrapped around from
is an enum reporting that overflow occurred.
(x+y)*z
performs the addition first.
Global functions include
abs
(absolute value),
max
, and
min
:
90 | Chapter 3: Variables and Simple Types
bers, …equal† means numerically equal. So
are …the same
number,† in exactly the sense you would expect.
The comparison operators are:
Built-In Simple Types | 91
The backslash in that string representation is the
escape
character; it means, …Im not
The multiline string literal must be delimited by a triple of double quotes (
) at
No material may follow the opening delimiter on the same line.
No material other than whitespace may appear on the same line as the closing
delimiter.
The last implicit newline character before the closing delimiter is ignored.
The indentation of the closing delimiter dictates the indentation of the lines of
text, which must be indented at least as far as the closing delimiter (except for
92 | Chapter 3: Variables and Simple Types
In a multiline string literal, quotation marks do
not
have to be escaped. A line ending
consists of
Built-In Simple Types | 93
94 | Chapter 3: Variables and Simple Types
Coercion to String is in fact the basis of string interpolation, and of representa‚
. You can make
any
making it conform to any of three protocols: TextOutputStreamable, Custom‚
StringConvertible, and CustomDebugStringConvertible. Ill give an example
when I explain what a protocol is, in
Chapter 4
property:
Built-In Simple Types | 95
96 | Chapter 3: Variables and Simple Types
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 code‚
points. Each approach has its advantages. The NSString way makes for great speed
and efficiency in comparison to Swift, which must walk the string to investigate how
the characters 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
property; its analog to an NSStrings
Fortunately, the element mismatch doesnt arise very often in practice; but it can arise.
Heres a good test case:
Similarly, you can pass a one-character String literal where a Character is expected,
and many examples in this section will do so.
By the same token, you can initialize a String from a Character:
Built-In Simple Types | 97
qua
character sequence, without having to take the strings
erty, as was necessary in Swift 3 and before:
98 | Chapter 3: Variables and Simple Types
qua
Built-In Simple Types | 99
breaks a string up into an array, according to a function that takes a Char‚
…word† is simplemindedly defined as a run of Characters other than a space:
Unfortunately, this isnt as easy as it might be. For example, whats the second charac‚
? This doesnt compile:
value with the
index(after:)
and
index(before:)
100 | Chapter 3: Variables and Simple Types
String. For example, the
Built-In Simple Types | 101
If the end value is a negative literal, it has to be enclosed in parentheses or preceded
102 | Chapter 3: Variables and Simple Types
Built-In Simple Types | 103
Tuples are a pure Swift language feature; they are not compatible with Cocoa and
Objective-C, so youll use them only for values that Cocoa never sees. Within Swift,
however, they have many uses. For example, a tuple is an obvious solution to the
104 | Chapter 3: Variables and Simple Types
The second way to access tuple elements is to give them labels. The notation is like
Built-In Simple Types | 105
106 | Chapter 3: Variables and Simple Types
stringMaybe = "farewell" // now stringMaybe is Optional("farewell")
Built-In Simple Types | 107
must reach inside it and
retrieve
the actual thing that it wraps. Now Im going to talk
about how to do that.
We have seen more than one way to wrap an object in an Optional. But what about
108 | Chapter 3: Variables and Simple Types
Built-In Simple Types | 109
have to be unwrapped explicitly before you could send it the
Alternatively, you could unwrap the implicitly unwrapped Optional explicitly at the
110 | Chapter 3: Variables and Simple Types
Because a variable typed as an Optional can be
is
, automatically. This is legal:
That code is interesting because it looks as if it should be illegal. We declared a vari‚
, 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
implicitly initialized
only
Built-In Simple Types | 111
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 ear‚
lier:
112 | Chapter 3: Variables and Simple Types
To handle this situation, Swift has a special rule. If an Optional chain contains an
optionally unwrapped Optional, and if this Optional chain produces a value, that
wrapped in an Optional
. Thus,
is typed as an Optional wrapping a
Built-In Simple Types | 113
sible, for other reasons, to end up with an Optional wrapped in an Optional. Ill give
an example in
Chapter 4
114 | Chapter 3: Variables and Simple Types
Built-In Simple Types | 115
a UIColor,
and you must be conscious of this fact
, for all the reasons Ive already dis‚
cussed: if youre not, surprising things can happen:
116 | Chapter 3: Variables and Simple Types
assigned a UIButton value, we can treat it as a reference to an actual UIButton, pass‚
ing through the Optional without noticing that it
is
an Optional. Moreover, none of
this view controllers code will run before the view is loaded and the actual button is
, so the implicitly unwrapped Optional is generally safe.
A closely related situation is when a variable, again typically an instance property,
represents 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
instantiate the root view controller
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;
until the data are gathered, at which time they are assigned their …real†
// ...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,
Built-In Simple Types | 117
Object Types
Object types declared at the
top level of a
will, by default, be visible to all files
in the same module. This is the usual place for object type declarations.
within the body of a function
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
Initializers
type
type will usually (though not always) be so that you can make an actual object ƒ
instance
ƒ that
has
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
default, it is an
instance property
ent for every instance of this type.
Alternatively, a property can be a
static/class property
. For an enum or struct, it is
; for a class, it may instead be declared with the
through 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
default, it is an
instance method
120 | Chapter 4: Object Types
initializer
is a function called in order to bring an instance of an object type into
Object Type Declarations and Features | 121
name, by supplying a license number, or by supplying both. In each initializer, the
122 | Chapter 4: Object Types
Now, the truth is that we dont need those four initializers, because an initializer is a
Object Type Declarations and Features | 123
var name : String
var license : Int
init(name:String = "") {
self.name = name // compile error
}
}
this instance has come into existence.
This situation conflicts with the requirement that all instance properties be initialized
either in their declaration or through an initializer. You could, of course, just circum‚
124 | Chapter 4: Object Types
vent the problem by assigning a default initial value anyway; but this fails to commu‚
nicate to your own code the fact that this isnt a …real† value.
Chapter 3
having an Optional type. An Optional has a value, namely
, signifying that no …real† value has been supplied; and an Optional
automatically. Thus, your code can test this instance property against
, 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 can 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:
have been initialized.
Object Type Declarations and Features | 125
Initializers within an object type can call one another by using the syntax
. An initializer that calls another initializer is called a
delegating ini
tializer
. When an initializer delegates, the other initializer ƒ the one that it delegates
126 | Chapter 4: Object Types
Object Type Declarations and Features | 127
If a property is an instance property (the default), it can be accessed only through an
128 | Chapter 4: Object Types
some of Swifts most perplexing compile error messages. For example, this is illegal
doesnt make it legal):
Object Type Declarations and Features | 129
130 | Chapter 4: Object Types
by way of
by way of
. This is because instance code can use
if the reference is unambiguous; thus, for example, I could have writ‚
never
write code like that (except by accident). Omitting
, in my view,
makes the code harder to read and maintain; the loose terms
Object Type Declarations and Features | 131
And heres how to call the static
132 | Chapter 4: Object Types
Object Type Declarations and Features | 133
subscript
Then, after the arrow operator, we have the type of value that is passed out (when
Finally, we have curly braces
whose contents are exactly like those of a computed
property. You can have
134 | Chapter 4: Object Types
Object Type Declarations and Features | 135

instance of the ViewController class, and your messages to that
the particular already existing instance
that you
wanted to talk to.
136 | Chapter 4: Object Types
alternative
values
. Think of it as a list of known possibilities. An enum is the Swift way to express
Enums | 137
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:
138 | Chapter 4: Object Types
Just as you can use the bare name of an enum case, preceded by a dot, where an
instance of that enum is expected, you can do the same thing when referring to a
types static/class member whose value is an instance of that type. For example,
UIColor has many class properties that produce a UIColor instance, so you can omit
Similarly, suppose we have a struct Thing with static constants whose values are
Thing instances (Ill explain later what RawRepresentable means):
In that code,
If the type is String, the implicitly assigned values are the string equivalents of the
case names. For example:
In that code,
Regardless of the type, you can assign values explicitly as part of the case declarations,
Enums | 139
raw values
. An instance of an enum
140 | Chapter 4: Object Types
Enums | 141
Ill explain in
Chapter 5
check the case
of an instance of an enum that has an
associated value case, as well as how to
extract
the associated value from such an
is
an associated value case.
142 | Chapter 4: Object Types
Enums | 143
144 | Chapter 4: Object Types
In this example, I add an
Enums | 145
And its easy to examine the game type by case name:
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
146 | Chapter 4: Object Types
Now you can say
, but you cant say
any longer. Of course,
you can add an explicit initializer that does the same thing:
Now you can say
A struct that has stored properties and that doesnt have an explicit initializer auto‚
Structs | 147
A struct can have instance properties and static properties, and they can be stored or
148 | Chapter 4: Object Types
Mutability
A class instance is mutable in place. Even if your reference to an instance of a
class is a constant (
instance. To see that this is true, add a
Classes | 149
150 | Chapter 4: Object Types
var name : String = "Fido"
}
When an enum instance or a struct instance is assigned or passed, what is
assigned or passed is essentially a
new copy
of that instance. (I say …essentially†
Classes | 151
because, behind the scenes, there can be some efficiency, preventing a new copy
When a class instance is assigned or passed, what is assigned or passed is a refer‚
same
To prove it, Ill assign one reference to another, and then mutate the second reference
152 | Chapter 4: Object Types
objects, and if they both have a Dog property (where Dog is a class), and if they have
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. If that happens unexpectedly, it can put your program into an
invalid state.
Class instances are also more complicated behind the scenes. Swift has to manage
Classes | 153
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. The moral is clear: if you need a property of a
An enum cases associated value
can
be an instance of that enum, provided the
case (or the entire enum) is marked
154 | Chapter 4: Object Types
}
}
}
Classes | 155
Figure 4-1. Part of the Cocoa class hierarchy as shown in Xcode
We can imagine diagramming this tree as an outline. And in fact Xcode will
show
you
): 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). Now locate NSObject in the list; the Cocoa classes are the
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
156 | Chapter 4: Object Types
func walk () {
print("walk walk walk")
}
}
class Dog : Quadruped {}
class Cat : Quadruped {}
Classes | 157
158 | Chapter 4: Object Types
print("woof woof woof")
}
}
Classes | 159
A class declaration can
prevent
class by preceding the members declaration with the
160 | Chapter 4: Object Types
its own. Thus we must somehow ensure that when a subclass is initialized, its super‚
classs properties 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
Swift solves this problem coherently and reliably ƒ and ingeniously ƒ by enforcing
some clear and well-defined rules about what a class initializer must do.
Classes | 161
var name = "Fido"
}
162 | Chapter 4: Object Types
self.init(name:"Fido", license:license)
}
convenience init() {
self.init(license:1)
}
}
A designated initializer cannot, except in order to initialize a property (or to
A convenience initializer is a delegating initializer, so it cannot say
any
purpose until after it has called, directly or indirectly, a designated initializer (and
Classes | 163
Moreover, the rules about saying
continue to apply. Thus, a subclass desig‚
nated initializer must do things in this order:
It must ensure that all properties of
this
It must call
, and the initializer that it calls must be a desig‚
nated initializer.
Only then may this initializer say
164 | Chapter 4: Object Types
vice versa
can call
init
.
by saying
and unwrapping the result with an excla‚
mation mark (and if the
fails, youll crash).
Classes | 165
Observe how NoisyDogs convenience initializer fulfills its contract by calling
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:
inheritance
only
way to make a NoisyDog is like this:
166 | Chapter 4: Object Types
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:
Classes | 167
Observe that our overridden required initializer is not marked with
is
, thus guaranteeing that the requirement continues drilling
down to any further subclasses.
I have explained what declaring an initializer as
does, but I have not
why
youd need to do it. Ill give examples later in this chapter.
A class, and only a class (not the other flavors of object type), can have a deinitializer.
taining the function body. You never call this function yourself; it is called by the run‚
the subclasss deinitializer (if any) is called before the 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
Chapter 5
168 | Chapter 4: Object Types
If the superclass property is writable (a stored property or a computed property
Alternatively, the subclasss override may be a computed property. In that case:
If the superclass property is stored, the subclasss computed property override
If the superclass property is computed, the subclasss computed property over‚
ride must reimplement all the accessors that the superclass implements. If the
Classes | 169
can
170 | Chapter 4: Object Types
object
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 polymor‚
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:
Polymorphism | 171
That code is legal, because, by the substitution principle, we can pass
NoisyDog, where a Dog is expected. Now, inside the
as a Dog. How will it react to being told to
typed
Dog, and a Dog barks by saying
is called, what is
really
passed is a NoisyDog instance, and a NoisyDog
barks by saying
172 | Chapter 4: Object Types
is encountered within the Dog classs implementation of
what matters is not
where
appears
but what it
means
. It means
this
instance
. And the internal identity principle tells us that this instance is a NoisyDog!
Thus, it is NoisyDogs override of
that is called when Dogs
says
Polymorphism applies to Optional types in the same way that it applies to the type of
thing wrapped by the Optional. Suppose we have a reference typed as an Optional
wrapping a Dog. You already know that you can assign a Dog to it. Well, you can also
assign a NoisyDog, or an Optional wrapping a NoisyDog, and the underlying wrap‚
ped object will maintain its integrity:
(The applicability of polymorphism to Optionals derives from a special dispensation
covariant
. Ill talk more about that later in this
chapter.)
Thanks to polymorphism, you can take advantage of subclasses to add power and
customization to existing classes. This is important particularly in the world of iOS
programming, 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
Polymorphism | 173
The Swift compiler, with its strict typing, imposes severe restrictions on what mes‚
sages can be sent to an object reference. The messages that the compiler will permit to
be sent to an object reference depend upon the references
declared
internal identity principle of polymorphism says that, under the hood, an object may
have a
real
type that is different from its references declared type. Such an object may
thus be capable of receiving messages that the compiler wont permit us to send.
174 | Chapter 4: Object Types
Casting | 175
To prevent yourself from lying accidentally, you can
test
the type of an instance at
runtime. One way to do this is with the keyword
. You can use
then
cast, in the knowledge that your cast is safe:
Then we optionally unwrap that Optional and send a message to it. If
isnt a Noisy‚
and the message wont be sent. If
is
a NoisyDog, the
Optional will be unwrapped and the message will be sent. Thus, that code is safe.
Chapter 3
that comparison operators applied to an Optional are automat‚
ically applied to the object wrapped by the Optional. The
operators
work the same way.
176 | Chapter 4: Object Types
is

Casting | 177
That sort of code, however, is rather artificial. In real life, you wont be casting all that
often, because the Cocoa API will present itself to you in terms of Swift types. For
example, this is legal with no cast:
178 | Chapter 4: Object Types
seems clumsy and inflexible. Why should we have
to hard-code into Dog a knowledge of what class it is? It
has
know
what it is.
In Swift, you can access the type of an object references underlying object through
function. Thus, if you dont like the notion of a Dog instance calling a
Type Reference | 179
In some situations, you may want to treat an object type
as a value.
That is legal; an
object type is itself an object. Heres what you need to know:
To
declare
that an object type is acceptable ƒ for example, as the type of a vari‚
To
use
an object type as a value ƒ for example, to assign a type to a variable or
pass it to a function ƒ use the types name followed by the keyword
dot-notation, or hand an object to
For example, heres a function
that accepts a Dog type as its
180 | Chapter 4: Object Types
I promised earlier that Id tell you why you might need to declare an initializer as
; now Im fulfilling that promise! The
designation reassures the
compiler; every subclass of Dog must inherit or reimplement
, so its
message to a type reference that might refer to Dog or
some subclass of Dog. Now our code compiles, and we can call our function:
Type Reference | 181
It works as expected:
182 | Chapter 4: Object Types
Protocols | 183
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
184 | Chapter 4: Object Types
fly

ciple, a Flier here could be an instance of any object type ƒ an enum, a struct, or a
class. It doesnt matter
what
as long as it adopts the Flier protocol.
If it
adopts the Flier protocol, it can be passed where a Flier is expected. Moreover, if it
adopts the Flier protocol, then it must have a
Protocols | 185
func fly() {
}
}
186 | Chapter 4: Object Types
We have now made Filter formally adopt the CustomStringConvertible protocol. The
CustomStringConvertible protocol requires that we implement a
property; we
do
implement a
String property, so our code compiles.
Now we can interpolate a Filter into a string, or hand it over to
will be used automatically:
Protocols | 187
qua
Flier, but it can
188 | Chapter 4: Object Types
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 pro‚
Protocols | 189
Swift, youd have to type
as a MyViewProtocol and then cast to UIView in order to
send it UIView messages, even if you knew that
would in fact always be a UIView.
In Objective-C, a protocol member can be declared optional, meaning that this mem‚
ber doesnt have to be implemented by the adopter, but it may be. For compatibility
explicitly bridged to Objective-C by preceding its declaration with the
attribute. In such a protocol, an optional member is declared by preceding its decla‚
ration with the keywords
190 | Chapter 4: Object Types
Protocols | 191
class
protocol
, meaning that it can be adopted only by class object types:
(There is no need to say
attribute implies that this is also a class protocol, because classes are the only
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‚
192 | Chapter 4: Object Types
Consider this simple example, which wont compile:
That code generates an elaborate but perfectly informative compile error message:
…Initializer requirement
can only be satisfied by a
final class Bird.† To compile our code, we must designate our initializer as
The alternative, as the compile error message informs us, would be to mark the Bird
. This would mean that it
cannot have any subclasses
ƒ thus guarantee‚
ing that the problem will never arise in the first place. If Bird were marked
not
is
This, as Ive already explained, means in turn that any subclass of Bird that imple‚
ments any designated initializers ƒ and thus loses initializer inheritance ƒ must
implement the required initializer and mark it
That fact is responsible for a strange and annoying feature of real-life iOS program‚
Protocols | 193
its own ƒ thus cutting off initializer inheritance. Therefore it must implement
But that makes no sense if you are not expecting
called
your UIViewController subclass. You are being forced to write an initializer for which
you can provide no meaningful functionality! Fortunately, Xcodes Fix-it feature will
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 ƒ which is fine, because
ex hypothesi
you dont expect it ever to be called.
do
ExpressibleByNilLiteral
ExpressibleByBooleanLiteral
ExpressibleByIntegerLiteral
ExpressibleByFloatLiteral
ExpressibleByExtendedGraphemeClusterLiteral
ExpressibleByUnicodeScalarLiteral
ExpressibleByArrayLiteral
194 | Chapter 4: Object Types
ExpressibleByDictionaryLiteral
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
Because Nest adopts ExpressibleByIntegerLiteral, we can pass an Int where a Nest is
will be called automatically, causing a
new Nest object with the specified
to come into existence at that moment:
generic
is a sort of placeholder for a type, into which an actual type will be slotted
later. In particular, there are situations where you want to say that a certain
same
type
is to be used in several places, without specifying precisely
what
Swift generics allow you to say that, without sacrificing or evading Swifts fundamen‚
A motivating case in point arose earlier in this chapter, when we wrote a global fac‚
Generics | 195
partic
ular
Optional. How can this be? Its because Optional is a generic! Heres how an
I have already said that an Optional is an enum, with two cases:
an Optionals case is
, 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 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
196 | Chapter 4: Object Types
The solution to this sort of problem is a generic ƒ in this case, a generic enum. The
declaration for the Optional enum in the Swift header starts like this:
That syntax means: …In the course of this enum declaration, Im going to be using a
placeholder
ƒ that I call Wrapped. 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 Wrapped, I mean this one particular type. When an actual Optional is
created, it will be perfectly clear what type Wrapped stands for, and then, wherever I
say Wrapped, you should substitute the type that it stands for.†
Generics | 197
That is the pseudocode declaration of an Optional whose Wrapped placeholder has
been replaced everywhere with the String type. We can summarize this by saying that
. In fact, that is legal syntax! We can create the same
198 | Chapter 4: Object Types
ated type name, thus resolving the placeholder. If the Bird struct adopts the Flier
Generics | 199
200 | Chapter 4: Object Types
Generics | 201
Comparable protocol exactly guarantees that the adopter
does
work with the less-than
operator:
Now
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.
Naturally, 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
this way, and for just this reason.
A generic protocol (a protocol whose declaration mentions
or has an associated
only
in a generic as a type constraint. If you try to use it in
202 | Chapter 4: Object Types
var name : T?
}
Generics | 203
generic type specialized to a supertype. For example, suppose we have a simple
generic Wrapper struct along with a Cat class and its CalicoCat subclass:
Then you cant assign a Wrapper specialized to CalicoCat where a Wrapper special‚
ized to Cat is expected:
204 | Chapter 4: Object Types
Its illegal in Swift to constrain the associated type Enemy directly to be a Fighter,
because of a rule that type constraints cannot recurse. This restriction is slated to
be removed soon; meanwhile, Ive worked around it by writing the constraint
with a where clause (explained in the next section).
Ill resolve that associated type manually for both the Soldier and the Archer structs:
Now Ill create a generic struct to express the opposing camps of these fighters:
Now suppose that a camp may contain a spy from the opposing camp. What is the
type of that spy? Well, if this is a Soldier camp, its an Archer; and if its an Archer
camp, its a Soldier. More generally, since T is a Fighter, its the type of the Enemy of
this adopter of Fighter. I can express that neatly by a chain consisting of the place‚
, a dot, and the associated type name
The result is that if, for a particular Camp, T is resolved to Soldier,
vice versa
. We have created a correct and inviolable rule for the type
that a Camps
must be. This wont compile:
Weve tried to assign an object of the wrong type to this Camps
property. But this
does compile:
Longer chains of associated type names are possible ƒ in particular, when a generic
protocol has an associated type which is
itself
Generics | 205
Ill add a Weapon associated type to Fighter, which is constrained to be a Wieldable,
and once again Ill resolve it manually for each type of Fighter:
206 | Chapter 4: Object Types
A simple type constraint limits the types eligible for resolving a placeholder to a sin‚
For a generic function, a where clause may appear after the signature declaration
For a generic type, a where clause may appear after the type declaration, before
For a generic protocol, a where clause may appear after the protocol declaration,
For an associated type in a generic protocol, a where clause may appear at the end
of the associated type declaration (this is new in Swift 4).
What sort of thing can appear in a where clause? One possibility is a comma-
separated list of additional constraints on an already declared placeholder. For exam‚
ple, you already know that we can constrain a placeholder at the point of declaration,
using a colon and a type (which might be a protocol composition):
Generics | 207
the associated type
. This pseudocode shows what I mean; Ive omitted the content of
the where clause, to focus on what the where clause will be constraining:
208 | Chapter 4: Object Types
}
struct Insect : Flier {
typealias Other = Walker
}
Generics | 209
An Array can consist of any type ƒ but only
one
type. Array is a generic struct whose
Element placeholder is the type of its elements. The constraint here enforces a rule
that you can append to an Array the elements of any sort of Sequence, but only if they
are the same kind of element as the elements of this array. If the array consists of
String elements, you can add more String elements to it, but not Int elements.
New in Swift 4, a generic protocol or its associated type can have a where clause. The
chief effect of this innovation is to reduce the length of associated type chains. For
example, the Sequence generic protocol has an associated type Iterator, which is con‚
strained to be an adopter of the generic IteratorProtocol, which in turn has an associ‚
ated type Element. Thus, the Swift headers used to be peppered with where clauses
constraining a type to a sequences
. In Swift 4, however, the intro‚
duction of associated type where clauses means that a Sequence itself can have an Ele‚
ment associated type which simply
is
As a result, wherever the Swift header used to say
, it can now say
simply
instead (as in the String and Array
tions I cited a moment ago).
We can use a similar trick to shorten the associated type chain from the preceding
If we find ourselves frequently saying
, we can encapsulate that notion
as an associated type with a where clause:
210 | Chapter 4: Object Types
extension
is a way of injecting your own code into an object type that has already
extending
an existing object type. You can extend
your own object types; you can also extend one of Swifts object types or one of
Cocoas object types, in which case you are
adding functionality
to a type that doesnt
Extension declaration can take place only at the top level of a file. To declare an
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 override an existing member (but it can overload an existing
An extension cant declare a stored property (but it can declare a computed
An extension of a class cant declare a designated initializer or a deinitializer (but
it can declare a convenience initializer).
Extensions | 211
var center : CGPoint {
212 | Chapter 4: Object Types
In that code, 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. Now we can
instantiate a Digit by calling the explicitly declared initializer ƒ
calling the implicit memberwise initializer ƒ
Extensions | 213
}
214 | Chapter 4: Object Types
enum Color : Int {
case color1 = 1
case color2
case color3
init?(_ what:Int) {
self.init(rawValue:what)
}
}
// ... and so on ...
Extensions | 215
make your code a little mystifying, because you seem to be using an undefined type
name out of the blue. It might be a good idea to add a comment, to remind yourself
what youre up to:
216 | Chapter 4: Object Types
The where clause is a constraint guaranteeing that this arrays elements adopt Compa‚
rable, so the compiler permits the use of the
operator ƒ and it doesnt permit the
Umbrella Types | 217
string key name. That object is typed, in Swift, as Any (or as an Optional wrapping
Any, so that it can be
For example:
218 | Chapter 4: Object Types
impossible. You can use the
operators, if youre in doubt, to make sure
It is a member of an Objective-C class.
It is a member of your own Swift subclass of an Objective-C class.
It is a member of your own Swift extension of an Objective-C class.
Umbrella Types | 219
It is a member of a Swift class or protocol marked
This feature is fundamentally parallel to optional protocol members, which I dis‚
220 | Chapter 4: Object Types
Swifts solution is the identity operator (
). Its operands can be an object whose
type is a class or an Optional whose wrapped type is a class (
pares one object reference with another. It is not a comparison of values for equality,
like the equality operator (
Umbrella Types | 221
, and it sees it as a class property. Therefore you
to an AnyClass reference:
to the type name, is of a type that adopts AnyClass, and you can
compare references to such types with the
operator. In effect, this is a way of find‚
222 | Chapter 4: Object Types
element type, despite lacking elements at this moment. An array is itself typed in
accordance with its element type. Two 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.
If all this reminds you of Optionals, it should. Like an Optional, a Swift array is a
generic. It is declared as
, where the placeholder Element is the type
of a particular arrays elements. And, like an Optional, Array types are covariant,
meaning that they behave polymorphically in accordance with their element types: if
NoisyDog is a subclass of Dog, then an array of NoisyDog can be used where an array
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
. However,
Collection Types | 223
generates the array of Int
generates the array of Character
is a Dictionary, generates an array of tuples of the key„value
Another array initializer,
224 | Chapter 4: Object Types
Similarly, the
operator will cast an array to an Optional wrapping an array, which
if the requested cast cannot be performed for each element individually:
Collection Types | 225
Thus, for example, suppose Dog is a struct with a
property, and we decide that
, you can say:
226 | Chapter 4: Object Types
numbers are not 0 and 1, but rather 1 and 2, just as in the original array. If you want
to extract a new array based on this slice, coerce the slice to an Array:
Collection Types | 227
228 | Chapter 4: Object Types
Collection Types | 229
starts(with:)
230 | Chapter 4: Object Types
popLast
Collection Types | 231
tor dictate the new order; alternatively, you can call
232 | Chapter 4: Object Types
Collection Types | 233
tighter way to express the same loop ƒ namely, to loop through the range
is the number of rows in the section). Since
234 | Chapter 4: Object Types
value. This values type ƒ the result type ƒ doesnt have to be the same as the arrays
iteration comes from. The answer is that you have to supply it as the first
argument of the
element of the array be
added to? We want the actual sum of all the elements, no more and no less; so clearly
the first element of the array should be added to
! So heres actual working code:
Collection Types | 235
esting when we consider the problem of splitting our original array of tuples into
two
arrays, composed of the first and second elements of the tuples, respectively:
236 | Chapter 4: Object Types
bridged to Objective-Cs NSArray. The most general medium of array interchange is
; if an Objective-C API specifies an NSArray, with no further type information,
Swift will see this as an array of Any. This reflects the fact that Objective-Cs rules for
what can be an element of an NSArray are looser than Swifts: the elements of an
NSArray do not all have to be of the same type. On the other hand, the elements of an
Objective-C NSArray must be Objective-C
objects
ƒ that is, they must be class types.
Passing a Swift array to Objective-C is thus usually easy. Typically, youll just pass the
array, either by assignment or as an argument in a function call:
Collection Types | 237
For example, this elegant code was previously impossible:
238 | Chapter 4: Object Types
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 as one another, 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
. As with arrays, however, Swift
provides syntactic sugar for expressing a dictionarys type, which is what youll usu‚
Collection Types | 239
ces can be a partial range; in theory the range is infinite, but in fact the end of the
240 | Chapter 4: Object Types
Collection Types | 241
In Swift 4, however, its effectively a one-liner:
()words.forEach {word in d[word, default:0] += 1}Earlier, I promised to give an example of
forming the same histogram in a silly but interesting way; I start with a values array
of ones, and sum the values whenever a duplicate key is encountered:
242 | Chapter 4: Object Types
the dictionary itself. You cant assign one to a variable, or print it out; but they are
For example, you can enumerate them with
them to arrive in any particular order, as a dictionary is unordered):
for s in d.keys { print(s) // NY, then CA}You can coerce them to an array:
var keys = Array(d.keys) // ["NY", "CA"]You can sort them, filter them, or map them (yielding an array). You can take their
. You can
them. You can compare
of different dictionaries for
equality:
Collection Types | 243
that yields a dictionary with its values changed according to your map function. This
makes dictionary transformations much easier than in the past. So, for example:
244 | Chapter 4: Object Types
dictionary as a literal and pass it, all in one move, with no need to cast anything:
Collection Types | 245
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
any
element, such as the first element. For this purpose, use the
instance
246 | Chapter 4: Object Types
,
subtract(_:)
Collection Types | 247
248 | Chapter 4: Object Types
Collection Types | 249
250 | Chapter 4: Object Types
This chapter is a miscellany, presenting various remaining aspects of the Swift lan‚
guage. Ill start by describing the syntax of Swifts flow control constructs for branch‚
ing, looping, and jumping. Next Ill discuss a new Swift 4 language feature, key paths.
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 aspects of Swift memory management.
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 com‚
puter program …intelligent,† and not merely a simple fixed sequence of steps. By test‚
condition
ƒ an expression that evaluates to a Bool and is thus
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
does not have to be wrapped in parentheses
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.
Swift has two forms of branching: the if construct, and the switch statement. Ill also
discuss conditional evaluation, a compact form of if construct.
is similar to C. Many examples of if constructs
have appeared already in this book. The construct may be formally summarized as
Example 5-1
Example 5-1.
if construct
252 | Chapter 5: Flow Control and More
The third form, containing
, can have as many
blocks as needed, and
block may be omitted.
Heres a real-life if construct that lies at the heart of one of my apps:
can be followed immediately by a variable declaration and assignment ƒ
that is, by
nil
, the condition fails and the block is not executed.
not
The Optional is unwrapped.
The unwrapped value is assigned to the declared local variable.
Thus, a conditional binding is a convenient shorthand for safely passing an unwrap‚
ped Optional into a block. The Optional is unwrapped, and the block is executed,
can
be unwrapped.
It is perfectly reasonable 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! There is then no need to make up a
Flow Control | 253
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
optionally unwrap a Notifications
254 | Chapter 5: Flow Control and More
reflects perfectly the successive stages of testing. If I want to avoid the pyramid of
statements (
…Guard† on page 282
switch statement
Heres an actual example:
In that code, a variable
is first compared to the
is
, that cases code is executed and thats all. If it is
not
, it is compared
is
that
cases code is executed and thats all. If the value of
matches neither of those, the
cases code is executed.
Flow Control | 255
In Swift, a switch statement must be
exhaustive
. This means that
every
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
256 | Chapter 5: Flow Control and More
case 1:
print("You have 1 thingy!")
Flow Control | 257
258 | Chapter 5: Flow Control and More
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
. Using a tuple, we can safely attempt to
Flow Control | 259
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
260 | Chapter 5: Flow Control and More
To combine switch case tests (with an implicit logical-or), separate them with a
In this example,
is declared as an Any:
A comma can even combine patterns that declare binding variables, provided they
is our MyError once again):
Flow Control | 261
use in a condition the same sort of pattern syntax youd use in a case of a switch state‚
ment. The structural difference is that, whereas a switch case pattern is compared
against a previously stated tag, an
pattern is followed by an equal sign and
For example, this is another way to extract an associated value from an enum;
our MyError enum once again:
262 | Chapter 5: Flow Control and More
Flow Control | 263
while loop
264 | Chapter 5: Flow Control and More
for loop
construct that forms the basis of Swifts for loop is similar to Objective-
Cs
construct. In Objective-C, this syntax is available whenever a class con‚
NSFastEnumeration
protocol. In Swift, it is available whenever a type
construct, the variable is implicitly declared with
Flow Control | 265
.) The variable is also local to the block. On each iteration, a suc‚
cessive element of the sequence is used to initialize the variable, which is then in
A common use of for loops is to iterate through successive numbers. This is easy in
Swift, because you can readily create a sequence of numbers on the fly ƒ a Range:
Under the hood, a Sequence has a
266 | Chapter 5: Flow Control and More
construct can take a where clause, allowing you to skip some values of
and
, theres also
, permitting a switch case pattern
to be used a for loop. The tag is each successive value of the sequence, so no assign‚
Flow Control | 267
sequence generated by the
is not a problem, because the resulting sequence is …lazy,† meaning that an element
isnt generated until you ask for it. In reality, youll use one of two techniques to limit
268 | Chapter 5: Flow Control and More
ways of jumping, which will, in practice, cover any real-life situation. Swifts modes of
jumping are all forms of
early exit
from the current flow of code.
In a while loop,
means to perform immediately the conditional
In a for loop,
means to proceed immediately to the next iteration if
statement aborts the current construct:
In a loop,
aborts the entire switch construct.
When constructs are nested, you may need to specify
which
construct you want to
or
label
construct, a switch statement, a while loop, or a for loop (or a do block, which Ill
describe later). The label is an arbitrary name followed by a colon. You can then use
that label name as a second term in a
or
statement within the labeled
construct at any depth, to specify that this is the construct you are referring to.
Heres an artificial example to illustrate the syntax. First, Ill nest two for loops with
Flow Control | 269
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:
type that adopts Error
ready to be used as an error object; the protocol requirements are magically ful‚
filled for you, behind the scenes. Typically, this type will be an enum, which will
270 | Chapter 5: Flow Control and More
communicate its message by means of its cases: different cases will distinguish
different kinds of possible failure, perhaps with raw values or associated types to
carry further information.
NSError
NSError is Cocoas class for communicating the nature of a problem; Swift
extends NSError to adopt Error and bridges them to one another. If your call to a
an error aborts the current path of execution and hands an error object
Catching
an error receives that error object from the error mechanism and
responds in good order, with the path of execution resuming after the point of
catching. In effect, we have
jumped
from the throwing point to the catching
point.
To
throw an error
followed by an error object. Thats all it
takes! The current block of code is immediately aborted, and the error mechanism
takes over. However, to ensure that the
command is used coherently, Swift
imposes a rule that you can say
only in a context where the error can be caught
What is such a context?
The primary context for throwing and catching an error is the
construct.
This consists of a do block and one or more catch blocks. It is legal to throw in the do
block; an accompanying catch block can then be fed any errors thrown from within
constructs schema looks like
Example 5-5
Example 5-5.
construct
A single do block can be accompanied by multiple catch blocks. Catch blocks are like
the cases of a switch statement, and will usually have the same logic: first, you might
Flow Control | 271
possible errors; finally, you might have a general catch block that acts as the default,
mopping up any errors that were not caught by any of the specialized catch blocks.
syntax
used by a catch block to specify what sorts of error it catches
is
the
pattern syntax used by a case in a switch statement! Imagine that this
is
a switch state‚
ment, and that the tag is the error object. Then the matching of that error object to a
particular catch block is performed just as if you had written
Typically, when the Error is an enum, a specialized catch block will state at least the
enum that it catches, and possibly also the case of that enum; it can have a binding, to
capture the enum or its associated type; and it can have a where clause to limit the
possibilities still further.
To illustrate, Ill start by defining a couple of errors:
And heres a
construct designed to demonstrate some of the different
ways we can catch different errors in different catch blocks:
In a catch block with an accompanying pattern, it is up to you to capture in the
pattern any desired information about the error. For example, if you want the
error itself to travel as a variable into the catch block, youll need a binding in the
pattern.
A catch block whose pattern is
only
a binding catches
any
error under that name;
for example,
272 | Chapter 5: Flow Control and More
In a …mop-up† catch block with
no
accompanying pattern (that is, the bare word
and no more), the error object arrives into the block
automatically
Flow Control | 273
to a function declaration creates a distinct function type. The
, but rather
274 | Chapter 5: Flow Control and More
But Swift also provides a clever shorthand. If you are very sure that a
function
not
throw, then you can call it with the keyword
relieves you of all further responsibility: you can say
anywhere
, without catching
the possible throw. But be warned: if youre wrong, and this function
does
when your program runs, your program can crash at that moment, because you have
allowed an error to percolate, uncaught, all the way up to the top of the call stack.
Flow Control | 275
276 | Chapter 5: Flow Control and More
if (s == nil) {
NSLog(@"%@", err);
}
As you can see, the whole procedure is a lot like using a Swift
inout

dance ƒ a much simpler, more pleasant
Flow Control | 277
An initializer can throw ƒ that is, the initializers declaration is marked
designing an initializer, when should you prefer a failable initializer (
)? No hard and fast rule can
be given. Both in the Swift header and in the Swift Foundation overlay,
outnumbers
implies simple failure to create an
implies that there is useful information to be gleaned by
studying the error. (At least one initializer in the Swift Foundation overlay is both,
though that might be a mistake.)
Objective-C sees a Swift error coherently as well. By default, it receives a Swift error
type is an enum, the NSErrors
is the index number of its case; otherwise, the
is 1. When you want to provide Objective-C with a fuller complement of infor‚
mation, make your error type adopt one or both of these protocols:
LocalizedError
Adopts Error, adding three optional properties:
). Observe
that these are
properties; declaring them as simple String rather than
Optional fails to communicate the information to Objective-C, and is a common
CustomNSError
Adopts Error, adding three properties with default implementations:
rors
278 | Chapter 5: Flow Control and More
Another use of a do block is to implement the simplest form of early exit. The do
block gives you a scope to jump out of; by labeling the do block and breaking to that
can
jump out of it:
Flow Control | 279
if
we can guarantee that the only path of execution out of this
280 | Chapter 5: Flow Control and More
it won†t be executed.
For this
reason, always place your defer block as close to the start of its surrounding block as
you can, to ensure that it will in fact be encountered.
If the current scope has multiple defer blocks pending, they will be called in the
reverse of the order in which they were originally encountered. In effect, there is a
stack
; each successive defer statement, as it is encountered, pushes its code onto
the top of the stack, and exiting the scope in which a defer statement appeared pops
that code and executes it.
Aborting the whole program 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
do
abort, things must be so bad that youve no
One way to abort is by calling the global function
. It takes a String
Flow Control | 281
By default,
works only when youre developing your program. When your
program is to be finalized and made public, you throw a different build switch, telling
the compiler that
. This means that you can safely
leave
your assertions should be failing; 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
guard construct
must
jump out of the current scope, by any of the means that Swift
282 | Chapter 5: Flow Control and More
An elegant consequence of this architecture is that, because the guard construct guar‚
antees an exit on failure of the condition, the compiler knows that the condition has
not
exit. Thus, a conditional binding in
is in scope
the guard construct
, without introducing a further nes‚
ted scope. For example:
Flow Control | 283
helps to solve an interesting problem. Suppose we have a function whose
284 | Chapter 5: Flow Control and More
ƒ and of course, the more choices there are, the more elaborate our code must be
Key paths solve the problem by permitting us to encapsulate
the notion
particular property of a type, such as Persons
performing
the access. That notion is expressed as an instance; therefore, we
Key Paths | 285
functions; from the
286 | Chapter 5: Flow Control and More
, preceded by an operator
type
by the name of the operator. The types are:
Operators | 287
� static func +(lhs:Vial, rhs:Vial) - Vial {
288 | Chapter 5: Flow Control and More
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 as well.
Operators | 289
access control
) refers to the explicit modification of the normal
scope rules. I gave an example in
Chapter 1
The intention here is to limit how other objects can see the Dog property
. It is a private property, intended primarily for the Dog classs own internal use: a
, but other objects should not be aware that it
Swift has five levels of privacy:
The default rule is that declarations are
internal
, meaning that they are globally
all code in all
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
statements.)
(narrower than
only within its containing
For exam‚
ple, two object types declared in the same file can see one anothers members
(even narrower than
only within its containing curly braces
effect, the visibility of an object types member declared
code within this class declaration. (A
declaration at the top level of a file
is equivalent to
(wider than
even outside its containing module
module must first import this module before it can see anything at all. But once
has
imported this module, it still wont be able to see anything in
this module that hasnt been explicitly declared
. If you dont write any
modules, you might never need to declare anything
must
something
290 | Chapter 5: Flow Control and More
(even wider than
, code in another module can subclass it; it cant do that
code in another module that subclasses this class can override this member; it
cant do that without the
declaration.
Privacy | 291
In effect, an extension sees its types
292 | Chapter 5: Flow Control and More
If the only initializer for a public type is implicit, code in another module cant
see it and thus cannot create an instance of this type. If you want other code to be
able to create an instance of this type, you must declare the initializer
explicitly
access level draws a further distinction. It is applicable only to classes and to
members of open classes. A public class cant be subclassed in another module that
can see this class; an open class can. A public member of an open class that has been
subclassed in another module cant be overridden in that subclass; an open member
A variable cant be public if its type is private, because other code wouldnt be able
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
ties. This means that we can later add more properties without having to modify our
implementation:
Introspection | 293
var name = "Fido"
var license = 1
var description : String {
var desc = "Dog ("
294 | Chapter 5: Flow Control and More
as soon as they are no longer needed. Nevertheless, there are some memory manage‚
ment issues of which even a Swift user must be conscious.
Memory management of reference type objects is quite tricky under the hood; Ill
Chapter 12
to a discussion of the underlying mechanism. Trouble typically
arises when two class instances have references to one another. When thats the case,
you can have a
retain cycle
memory leak
, meaning that the two
never
go out of existence. Some computer languages solve this sort of prob‚
Memory Management | 295
296 | Chapter 5: Flow Control and More
. Also, the reference must be a
reference, precisely because it can change
spontaneously to
Memory Management | 297
object absolutely cannot exist without a reference to another, but where this reference
298 | Chapter 5: Flow Control and More
ence is also dangerous, because the object referred to can go out of existence behind
the referrers back, and an attempt to use that reference will cause a crash, as I can
demonstrate by this rather forced code:
Memory Management | 299
� var function : (() - ())?
deinit {
print("farewell from FunctionHolder")
}
}
func testFunctionHolder() {
300 | Chapter 5: Flow Control and More
in my capture list instead. In real
life, my own most frequent use of
is precisely in this context. Very often, the
in the capture list will be
Dont panic! Beginners have a tendency to backstop
all
their anonymous func‚
. Thats unnecessary and wrong. Only a
stored
Memory Management | 301
New in Swift 4, even value types, such as structs, can have memory management
issues. In particular, a struct and its members might be directly accessed simultane‚
ously, which could lead to unpredictable results. Fortunately, in many cases the com‚
To illustrate, imagine that we have a Person struct with a
string property.
302 | Chapter 5: Flow Control and More
Memory Management | 303
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
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
project
of files from which an app is generated.
Chapter 7
nib
is a file containing a drawing of your interface.
Understanding 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
various steps youll take on the way to submitting your app to the App Store.
Xcode is the application used to develop an iOS app. An Xcode
project
Start up Xcode and choose File ΠNew ΠProject.
The …Choose a template† dialog appears. The
template
You are now asked to provide a name for your project (Product Name).
Ignore the Team pop-up menu for now; Ill discuss its significance in
Chapter 9
Ignore the Organization Name as well; it is used only in some automatically gen‚
erated code comments.
Note the Organization 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 identifying you or your organization. The convention is to start the organi‚
zation identifier with
and to follow it with a string (possibly with multiple
dot-components) that no one else is likely to use. For example, I use
. 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 organization identifier, will consist by default of the organization iden‚
tifier 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 identify this
project and the app that it produces. (You will be able to change the bundle iden‚
tifier manually later if necessary.)
308 | Chapter 6: Anatomy of an Xcode Project
Objective-C files to a Swift project. You can even start with an Objective-C
For this example project, make sure Use Core Data, Include Unit Tests, and
Include UI Tests are
not
checked. Click Next.
Youve now told Xcode how to construct your project. Basically, its going to copy
Single View App.xctemplate
Xcode application bundle. But you need to tell it where to copy this template
to
. Thats why Xcode is now presenting a Save dialog with a Create button.
You are to specify the location of a folder that is about to be created ƒ 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.
Xcode also offers, through a checkbox, to create a git repository for your project.
(You might need to click Options to see the checkbox.) In real life, this can be a
great convenience (see
Chapter 9
), but for now, uncheck that checkbox. If you see
an Add To pop-up menu, leave it at the default, …Dont add to any project or
workspace.† Click Create.
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
The project weve just created is a working project; it really does build an iOS app
called Empty Window. To see this, you can actually build the app ƒ and run it! The
scheme and destination in the project windows toolbar are probably listed as Empty
Window Œ iPhone 7 Plus; thats fine. (The scheme and destination are actually pop-
up menus, so you can click on them to change their values if needed.) Choose Prod‚
uct ΠRun. After some delay, the Simulator application eventually opens and displays
your app running ƒ an empty white screen.
To
build
a project is to compile its code and assemble the compiled code,
The Project Window | 309
Figure 6-1.
project window
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
Any frameworks that the code will need when it runs
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.
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.
310 | Chapter 6: Anatomy of an Xcode Project
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.
At the bottom is the Debug pane. Show and hide it with View Œ Debug Area Œ
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 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:
The Project Window | 311
Figure 6-2.
Project navigator
in the Project navigator are actually called
groups
view its code in the editor.
At the top level of the Project navigator, with a blue Xcode icon, is the Empty
312 | Chapter 6: Anatomy of an Xcode Project
Figure 6-3.
Find navigator
appears in the Symbol navigator; for example, try typing …active† in the search
field, and see what happens.
Find navigator (Command-4)
This is a powerful search facility for finding text globally in your project. You can
also summon the Find 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† (
). 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; every navigator has it in some form.)
Issue navigator (Command-5)
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. The Issue navigator can also display certain run‚
time issues (such as leaks, as Ill explain in
Chapter 9
, and in the blank line after the last comment at the top of the
files contents, above the
B). Switch to the Issue navigator if it doesnt appear automatically; in its Build‚
time pane, it displays some error messages, showing that the compiler is unable
to cope with this illegal word appearing in an illegal place. Click an issue to see it
The Project Window | 313
Figure 6-4.
Debug layout
within its file. In your code, issue …balloons† may appear to the right of lines con‚
, select in the line that says
314 | Chapter 6: Anatomy of an Xcode Project
The Debug navigator starts with several numeric and graphical displays of profil‚
variables list (on 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
The Project Window | 315
Figure 6-5. Viewing a report
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 report, we
). 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
316 | Chapter 6: Anatomy of an Xcode Project
top half
What appears in the top half of the Utilities pane depends on whats selected in
the current editor. For example:
A code
is being edited
The top half of the Utilities pane shows either the File inspector or Quick
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
multiple sections, each of which can be expanded or collapsed by clicking its
header.
Other forms of editing may cause other inspector combinations to appear here.
bottom half
The Project Window | 317
editor
simultaneously. This can be achieved in three ways: assistants, tabs, and secondary
318 | Chapter 6: Anatomy of an Xcode Project
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-
The Project Window | 319
Figure 6-6.
Project navigator (Xcode) and the project folder (Finder)
Secondary windows
A secondary project window is similar to a tab, but it appears as a separate win‚
dow 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 win‚
dow by dragging it right out of its current window.
, corresponding to the project listed first in the Project nav‚
igator. 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 icon
320 | Chapter 6: Anatomy of an Xcode Project
(in the Finder, in the Dock, or in the application switcher) and Xcode will locate the
Recall that
group
is the technical term for the folder-like objects shown in the Project
The Empty Window group corresponds directly to the
Empty Window
disk. Groups in the Project navigator dont necessarily correspond to folders on
disk in the Finder, and folders on disk in the Finder dont necessarily correspond
to groups in the Project navigator. But in this case, there is such a correspond‚
Files within the Empty Window group, such as
real files on disk that are inside the
Empty Window
folder. If you were to create
course of developing your project), you would likely put them in the Empty Win‚
dow 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.)
Two files in the Empty Window group,
Main.storyboard
LaunchScreen.story
board
, appear in the Finder inside a folder that doesnt visibly correspond to any‚
thing in the Project navigator, called
Base.lproj
. This arrangement has to do with
localization
, which Ill discuss in
Chapter 9
Assets.xcassets
in the Project navigator corresponds to a specially struc‚
Assets.xcassets
asset catalog
The Products group and its contents dont correspond to anything in the project
folder. Xcode generates a reference to the executable bundle generated by build‚
The Project File and Its Dependents | 321
and has a solid folder icon, like the Empty Window group in
and simple exists purely within the Project navigator, and has a marked folder icon,
. Youll encounter this distinction when creating
a group, when using a group, and when renaming a group:
Creating a group
When you make a new group, theres a choice of menu items; for example, in the
contextual menu, you might see New Group and New Group With Folder. (Con‚
322 | Chapter 6: Anatomy of an Xcode Project
Figure 6-7. Two ways of showing the project and targets
You might want to perform unit tests or interface tests; to do so, youd add a tar‚
You might 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 configure its pri‚
You might write an application extension, such as a today extension (content to
appear in the notification center) or a photo editing extension (custom photo
currently contains
Figure 6-8.
app target†s build phases
Swift file to your project (typically in order to declare another class), youll spec‚
324 | Chapter 6: Anatomy of an Xcode Project
Figure 6-9. Target build settings
Multiple configurations are needed because you build in different ways at different
326 | Chapter 6: Anatomy of an Xcode Project
Figure 6-10.
Figure 6-11. How
build settings
ing 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 Optimiza‚
tion Level is Fast, Whole Module Optimization. When your app is ready to ship, you
build it with the Release configuration, so the resulting binary is optimized for speed,
which is great for your users 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. In addition, Whole Module Optimization allows the Swift
compiler to survey all your code files at once. Compilation may take longer, but the
Figure 6-12.
scheme editor
On the left side of the scheme editor are listed various actions you might perform
328 | Chapter 6: Anatomy of an Xcode Project
Figure 6-13.
Scheme pop-up menu
scheme where the Address Sanitizer is always turned on. You would then use the
Address Sanitizer by switching schemes.
Handy access to schemes and their management is through the Scheme pop-up menu
Each simulated device has a system version that is installed on that device. At the
moment, all our simulated devices are running iOS 11; thus, there is no distinction to
be drawn, and the system version is not shown. However, you can download addi‚
tional SDKs (systems) in Xcodes Components 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 exam‚
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
330 | Chapter 6: Anatomy of an Xcode Project
Figure 6-14.
built app, in the Finder
Figure 6-15. Contents of the app package
linked to the various frameworks, and the code begins to run. (Later in this chap‚
From Project to Running App | 331
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
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
LaunchScreen.storyboardc
Our apps launch screen file. This file, the compiled version of
LaunchScreen.storyboard
, contains the interface that will be displayed briefly dur‚
ing the time it takes for our app to launch.
Assets.car, AppIcon60x60@2x.png
332 | Chapter 6: Anatomy of an Xcode Project
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.
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,
then choose Editor ΠShow Raw Keys & Values, or use the contextual menu.
Info.plist
file in its true XML form: Control-
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
From Project to Running App | 333
Orientation checkbox here, you are changing the value of the …Supported inter‚
face orientations† key in the
Info.plist
334 | Chapter 6: Anatomy of an Xcode Project
Figure 6-16. Options when adding a resource to a project
Resources
Project navigator
If you add a resource to the Project navigator, also ensuring that it appears in the
level of your app bundle.
An asset catalog
From Project to Running App | 335
Added folders
This choice matters only if what youre adding to the project is a folder; the dif‚
ference is in how the project references the folder contents:
Create groups
The folder name becomes the name of a folder-linked group within the
Project navigator. The folder contents appear in this group, but they are lis‚
ted individually in the Copy Bundle Resources build phase, so by default
they will all be copied individually to the top level of the app bundle.
Create folder references
The folder is shown in blue in the Project navigator (a
folder reference
moreover, 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 arrange‚
ment can be valuable if you have many resources and you want to separate
them into categories (rather than clumping them all at the top level of the
app bundle) or if the folder hierarchy among resources is meaningful to your
app. The downside of this arrangement is that the code you write for access‚
ing a resource will have to be specific about what subfolder of the app bundle
contains that resource.
Add to targets
336 | Chapter 6: Anatomy of an Xcode Project
Figure 6-17. Slots for an image set in the asset catalog
listen@3x.png
. The resulting proliferation of image files in the Project navigator can
be overwhelming and error-prone.
From Project to Running App | 337
The build process knows what code files to compile to form the apps binary because
development of your app proceeds, you will probably add further code files to the
project, typically in order to declare a new object type, and they, too, will be part of
338 | Chapter 6: Anatomy of an Xcode Project
When you build your code
A copy of any needed frameworks is used. This copy lives in
/System/Library/Frameworks
folder inside the iPhone SDK, which is located
inside the Xcode app bundle.
When your code runs on a device
The code, as it starts running, looks for the frameworks that it needs on the
device itself, in the devices top-level
/System/Library/Frameworks
folder.
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
target†s Link Binary With Libraries build phase
From Project to Running App | 339
Module-based autolinking
modules
autolinking
modules and autolinking are optional features, and are governed by build
Select iOS; under Framework & Library, select Cocoa Touch Framework. Click
Next.
and will then be able to see that object type and its public
340 | Chapter 6: Anatomy of an Xcode Project
Having located and loaded the binary (which, as Ive already explained, is possible
because the name of the binary is specified in the
Info.plist
file), and having linked to
any needed frameworks, the system must call into the binarys code to start it run‚
ning. 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
have a
main.m
file containing the
It calls the
function, which does the heavy lifting of helping
can see it, attached to the declaration of the AppDelegate class:
This attribute essentially does everything that the Objective-C
main.m
it creates an entry point that calls
The App Launch Process | 341
Why might you do that sort of thing? Presumably, it would be because you want to do
file, or because you want to customize the call to
attribute, you are calling
tion call is the primary thing your app does. Your entire app is really nothing but a
single gigantic call to
! Moreover,
creates your apps
instance
ƒ the shared application
instance, which subsequently is to be accessible in code as
The third argument in the call to
specifies, as a string, what class the shared application instance should be an
instance of. If this argument is
, as will usually be the case, the default class is
UIApplication. If, however, you needed to subclass UIApplication, you would
specify that subclass by substituting a different value, such as
(depending on what the subclass is called), as the
third argument in an explicit call to
also creates your apps
second instance
ƒ the application
instances
delegate
. Delegation is an important and pervasive Cocoa pattern,
, that specification is
attribute, that attribute is
attached, by default, to the AppDelegate class declaration in
the attribute means: …
is the app delegate class!†
If there is a main storyboard (as specified by the
Info.plist
loads it and looks inside it to find the view controller that is designated as
this storyboards
initial view controller
storyboard entry point
it instantiates
342 | Chapter 6: Anatomy of an Xcode Project
this view controller, thus creating your apps
third instance
, a UIViewController
subclass. In the case of our Empty Window project, as constructed for us from
the Single View App template, that view controller will be an instance of the class
called ViewController; the code file defining this class,
also created by the template.
If there is a main storyboard,
now creates your apps
window
ƒ this is your apps
fourth instance
, an instance of UIWindow (or your app dele‚
gate can substitute an instance of a UIWindow subclass). It assigns this window
instance as the app delegates
property; it also assigns the initial view con‚
troller instance as the window instances
property. This
view controller is now the apps
root view controller
now turns to the app delegate instance and starts calling
is a good place to put your code that initializes values
and performs startup tasks; but you dont want anything time-consuming to hap‚
pen here, because your apps interface still hasnt appeared.
If there is a main storyboard,
now causes your apps interface
The window is now about to appear. This, in turn, causes the window to turn to
the root view controller and tell it to obtain its main view, which will occupy and
The App Launch Process | 343
In my description of the app launch process, I used several times the phrase …if there
is a main storyboard.† In the Xcode app templates, such as the Single View App tem‚
plate that we used to generate the Empty Window project, there
is
a main storyboard.
It is possible, however,
not
to have a main storyboard. This way of structuring an app
project is unusual nowadays, but it is quite viable; in fact, some of my own apps have
no main storyboard.
Without a storyboard, things like creating a window instance, giving it a root view
controller, assigning it to the app delegates
property, and calling
on the window to show the interface, must be done by your code. To see
To make a minimal working app, edit
in such a way as to recre‚
ate the AppDelegate class with just enough code to create and show the window,
Example 6-1
Example 6-1. An App Delegate class with no storyboard
so that its
344 | Chapter 6: Anatomy of an Xcode Project
Run the app again; sure enough, the background is now red.
You can actually omit steps 1 and 2, and
Example 6-1
will still work. What you then
have is an app that
has
a main storyboard, but
ignores
it at launch time: it creates its
root view controller in code, overriding the automatic behavior of
. This approach can be useful when you want the choice of root view controller
(the storyboards initial view controller or some other view controller) to depend on
the circumstances; a common case in point is an initial sign-in screen that shouldnt
appear again once the user has signed in.
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
Renaming Parts of a Project | 345
You can change the name of the project folder in the Finder at any time, and you can
346 | Chapter 6: Anatomy of an Xcode Project
Chapter 4
, I talked about ways of obtaining an instance. You can directly instanti‚
ate an object type:
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.
Nibs are probably the least understood aspect of iOS programming. Many beginners
go on using nibs without knowing what they really are, how they really work, or how
, has nothing to do with fountain pens or bits of choco‚
late. The graphical nib-design aspect of Xcode, which I call the
nib editor
, used to
be (up through Xcode 3.2.x) a separate application called Interface Builder. (The
nib editor environment within Xcode is still often referred to as Interface
Builder.) The files created by Interface Builder were given the
.nib
as an acronym for …NeXTStep Interface Builder.† Nowadays, the file you edit
.storyboard
.xib
app is built, they are compiled into nib files (see
Chapter 6
348 | Chapter 7: Nib Management
Figure 7-1. Editing a nib
Main.storyboard
. (Ive made
some additional adjustments to make the screenshot fit on the page.) The interface
may be considered in four pieces:
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 rectan‚
gular area. The phrase …things that can contain views† is my way of including
view controllers, which are represented in the canvas even though they are not
drawn in your apps interface; a view controller isnt a view, but it
has
a view.
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 below the the canvas.
The libraries in the Utilities pane, especially the Object library, are your source of
interface objects to be added to the nib.
The Nib Editor Interface | 349
Figure 7-2. A view controller selected in a storyboard
350 | Chapter 7: Nib Management
Figure 7-3. A .xib
containing a view
Proxy objects
not
represent
instances that will come from the nib when it is loaded. Rather, they represent
The Nib Editor Interface | 351
Figure 7-4.
dock in a .xib
is loaded as the app runs. The document outline in a
.xib
352 | Chapter 7: Nib Management
Figure 7-5. Dragging a button into a view
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
Figure 7-1
.
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
Drag the Button object from the Object library into the view controllers main
view in the canvas (
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 standard
spacing. Similarly, drag the button near the center of the view: a guideline shows
you when the button is centered.
The Nib Editor Interface | 353
Figure 7-6.
Empty Window app†s window is empty no longer
With the button selected, hold down the Option key and hover the mouse out‚
Double-click the buttons title. The title becomes editable. Give it a new title, such
top
corner of the canvas. (If you dont
do this, the button could be off the screen when the app runs.)
Examine the Debug ΠActivate / Deactivate Breakpoints menu item. If it says
Deactivate Breakpoints, choose it; we dont want to pause at any breakpoints you
may have created while reading the previous chapter.
Make sure the destination in the Scheme pop-up menu is an iPhone simulator,
Choose Product ΠRun (or click the Run button in the toolbar).
After a heart-stopping pause, the Simulator opens, and presto, our empty window is
empty no longer (
); 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.
354 | Chapter 7: Nib Management
In addition to the File and Quick Help inspectors, four inspectors appear specifically
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)
The Nib Editor Interface | 355
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; inter‚
face 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 at launch time only just the nibs needed to generate the apps
initial
interface, and no more, makes launching faster.
Theres no such thing as …unloading† a nib. The job of the nib-loading process is to
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
356 | Chapter 7: Nib Management
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
You can instantiate any view controller whose scene is named within the
storyboard by an identifier string by calling
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 obtains
later
, when that view is needed because it is to be placed into the
interface. (We say that a view controller loads its view
lazily
.) 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
controller was loaded in order to instantiate the view controller, as I just
described; later, when that view controller instance needs its main view, the main
automatically
, and the whole interface connected with that
view controller springs to life.
Another fairly common configuration is that the view controller is instantiated in
not
from a storyboard, but by calling the UIViewController designa‚
.xib
manually
Nib Loading | 357
In the Empty Window project, choose File ΠNew ΠFile and specify iOS ΠUser
Interface ΠView. This will be a
.xib
file containing a UIView instance. Click
Next.
In the Save dialog, accept the default name, View, for the new
.xib
Create.
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.
Our view is too large for purposes of this demonstration, so select it and, in the
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 (
load
this nib file, manually, in code, when the app runs. Edit
View
viewDidLoad
Load the nib.
Obtain the instances that it creates as it loads.
358 | Chapter 7: Nib Management
Figure 7-7. Designing a view in a .xib
task ƒ we loaded the nib ƒ but we didnt obtain any instances
from it. Thus, those instances were created
and then vanished in a
of smoke!
order to prevent that, we need to
capture
those instances somehow. The call to
Nib Loading | 359
Figure 7-8. A nib-loaded view appears in our interface
connection
is an entity in a nib file that 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
destination
Person.
Theres a Dog object and a Person object in a nib.
360 | Chapter 7: Nib Management
Figure 7-9. How an outlet provides a reference to a nib-instantiated object
places
Connections | 361
.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.
So exactly what
is
the nib owner object in the nib editor? It represents an instance that
already
outside
the nib at the time that the nib is loaded. When the nib is
doesn†t
instantiate this object; it is
already
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
instance 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:
Your code loads the nib
If your code loads a nib manually, either by calling
you specify an owner object as the
argument.
A view controller loads the nib
If a view controller instance loads a nib automatically in order to obtain its main
view, the view controller instance specifies
itself
Person.
There is a Person nib object in our nib, but
no
nib
owner object
362 | Chapter 7: Nib Management
Figure 7-10. An outlet from the nib owner object
When we load the nib, we specify
an existing Dog instance as owner
In that case, the nib-loading mechanism will
match
the already existing actual Dog instance that we specified as owner, and will assign
the newly instantiated Person instance as
that
Dog instances
running inside a ViewController instance. We want to use that instance as the nib
owner. This will be a little tedious to configure, but bear with me, because under‚
standing how to use this mechanism is crucial. Here we go:
Connections | 363
Figure 7-11. Creating an outlet
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:
View.xib
. Our first step must be to ensure that the nib owner object is desig‚
nated as a ViewController instance. Select the Files Owner proxy object and
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!
Instead, were going to load the nib
with ourself as owner
. This will cause our
364 | Chapter 7: Nib Management
In code, there must be an
instance property
That property must be
marked
In the nib editor, the
class of the nib owner object
In the nib editor, an
outlet
must be created, with the same name as the property,
configurations were correctly performed.)
if
In our manual example, we had to have an instance property in our nib owner
class. Well, ViewController is a UIViewController, and UIViewController has a
In our manual example, in the nib editor, we had to make sure that the nib owner
objects class was the class whose instance really will be the owner when the nib
loads. Well, in
Main.storyboard
, in the single scene, the View Controller object
is
the nib owner. Moreover, it is of the correct class, namely ViewController (the
file). Look and see! Select the View‚
Controller object in the storyboard and examine its class in the Identity inspec‚
tor.
Connections | 365
Figure 7-12. A view controller†s view outlet connection
has
badview
:
366 | Chapter 7: Nib Management
. Run the
project to prove that all is well. Now were going to mess things up at the other
View.xib
. Select the Files Owner and switch to the Connections inspec‚
tor, and disconnect the
Connections | 367
No view outlet
I cant demonstrate this problem using a
.storyboard
file. What wed like to do is
disconnect
Now attempt to build the project; the compiler issues an error on the line refer‚
, because there is now no such
368 | Chapter 7: Nib Management
In the nib editor, we control-dragged from the source to the destination in the
, create (or uncomment) the prop‚
erty declaration, and save:
Connections | 369
Figure 7-13. Connecting an outlet by dragging from code to nib editor
. In the assistant pane, show
View.xib
, in such a way that the view is
Drag from property declaration to nib
Next to the property declaration in the code, in the gutter, is an empty circle.
Drag from that circle
right across the barrier
to the View in the nib editor
370 | Chapter 7: Nib Management
Figure 7-14. Creating an outlet by dragging from nib editor to code
Figure 7-15.
a property declaration
Drag from nib to code
Control-drag from the view in the nib editor across the pane barrier to just inside
declaration. A HUD offers to Insert Out‚
Connections | 371
372 | Chapter 7: Nib Management
connection, as you form it, what the control event and action message should be. To
destination
, so that there is no out‚
declaration body:
Connections | 373
Figure 7-16. A HUD showing an action method
(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
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).
A HUD listing possible connections appears (
but it also lists Sent Events, and in particular it lists
listing in the HUD.
The action connection has now been formed. This means that when the app runs, any
Drag from source Connections inspector
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
374 | Chapter 7: Nib Management
Figure 7-17.
an action method declaration
Drag from source HUD
Control-click the button. A HUD appears, similar to the Connections inspector.
Drag from destination HUD
Control-click the view controller. A HUD appears, similar to the Connections
inspector. Drag from
(under Received Actions) to the button.
Another HUD appears, listing possible control events. Click Touch Up Inside.
Drag from action method to nib
Make an assistant pane. Arrange to see
storyboard in the other. The
declaration in
View
has a circle to its left, in the gutter. Drag from that circle across
the pane barrier to the button in the nib.
in one pane and the storyboard in the other.
Now:
Control-drag from the button in the nib editor to an empty area in the View‚
The popover view appears. This is the tricky part. By default, the popover view is
Connections | 375
}
nib. 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). For example:
You cant open nib editors on two different
.xib
files and Control-drag a connec‚
tion from one to the other.
376 | Chapter 7: Nib Management
.storyboard
By the time a nib finishes loading, its instances are fully fledged; they have been ini‚
tialized and configured with all the attributes dictated through the Attributes and Size
of Nib-Based Instances | 377
In the Project navigator, choose File Œ New Œ File. Specify iOS Œ Source Œ
Cocoa Touch Class. Click Next.
Call the new class RedButton. Make it a subclass of UIButton. Click Next.
Make sure youre saving into the project folder, with the Empty Window group,
, inside the body of the RedButton class declaration, imple‚
ment
We now have a UIButton subclass that turns itself red when its instantiated from a
378 | Chapter 7: Nib Management
Figure 7-18. Rounding a button†s corners with a runtime attribute
of Nib-Based Instances | 379
Figure 7-19. An inspectable property in the nib editor
super.init(coder:aDecoder)
// your code here
}
380 | Chapter 7: Nib Management
Knowledge is of two kinds. We know a subject ourselves,
or we know where we can
information upon it.
ƒSamuel Johnson,
Boswell†s Life of Johnson
No aspect of iOS programming is more important than a fluid and nimble relation‚
ship with the documentation. There is a huge number of built-in Cocoa classes, with
same documentation online, from Apples server, as web pages in the browser
https://developer.apple.com/documentation
Secondary documentation
Secondary documentation such as guides and sample code is available
only
Apples server, and is displayed as web pages in the browser (
https://devel
oper.apple.com/library/content/navigation/
Within the documentation window, the primary way into the documentation is to do
a search; for example, press Command-Shift-0 (or Command-L or Command-Shift-F
if youre already in the documentation window) and type
youre shown the top search results pertinent to the language of your choice (Swift,
Objective-C, or Other). Besides choosing with the mouse, you can navigate these
382 | Chapter 8: Documentation
Figure 8-1.
start of the UIButton class documentation page
Class Documentation Pages | 383
Language
What sort of
hardware
youre programming for when you use this class.
Thats important because searches are not filtered by SDK. If you were to
stumble accidentally into the NSViewController class documentation page,
you might be confused about how this class fits into the rest of iOS program‚
ming, unless you notice that iOS is not listed among this classs SDKs.
version number
in which this class became available ƒ also called
the classs
availability
. The UIGraphicsImageRenderer page, for example,
tells you that this class is available in iOS 10.0 and later. So you wont be able
to use it in code intended to run on iOS 9.
Framework
The framework that vends this class.
On
Page
The class reference page is divided into sections, and these are links to them, in
order:
Overview
If a page has an Overview section, read it! It explains what this class is for
and how to use it. It may also contain valuable links to guides that provide
related information.
Topics
384 | Chapter 8: Documentation
its superclasses, so the functionality or information youre looking for
may be in a superclass. You wont find
Page
There is no separate Overview section, but there is always an initial summary of
purpose (the same summary that appears on the class documentation page). The
Class Documentation Pages | 385
Figure 8-2. Filtering the jump bar for the UIButton topics
Return Value
386 | Chapter 8: Documentation
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
). This can help you understand compile
The Quick Help documentation contains links. For example, click the Class Reference
. The comment
becomes the Description field for Quick Help; certain list items (paragraphs begin‚
followed by space) are treated in a special way:
Paragraphs beginning with
A paragraph beginning with
A paragraph beginning with
Quick Help | 387
Figure 8-3. Custom documentation injected into Quick Help
You can also generate a documentation comment automatically. Select within the dec‚
laration line and choose Editor ΠStructure ΠAdd Documentation. The comment is
inserted before the declaration. The description, plus (if this is a function declaration)
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
If the symbol is declared in a Cocoa framework, you jump to the declaration in
file, the header file that you jump to is
translated into Swift. (Ill talk more about header files in the next section.)
The precise meaning of the notion …jump† depends upon the additional modifier keys
388 | Chapter 8: Documentation
To jump to the declaration of a symbol whose name you know, even if you dont see
Header Files | 389
A neat trick is to write an
statement just so that you can Command-
Control-click it to reach a header. For example, if you
at the top of
itself is a symbol that you can Command-Control-
click to jump to the Swift header.
Apples online documentation (
https://developer.apple.com/library/content/naviga
tion/
) includes plenty of sample code projects. You can view the code directly, but you
390 | Chapter 8: Documentation
interesting discussions take place here, and they are patrolled by some very helpful
Apple employees, but the interface remains extraordinarily clunky.
Other online resources have sprung up spontaneously as iOS programming has
become more popular, and lots of iOS and Cocoa programmers
experiences. One site that Im particularly fond of is Stack Overflow
); it isnt devoted exclusively to iOS programming, of
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 opportu‚
nity to discuss some additional features of the Xcode development environment: con‚
Universal (Targeted Device Family
The app will run natively on both kinds of device.
Base SDK
latest
system your app can run on. As of this writing, in Xcode 9.0, you have
just two choices, iOS 11.0 and Latest iOS (iOS 11.0). They sound the same, but
394 | Chapter 9: Life Cycle of a Project
Unsupported features are a different story. If the compiler knows that a feature is
unsupported by an earlier system, it will help prevent you from accidentally using
that feature on that system. For example, heres how to start drawing a small image in
iOS 10 and later:
Runtime Environment | 395
Switch the Devices pop-up menu to iPhone and check the desired Device Orien‚
tation checkboxes for the iPhone.
Switch the Devices pop-up menu to iPad and check the desired Device Orienta‚
tion checkboxes for the iPad.
Switch the Devices pop-up menu to Universal.
396 | Chapter 9: Life Cycle of a Project
once for iPad only (
Similarly, if your app loads a nib
file, the naming of that nib file works like that of an image file: if there is an alterna‚
appended, it will load automatically if we
are running on an iPad.
(My own Diabellis Theme app works in just that way. There is no main storyboard;
Chapter 7
ViewController.xib
two
View
Controller~iphone.xib
ViewController~ipad.xib
, and the runtime automatically
chooses the one that corresponds to the current device type. In this way, I end up
with one interface on iPhone and a different interface on iPad.)
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 and later, there are no iPad-only classes, and
the interface classes themselves adapt if your code is running on an iPhone. Similarly,
Version Control | 397
Collaboration
Version control affords multiple developers ready, rational access to the same
Freedom from fear
A project is a complicated thing; often, changes must be made experimentally,
398 | Chapter 9: Life Cycle of a Project
GitHub can clone directly into Xcode
When youre in the browser looking at your GitHub repository, if you click the
The Source Control menu
The Source Control submenu of the contextual menu (summoned on the listing
of files in the Project navigator)
The Source Control navigator
The Source Control inspector
The Version editor
For example, having made a change in a source file, I can commit the changes for that
file by choosing Source Control ΠCommit [Filename] in the contextual menu for
that file, or commit changes in all files by choosing Source Control ΠCommit from
the menu bar. These commands summon a comparison view of the changes; each
change can be excluded from this commit (or reverted entirely), so its possible to
group related file hunks into meaningful commits. I can also discard changes, push,
and pull using the Source Control menu.
Branches, tags, and remotes are handled in the Source Control navigator. Selecting an
item here causes relevant information to be displayed in the Source Control inspec‚
tor; for example, selecting a branch displays its corresponding remote, and selecting a
remote displays its URL. Selecting a branch also shows the log of its commits in the
editor. The list of commits is filterable through a search field at the top of the editor;
for example, you can filter by a word that appears in the commit message. Selecting a
commit in this list displays its branches, its commit message, and its involved files, in
the inspector. Double-click a commit to see its involved files and their differences
from the previous commit in a comparison view.
Other relevant commands appear in the contextual menu for items in the Source
Control navigator. For example, to add a remote, summon the contextual menu for
Version Control | 399
Figure 9-1. Version comparison
400 | Chapter 9: Life Cycle of a Project
hierarchical menu. Also, the Fonts & Colors preference pane now gives you a choice
Editing and Navigating Your Code | 401
Figure 9-2.
autocompletion menu
to a UIAlertController (
). You can navigate this menu, dismiss it, or accept
the selection, using the mouse or the keyboard alone. I like to use the keyboard. So, if
it were not already selected by default, I would navigate to
402 | Chapter 9: Life Cycle of a Project
among the choices in the pop-up menu.
Editing and Navigating Your Code | 403
Figure 9-3. A compile error with a Fix-it suggestion
&#x#cod;#00; #code#
}
If you have a class declaration in your code, you can hold Command and click
404 | Chapter 9: Life Cycle of a Project
New in Xcode 9, the intelligence of Fix-it is increased. For example, if a switch state‚
ments tag is an enum and you omit cases, Fix-it can add them. If a type adopts a pro‚
tocol and fails to implement required members, Fix-it can insert stubs for those
Live syntax checking is like a form of continual compilation. Even if you dont com‚
Project navigator
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
jump bar
Every path component of the code editors jump bar is a menu:
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
Editing and Navigating Your Code | 405
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 buttons as well as pop-up menus (or choose Navi‚
gate Π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
hierarchical menu of files related to the current file, such as superclasses and
adopted protocols. This list even includes functions that call or are called by
the currently selected function.
Your code can inject bold section titles into the jump bars bottom-level menu
using a comment whose first word is
. To make a divider line in the menu,
comment whose value is a hyphen. The two can be combined. For
example, try modifying
in our Empty Window project, and
then look in the bottom-level jump bar menu:
Similarly, comments starting with
will appear in the bottom-
level menu.
assistant pane
Navigate ΠJump to Definition (Command-Control-J, Command-Control-click)
406 | Chapter 9: Life Cycle of a Project
Figure 9-4. A call hierarchy in the Find navigator
Breakpoints
The Breakpoint navigator lists all breakpoints in your code. Xcode lacks code
bookmarks, but you can misuse a disabled breakpoint as a bookmark. Break‚
points are discussed later in this chapter.
Finding is a form of navigation.
Command-Shift-F), using the Find navigator, and an editor-level find (Find ΠFind,
Youll want to configure your search with find options:
Editor-level
options
Buttons at the right end of the search field toggle case sensitive search and regu‚
Global
options
The options appear above and below the search field. Above the search field, you
Editing and Navigating Your Code | 407
Editor level
and replace
Click the magnifying glass icon and choose Replace to toggle the visibility of the
Replace field. You can perform a Find and then click Replace to replace that
Global
and replace
Click 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 Find navigator and replace only those
delete
find results from the Find navigator, to protect
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;
just to survey how the name is used.
Refactoring is an intelligent form of code reorganization. Originally added to Xcode
in the days when Objective-C held sway, refactoring has hitherto been unavailable to
Swift programmers. New in Xcode 9, refactoring for Swift code has begun to appear.
To use it, select a term in your code and choose from the Editor Œ Refactor hierarchi‚
cal menu. As of this writing, only a few refactoring commands are operative; for
example:
Rename
Like Edit All In Scope (mentioned at the end of the previous section), but its
408 | Chapter 9: Life Cycle of a Project
More refactoring commands may be expected to start working as Xcode evolves
further.
When you build and run with the Simulator as the destination, you run in the Simu‚
lator application. A Simulator window represents a device. Depending on your app
Running in the Simulator | 409
, for which values (the format arguments) will be sub‚
stituted 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 (
character(s) following the percent sign specify the type of value that will be supplied
410 | Chapter 9: Life Cycle of a Project
at runtime. The most common format specifiers are
int),
(a double). For example:
In that example,
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:
the view: UIView: 0x7c233b90; frame = (0 0; 320 480); autoresize = RM+BM;ÊLa;&#xyer:;&#x 0x7;숳퀀ÊLa;&#xyer:;&#x 0x7;숳퀀 layer = CALayer: 0x7c233d00I like NSLogs output because it provides the current time and date, along with the
Debugging | 411
Swift defines four special literals, particularly useful when logging because they
Another useful form of caveman debugging is deliberately aborting your app because
412 | Chapter 9: Life Cycle of a Project
Figure 9-5. A breakpoint
Figure 9-6. A disabled breakpoint
leave in place a breakpoint that you might need later without pausing at it every
time its encountered.
To create a breakpoint (
select in the editor the line where you want to
pause, and choose Debug ΠBreakpoints ΠAdd/Remove Breakpoint at Current Line
Debugging | 413
Figure 9-7. A
breakpoint
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:
call, which must be compiled into your code
error breakpoint
Similar to an exception breakpoint, but it pauses when your code says
Symbolic breakpoint
A symbolic breakpoint
414 | Chapter 9: Life Cycle of a Project
Figure 9-8. Paused at a breakpoint
Using Objective-C method notation
Debugging | 415
Figure 9-9. A data tip
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
information, by opening triangles. (Local variable values are shown even if, at the
416 | Chapter 9: Life Cycle of a Project
Inspect your view hierarchy
You can study the view hierarchy while paused in the debugger. Click the Debug
View Hierarchy button in the bar at the top of the Debug pane, 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 the Size inspector dis‚
play information about the currently selected view.
Inspect your object graph
You can study your object graph (what objects youve created and how they are
referring to one another) while paused in the debugger. Ill talk more about that
later in this chapter.
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
Talk to the debugger
You can communicate directly with the debugger through the console. Xcodes
debugger 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. Common commands are:
(short for
Alone, prints out all variables locally in scope, similar to the display in the
variables list. Alternatively, can be followed by the name of a variable you
want to examine.
(short for
Followed by a type name, dumps a full declaration for the type, listing all its
Debugging | 417
paused here. Indeed, this is one of the main advantages of breakpoints over cave‚
man debugging. To change your caveman debugging, you have to stop the app,
edit it, rebuild it, and start running the app all over again. But to fiddle with
breakpoints, you dont have to be stopped; you dont even have to be paused! An
operation that went wrong, if it doesnt crash your app, can probably be repeated
in real time; so you can just add a breakpoint and try again. For example, if tap‚
ping a button produces the wrong results, you can add a breakpoint to the action
418 | Chapter 9: Life Cycle of a Project
test
Testing | 419
…Assertions Listed by Category.† Unlike the corresponding Objective-C macros, the
not
take format strings (the way
a 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.
420 | Chapter 9: Life Cycle of a Project
EmptyWindowTests
In the Project navigator, a new group has been created, EmptyWindowTests, contain‚
. It contains a test class EmptyWin‚
At the top of
, where we are importing XCTest, we must
Prepare an instance property in the declaration of the EmptyWindowTests class
to store our ViewController instance:
itself, theres a diamond-shaped indicator in the gutter to
Testing | 421
Figure 9-10.
Report navigator reports a test failure
next to the declaration of
best place to survey what went wrong is the Report navigator. The Tests pane displays
, modify
422 | Chapter 9: Life Cycle of a Project
existing
ViewController instance? This is the same general problem of
testExample

Choose Editor Œ Start Recording UI Test. (Alternatively, theres a Record button
at the bottom of the project window, in the debug bar.) The app launches in the
Simulator.
Tap the button in the interface. When the alert appears, tap OK to dismiss it.
Testing | 423
Now run the test by clicking in the diamond in the gutter at the left of the
declaration. The app launches in the Simulator, and a ghost finger performs
the same actions we performed, tapping first the button in the interface and then,
when the alert appears, the OK button that dismisses it. The test ends and the app
stops running in the simulator. The test passes!
The important thing, however, is that if the interface stops looking and behaving as it
does now, the test will
not
pass. For example, in
Main.storyboard
and, under Control in the Attributes inspector, uncheck Enabled. The button is still
there, but it cant be tapped; weve broken the interface. Run the test. The test fails,
and the Report navigator explains why: when we came to the Tap the …OK† Button
step, we first had to perform Find the …OK† Button, and we failed because there was
no alert. Ingeniously, the report also incorporates screen shots so that we can inspect
the state of the interface during the test. Under Tap …OK† Button, double-click Auto‚
matic Screenshot; youre shown the screen at that moment, displaying clearly the dis‚
abled interface button (and no alert).
Fix the bug by enabling the button once again. If you now choose Product ΠTest, all
tests in all test suites are run, both the unit tests and the interface tests, and they all
pass. Our app may be trivially simple, but its definitely working!
New in Xcode 9, XCUIElement has a
424 | Chapter 9: Life Cycle of a Project
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
including a certain resource in your app, and you decide it is no longer needed. You
whole), but that doesnt necessarily remove it from your built app. This sort of left‚
over 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
I think of cleaning as having several levels or degrees:
Shallow clean
Choose Product Œ Clean, which removes the built app and some of the inter‚
mediate information in the build folder.
Deeper clean
Hold Option and choose Product ΠClean Build Folder, which removes the
entire build folder.
Insanely clean
~/Library/Developer/Xcode/DerivedData
Running on a Device | 425
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
To obtain a Developer Program membership, go to the Apple Developer Program
https://developer.apple.com/programs/
) and initiate the enrollment process.
When youre starting out, the Individual program is sufficient. The Organization pro‚
ious roles. (You do
not
need the Organization program merely in order to distribute
your built app to other users for testing.)
Your 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
426 | Chapter 9: Life Cycle of a Project
Running an app on a device is a remarkably complicated business. 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
An identity
An identity represents Apples permission for a given team to develop,
on this
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 identi‚
fies a computer where this team can
potentially
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
A provisioning profile is a virtual permission slip from Apple, uniting four
identity
app
, identified by its bundle identifier.
devices
, identified by their unique device identifiers
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
There are two types of identity, and hence two types of certificate, and hence two
development
and
distribution
(a distribution certificate is
production
certificate). We are concerned here with the development
identity, certificate, and profile; Ill talk about the distribution side later.
The only thing that belongs entirely to you is the private key in your computers key‚
chain. Apple is the ultimate keeper of all other information: your certificates, your
Running on a Device | 427
provisioning profiles, what apps and what devices youve registered. Your communi‚
cation with Apple, when you need to verify or obtain a copy of this information, will
developer member center
access 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
Just about everything you would need to do at the developer 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 developer member center to iron it out.
Apple provides two distinct ways of obtaining and managing certificates and profiles
428 | Chapter 9: Life Cycle of a Project
Figure 9-11. Xcode knows of no devices
Figure 9-12. Xcode
to register a device
Figure 9-13. Xcode has registered a device for us
window toolbar. This causes the error in
button now appears (
The problem is resolved; the error vanishes. You can switch to the Report navigator
to learn what just happened (
As the Report navigator tells us, the device has been registered ƒ and a development
provisioning profile has been created (and has been stored in your
~/Library/Mobile
Device/Provisioning
folder). This is a universal iOS Team Provisioning Profile
ƒ and that is all you need in order to run any basic app on any device!
shows the resulting display in the Signing section of the General pane when you edit
Running on a Device | 429
Figure 9-14. Xcode manages signing credentials automatically
Figure 9-15. Xcode prepares for debugging on a device
The good news is that once you
already
have a development certificate, and once
already
generated and downloaded a universal iOS Team Provisioning
already
registered with Apple and prepared by Xcode
none
of that will be necessary ever again. When you create a new
project, you supply your team name. Xcode thus knows everything it needs to know!
The development certificate is valid for this computer, the universal iOS Team Provi‚
sioning Profile is universal, and the device is registered with Apple and prepared for
debugging. Therefore, you should from now on be able to create a project and run it
immediately
If you decide for any reason that you dont want a projects signing to be managed
automatically by Xcode, simply uncheck the …Automatically manage signing† check‚
a development certificate manually. How would you do it?
The full procedure, which is somewhat elaborate, is as follows:
You launch Keychain Access and choose Keychain Access ΠCertificate Assistant
ΠRequest a Certificate from a Certificate Authority. Using your name and email
430 | Chapter 9: Life Cycle of a Project
Figure 9-16. A valid development
address as identifiers, you generate and save to disk a 2048-bit RSA certificate
request file. Your private key is stored in your keychain then and there; the certif‚
icate request containing your public key has been saved temporarily onto your
computer. (For example, you might save it to the desktop.)
In your browser, at the developer member center, you go to the Certificates page
and click the Plus button at the top right. You specify that you want an iOS App
Development certificate. You are taken to an interface allowing you to upload the
saved certificate request file. You upload it, and the certificate is generated; you
click its listing at the developer member center to expose the Download button,
You locate and double-click the file you just downloaded; Keychain Access auto‚
matically imports the certificate and stores it in your keychain, where Xcode is
You do not need to keep the certificate request file or the downloaded certificate file;
your keychain contains all the needed credentials. If this has worked, you can see the
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 keychain; if not, you can
obtain a copy of it manually by clicking a link at the bottom of the page at the devel‚
oper member center where you begin the process of adding a certificate.
A provisioning profile, as Ive already mentioned, unites an identity, a device, and an
app bundle identifier. If things have gone well, you should by now have obtained a
Running on a Device | 431
Figure 9-17. A universal development
development provisioning profile
automatically from within Xcode, because you have
…Automatically manage signing† checked in the Signing section of the General pane
device
must be registered at the developer member center. Look under
Devices to see if it is. If it isnt, 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 and Simulators window. Alternatively, you can submit a tab-
Next, the
app
must be registered at the developer member center. Look under
Identifiers Œ App IDs to see if it is. If it isnt, add it, as follows: Click Plus. Enter a
name for this app. Enter the bundle identifier under Explicit App ID exactly as
shown in Xcode, in the Bundle Identifier field under General when you edit the
432 | Chapter 9: Life Cycle of a Project
Figure 9-18. Manual code signing
(If your app uses special entitlements, this step is also where youd associate those
entitlements manually with the app.)
Under Provisioning Profiles, click Plus. Ask for an iOS App Development profile.
On the next screen, choose the App ID. (Youll see an option to create a …wild‚
card† development profile; this is a universal development profile, but its a
man
ually generated
universal development profile. Do
not
choose that! Create a
In Xcode, use the Provisioning Profile pop-up menu to download your profile
from the developer member center.
The result, for an actual app of mine for which Ive elected to use manual signing, is
If youre using manual signing, no automatic actions will be performed; Xcode will
keep its hands off, and you will need do everything through the developer member
center. If you have a profile for your app already, and if you switch on some entitle‚
Running on a Device | 433
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), you can 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 neces‚
sary, 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, profile your app with Instruments,
and so on. The outward difference is that to interact physically with the app, you use
the device, not the Simulator.
New in Xcode 9 and iOS 11, you can configure your device to allow Xcode to build
and run apps on it wirelessly. To do so, start with the device connected via USB; locate
Starting in Xcode 8, youre allowed to have more than one development certificate.
Thus, management of development certificates may not be necessary. All you have to
do, in order to run on a device on another computer, is what you did on the first
computer. If youre using automatic signing, a new certificate will be generated for
you ƒ one that doesnt conflict with the old certificate.
When a device is attached to the computer, it appears in Xcodes Devices and Simula‚
tors window. If this device has never been prepared for development, you can ask
Xcode to prepare it for development. You can then build and run onto the device. If
434 | Chapter 9: Life Cycle of a Project
devices console log in real time. (The interface for this is a little obscure: click the tiny
up-arrow at the bottom left of the Devices pane.) Using the Gear 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.
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
navigator allow you to monitor key indicators, such as CPU and memory usage, any
time you run your app. Memory debugging gives you a graphical view of your apps
objects and their ownership chains, and can even reveal memory leaks. And Instru‚
ments, 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.
The gauges in the Debug navigator are operating whenever you build and run your
| 435
Figure 9-19.
Debug navigation gauges
436 | Chapter 9: Life Cycle of a Project
Figure 9-20. A memory graph
Figure 9-21.
memory graph displays a leak
into being. Hover over a line of the backtrace and click the right-arrow button to
jump to that line of your code.
| 437
Figure 9-22. Instruments graphs memory usage over time
see some validation warnings, but you can safely ignore them. Instruments launches;
438 | Chapter 9: Life Cycle of a Project
Figure 9-23. Instruments describes a retain cycle
| 439
Figure 9-24. Drilling down into the time
Figure 9-25. My code,
440 | Chapter 9: Life Cycle of a Project
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:
To localize your
Info.plist
InfoPlist.strings
To localize your
Main.storyboard
Main.strings
To localize your code strings, use
Localizable.strings
You dont have to create or maintain these files manually. Instead, you can work with
format. Xcode will generate
files auto‚
matically, based on the structure and content of your project; it will also read them
and will turn them automatically into the various localized
.strings
To experiment with localization, our app needs some localizable content:
Main.storyboard
and confirm that it contains a button whose title is …Hello.†
That title will be localized. (It will help the example if you also widen the button
to about 100 points.)
. The code here contains some literal strings, such as
Localization | 441
Edit the project. Under Localizations, click the Plus button. In the pop-up menu
that appears, choose French. In the dialog, click Finish.
Still editing the project, choose Editor ΠExport For Localization. In the dialog
that appears, include Existing Translations and check French (the default). Youre
is generated. Examining this file, youll
observe that our apps localizable strings have all been discovered:
For our
Info.plist
file in the project, Xcode has created a corresponding
element. When imported, this element will be turned into a localized
Info
Plist.strings
For every
.storyboard
.xib
has created a corresponding
element. When imported, these elements will
be turned into eponymous localized
.strings
For our code files containing a call to
to parse the file, and has created a corresponding
element.
When imported, this element will be turned into a localized
Localizable.strings
442 | Chapter 9: Life Cycle of a Project
&#xsour;츀&#x/sou;&#xrce0; sourceHello/source
Choose Editor ΠImport Localizations; in the dialog, locate and open the edited
Xcode processes the file and creates the corresponding files in the project. In particu‚
lar, there is now a
fr.lproj
folder containing
.strings
files in the correct format, which is
.strings
fr.lproj
InfoPlist.strings
Info.plist
file. It reads like this:
Localization | 443
"CFBundleDisplayName" = "Fenƒtre Vide";
/* (No Comment) */
"CFBundleName" = "$(PRODUCT_NAME)";
Main.strings
Main.storyboard
. It will be similar to this:
Localizable.strings
file, localizing the strings in our code. It looks like this:
Tap the app in the Springboard to run it. The button in the interface has the title
Bonjour.
Tap the button. The alert contains …Bonjour,† …Vous mavez tap!†, and …OK.†
Our app is localized for French! Of course, our app is also very small and simple. Its
wise to wait until quite late in the development process before starting on localiza‚
tion. Nevertheless, if our app is subsequently modified, we can again export the local‚
ization as an
file, edit the file as needed, and reimport it to incorporate any
444 | Chapter 9: Life Cycle of a Project
In real life, preparing your nib files to deal with localization will take some additional
work. In particular, youll want to use autolayout, configuring your interface so that
interface objects containing text have room to grow and shrink to compensate for the
change in the length of their text in different languages. New in Xcode 9, if your
storyboard is localized, the nib editor will treat objects like fixed-width autolayout
buttons as errors, because they cannot change size when the text changes.
To test your interface under different localizations, you can also
preview
ized nib files within Xcode, without running the app. Edit a
.storyboard
.xib
and open an assistant pane, and switch the Tracking menu to Preview. A menu at the
Distribution | 445
ute that archive to yourself and run it, knowing that you are testing exactly the
same app.
Symbolication
.dSYM
report the crashs location in your code. This allows you to deal with crash
Heres how to build an archive of your app:
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-
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).
Youve just signed your archive with a development profile; thats good, because it
means you can run the archived build directly on your device. A development profile
cant be used to make an Ad Hoc or App Store build of your app, but when you export
the archive to form an Ad Hoc or App Store build, Xcode will
substitute
the appropri‚
ate distribution profile for the development profile that you used for archiving.
If youre using automatic signing, and if you have no distribution certificate, then
when you first export the archive to the App Store (as Ill describe later in this chap‚
ter), Xcode will offer to obtain a distribution certificate for you, along with a distribu‚
Otherwise, you can request a distribution certificate through Xcodes Accounts pref‚
erence pane: select your Apple ID, choose your team, click Manage Certificates, click
the Plus button at the bottom left, and ask for an iOS Distribution certificate. Alter‚
natively, you can obtain the distribution certificate by working through your keychain
and the developer member center, just as I described earlier for a development certifi‚
cate.
446 | Chapter 9: Life Cycle of a Project
Figure 9-26. Xcode reports a missing distribution
Once youve obtained a distribution certificate, youll see it in your keychain. It will
, except that it will say …iPhone Distribution† instead of
…iPhone Development.†
If you already have a distribution certificate, there is a pitfall to watch out for: Xcode
will happily permit you to make a new distribution certificate, but this will
not
be the
same distribution certificate you already have, and thus will not work with any distri‚
bution profiles you already have.
A case in point is when you change computers. Your distribution certificate is back in
the keychain of your old computer. On your new computer, Xcode reports the exis‚
tence of the distribution certificate (in the Accounts preference pane, under Manage
Certificates), but tells you that it
isn†t
this
computer (
You can ask for a new distribution certificate at this point, but you probably
shouldnt. What you need is the
existing
distribution certificate.
If youre using automatic signing for this project, Xcode will probably be able to cre‚
ate an appropriate distribution profile for you automatically when you export your
Otherwise, youre going to have to create your profile manually, at the developer
member center. Alternatively, if you
are
using automatic signing, but when you try to
Distribution | 447
export your archive (as described in the next section) theres an error and the export
fails, youll have to
stop
using automatic signing and create your profile manually
Heres how to obtain a distribution profile manually:
If this is to be an Ad Hoc distribution profile, collect the UDIDs of all the devices
where this build is to run, and make sure youve added each of them at the devel‚
oper member center under Devices. (For an App Store distribution profile, omit
this step.)
Make sure that the app is registered at the developer member center, as I
described earlier in this chapter.
At the developer member center, under Provisioning Profiles, click the Plus but‚
ton to ask for a new profile. In the Add iOS Provisioning Profile form, specify an
Ad Hoc profile 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 might need to be able to recognize it
later from within Xcode! My own practice is to assign a name containing the
term …AdHoc† or …AppStore† and the name of the app.
Click Generate to generate the profile. You should subsequently be able to down‚
load the profile from within Xcode (and if not, you can click Download at the
developer member center).
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 unneces‚
sary. If you want to include this icon, it should be a PNG or JPEG file, 512Ž512 pixels
iTunesArtwork
no
extension
. Make sure the
icon is included in the build, being present in the Copy Bundle Resources build
phase. (After adding this icon, youll need to make a new archive of your app.)
Here are the steps for creating an Ad Hoc distribution file from an archive:
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 spec‚
In the next screen, you may be offered various options. For example:
448 | Chapter 9: Life Cycle of a Project
Thinning means that multiple copies of the app can be created, each contain‚
ing resources appropriate only to one type of device, simulating what the
App Store will do when the user downloads the app to a device. There would
normally be no need for this, though it might be interesting to learn the size
of your thinned app.
Rebuild from Bitcode
Bitcode allows the App Store to regenerate your app to incorporate future
optimizations. If youre going to be using bitcode when you upload to the
App Store, you might like to use it when you perform your Ad Hoc build.
Personally, I avoid bitcode, so I would uncheck this checkbox.
Strip
symbols
Check this box to reduce the build size somewhat.
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.
You are shown a dialog for saving a folder. The file will be inside that folder, with
.ipa
(…iPhone app†), accompanied by
.plist
Locate in the Finder the
.ipa
file you just saved. Provide this file to your users
.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
.ipa
puter, 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
Distribution | 449
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 and Simulators win‚
dow 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 distri‚
bution 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 coun‚
450 | Chapter 9: Life Cycle of a Project
Figure 9-27. Icon slots in the asset catalog
should be double or triple the listed dimensions for an icon; thus, for example, an
iPhone app icon listed as …60pt† or …60Ž60,† but also with …3x,† means that you should
Distribution | 451
Figure 9-28. Marketing icon slot in the asset catalog
When you submit an app to the App Store, you will need to supply a 1024Ž1024 PNG
or high-quality JPEG icon to be displayed at the App Store (the
marketing icon
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
ƒ a single
.xib
or
.storyboard
file containing a single
view to be displayed as a launch image. You construct this view using subviews and
452 | Chapter 9: Life Cycle of a Project
autolayout. Thus, the view is automatically reconfigured to match the screen size and
orientation of the device on which the app is launching, and label and button text can
By default, a new app project comes with a
LaunchScreen.storyboard
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 (
). You can
Info.plist
the computer:
Simulator
Run the app in the Simulator with the desired device type as your destination.
Choose File ΠNew Screen Shot. Hold the Option key if you want to specify the
screen shots name and location.
Device
In Xcode, in the Devices and Simulators window, locate your connected device
under Devices and click Take Screenshot. Alternatively, choose Debug ΠView
Debugging ΠTake Screenshot of [Device].
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
Distribution | 453
app, and you can communicate it to your computer in any convenient way (such as
by emailing it to yourself).
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 macOS 10.10 (…Yosemite†) or later. Your
device must be sufficiently modern to have a Lightning connector:
Connect the device to the computer and launch QuickTime Player. Choose File
ΠNew Movie Recording.
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:
After importing the movie file, choose File ΠNew App Preview.
Edit! When youre done editing, choose File Œ Share Œ App Preview. This
ensures the correct resolution and format.
454 | Chapter 9: Life Cycle of a Project
the order of possible orientations, because on an iPhone the
orien‚
tation listed may be the one into which the app will actually launch.
Required device capabilities (
Distribution | 455
oper Guide
, which is the final word on such matters. But here are some of the main
pieces of information you will sooner or later have to supply (and see also
https://
developer.apple.com/app-store/product-page/
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
456 | Chapter 9: Life Cycle of a Project
Price
youll see the bitcode checkbox; and theres a checkbox for uploading symbols, which
After some time, a screen is displayed summarizing the
.ipa
content, and you can
now click Export to save to disk or Upload to proceed to upload to iTunes Connect. If
you clicked Upload, the upload will be performed, and the app will be validated at the
Alternatively, you can use Application Loader. Export the archive as an
.ipa
file, as for
Distribution | 457
The Cocoa Touch frameworks provide the general capabilities needed by any iOS
application. Buttons can be tapped, text can be read, screens of interface can succeed
Chapter 10
Objective-C language features as subclassing, categories, and protocols. Then
some important built-in Cocoa object types are introduced. The chapter con‚
cludes with a description of Cocoa key„value coding and a look at how the root
Chapter 11
presents Cocoas event-driven model of activity, along with its major
design patterns and event-related features ƒ notifications, delegation, data sour‚
Chapter 12
is about Cocoa memory management. Ill explain how memory man‚
agement of reference types works. Then some special memory management sit‚
property memory management, and advice on how to debug memory manage‚
ment issues.
Chapter 13
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
When you program iOS, youre programming Cocoa. The Cocoa API is written
derived from the root class, NSObject. When programming iOS, youll be making
heavy use of the built-in Cocoa classes.
This chapter introduces Cocoas class structure and explains how youll interact with
it as an iOS programmer. 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.
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 edita‚
ble text, how to summon the keyboard, and how to accept keyboard input.
Often, the default behavior or appearance of an object supplied by Cocoa wont be
quite what youre after, and youll want to customize it. This does
not
In addition, many built-in classes use
delegation
Chapter 11
) as the preferred way of
462 | Chapter 10: Cocoa Classes
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
. Make sure its part of
, replace the contents of the class declaration with this
(without further explanation):
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
With the UIView that you just dragged into the canvas still selected, use the Iden‚
tity 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
; the default implementation of
UIViews
does nothing. But you might also be able to subclass a built-in
UIView subclass to modify the way it already draws itself. For example, the UILabel
Subclassing | 463
In the Empty Window project, make a new class file, a UILabel subclass; call the
class MyBoundedLabel.
, insert this code into the body of the class declaration:
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
464 | Chapter 10: Cocoa Classes
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
For the sake of object-oriented encapsulation, you will often want to write a function
Categories and Extensions | 465
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 cate‚
gories; often, these will even appear in separate header files.
A good example is NSString. NSString is defined as part of the Foundation frame‚
A string may serve as a file pathname, so we also find a category on NSString in
NSPathUtilities.h
NSURL.h
, which is primarily devoted to declaring the NSURL class (and
its
466 | Chapter 10: Cocoa Classes
Protocols | 467
Thats translated into Swift as follows:
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 UITable‚
ViewDataSource protocol.† Such conformance constitutes a promise that the data
468 | Chapter 10: Cocoa Classes
(Ill explain the
Chapter 12
type is
a protocol. This is how the shared UIApplication object knows that its delegate might
be capable of receiving messages such as
. So the AppDelegate class officially announces its role by explicitly adopt‚
ing the UIApplicationDelegate protocol.
Protocols | 469
conforms; instead, messages listed in the protocol are sent only to objects typed as
(AnyObject), thus suppressing any possible objections from the compiler (see
…Sup‚
pressing type checking† on page 219
470 | Chapter 10: Cocoa Classes
Note the cast of
to AnyObject. This causes Swift to abandon its strict type checking
…Suppressing type checking†
); we can now send this object any mes‚
sage that Swift knows about, provided it is susceptible to Objective-C introspection
ƒ thats why I marked my protocol declaration as
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. I could have written this:
Protocols | 471
application:didChangeStatusBarOrientation:
application:willChangeStatusBarFrame:
application:didChangeStatusBarFrame:
application:deviceAccelerated:
application:deviceChangedOrientation:
applicationDidBecomeActive:
applicationWillResignActive:
applicationDidEnterBackground:
applicationWillEnterForeground:
applicationWillSuspend:
application:didResumeWithOptions:
application:shouldSaveApplicationState:
application:supportedInterfaceOrientationsForWindow:
472 | Chapter 10: Cocoa Classes
a String or an Array. Moreover, when you use String or Array in the presence of
Some Foundation Classes | 473
Unfortunately, theres a common situation where a Swift Ranges endpoints are
not
Ints ƒ they are
, because youre working with a Swift String. Mean‚
while, on the Cocoa side, an NSString still uses an NSRange whose components are
integers. Not only is there a type mismatch, theres also a value mismatch, because (as
Chapter 3
graphemes, but an NSString is indexed on its Unicode codepoints.
474 | Chapter 10: Cocoa Classes
Why does Cocoa resort to an integer value with a special meaning in this way?
Because it has to. The result could not be
to indicate the absence of the object,
because
would indicate the first element of the array. Nor could it be
, because an
NSArray index value is always positive. Nor could it be
, because Objective-C cant
Some Foundation Classes | 475
Similarly, to use NSStrings
, you must cast the String to an NSString
but you cant change the string
in place
. To do that, you need another class, a subclass
of NSString, NSMutableString. Swift String isnt bridged to NSMutableString, so you
String, youll have to make one. The simplest way is with NSMutableStrings initial‚
, 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 to
a Swift String in one move, because an NSMutableString is an NSString:
476 | Chapter 10: Cocoa Classes
range

Perhaps you dont know exactly what youre looking for: you need to describe it
By specifying the
regular expression. Regular expressions are also supported as a separate class,
, which in turn uses NSTextCheckingResult to describe
match results.
More sophisticated automated textual analysis is supported by some additional
Some Foundation Classes | 477
single
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 attributed string.
478 | Chapter 10: Cocoa Classes
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 for‚
mat may surprise you. For example, if you simply
a Date, you are shown the
date in the GMT timezone, which can be confusing if that isnt where you live. A sim‚
On my device, the result might be …July 31, 2017, 8:23 PM PDT.†
If I change my devices
region
to France, it might be …31 July 2017 8:23 PM
GMT-7.†
If I also change my devices
language
Some Foundation Classes | 479
480 | Chapter 10: Cocoa Classes
Some Foundation Classes | 481
as it crosses the bridge from Swift to Objective-C. Heres an example from my own
482 | Chapter 10: Cocoa Classes
transform the UIColor into a Data object (using NSKeyedArchiver) and save
that:
Some Foundation Classes | 483
and French, the very same code outputs
point notation and the French preferred unit of distance measurement.
In Swift, the equality and comparison operators can be overridden for an object type
that adopts Equatable and Comparable (
…Operators†
operators cant do that; they are applicable only to scalars. Objective-C therefore per‚
forms comparison of object instances in a special way, and it can be useful to know
That code seems to do three impossible things before breakfast:
We treat an array of NSNumber objects as an array of Equatables and call the
The Ints are being wrapped in NSNumber objects for us.
operator (also used behind the scenes by the
NSNumber implements
to compare two NSNumber objects by
comparing the numeric values that they wrap.
Therefore the equality comparisons all work correctly.
484 | Chapter 10: Cocoa Classes
doesn†t
implement
, it inherits NSObjects imple‚
mentation, which compares the two objects for identity (like Swifts
operator).
For example, 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 implement
defaults to NSObjects identity compari‚
Some Foundation Classes | 485
and class instances), and they dont have to be of a single type. For a full discussion of
. The index of the first element, as with a Swift Array, is zero, so
the index of the last element is
minus one.
, you can use subscripting with an NSArray. This is not
because NSArray is bridged to Swift Array, but because NSArray implements an
486 | Chapter 10: Cocoa Classes
Some Foundation Classes | 487
488 | Chapter 10: Cocoa Classes
Some Foundation Classes | 489
You can test an object for equality against
using the ordinary equality oper‚
ator (
), because it falls back on NSObjects
, which is identity compari‚
490 | Chapter 10: Cocoa Classes
These immutable/mutable class pairs are all implemented as
class clusters
Some Foundation Classes | 491
When you reconstruct an NSArray or NSDictionary object from a property list file in
this way, the collections, string objects, and data objects in the collection are all
immutable. If you want them to be mutable, or if you want to convert an instance of
one of the other property list classes to a property list, youll use the PropertyListSeri‚
alization class (Objective-C NSPropertyListSerialization; see the
Property List Pro
gramming Guide
New in Swift 4, you can serialize Swift types (enums, structs, classes not derived
from NSObject) to a property list, using the Codable protocol. Ill talk about that
New in Swift 4, you can serialize an object without crossing the bridge into the
Objective-C world, provided it adopts the Codable protocol. In effect, every native
Swift type and every Foundation overlay type
does
means, among other things, that enums and structs can easily be serialized, some‚
thing that was previously quite tricky.
There are three main use cases, involving three pairs of classes to serialize the object
and extract it again later:
Property lists
Use PropertyListEncoder and PropertyListDecoder.
JSON
Use JSONEncoder and JSONDecoder.
NSCoder
Use NSKeyedArchiver and NSKeyedUnarchiver.
In every case, what youre encoding to and decoding from is a Data object.
492 | Chapter 10: Cocoa Classes
&#xstri;&#xng00;&#x/str;&#xing0;stringManny/string
&#xstri;&#xng00;&#x/str;&#xing0;stringMoe/string
&#xstri;&#xng00;&#x/str;&#xing0;stringJack/string
That example doesnt do anything that we couldnt have done with NSArray. But now
Some Foundation Classes | 493
the types properties are themselves Codable, the right thing will happen automati‚
494 | Chapter 10: Cocoa Classes
The outcome is not substantially different from calling NSKeyedArchivers
, because the Data object generated by
Accessors, Properties, and Key‚Value Coding | 495
implement
accessor methods
getter method
setter method
sees it as a
property
. Thus, UIViews
property declaration is translated directly into a Swift
declaration of an instance property
An Objective-C property declaration can include the word
in the parenthe‚
496 | Chapter 10: Cocoa Classes
Accessors, Properties, and Key‚Value Coding | 497
498 | Chapter 10: Cocoa Classes
The value in key„value coding must be an Objective-C object, and is typed in Swift as
Any. When calling
, youll receive an Optional wrapping an Any;
youll want to cast this down safely to its expected type.
keyˆvalue coding compliant
(or
KVC compliant
Accessors, Properties, and Key‚Value Coding | 499
if the compiler cant confirm that the key in question is legal. For example, earlier we
crashed by saying this:
500 | Chapter 10: Cocoa Classes
to an NSArray, it sends
NSDictionary implements
as an alternative to
(useful particularly if you have an NSArray of dictionaries). Similarly,
NSMutableDictionary treats
NSSortDescriptor sorts an NSArray by sending
elements. This makes it easy to sort an array of dictionaries on the value of a par‚
ticular dictionary key, or an array of objects on the value of a particular property.
NSManagedObject, used in conjunction with Core Data, is guaranteed to be key„
value coding compliant for attributes youve configured in the entity model.
Thus, its common to access those attributes with
CALayer and CAAnimation permit you to use key„value coding to define and
Accessors, Properties, and Key‚Value Coding | 501
502 | Chapter 10: Cocoa Classes
The result is an array consisting of the strings
dont see why, review what I said earlier about how NSArray and NSDictionary
implement
syntax can chain property names with dot-notation, similar to a
Cocoa key path. In that example, however, we could not have achieved the same
syntax. The expression
is structurally legal, but it wont compile. The Swift compiler knows that
a MyClass has a property
thats an array of dictionaries, but it does not know
that every dictionary has a
key. Thus, you are compelled to pass a string as
your key path, and hope that the string is correct. If, on the other hand,
were
typed as an array of Dog, that expression would be legal, because Dog has a
property.
Cocoa key„value coding is a powerful technology with many additional ramifica‚
tions. (See Apples
Key-Value Coding Programming Guide
for full information.) Ill
illustrate just one of them. Key„value coding allows an object to synthesize a key
Accessors, Properties, and Key‚Value Coding | 503
any instance method of NSObject
can be called on a class object as a class method!
For example,
504 | Chapter 10: Cocoa Classes
Class relationships
Cocoa Events
Broadly speaking, the reasons you might receive an event may be divided informally
into four categories. These categories are not official; I made them up. Often it isnt
508 | Chapter 11: Cocoa Events
view is drawn, without taking command of the entire drawing procedure yourself. In
Chapter 10
I gave an example involving UILabel and its
), so that you can perform initializations; its an obvi‚
Subclassing | 509
class for this purpose. The majority of your communication from Cocoa will be
Cocoa provides your app with a single NotificationCenter instance (Objective-C
NSNotificationCenter), available as
center
tions
. A notification is a Notification
instance (Objective-C NSNotification). The idea
is that any object can be registered with the notification center to receive certain noti‚
fications. Another object can hand the notification center a notification to send out;
posting
the notification. The notification center will then send that notifi‚
cation to all objects that are registered to receive it.
Cocoa itself posts notifications through the notification center, and your code can
register to receive them. Thus, notifications are a way of receiving events from Cocoa.
Youll find a separate Notifications section in the documentation for a class that pro‚
You may also want to post notifications yourself, as a way of communicating with
your own code. The notification mechanism is often described as a dispatching or
510 | Chapter 11: Cocoa Events
An Optional dictionary; if not
, it contains additional information associated
with the notification. What information it will contain, and under what keys,
depends on the particular notification; you have to consult the documentation.
For example, the documentation tells us that UIApplications
notification includes a
dictionary with a
whose value is the status
bars previous orientation. When you post a
notification
anything you like into the
To register to receive a notification, you send one of two messages to the notification
center. One is
| 511
tions in the MPMusicPlayerController class documentation as
It turns out, looking at the documentation, that this notification wont be posted
at all unless I first call MPMusicPlayerControllers
512 | Chapter 11: Cocoa Events
the Notification itself. You can use an anonymous function so that your response to
the notification becomes part of the registration:
| 513
You called
returned
an observer token object typed as an NSObjectProtocol (its real
class and nature are undocumented); that is the observer you will now unregister.
In order to unregister an object, then, you need a reference to that object. That means
cannot
Although youll be interested mostly in receiving notifications from Cocoa, you can,
as I mentioned earlier, take advantage of the notification mechanism as a way of com‚
514 | Chapter 11: Cocoa Events
bly avoid using notifications merely to compensate for a failure to devise proper lines
) after the lapse of a certain
time interval. The signal is a message to one of your instances. Thus you can arrange
| 515
to be notified when a certain time has elapsed. The timing is not perfectly accurate,
516 | Chapter 11: Cocoa Events
Timers have some memory management implications that Ill discuss in
Chap‚
Delegation
Delegation | 517
only in portrait orientation when this view controller is in charge. But UINavigation‚
Controller isnt my class; it belongs to Cocoa. My own class is a
view control‚
ler, a UIViewController subclass, which acts as the UINavigationControllers child.
How can the child tell the parent how to rotate? Well, UINavigationController has a
property, typed as UINavigationControllerDelegate (a protocol). It prom‚
ises to send this delegate the
message when it needs to know how to rotate. So my view
518 | Chapter 11: Cocoa Events
to prevent it. The documentation tells you what the default response
is; you dont have to implement a
Delegation | 519
any
class to present and dismiss a ColorPickerController, and thus to be eligi‚
Therefore we want ColorPickerController
itself
520 | Chapter 11: Cocoa Events
Chapter 13
only requirement is that the data source must be able to supply information quickly,
because it will be asked for it in real time when the data needs displaying.
Another surprise is that the data source is different from the delegate. But this again
is only for generality; its an option, not a requirement. There is no reason why the
data source and the delegate should not be the same object, and most of the time they
Data Sources | 521
action
is a message emitted by an instance of a UIControl subclass (a
control
reporting a significant user event taking place in that control. The
UIControl
classes are all simple interface objects that the user can interact with directly, such as a
button (UIButton) or a segmented control (UISegmentedControl).
The significant user events (
control events
) are listed under UIControlEvents in the
Constants section of the UIControl class documentation. Different controls imple‚
ment different control events: for example, a segmented controls Value Changed
event signifies that the user has tapped to select a different segment, but a buttons
Touch Up Inside event signifies that the user has tapped the button. Of itself, a con‚
trol event has no external effect; the control responds visually (for example, a tapped
button looks tapped), but it doesnt automatically share the information that the event
has taken place. If you want to know when a control event takes place, so that you can
you
must arrange for that control event to trigger an
action
message
Heres how it works. A control maintains an internal dispatch table: for each control
522 | Chapter 11: Cocoa Events
Figure 11-1.
targetˆaction architecture
Actions | 523
. Then the view controller, after the nib loads, can configure the buttons
dispatch table like this:
The control.
The UIEvent that generated the control event.
524 | Chapter 11: Cocoa Events
responder
is an object that knows how to receive UIEvents directly (see the previous
It knows this because it is an instance of UIResponder or a UIResponder
subclass. If you examine the Cocoa class hierarchy, youll find that just about any class
that has anything to do with display on the screen is a responder. A UIView is a res‚
ponder. A UIWindow is a responder. A UIViewController is a responder. Even a
UIApplication is a responder. Even the app delegate is a responder!
The UIView that we start with (here, the hit-test view).
If this UIView is a UIViewControllers
, that UIViewController.
The UIViews superview.
Go back to step 2 and repeat! Keep repeating until we reachˆ
The UIWindow.
The UIApplication.
The UIApplications delegate.
The Responder Chain | 525
The next responder up the responder chain is a responders
next responder
526 | Chapter 11: Cocoa Events
button. If the class of this view controller is the only class that does in fact implement
, tapping the button will cause the view controllers
Select the First Responder proxy in the nib, and switch to the Attributes
inspector.
Now you can Control-drag from a control, such as a UIButton, to the First Res‚
Key‚Value Observing | 527
The process of using KVO may be broken down into stages:
Registration
The object that desires to hear about future changes in a value belonging to the
observed object must register with that observed object.
Change
A change takes place in the value belonging to the observed object, and it must
take place in a special way ƒ a KVO compliant way. Typically, this means using a
The observer is automatically notified that the value in the observed object has
Unregistration
The observer eventually unregisters to prevent the arrival of further notifications
about the observed value of the observed object.
The Cocoa API for registration and notification works like this: you call
want to observe; the observers
then called for every change for which this observer was registered, constituting a
nasty bottleneck. New in Swift 4, however, theres a revised API for key„value observ‚
ing, and Im going to assume that youll want to use this rather than the Cocoa API.
Heres how the Swift 4 key„value observing API works. You register by calling
on the object whose property you want to
528 | Chapter 11: Cocoa Events
function will typically be an anonymous function, thus
making the notification function part of the registration.
In the past, it was necessary to unregister from the observed object before the
observer went out of existence, because the observed object might try to send a mes‚
sage to a nonexistent observer. Unregistration is performed through a message to the
observed object, namely
that the observer needs to maintain a reference to the observed object. That becomes
unnecessary with the new Swift 4 key„value observing API.
Key‚Value Observing | 529
The object to be observed must be an instance of a class derived from NSObject;
otherwise, you wont be able to call
Thats because the mechanism for being observed is a feature of NSObject.
The property to be observed must be declared
Objective-C. It must also be declared
. Thats because KVO works by
// change is an NSKeyValueObservedChange
}
MyClass2 has an instance property for maintaining NSKeyValueObservation
MyClass2 will register with a MyClass1 instance by calling
. Note the use of the Swift key path to
specify the
property. Ive illustrated the use of NSKeyValueObservingOp‚
tions by asking for both the old and new values of the observed property when a
notification arrives. That information arrives into the notification function inside
an NSKeyValueObservedChange object.
observe(_:options:changeHandler:)
530 | Chapter 11: Cocoa Events
Swamped by Events | 531
probably use it as the table views data source and delegate as well. In this single class,
then, youre likely to want to implement
at a minimum
532 | Chapter 11: Cocoa Events
A Cocoa program thus consists of numerous disconnected entry points, each with its
a delay between the time when my view appears and when my button takes
on its correct title.
Swamped by Events | 533
My subviews are positioned in code and they†re turning out all wrong.
Thats because you put the code that positions your subviews in
Thats
too early
; your code needs to run later, when your views dimensions have
My view is rotating even though my view controller†s
says not to.
Thats because you implemented
wrong class
. Only the topmost view controller in the view controller hierarchy is
consulted through this property.
I set up an action connection for Value Changed on a text
but my code isn†t
being called when the user edits.
Thats because you connected the
wrong control event
Changed, not Value Changed.
Your code is executed in response to some event; but your code in turn may trigger a
534 | Chapter 11: Cocoa Events
That utility function is so important that I routinely paste it at the top level of the
AppDelegate class file in every app I write. Its going to come in handy, I know! To use
with a delay time (usually a very small number of seconds such as
and an anonymous function saying what to do after the delay. Note that what you
propose to do in this anonymous function will be done later on; youre deliberately
breaking out of your own codes line-by-line sequence of execution. So a delayed per‚
Delayed Performance | 535
didSelectRowAt indexPath: IndexPath) {
delay(0.1) {
536 | Chapter 11: Cocoa Events
…Value
Types and Reference Types† on page
). Behind the scenes, Swift and Objective-C
memory management for reference types works essentially the same way. Such mem‚
ory management, as I pointed out in
Chapter 5
Fortunately, Swift uses ARC (automatic reference counting), so you dont have to
manage the memory for every reference type object explicitly and individually, as was
once necessary in Objective-C. Thanks to ARC, you are far less likely to make a
memory management mistake, and more of your time is liberated to concentrate on
what your app actually does instead of dealing with memory management concerns.
Still, even in Swift, even with ARC, it is possible to make a memory management
mistake, or to be caught unawares by Cocoas memory management behavior. A
memory management mistake can lead to runaway excessive memory usage, crashes,
or mysterious misbehavior of your app. Cocoa memory management can be surpris‚
ing in individual cases, and you need to understand, and prepare for, what Cocoa is
going to do.
The reason why reference type memory must be managed at all is that references to
reference type objects are merely pointers. The real object pointed to occupies a hunk
the very same object. To illustrate, imagine three objects, Manny, Moe, and Jack,
where both Manny and Moe have references to Jack:
Too late
At the very latest, an object should go out of existence when no other objects
have a pointer to it. If both Manny and Moe go out of existence, and if no other
object has a reference to Jack, Jack should go out of existence too. An object
without a pointer to it is useless; it is occupying memory, but no other object has,
There cannot be any dangling pointers, because any object that has a pointer to
There cannot be any memory leaks, because any object that no longer needs Jack
538 | Chapter 12: Memory Management
If Manny or Moe
explicitly instantiates
Jack ƒ by directly calling an initializer ƒ
increments
If Manny or Moe
makes a copy
of Jack ƒ by calling
or any
If Manny or Moe
acquires
a reference to Jack (not through explicit instantiation
or copying), and needs Jack to
persist
ƒ long enough to work with Jack in code,
incre
ments
If and only if Manny or Moe has done any of those things ƒ that is, if Manny or
What ARC Is and What It Does | 539
ments
540 | Chapter 12: Memory Management
the
line
Autorelease Pool | 541
Figure 12-1. Memory usage grows during a loop
542 | Chapter 12: Memory Management
Figure 12-2. Memory usage holds steady with an autorelease pool
course of a loop with many iterations. Swift provides such a way ƒ the global
function, which takes a single argument that youll supply as a
trailing anonymous function. Before the anonymous function is called, a special tem‚
porary autorelease pool is created, and is used for all autoreleased objects thereafter.
After the anonymous function exits, the temporary autorelease pool is drained and
You assign a different value to the same property.
In order to obey the golden rule of memory management, the object taking charge of
this memory management ƒ the owner ƒ clearly needs to be the object whose
instance property this is. The only way to ensure that memory management of a
property is handled correctly, therefore, is to implement it
in the setter method
Memory Management of Instance Properties | 543
544 | Chapter 12: Memory Management
reference takes advantage of a powerful ARC feature. When a reference is
not
Figure 12-3. A crash from messaging a dangling pointer
are synonyms; they tell you
that theres no ARC memory management here. The
designation is a further
warning inserted by Swift; unlike your own code, where you wont use
unless
it is safe, Cocoas
is potentially dangerous and you need to exercise caution.
Even though
your
code is using ARC, the fact that Cocoas code is
not
means that memory management mistakes can still occur. A reference such as a
CLLocationManagers
can end up as a dangling pointer, pointing at
garbage, if the object to which that reference was pointing has gone out of existence.
If anyone (you or Cocoa) tries to send a message by way of such a reference, the app
will then crash ƒ and, since this typically happens long after the point where the real
mistake occurred, figuring out the cause of the crash can be quite difficult. The typi‚
cal sign of such a crash is that
ory management activity (
). (This is the sort of situation in which you
might need to turn on zombies in order to debug, as Ill describe later in this chapter.)
Defending against this kind of situation is up to you. If you assign some object to a
non-ARC unsafe reference, such as a CLLocationManagers
, and if that
object is about to go out of existence at a time when this reference still exists,
you
have a duty to assign
(or some other object) to that reference, thus rendering it
This section discusses some situations that call for some special memory manage‚
ment handling on your part.
When you register with the notification center by calling
Chapter 11
, theres a trap: you can end
up with a leak, which can potentially be extremely serious, because what leaks is usu‚
ally your entire view controller and its properties:
546 | Chapter 12: Memory Management
Unusual Memory Management Situations | 547
print(self.description)}Perform manual memory management
, when we unregister the observers, we also release them by
548 | Chapter 12: Memory Management
Unusual Memory Management Situations | 549
Other Cocoa objects with unusual memory management behavior will usually be
called out clearly in the documentation. For example, the UIWebView documentation
550 | Chapter 12: Memory Management
Memory Management of CFTypeRefs | 551
through global C functions. In Swifts Core Graphics overlay, however, those global C
look
CFTypeRef object through a function whose name contains the word
or
crosses the bridge
from the CFTypeRef world into the Swift world.
From that moment on, until you are done with it, it needs memory management.
552 | Chapter 12: Memory Management
Swift is aware of this, and for the most part, Swift itself will use the golden rule and
will apply correct memory management. Thus, for example, the code I showed earlier
Property Memory Management Policies | 553
The possible memory management policies for a Cocoa property are:
equivalent)
The default. The two terms are pure synonyms of one another;
equivalent, or
weak
)
No memory management. This policy is inherited from pre-ARC days, and is
inherently unsafe (hence the additional
warning in the Swift translation
become a dangling pointer and can cause a crash if you subsequently try to use it.
policy is used by Cocoa particularly when an immutable class has a mutable
subclass (such as NSString and NSMutableString, or NSArray and NSMutableArray;
Chapter 10
554 | Chapter 12: Memory Management
NSAttributedString has a mutable subclass, NSMutableAttributedString. Youve prob‚
ably configured this attributed string as an NSMutableAttributedString, and now
youre assigning it as the UILabels
. UILabel doesnt want you keep‚
ing a reference to this mutable string and mutating it in place, since that would
Debugging Memory Management Mistakes | 555
that they cant. Experience suggests that you should use every tool at your disposal to
The memory gauge in the Debug navigator charts memory usage whenever your
app runs, allowing you to observe possible memory leakage or other unwarran‚
ted heavy memory use. Note that memory management in the Simulator is not
necessarily indicative of reality! Always observe the memory gauge with the app
running on a device before making a judgment.
Instruments (Product Œ Profile) has excellent tools for noticing leaks and track‚
ing memory management of individual objects.
Good old caveman debugging can help confirm that your objects are behaving as
you want them to. Implement
call. If it isnt called, your
object is not going out of existence. This technique can reveal problems that even
Instruments will not directly expose.
Memory graphing (
…Memory Debugging† on page 436
) will draw you a picture of
Dangling pointers are particularly difficult to track down, but they can often be
located by …turning on zombies.† This is easy in Instruments with the Zombies
template.
Alternatively, edit the Run action in your scheme, switch to the Diag‚
nostics tab, and check Enable Zombie Objects. The result is that an object that
goes out of existence is replaced by a …zombie† that will report to the console if a
message is sent to it (…message sent to deallocated instance†). Be sure to turn
zombies back off when youve finished tracking down your dangling pointers.
Dont use zombies with the Leaks instrument: zombies
are
The Address Sanitizer
a Very Bad Thing, writing directly into memory that doesnt belong to us:
556 | Chapter 12: Memory Management
Objects can perform two-way communication without both of them holding refer‚
ences to one another. It may be sufficient for
one
of them to have a reference to the
other ƒ because the former, as part of a message to the latter, can include a reference
to himself. For example, Manny might send a message to Jack where one of the
question. Much of the art of iOS programming, and of object-oriented programming
generally, lies in one object
getting a reference
erences†
). Every case is different and must be solved separately, but cer‚
tain general patterns emerge, and this chapter will outline some of them.
There are also ways for Manny to send a message that Jack
receives
without having to
to
Jack ƒ possibly without even knowing or caring who Jack is. Noti‚
fications and key„value observing are examples, and Ill mention them in this chapter
Finally, the chapter ends with a section on the larger question of what kinds of objects
need
to see one another, within the general scope of a typical iOS program.
Every instance comes from somewhere and at someones behest: some object sent a
message commanding this instance to come into existence in the first place. The
commanding object therefore has a reference to the instance at that moment. When
Manny creates Jack, Manny has a reference to Jack.
That simple fact can serve as the starting point for establishing future communica‚
tion. If Manny creates Jack and knows that he (Manny) will need a reference to Jack
in the future, Manny can keep the reference that he obtained by creating Jack in the
first place. Or, it may be that what Manny knows is that Jack will need a reference to
Manny in the future; Manny can supply that reference immediately after creating
Jack, and Jack will then keep it.
Delegation is a case in point. Manny may create Jack and immediately make himself
Jacks delegate, as in my example code in
Chapter 11
Indeed, if this crucial, you might endow Jack with an initializer so that Manny can
create Jack and hand Jack a reference to himself
at the same time
, to help prevent any
slip-ups. Compare the approach taken by UIBarButtonItem, where three different
nibs ƒ either different
.xib
files or different
Visibility by Instantiation | 559
object in nib A and an object in nib B; its particularly frustrating when you can see
both objects sitting right there in the same storyboard. But, as I explained earlier
reference to Jack), by asking the segue for it ƒ and now the source view controller
can make itself the destination view controllers delegate, hand it any needed informa‚
Objects may acquire the ability to see one another automatically by virtue of their
position in a containing structure. Before worrying about how to supply one object
Similarly, a responder (
Chapter 11
property ƒ which also means, because of the structure of the res‚
ponder chain, that a view controllers main view can see the view controller. In this
code from one of my apps, I work my way up from a view some way down the view
hierarchy to obtain a reference to the view controller thats in charge of this whole
scene (and there are similar examples in
Chapter 5
Similarly, view controllers are themselves part of a hierarchy and therefore can see
one another. If a view controller is currently presenting a view through a second view
controller, the latter is the formers
latters
. If a view controller is the child of a
UINavigationController, the latter is its
. A UINavigation‚
Controllers visible view is controlled by its
. And from any
of these, you can reach the view controllers view through its
property, and so
User-
Defaults.standard
.
Global Visibility | 561
Notifications (
Chapter 11
and Key‚Value Observing | 563
information ƒ meaning, in effect, a program with a graphical user interface. The
notion goes back to the days of Smalltalk, and much has been written about it since
then, but informally, heres what the terms mean:
Model
The data and its management, often referred to as the programs …business logic†
ƒ the hard-core stuff that the program is really all about.
View
What the user sees and interacts with.
Controller
store
score is maintained (model)
The score is data being maintained internally; it is
model
. It could be as simple as
score is updated (controller)
Telling the score when to change, and causing the updated score to be reflected in
the user interface, is the work of the
controller
imagine that the models numeric score needs to be transformed in some way for
presentation to the user.
For example, suppose the UILabel that presents the score reads: …The score is 20.†
The model is presumably storing and providing the number 20, so whats the
source of the phrase …The score isˆ†? Whoever is causing this phrase to precede
the score in the presentation of the score to the user is a controller.
Figure 13-1. Modelˆviewˆcontroller
Even this simplistic example (
) illustrates very well the advantages of
MVC. By separating powers in this way, we allow the aspects of the program to evolve
with a great degree of independence. Do you want a different font and size in the pre‚
sentation of the score? Change the view; the model and controller need know nothing
about it, but will just go on working exactly as they did before. Do you want to
change the phrase that precedes the score? Change the controller; the model and view
Adherence to MVC is particularly appropriate in a Cocoa app, because Cocoa itself
adheres to it. The very names of Cocoa classes reveal the MVC philosophy that
underlies them. A UIView is a view. A UIViewController is a controller; its purpose is
to embody the logic that tells the view what to display. In
Chapter 11
we saw that a
Model‚View‚Controller | 565
You are an iOS programmer, and youve chosen to adopt Apples new language, Swift.
And this means that youll never have to concern yourself with Apples
old
Objective-C, right? Wrong.
Objective-C is not dead. Far from it.
You
may be using Swift, but Cocoa is not. Pro‚
gramming iOS involves communicating with Cocoa and its supplementary frame‚
works. The APIs for those frameworks are written in Objective-C ƒ or in its
underlying base language, C. Messages that you send to Cocoa using Swift are being
translated for you into Objective-C. Objects that you send and receive back and forth
across the Swift/Objective-C bridge are Objective-C objects. Some objects that you
send from Swift to Objective-C are even being translated for you into other object
types, or into nonobject types.
You need to understand what Objective-C expects from you when you are sending
messages across the language bridge. You need to know what Objective-C is going to
do
with those messages. You need to know what is coming
from
how it will be represented in Swift. Your app may even include some Objective-C
code as well as Swift code, so you need to know how the parts of your own app will
communicate with each other.
This appendix summarizes certain linguistic features of C and Objective-C, and
describes how Swift interfaces with those features. I do not explain here how to write
568 | Appendix A: C, Objective-C, and Swift
to create a C string variable, the NSString
property or the Swift Founda‚
tion overlays
C, Objective-C, and Swift | 569
Thus, if a C function
enum
name and raw value type intact. This is a true Swift enum, so the enumerand names
become namespaced case names. Moreover, Swift automatically subtracts the com‚
Going the other way, a Swift enum with an Int raw value type can be exposed to
attribute. Thus, for example, Objective-C sees this Swift
enum as an enum with type NSInteger and enumerand names
Another variant of C enum notation, using the
macro, is suitable for
570 | Appendix A: C, Objective-C, and Swift
C, Objective-C, and Swift | 571
Thats obviously a bitmask, but in Objective-C it is marked with
, and so in Swift its a simple enum. To work with it as a bitmask, you are
572 | Appendix A: C, Objective-C, and Swift
A C struct is a compound type whose elements can be accessed by name using dot-
notation after a reference to the struct. For example:
After that declaration, it becomes possible to talk like this in C:
A C struct arrives wholesale into Swift as a Swift struct, which is thereupon endowed
with Swift struct features. Thus, for example, CGPoint in Swift has
CGFloat
instance properties, as you would expect; but it also magically acquires the implicit
place.
C, Objective-C, and Swift | 573
name; a space can appear on either or both sides of the asterisk. These are equivalent
declarations of a pointer-to-int:
(or, with a space,
). Objective-C, for reasons that Ill
explain later, uses C pointers heavily, so youre going to be seeing that asterisk a lot if
you look at any Objective-C.
A C pointer arrives into Swift as an UnsafePointer or, if writable, an UnsafeMutable‚
Pointer; this is a generic, and is specified to the actual type of data pointed to. (A
pointer is …unsafe† because Swift isnt managing the memory for, and cant even guar‚
antee the integrity of, what is pointed to.)
574 | Appendix A: C, Objective-C, and Swift
In this example, we receive a
C, Objective-C, and Swift | 575
576 | Appendix A: C, Objective-C, and Swift
If youre going to do that, however, you really need to take upon yourself the full
C, Objective-C, and Swift | 577
578 | Appendix A: C, Objective-C, and Swift
C, Objective-C, and Swift | 579
580 | Appendix A: C, Objective-C, and Swift
fore those features are simply invisible to Objective-C. Objective-C cant see any of
Swift enums, except for an
enum with an Int raw value
Swift structs, except for structs that come ultimately from C (or that are bridged)
@objc
Tuples
Nested types
Nothing in that list can be directly exposed to Objective-C ƒ and, by implication,
nothing that
involves
anything in that list can be exposed to Objective-C. For exam‚
ple, suppose we have a class MyClass not derived from NSObject. Then if your
UIViewController subclass has a property typed as a MyClass, that property cannot
Classes that derive from NSObject. Such a class will be declared in Swift either as
class defined by Cocoa (such as UIViewController).
C, Objective-C, and Swift | 581
Within such a class, implementations of members of protocols that are defined in
Objective-C (such as NSCodings
Within such a class, instance properties marked
582 | Appendix A: C, Objective-C, and Swift
Swift will convert certain native nonclass types to their Objective-C class equivalents
for you. The following native Swift structs are bridged to Objective-C class types:
Numbers (and Bool) to NSNumber
Array to NSArray
Dictionary to NSDictionary
C, Objective-C, and Swift | 583
The Swift overlay types are all bridged to their Foundation counterparts. The Swift
rendering of an Objective-C API will show you the Swift overlay type rather than the
584 | Appendix A: C, Objective-C, and Swift
provided. In this way, Objective-C is able to store the object for us, in its box, and
hand it back to us intact upon request. Like Pandora, Objective-C will cope perfectly
well as long as it doesnt look in the box!
+
or
-
C, Objective-C, and Swift | 585
component called the
Clang importer
Swift prunes redundant initial type names. Were starting with a string, and its
. Thats a common Cocoa locution, but Swift finds it merely
verbose. Now were down to
586 | Appendix A: C, Objective-C, and Swift
// ...
}
C, Objective-C, and Swift | 587
588 | Appendix A: C, Objective-C, and Swift
There is a second way to create an instance in Objective-C. Very commonly, a class
class
C, Objective-C, and Swift | 589
syntax has numerous advantages. In addition to translating the
Add a colon.
590 | Appendix A: C, Objective-C, and Swift
con, grad, CGPointMake(89,0), CGPointMake(111,0), [])
Nowadays, as part of renamification, many commonly used CFTypeRef functions
(such as those in the Core Graphics framework) are recast as if the CFTypeRef objects
In Objective-C, a CFTypeRef is created with some sort of
Swift, the CFTypeRef is treated as an object type name, and the syntax looks
In Objective-C, a CFTypeRef function operating on a CFTypeRef pseudo-object
C, Objective-C, and Swift | 591
you cant do that with a CFDictionary, because it isnt an object ƒ so I cast it to a
Swift dictionary. The key
is a CFString, but when I try
To illustrate, Ill repeat the preceding example where I called
, but this time I wont cast to a Swift dictionary; Ill work with the
result as a CFDictionary to extract the value of its
key.
To do so, Ill call
592 | Appendix A: C, Objective-C, and Swift
C, Objective-C, and Swift | 593
� animations: @escaping () - Swift.Void,
594 | Appendix A: C, Objective-C, and Swift
ment, especially because most objects arriving from Objective-C were never
in
fact
Too many umbrella collections
In Objective-C, a collection type such as NSArray can contain elements of multi‚
ple object types, and the collection itself is agnostic as to what types of elements it
contains. But a Swift collection type can contain elements of just one type, and is
itself typed according to that element type.
The default solution was for every collection to arrive from Objective-C typed as
having AnyObject elements; it then had to be cast down explicitly on the Swift
side. It was particularly galling to ask for a views
C, Objective-C, and Swift | 595
github.com/apple/swi€-evolution
596 | Appendix A: C, Objective-C, and Swift
sees Objective-C
C, Objective-C, and Swift | 597
Then:
For Swift code to see the Thing class, I need to
visible
MyCoolApp-Bridging-Header.h
For Thing class code to see my Swift declarations, I need to import the
invisible
) at the top of
Once youve imported the invisible bridging header into an Objective-C file, you
can Control-Command-click its name to open it. This shows you your apps
entire Swift API as seen as by Objective-C!
On that basis, heres the procedure I use for turning my own Objective-C apps into
Swift apps:
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.
Remove that
In every Objective-C file that
file, remove that
statement and import in its place the invisible bridging header (if you
arent importing it in this file already).
If you were importing the corresponding
file in the visible bridging header,
statement.
Create the
598 | Appendix A: C, Objective-C, and Swift
file, declare the class and provide stub declarations for all members
that were being made public in the
tocols, adopt them; you may have to provide stub declarations of required proto‚
The project should now compile! It doesnt work, of course, because you have not
written any real code in the
file. But who cares about that? Time for a beer!
Now fill out the code in the
file. My technique is to translate more or less
particularly idiomatic or Swifty.
.m
file! Repeat all of the above steps.
When all of the other files have been translated, translate the app delegate class.
C, Objective-C, and Swift | 599
access control,
Accounts preferences,
connections, creating,
app bundle,
app delegate,
app launch process,
app name,
App Store,
App Store distribution,
mutating,
bitwise operators,
602 | Index
data types,
enums,
numeric types,
pointer-to-function,
pointer-to-void,
pointers,
canvas,
Capabilities pane,
capitalization,
capture list,
captured variable references,
preserving,
documentation,
hierarchy,
instances, multiple references,
instances, mutating,
Index | 603
code, location,
codepoints, Unicode,
coercion, numeric,
coercion, Range and NSRange,
coercion, String and Int,
collections, Foundation,
collections, memory management,
argument label,
enum raw value type,
generic type constraint,
compound assignment operators,
computed variable initializer,
computed variables,
concatenating arrays,
concatenating strings,
conditional assignment,
conditional evaluation,
conditional initialization,
configurations,
604 | Index
currying,
CustomStringConvertible,
dangling pointers,
Data,
data sources,
data tips,
Date,
DateComponents,
DateFormatter,
DateInterval,
dates,
Debug menu (Simulator),
Debug navigator,
debugger, Xcode,
memory management,
decimal point,
declaration
jumping to,
of arrays,
of enums,
of operators,
delegation (see delegate)
Index | 605
dot-notation,
key paths,
drawing a view,
drawing text,
dynamic dispatch,
a storyboard,
equality operators,
Equatable,
ErrorPointer,
catching,
errors, compiler,
cannot invoke index,
closure cannot implicitly capture,
expected declaration,
606 | Index
212
functional events,
anonymous,
Index | 607
generic pointer,
associated type chains,
declaration,
protocols, constraining associated type,
type constraints,
type constraints, extensions,
type constraints, multiple,
type, telling compiler,
where clauses,
where clauses, extensions,
heads-up display,
hexadecimal number,
hierarchy of classes,
hierarchy of views,
IBAction,
608 | Index
of enums,
initialization of properties,
convenience,
delegating,
designated,
enum,
implicit,
implicit, class,
implicit, enum,
implicit, struct,
Instruments,
Int,
Interface Builder,
interface tests,
internal,
internal identity principle,
Index | 609
labels (flow control),
main view of view controller,
maintenance of state,
map,
mapValues,
Markdown,
610 | Index
19
launch,
nib-based instantiation,
nibs, apps without,
Index | 611
NSMutableArray,
NSMutableDictionary,
categories,
comparison,
612 | Index
preventing,
owner (memory management),
Index | 613
print,
private,
Project navigator,
project templates,
computed initialization,
deferred initialization,
enums,
initialization,
initialization, classes,
lazy initialization,
memory management,
Objective-C, memory management,
private,
static,
static vs. class,
static, initialization,
static, struct,
associated type,
associated type, chaining,
associated type, constraining,
composition,
declaration,
delegate,
documentation,
constraining associated type,
extensions, invisible to Objective-C,
constraining associated type,
implicitly required initializers,
literal convertible,
memory management,
development,
query events,
Quick Help,
Range,
raw value,
RawRepresentable,
614 | Index
memory management,
Index | 615
172
100
,
231
616 | Index
bridged to Objective-C classes,
482
,
583
C structs,
481
,
573
C structs, logging,
411
initializers,
146
initializers, extensions,
212
tabs in Xcode,
319
Index | 617
195
(see also generics)
type references,
178
type(of:),
179
updateValue,
User Defined Runtime Attributes,
user events,
UserDefaults,
UTF-8, UTF-16, UTF-32,
Utilities pane,
memory management,
values (dictionary),
computed,
declaration,
global, initialization,
initialization,
initialization of Optional,
618 | Index
warnings, compiler,
WWDR Intermediate Certificate,
Index | 619
Matt Neuburg
started programming computers in 1968, when he was 14 years old, as
became hopelessly hooked on computers again, migrating to a Macintosh in 1990. He
wrote some educational and utility freeware, became an early regular contributor to
TidBITS
MacTech
August 1996 he became a freelancer, which means he has been looking for work ever
since. He is the author of
Frontier:
Guide
REALbasic:
Guide
AppleScript:
Guide
Programming iOS 11
OReilly Media).
iOS 11 Programming Fundamentals with
Pagophilus groenlandicus
), a Latin name that translates to …ice-lover from Green‚
land.† These animals are native to the northern Atlantic and Arctic Oceans, and
spend most of their time in the water, only going onto ice packs to give birth and
molt. As earless (…true†) seals, their streamlined bodies and energy-efficient swim‚
ming style make them well-equipped for aquatic life. While eared seal species like sea
lions are powerful swimmers, they are considered semiaquatic because they mate and
The harp seal has silvery-gray fur, with a large black marking on its back that resem‚
ity after 4„8 years (depending on their gender), and have an average lifespan of 35
Harp seals are hunted commercially off the coasts of Canada, Norway, Russia, and
Greenland for their meat, oil, and fur. Though some of these governments have regu‚
lations and enforce hunting quotas, it is believed that the number of animals killed
every year is underreported. Public outcry and efforts by conservationists have resul‚

Приложенные файлы

  • pdf 10915217
    Размер файла: 6 MB Загрузок: 0

Добавить комментарий