Using Object-Oriented Features in Objective-C
- Communicating to Methods with Messages
- Allocating and Initializing Objects
- Summary
- Q&A
- Workshop
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.)
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.
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.
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.
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.
Nesting Messages
Messages can be nested within one another. You could write the following:
myObject = [MyClass
alloc
]; myObject = [myObjectinit
];
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.
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 =[NSSet
alloc
]; [mySetinitWithArray
: 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
(instanceType
)initWithSet:copyItems: