Add section on properties from dmaclach, remove some tabs.

This commit is contained in:
pinkerton 2008-09-10 19:31:02 +00:00
parent 48fcffea4c
commit a7dd19342d

View File

@ -5,13 +5,13 @@
<div align="right"> <div align="right">
<address> <address>
Mike Pinkerton<br/> Mike Pinkerton<br/>
Greg Miller <br/> Greg Miller <br/>
Dave MacLachlan Dave MacLachlan
</address> </address>
</div> </div>
<OVERVIEW> <OVERVIEW>
<CATEGORY title="Important Note"> <CATEGORY title="Important Note">
@ -34,31 +34,40 @@
<CATEGORY title="Background"> <CATEGORY title="Background">
<p>Objective-C is a very dynamic, object-oriented extension of C. It's <p>
designed to be easy to use and read, while enabling sophisticated Objective-C is a very dynamic, object-oriented extension of C. It's
object-oriented design. It is the primary development language for new designed to be easy to use and read, while enabling sophisticated
applications on Mac OS X and the iPhone.</p> object-oriented design. It is the primary development language for new
applications on Mac OS X and the iPhone.
</p>
<p>Cocoa is one of the main application frameworks on Mac OS X. It is a <p>
collection of Objective-C classes that provide for rapid development of Cocoa is one of the main application frameworks on Mac OS X. It is a
full-featured Mac OS X applications.</p> collection of Objective-C classes that provide for rapid development of
full-featured Mac OS X applications.
</p>
<p>Apple has already written a very good, and widely accepted, coding guide <p>
for Objective-C. Google has also written a similar guide for C++. This Apple has already written a very good, and widely accepted, coding guide
Objective-C guide aims to be a very natural combination of Apple's and for Objective-C. Google has also written a similar guide for C++. This
Google's general recommendations. So, before reading this guide, please make Objective-C guide aims to be a very natural combination of Apple's and
sure you've read: Google's general recommendations. So, before reading this guide, please make
<ul> sure you've read:
<li><a href="http://developer.apple.com/documentation/Cocoa/Conceptual/CodingGuidelines/index.html">Apple's <ul>
Cocoa Coding Guidelines</a></li> <li>
<li> <a href="http://developer.apple.com/documentation/Cocoa/Conceptual/CodingGuidelines/index.html">
Apple's Cocoa Coding Guidelines
<div> </a>
<a href="http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml">Google's </li>
Open Source C++ Style Guide</a> <li>
</div>
</li> <div>
</ul> <a href="http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml">
Google's Open Source C++ Style Guide
</a>
</div>
</li>
</ul>
</p> </p>
@ -80,8 +89,11 @@
<p> <p>
Google has already released open-source code that conforms to these Google has already released open-source code that conforms to these
guidelines as part of the <a href="http://code.google.com/p/google-toolbox-for-mac/">Google guidelines as part of the
Toolbox for Mac project</a> (abbreviated GTM throughout this document). <a href="http://code.google.com/p/google-toolbox-for-mac/">
Google Toolbox for Mac project
</a>
(abbreviated GTM throughout this document).
Code meant to be shared across different projects is a good candidate to Code meant to be shared across different projects is a good candidate to
be included in this repository. be included in this repository.
</p> </p>
@ -91,124 +103,126 @@
<p> <p>
Note that this guide is not an Objective-C tutorial. We assume that the Note that this guide is not an Objective-C tutorial. We assume that the
reader is familiar with the language. If you are new to Objective-C or reader is familiar with the language. If you are new to Objective-C or
need a refresher, please read <a href="http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/index.html">The need a refresher, please read
Objective-C Programming Language</a>. <a href="http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/index.html">
The Objective-C Programming Language
</a>.
</p> </p>
</CATEGORY> </CATEGORY>
</OVERVIEW> </OVERVIEW>
<CATEGORY title="Example"> <CATEGORY title="Example">
<p> <p>
They say an example is worth a thousand words so let's start off with an They say an example is worth a thousand words so let's start off with an
example that should give you a feel for the style, spacing, naming, etc. example that should give you a feel for the style, spacing, naming, etc.
</p> </p>
<p> <p>
An example header file, demonstrating the correct commenting and spacing An example header file, demonstrating the correct commenting and spacing
for an <code>@interface</code> declaration for an <code>@interface</code> declaration
</p> </p>
<pre> <CODE_SNIPPET>
// GTMFoo.h // GTMFoo.h
// FooProject // FooProject
// //
// Created by Greg Miller on 6/13/08. // Created by Greg Miller on 6/13/08.
// Copyright 2008 Google, Inc. All rights reserved. // Copyright 2008 Google, Inc. All rights reserved.
// //
#import &lt;Foundation/Foundation.h&gt; #import &lt;Foundation/Foundation.h&gt;
// A sample class demonstrating good Objective-C style. All interfaces, // A sample class demonstrating good Objective-C style. All interfaces,
// categories, and protocols (read: all top-level declarations in a header) // categories, and protocols (read: all top-level declarations in a header)
// MUST be commented. Comments must also be adjacent to the object they're // MUST be commented. Comments must also be adjacent to the object they're
// documenting. // documenting.
// //
// (no blank line between this comment and the interface) // (no blank line between this comment and the interface)
@interface GTMFoo : NSObject { @interface GTMFoo : NSObject {
@private @private
NSString *foo_; NSString *foo_;
NSString *bar_; NSString *bar_;
} }
// Returns an autoreleased instance of GMFoo. See -initWithString: for details // Returns an autoreleased instance of GMFoo. See -initWithString: for details
// about the argument. // about the argument.
+ (id)fooWithString:(NSString *)string; + (id)fooWithString:(NSString *)string;
// Designated initializer. |string| will be copied and assigned to |foo_|. // Designated initializer. |string| will be copied and assigned to |foo_|.
- (id)initWithString:(NSString *)string; - (id)initWithString:(NSString *)string;
// Gets and sets the string for |foo_|. // Gets and sets the string for |foo_|.
- (NSString *)foo; - (NSString *)foo;
- (void)setFoo:(NSString *)newFoo; - (void)setFoo:(NSString *)newFoo;
// Does some work on |blah| and returns YES if the work was completed // Does some work on |blah| and returns YES if the work was completed
// successfuly, and NO otherwise. // successfuly, and NO otherwise.
- (BOOL)doWorkWithString:(NSString *)blah; - (BOOL)doWorkWithString:(NSString *)blah;
@end @end
</pre> </CODE_SNIPPET>
<p> <p>
An example source file, demonstating the correct commenting and spacing An example source file, demonstating the correct commenting and spacing
for the <code>@implementation</code> of an interface. It also includes the for the <code>@implementation</code> of an interface. It also includes the
reference implementations for important methods like getters and setters, reference implementations for important methods like getters and setters,
<code>init</code>, and <code>dealloc</code>. <code>init</code>, and <code>dealloc</code>.
</p> </p>
<pre> <CODE_SNIPPET>
// //
// GTMFoo.m // GTMFoo.m
// FooProject // FooProject
// //
// Created by Greg Miller on 6/13/08. // Created by Greg Miller on 6/13/08.
// Copyright 2008 Google, Inc. All rights reserved. // Copyright 2008 Google, Inc. All rights reserved.
// //
#import "GTMFoo.h" #import "GTMFoo.h"
@implementation GTMFoo @implementation GTMFoo
+ (id)fooWithString:(NSString *)string { + (id)fooWithString:(NSString *)string {
return [[[self alloc] initWithString:string] autorelease]; return [[[self alloc] initWithString:string] autorelease];
}
// Must always override super's designated initializer.
- (id)init {
return [self initWithString:nil];
}
- (id)initWithString:(NSString *)string {
if ((self = [super init])) {
foo_ = [string copy];
bar_ = [[NSString alloc] initWithFormat:@"hi %d", 3];
} }
return self;
} // Must always override super's designated initializer.
- (id)init {
- (void)dealloc { return [self initWithString:nil];
[foo_ release]; }
[bar_ release];
[super dealloc]; - (id)initWithString:(NSString *)string {
} if ((self = [super init])) {
foo_ = [string copy];
- (NSString *)foo { bar_ = [[NSString alloc] initWithFormat:@"hi %d", 3];
return foo_; }
} return self;
}
- (void)setFoo:(NSString *)newFoo {
[foo_ autorelease]; - (void)dealloc {
foo_ = [newFoo copy]; [foo_ release];
} [bar_ release];
[super dealloc];
- (BOOL)doWorkWithString:(NSString *)blah { }
// ...
return NO; - (NSString *)foo {
} return foo_;
}
@end
</pre> - (void)setFoo:(NSString *)newFoo {
[foo_ autorelease];
foo_ = [newFoo copy];
}
- (BOOL)doWorkWithString:(NSString *)blah {
// ...
return NO;
}
@end
</CODE_SNIPPET>
</CATEGORY> </CATEGORY>
@ -828,11 +842,11 @@
<BODY> <BODY>
<p> <p>
Unlike C++, Objective-C doesn't have a way to differentiate between Unlike C++, Objective-C doesn't have a way to differentiate between
public and private methods &#8212; everything is public. As a result, avoid public and private methods &#8212; everything is public. As a result,
placing methods in the public API unless they are actually expected to avoid placing methods in the public API unless they are actually
be used by a consumer of the class. This helps reduce the likelihood expected to be used by a consumer of the class. This helps reduce the
they'll be called when you're not expecting it. This includes methods likelihood they'll be called when you're not expecting it. This includes
that are being overridden from the parent class. For internal methods that are being overridden from the parent class. For internal
implementation methods, use a category defined in the implementation implementation methods, use a category defined in the implementation
file as opposed to adding them to the public header. file as opposed to adding them to the public header.
</p> </p>
@ -1123,9 +1137,177 @@
</CODE_SNIPPET> </CODE_SNIPPET>
</BODY> </BODY>
</STYLEPOINT> </STYLEPOINT>
<STYLEPOINT title="Properties">
<SUMMARY>
Properties in general are allowed with the following caveat: properties
are an Objective-C 2.0 feature which will limit your code to running
on the iPhone and MacOS X 10.5 (Leopard) and higher. Dot notation to
access properties is not allowed.
</SUMMARY>
<BODY>
<SUBSECTION title="Naming">
<p>
A property's associated instance variable's name must conform to the
trailing _ requirement. The property's name should be the same as its
associated instance variable without the trailing _.
</p>
<p>
Use the @synthesize directive to rename the property correctly.
</p>
<CODE_SNIPPET>
@interface MyClass : NSObject {
@private
NSString *name_;
}
@property(copy, nonatomic) NSString *name;
@end
@implementation MyClass
@synthesize name = name_;
@end
</CODE_SNIPPET>
</SUBSECTION>
<SUBSECTION title="Location">
<p>
A property's declaration must come immediately after the instance
variable block of a class interface. A property's definition must
come immediately after the <code>@implementation</code> block in a
class definition. They are indented at the same level as the
<code>@interface</code> or <code>@implementation</code> statements
that they are enclosed in.
</p>
<CODE_SNIPPET>
@interface MyClass : NSObject {
@private
NSString *name_;
}
@property(copy, nonatomic) NSString *name;
@end
@implementation MyClass
@synthesize name = name_;
- (id)init {
...
}
@end
</CODE_SNIPPET>
</SUBSECTION>
<SUBSECTION title="Use Copy Attribute For Strings">
<p>
NSString properties should always be declared with the
<code>copy</code> attribute.
</p>
<p>
This logically follows from the requirement that setters for
NSStrings always must use <code>copy</code> instead of
<code>retain</code>.
</p>
</SUBSECTION>
<SUBSECTION title="Never synthesize CFType properties">
<p>
CFTypes should always have the <code>@dynamic</code> implementation
directive.
</p>
<p>
Since CFTypes can't have the <code>retain</code> property
attribute, the developer must handle retaining and releasing the
value themselves. In the rare case that you do actually want
assignment it is better to make that completely clear by actually
implementing the setter and getter and commenting why that is the
case.
</p>
</SUBSECTION>
<SUBSECTION title="List out all implementation directives">
<p>
Use implementation directives for all properties even if they are
<code>@dynamic</code> by default.
</p>
<p>
Even though <code>@dynamic</code> is default, explicitly list it out
with all of the other property implementation directives making it
clear how every property in a class is handled at a single glance.
</p>
<BAD_CODE_SNIPPET>
@interface MyClass : NSObject
@property(readonly) NSString *name;
@end
@implementation MyClass
.
.
.
- (NSString*)name {
return @"foo";
}
@end
</BAD_CODE_SNIPPET>
<CODE_SNIPPET>
@interface MyClass : NSObject
@property(readonly) NSString *name;
@end
@implementation MyClass
@dynamic name;
.
.
.
- (NSString*)name {
return @"foo";
}
@end
</CODE_SNIPPET>
</SUBSECTION>
<SUBSECTION title="Atomicity">
<p>
Be aware of the overhead of properties. By default, all synthesized
setters and getters are atomic. This gives each set and get calls a
substantial amount of synchronization overhead. Declare your
properties <code>nonatomic</code> unless you require atomicity.
</p>
</SUBSECTION>
<SUBSECTION title="Dot notation">
<p>
We do not allow the use of dot notation to access properties for
the following reasons:
</p>
<ol>
<li>
Dot notation is purely syntactic sugar for standard method calls,
whose readability gains are debatable. It just gives you another
way to make method calls.
</li>
<li>
It obscures the type that you are dereferencing. When one sees:
<code>[foo setBar:1]</code> it is immediately clear that you are
working with an Objective-C object. When one sees
<code>foo.bar = 1</code> it is not clear if foo is an object, or
a struct/union/C++ class.
</li>
<li>
It allows you to do method calls that look like getters.
<BAD_CODE_SNIPPET>
NSString *upperCase = @"foo".uppercaseString;
</BAD_CODE_SNIPPET>
which is not only confusing, but difficult to spot in a code review.
</li>
<li>
It hides method calls.
<BAD_CODE_SNIPPET>
bar.value += 10;
</BAD_CODE_SNIPPET>
is actually two separate method calls (one to set and one to get)
and if your properties are not simple you may find a lot of work
being done in a hidden manner.
</li>
</ol>
</SUBSECTION>
</BODY>
</STYLEPOINT>
</CATEGORY> </CATEGORY>
<CATEGORY title="Cocoa Patterns"> <CATEGORY title="Cocoa Patterns">
<STYLEPOINT title="Delegate Pattern"> <STYLEPOINT title="Delegate Pattern">