Hour 3. Using Object-Oriented Features in Objective-C


What You’ll Learn in This Hour

Image Sending and receiving messages

Image Looking inside a message

Image Initializing objects


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 = [MyClass alloc];
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 =[NSSet alloc];
[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

(instanceType)initWithSet:copyItems:

Allocating and Initializing Objects

The messages shown in this hour have demonstrated how you can allocate and initialize objects. Because these processes are used so extensively in Objective-C, it is worthwhile to take a few moments to look more carefully at these messages.

As noted previously, you most often create instances of classes by calling alloc. This is a class method of NSObject, which means it is available to any class in the frameworks or in your own code. You simply send a message to the class, and you get back a new instance.

MyClass *newInstance = [MyClass alloc];

Immediately thereafter, you initialize the newly created instance, most often with a call to init or a related method.

newInstance = [newInstance init];

As noted previously, you can combine these two messages into one line of code.

MyClass *newInstance = [[MyClass alloc] init];

It makes sense that alloc returns an object that you can place in an instance variable. You might be surprised that init also returns an object. The reason for this is that after you have created the new object, the call to init might not only set instance variables and other settings, but it also might decide to replace the allocated object with another one. That is the one that you should use thereafter.

By convention, initializer names start with init. They might have additional parameters, such as these various initializers for UIBarButtonItem in Cocoa Touch:

– initWithBarButtonSystemItem:target:action:
– initWithCustomView:
– initWithImage:style:target:action:
– initWithTitle:style:target:action:
– initWithImage:landscapeImagePhone:style:target:action:

Initializers may set various properties of the object being created; they also may take various routes to complete the initialization. If you create a series of initializers, there are two rules to follow:

Image The first step in an initializer is to call [super init]. This ensures that the basic object is there and complete.

Image Initializers can call other initializers that each performs some initialization. The most complete initializer (that is, the one that sets all of the properties rather than just some of them) is the designated initializer. The others are secondary initializers.

It is a good practice to put all of the initializers together in your code, possibly using a #pragma mark – section. This separates the initializers and, in the list of methods in the jump bar for a file, the pragma section names will appear.

Summary

In this hour, you have seen the messaging structure that is at the heart of Objective-C. It is not just another way of talking about the calling of methods that other languages use; it is a different way of constructing software. You see in later hours how the messaging architecture helps to implement dynamic aspects of Objective-C programs.

The common alloc and init methods have been used in this hour as examples. You have also seen how you can work with them and construct a hierarchy of designated and secondary initializers to construct your runtime objects.

Q&A

Q. Why does init return an id?

A. By returning an id, which is often a reference to the object on which it was called, it allows init to substitute a new object for the original one. Increasingly, the declarations are being changed to use the new instanceType return value, which allows for more error checking. Each new release of iOS adds more of these revisions.

Q. What is the difference between a class method and an instance method?

A. You must have an instance of a class to use an instance method; you can simply call a class method with the class name (that is, you do not need an instance). Class methods are often used as factory methods to create new instances of the class.

Workshop

Quiz

1. How do you differentiate class and instance methods in your code?

2. When do you call [super init] in an initializer?

Quiz Answers

1. Class methods begin with +; instance methods begin with –.

2. This is the first thing you do. You might go up through a hierarchy, but you have to have all of the superclasses created and initialized before you continue with your own.

Activities

Browse the Cocoa frameworks to see how messages are structured. Get used to the sequence of labeled parameters in the messages. It might take a while to be comfortable reading them, but remember that this is the environment in which you are going to be working.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.137.67