Вы находитесь на странице: 1из 6

Cocoa Style for Objective-C: Part II

In a nutshell: how Cocoa and Objective-C code should look

Once you've figured out the basics of Objective-C and Cocoa, you're ready to start
writing some code. But the conventions of naming and formatting Objective-C code
are not the same as traditional C, C++ or even Java programs.

Apple has laid out a set of guidelines as to how code should be written for
maximum clarity and integration with the frameworks. In addition, there are some
undocumented conventions that Cocoa developers often use.

In essence, the human factor present in Apple's products for the end user can be
found in Objective-C and Cocoa themselves.

Part 1: basics on naming classes, variables, accessors, general methods and


abbreviations.
Part 2: more detail on method names, global symbols, the id type, method
parameters, etc

1 of 8

Method Names: Returning Objects

In addition to simple accessors, classes or objects can also return objects based
on various conditions or input. The format is simple:

[object/class thing+condition];
[object/class thing+input:input];
[object/class thing+identifer:input];

Examples

realPath = [path stringByExpandingTildeInPath];


fullString = [string stringByAppendingString:@"Extra Text"];
object = [array objectAtIndex:3];

// class methods
newString = [NSString stringWithFormat:@"%f",1.5];
newArray = [NSArray arrayWithObject:newString];
If I wrote some of my own, this is what they might look like.

recipients = [email recipientsSortedByLastName];


newEmail = [CDCEmail emailWithSubjectLine:@"Extra Text"];
emails = [mailbox messagesReceivedAfterDate:yesterdayDate];
Note that all of these messages first indicate what kind of thing will be
returned, followed by what the circumstances will be for returning it. Also note
that the last word right before the colon describes the type of the supplied
argument.

Sometimes, you want a variation on a value. In that case, the format is generally:

[object adjective+thing];
[object adjective+thing+condition];
[object adjective+thing+input:input];

Examples

capitalized = [name capitalizedString];


rate = [number floatValue];
newString = [string decomposedStringWithCanonicalMapping];
subarray = [array subarrayWithRange:segment];
Messages are rarely quite as long as -decomposedStringWithCanonicalMapping

2 of 8

Avoid Ambiguity

Bugs are scarce where code doesn't leave questions unanswered.

Ambiguous Messages

-sortInfo
-refreshTimer
-update
-fetchInfo:
On the surface, these methods may seem good. For example, they all have vowels.
But what they share is the potential for different interpretations because of the
language used.

sortInfo - returns sort info, or sort something called "info"?


refreshTimer - return a timer used for refreshing, or refresh a timer?
update - a verb? what is updated and how?
fetchInfo - fetch info about something or give info about a fetch?
This is all fixed by slightly modifying the phrases:

Clear Messages

-currentSortInfo // "current" obviously describes the noun "sort info"


-refreshDefaultTimer // refresh is now clearly a verb
-updateMenuItemTitle // an action is taking place
-infoForFetch: // now we know info is returned for a fetch
By just adding a few characters to each method, we've removed almost all
ambiguity. And there was much rejoicing.

Note that the -updateMenuItem method doesn't put the NS prefix on menu item

3 of 8

Global C Functions

Global C functions generally use one of a few simple formulas:

Prefix + Value ()
Prefix + Value + With/From/For + Input ()
Prefix + Action ()
Prefix + Action + Type ()
Just like classes, functions are prefixed with initials in order to prevent
namespace issues. Since C functions are free-standing by nature, the function name
needs to indicate data types they interact with, if any.
Functions from Cocoa

NSHomeDirectory()
NSHomeDirectoryForUser()
NSClassFromString()
NSBeginAlertSheet()
NSDrawGrayBezel()

Core Services Functions

In Core Services frameworks such as Core Foundation and Core Graphics, functions
are prefixed with the most-relevant opaque type, and the "get" prefix is used even
when there's no indirection involved:

Core Foundation

CFArrayGetValueAtIndex() // returned directly, but "get" is still used


CFDictionaryGetValue()
CFDateGetAbsoluteTime()

Core Graphics / Quartz

CGImageCreate()
CGImageGetHeight()
CGImageGetTypeID()
4 of 8

Other Global Symbols

There are several types of symbols with global scope in addition to C functions.
For example:

Constants
Typedef'd structs
Typedef'd enums
Individual enum values
Objective-C Protocols
Protocols, constants, structs, enums and enum values are basically named according
to the same rules as classes or C functions. Capitalized with initials at the
front:

Structs

NSPoint point; // struct


NSRange range; // struct
NSRectArray * rects; // c-style array of structs
In Cocoa, enums are frequently used as "modes" for methods:

range = [string rangeOfString:@"find me" options:NSLiteralSearch];


Both constants and enums have a suffix that indicates what kind of thing they are:

Constants and Enums

// search modes (enums)

NSLiteralSearch
NSCaseInsensitiveSearch
// exception names (constants)

NSMallocException
NSInvalidArgumentException

// notification names (constants)

NSTaskDidTerminateNotification
NSWindowWillMoveNotification
Also, note that notification names have a slightly different formula:

Class of Affected Object + Did/Will + Action + "Notification"


5 of 8

Dynamic Typing

Objective-C is a dynamically-typed language, meaning that you don't have to tell


the compiler what type of object you're working with at compile time.

Declaring a type for a varible is merely a promise which can be broken at runtime
if the code leaves room for such a thing. You can declare your variables as type
id, which is suitable for any Objective-C object.

Dynamically-Typed Variables

id hostName;
id ipAddress;
id keyedAccountNames;
id theObject;

// the compiler is fine with this

theObject = [NSString string];


theObject = [NSNumber numberWithInt:1];
theObject = [NSDictionary dictionary];

So why specify type at all? Three basic reasons:

To be clear: Makes it clear what you intend to do with the variable


To avoid useless warnings: If multiple classes share the same method name, the
compiler may warn you when you send that message to a generic object.
To get useful warnings: If you mispell a message name, such as "-stringg", the
compiler will tell you that NSMutableString does not implement such a method
In addition, there are situations where the id type makes the most sense. Some
are:

A delegate or datasource
Object for a notification
Contents for a generic container
Objects involved in target/action
So no hard rules here, but a good basic practice is to specify the type if you
have reason to believe other types of objects wouldn't make sense in a given
situation.

6 of 8
When to Use Accessors

Short answer: always

Why not just directly access instance variables within a class? It's a lot less
code, right?

The reason is flexibility. If your code gets to data via accessors, it's easy to
change how that data is manipulated later.

For example, it gives you a good entry point for registering the previous value
with NSUndoManager. Or when debugging, it might help to log when a particular
instance variable is fetched.

But there's an even better reason to create accessors: Key-Value Coding. KVC is a
protocol used throughout Cocoa, most notably in bindings. It will look for
accessors for your keys first, and only access data directly as a last resort. You
can shorten KVC's search and thus speedup data access by implementing accessors.

Also be aware that if you set instance variables directly, in the form of var =
value, Key-Value Observing will not notice the change and bound objects will not
get the new value.

7 of 8

Naming Parameters

Let's take a quick visit to method parameters. What's the standard here? The
guidelines are considerably more loose, but typically you prefix the input name
with "the", "an" or "new"

Prefixes for Method Parameters

- (void) setTitle: (NSString *) aTitle;


- (void) setName: (NSString *) newName;
- (id) keyForOption: (CDCOption *) anOption
- (NSArray *) emailsForMailbox: (CDCMailbox *) theMailbox;
- (CDCEmail *) emailForRecipients: (NSArray *) theRecipients;

Also worth noting is the naming convention for a loop. Typically, the current
object in the loop is prefixed with "one" or "a/an". Some also simply refer to the
individual object as "item":

Variable Names in Loops

for (i = 0; i < count; i++) {


oneObject = [allObjects objectAtIndex: i];
NSLog (@"oneObject: %@", oneObject);
}

NSEnumerator *e = [allObjects objectEnumerator];


id item;

while (item = [e nextObject])


NSLog (@"item: %@", item);
8 of 8
Odds and Ends

If you're sending a message with a particularly long name, break it up into


multiple lines:

Splitting Up Long Message Names

color = [NSColor colorWithCalibratedHue: 0.10


saturation: 0.82
brightness: 0.89
alpha: 1.00];

Classes that return one and only one instance of themselves (singletons) are named
and implemented as follows:

Singleton

@implementation CDCMailboxManager

+ (id) sharedMailboxManager
{
static CDCMailboxManager * shared = nil;

if ( !shared )
shared = [[self alloc] init];

return shared;
}

Вам также может понравиться