Objective-C Instances - Language - iOS 7 Programming Fundamentals: Objective-C, Xcode, and Cocoa Basics (2014)

iOS 7 Programming Fundamentals: Objective-C, Xcode, and Cocoa Basics (2014)

Part I. Language

Chapter 5. Objective-C Instances

Instances are the heart of the action in an Objective-C program. Obtaining and manipulating instances will be crucial to just about everything you do. Nearly every line of code that you write will be concerned with one or more of these activities:

§ Referring to an instance that already exists

§ Creating a new instance that didn’t exist previously

§ Assigning an instance to a variable

§ Sending a message to an instance

§ Passing an instance as an argument in a method call

How Instances Are Created

Your class objects are created for you automatically as your program starts up, but instances must be created individually as the program runs. Ultimately, every instance comes into existence in just one way: someone asks a class to instantiate itself (see Chapter 4). But there are three different ways in which this can occur: ready-made instances, instantiation from scratch, and nib-based instantiation.

Ready-Made Instances

One way to create an instance is indirectly, by calling code that does the instantiation for you. You can think of an instance obtained in this indirect manner as a “ready-made instance.” (That’s my made-up phrase, not an official technical term.) Consider this simple code:

NSString* s2 = [s uppercaseString];

The documentation for the NSString instance method uppercaseString says that it returns “a string with each character from the receiver changed to its corresponding uppercase value.” In other words, you send the uppercaseString message to an NSString instance, and you get back adifferent, newly created NSString instance. After that line of code, s2 points to an NSString instance that didn’t exist before.

The NSString instance produced by the uppercaseString method comes to you ready-made. Your code didn’t say anything about instantiation; it just sent the uppercaseString message. But clearly someone said something about instantiation, because instantiation took place; this is a newly minted NSString instance. That “someone” is presumably some code inside the NSString class. But we don’t have to worry about the details. We are guaranteed of receiving a complete brand spanking new ready-to-roll NSString instance, and that’s all we care about.

Similarly, any class factory method instantiates the class and dispenses the resulting instance as a ready-made instance. So, for example, the NSString class method stringWithContentsOfFile:encoding:error: reads a file and produces an NSString instance representing its contents. All the work of instantiation has been done for you. You just accept the resulting string and away you go.

Instantiation from Scratch

The alternative to requesting a ready-made instance is to tell a class explicitly to instantiate itself. To do so, you send a class the alloc message. The alloc class method is implemented by the NSObject class, the root class from which all other classes inherit. It causes memory to be set aside for the instance so that an instance pointer can point to it. (Management of that memory is a separate issue, discussed in Chapter 12.)

You must never, never, never call alloc by itself. You must immediately call another method, an instance method that initializes the newly created instance, placing it into a known valid state so that it can be sent other messages. Such a method is called an initializer. Moreover, an initializer returns an instance — usually the same instance, initialized. Therefore you can, and always should, call alloc and the initializer in the same line of code. The minimal initializer is init. So the basic pattern, known informally as “alloc-init,” looks like Example 5-1.

Example 5-1. The basic pattern for instantiation from scratch

SomeClass* aVariable = [[SomeClass alloc] init];

You cannot instantiate from scratch if you do not also know how to initialize, so we turn immediately to a discussion of initialization.

Initialization

Every class defines or inherits at least one initializer. This is an instance method; the instance has just been created, by calling alloc on the class, and it is to this newly minted instance that the initializer message must be sent. An initializer message must be sent to an instance immediately after that instance is created by means of the alloc message, and it must not be sent to an instance at any other time.

The basic initialization pattern, as shown in Example 5-1, is to nest the alloc call in the initializer call, assigning the result of the initialization (not the alloc!) to a variable. One reason for this nested structure is that if something goes wrong and the instance can’t be created or initialized, the initializer will return nil; therefore it’s important to capture the result of the initializer and treat that, not the result of alloc, as the pointer to the instance.

To help you identify initializers, all initializers are named in a conventional manner. The convention is that all initializers, and only initializers, begin with the word init. The ultimate bare-bones initializer is called simply init, and takes no parameters. Other initializers do take parameters, and usually begin with the phrase initWith followed by descriptions of their parameters. For example, the NSArray class documentation lists these methods:

– initWithArray:

– initWithArray:copyItems:

– initWithContentsOfFile:

– initWithContentsOfURL:

– initWithObjects:

– initWithObjects:count:

Let’s try a real example. In Chapter 3, we created an NSArray from three strings constituting its elements, by means of a class factory method, arrayWithObjects:, taking a nil-terminated list of objects and returning a ready-made instance:

NSArray* pep =

[NSArray arrayWithObjects:@"Manny", @"Moe", @"Jack", nil];

It turns out, however, that there is also an initializer for NSArray, initWithObjects:, that works exactly the same way as arrayWithObjects:. The difference is that the latter is a class method, a factory method that returns a ready-made instance, while the former is an initializer, an instance method, that may be used only in the same breath with alloc. Thus we can now do exactly the same thing that we did in Chapter 3, except that we are now creating the instance ourselves, from scratch:

NSArray* pep =

[[NSArray alloc] initWithObjects:@"Manny", @"Moe", @"Jack", nil];

In modern Objective-C, as I mentioned in Chapter 3, you are unlikely to call arrayWithObjects: or initWithObjects:, because there is now a convenient literal array syntax that generates an array based on a list of its contents:

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

So I’ll give another example. Suppose that, one way or another, you now have an array pep containing the three strings @"Manny", @"Moe", and @"Jack", and that you want to instantiate a second array based on it and containing those same three strings. Note that it is not sufficient to assign pep to another NSArray variable:

NSArray* pep2 = pep; // no, that isn't another array

Object references are pointers, and pointer assignment merely points two references at the same thing (Chapter 3). So pep2 in that code isn’t a second array; it’s the same array, which isn’t what we said we wanted. To make a second array instance based on the first, we can call the class method arrayWithArray:, like this:

NSArray* pep2 = [NSArray arrayWithArray: pep];

Now pep2 is a newly minted instance, separate from pep. It’s a ready-made instance, returned from a class factory method. Once again, though, it turns out that there’s a corresponding initializer, initWithArray:. To create the instance ourselves from scratch, therefore, we might instead use that initializer:

NSArray* pep2 = [[NSArray alloc] initWithArray: pep];

It is often the case that a built-in Cocoa class will offer both a factory method and an initializer that start from the same kind of data and produce the same kind of result. Ultimately, it makes no difference which you use; given the same arguments, both approaches result in instances that are indistinguishable from one another. (The two approaches do have differing implications for memory management, as I’ll explain in Chapter 12, but under ARC those differences will probably not matter to you.)

In looking through the documentation for an initializer, don’t forget to look upward through the class hierarchy. For example, the class documentation for UIWebView lists no initializers, but UIWebView inherits from UIView, and in UIView’s class documentation you’ll discoverinitWithFrame:. Moreover, the init method is defined as an instance method of the NSObject class, so every class inherits it and every newly minted instance can be sent the init message. Thus it is a given that if a class defines no initializers of its own, you can initialize an instance of it with init. For example, the UIResponder class documentation lists no initializers at all (and no factory methods). So to create a UIResponder instance from scratch, you’d call alloc and init.

NOTE

When init is the initializer you want to call, you can collapse the successive calls to alloc and init into a call to the class method new. In other words, [MyClass new] is a synonym for [[MyClass alloc] init]. This is a convenient shorthand, but it applies only when the initializer is init, plain and simple; to use any other initializer, you’ll have to call alloc and the initializer explicitly.

The designated initializer

If a class defines initializers, one of them may be described in the documentation as the designated initializer. (There’s nothing about a method’s name that tells you it’s the designated initializer; you must peruse the documentation to find out.) For example, in the UIView class documentation, the initWithFrame: method is described as the designated initializer. A class that does not define a designated initializer inherits its superclass’s designated initializer; the ultimate designated initializer, inherited by all classes without any other designated initializer anywhere in their superclass chain, is init. Thus, every class has exactly one designated initializer.

A class’s designated initializer must be called in the course of instantiating that class. If a class has more than one initializer, whether inherited or defined within the class, its designated initializer is the initializer on which its other initializers depend: ultimately, they must call it.

Other initializers can relate to the designated initializer in various ways. The designated initializer might have the most parameters, allowing the most instance variables to be set explicitly (with the other initializers supplying default values for some instance variables). Or it might just be the most basic form of initialization. Here are some real-life examples:

§ The NSDate class documentation says that initWithTimeIntervalSinceReferenceDate: is the designated initializer, and that other initializers (such as initWithTimeIntervalSinceNow:) call it.

§ The UIView class documentation says that initWithFrame: is the designated initializer. UIView contains no other initializers, but some of its subclasses do. UIWebView, a UIView subclass, has no initializer, so initWithFrame: is its designated initializer (by inheritance). UIImageView, a UIView subclass, has initializers such as initWithImage:, but none of them is a designated initializer; so initWithFrame: is its inherited designated initializer as well, and initWithImage: must call initWithFrame:.

A class that implements a designated initializer of its own must override the designated initializer inherited from the superclass, so that the latter calls the former. Thus:

§ NSDate overrides the inherited init to call its own designated initializer, initWithTimeIntervalSinceReferenceDate:, with a value that will generate a date specifying the current date and time.

§ UIView overrides the inherited init to call its own designated initializer, initWithFrame:, with a frame value of CGRectZero.

Nib-Based Instantiation

The third means of instantiation is through a nib file. A nib file is a file within the built app, generated from a .storyboard file or .xib file in which you have “drawn” parts of the user interface. Most Xcode projects will include at least one .storyboard file or .xib file, and thus most apps will contain at least one nib file inside the app bundle. A nib file, to be used, must be explicitly loaded, by some mechanism, as the app runs. A nib file consists, in a sense, of the names of classes along with instructions for instantiating and initializing them. When the app runs and a nib file is loaded, those instructions are carried out — those classes are instantiated and initialized. Thus the running app ends up generating instances based on what you originally drew in the .storyboard file or .xib file.

For example, suppose you’d like the user to be presented with a view containing a button whose title is “Howdy!” Xcode lets you arrange this graphically by editing a .storyboard file or .xib file. You drag a button from the Object library into the view, as in Figure 5-1. Then you place it at its desired position in the view, and set its title to “Howdy!”, as in Figure 5-2. In effect, you create a drawing of what you want the view and its contents to look like.

Dragging a button into a view

Figure 5-1. Dragging a button into a view

Configuring a button graphically

Figure 5-2. Configuring a button graphically

When the app runs, the nib file loads, and that drawing is turned into reality. To do this, the drawing is treated as a set of instructions for instantiating objects. The button that you dragged into the view is treated as a representative of the UIButton class. The UIButton class is told to instantiate itself, and that instance is then initialized, giving it the same position you gave it in the drawing (the instance’s frame), the same title you gave it in the drawing (the instance’s title), and putting it into the view. In effect, the loading of your nib file is equivalent to code like this (assuming that self.view is a reference to the view object):

UIButton* b =

[UIButton buttonWithType:UIButtonTypeSystem]; // instantiate

[b setTitle:@"Howdy!" forState:UIControlStateNormal]; // set up title

[b setFrame: CGRectMake(100,100,52,30)]; // set up frame

[self.view addSubview:b]; // place button in view

In that code, the UIButton instance is created as a ready-made instance by calling a class factory method, and is then assigned to a variable b. But in the case of nib-based instantiation, getting an instance from the nib to be assigned to a variable is quite a tricky business, involving considerable preparation and a device called an outlet. The fact that nib files are a source of instances, and that those instances are brought into existence as the nib file is loaded, along with the problem of how to assign such instances to variables, is a source of confusion to beginners. I’ll discuss the matter in detail in Chapter 7.

Polymorphism

Given a subclass and its superclass, you are free to supply a subclass instance wherever an instance of the superclass is expected. For example, UIButton is a subclass of UIControl, which is a subclass of UIView. So it would be perfectly legal and acceptable to say this:

UIButton* b = [UIButton buttonWithType:UIButtonTypeSystem];

UIView* v = b;

The variable b is declared as a UIButton, but I’m assigning it to a variable declared as a UIView. That’s legal and acceptable because UIView is an ancestor (up the superclass chain) of UIButton. Putting it another way, I’m behaving as if a UIButton were a UIView, and the compiler accepts this because a UIButton is a UIView.

What’s important when the app runs, however, is not the declared class of a variable, but the actual class of the object to which that variable refers. After I assign the UIButton instance to the variable v, the object to which the variable v points is a UIButton. So even though v is not typed as a UIButton, it can do no harm to send it messages appropriate to a UIButton, because it is a UIButton. For example:

UIButton* b = [UIButton buttonWithType:UIButtonTypeSystem];

UIView* v = b;

[v setTitle:@"Howdy!" forState:UIControlStateNormal];

There is no UIView message setTitle:forState:. Nevertheless, that code is perfectly reasonable and safe; v may be typed as a mere UIView, but in reality, when the code runs, it will be pointing to a UIButton — and there is a UIButton message setTitle:forState:. The compiler, however, doesn’t know anything about what v will be pointing to when the code runs, so (under ARC) it declares a compile error. I can allay the compiler’s fears by typecasting the receiver:

UIButton* b = [UIButton buttonWithType:UIButtonTypeSystem];

UIView* v = b;

[(UIButton*)v setTitle:@"Howdy!" forState:UIControlStateNormal];

The typecast calms the compiler’s fears, and the code now compiles. And when the code runs, it works just fine! It works not because I typecast v to a UIButton (typecasting doesn’t magically convert anything to anything else; it’s just a hint to the compiler), but because v really is a UIButton. I typecast the receiver, and the compiler always takes your word for it when you typecast; moreover, my typecast told the truth, so when the message setTitle:forState: arrives at the object pointed to by v, everything is fine. If v had been a UIView but not a UIButton, on the other hand, the program would have crashed at that instant.

Now let’s turn the tables. We called a UIButton a UIView and sent it a UIButton message. Now we’re going to call a UIButton a UIButton and send it a UIView message.

What an object really is depends not just upon its class but also upon that class’s inheritance. A message is acceptable even if an object’s own class doesn’t implement a corresponding method, provided that the method is implemented somewhere up the superclass chain. For example:

UIButton* b = [UIButton buttonWithType:UIButtonTypeSystem];

[b setFrame: CGRectMake(100,100,52,30)];

That code works fine. But you won’t find setFrame: in the documentation for the UIButton class. That’s because you’re looking in the wrong place. A UIButton is a UIControl, and a UIControl is a UIView. To find out about setFrame:, look in the UIView class’s documentation. (Okay, it’s more complicated than that; you won’t find setFrame: there either. But you will find a term frame which is called a “property,” and this amounts to the same thing, as I’ll explain later in this chapter.) So the setFrame: message is sent to a UIButton, but it corresponds to a method defined on a UIView. Yet it works fine, because a UIButton is a UIView.

TIP

A common beginner mistake is to consult the documentation without following the superclass chain. If you want to know what you can say to a UIButton, don’t just look in the UIButton class documentation: also look in the UIControl class documentation, the UIView class documentation, and so on.

We treated a UIButton object as a UIView, yet (by typecasting) we were still able to send it a UIButton message. We treated a UIButton as a UIButton, yet (by inheritance) we were still able to send it a UIView message.

An object responds to a message sent to it, not on the basis of anything said in code about what it is, but on the basis of what it really is when the program runs and the message is actually sent to that object. What matters when a message is sent to an object is not how the variable pointing to that object is declared or typecast, but what class the object really is. What an object really is depends upon its class, along with that class’s inheritance from the superclass chain; these facts are innate to the object and are independent of how your code characterizes the variable pointing to the object. This independent maintenance of object type integrity is the basis of what is called polymorphism.

But it is not quite the whole of polymorphism. To understand the whole of polymorphism, we must go further into the dynamics of message sending.

The Keyword self

A common situation is that code in an instance method defined in a class must call another instance method defined within the same class. We have not yet discussed how to do this. A method is called by sending a message to an object; in this situation, what object would that be? The answer is supplied by a special keyword, self. Here’s a simple example:

@implementation MyClass

- (NSString*) greeting {

return @"Goodnight, Gracie!";

}

- (NSString*) sayGoodnightGracie {

return [self greeting];

}

@end

When the sayGoodnightGracie message is sent to a MyClass instance, the sayGoodnightGracie instance method runs. It sends the greeting message to self. As a result, the greeting instance method is called; it returns the string @"Goodnight, Gracie!", and this same string is then returned from the sayGoodnightGracie method.

The example seems straightforward enough, and it is. In real life, your code for a class will often consist of a few public instance methods along with lots of other instance methods on which they rely. The instance methods within this class will be calling each other constantly. They do this by sending messages to self.

Behind this simple example, though, is a subtle and important mechanism having to do with the real meaning of the keyword self. The keyword self does not actually mean “in the same class.” It’s an instance, after all, not a class. What instance? It’s this same instance. The same as what? The same instance to which the message was sent that resulted in the keyword self being encountered in the first place.

So let’s consider in more detail what happens when we instantiate MyClass and send the sayGoodnightGracie message to that instance:

MyClass* thing = [MyClass new];

NSString* s = [thing sayGoodnightGracie];

We instantiate MyClass and assign the instance to a variable thing. We then send the sayGoodnightGracie message to thing, the instance we just created. The message arrives, and it turns out that this instance is a MyClass. Sure enough, MyClass implements a sayGoodnightGracieinstance method, and this method is called. As it runs, the keyword self is encountered. It means “the instance to which the original message was sent in the first place.” That, as it happens, is the instance pointed to by the variable thing. So now the greeting message is sent to that instance (Figure 5-3).

The meaning of self

Figure 5-3. The meaning of self

This mechanism may seem rather elaborate, considering that the outcome is just what you’d intuitively expect. But the mechanism needs to be elaborate in order to get the right outcome. This is particularly evident when superclasses are involved and a class overrides a method of its superclass.

To illustrate, suppose we have a class Dog with an instance method bark. And suppose Dog also has an instance method speak, which simply calls bark. Now suppose we subclass Dog with a class Basenji, which overrides bark (because Basenjis can’t bark). What happens when we send the speak message to a Basenji instance, as in Example 5-2?

Example 5-2. Polymorphism in action

@implementation Dog

- (NSString*) bark {

return @"Woof!";

}

- (NSString*) speak {

return [self bark];

}

@end

@implementation Basenji : Dog

- (NSString*) bark {

return @""; // empty string, Basenjis can't bark

}

@end

// So, in some other class:

Basenji* b = [Basenji new];

NSString* s = [b speak];

If the keyword self meant merely “the same class where this keyword appears,” then when we send the speak message to a Basenji instance, we would arrive at the implementation of speak in the Dog class (because that’s where speak is implemented), and the Dog class’s bark method would be called. This would be terrible, because it would make nonsense of the notion of overriding; we’d return @"Woof!", which is wrong for a Basenji. But that is not what the keyword self means. It has to do with the instance, not the class.

So here’s what happens. The speak message is sent to our Basenji instance, b. The Basenji class doesn’t implement a speak method, so we look upward in the class hierarchy and discover that speak is implemented in the superclass, Dog. We call Dog’s instance method speak, the speakmethod runs, and the keyword self is encountered. It means “the instance to which the original message was sent in the first place.” That instance is still our Basenji instance b. So we send the bark message to the Basenji instance b. The Basenji class implements a bark instance method, so this method is found and called, and the empty string is returned (Figure 5-4).

Class inheritance, overriding, self, and polymorphism

Figure 5-4. Class inheritance, overriding, self, and polymorphism

Of course, if the Basenji class had not overridden bark, then when the bark message was sent to the Basenji instance, we would have looked upward in the class hierarchy again and found the bark method implemented in the Dog class and called that. Thus, thanks to the way the keywordself works, inheritance works correctly both when there is overriding and when there is not.

If you understand that example, you understand polymorphism. The mechanism I’ve just described is crucial to polymorphism and is the basis of object-oriented programming. (Observe that I now speak of object-oriented programming, not just object-based programming as in Chapter 2. That’s because, in my view, the addition of polymorphism is what turns object-based programming into object-oriented programming.)

The Keyword super

Sometimes (quite often, in Cocoa programming) you want to override an inherited method but still access the overridden functionality. To do so, you’ll use the keyword super. Like self, the keyword super is something you send a message to. But its meaning has nothing to do with “this instance” or any other instance. The keyword super is class-based, and it means: “Start the search for messages I receive in the superclass of this class” (where “this class” is the class where the keyword super appears).

You can do anything you like with super, but its primary purpose, as I’ve just said, is to access overridden functionality — typically from within the very functionality that does the overriding, so as to get both the overridden functionality and some additional functionality.

For example, suppose we define a class NoisyDog, a subclass of Dog. When told to bark, it barks twice:

@implementation NoisyDog : Dog

- (NSString*) bark {

return [NSString stringWithFormat: @"%@ %@", [super bark], [super bark]];

}

@end

That code calls super’s implementation of bark, twice; it assembles the two resulting strings into a single string with a space between (using the stringWithFormat: method), and returns that. Because Dog’s bark method returns @"Woof!", NoisyDog’s bark method returns @"Woof! Woof!". Notice that there is no circularity or recursion here: NoisyDog’s bark method will never call itself.

A nice feature of this architecture is that by sending a message to the keyword super, rather than hard-coding @"Woof!" into NoisyDog’s bark method, we ensure maintainability: if Dog’s bark method is changed, the result of NoisyDog’s bark method will change to match. For example, if we later go back and change Dog’s bark method to return @"Arf!", NoisyDog’s bark method will return @"Arf! Arf!" with no further change on our part.

In real Cocoa programming, it will very often be Cocoa’s own methods that you’re overriding. For example, the UIViewController class, which is built into Cocoa, implements a method viewDidAppear:, described in the documenation as follows:

- (void)viewDidAppear:(BOOL)animated

The documentation says that UIViewController is a class for which you are very likely to define a subclass. The documentation proceeds to suggest that in your subclass of UIViewController you might want to override this method, but cautions that if you do, “you must call super at some point in your implementation.” The phrase “call super” is a kind of shorthand, meaning “pass on to super the very same call and arguments that were sent to you.”

So let’s say you’re overriding viewDidAppear: in your UIViewController subclass, called MyViewController. Your implementation might look like this:

- (void) viewDidAppear: (BOOL) animated {

[super viewDidAppear: animated];

// ... do more stuff here ...

}

The result is that when viewDidAppear: is called in a MyViewController instance, we do both the standard stuff that its superclass UIViewController does in response to viewDidAppear: and the custom stuff pertaining to our own class MyViewController. In this particular case, we don’t even know exactly what the UIViewController stuff is, and we don’t care. When the documentation tells you to call super when overriding, call super when overriding! Neglecting to call super when told by the documentation to do so can cause your app to behave incorrectly in unpredictable ways, and is a common beginner mistake.

Instance Variables and Accessors

In Chapter 3, I explained that one of the main reasons there are instances and not just classes is that instances can have instance variables. Instance variables, you remember, are declared when you define the class, and in Chapter 4 I said that these declarations go into curly braces at the start of the class’s interface section or, in modern Objective-C, its implementation section. But for every instance variable defined in a class, each individual instance of that class keeps its instance variables individually; the value of any instance variable of any instance can be set and maintained and fetched and changed for as long as the instance itself persists.

NOTE

The term “instance variable” arises so often that it is often abbreviated to ivar. I’ll use both terms indiscriminately from now on.

Let’s write a class that uses an instance variable. Suppose we have a Dog class and we want every Dog instance to have a number, which should be an int. (For example, this number might correspond to the dog’s license number.) In modern Objective-C, we would probably declare number in the implementation section for the Dog class, like this:

@implementation Dog {

int number;

}

// method implementations go here

@end

(You might ask why, for this example, I don’t use instead the concept of giving the dog a name. The reason is that a name would be an NSString instance, which is an object; instance variables that are pointers to objects raise some additional issues I don’t want to discuss just now. But instance variables that are simple C data types raise no such issues. We’ll return to this matter in Chapter 12.)

Within a class, that class’s own instance variables are global to all instance methods. Any Dog instance method can just use the variable name number and access this instance variable, just like any other variable. But code that does this can be confusing when you’re reading it; suddenly there’s a variable called number and you don’t understand what it is, because there’s no nearby declaration for it. So I often use a different notation, like this: self->ivarName. The “arrow” operator, formed by a minus sign and a greater-than sign, is called the structure pointer operator, because of its original use in C (K&R 6.2).

Another conventional device is to start the name of an instance variable with an underscore: _ivarName. That way, even if you don’t write self->_ivarName, the bare name _ivarName provides a clue as to where this variable might be declared.

The fact that ivars are global to all instance methods within a class, and that they persist for as long as the instance itself, is often a perfectly sufficient reason for having ivars. Think of ivars as a convenient and powerful way of sharing values across different instance methods of the same class. You will often, in one instance method, stick a value into an instance variable, exactly so that some other instance method can come alone later and retrieve it. An instance method here functions as a kind of drop box, and this is a very important function indeed (especially in the event-driven world of the Cocoa framework; see Chapter 11).

However, ivars can also be a means of communication with an instance from outside that instance. You may, as you construct the code for a class and think about its place in your program, want to allow instances of other classes to get or even set the value of an instance variable of an instance of this class. By default, however, instance variables are protected, meaning that other classes, except for subclasses of this one, can’t see them. And if instance variables are declared in a class’s implementation section, no other classes, not even subclasses of this one, can see them. So if, somewhere else, I instantiate a Dog, I won’t be able to access that Dog instance’s number instance variable. This is a deliberate feature of Objective-C; you can work around it if you like, but in general you should not. Instead, you will want to provide accessor methods.

There’s a convention for the naming of such methods: they should be named setXxx: and xxx, where “xxx” are the same as one another (and may well be the same as the name of an instance variable). For example, we might name our accessor methods setNumber: and number.

Let’s write, then, in Dog’s implementation section, an accessor method setNumber: that allows setting a value for the number ivar (that is, this method is a setter):

- (void) setNumber: (int) n {

self->number = n;

}

Of course, to make setNumber: public to any other class that imports Dog’s interface file Dog.h, we must also declare it in Dog’s interface section:

@interface Dog : NSObject

- (void) setNumber: (int) n;

@end

We can now, in any class that imports Dog.h, instantiate a Dog and assign that instance a number:

Dog* fido = [Dog new];

[fido setNumber: 42];

We can now set a Dog’s number, but we can’t get it (from outside that Dog instance). To correct this problem, we’ll write a second accessor method, number, that allows for getting the value of the number ivar (this method is a getter):

- (int) number {

return self->number;

}

Again, we declare the number method in Dog’s interface section. We can now, in any class that imports Dog.h, both set and get a Dog instance’s number:

Dog* fido = [Dog new];

[fido setNumber: 42];

int n = [fido number];

// sure enough, n is now 42!

Luckily, modern Objective-C provides a mechanism for generating accessor methods automatically (discussed in Chapter 12), so you won’t have to go through the tedium of writing them by hand every time you want to make an ivar publicly accessible. (Though, to be honest, I don’t see why you shouldn’t have to go through that tedium; before Objective-C 2.0, we all had to, so why shouldn’t you? We also had to clean the roads with our tongues on the way to school. And we liked it! You kids today, you don’t know what real programming is.)

In my code, Dog now has both a number method and a number instance variable. This fact should not confuse you. It doesn’t confuse the compiler, because the method name and the instance variable name are used in completely different ways in code. If the compiler can tell the difference, so can you. Still, elimination of any such confusion is another benefit of the convention that I mentioned a moment ago, where we begin our ivar names with an underscore: _number, not number. If we follow this convention and rename our ivar, we’ll also have to rewrite (but not rename) the methods that access it:

@implementation Dog {

int _number;

}

- (void) setNumber: (int) n {

self->_number = n;

}

- (int) number {

return self->_number;

}

@end

All instance variables are set to some form of zero when the instance comes into existence (as part of the call to the class method alloc). This is important, because it means that, unlike a local automatic variable, mere declaration of an instance variable without providing an initial value is not dangerous — which is good, because it’s also impossible. We can’t say:

@implementation Dog {

int _number = 42; // no, sorry, that's not Objective-C!

}

However, at least we know that _number will start out life as 0, not as some dangerous indeterminate value. By the same token, a BOOL instance variable will start out life as NO, the BOOL form of 0, and an instance variable typed as an object will start out life as nil, the object form of 0. If you want an instance variable to have a nonzero value early in the lifetime of the instance, it is up to your code to give it that nonzero value. It can be important to remember to test an instance variable for 0 (or nil) to see whether this has happened yet.

Key–Value Coding

Objective-C provides a means for translating from a string to an accessor call, called key–value coding. Such translation is useful, for example, when the name of the desired accessor will not be known until runtime. The string is the key. The key–value coding equivalent of calling a getter isvalueForKey:; the equivalent of calling a setter is setValue:forKey:.

Thus, for example, suppose we wish to call the number method on the fido instance. We can do this by sending valueForKey: to fido, with a key @"number". However, even though the number method returns an int, the value returned by valueForKey: is an object — in this case, an NSNumber, the object equivalent of a number (see Chapter 10). If we want the actual int, NSNumber provides an instance method, intValue, that lets us extract it:

NSNumber* num = [fido valueForKey: @"number"];

int n = [num intValue];

Similarly, to use key–value coding to call the setNumber: method on the fido instance, we would say:

NSNumber* num = [NSNumber numberWithInt:42];

[fido setValue: num forKey: @"number"];

Before handing off the number 42 as the value argument in setValue:forKey:, we had to wrap it up as an object — in this case, an NSNumber object. Starting with LLVM compiler version 4.0 (Xcode 4.4), there’s a syntactic shorthand for doing that; just as we can create an NSString by wrapping text in a compiler directive @"...", we can create an NSNumber by wrapping a numeric expression in a compiler directive @(...) — or, if the numeric expression is just a literal number, by preceding that literal number with @. So we can rewrite the previous example like this:

NSNumber* num = @42;

[fido setValue: num forKey: @"number"];

In real life, you’d probably omit the intermediate variable num and write the whole thing as a single line of code:

[fido setValue: @42 forKey: @"number"];

In these examples there is no advantage to using key–value coding over just calling the accessors. But suppose we had received the value @"number" in a variable (as the result of a method call, perhaps). Suppose that variable is called something. Then we could say:

id result = [fido valueForKey: something];

Thus we could access a different accessor under different circumstances. This powerful flexibility is possible because Objective-C is such a dynamic language that a message to be sent to an object does not have to be formed until the program is already running.

When you call valueForKey: or setValue:forKey:, the correct accessor method is called if there is one. Thus, when we use @"number" as the key, a number method and a setNumber: method are called if they exist. This is one reason why your accessors should be properly named. On the other hand, if there isn’t an accessor method, but there is an instance variable with the same name as the key, the instance variable is accessed directly (even if its name starts with an underscore)! Such direct access violates the privacy of instance variables, so there’s a way to turn off this feature for a particular class if you don’t like it. (I’ll explain what it is, with more about key–value coding, in Chapter 12.)

Properties

A property is a syntactic feature of modern Objective-C designed to provide an alternative to the standard syntax for calling an accessor method. As syntactic sugar for formally calling an accessor, you can append the property name to an instance reference using dot-notation. You can use the resulting expression either on the left side of an equal sign (to call the corresponding setter) or elsewhere (to call the corresponding getter). The name of the property relies, by default, on the accessor naming conventions.

I’ll use the Dog class as an example. If the Dog class has a public getter method called number and a public setter method called setNumber:, then the Dog class also has a number property that can be used on the left side of an equal sign or elsewhere. This means that, instead of saying things like this:

[fido setNumber: 42];

int n = [fido number];

You can talk like this:

fido.number = 42;

int n = fido.number;

Your use of property syntax is entirely optional. The existence of a property is equivalent to the existence of the corresponding getter and setter methods; using the property is equivalent to calling the accessor method. You’re free to call an accessor method by either syntax. In the case of Dog, you can call the getter and setter methods (number and setNumber:), or you can use the property (number).

To use a property within the class that has that property, you must write self explicitly. So, for example:

self.number = 42;

WARNING

Do not confuse a property with an instance variable. An expression like self->number = n, or even simply number = n, sets the instance variable directly (and is possible only within the class, because instance variables are protected by default). An expression like fido.number or self.number involves a property and is equivalent to calling a getter or setter method. That getter or setter method may access an instance variable, and that instance variable may even have the same name as the property, but that doesn’t make them the same thing.

Properties will be taken up again in Chapter 12, where it will turn out that they are much more powerful and interesting beasts than I’m suggesting here. But I’m telling you about properties now because they are so widely used in Cocoa and because you’ll encounter them so frequently in the documentation.

For example, earlier in this chapter I called UIView’s setFrame: instance method on a UIButton instance:

[b setFrame: CGRectMake(100,100,52,30)];

I mentioned that setFrame: is not documented under UIButton; you have to look in the UIView documentation. But in fact, no such method is mentioned there either. What the UIView documentation does say is this:

frame

The frame rectangle, which describes the view’s location and size in its superview’s coordinate system.

@property(nonatomic) CGRect frame

The documentation is telling me about the UIView property name frame. That last line is a property declaration. From the point of view of the UIView class’s client — in this case, that’s me — the property declaration is simply a shorthand, telling me that such a property exists. (Never mind for now what nonatomic means.) But that’s the same thing as telling me about the existence of UIView instance methods frame and setFrame:; I can use these methods either through the frame property and dot-notation or by calling them explicitly. That’s how I knew there was a settersetFrame:. In my code, I called setFrame: explicitly; now you know that I could have used the frame property:

b.frame = CGRectMake(100,100,52,30);

Objective-C uses dot-notation for properties, and C uses dot-notation for structs; these can be chained. So, for example, UIView’s frame is a property whose value is a struct (a CGRect); thus, you can say myView.frame.size.height, where frame is a property that returns a struct, sizeis an element of that struct, and height is an element of that struct. But there are limitations on this syntax; you cannot (for example) set a frame’s height directly through a chain starting with the UIView, like this:

myView.frame.size.height = 36.0; // error, "Expression is not assignable"

Instead, if you want to change a component of a struct property, you must fetch the property value into a struct variable, change the struct variable’s value, and set the entire property value from the struct variable:

CGRect f = myView.frame;

f.size.height = 0;

myView.frame = f;

DOT-NOTATION WARS

Naturally, there is quasi-religious debate over properties and dot-notation syntax, with one side claiming that property syntax is convenient and compact, and makes Objective-C more like other languages that use dot-notation, and the other side retorting that it does no such thing, because it is so limited.

For example, property syntax opponents would argue, a UIScrollView has a contentView property, but when setting it you are most likely to want to animate the scroll view at the same time, which you do by calling setContentView:animated:. That’s a kind of setter, but it takes two parameters; property syntax can’t express that, so we’re back to using an explicit method call, and property syntax has saved us nothing, and in fact is more likely to mislead us into forgetting to add the animation.

Another objection to property notation is that the compiler restricts its use; for example, you can use a formal method call to send the number message to a Dog instance typed as an id, but you can’t append the number property with dot-notation to such an instance.

Yet another problem is that it is permitted to misuse property syntax to call a method that isn’t, strictly speaking, a getter. For example, the lastObject instance method of NSArray is just a method; it isn’t listed as a property. Nevertheless, programmers will often write myArray.lastObject just because it’s simpler and faster to write than [myArray lastObject] — and because it works. But, again, you can’t do that with methods that don’t return a value or that take any parameters; the method in question has to be getter-like, even if it isn’t really a getter. Such misuse of property syntax may seem abominable, but it is also overwhelmingly tempting, as is proven by the fact that even Apple’s own example code sometimes does it.

How to Write an Initializer

Now that you know about self and super and instance variables, we can return to a topic that I blithely skipped over earlier. I described how to initialize a newly minted instance by calling an initializer, and emphasized that you must always do so, but I said nothing about how to write an initializer in your own classes. You will wish to do this when you want your class to provide a convenient initializer that goes beyond the functionality of the inherited initializers. Often your purpose will be to accept some parameters and use them to set the initial values of some instance variables.

For example, in the case of a Dog with a number, let’s say we don’t want any Dog instances to come into existence without a number; every Dog must have one. So having a value for its number ivar is a sine qua non of a Dog being instantiated in the first place. An initializer publicizes this rule and helps to enforce it — especially if it is the class’s designated initializer. So let’s decide that this initializer will be Dog’s designated initializer.

Moreover, let’s say that a Dog’s number should not be changed. Once the Dog has come into existence, along with a number, that number should remain attached to that Dog instance for as long as that Dog instance persists.

So delete the setNumber: method and its declaration, thus destroying any ability of other classes to set a Dog instance’s number after it has been initialized. Instead, we’re going to set a Dog’s number as it is initialized, using a method we’ll declare like this:

- (id) initWithNumber: (int) n;

Our return value is typed as id, not as a pointer to a Dog, even though in fact we will return a Dog object. This is a convention that we should obey. The name is conventional as well; as you know, the init beginning tells the world this is an initializer.

Now I’m just going to show you the actual code for the initializer (Example 5-3). Much of this code is conventional — a dance you are required to do. You should not question this dance: just do it. I’ll describe the meaning of the code, but I’m not going to try to justify all the parts of the convention.

Example 5-3. Conventional schema for an initializer

- (id) initWithNumber: (int) n {

self = [super init]; 1 2

if (self) {

self->_number = n; 3

}

return self; 4

}

The parts of the convention are:

1

We send some sort of initialization message, calling a designated initializer. If the method we are writing is our class’s designated initializer, this message is sent to super and calls the superclass’s designated initializer. Otherwise, it is sent to self and calls either this class’s designated initializer or another initializer that calls this class’s designated initializer. In this case, the method we are writing is our class’s designated initializer, and the superclass’s designated initializer is init.

2

We capture the result of the initialization message we send, and assign that result to self. It comes as a surprise to many beginners (and not-so-beginners) that one can assign to self at all or that it would make sense to do so. But one can assign to self (because of how Objective-C messaging works behind the scenes), and it makes sense to do so because in certain cases the instance returned from the initialization message we send might not be same as the self we started with.

3

If self is not nil, we initialize any instance variables we care to. This part of the code is typically the only part you’ll customize; the rest will be according to the pattern. Observe that I don’t use any setter methods (or properties); in initializing an instance variable not inherited from the superclass, you should assign directly to the instance variable.

(Earlier, I mentioned that instance variables start out life with a zero value, and that if you don’t like that, giving them a different value is up to you. Clearly, writing a designated initializer is one way to do that! Conversely, if the default zero values are satisfactory initial values for some of your instance variables, you won’t bother to set them in your designated initializer.)

4

We return self.

But we are not finished. Recall from earlier in this chapter that a class that defines a designated initializer should also override the inherited designated initializer (in this case, init). And you can see why: if we don’t, someone could say [[Dog alloc] init] (or [Dog new]) and create a dog without a number — the very thing our initializer is trying to prevent. Just for the sake of the example, I’ll make the overridden init assign a negative number as a signal that there’s a problem. Notice that we’re still obeying the rules: this initializer is not the designated initializer, so it calls this class’s designated initializer:

- (id) init {

return [self initWithNumber: -9999];

}

Just to complete the story, here’s some code showing how we now would instantiate a Dog:

Dog* fido = [[Dog alloc] initWithNumber:42];

int n = fido.number;

// n is now 42; our initialization worked!

NOTE

Even though an initializer returns an id, and even though id is the universal donor, the compiler warns if we assign the result to an inappropriately typed variable:

NSString* s = [[Dog alloc] initWithNumber:42]; // compiler warns

This magic is performed by the modern LLVM compiler, which infers, from the fact that the name of this method starts with init, that it is an initializer, and effectively substitutes for id the keyword instancetype, indicating that the value returned from this method should be of the same type as its receiver (here, a Dog).

Referring to Instances

This chapter has largely concentrated on the mechanics of instance creation. Often, however, your code will be concerned, not with creating a new instance, but with referring to an instance that already exists. An instance can be referred to either by using the name of an object reference to which it has previously been assigned (a variable, which may be an ivar) or by producing it as the result of a method call — and in no other way. If you haven’t already got a named reference to a certain instance (by way of a variable or ivar), there may be a method call that returns the desired instance. For example, this is how you ask an array (an NSArray) for its last element:

id myThing = [myArray lastObject];

The NSArray myArray didn’t create the object that it hands you. That object already existed; myArray was merely containing it, as it were — it was holding the object, pointing to it. Now it’s sharing that object with you, that’s all.

Similarly, many classes dispense one particular object repeatedly. For example, your app has exactly one instance of the UIApplication class (we call this the singleton UIApplication instance); to access it, you send the sharedApplication class method to the UIApplication class:

UIApplication* theApp = [UIApplication sharedApplication];

This singleton instance existed before you asked for it; indeed, it existed before any code of yours could possibly run. You don’t care how it was brought into being; all you care is that you can get hold of it when you want it. I’ll talk more about globally available singleton objects of this kind in Chapter 13.

In both those examples, the code is concerned with two things: finding a way to specify an already existing instance, and assigning that existing instance to a variable, thus creating (not a new instance, but) a new name under which to refer to that already existing instance. These are both aspects of the same thing — referring to an instance.

The business of referring to an instance is something with which you will be intimately concerned while programming iOS. The matter may sound trivial, but it is not. Indeed, the problem of referring to an already existing instance is so important that I will devote much of Chapter 13 to it. An instance does you no good if you can’t refer to it. If you can’t refer to it, you can’t send a message to it. If you can’t refer to it, you can’t use it as an argument in a method call. If you can’t refer to it, you can’t find out anything about or do anything to or with it. You will quite often find yourself in a situation where you know an instance exists but you have to sweat in order to refer to it. You may even have to rewrite or rearchitect your program, changing what happens earlier in the program so that you’ll be able to get a reference to a particular instance later in the program at the moment when you need it.

Moreover, once you do have a reference to a desired instance, you may very well be concerned to keep it. In the case of a singleton instance such as [UIApplication sharedApplication], this is not really an issue. There is just one shared application instance, and the UIApplication class will be happy to hand it to you over and over again whenever you ask for it. Thus, you could just keep saying [UIApplication sharedApplication] in various places in your program, and you probably will. Assigning the shared application instance to a variable of your own, such as theApp in the earlier example, is merely a convenience. It’s just a short, easy name for this same instance.

Not so, though, with an instance like [myArray lastObject]. Here, we already had a reference to an array (myArray), and now we are concerned with obtaining a reference to one of its elements, namely, the last one. The instance that currently functions as the last element of myArraymight not always be the last element of myArray. It might not always be an element of myArray at all. In fact, the array myArray might itself go out of existence. If the particular instance that we are presently able to refer to as [myArray lastObject] is going to be important to us in the future, we may need to take steps now to maintain some other reference to it, one that does not depend upon the status or state of some array. That is a likely reason for assigning the instance returned by [myArray lastObject] to a variable myThing. Now, regardless of what happens to the array, the name myThing will continue on as a reference to this instance.

In the preceding code, though, myThing is obviously just a local automatic variable; the variable will go out of scope when the current scope ends (for example, when the current method finishes executing), and the ability to refer to this instance will be lost. What can we do about that? Well, all this is happening within the class code running within some instance: let’s say it’s a Dog instance. If we need the myThing instance to live longer within this Dog instance, we will want to assign it to an instance variable. And doing so has an additional benefit: thereafter, other instance methods of this Dog instance will have a reference to it! What’s more, if there’s an accessor, other objects, if they have a reference to the Dog instance, will have a reference to the myThing instance as well! By this technique, we promote or extend the life of an instance, while broadening and ensuring our own future ability to get a reference to it. That, indeed, is such an important and valuable thing to be able to do that it will often be our reason for giving a class an instance variable in the first place.