As a courtesy, this is a full free rendering of my book, Programming iOS 6, by Matt Neuburg. Copyright 2013 Matt Neuburg. Please note that this book has now been completely superseded by two more recent books, iOS 7 Fundamentals and Programming iOS 7. If my work has been of help to you, please consider purchasing one or both of them. Thank you!

Chapter 3. Objective-C Objects and Messages

One of the first object-based programming languages to achieve maturity and widespread dissemination was Smalltalk. It was developed during the 1970s at Xerox PARC under the leadership of Alan Kay and started becoming widely known in 1980. The purpose of Objective-C, created by Brad Cox and Tom Love in 1986, was to build Smalltalk-like syntax and behavior on top of C. Objective-C was licensed by NeXT in 1988 and was the basis for its application framework API, NeXTStep. Eventually, NeXT and Apple merged, and the NeXT application framework evolved into Cocoa, the framework for Mac OS X applications, still revolving around Objective-C. That history explains why Objective-C is the base language for iOS programming. (It also explains why Cocoa class names often begin with “NS” — it stands for “NeXTStep.”)

Having learned the basics of C (Chapter 1) and the nature of object-based programming (Chapter 2), you are ready to meet Objective-C. This chapter describes Objective-C structural fundamentals; the next two chapters provide more detail about how Objective-C classes and instances work. (A few additional features of the language are discussed in Chapter 10.) As with the C language, my intention is not to describe the Objective-C language completely, but to provide a practical linguistic grounding, founded on my own experience of those aspects of the language that need to be firmly understood as a basis for iOS programming.

An Instance Reference Is a Pointer

In C, every variable must be declared to be of some type. In an object-based language such as Objective-C, an instance’s type is its class. The C language includes very few basic data types. To facilitate the multiplicity of class types required by its object-based nature, Objective-C takes advantage of C pointers. So, in Objective-C, if a variable is an instance of the class MyClass, that variable is of type MyClass* — a pointer to a MyClass. In general, in Objective-C, a reference to an instance is a pointer and the name of the data type of what’s at the far end of that pointer is the name of the instance’s class.

Tip

Note the convention for capitalization. Variable names tend to start with a lowercase letter; class names tend to start with an uppercase letter.

As I mentioned in Chapter 1, the fact that a reference to an instance is a pointer in Objective-C will generally not cause you any difficulties, because pointers are used consistently throughout the language. For example, a message to an instance is directed at the pointer, so there is no need to dereference the pointer. Indeed, having established that a variable representing an instance is a pointer, you’re likely to forget that this variable even is a pointer and just work directly with that variable:

NSString* s = @"Hello, world!";
NSString* s2 = [s uppercaseString];

Having established that s is an NSString*, you would never dereference s (that is, you would never speak of *s) to access the “real” NSString. So it feels as if the pointer is the real NSString. Thus, in the previous example, once the variable s is declared as a pointer to an NSString, the uppercaseString message is sent directly to the variable s. (The uppercaseString message asks an NSString to generate and return an uppercase version of itself; so, after that code, s2 is @"HELLO, WORLD!")

The tie between a pointer, an instance, and the class of that instance is so close that it is natural to speak of an expression like MyClass* as meaning “a MyClass instance,” and of a MyClass* value as “a MyClass.” A Objective-C programmer will say simply that, in the previous example, sis an NSString, that uppercaseString returns “an NSString,” and so forth. It is fine to speak like that, and I do it myself (and will do it in this book) — provided you remember that this is a shorthand. Such an expression means “an NSString instance,” and because an instance is represented as a C pointer, it means an NSString*, a pointer to an NSString.

Although the fact that instance references in Objective-C are pointers does not cause any special difficulty, you must still be conscious of what pointers are and how they work. As I emphasized in Chapter 1, when you’re working with pointers, you must keep in mind the special meaning of your actions. So here are some basic facts about pointers that you should keep in mind when working with instance references in Objective-C.

Warning

Forgetting the asterisk in an instance declaration is a common beginner mistake, and will net you a mysterious compiler error message, such as “Interface type cannot be statically allocated.”

Instance References, Initialization, and nil

After that declaration, s is typed as a pointer to an NSString, but it is not in fact pointing to an NSString. You have created a pointer, but you haven’t supplied an NSString for it to point to. It’s just sitting there, waiting for you to point it at an NSString, typically by assignment (as we did with @"Hello, world!" earlier). Such assignment initializes the variable, giving it an actual meaningful value of the proper type.

You can declare a variable as an instance reference in one line of code and initialize it later, like this:

NSString* s;
// ... time passes ...
s = @"Hello, world!";

But this is not common. It is much more common, wherever possible, to declare and initialize a variable all in one line of code:

NSString* s = @"Hello, world!";

Declaration without initialization, before the advent of ARC in iOS 5 (Chapter 12), created a dangerous situation:

NSString* s;

What iss after a mere declaration like that? It could be anything. But it is claiming to be a pointer to an NSString, and so your code might proceed to treat it as a pointer to an NSString. But it is pointing at garbage. A pointer pointing at garbage is liable to cause serious trouble down the road when you accidentally try to use it as an instance. Sending a message to a garbage pointer, or otherwise treating it as a meaningful instance, can crash your program. Even worse, it might not crash your program: it might cause your program to behave very, very oddly instead — and figuring out why can be difficult.

For this reason, if you aren’t going to initialize an instance reference pointer at the moment you declare it by assigning it a real value, it’s a good idea to assign it nil:

NSString* s = nil;

A small but delightful bonus feature of using ARC is that this assignment is performed for you, implicitly and invisibly, as soon as you declare a variable without initializing it:

NSString* s; // under ARC, s is immediately set to nil for you

This prevents the existence of a garbage pointer, and could save you from yourself by preventing a crash when you accidentally use s as an instance without initializing it. Nevertheless, long years of habit have trained me to initialize or explicitly set to nil an instance pointer as soon as I declare it, and you’ll see that I continue to do so in examples in this book.

What is nil? It’s simply a form of zero — the form of zero appropriate to an instance reference. The nil value simply means: “This instance reference isn’t pointing to any instance.” Indeed, you can test an instance reference against nil as a way of finding out whether it is in fact pointing to a real instance. This is an extremely common thing to do:

if (nil == s) // ...

As I mentioned in Chapter 1, the explicit comparison with nil isn’t strictly necessary; because nil is a form of zero, and because zero means false in a condition, you can perform the same test like this:

if (!s) // ...

I do in fact write nil tests in that second form all the time, but some programmers would take me to task for bad style. The first form has the advantage that its real meaning is made explicit, rather than relying on a cute implicit feature of C. The first form places nil first in the comparison so that if the programmer accidentally omits an equal sign, performing an assignment instead of a comparison, the compiler will catch the error (because assignment to nil is illegal).

Many Cocoa methods use a return value of nil, instead of an expected instance, to signify that something went wrong. You are supposed to capture this return value and test it for nil in order to discover whether something did go wrong. For example, the documentation for the NSString class method stringWithContentsOfFile:encoding:error:
says that it returns “a string created by reading data from the file named by path using the encoding, enc. If the file can’t be opened or there is an encoding error, returns nil.” So, as I described in Chapter 1, your next move after calling this method and capturing the result should be to test that result against nil, just to make sure you’ve really got an instance now:

You should now be wondering about the implications of a nil-value pointer for sending a message to a noninstance. For example, you can send a message to an NSString instance like this:

NSString* s2 = [s uppercaseString];

That code sends the uppercaseString message to s. So s is supposedly an NSString instance. But what if s is nil? With some object-based programming languages, sending a message to nil constitutes a runtime error and will cause your program to terminate prematurely (REALbasic and Ruby are examples). But Objective-C doesn’t work like that. In Objective-C, sending a message to nil is legal and does not interrupt execution. Moreover, if you capture the result of the method call, it will be a form of zero — which means that if you assign that result to an instance reference pointer, it too will be nil:

Whether this behavior of Objective-C is a good thing is a quasi-religious issue and a subject of vociferous debate among programmers. It is useful, but it is also extremely easy to be tricked by it. The usual scenario is that you accidentally send a message to a nil reference without realizing it, and then later your program doesn’t behave as expected. Because the point where the unexpected behavior occurs is later than the moment when the nil pointer arose in the first place, the genesis of the nil pointer can be difficult to track down (indeed, it often fails to occur to the programmer that a nil pointer is the cause of the trouble in the first place).

Short of peppering your code with tests to ascertain that your instance reference pointers are not accidentally nil, which is not generally a good idea, there isn’t much you can do about this. This behavior is strongly built into the language and is not going to change. It’s just something you need to be aware of.

If, on the other hand, a method call can return nil, be conscious of that fact. Don’t assume that everything will go well and that it won’t return nil. On the contrary, if something can go wrong, it probably will. For example, to omit the nil test after calling stringWithContentsOfFile:encoding:error: is just stupid. I don’t care if you know perfectly well that the file exists and the encoding is what you say it is — test the result for nil!

Note

In pure C code, you will sometimes see a pointer-to-nothing expressed as NULL. NULL and nil are functionally equivalent nowadays, and I’ll use nil exclusively in this book.

Instance References and Assignment

As I said in Chapter 1, assigning to a pointer does not mutate the value at the far end of the pointer; rather, it repoints the pointer. Moreover, assigning one pointer to another repoints the pointer in such a way that both pointers are now pointing to the very same thing. Failure to keep these simple facts firmly in mind can have results that range from surprising to disastrous.

For example, instances in general are usually mutable: they typically have instance variables that can change. If two references are pointing at one and the same instance, then when the instance is mutated by way of one reference, that mutation also affects the instance as seen through the other reference. To illustrate, pretend that we’ve implemented the Stack class described in the previous chapter:

After we pop myStack2, s is @"World" even though nothing was ever pushed onto myStack2 (and the stack myStack1 contains only @"Hello" even though nothing was ever popped off of myStack1). That’s because we did push two strings onto myStack1 and then pop one string off myStack2, and myStack1ismyStack2 — in the sense that they are both pointers to the very same stack instance. That’s perfectly fine, as long as you understand and intend this behavior.

In real life, you’re likely to pass an instance off to some other object, or to receive it from some other object:

After that code, myObject has a pointer to the very same instance we’re already pointing to as myStack. So we must be careful and thoughtful. The object myObject might mutate myStack right under our very noses. Even more, the object myObject might keep its reference to the stack instance and mutate it later — possibly much later, in a way that could surprise us. This is possible because instances can have instance variables that point to other objects, and those pointers can persist as long as the instances themselves do. This kind of shared referent situation can be intentional, but it is also something to watch out for and be conscious of (Figure 3.1).

Figure 3.1. Two instances end up with pointers to the same third instance

Another possible misunderstanding is to imagine that the assignment myStack2 = myStack1 somehow makes a new, separate instance that duplicates myStack1. That’s not at all the case. It doesn’t make a new instance; it just points myStack2 at the very same instance that myStack1 is pointing at. It may be possible to make a new instance that duplicates a given instance, but the ability to do so is not a given and it is not going to happen through mere assignment. (For how a separate duplicate instance might be generated, see the NSCopying protocol and the copy method mentioned in Chapter 10.)

Instance References and Memory Management

The pointer nature of instance references in Objective-C also has implications for management of memory. The scope, and in particular the lifetime, of variables in pure C is typically quite straightforward: if you bring a piece of variable storage into existence by declaring that variable within a certain scope, then when that scope ceases to exist, the variable storage ceases to exist. That sort of variable is called automatic (K&R 1.10). So, for example:

void myFunction() {
int i; // storage for an int is set aside
i = 7; // 7 is placed in that storage
} // the scope ends, so the int storage and its contents vanish

But in the case of a pointer, there are two pieces of memory to worry about: the pointer itself, which is an integer signifying an address in memory, and whatever is at that address, at the far end of that pointer. Nothing about the C language causes the destruction of what a pointer points to when the pointer itself is automatically destroyed as it goes out of scope:

void myFunction() {
NSString* s = @"Hello, world!"; // pointer and NSString
NSString* s2 = [s uppercaseString]; // pointer and NSString
} // the two pointers go out of existence...
// ... but what about the two NSStrings they point to?

Some object-based programming languages in which a reference to an instance is a pointer do manage automatically the memory pointed to by instance references (REALbasic and Ruby are examples). But Objective-C, at least the way it’s implemented when you’re programming for iOS, is not one of those languages. Because the C language has nothing to say about the automatic destruction of what is pointed to by a reference to an instance, Objective-C implements an explicit mechanism for the management of memory. I’ll talk in a later chapter (Chapter 12) about what that mechanism is and what responsibilities for the programmer it entails. Fortunately, under ARC, those responsibilities are fewer than they used to be; but memory must still be managed, and you must still understand how memory management works.

Messages and Methods

An Objective-C method is defined as part of a class. It has three aspects:

Whether it’s a class method or an instance method

If it’s a class method, you call it by sending a message to the class itself. If it’s an instance method, you call it by sending a message to an instance of the class.

Its parameters and return value

As with a C function, an Objective-C method takes some number of parameters; each parameter is of some specified type. And, as with a C function, it may return a value, which is also of some specified type; if the method returns nothing, its return type is declared as void.

Its name

An Objective-C method’s name must contain as many colons as it takes parameters. The name is split after each colon in a method call or declaration, so it is usual for the part of the name preceding each colon to describe the corresponding parameter.

Sending a Message

As you’ve doubtless gathered, the syntax for sending a message to an object involves square brackets. The first thing in the square brackets is the object to which the message is to be sent; this object is the message’s receiver. Then follows the message:

You can send a class method to a class, and an instance method to an instance, no matter how you got hold of and represent the class or the instance. For example, @"Hello, world!" is itself an NSString instance, so it’s legal to say:

NSString* s2 = [@"Hello, world!" uppercaseString];

If a method takes no parameters, then its name contains no colons, like the NSString instance method uppercaseString. If a method takes one parameter, then its name contains one colon, which is the final character of the method name, like the hypothetical Stack instance method push:. If a method takes two or more parameters, its name contains that number of colons. In the minimal case, its name ends with that number of colons. For example, a method taking three parameters might be called hereAreThreeStrings:::. To call it, we split the name after each colon and follow each colon with an argument, which looks like this:

That’s a legal way to name a method, but it isn’t very common, mostly because it isn’t very informative. Usually the name will have more text; in particular, the part before each colon will describe the parameter that follows that colon.

For example, there’s a UIColor class method for generating an instance of a UIColor from four CGFloat numbers representing its red, green, blue, and alpha (transparency) components, and it’s called colorWithRed:green:blue:alpha:. Notice the clever construction of this name. The colorWith part tells something about the method’s purpose: it generates a color, starting with some set of information. All the rest of the name, Red:green:blue:alpha:, describes the meaning of each parameter. And you call it like this:

The space after each colon in the method call is optional. (Space before a colon is also legal, though in practice one rarely sees this.)

The rules for naming an Objective-C method, along with the conventions governing such names (like trying to make the name informative about the method’s purpose and the meanings of its parameters), lead to some rather long and unwieldy method names, such as getBytes:maxLength:usedLength:encoding:options:range:remainingRange:. Such verbosity of nomenclature is characteristic of Objective-C. Method calls, and even method declarations, are often split across multiple lines to prevent a single line of code from becoming so long that it wraps within the editor, as well as for clarity.

Declaring a Method

The declaration for a method has three parts:

Either + or -, meaning that the method is a class method or an instance method, respectively.

The data type of the return value, in parentheses.

The name of the method, split after each colon. Following each colon is the corresponding parameter, expressed as the data type of the parameter, in parentheses, followed by a placeholder name for the parameter.

So, for example, Apple’s documentation tells us that the declaration for the UIColor class method colorWithRed:green:blue:alpha: is:

(Note that I’ve split the declaration into two lines, for legibility and to fit onto this page. The documentation puts it all on a single line.)

Make very sure you can read this declaration! You should be able to look at it and say to yourself instantly, “The name of this method is colorWithRed:green:blue:alpha:. It’s a class method that takes four CGFloat parameters and returns a UIColor.”

It is not uncommon, outside of code, to write a method’s name along with the plus sign or the minus sign, to make it clear whether this is a class method or an instance method. So you might speak informally of “-uppercaseString,” just as a way of reminding yourself or a reader that this is an instance method. Again outside of code, it is not uncommon, especially when communicating with other Objective-C programmers, to speak of a method’s name along with the class in which this method is defined. So you might say “NSString’s -uppercaseString,”
or even something like “-[NSString uppercaseString].” Notice that that isn’t code, or even pseudo-code, because you are not actually speaking of a method call, and in any case you could never send the uppercaseString message to the NSString class; it’s just a compact way of saying, “I’m talking about the uppercaseString that’s an instance method of NSString.”

Nesting Method Calls

Wherever in a method call an object of a certain type is supposed to appear, you can put another method call that returns that type. Thus you can nest method calls. A method call can appear as the message’s receiver:

NSString* s = [[NSString string] uppercaseString]; // silly but legal

That’s legal because NSString’s class method string returns an NSString instance (formally, an NSString* value, remember), so we can send an NSString instance method to that result. Similarly, a method call can appear as an argument in a method call:

However, I must caution you against overdoing that sort of thing. Code with a lot of nested square brackets is very difficult to read (and to write). Furthermore, if one of the nested method calls happens to return nil unexpectedly, you have no way to detect this fact. It is often better, then, to be even more verbose and declare a temporary variable for each piece of the method call. Just to take an example from my own code, instead of writing this:

Even though the first version is quite short and legible, and even though in the second version the variable query will never be used again — it exists solely in order to be the receiver of the collections message in the second line — it is worth creating it as a separate variable. For one thing, it makes this code far easier to step through in the debugger later on, when I want to pause after the albumsQuery call and see whether the expected sort of result is being returned.

Note

Incorrect number or pairing of nested square brackets can net you some curious messages from the compiler. For example, too many pairs of square brackets ([[query collections]]) or an unbalanced left square bracket ([[query collections]) is reported as “Expected identifier.”

No Overloading

The data type returned by a method, together with the data types of each of its parameters in order, constitute that method’s signature. It is illegal for two methods of the same type (class method or instance method) to exist in the same class with the same name but different signatures.

So, for example, you could not have two MyClass instance methods called myMethod, one of which returns void and one of which returns an NSString. Similarly, you could not have two MyClass instance methods called myMethod:, both returning void, one taking a CGFloat parameter and one taking an NSString parameter.
An attempt to violate this rule will be stopped dead in its tracks by the compiler, which will announce a “duplicate declaration” error. The reason for this rule is that if two such conflicting methods were allowed to exist, there would be no way to determine from a method call to one of them which method was being called.

You might think that the issue could be decided by looking at the types involved in the call. If one myMethod: takes a CGFloat parameter and the other myMethod: takes an NSString parameter, you might think that when myMethod: is called, Objective-C could look at the actual argument and realize that the former method is meant if the argument is a CGFloat and the latter if the argument is an NSString. But Objective-C doesn’t work that way. There are languages that permit this feature, called overloading, but Objective-C is not one of them.

Parameter Lists

It isn’t uncommon for an Objective-C method to require an unknown number of parameters. A good example is the NSArray class method arrayWithObjects:, which looks from the name as if it takes one parameter but in fact takes any number of parameters, separated by comma. The parameters are the objects of which the NSArray is to consist. The trick here, however, which you must discover by reading the documentation, is that the list must end with nil. The nil is not one of the objects to go into the NSArray (nil isn’t an object, so an NSArray can’t contain nil); it’s to show where the list ends.

The declaration for arrayWithObjects: uses three dots to show that a comma-separated list is legal:

+ (id)arrayWithObjects:(id)firstObj, ... ;

Without the nil terminator, the program will not know where the list ends, and bad things will happen when the program runs, as it goes hunting off into the weeds of memory, incorporating all sorts of garbage into the NSArray that you never meant to have incorporated.

Forgetting the nil terminator is a common beginner error, but not as common as it used to be: by a bit of deep-C voodoo, the Objective-C compiler now notices if you’ve forgotten the nil, and warns you (“missing sentinel in method dispatch”). Even though it’s just a warning, don’t run that code! Another way to avoid forgetting the nil terminator is to avoid calling arrayWithObjects: altogether; this is now possible starting with LLVM compiler version 4.0 (Xcode 4.4 or later), which allows you to form a literal NSArray object directly, using @[...] syntax, like this:

NSArray* pep = @[@"Manny", @"Moe", @"Jack"];

That’s just a notation, a kind of syntactic sugar; behind the scenes, arrayWithObjects: is presumably still being called for you. But it’s being called for you correctly, nil terminator and all, so this notation is much more bullet-proof than explicitly calling arrayWithObjects: yourself; plus it’s a lot less typing. I’ll be using this new Objective-C notation for literal arrays throughout this book.

Nevertheless, you will still encounter other Objective-C methods that do have a parameter that’s a nil-terminated list of variable length. For example, there’s the UIAppearance protocol class method appearanceWhenContainedIn: (Chapter 25), or UIAlertView’s initWithTitle:message:delegate:cancelButtonTitle:otherButtonTitles: (Chapter 26). It’s a pity that Apple hasn’t somehow tweaked Objective-C or these methods to avoid the use of the nil terminator; for instance, they could have made the variable-length list parameter into an NSArray parameter instead. But until they do, knowing how to call such methods remains important.

The C language has explicit provision for argument lists of unspecified length, which Objective-C methods such as arrayWithObjects: are using behind the scenes. I’m not going to explain the C mechanism, because I don’t expect you’ll ever write a method or function that requires it; see K&R 7.3 if you need the gory details.

Unrecognized Selectors

Objective-C messaging is dynamic, meaning that the compiler takes no formal responsibility for whether a particular object is a legal recipient of a given message. That’s because whether an object can deal with a message sent to it isn’t decided until the program actually runs and the message actually arrives. Objective-C has various devices for dealing at runtime with a message that doesn’t correspond directly to a method, and for all the compiler knows, one of them might come into play in this case. For example, at the time the program runs, the recipient of the message might be nil — and it’s harmless to send any message to nil.

Thus, it is theoretically legal to direct a message at an object with no corresponding method. The only guardian against this possibility is the compiler. Before ARC, the compiler was not a very strong guardian in this respect. For example:

An NSString has no method rockTheCasbah. But the (non-ARC) compiler will not stop you from running a program containing this code; it’s legal. The compiler will warn you, but it won’t stop you. There are actually two possible warnings:

If no rockTheCasbah method is defined anywhere in your code, the compiler will say: “Instance method ‘-rockTheCasbah’ not found (return type defaults to ‘id’).” Without going into the details, what the compiler means is: “I know of no instance method rockTheCasbah, so I can’t check its signature against the return type and arguments you’re actually using, so I’ll just make some loose assumptions and let it pass.”

If a rockTheCasbah method is defined somewhere in your code, the compiler will say: “‘NSString’ may not respond to ‘rockTheCasbah’.” This means: “There’s a rockTheCasbah method, all right, but you seem to be sending the rockTheCasbah method to an instance of a class that doesn’t have it as an instance method.”

This is a good example of what I meant in Chapter 2 when I said that sending a message and calling a method were not the same thing. The compiler is saying that NSString has no rockTheCasbah instance method, but that it isn’t going to stop you from sending an NSString a rockTheCasbah message. At runtime, the object that receives the rockTheCasbah message might be able to deal with it, for all the compiler knows.

With ARC, however, the compiler is much stricter. The example above won’t compile at all under ARC! The compiler declares a fatal compilation error: “Receiver type ‘NSString’ for instance message does not declare a method with selector ‘rockTheCasbah’.” There is no NSString method rockTheCasbah, and by golly the compiler isn’t going to let you send the rockTheCasbah message to an NSString, and that’s final.

This is another of those delightful secondary benefits of using ARC. In order to do what it primarily does (manage memory), ARC must insist on more information about classes and their methods than the Objective-C standard calls for. Here, ARC is demanding that you prove that an NSString can respond to rockTheCasbah, or it won’t let you run this code at all. (Nevertheless, if you really want to, you can slip past even ARC’s stringent guardianship; I’ll explain how in the next section.)

Let us assume for a moment that we are compiling without ARC, or that we have somehow tricked even ARC into letting us compile successfully. Warning or no warning, we are now ready to run a program that sends the rockTheCasbah message to an NSString, and damn the consequences. What might those consequences be? Quite simply, if you send a message to an object that can’t deal with it, your program will crash at that instant. So, for example, our attempt to send an NSString the rockTheCasbah message will crash our program, with a message (in the console log) of this form: “-[NSCFConstantString rockTheCasbah]: unrecognized selector sent to instance 0x3048.”

The important thing here is the phrase unrecognized selector. The term “selector”
is roughly equivalent to “message,”
so this is a way of saying that a certain instance was sent a message it couldn’t deal with. The console message also tries to tell us what instance this was. 0x3048 is the value of the instance pointer; it is the address in memory to which our NSString* variable s was actually pointing. (Never mind why the NSString is described as an NSCFConstantString; this has to do with NSString’s implementation behind the scenes.)

(Strictly speaking, I should not say that a situation like this will “crash our program.” What it will actually do is to generate an exception, an internal message as the program runs signifying that something bad has happened. It is possible for Objective-C code to “catch” an exception, in which case the program will not crash. The reason the program crashes, technically, is not that a message was sent to an object that couldn’t handle it, but that the exception generated in response wasn’t caught. That’s why the crash log may also say, “Terminating app due to uncaught exception.”)

Typecasting and the id Type

One way to silence the compiler when it warns in the way I’ve just described is by typecasting. A typecast, however, is not a viable way of fixing the problem unless it also tells the truth. It is perfectly possible to lie to the compiler by typecasting; this is not nice, and is not likely to yield nice consequences.

For example, suppose we’ve defined a class MyClass that does contain an instance method rockTheCasbah. As a result, it is fine with the compiler if you send the rockTheCasbah message to a MyClass, although it is not fine to send the rockTheCasbah message to an NSString. So you can silence the compiler by claiming that an NSString instance is a MyClass instance:

NSString* s = @"Hello, world!";
[(MyClass*)s rockTheCasbah];

The typecast silences the compiler; there is no warning. Notice that the typecast is not a value conversion; it’s merely a claim about what the type will turn out to be at runtime. You’re saying that when the program runs, s will magically turn out to be a MyClass instance. Because MyClass has a rockTheCasbah instance method, that silences the compiler. Of course, you’ve lied to the compiler, so when the program runs it will crash anyway, in exactly the same way as before! You’re still sending an NSString a message it can’t deal with, so the very same exception about sending an unrecognized selector to an NSCFConstantString instance will result. So don’t do that!

Sometimes, however, typecasting to silence the compiler is exactly what you do want to do. This situation quite often arises in connection with class inheritance. We haven’t discussed class inheritance yet, but I’ll give an example anyway. Let’s take the built-in Cocoa class UINavigationController. Its topViewController method is declared to return a UIViewController instance. In real life, though, it is likely to return an instance of some class you’ve created. So in order to call a method of the class you’ve created on the instance returned by topViewController without upsetting the compiler, you have to reassure the compiler that this instance really will be an instance of the class you’ve created. That’s what I’m doing in this line from one of my own apps:

The expression (RootViewController*) is a typecast in which I’m assuring the compiler that at this moment in the program, the value returned by the topViewController method call will in fact be an instance of RootViewController, which is my own defined class. The typecast silences the compiler when I send this instance the setAlbums: message, because my RootViewController class has a setAlbums: instance method and the compiler knows this. And the program doesn’t crash, because I’m not lying: this topViewController method call really will return a RootViewController instance.

Objective-C also provides a special type designed to silence the compiler’s worries about object data types altogether. This is the id type. An id is a pointer, so you don’t say id*. It is defined to mean “an object pointer,” plain and simple, with no further specification. Thus, every instance reference is also an id.

Use of the id type causes the compiler to stop worrying about the relationship between object types and messages. The compiler can’t know anything about what the object will really be, so it throws up its hands and doesn’t warn about anything. Moreover, any object value can be assigned or typecast to an id, and a value typed as an id can be assigned where any object type is expected. The notion of assignment includes parameter passing. So you can pass a value typed as an id as an argument where a parameter of some particular object type is expected, and you can pass any object as an argument where a parameter of type id is expected. (I like to think of an id as analogous to both type AB blood and type O blood: it is both a universal recipient and a universal donor.) So, for example:

The second line is legal, because any object value can be assigned to an id. The third line doesn’t generate any compiler warning, because any message can be sent to an id. (Of course the program will still crash when it actually runs and unknown turns out to be an NSString — which is incapable of receiving of the rockTheCasbah message!)

That trick works even under ARC, with one caveat. ARC is willing to let that code compile — but only if a matching rockTheCasbah method is defined somewhere in your code (even if it isn’t an NSString method). If there’s no such method, ARC will stop you with a different error: “No known instance method for selector ‘rockTheCasbah’.” This is another way of saying the same thing the non-ARC compiler said earlier: “I know of no instance method rockTheCasbah, so I can’t check its signature against the return type and arguments you’re actually using.” But instead of implicitly adding, “So I’ll just make some loose assumptions and let it pass,” ARC is stricter. After all, even without knowing what class unknown will turn out to be when the program runs, ARC can be pretty sure that that class won’t have a rockTheCasbah method, because no known class has a rockTheCasbah method. So ARC, like a good guardian, continues to bar the way.

If, however, a matching rockTheCasbah method is defined somewhere in your code, even though it isn’t an NSString method, ARC now takes its hands off the tiller entirely, and permits the program to compile and run without warning. You are now sending a message to an id, and an id can legally receive any message. If you crash at runtime, that’s your problem; ARC can’t save you from yourself.

If an id’s ability to receive any message reminds you of nil, it should. I have already said that nil is a form of zero; I can now specify what form of zero it is. It’s zero cast as an id. Of course, it still makes a difference at runtime whether an id is nil or something else; sending a message to nil won’t crash the program, but sending an unknown message to an actual object will.

Thus, id is a device for turning off the compiler’s type checking altogether. Concerns about what type an object is are postponed until the program is actually running. All the compiler can do is intelligently analyze your code to see if you might be making a mistake that could matter at runtime. Using id turns off this part of the compiler’s intelligence and leaves you to your own devices.

I do not recommend that you make extensive use of id to live in a world of pure dynamism. The compiler is your friend; you should let it use what intelligence it has to catch mistakes in your code. Thus, I almost never declare a variable or parameter as an id. I want my object types to be specific, so that the compiler can help check my code.

On the other hand, the Cocoa API does make frequent use of id, because it has to. For example, consider the NSArray class, which is the object-based version of an array. In pure C, you have to declare what type of thing lives in an array; for example, you could have “an array of int.” In Objective-C, using an NSArray, you can’t do that. Every NSArray is an array of id, meaning that each element of the array can be of any object type. You can put a specific type of object into an NSArray because any specific type of object can be assigned to an id (id is the universal recipient). You can get any specific type of object back out of an NSArray because an id can be assigned to any specific type of object (id is the universal donor).

So, for example, NSArray’s lastObject method is defined as returning an id. So, given an NSArray arr, I can fetch its last element like this:

id unknown = [arr lastObject];

However, after that code, unknown can now be sent any message at all, and we are dispensing with the compiler’s type checking. Therefore, if I happen to know what type of object an array element is, I always assign or cast it to that type. For example, let’s say I happen to know that arr contains nothing but NSString instances (because I put them there in the first place). Then I will say:

NSString* s = [arr lastObject];

The compiler doesn’t complain, because an id can be assigned to any specific type of object (id is the universal donor). Moreover, from here on in, the compiler regards s as an NSString, and uses its type checking abilities to make sure I don’t send s any non-NSString messages, which is just what I wanted. And I didn’t lie to the compiler; at runtime, s really is an NSString, so everything is fine.

The compiler’s type checking is called static typing, as opposed to the dynamic behavior that takes place when the program actually runs. What I’m saying here, then, is that I prefer to take advantage of static typing as much as possible.

The Cocoa API will sometimes return an id from a method call where you might not expect it. It’s good to be conscious of this, because otherwise the compiler can mislead you into thinking you’re doing something safe when you’re not. For example, consider this code:

UIColor* c = [NSString string];

This is clearly a mistake — you’re assigning an NSString to a UIColor variable, which is likely to lead to a crash later on — but the compiler is silent. Why doesn’t the compiler warn here? It’s because the NSString string class method is declared like this:

+ (id)string

The string method returns an NSString, but its return value is typed as an id. An id can be assigned where any object type is expected, so the compiler doesn’t complain when it’s assigned to a UIColor variable. This fact is a common source of programmer mistakes (especially if the programmer is me).

Earlier, I said that it is illegal for the same class to define methods of the same type (class method or instance method) with the same name but different signatures. But I did not say what happens when two different classes declare conflicting signatures for the same method name. This is another case in which it matters whether you’re using static or dynamic typing. If you’re using static typing — that is, the type of the object receiving the message is specified — there’s no problem, because there’s no doubt which method is being called (it’s the one in that object’s class). But if you’re using dynamic typing, where the object receiving the message is an id, you might get a warning from the compiler; and if you’re using ARC, you’ll get a downright error: “Multiple methods named ‘rockTheCasbah’ found with mismatched result, parameter type or attributes.” This is another reason why method names are so verbose: it’s in order to make each method name unique, preventing two different classes from declaring conflicting signatures for the same method.

Warning

Accidentally defining your own method with the same name as an existing Cocoa method can cause mysterious problems. For example, in a recent online query, a programmer was confused because the compiler complained that his call to initWithObjects: lacked a nil terminator, even though his initWithObjects: didn’t need a nil terminator. No, hisinitWithObjects: didn’t, but Cocoa’s did, and the compiler couldn’t distinguish them because this message was being sent to an id. He should have picked a different name.

Messages as Data Type

Objective-C is so dynamic that it doesn’t have to know until runtime what message to send to an object or what object to send it to. Certain important methods actually accept both pieces of information as parameters. For example, consider this method declaration from Cocoa’s NSNotificationCenter class:

We’ll discuss later what this method does (when we talk about notifications in Chapter 11), but the important thing to understand here is that it constitutes an instruction to send a certain message to a certain object at some later, appropriate time. For example, our purpose in calling this method might be to arrange to have the message tickleMeElmo: sent at some later, appropriate time to the object myObject.

So let’s consider how we might actually make this method call. The object to which the message will be sent is here called notificationObserver, and is typed as an id (making it possible to specify any type of object to send the message to). So, for the notificationObserver parameter, we’re going to pass myObject. The message itself is the notificationSelector parameter, which has a special data type, SEL (for “selector,” the technical term for a message name). The question now is how to express the message name tickleMeElmo:.

You can’t just put tickleMeElmo: as a bare term; that doesn’t work syntactically. You might think you could express it as an NSString, @"tickleMeElmo:", but surprisingly, that doesn’t work either. It turns out that the correct way to do it is like this:

@selector(tickleMeElmo:)

The term @selector() is a directive to the compiler, telling it that what’s in parentheses is a message name. Notice that what’s in parentheses is not an NSString; it’s the bare message name. And because it is the name, it must have no spaces and must include any colons that are part of the message name.

So the rule is extremely easy: when a SEL is expected, you’ll usually pass a @selector expression. Failure to get this syntax right, however, is a common beginner error. Notice also that this syntax is an invitation to make a typing mistake, especially because there is no checking by the compiler. If myObject implements a tickleMeElmo: method and I accidentally type @selector(tickleMeElmo), forgetting the colon or making any other mistake in specifying the message name, there is no compiler error; the problem won’t be discovered until the program runs and something bad happens. (In this case, if the tickleMeElmo message without the colon is ever sent to myObject, the app will probably crash with an unrecognized selector exception.)

C Functions

Although your code will certainly call many Objective-C methods, it will also probably call quite a few C functions. For example, I mentioned in Chapter 1 that the usual way of initializing a CGPoint based on its x and y values is to call CGPointMake, which is declared like this:

CGPoint CGPointMake (
CGFloat x,
CGFloat y
);

Make certain that you can see at a glance that this is a C function, not an Objective-C method, and be sure you understand the difference in the calling syntax. To call an Objective-C method, you send a message to an object, in square brackets, with each argument following a colon in the method’s name; to call a C function, you use the function’s name followed by parentheses containing the arguments.

You might even have reason to write your own C functions as part of a class, instead of writing a method. A C function has lower overhead than a full-fledged method; so even though it lacks the object-oriented abilities of a method, it is sometimes useful to write one, as when some utility calculation must be called rapidly and frequently. Also, once in a while you might encounter a Cocoa method or function that requires you to supply a C function as a “callback.”

An example is the NSArray method sortedArrayUsingFunction:context:. The first parameter is typed like this:

NSInteger (*)(id, id, void *)

That expression denotes, in the rather tricky C syntax used for these things, a pointer to a function that takes three parameters and returns an NSInteger. The three parameters of the function are an id, an id, and a pointer-to-void (which means any C pointer). The bare name of a function (see Chapter 1) can be used as a pointer to a C function. So to call sortedArrayUsingFunction:context: you’d need to write a C function that meets this description, and use its name as the first argument.

To illustrate, I’ll write a “callback” function to sort an NSArray of NSStrings on the last character of each string. (This would be an odd thing to do, but it’s only an example!) The NSInteger returned by the function has a special meaning: it indicates whether the first parameter is to be considered less than, equal to, or larger than the second. I’ll obtain it by calling the NSString compare: method, which returns an NSInteger with that same meaning. Example 3.1 defines the function and shows how we’d call sortedArrayUsingFunction:context: with that function as our callback (assume that arr is an NSArray of strings).

CFTypeRefs

Many Objective-C objects have lower-level C counterparts, along with C functions for manipulating them. For example, besides the Objective-C NSString, there is also something called a CFString; the “CF” stands for “Core Foundation,” which is a lower-level C-based API. A CFString is an opaque C struct (“opaque” means that the elements constituting this struct are kept secret, and that you should operate on a CFString only by means of appropriate functions). As with an NSString or any other object, in your code you’ll typically refer to a CFString by way of a C pointer; the pointer to a CFString has a type name, CFStringRef (a “reference to a CFString,” evidently). You work with a CFString in pure C, by calling functions.

You might, on occasion, actually have to work with a Core Foundation type even when a corresponding object type exists. For example, you might find that NSString, for all its power, fails to implement a needed piece of functionality, which is in fact available for a CFString. Luckily, an NSString (a value typed as NSString*) and a CFString (a value typed as CFStringRef) are interchangeable: you can use one where the other is expected, though you will have to typecast in order to quiet the worries of the compiler. The documentation describes this interchangeability by saying that NSString and CFString are “toll-free bridged” to one another.

To illustrate, I’ll use a CFString to convert an NSString representing an integer to that integer (this use of CFString is unnecessary, and is just by way of demonstrating the syntax; NSString has an intValue method):

The typecast prevents the compiler from complaining, and works because NSString is toll-free bridged to CFString — in effect, behind the scenes, an NSString is a CFString.

Under ARC, that code won’t compile unless you supply a little more information. ARC, as we’ll see in Chapter 12, is about memory management; but ARC manages only Objective-C objects, not their C counterparts. So although ARC manages the memory for an NSString, it leaves memory management for a CFStringRef up to you; and in order to compile that code, it needs you to show it that you understand the memory management status of this value as it crosses the toll-free bridge. You do so like this:

The extra qualifier __bridge means: “Don’t worry, ARC, I know I’m crossing the toll-free bridge, and I assure you that this has no implications for memory management.” On the other hand, there are situations where crossing the toll-free bridge does have implications for memory management, and you may rest assured that I’ll discuss them in Chapter 12.

The pointer-to-struct C data types, whose name typically ends in “Ref”, may be referred to collectively as CFTypeRef, which is actually just the generic pointer-to-void. Thus, crossing the toll-free bridge may usefully be thought of as a cast between an object pointer and a generic pointer — that is, in general terms, from id to void* or from void* to id. Even where there is no toll-free bridging between specific types (as there is with NSString and CFString), there is always bridging at the top of the hierarchy, so to speak, between NSObject (the base object class, as explained in Chapter 4) and CFTypeRef.

Note

It is sometimes necessary to assign a CFTypeRef to an id variable or parameter. For example, a CALayer’s setContents: method (Chapter 16) expects an id parameter, but the actual value must be a CGImageRef. This is legal, because a pointer is just a pointer, but the compiler will complain unless you also typecast to an id, along with a __bridge qualifier if you’re using ARC.

Blocks

A block is an extension to the C language, introduced in Mac OS X 10.6 and available in iOS 4.0 or later. It’s a way of bundling up some code and handing off that entire bundle as an argument to a C function or Objective-C method. This is similar to what we did in Example 3.1, handing off a pointer to a function as an argument, but instead we’re handing off the code itself. The latter has some major advantages over the former, which I’ll discuss in a moment.

As an example, I’ll rewrite Example 3.1 to use a block instead of a function pointer. Instead of calling sortedArrayUsingFunction:context:, I’ll call sortedArrayUsingComparator:, which takes a block as its parameter. The block is typed like this:

NSComparisonResult (^)(id obj1, id obj2)

That’s similar to the syntax for specifying the type of a pointer to a function, but a caret character is used instead of an asterisk character. So this means a block that takes two id parameters and returns an NSComparisonResult (which is merely an NSInteger, with just the same meaning as in Example 3.1). We can define the block and hand it off as the argument to sortedArrayUsingComparator: all in a single move, as in Example 3.2.

Thanks to the block, as you can see, we’ve combined the definition of the callback function with its use. You might object that this means the callback isn’t reusable; if we had two calls to sortedArrayUsingComparator: using the same callback, we’d have to write out the callback in full twice. To avoid such repetition, or simply for clarity, a block can be assigned to a variable:

Note

The return type in an inline block definition is usually omitted. If included, it follows the caret character, not in parentheses. If omitted, you may have to use typecasting in the return line to make the returned type match the expected type. For a complete technical syntax specification for blocks, see http://clang.llvm.org/docs/BlockLanguageSpec.html.

The power of blocks really starts to emerge when they are used instead of a selector name. In an example earlier in this chapter, we talked about how you could pass @selector(tickleMeElmo:) as the second argument to add⁠Observer:⁠selector:​name:object: as a way of saying, “When the time comes, please call my tickleMeElmo: method.” We also talked about how error-prone this syntax was: make a typing error, and your tickleMeElmo: method mysteriously won’t be called. Moreover, such code is hard to maintain; there’s the tickleMeElmo: method sitting there, completely separate from the code that calls addObserver:selector:name:object:, yet existing only to specify what should happen at the later time when our message arrives. It might well be clearer and more compact to call addObserverForName:object:queue:usingBlock: and specify there and then as a block what should happen at message time, with no separate method callback. (I’ll talk about this again, along with an example, in Chapter 11.)

Perhaps the most remarkable feature of blocks is this: variables in scope at the point where a block is defined keep their value within the block at that moment, even though the block may be executed at some later moment. (Technically, we say that a block is a closure.) It is this aspect of blocks that makes them useful for specifying functionality to be executed at some later time, or even, as we’ll see in Chapter 38, in some other thread.

Here’s an example that will appear in Chapter 17. It will make perfect sense to you in its proper context, so I won’t explain it fully now; but the point is that outside any blocks we have a UIView object v in scope, along with a CGPoint p and another CGPoint pOrig, and we can use the two CGPoint values to mutate vinside two blocks (called anim and after), even though these blocks won’t be executed until some indeterminate moment in the future, at the start and end of an animation:

If a variable outside a block is in scope within the block, and if that variable is an object reference,
messages can be sent to it and the object may be mutated, as we did with the UIView object v in that example. But if we try, inside a block, to assign directly to a variable outside the block, we can’t do it; the variable is protected, and the compiler will stop us (“variable is not assignable”):

On rare occasions, you may need to turn off this protection; you can do so by declaring the variable using the __block qualifier. Here’s an example that will appear in Chapter 35. We cycle through an array until we find the value we want; when we find it, we set a variable (dir) to that value. That variable is declared outside the block, because we intend to use its value after executing the block; therefore we qualify the variable’s declaration with __block, so that we can assign to it from inside the block:

(Note also the assignment to a dereferenced pointer-to-BOOL. When the method to which we are submitting a block is going to call the block repeatedly as the equivalent of a for loop, we can’t abort the loop with a break statement, because this isn’t a real for loop. So the method will commonly specify that our block should take a pointer-to-BOOL parameter; the idea is that we can set this BOOL by indirection to YES, and the method will notice this as it prepares to call the block for the next iteration, and will stop instead. This is one of the few common situations in iOS programming where it is necessary to dereference a pointer.)

Another use of the __block qualifier is to allow a block to capture the value of a variable that is set by the very same method call that takes the block as an argument. Here’s an example that will appear in Chapter 38:

The method beginBackgroundTaskWithExpirationHandler: takes a block and returns a UIBackgroundTaskIdentifier, which is really just an integer. We want to use that integer inside the block, which will actually be executed at some later time (if ever). If we don’t declare the integer variable with the __block qualifier, the block will capture the variable’s value at the time the block is defined, which is before the beginBackgroundTaskWithExpirationHandler: method call is actually executed. After the method call is executed, the variable is set to its true value, the value we want to use inside the block; because we declared the variable with __block, the block has access to that true value.

Note that this trick works only because the block is being stored (by the receiver of the beginBackgroundTaskWithExpirationHandler: message) for later execution. If the block were to be executed right now, before returning from the beginBackgroundTaskWithExpirationHandler: call, the result of that call would not yet have been set.

At the same time that blocks were introduced into Objective-C, Apple introduced a system library of C functions called Grand Central Dispatch (GCD) that makes heavy use of them. GCD’s most important use is for threading (Chapter 38), but it also comes in handy for expressing neatly and compactly certain notions about when code should be executed. For example, GCD can help us delay execution of our code (delayed performance). The following code (from Chapter 14) means, “change the bounds of v1, but not right this moment — wait two seconds and then do it”:

This next example rewrites the code from the end of Chapter 1, where a class method vends a singleton object. GCD promises that the block creating the singleton object to begin with will execute only once in the entire life of our program, thus guaranteeing that the singleton is a singleton:

Why is calling dispatch_once better, as a way of making sure we generate the singleton instance only once, than testing sp against nil, as in Chapter 1? Aside from being thread-safe, it isn’t; it’s just an example of GCD’s elegant use of a block.