Communicating to Methods with Messages

Perhaps the biggest difference between Objective-C and languages such as C++ is its messaging syntax as well as the way people talk about it. Objective-C has classes just as other object-oriented languages do, and those classes can have methods within them. You communicate with those methods with messages. A message is enclosed within square brackets, and it consists of the name of the object to which it is being sent followed by the message itself.

The implementation files that you create carry the .m suffix because originally they were referred to as message files that contained the code for the messages defined in the header (.h) files. (This is possibly an apocryphal tale, but the importance of messaging in Objective-C is undisputed.)

NOTE

There is an ulterior purpose to this section. It does help you to understand how to communicate with Objective-C methods and messages, but the examples begin with the messages that you use to allocate and initialize objects.

Looking at a Simple Message

Here is a simple message that is sent to an object called myObject, which is assumed to be of type NSObject—the object that is the root class of most class hierarchies in Objective-C.

[myObject init];

This message calls the init method on myObject.

NOTE

That is the point made previously about the different way many people talk about Objective-C methods: They often refer to calling a message “on” an object.

Methods can return a value. If a method returns a value, you can set it to a variable as in the following:

myVariable = [myObject init];

Declaring a Method

When you declare a simple method, you use an Objective-C variation on C function syntax. NSObject, the root class of almost all of the Objective-C objects you use, does declare an init method.

NOTE

NSObject Class

As a matter of simplification, NSObject is referred to as the superclass of all objects in the Objective-C frameworks for Cocoa and Cocoa Touch. Note the NS prefix, which indicates that this method dates back to NeXTSTEP. Although it does not matter in most cases, the fact that NSObject is only the superclass of objects in the frameworks (and not all Objective-C objects) is something to bear in mind.

The following is the declaration that supports the messages shown in the previous section:

– (id)init

As you might surmise, the init method shown here returns a result of type id. (You find out more about id shortly.)

The minus sign at the start of the method is an important part of the declaration: It is the method type. It indicates that this is a method that is defined for instances of a class. Any instance of the class in which this declaration is used can invoke this method.

To put it another way, you (or an instance of a class) can send the init message to any instance of this class. Because this is the NSObject superclass of every other object, that means you can send the init message to any instance of any class.

There is more on allocating and initializing objects later in this hour.

Using Class Methods

The minus sign at the start of the method shown in the previous section indicates that it is an instance method. There is another type of method in Objective-C: a class method. It is indicated by a plus sign.

TIP

Class objects are often used as factory objects to create new, concrete instances of themselves.

A message to an instance method can be sent to any instance of that class subject to constraints for that specific class. Whereas you call an instance method on an instance of a class, you call a class method on the class itself. No instance is involved.

Class methods are used most frequently as factory methods. Perhaps the most common class method is alloc. For NSObject, its declaration is

+ (id)alloc;

Whereas you send init to an instance, as in this case:

[myObject init];

alloc allocates an uninitialized instance of a class as in

[MyClass alloc];

This returns an instance of MyClass. As you can see in the declaration, this result is of type id. It is time to explore that type.

Working with id—Strongly and Weakly Typed Variables

Objective-C supports strongly and weakly typed variables. When you reference a variable using a strong type, you specify the type of the variable. The actual variable must be of that type or a subclass of that type; if it is a subclass, it is, by definition, the type of all of its superclasses.

In Cocoa, you can declare a variable as:

NSArray *myArray

This means you could be referring to an object of type NSMutableArray, which is a subclass. You can write the same code to work with elements of the array no matter what its actual type is. If necessary, you might have to coerce a specific instance to the subclass that you want (if you know that is what it is).

id is the ultimate weakly typed variable; it could be any class. That is why it is used as the return type from alloc. alloc is a class method on NSObject so if you call it on an NSArray, you get an instance of NSArray returned through id.

NOTE

instanceType

A new keyword, instanceType, is available when working with related result types. By convention, methods beginning with names such as init and alloc always return objects that are an instance of the class type that receives the message. Thus, [MyClass init] returns an instance of MyClass. Init is declared as returning an id, but with this convention it is the related type. You can now use instanceType instead of id to specify that the returned value is the same type as the receiver’s type (that is, MyClass in this example). Because instanceType turns out to be more specific than id at compile time, it is preferable to use in these cases because it can allow for more error checking. As you can see from the examples in this hour, many types of the code you write already use specific variables of the correct type; however, instanceType in declarations of your own methods can make that more likely.

Nesting Messages

Messages can be nested within one another. You could write the following:

myObject = [MyClassalloc];
myObject = [myObject init];

This would use the class method of MyClass to allocate a new instance of MyClass, which you immediately assign to myObject.

You can nest them together as follows:

myObject = [[MyClass alloc] init];

The rules for nesting square brackets are the same as for nesting parentheses——the innermost set is evaluated first.

TIP

Xcode gives you a big assist by enabling you to set a preference to match brackets as you type.

Looking at Method Signatures and Parameters

alloc and init are very good basic examples because they have no parameters. Most methods in any language do have parameters. For example, you can write an area function that takes two parameters (height and width) and returns the product as its return value.

Other languages generally specify a name and a type for each parameter, and so does Objective-C. However, it adds another dimension: It labels each parameter.

This labeling means that the code is more readable, but you do have to understand what is going on when there is more than one parameter. When there is no parameter, the message is simply the receiver and the name of the method:

[myObject init];

If there is a parameter, it follows the method name. In the message, a colon precedes the parameter itself. For example, in NSSet, you can initialize a set with an NSArray using code like this:

mySet =[NSSetalloc];
[mySet initWithArray: myArray];

The declaration needs to specify not only the parameter name, which is used in the code of the method, but also its type:

(instanceType)initWithArray:(NSArray *)array;

The second and subsequent parameters are also labeled. The difference is that the first parameter is labeled in effect by the name of the method. If you add more parameters, their names and types are needed; they are preceded by a keyword (which, in the case of the first parameter is the method name). Here is another NSSet method. It initializes an NSSet to the elements of another NSSet (the first parameter). The second parameter specifies whether the elements of the first set are to be copied or not.

Here is a typical invocation:

[mySet: initWithSet: aSet copyItems:YES];

Here is the declaration:

(instanceType)initWithSet:(NSSet *)set copyItems:(BOOL)flag

In documentation (and in this book), the signature sometimes is compressed to be the result, method name, and parameters so that the previous declaration is shown as