Cocoa Programming in OS X
Cocoa Programming in OS X
All rights reserved. Printed in the United States of America. This publication is protected by copyright, and
permission must be obtained from the publisher prior to any prohibited reproduction, storage in a retrieval system,
or transmission in any form or by any means, electronic, mechanical, photocopying, recording, or likewise. For
information regarding permissions, contact
The 10-gallon hat with propeller logo is a trademark of Big Nerd Ranch, LLC.
Exclusive worldwide distribution of the English edition of this book by
The authors and publisher have taken care in writing and printing this book but make no expressed or implied
warranty of any kind and assume no responsibility for errors or omissions. No liability is assumed for incidental
or consequential damages in connection with or arising out of the use of the information or programs contained
herein.
Many of the designations used by manufacturers and sellers to distinguish their products are claimed as
trademarks. Where those designations appear in this book, and the publisher was aware of a trademark claim, the
designations have been printed with initial capital letters or in all capitals.
ISBN-10 0134077113
ISBN-13 978-0134077116
Fifth edition, first printing, April 2015
Release D.5.1.1
For Aaron’s sons, Walden and Otto
iii
This page intentionally left blank
Acknowledgments
Creating this book required the efforts of many people. We want to thank them for their help. Their
contributions have made this a better book than we could have ever written alone.
Thanks to the students who took the Cocoa programming course at the Big Nerd Ranch. They helped
us work the kinks out of the exercises and explanations that appear here. Their curiosity inspired us to
make the book more comprehensive, and their patience made it possible.
Thank you to all the readers of the first four editions who made such great suggestions on our forums
( http://forums.bignerdranch.com/ ).
Thank you to our technical reviewers, Juan Pablo Claude, Chris Morris, Nick Teissler, Pouria Almassi,
and John Gallagher, who made great additions and caught many of our most egregious errors.
Finally, a very big thank you to our support team in writing this book: Liz Holaday, for copy-editing;
Chris Loper, whose excellent tool chain made writing this book that much easier; and most of all Susan
Loper, whose collaboration helped us write the kind of book we believe this technology deserves.
v
This page intentionally left blank
Table of Contents
Introduction .................................................................................................................. xvii
About This Book ................................................................................................... xvii
Prerequisites ................................................................................................. xviii
Typographical conventions .............................................................................. xviii
What’s new in the fifth edition? ...................................................................... xviii
The Story of Cocoa ............................................................................................... xviii
NeXTSTEP and OpenStep ............................................................................... xix
From NeXTSTEP to OS X to iOS ..................................................................... xix
OSX, Unix, and Cocoa ..................................................................................... xx
Introducing the Swift Language ................................................................................. xx
The Cocoa Frameworks ........................................................................................... xxi
Tools for Cocoa Programming .................................................................................. xxi
Some Advice on Learning ....................................................................................... xxii
1. Let’s Get Started ........................................................................................................... 1
Creating an Xcode Project .......................................................................................... 1
Getting around in Xcode .................................................................................... 3
Application Design .................................................................................................... 4
Model-View-Controller ....................................................................................... 4
Creating the MainWindowController class ............................................................. 6
Creating the User Interface in Interface Builder .............................................................. 8
Adding view objects .......................................................................................... 9
Configuring view objects .................................................................................. 11
XIB files and NIB files .................................................................................... 14
Showing the Window ............................................................................................... 14
Making Connections ................................................................................................ 17
Creating an outlet ............................................................................................ 17
Connecting an outlet ........................................................................................ 18
Defining an action method ................................................................................ 19
Connecting actions ........................................................................................... 20
Creating the Model Layer ......................................................................................... 22
Connecting the Model Layer to the Controller .............................................................. 24
Improving Controller Design ..................................................................................... 24
2. Swift Types ................................................................................................................. 27
Introducing Swift ..................................................................................................... 27
Types in Swift ........................................................................................................ 27
Using Standard Types ............................................................................................... 28
Inferring types ................................................................................................ 30
Specifying types .............................................................................................. 30
Literals and subscripting ................................................................................... 32
Initializers ...................................................................................................... 33
Properties ....................................................................................................... 34
Instance methods ............................................................................................. 34
Optionals ................................................................................................................ 34
Subscripting dictionaries ................................................................................... 36
Loops and String Interpolation ................................................................................... 36
vii
Cocoa Programming for OS X
viii
Cocoa Programming for OS X
ix
Cocoa Programming for OS X
x
Cocoa Programming for OS X
xi
Cocoa Programming for OS X
xii
Cocoa Programming for OS X
xiii
Cocoa Programming for OS X
xiv
Cocoa Programming for OS X
xv
Cocoa Programming for OS X
xvi
Introduction
If you are developing applications for OS X, or are hoping to do so, this book will be your foundation
and will help you understand Cocoa, the set of frameworks for developing applications for OS X. You,
the developer, are going to love developing for OS X because Cocoa will enable you to write full-
featured applications in a more efficient and elegant manner.
xvii
Introduction
Prerequisites
This book is written for programmers and assumes that you are familiar with basic programming
concepts (like functions, variables, and loops) as well as object-oriented concepts (like classes, objects,
and inheritance). If you do not fit this profile, you will find this book tough going. You are not expected
to have any experience with Mac programming.
One of the challenges of learning Cocoa programming is learning the Swift language. If you have a
basic foundation in programming and know something about objects, you will find learning Swift
to be easy. This book includes three chapters to introduce to you to the language. Then you will
learn more Swift as you build Cocoa applications throughout the book. If you would prefer a gentler
introduction, start with Apple’s The Swift Programming Language, available in the iBooks store or
from developer.apple.com/swift, offers a more gentle introduction. Or, if you can wait until Summer
2015, you can read Swift Programming: The Big Nerd Ranch Guide first.
This is a hands-on book and assumes that you have access to OS X and the developer tools. The book
requires OS X Yosemite (10.10) or higher. The exercises are written for Xcode 6.3 and Swift 1.2.
We strongly recommend that you join Apple’s Mac Developer Program at developer.apple.com/
programs. Joining the program gives you access to pre-release versions of Xcode and OS X. These
can be very useful when trying to stay ahead of Apple’s development curve. In addition, you must be a
member of the developer program to distribute your apps on the App Store.
Typographical conventions
To make the book easier to follow, we have used several typographical conventions.
In Swift, class names are always capitalized. In this book, we have also made them appear in a
monospaced bold font. In Swift, method names start with a lowercase letter. Here, method names will
also appear in a monospaced bold font. For example, you might see “The class NSWindowController
has the method showWindow(_:).”
Other literals, including instance variable names that you would see in code, will appear in a
regular monospaced font. Also, filenames will appear in this same font. Thus, you might see “In
MyClass.swift, set the optional favoriteColor to nil.”
Code samples in this book appear in the regular monospaced font. New portions, which you will need
to type yourself, will appear in bold. Code that you should delete is struck-through.
xviii
NeXTSTEP and OpenStep
After a few conflicts, John Sculley moved Steve Jobs to a position where he had no control over the
company. Steve Jobs left to form another computer company, NeXT Computer.
NeXT hired a small team of brilliant engineers. This small team developed a computer, an operating
system, a printer, a factory, and a set of development tools. Each piece was years ahead of competing
technologies. Unfortunately, the computer and the printer were commercial failures. In 1993, the
factory closed, and NeXT Computer, Inc. became NeXT Software, Inc. The operating system and the
development tools continued to sell under the name NeXTSTEP.
xix
Introduction
and Apple finally decided to pull the plug and buy the next version of Mac OS instead. After surveying
the existing operating systems, Apple selected NeXTSTEP. Because NeXT was small, Apple simply
bought the whole company in December 1996. In 1997, Steve Jobs returned to Apple.
NeXTSTEP became Mac OS X, and OpenStep became Cocoa. In 2001, the first desktop version
of Mac OS X was released with several more to follow. In 2012, Apple dropped the “Mac,” and the
operating system became known as OS X.
The mutation of NeXTSTEP didn’t stop with OS X. iOS, the operating system for iPhones and iPads,
is based on OS X, and iOS’s Cocoa Touch is built on the same foundations as Cocoa. As a developer
you will find that your knowledge transfers well between the two: the design patterns are identical, and
many of the APIs are very similar if not the same.
As shown in Figure 1, the window server and your application are Unix processes. Cocoa is your
application’s interface to the window server to receive events and draw to the screen. At the same time
it has access to the Unix layer where it can make lower level calls.
xx
The Cocoa Frameworks
Swift maintains the expressiveness of Objective-C while introducing a syntax that is significantly
more rich, succinct, and – in the opinion of some – readable. It emphasizes type safety and introduces
advanced features such as optionals and generics. Swift is much stricter than Objective-C and will not
allow you to make as many ridiculous errors.
Although we will focus on Swift, you can still write Cocoa code in Objective-C, even alongside Swift,
compiling the two in the same project.
Most importantly, Swift allows the use of these new features while relying on the same tested, elegant
Cocoa frameworks that developers have built upon for years and years.
• Foundation: Every object-oriented programming language needs the standard value, collection,
and utility classes. Strings, dates, lists, threads, and timers are in the Foundation framework. All
Cocoa apps, from command-line tools to fully-featured GUI apps, use Foundation. Foundation is
also available on iOS.
• AppKit: All things related to the user interface are in the AppKit framework. These include
windows, buttons, text fields, events, and drawing classes. AppKit is built on top of Foundation
and is used in practically every graphical application on OS X.
• Core Data: Core Data makes it easy to save objects to a file and then reload them into memory. It
is a persistence framework.
In addition to the three Cocoa frameworks, over a hundred frameworks ship with OS X. The
frameworks offer a wide variety of features and functionality. For example, AVFoundation is great
for working with audio and video, AddressBook provides an API to the user’s contacts (with their
permission), and and SpriteKit is a full-featured 2D game engine with physics. You can pick and
choose from these frameworks to suit the needs of your application. You can also create your
own frameworks from the classes that you create. Typically, if a set of classes is used in several
applications, you will want to turn them into a framework.
This book will focus on the Cocoa frameworks and especially Foundation and AppKit because they
will form the basis of most Cocoa applications that you will write. Once you have mastered these,
other frameworks will be easier to understand.
xxi
Introduction
invoke and control the debugger. Behind the scenes, swiftc (Apple’s Swift compiler) will be used to
compile your code, and LLDB (Low Level Debugger) will help you find your errors.
Inside Xcode, you will use the Interface Builder editor as a GUI builder to lay out windows and
add UI elements to those windows. But Interface Builder is more than a simple GUI builder. In
Interface Builder, you can create objects and edit their attributes. Most of those objects are UI elements
from the AppKit framework such as buttons and text fields, but some will be instances of classes that
you create.
You will use Instruments to profile your application’s CPU, memory, and filesystem usage. Instruments
can also be used to debug memory-management issues. Instruments is built on top of dtrace, which
makes it possible to create new instruments.
xxii
3
Structures and Classes
At this point you should be somewhat familiar with using Swift’s standard types: strings, arrays,
enums, etc. It is time to move on to bigger and better things: defining your own types. In this chapter,
you will build a simple 2D physics simulation. You will create your own structure and a few classes,
and you will learn about the differences between them.
Structures
In Cocoa, structures are typically used to represent groupings of data. For example, there is NSPoint,
which represents a point in 2D space with an X and a Y value. As your first structure you will create a
2D vector structure.
Create a new playground. From Xcode’s File menu, select New... → Playground. Name the playground
Physics and save it with the rest of your projects.
import Cocoa
struct Vector {
var x: Double
var y: Double
}
Much like C structures, Swift structures are composite data types. They are composed of one or more
fields, or properties, each of which has a specified type. A few lines down, create an instance of Vector
and access its properties:
You just used Swift’s automatic initializer to create an instance of this structure. The automatic
initializer has a parameter for each property in the structure. If you were to add a z field, this code
would cause a compiler error because it lacks a z parameter. (Do not worry about the zeros; that is just
typical floating point fun.)
You can provide your own initializers, but when you do, the automatic initializer is no longer provided.
Go back to Vector and add an initializer that takes no parameters and initializes x and y to 0.
41
Chapter 3 Structures and Classes
struct Vector {
var x: Double
var y: Double
init() {
x = 0
y = 0
}
}
Initializers in Swift use the init keyword, followed by the parameter list, and then the body of the
initializer. Within the body, the x and y properties are assigned directly.
An initializer must initialize all of the properties of its structure.
As we warned, defining this initializer has caused the automatic one to vanish, causing an error in the
playground. You can easily define it manually, however:
struct Vector {
var x: Double
var y: Double
init() {
x = 0
y = 0
}
A Swift programmer would say that this initializer takes two parameters, x and y, both of type Double.
What is self? It represents the instance of the type that is being initialized. Using self.propertyName
is usually unnecessary (you did not use it in init()), but because the initializer’s parameter names
match the names of the properties you must use self to tell the compiler that you mean the property
and not the parameter.
Before continuing, let’s make an improvement. As the Vector structure stands, its two initializers have
independent code paths. It would be better to have them use one code path by having the parameterless
initializer call the initializer which takes both x and y.
struct Vector {
var x: Double
var y: Double
init() {
x = 0
y = 0
self.init(x: 0, y: 0)
}
42
Instance methods
A single code path for initialization is not required for structures, but it is a good habit to get into as
you will use it when working with classes.
Instance methods
Methods allow you to add functionality to your data types. In Swift, you can add methods to structures
as well as classes (and enums!). Instance methods operate within the context of a single instance of the
type. Add an instance method for multiplying a vector by a scalar:
struct Vector {
...
The func keyword in the context of a structure indicates that this is a method. It takes a single
parameter of type Double and returns an instance of Vector.
Try this new method out:
What is the name of this method? In conversation you would call it vectorByAddingVector, but in this
text we include parameters, like this: vectorByAddingVector(_:). By default, the first parameter of a
method is not named – thus the underscore.
Why not name the first parameter? Because the convention – inherited from Objective-C and Cocoa
– is that the base name of the method includes the name of the first parameter, in this case Vector.
Suppose you added another parameter to that method. What would it look like?
43
Chapter 3 Structures and Classes
numberOfTimes. That is certainly very descriptive, but you might prefer to use a shorter name (like
times) within the method. In that case you would explicitly set the internal parameter name like this:
The method’s signature has not changed. For those calling it, its name is still
vectorByAddingVector(_:numberOfTimes:), but internally you have the satisfaction of using the
name you want.
struct Vector {
...
Operator Overloading
By overloading operators you can make your own types work with common (and even uncommon)
operators. This ability falls deep beyond the “with great power comes great responsibility” line.
However, vectors are a natural and respectable application for this technique.
To define an operator overload you simply add a function that takes the appropriate types. To start with,
instead of calling vectorByAddingVector(_:), it would be nice to use the + operator. Overload + and *
for adding and scaling vectors, respectively.
struct Vector {
...
}
44
Classes
Note that the order of types for binary operators like * and + is important. In order to write 2.0 *
gravity you will need to implement another operator overload function:
Classes
Now that you have the beginnings of a robust vector type, let’s put it to work. Your 2D physics
simulation will consist of two classes: Particle, which represents a single moving object within the
simulation, and Simulation, which contains an array of Particle instances.
Classes are very similar to structures. They have a lot of the same features: initializers, properties,
computed properties, and methods. They have a significant difference, however, which we will discuss
once the simulation is up and running.
Start by defining the Particle class in your playground. The position is not important, as long as
it is above or below (but not inside!) the Vector structure. A Particle has three Vector properties:
position, velocity, and acceleration.
struct Vector {
...
}
class Particle {
Classes and structures differ significantly in terms of initializers. Most noticeably, classes do not have
automatic initializers, so you will see a compiler error: Class 'Particle' has no initializers.
Fix this by adding an initializer to Particle:
class Particle {
init(position: Vector) {
self.position = position
self.velocity = Vector()
self.acceleration = Vector()
}
}
You do not need to provide a parameter for every property in a class like you did in Vector’s
init(x:y:). You just need to initialize everything. As with initializers for structures, a class’s
45
Chapter 3 Structures and Classes
initializer must initialize all of its properties before returning or performing any other tasks. By
requiring this of initializers the Swift compiler guarantees that every instance is fully initialized before
it is put to work.
Another approach is to give properties default values:
class Particle {
init(position: Vector) {
self.position = position
}
}
In a simple case like this, there is not a clear benefit to either approach.
class Particle {
...
init(position: Vector) {
self.position = position
self.velocity = Vector()
self.acceleration = Vector()
}
convenience init() {
self.init(position: Vector())
}
There is an exception to these designated initializer rules: required initializers, which you will see in
Chapter 12.
46
Add an instance method
class Particle {
...
convenience init() {
self.init(position: Vector())
}
The tick(_:) method takes an NSTimeInterval parameter, dt, the number of seconds to simulate.
NSTimeInterval is an alias for Double.
Below the definition of Particle, define the Simulation class, which will have an array of Particle
objects and its own tick(_:) method:
class Particle {
...
}
class Simulation {
The Simulation class has no initializers defined since all of its properties have default values. The
for-in loop iterates over the contents of the particles property. The tick(_:) method applies
constant acceleration due to gravity to each of the particles before simulating them for the time
interval.
Before you warm up the simulator and add a particle, add a line to evaluate particle.position.y.
You will use this shortly with the playground’s Value History. Additionally, add some code to remove
particles once they drop below y = 0:
47
Chapter 3 Structures and Classes
class Simulation {
...
The last chunk of code filters the particles array, removing any particles that have fallen to the
ground. This is a closure, and it is OK if you do not understand it at this point. You will learn more
about closures in Chapter 15.
Now you are ready to run the simulator. Create an instance of the simulator and a particle, add the
particle to the simulation, and see what happens.
class Simulation {
...
}
You should see the playground tally up (20 times) on a number of lines. If the playground runs the
simulation continuously, you can stop it by commenting out the while loop. Select the three lines and
hit Command-/ to toggle the comment marks:
Double-check your code against the listings above, in particular the lines that filter the particles array
and the line that increments time.
48
Inheritance
Once you have the simulation running as expected, click the Variables View circle in the playground
sidebar on the line that reads particle.position.y, as shown in Figure 3.1. A graph will appear,
showing the Y values of the particle over time. The X axis on this graph represents iterations over time
and not the X coordinate of the particle.
Inheritance
Suppose you wanted to simulate a particle that had different behavior than the Particle class you
have already implemented: a rocket that propels itself with thrust over a certain period of time. Since
Particle already knows about physics, it would be natural to extend and modify its behavior through
subclassing.
49
Chapter 3 Structures and Classes
The thrust property represents the magnitude of the rocket’s thrust. thrustTimeRemaining is the
number of seconds that the thrust will be applied for. direction is the direction that the thrust will be
applied in.
Take a minute to go through the initializers you just typed in. Which is the designated initializer?
(Remember the rule of thumb about designated initializers?)
In order to guarantee that a class’s properties are initialized, initializers are only inherited if a subclass
does not add any properties needing initialization. Thus, Rocket provides its own initializers and calls
the superclass’s designated initializer.
Next you will override the tick(_:) method, which will do a little math to calculate the acceleration
due to thrust and apply it before calling the superclass’s – Particle’s – tick(_:) method.
Finally, create an instance of Rocket and add it to the simulation in place of the ball:
50
Computed Properties
The simulation will run for 70 “seconds” with these parameters. The Value History shows quite a
different profile! (Figure 3.2)
Note that inheritance is one key differentiator between classes and structures: structures do not support
inheritance.
Computed Properties
It is frequently useful to find a vector’s length or magnitude. You could do this by adding a function
returning a Double:
51
Chapter 3 Structures and Classes
struct Vector {
...
However, it is much more natural to think of this as a read-only property. In Swift the general term for
this is computed property, which is in contrast to the stored properties you have been using so far. A
read-only computed property version of length would look like this:
struct Vector {
...
This read-only computed property pattern (called a “getter”) is so common, in fact, that Swift provides
a shorthand means of expressing it. Add this to Vector:
struct Vector {
...
At other times it is useful to have a getter and setter for a computed property. This tends to be used
to alias other properties or to transform a value before it is used elsewhere. For example, you could
abstract the setting of the textField from the RandomPassword with a computed property:
...
52
Reference and Value Types
Computed properties do not have any storage associated with them. If you need to store a value, you
must create a separate stored property for it.
When vector0 is assigned to vector1, the entire value of vector0 is copied into the memory
represented by vector1. When vector0 is changed, vector1 is unaffected.
Contrast this behavior with classes, which, again, are reference types:
Even though you assign ball0 to ball1, there is still only one Particle instance in existence; no
copies are made. The ball0 constant is a reference to the instance, and when ball0 is assigned to
ball1, ball1 is then a reference to the same instance.
(A reference is similar to a pointer in C-based languages. However, a pointer stores the actual memory
address of the object and you can access that address directly. A Swift reference does not provide direct
access to the address of the object being referenced.)
There is another reference type. Functions are types so that a function can be passed in to other
functions as a defined parameter, or even assigned to a property. This is the basis of closures, which
you saw briefly earlier in this chapter, and which you will see again in Chapter 15.
53
Chapter 3 Structures and Classes
A constant reference provides no such protection. Only the reference itself is constant.
let cannonball = Particle()
cannonball.velocity = Vector(x: 100, y: 5) // No error!
Note that constants within a class or structure are constant. The Rocket class’s thrust property,
defined with let and given an initial value in the initializer, cannot be changed:
let rocket = Rocket(thrust: 10.0, thrustTime: 60.0)
rocket.thrust = 3 // Error: Cannot assign 'thrust' in 'rocket'
You can improve this by conforming to the Printable protocol, which looks like this:
protocol Printable {
var description: String { get }
}
We will cover protocols in more detail in Chapter 6, but the short version is that a protocol defines a
set of properties or methods. In order to conform to a protocol, your type must implement the required
properties and methods.
54
Swift and Objective-C
To conform to Printable, you must implement a read-only computed property called description to
return a String. Start by declaring that Vector conforms to Printable:
struct Vector {
struct Vector: Printable {
var x: Double
var y: Double
NSString *newString;
newString = [originalString stringByReplacingOccurrencesOfString: @"Mavericks"
withString: @"Yosemite"];
In this example, the receiver is originalString, an instance of NSString, and the selector is
stringByReplacingOccurrencesOfString:withString:. The parameters are the two NSString
literals.
Note that the selector in the message is “the name of the method.” It is not the method itself or even a
reference to it. You can think of a selector as a glorified string.
Objective-C classes know how to receive a message, match the selector with a method of the same
name, and execute the method. Or they can do something else with the selector, like forward it in
a message to another class. Relying on selectors and message-passing is relatively unique among
languages in modern use, and its dynamic nature made the powerful design patterns of Cocoa, and later
iOS, possible.
55
Chapter 3 Structures and Classes
Calling a method is a cut-and-dried process. Either the object implements the method or it does not,
and this can be determined at compile time. Passing a message, on the other hand, is dynamic. At
runtime, the object is asked, “Does your class implement a method with this name?” If yes, the method
with that name is executed. If no, the message is run up the inheritance hierarchy: The superclass
is asked, “Do you have a method with this name?” If that class does not have the method, then its
superclass is asked, and so on. If the message reaches NSObject at the top of the hierarchy, and
NSObject says, “No, I do not have a method with that name,” then an exception occurs, and your app
will halt.
You are developing in Swift, which means that you are not writing message sends in code; you are
calling methods. These Swift methods have to be named in such a way that the Swift compiler can turn
a method call into a message send when the receiver is an Objective-C object.
If you were to write the above message send in Swift, it would look like this:
Remember, the Swift method has two parameters in the parameter list, but only one has a
name. This is why you see methods named in this text and in Apple’s documentation with
underscores where you expect a parameter name. For example, this method is listed as
stringByReplacingOccurrencesOfString(_:withString:).
Basic bridging
Swift types are automatically bridged to their Foundation counterparts:
Another class that you may see is NSNumber. Because Foundation collections can only store objects, in
order to store numbers they must be represented by an object. NSNumber is the class that Objective-C
programmers use for this task. Swift numbers also bridge easily with NSNumber:
56
Bridging with collections
You may be surprised to learn that Foundation collections can hold any kind of object – that is, the
collection’s contents do not have to be of the same type! You will see the Swift type AnyObject used
with these collections, like this: [AnyObject]. (If you are familiar with Objective-C, AnyObject has the
same meaning as id.)
The solutions to this problem are similar to unwrapping optionals: there are safe and unsafe paths. The
unsafe path is to use as!, the forced cast operator:
let swiftArray: [Int] = objcArray as! [Int]
As with forced unwrapping, if the type cannot be cast successfully your app will crash. If you
are certain that the type is correct, such as when the value is coming from a known API, this is a
reasonable assumption to make.
If you are not so certain, you should use the optional type casting operator as?, which will evaluate to
nil if the values cannot be safely cast:
This situation is most commonly seen with Cocoa APIs using NSDictionary: it is typical for the keys
to all be NSStrings, but the types of the values commonly differ depending on the key. We will further
discuss how to handle these untyped collections safely in Chapter 28.
Suppose you were working with an Objective-C class that supplied a dictionary. When Swift imports
the class, it does a basic level of conversion, but it does not know what type the method actually
returns, so it is shown as [NSObject : AnyObject]!:
To work with this API you first need to know the actual types contained in the dictionary, which can
usually be found in the documentation. You will then need to safely cast the result to Swift types:
57
Chapter 3 Structures and Classes
It is important to remember that Swift strings and collections are value types and the Foundation types
are all reference types. While Swift’s compiler can enforce the constant-ness of an array, with NSArray
the same array object may be referenced by many parts of an application.
The Foundation classes we have discussed so far are all immutable, meaning that they cannot be
changed – equivalent to being defined with Swift’s let. Each of them has a mutable subclass:
NSMutableArray, NSMutableString, and so forth. This has less of an impact on Swift code, but it is
important to watch out for if you are working with a significant body of Objective-C code. Because it
is a reference type, an instance of NSMutableArray could be changed by any code that has a reference
to it.
Runtime Errors
Despite your best efforts, things will sometimes go wrong while your app is running. In Cocoa, these
errors fall into two categories.
Programmer errors are situations that should never happen, which means that they are the result of,
well, a mistake you made. (We say they should never happen… but we have made plenty of these.)
Examples include not meeting the precondition of a method (the index was not within the array’s
bounds), performing an illegal operation (such as force-casting incorrectly or force-unwrapping a nil),
or sending a message to an Objective-C object that does not understand it.
Swift alerts you to programmer errors by trapping, which results in stopping the program. Cocoa APIs
use Objective-C exceptions. A trap is typically accompanied by a fatal error line in the console,
while exceptions have much longer output showing the full stack. Note that Swift does not presently
support exceptions.
Recoverable errors, on the other hand, are errors that your application can check for, deal with, and
move on from. Examples include being unable to contact a remote server, errors parsing data, or
lacking hardware capabilities.
Recoverable errors will be communicated to your code through the return values of methods (such as
a nil return). For more sophisticated APIs, especially those involving I/O, an NSError object will be
used. You will learn about NSError in Chapter 12.
You can code defensively and check preconditions in your own code using assert() and
fatalError(). For example:
fatalError() is useful in methods that are declared to return a value. The Swift compiler requires that
all code paths return a value – unless you call a noreturn function like fatalError():
58
More Exploring of Apple’s Swift Documentation
59
This page intentionally left blank
Index API Reference, 88
App Store (distribution), 507-509
AppDelegate
513
Index
514
Index
515
Index
516
Index
517
Index
518
Index
519
Index
520
Index
521
Index
in Swift, 36 action, 78
.lprojfiles (localization), 379 explained, 55, 56
and NSInvocation, 189
M methods
(see also individual method names, initializers,
Mac App Store (distribution), 507-509
messages, properties)
Mac Developer Program, xviii
(_: ), meaning of, 43
main bundle, 390
about, 43
main thread, 479
action, 81
managed object model (Core Data), 221
application lifecycle, 115
managedObjectContext (NSArrayController),
class, 121
223
in classes, 46
map(), 256
data source, 121, 129
// MARK:, 105
defined, 27, 34
master/detail interfaces, 444
delegate, 268
maxValue (NSSlider), 83
in enums, 43
mediated file access, 506
in extensions, 318
memory management
KVC, 135
and arrays, 63
KVO, 141
in closures, 252, 253
naming conventions, 43
and delegate, 112
optional, 110, 116
and Instruments, 483
parameters, 43
manual reference counting, 68
in protocols, 110
need for, 61
required, 110
and notifications, 267
spelling errors in, 114
of windows, 444
static, 27
for reference types, 61
stepping through, 149, 150
reference counting, 61-65
in structures, 43
strong reference cycles, 65-67
minValue (NSSlider), 83
strong references, 65
modal alerts, 249, 250
and timers, 343
modal windows, 355
unowned references, 67
model key path, 139
for value types, 61
model layer (MVC), 5
weak references, 65, 67
binding to array controller, 163, 164
and zombie objects, 98
encapsulating in web services, 409
menu items
and table views, 120
creating in Interface Builder, 319
Model-View-Controller (MVC)
disabling, 329
(see also application architecture, controller
hooking up, 263, 264
layer, model layer, view layer)
and keyboard events, 310
defined, 4-6
and NSDocument, 207, 209
and web services, 407, 409
and NSDocumentController, 207
modifierFlags (NSEvent), 297, 307
state, 329
modules, 427
targets of, 326-328
modules (product), 162
validating, 329
mouse events
messageFontOfSize(_: ) (NSFont), 313
(see also events, first responder, NSEvent)
messages
checking click count, 298
(see also methods)
double-clicks, 298
522
Index
N content, 161
managedObjectContext, 223
navigators (Xcode)
selectionIndexes, 161, 169
about, 3
subclassing for custom objects, 237
breakpoint, 151
NSAttributedString, 314-317
debug, 148
(see also NSString, strings)
project, 3
NSBezierPath, 276
needsDisplay (NSView), 278
NSBox, 449, 452, 455
nested types, 411
NSBundle, 390-393
nextKeyView (NSView), 310
NSButton, 10
nextResponder (NSResponder), 327
(see also buttons)
NeXTSTEP, xviii-xx, 5
NSCell, 80
NIB files
NSClipView, 125
(see also XIB files)
NSCoder, 204-206
defined, 14
NSCoding (protocol), 204-206
loading, 75-77
NSColor, 90, 91, 95
and loading documents, 209
NSColorWell, 89
and localization, 380
NSComparisonResult, 176
names of, 24-26
NSControl
naming conventions for, 72
(see also controls)
523
Index
524
Index
525
Index
526
Index
527
Index
R reverse(), 34
RoboCop, 109
race conditions (multithreading), 480, 481
run loops, 343, 493
radio buttons (NSButton), 97
runModal() (NSAlert), 250
Range, 37
runModalForWindow(_: ) (NSApplication), 355
rawValue (enums), 39
runtime errors, 58
readFromData(_:ofType:error: ) (NSDocument),
209
readFromFileWrapper(_:ofType:error: ) S
(NSDocument), 209 sandboxing (applications), 505-507
readFromURL(_:ofType:error: ), 491 saveGraphicsState() (NSGraphicsContext),
readFromURL(_:ofType:error: ) (NSDocument), 284
209 saving documents, 207, 218
readObjects(_:options:) (NSPasteboard), 324 saving objects, 211
receipt validation, 507-509 SAX parsing, 421
receivers, 55 scenes (storyboards), 457, 463, 470
recoverable errors, 58 scheduledTimerWithTimeInterval (NSTimer),
rectForPage(_:) (NSView), 398 342
redo stack, 190 Scheme Editor, 500, 502, 503
reduce(), 256 scroll views, 125, 291
reference counting, 61-65, 68 scrollers, 125
reference types, 53, 54 Sculley, John, xviii
references, strong, 65 segues (storyboards), 457, 459
references, unowned, 67 selectionIndexes (NSArrayController), 161,
references, weak, 65 169
registerDefaults(_:) (NSUserDefaults), 240 selectors, 55
registerForDraggedTypes(_: ), 337 selectTab(_: ), 451
registerForDraggedTypes(_: ) (NSView), 337, selectTabAtIndex(_: ), 451
338 self
relationships (Core Data), 221 in closures, 252
release builds, 98, 499, 503, 504 in initializers, 42
reloadData() (NSTableView), 134 in instance methods, 44
removeFromSuperview() (NSView), 449 and property names, 17
removeObjectForKey(_:) (NSUserDefaults), sendAction(_:to:from: ) (NSApplication), 330
240 sender (action methods), 81
removeObserver(_:) (NSNotificationCenter), setBool(_:forKey:) (NSUserDefaults), 240
260 setData(_:forType: ) (NSPasteboardItem), 325
representedObject, 454 setFloat(_:forKey:) (NSUserDefaults), 240
resignFirstResponder() (NSResponder), 307 setInteger(_:forKey:) (NSUserDefaults), 240
resources setNeedsDisplayInRect(_: ) (NSView), 295
(see also bundles) setNilValueForKey(_: ), 146
application access to, 505 setObject(_:forKey:) (NSUserDefaults), 240
for future learning, 511, 512 setPropertyList(_:forType: )
in bundles, 390, 391 (NSPasteboardItem), 325
localizing, 379 sets, 32, 33
responder chain, 327, 328 setString(_:forType: ) (NSPasteboardItem),
restoreGraphicsState() (NSGraphicsContext), 325
284 setUp(), 424, 429
528
Index
529
Index
530
Index
531
Index
532
Index
Z
zip files
for distribution, 505
inspecting, 489
zipinfo utility, 489
zombie objects, 98
533