Hour 10. Declaring Methods in an Interface File


What You’ll Learn in This Hour

Image Examining the difference between class and instance methods

Image Naming methods properly

Image Returning complex data structures as method results


Working with Methods in a Class

As you have seen in the previous hours of this part, you declare classes that can contain instance variables and declared properties in addition to the information in the class declaration itself. The other major component of a class is its methods. Methods are the messages to which instances of the class (or, in some cases, the class itself) respond. They provide the functionality for the class.

In this hour, you learn how to declare and define your classes. To help you create useful methods, you also see the basics of how people can use the classes that you create.

Objective-C methods use much the same syntax as do C functions. The major difference is that Objective-C methods use named arguments. Inside the body of a method, the structure is the same as the inside of a C function, although, of course, you can use Objective-C syntax in addition to the standard C syntax. Remember that C code compiles properly under Objective-C, so nothing prevents you from mixing Objective-C and C code; you also can write a method that consists solely of C code.

Because Objective-C methods are so similar to C functions, a good place to start is with the naming conventions for Objective-C and Cocoa methods. The naming conventions provide standards that make your code easier to read (this is valuable even on a one-person project). In addition, the options and standards help you to appreciate the features and options that are available to you as you develop Objective-C methods.

Reviewing Method Syntax

As you have seen, the basic syntax for a method declaration consists of two basic parts followed, as always with a declaration, by a semicolon. The two parts are the instance/class indicator and the method header itself.

Distinguishing Between Class and Instance Methods

The first character indicates if this is a class instance (+) or a method instance (-). Class instances are called using the class name rather than a specific instance. They often are used as factory methods to create new instances of the class. In many cases, these new instances represent a conversion from other classes (or even basic types) to the class.

For example, NSNumber has class methods that return new instances of NSNumber based on values that are passed in. Here is a commonly used method:

+ (NSNumber *)numberWithBool:(BOOL)value;

You pass in a BOOL and receive a new instance of NSNumber. You perform this method from an implementation file by using the following:

NSNumber *myNumber = [NSNumber numberWithBool: YES];

A more common invocation would use a variable for the argument:

BOOL myBool = YES;
NSNumber *myNumber = [NSNumber numberWithBool: myBool];

An instance method is declared with a - at the beginning. Most init methods initialize an already-created instance and set the appropriate values, as follows:

– (id)initWithBool:(BOOL)value;

The difference between the instance method and the class method is that you must have created the instance first. Thus, you need both of these lines of code:

myNumber = [NSNumber alloc];
[myNumber initWithBool: myBool];

As shown previously, you can combine these two lines of code into one:

myNumber = [[NSNumber alloc] initWithBool: myBool];


Tip: Copying and Pasting Method Declarations and Implementations

If you have a method declaration such as

Click here to view code image

– (id)initWithBool:(BOOL)value;

you can copy and paste it into your implementation. Delete the final semicolon and type a single open brace. When you press Return, Xcode adds a blank line and a closing brace. You can now start to write the code.

Click here to view code image

– (id)initWithBool:(BOOL)value {

}


Exploring the Method Declaration

Look closely at a method declaration to understand its three basic components. This is a method declaration that has been used previously in this hour and one that is frequently used by programmers:

– (id)numberWithBool:(BOOL)value;

After the instance/class indicator, the components are the following:

Image Return value—Just as with C functions, each method can return a result (in fact, all methods return a result, as you see later in this section). The result is a single value, but it can be a collection object such as NSDictionary or NSArray, which can contain multiple values within the single object.

Image Method name—This is a standard Objective-C identifier. Naming standards for methods are described in this section.

Image Arguments—There can be zero or more of these. As with C functions, you can end the list with an ellipsis (...) to indicate a variable number of arguments (this is called a variadic method or function). That style is rarely used today in Objective-C, and it is not discussed in this book.

Return Value

Every method returns the same type of value: an id. This is a pointer to an object—any object. (Note that you don’t use an asterisk with the id type.) Standard practice is to cast the result of a method to a more specific value using the standard casting syntax. For example, consider this class method:

+ (NSNumber *)numberWithBool:(BOOL)value;

The returned id (a pointer to an object) is cast to being a pointer to an NSNumber instance. This enables better compile-time checking of the code that you write.

Perhaps the most common casting of a method result is not to a pointer to an object; it is cast to void. You can see this in methods such as the following:

– (void)setIdentifier:(NSString *)identifier

For methods that return values that are not objects, you can use the standard C types such as float, short, double, and unsigned char.

Method Name

By convention, a method name begins with a lowercase character. If it consists of several words, combine them by starting each word after the first one with a capital letter. Do not use underscores or other special characters.

Method names are often verbs. You may modify them, but somewhere (preferably at the beginning), there should be a verb. You have already seen examples of simple methods that consist only of a verb (init and alloc, for example).


Tip

Although “do” is a verb, for the sake of method naming, ignore it. doDuplicate is not a good method name: Simply use duplicate. do adds nothing to the method name.


If a method performs several tasks, they should normally be reflected in the method name unless they are clearly part of the main task. As the frequently cited example of alloc and init shows, it can be better to have two separate methods that cooperate by returning a value that is passed into the next one. That way, you know what is happening.


Tip: Do Not Hide Method Tasks

The only exception to this guideline is the case in which one or more tasks are subsidiary and are so essential that it is inconceivable that the method’s main task could be performed without them. This guidance is particularly important for tasks that create, modify, or change data. If your method is going to create a certain object with a name that is passed into the method, checking to see if the name is a duplicate is pretty clearly part of the basic processing, and there often is no reason to separate the process into two tasks.


What is common, however, is to create a composite task that interacts with the user. You might have a task called createNamedObject that returns an NSError object. The composite task createNamedObjectWithError could add user interaction for error handling. Both methods would ultimately do the same thing, but this structure enables you to create a pair of methods that can be used in a variety of circumstances.

Many methods do not perform tasks, and in these cases, verbs are inappropriate. If a method returns a value, the beginning of its method name should be the name of what it is returning; get is as superfluous as do.

Arguments

Methods can accept any number of arguments. A colon precedes each argument. When you are looking at a list of methods (perhaps in a class reference), this fact is important. For example, Listing 10.1 shows the instance methods for working with state information in NSPersistentStore.

LISTING 10.1 State Information Methods in NSPersistentStore


– type
– persistentStoreCoordinator
– configurationName
– options
– URL
– setURL:
– identifier
– setIdentifier:
– isReadOnly
– setReadOnly:


The colons let you distinguish between the methods that take no arguments and the three methods listed below that take a single argument:

Image setURL

Image setIdentifier

Image setReadOnly

Methods can take more than one argument. Here is a method from NSPersistentStore that takes three arguments:

+ setMetadata:forPersistentStoreWithURL:error:

As you can see, each argument follows a colon. In all cases except the first argument, the argument has a name. In the case of the first argument, the name of the argument is the name of the method.

Writing the Method Declaration

Particularly when a method has several arguments, the method declaration becomes a meaningful phrase and sometimes even a sentence. The method name is frequently a verb, and the argument names often include a preposition as in the example just shown. A good example of the argument is forPersistentStoreWithURL. That particular argument has a bonus by having two prepositions. forPersistentStore and WithURL provide clear indications of how setMetadata functions.

Also, the final argument, error, illustrates another common aspect of argument naming. Certain arguments such as error are so common that it is not necessary to decorate them with a preposition. You could name the final argument withError, but the convention of a final argument named error is sufficient for most people.

Returning Complex Data Structures from Methods

You can easily return a result from a method. The default return value is id, and you can cast it to a pointer to a class instance such as NSView * or to the common void, which effectively returns nothing from the method.

Because the result is a pointer to a class instance in many cases, it can carry all of the data in that class instance. Many (possibly most) classes have significant amounts of data. The NSNumber class is used in this hour precisely because it does not have much data, and you can see how its methods work.

Some classes are specifically designed to manage large amounts of data.

GO TO Image Hour 15, “Organizing Data with Collections,” p. 205, to learn how to work with dictionaries, sets, and arrays.

Pointers can be dereferenced with & so as to get to the underlying data. This is commonly used with NSError. Some methods use double indirection in their declaration, as shown here for outError:

(BOOL)readFromURL:(NSURL *)url error:(NSError **)outError

You can invoke it with code such as the following:

NSError *err = nil;
myResult =  [myDocument readFromURL:myURL error: &error];

The argument myURL is a pointer to the NSURL class. outError is a pointer to a pointer to the NSError class (this is called double indirection). If the method makes a change to myURL, it affects the object passed in via the argument. With the double indirection of outError, the method can change the pointer so that it points to another object. Typically, it is used to change it from its initial value (nil) to another instance of NSError. In this way, a method can return a new value not only as its result (BOOL, in this case), but also through a doubly indirected argument.

Biggest Difference in Architectures for Returning Objects

The biggest difference between returning an object as a method result and returning an object using double indirection as described here is that you can only return one method result (although it can contain many elements within the object returned), but with double indirection you can have several arguments that can return results. Before embarking on this architecture, think about whether this is the best structure.

In many cases, if you think you need to return three separate results through arguments, maybe you need to construct a new class or even a container class such as NSDictionary that can bring those separate results into a single, logical form. Returning several values that are related only by a single method call may indicate that the method is too general or is not focused enough.

The common use of an NSError argument that is passed in as nil and may be returned as a value or still as nil is a good design because in most cases, nothing new is returned. If there is no error, nil is passed in and nil is returned. Returning a new NSError object (or any other object in other cases) is appropriate when the primary result is returned as the method’s result and the other result is returned either in an error condition or another rare and exceptional circumstance.

This all boils down to a matter of programming style and personal preference, but most developers have come to believe that the simplest implementation of any process is best if only because when new developers come along to maintain it, they will understand what it does.

Summary

This hour has shown you how to declare methods in your interface. Methods are of two types: instance and class methods. Class methods are called on the class itself—often they are factory methods that create new instances of the class. Each type of method then has three primary components: a result, a name, and zero or more arguments.

Q&A

Q. What is the purpose of a doubly indirected argument in a method declaration?

A. With a typical argument (single indirection such as NSError *), you pass in a pointer to an instance; you may modify it as a result of the method’s code. (This is common in the init methods.) With double indirection such as NSError **, you typically pass in a nil value and return a new object. (In some cases, you pass in one object and return another.)

Q. Why is the ellipsis not used much at the end of a list of method arguments?

A. The code can be clearer if each argument is named. If you need a flexible number of arguments, consider using one of the collection classes such as NSArray, NSSet, or NSDictionary.

Workshop

Quiz

1. What does (void) mean at the beginning of a method declaration?

2. What are the basic rules of method declaration naming?

Quiz Answers

1. Nothing is returned.

2. The method itself should be a verb if it does something; if it simply returns a value, it should be the name of the value. Argument names typically end with a prepositional phrase such as withStyle.

Activities

How many problems can you find with these declarations?

– convertRectToCircle: (NSRect *)aRect;
– doMainProcess;
– (MyUserClass *)getUserIDForName: (NSString*)aName;

..................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