mirror of
https://github.com/tiennm99/styleguide.git
synced 2026-10-05 08:14:51 +00:00
2387 lines
71 KiB
Markdown
2387 lines
71 KiB
Markdown
# Google Objective-C Style Guide
|
||
|
||
> Objective-C is a dynamic, object-oriented extension of C. It's designed to be
|
||
> easy to use and read, while enabling sophisticated object-oriented design. It
|
||
> is one of the primary development languages for applications on Apple
|
||
> platforms.
|
||
>
|
||
> Apple has already written a very good, and widely accepted, [Cocoa Coding
|
||
> Guidelines](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html)
|
||
> for Objective-C. Please read it in addition to this guide.
|
||
>
|
||
> The purpose of this document is to describe the Objective-C (and
|
||
> Objective-C++) coding guidelines and practices. These guidelines have evolved
|
||
> and been proven over time on other projects and teams.
|
||
> Open-source projects developed by Google conform to the requirements in this guide.
|
||
>
|
||
> 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 need a
|
||
> refresher, please read [Programming with
|
||
> Objective-C](https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Introduction/Introduction.html).
|
||
|
||
|
||
|
||
## Principles
|
||
|
||
### Optimize for the reader, not the writer
|
||
|
||
Codebases often have extended lifetimes and more time is spent reading the code
|
||
than writing it. We explicitly choose to optimize for the experience of our
|
||
average software engineer reading, maintaining, and debugging code in our
|
||
codebase rather than the ease of writing said code. For example, when something
|
||
surprising or unusual is happening in a snippet of code, leaving textual hints
|
||
for the reader is valuable.
|
||
|
||
### Be consistent
|
||
|
||
When the style guide allows multiple options it is preferable to pick one option
|
||
over mixed usage of multiple options. Using one style consistently throughout a
|
||
codebase lets engineers focus on other (more important) issues. Consistency also
|
||
enables better automation because consistent code allows more efficient
|
||
development and operation of tools that format or refactor code. In many cases,
|
||
rules that are attributed to "Be Consistent" boil down to "Just pick one and
|
||
stop worrying about it"; the potential value of allowing flexibility on these
|
||
points is outweighed by the cost of having people argue over them.
|
||
|
||
### Be consistent with Apple SDKs
|
||
|
||
Consistency with the way Apple SDKs use Objective-C has value for the same
|
||
reasons as consistency within our code base. If an Objective-C feature solves a
|
||
problem that's an argument for using it. However, sometimes language features
|
||
and idioms are flawed, or were just designed with assumptions that are not
|
||
universal. In those cases it is appropriate to constrain or ban language
|
||
features or idioms.
|
||
|
||
### Style rules should pull their weight
|
||
|
||
The benefit of a style rule must be large enough to justify asking engineers to
|
||
remember it. The benefit is measured relative to the codebase we would get
|
||
without the rule, so a rule against a very harmful practice may still have a
|
||
small benefit if people are unlikely to do it anyway. This principle mostly
|
||
explains the rules we don’t have, rather than the rules we do: for example, goto
|
||
contravenes many of the following principles, but is not discussed due to its
|
||
extreme rarity.
|
||
|
||
<a id="Example"></a>
|
||
|
||
## Example
|
||
|
||
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, and so on.
|
||
|
||
Here is an example header file, demonstrating the correct commenting and spacing
|
||
for an `@interface` declaration.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
#import <Foundation/Foundation.h>
|
||
|
||
@class Bar;
|
||
|
||
/**
|
||
* A sample class demonstrating good Objective-C style. All interfaces,
|
||
* categories, and protocols (read: all non-trivial top-level declarations
|
||
* in a header) MUST be commented. Comments must also be adjacent to the
|
||
* object they're documenting.
|
||
*/
|
||
@interface Foo : NSObject
|
||
|
||
/** The retained Bar. */
|
||
@property(nonatomic) Bar *bar;
|
||
|
||
/** The current drawing attributes. */
|
||
@property(nonatomic, copy) NSDictionary<NSString *, NSNumber *> *attributes;
|
||
|
||
/**
|
||
* Convenience creation method.
|
||
* See -initWithBar: for details about @c bar.
|
||
*
|
||
* @param bar The string for fooing.
|
||
* @return An instance of Foo.
|
||
*/
|
||
+ (instancetype)fooWithBar:(Bar *)bar;
|
||
|
||
/**
|
||
* Initializes and returns a Foo object using the provided Bar instance.
|
||
*
|
||
* @param bar A string that represents a thing that does a thing.
|
||
*/
|
||
- (instancetype)initWithBar:(Bar *)bar NS_DESIGNATED_INITIALIZER;
|
||
|
||
/**
|
||
* Does some work with @c blah.
|
||
*
|
||
* @param blah
|
||
* @return YES if the work was completed; NO otherwise.
|
||
*/
|
||
- (BOOL)doWorkWithBlah:(NSString *)blah;
|
||
|
||
@end
|
||
```
|
||
|
||
An example source file, demonstrating the correct commenting and spacing for the
|
||
`@implementation` of an interface.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
#import "Shared/Util/Foo.h"
|
||
|
||
@implementation Foo {
|
||
/** The string used for displaying "hi". */
|
||
NSString *_string;
|
||
}
|
||
|
||
+ (instancetype)fooWithBar:(Bar *)bar {
|
||
return [[self alloc] initWithBar:bar];
|
||
}
|
||
|
||
- (instancetype)init {
|
||
// Classes with a custom designated initializer should always override
|
||
// the superclass's designated initializer.
|
||
return [self initWithBar:nil];
|
||
}
|
||
|
||
- (instancetype)initWithBar:(Bar *)bar {
|
||
self = [super init];
|
||
if (self) {
|
||
_bar = [bar copy];
|
||
_string = [[NSString alloc] initWithFormat:@"hi %d", 3];
|
||
_attributes = @{
|
||
@"color" : UIColor.blueColor,
|
||
@"hidden" : @NO
|
||
};
|
||
}
|
||
return self;
|
||
}
|
||
|
||
- (BOOL)doWorkWithBlah:(NSString *)blah {
|
||
// Work should be done here.
|
||
return NO;
|
||
}
|
||
|
||
@end
|
||
```
|
||
|
||
<a id="Naming"></a>
|
||
|
||
## Naming
|
||
|
||
Names should be as descriptive as possible, within reason. Follow standard
|
||
[Objective-C naming
|
||
rules](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html).
|
||
|
||
Avoid non-standard abbreviations (including non-standard acronyms and
|
||
initialisms). Don't worry about saving horizontal space as it is far more
|
||
important to make your code immediately understandable by a new reader. For
|
||
example:
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
// Good names.
|
||
int numberOfErrors = 0;
|
||
int completedConnectionsCount = 0;
|
||
tickets = [[NSMutableArray alloc] init];
|
||
userInfo = [someObject object];
|
||
port = [network port];
|
||
NSDate *gAppLaunchDate;
|
||
```
|
||
|
||
```objectivec
|
||
// AVOID:
|
||
|
||
// Names to avoid.
|
||
int w;
|
||
int nerr;
|
||
int nCompConns;
|
||
tix = [[NSMutableArray alloc] init];
|
||
obj = [someObject object];
|
||
p = [network port];
|
||
```
|
||
|
||
Any class, category, method, function, or variable name should use all capitals
|
||
for acronyms and [initialisms](https://en.wikipedia.org/wiki/Initialism) within
|
||
(including at the beginning of) the name. This follows Apple's standard of using
|
||
all capitals within a name for acronyms such as URL, ID, TIFF, and EXIF.
|
||
|
||
Names of C functions and typedefs should be capitalized and use camel case as
|
||
appropriate for the surrounding code.
|
||
|
||
<a id="Inclusive_Language"></a>
|
||
|
||
### Inclusive Language
|
||
|
||
In all code, including naming and comments, use inclusive language and avoid
|
||
terms that other programmers might find disrespectful or offensive (such as
|
||
"master" and "slave", "blacklist" and "whitelist", or "redline"), even if the
|
||
terms also have an ostensibly neutral meaning. Similarly, use gender-neutral
|
||
language unless you're referring to a specific person (and using their
|
||
pronouns). For example, use "they"/"them"/"their" for people of unspecified
|
||
gender (even when singular), and "it"/"its" for non-people.
|
||
|
||
|
||
<a id="File_Names"></a>
|
||
|
||
### File Names
|
||
|
||
File names should reflect the name of the class implementation that they
|
||
contain—including case.
|
||
|
||
Follow the convention that your project uses.
|
||
|
||
File extensions should be as follows:
|
||
|
||
Extension | Type
|
||
--------- | ---------------------------------
|
||
.h | C/C++/Objective-C header file
|
||
.m | Objective-C implementation file
|
||
.mm | Objective-C++ implementation file
|
||
.cc | Pure C++ implementation file
|
||
.c | C implementation file
|
||
|
||
Files containing code that may be shared across projects or used in a large
|
||
project should have a clearly unique name, typically including the project or
|
||
class [prefix](#prefixes).
|
||
|
||
File names for categories should include the name of the class being extended,
|
||
like GTMNSString+Utils.h or NSTextView+GTMAutocomplete.h
|
||
|
||
### Prefixes
|
||
|
||
Prefixes are commonly required in Objective-C to avoid naming collisions in a
|
||
global namespace. Classes, protocols, global functions, and global constants
|
||
should generally be named with a prefix that begins with a capital letter
|
||
followed by one or more capital letters or numbers.
|
||
|
||
WARNING: Apple reserves two-letter prefixes—see
|
||
[Conventions in Programming with Objective-C](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Conventions/Conventions.html)—so
|
||
prefixes with a minimum of three characters are considered best practice.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
/** An example error domain. */
|
||
GTM_EXTERN NSString *GTMExampleErrorDomain;
|
||
|
||
/** Gets the default time zone. */
|
||
GTM_EXTERN NSTimeZone *GTMGetDefaultTimeZone(void);
|
||
|
||
/** An example delegate. */
|
||
@protocol GTMExampleDelegate <NSObject>
|
||
@end
|
||
|
||
/** An example class. */
|
||
@interface GTMExample : NSObject
|
||
@end
|
||
|
||
```
|
||
|
||
<a id="Class_Names"></a>
|
||
|
||
### Class Names
|
||
|
||
Class names (along with category and protocol names) should start as uppercase
|
||
and use mixed case to delimit words.
|
||
|
||
Classes and protocols in code shared across multiple applications must have an
|
||
appropriate [prefix](#prefixes) (e.g. GTMSendMessage). Prefixes are recommended,
|
||
but not required, for other classes and protocols.
|
||
|
||
<a id="Category_Names"></a>
|
||
|
||
### Category Naming
|
||
|
||
Category names should start with an appropriate [prefix](#prefixes) identifying
|
||
the category as part of a project or open for general use.
|
||
|
||
Category source file names should begin with the class being extended followed
|
||
by a plus sign and the name of the category, e.g., `NSString+GTMParsing.h`.
|
||
Methods in a category should be prefixed with a lowercase version of the prefix
|
||
used for the category name followed by an underscore (e.g.,
|
||
`gtm_myCategoryMethodOnAString:`) in order to prevent collisions in
|
||
Objective-C's global namespace.
|
||
|
||
There should be a single space between the class name and the opening
|
||
parenthesis of the category.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
// UIViewController+GTMCrashReporting.h
|
||
|
||
/** A category that adds metadata to include in crash reports to UIViewController. */
|
||
@interface UIViewController (GTMCrashReporting)
|
||
|
||
/** A unique identifier to represent the view controller in crash reports. */
|
||
@property(nonatomic, setter=gtm_setUniqueIdentifier:) int gtm_uniqueIdentifier;
|
||
|
||
/** Returns an encoded representation of the view controller's current state. */
|
||
- (nullable NSData *)gtm_encodedState;
|
||
|
||
@end
|
||
```
|
||
|
||
If a class is not shared with other projects, categories extending it may omit
|
||
name prefixes and method name prefixes.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
/** This category extends a class that is not shared with other projects. */
|
||
@interface XYZDataObject (Storage)
|
||
- (NSString *)storageIdentifier;
|
||
@end
|
||
```
|
||
|
||
<a id="Objective-C_Method_Names"></a>
|
||
|
||
### Objective-C Method Names
|
||
|
||
Method and parameter names typically start as lowercase and then use mixed case.
|
||
|
||
Proper capitalization should be respected, including at the beginning of names.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
+ (NSURL *)URLWithString:(NSString *)URLString;
|
||
```
|
||
|
||
The method name should read like a sentence if possible, meaning you should
|
||
choose parameter names that flow with the method name. Objective-C method names
|
||
tend to be very long, but this has the benefit that a block of code can almost
|
||
read like prose, thus rendering many implementation comments unnecessary.
|
||
|
||
Use prepositions and conjunctions like "with", "from", and "to" in the second
|
||
and later parameter names only where necessary to clarify the meaning or
|
||
behavior of the method.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
- (void)addTarget:(id)target action:(SEL)action; // GOOD; no conjunction needed
|
||
- (CGPoint)convertPoint:(CGPoint)point fromView:(UIView *)view; // GOOD; conjunction clarifies parameter
|
||
- (void)replaceCharactersInRange:(NSRange)aRange
|
||
withAttributedString:(NSAttributedString *)attributedString; // GOOD.
|
||
```
|
||
|
||
If the method returns an attribute of the receiver, name the method after the
|
||
attribute.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
/** Returns this instance's sandwich. */
|
||
- (Sandwich *)sandwich; // GOOD.
|
||
|
||
- (CGFloat)height; // GOOD.
|
||
|
||
// GOOD; Returned value is not an attribute.
|
||
- (UIBackgroundTaskIdentifier)beginBackgroundTask;
|
||
```
|
||
|
||
```objectivec
|
||
// AVOID:
|
||
|
||
- (CGFloat)calculateHeight; // AVOID.
|
||
- (id)theDelegate; // AVOID.
|
||
```
|
||
|
||
An accessor method should be named the same as the object it's getting, but it
|
||
should not be prefixed with the word `get`. For example:
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
- (id)delegate; // GOOD.
|
||
```
|
||
|
||
```objectivec
|
||
// AVOID:
|
||
|
||
- (id)getDelegate; // AVOID.
|
||
```
|
||
|
||
Accessors that return the value of boolean adjectives have method names
|
||
beginning with `is`, but property names for those methods omit the `is`.
|
||
|
||
Dot notation is used only with property names, not with method names.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
@property(nonatomic, getter=isGlorious) BOOL glorious;
|
||
// The method for the getter of the property above is:
|
||
// - (BOOL)isGlorious;
|
||
|
||
BOOL isGood = object.glorious; // GOOD.
|
||
BOOL isGood = [object isGlorious]; // GOOD.
|
||
```
|
||
|
||
```objectivec
|
||
// AVOID:
|
||
|
||
BOOL isGood = object.isGlorious; // AVOID.
|
||
```
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
NSArray<Frog *> *frogs = [NSArray<Frog *> arrayWithObject:frog];
|
||
NSEnumerator *enumerator = [frogs reverseObjectEnumerator]; // GOOD.
|
||
```
|
||
|
||
```objectivec
|
||
// AVOID:
|
||
|
||
NSEnumerator *enumerator = frogs.reverseObjectEnumerator; // AVOID.
|
||
```
|
||
|
||
See [Apple's Guide to Naming
|
||
Methods](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingMethods.html#//apple_ref/doc/uid/20001282-BCIGIJJF)
|
||
for more details on Objective-C naming.
|
||
|
||
These guidelines are for Objective-C methods only. C++ method names continue to
|
||
follow the rules set in the C++ style guide.
|
||
|
||
<a id="Function_Names"></a>
|
||
|
||
### Function Names
|
||
|
||
Function names should start with a capital letter and have a capital letter for
|
||
each new word (a.k.a. "[camel case](https://en.wikipedia.org/wiki/Camel_case)"
|
||
or "Pascal case").
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
static void AddTableEntry(NSString *tableEntry);
|
||
static BOOL DeleteFile(const char *filename);
|
||
```
|
||
|
||
Because Objective-C does not provide namespacing, non-static functions should
|
||
have a [prefix](#prefixes) that minimizes the chance of a name collision.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
GTM_EXTERN NSTimeZone *GTMGetDefaultTimeZone(void);
|
||
GTM_EXTERN NSString *GTMGetURLScheme(NSURL *URL);
|
||
```
|
||
|
||
<a id="Variable_Names"></a>
|
||
|
||
### Variable Names
|
||
|
||
Variable names typically start with a lowercase and use mixed case to delimit
|
||
words.
|
||
|
||
Instance variables have leading underscores. File scope or global variables have
|
||
a prefix `g`. For example: `myLocalVariable`, `_myInstanceVariable`,
|
||
`gMyGlobalVariable`.
|
||
|
||
<a id="Common_Variable_Names"></a>
|
||
|
||
#### Common Variable Names
|
||
|
||
Readers should be able to infer the variable type from the name, but do not use
|
||
Hungarian notation for syntactic attributes, such as the static type of a
|
||
variable (int or pointer).
|
||
|
||
File scope or global variables (as opposed to constants) declared outside the
|
||
scope of a method or function should be rare, and should have the prefix `g`.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
static int gGlobalCounter;
|
||
```
|
||
|
||
<a id="Instance_Variables"></a>
|
||
|
||
#### Instance Variables
|
||
|
||
Instance variable names are mixed case and should be prefixed with an
|
||
underscore, like `_usernameTextField`.
|
||
|
||
NOTE: Google's previous convention for Objective-C ivars was a trailing
|
||
underscore. Existing projects may opt to continue using trailing underscores in
|
||
new code in order to maintain consistency within the project codebase.
|
||
Consistency of prefix or suffix underscores should be maintained within each
|
||
class.
|
||
|
||
<a id="Constants"></a>
|
||
|
||
#### Constants
|
||
|
||
Constant symbols (const global and static variables and constants created
|
||
with #define) should use mixed case to delimit words.
|
||
|
||
Global and file scope constants should have an appropriate [prefix](#prefixes).
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
/** The domain for GTL service errors. */
|
||
GTL_EXTERN NSString *const GTLServiceErrorDomain;
|
||
|
||
/** An enumeration of GTL service error codes. */
|
||
typedef NS_ENUM(int32_t, GTLServiceError) {
|
||
/** An error code indicating that a query result was missing. */
|
||
GTLServiceErrorQueryResultMissing = -3000,
|
||
/** An error code indicating that the query timed out. */
|
||
GTLServiceErrorQueryTimedOut = -3001,
|
||
};
|
||
```
|
||
|
||
Because Objective-C does not provide namespacing, constants with external
|
||
linkage should have a prefix that minimizes the chance of a name collision,
|
||
typically like `ClassNameConstantName` or `ClassNameEnumName`.
|
||
|
||
For interoperability with Swift code, enumerated values should have names that
|
||
extend the typedef name:
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
/** An enumeration of supported display tinges. */
|
||
typedef NS_ENUM(int32_t, DisplayTinge) {
|
||
DisplayTingeGreen = 1,
|
||
DisplayTingeBlue = 2,
|
||
};
|
||
```
|
||
|
||
A lowercase k can be used as a standalone prefix for constants of static storage
|
||
duration declared within implementation files:
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
static const int kFileCount = 12;
|
||
static NSString *const kUserKey = @"kUserKey";
|
||
```
|
||
|
||
NOTE: Previous convention was for public constant names to begin with a
|
||
lowercase k followed by a project-specific [prefix](#prefixes). This practice is
|
||
no longer recommended.
|
||
|
||
<a id="Types_and_Declarations"></a>
|
||
|
||
## Types and Declarations
|
||
|
||
<a id="Method_Declarations"></a>
|
||
|
||
### Method Declarations
|
||
|
||
As shown in the [example](#Example), the recommended order
|
||
for declarations in an `@interface` declaration are: properties, class methods,
|
||
initializers, and then finally instance methods. The class methods section
|
||
should begin with any convenience constructors.
|
||
|
||
<a id="Local_Variables"></a>
|
||
|
||
### Local Variables
|
||
|
||
Declare variables in the narrowest practical scopes, and close to their use.
|
||
Initialize variables in their declarations.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
CLLocation *location = [self lastKnownLocation];
|
||
for (int meters = 1; meters < 10; meters++) {
|
||
reportFrogsWithinRadius(location, meters);
|
||
}
|
||
```
|
||
|
||
Occasionally, efficiency will make it more appropriate to declare a variable
|
||
outside the scope of its use. This example declares meters separate from
|
||
initialization, and needlessly sends the lastKnownLocation message each time
|
||
through the loop:
|
||
|
||
```objectivec
|
||
// AVOID:
|
||
|
||
int meters; // AVOID.
|
||
for (meters = 1; meters < 10; meters++) {
|
||
CLLocation *location = [self lastKnownLocation]; // AVOID.
|
||
reportFrogsWithinRadius(location, meters);
|
||
}
|
||
```
|
||
|
||
Under Automatic Reference Counting, strong and weak pointers to Objective-C
|
||
objects are automatically initialized to `nil`, so explicit initialization to
|
||
`nil` is not required for those common cases. However, automatic initialization
|
||
does *not* occur for many Objective-C pointer types, including object pointers
|
||
declared with the `__unsafe_unretained` ownership qualifier and CoreFoundation
|
||
object pointer types. When in doubt, prefer to initialize all Objective-C
|
||
local variables.
|
||
|
||
### Static Variables
|
||
|
||
When file scope variable/constant declarations in an implementation file do not
|
||
need to be referenced outside that file, declare them static (or in an anonymous
|
||
namespace in Objective-C++). Do not declare file scope variables or constants
|
||
with static storage duration (or in anonymous namespaces in Objective-C++) in .h
|
||
files.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
// file: Foo.m
|
||
static const int FOORequestLimit = 5;
|
||
```
|
||
|
||
```objectivec
|
||
// AVOID:
|
||
|
||
// file: Foo.h
|
||
static const int FOORequestLimit = 5; // AVOID.
|
||
```
|
||
|
||
<a id="Unsigned_Integers"></a>
|
||
|
||
### Unsigned Integers
|
||
|
||
Avoid unsigned integers except when matching types used by system interfaces.
|
||
|
||
Subtle errors crop up when doing math or counting down to zero using unsigned
|
||
integers. Rely only on signed integers in math expressions except when matching
|
||
NSUInteger in system interfaces.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
NSUInteger numberOfObjects = array.count;
|
||
for (NSInteger counter = numberOfObjects - 1; counter >= 0; --counter)
|
||
```
|
||
|
||
```objectivec
|
||
// AVOID:
|
||
|
||
for (NSUInteger counter = numberOfObjects - 1; counter >= 0; --counter) // AVOID.
|
||
```
|
||
|
||
Unsigned integers may be used for flags and bitmasks, though often NS_OPTIONS or
|
||
NS_ENUM will be more appropriate.
|
||
|
||
<a id="Types_with_Inconsistent_Sizes"></a>
|
||
|
||
### Types with Inconsistent Sizes
|
||
|
||
Be aware that types long, NSInteger, NSUInteger and CGFloat have sizes that
|
||
differ in 32- and 64-bit builds. Their use is appropriate when matching system
|
||
interfaces but should be avoided when dealing with APIs that
|
||
require exact sizing, e.g., proto APIs.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
int32_t scalar1 = proto.intValue;
|
||
|
||
int64_t scalar2 = proto.longValue;
|
||
|
||
NSUInteger numberOfObjects = array.count;
|
||
|
||
CGFloat offset = view.bounds.origin.x;
|
||
```
|
||
|
||
```objectivec
|
||
// AVOID:
|
||
|
||
NSInteger scalar2 = proto.longValue; // AVOID.
|
||
```
|
||
|
||
File and buffer sizes often exceed 32-bit limits, so they should be declared
|
||
using `int64_t`, not with `long`, `NSInteger`, or `NSUInteger`.
|
||
|
||
<a id="Floating_Point_Constants"></a>
|
||
|
||
#### Floating Point Constants
|
||
|
||
When defining `CGFloat` constants, please keep in mind the following.
|
||
|
||
Previously for projects targeting 32-bit platforms, using `float` literals
|
||
(numbers with the `f` suffix) could be necessary to avoid type-conversion
|
||
warnings.
|
||
|
||
Since all Google iOS projects are now targeting only 64-bit runtime, `CGFloat`
|
||
constants may omit the suffix (use `double` values). However, teams may choose
|
||
to continue using `float` numbers for legacy code consistency, until they
|
||
eventually migrate to `double` values everywhere. Avoid a mixture of `float`
|
||
and `double` values in the same code.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
// Good since CGFloat is double
|
||
static const CGFloat kHorizontalMargin = 8.0;
|
||
static const CGFloat kVerticalMargin = 12.0;
|
||
|
||
// This is OK as long as all values for CGFloat constants in your project are float
|
||
static const CGFloat kHorizontalMargin = 8.0f;
|
||
static const CGFloat kVerticalMargin = 12.0f;
|
||
```
|
||
|
||
```objectivec
|
||
// AVOID:
|
||
|
||
// Avoid a mixture of float and double constants
|
||
static const CGFloat kHorizontalMargin = 8.0f;
|
||
static const CGFloat kVerticalMargin = 12.0;
|
||
```
|
||
|
||
<a id="Comments"></a>
|
||
|
||
## Comments
|
||
|
||
Comments are absolutely vital to keeping our code readable. The following rules
|
||
describe what you should comment and where. But remember: while comments are
|
||
important, the best code is self-documenting. Giving sensible names to types and
|
||
variables is much better than using obscure names and then trying to explain
|
||
them through comments.
|
||
|
||
Pay attention to punctuation, spelling, and grammar; it is easier to read
|
||
well-written comments than badly written ones.
|
||
|
||
Comments should be as readable as narrative text, with proper capitalization and
|
||
punctuation. In many cases, complete sentences are more readable than sentence
|
||
fragments. Shorter comments, such as comments at the end of a line of code, can
|
||
sometimes be less formal, but use a consistent style.
|
||
|
||
When writing your comments, write for your audience: the next contributor who
|
||
will need to understand your code. Be generous—the next one may be you!
|
||
|
||
<a id="File_Comments"></a>
|
||
|
||
### File Comments
|
||
|
||
A file may optionally start with a description of its contents.
|
||
|
||
Every file may contain the following items, in order
|
||
* License boilerplate if necessary. Choose the appropriate boilerplate for the
|
||
license used by the project.
|
||
* A basic description of the contents of the file if necessary.
|
||
|
||
If you make significant changes to a file with an author line, consider deleting
|
||
the author line since revision history already provides a more detailed and
|
||
accurate record of authorship.
|
||
|
||
|
||
<a id="Declaration_Comments"></a>
|
||
|
||
### Declaration Comments
|
||
|
||
Every non-trivial interface, public and private, should have an accompanying
|
||
comment describing its purpose and how it fits into the larger picture.
|
||
|
||
Comments should be used to document classes, properties, ivars, functions,
|
||
categories, protocol declarations, and enums.
|
||
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
/**
|
||
* A delegate for NSApplication to handle notifications about app
|
||
* launch and shutdown. Owned by the main app controller.
|
||
*/
|
||
@interface MyAppDelegate : NSObject {
|
||
/**
|
||
* The background task in progress, if any. This is initialized
|
||
* to the value UIBackgroundTaskInvalid.
|
||
*/
|
||
UIBackgroundTaskIdentifier _backgroundTaskID;
|
||
}
|
||
|
||
/** The factory that creates and manages fetchers for the app. */
|
||
@property(nonatomic) GTMSessionFetcherService *fetcherService;
|
||
|
||
@end
|
||
```
|
||
|
||
[Doxygen](https://doxygen.nl)-style comments are encouraged for interfaces as
|
||
they are parsed by Xcode
|
||
to display formatted documentation. There is a wide variety of
|
||
[Doxygen commands](https://www.doxygen.nl/manual/commands.html);
|
||
use them consistently within a project.
|
||
|
||
If you have already described an interface in detail in the comments at the top
|
||
of your file, feel free to simply state, "See comment at top of file for a
|
||
complete description", but be sure to have some sort of comment.
|
||
|
||
Additionally, each method should have a comment explaining its function,
|
||
arguments, return value, thread or queue assumptions, and any side effects.
|
||
Documentation comments should be in the header for public methods, or
|
||
immediately preceding the method for non-trivial private methods.
|
||
|
||
Use descriptive form ("Opens the file") rather than imperative form ("Open the
|
||
file") for method and function comments. The comment describes the function; it
|
||
does not tell the function what to do.
|
||
|
||
Document the thread usage assumptions the class, properties, or methods make, if
|
||
any. If an instance of the class can be accessed by multiple threads, take extra
|
||
care to document the rules and invariants surrounding multithreaded use.
|
||
|
||
Any sentinel values for properties and ivars, such as `NULL` or `-1`, should be
|
||
documented in comments.
|
||
|
||
Declaration comments explain how a method or function is used. Comments
|
||
explaining how a method or function is implemented should be with the
|
||
implementation rather than with the declaration.
|
||
|
||
Declaration comments may be omitted on test case classes and test methods
|
||
if comments would communicate no additional information beyond the method's
|
||
name. Utility methods in tests or test-specific classes (such as helpers) should
|
||
be commented.
|
||
|
||
<a id="Implementation_Comments"></a>
|
||
|
||
### Implementation Comments
|
||
|
||
Provide comments explaining tricky, subtle, or complicated sections of code.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
// Set the property to nil before invoking the completion handler to
|
||
// avoid the risk of reentrancy leading to the callback being
|
||
// invoked again.
|
||
CompletionHandler handler = self.completionHandler;
|
||
self.completionHandler = nil;
|
||
handler();
|
||
```
|
||
|
||
When useful, also provide comments about implementation approaches that were
|
||
considered or abandoned.
|
||
|
||
End-of-line comments should be separated from the code by at least 2 spaces. If
|
||
you have several comments on subsequent lines, it can often be more readable to
|
||
line them up.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
[self doSomethingWithALongName]; // Two spaces before the comment.
|
||
[self doSomethingShort]; // More spacing to align the comment.
|
||
```
|
||
|
||
|
||
<a id="Disambiguating_Symbols"></a>
|
||
|
||
### Disambiguating Symbols
|
||
|
||
Where needed to avoid ambiguity, use backticks or vertical bars to quote
|
||
variable names and symbols in comments in preference to using quotation marks
|
||
or naming the symbols inline.
|
||
|
||
In Doxygen-style comments, prefer demarcating symbols with a monospace text
|
||
command, such as [`@c`](https://www.doxygen.nl/manual/commands.html#cmdc).
|
||
|
||
Demarcation helps provide clarity when a symbol is a common word that might make
|
||
the sentence read like it was poorly constructed. A common example is the symbol
|
||
`count`:
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
// Sometimes `count` will be less than zero.
|
||
```
|
||
|
||
or when quoting something which already contains quotes
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
// Remember to call `StringWithoutSpaces("foo bar baz")`
|
||
```
|
||
|
||
Backticks or vertical bars are not needed when a symbol is self-apparent.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
// This class serves as a delegate to GTMDepthCharge.
|
||
```
|
||
|
||
Doxygen formatting is also suitable for identifying symbols.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
/** @param maximum The highest value for @c count. */
|
||
```
|
||
|
||
<a id="Object_Ownership"></a>
|
||
|
||
### Object Ownership
|
||
|
||
For objects not managed by ARC, make the pointer ownership model as explicit as
|
||
possible when it falls outside the most common Objective-C usage idioms.
|
||
|
||
<a id="Manual_Reference_Counting"></a>
|
||
|
||
#### Manual Reference Counting
|
||
|
||
Instance variables for NSObject-derived objects are presumed to be retained; if
|
||
they are not retained, they should be either commented as weak or declared with
|
||
the `__weak` lifetime qualifier.
|
||
|
||
An exception is in Mac software for instance variables labeled as `@IBOutlets`,
|
||
which are presumed to not be retained.
|
||
|
||
Where instance variables are pointers to Core Foundation, C++, and other
|
||
non-Objective-C objects, they should always be declared with strong and weak
|
||
comments to indicate which pointers are and are not retained. Core Foundation
|
||
and other non-Objective-C object pointers require explicit memory management,
|
||
even when building for automatic reference counting.
|
||
|
||
Examples of strong and weak declarations:
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
@interface MyDelegate : NSObject
|
||
|
||
@property(nonatomic) NSString *doohickey;
|
||
@property(nonatomic, weak) NSString *parent;
|
||
|
||
@end
|
||
|
||
|
||
@implementation MyDelegate {
|
||
IBOutlet NSButton *_okButton; // Normal NSControl; implicitly weak on Mac only
|
||
|
||
AnObjcObject *_doohickey; // My doohickey
|
||
__weak MyObjcParent *_parent; // To send messages back (owns this instance)
|
||
|
||
// non-NSObject pointers...
|
||
CWackyCPPClass *_wacky; // Strong, some cross-platform object
|
||
CFDictionaryRef *_dict; // Strong
|
||
}
|
||
@end
|
||
```
|
||
|
||
<a id="Automatic_Reference_Counting"></a>
|
||
|
||
#### Automatic Reference Counting
|
||
|
||
Object ownership and lifetime are explicit when using ARC, so no additional
|
||
comments are required for automatically retained objects.
|
||
|
||
<a id="C_Language_Features"></a>
|
||
|
||
## C Language Features
|
||
|
||
<a id="Macros"></a>
|
||
|
||
### Macros
|
||
|
||
Avoid macros, especially where `const` variables, enums, Xcode snippets, or C
|
||
functions may be used instead.
|
||
|
||
Macros make the code you see different from the code the compiler sees. Modern C
|
||
renders traditional uses of macros for constants and utility functions
|
||
unnecessary. Macros should only be used when there is no other solution
|
||
available.
|
||
|
||
Where a macro is needed, use a unique name to avoid the risk of a symbol
|
||
collision in the compilation unit. If practical, keep the scope limited by
|
||
`#undefining` the macro after its use.
|
||
|
||
Macro names should use `SHOUTY_SNAKE_CASE`—all uppercase letters with
|
||
underscores between words. Function-like macros may use C function naming
|
||
practices. Do not define macros that appear to be C or Objective-C keywords.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
#define GTM_EXPERIMENTAL_BUILD ... // GOOD
|
||
|
||
// Assert unless X > Y
|
||
#define GTM_ASSERT_GT(X, Y) ... // GOOD, macro style.
|
||
|
||
// Assert unless X > Y
|
||
#define GTMAssertGreaterThan(X, Y) ... // GOOD, function style.
|
||
```
|
||
|
||
```objectivec
|
||
// AVOID:
|
||
|
||
#define kIsExperimentalBuild ... // AVOID
|
||
|
||
#define unless(X) if(!(X)) // AVOID
|
||
```
|
||
|
||
Avoid macros that expand to unbalanced C or Objective-C constructs. Avoid macros
|
||
that introduce scope, or may obscure the capturing of values in blocks.
|
||
|
||
Avoid macros that generate class, property, or method definitions in
|
||
headers to be used as public API. These only make the code hard to
|
||
understand, and the language already has better ways of doing this.
|
||
|
||
Avoid macros that generate method implementations, or that generate declarations
|
||
of variables that are later used outside of the macro. Macros shouldn't make
|
||
code hard to understand by hiding where and how a variable is declared.
|
||
|
||
```objectivec
|
||
// AVOID:
|
||
|
||
#define ARRAY_ADDER(CLASS) \
|
||
-(void)add ## CLASS ## :(CLASS *)obj toArray:(NSMutableArray *)array
|
||
|
||
ARRAY_ADDER(NSString) {
|
||
if (array.count > 5) { // AVOID -- where is 'array' defined?
|
||
...
|
||
}
|
||
}
|
||
```
|
||
|
||
Examples of acceptable macro use include assertion and debug logging macros
|
||
that are conditionally compiled based on build settings—often, these are
|
||
not compiled into release builds.
|
||
|
||
<a id="Nonstandard_Extensions"></a>
|
||
|
||
### Nonstandard Extensions
|
||
|
||
Nonstandard extensions to C/Objective-C may not be used unless otherwise
|
||
specified.
|
||
|
||
Compilers support various extensions that are not part of standard C. Examples
|
||
include compound statement expressions (e.g. `foo = ({ int x; Bar(&x); x })`).
|
||
|
||
#### The `__typeof__` Keyword
|
||
|
||
The `__typeof__` keyword is allowed in cases where the type doesn't aid in
|
||
clarity for the reader. The `__typeof__` keyword is encouraged over other
|
||
similar keywords (e.g., the `typeof` keyword) as it is supported in all language
|
||
variants.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
__weak __typeof__(self) weakSelf = self;
|
||
```
|
||
|
||
```objectivec
|
||
// AVOID:
|
||
|
||
__typeof__(data) copiedData = [data copy]; // AVOID.
|
||
__weak typeof(self) weakSelf = self; // AVOID.
|
||
```
|
||
|
||
#### The `__auto_type` Keyword and Type Deduction
|
||
|
||
Type deduction using the `__auto_type` keyword is allowed only for local
|
||
variables of block and function pointer types. Avoid type deduction if a typedef
|
||
already exists for the block or pointer type.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
__auto_type block = ^(NSString *arg1, int arg2) { ... };
|
||
__auto_type functionPointer = &MyFunction;
|
||
|
||
typedef void(^SignInCallback)(Identity *, NSError *);
|
||
SignInCallback signInCallback = ^(Identity *identity, NSError *error) { ... };
|
||
```
|
||
|
||
```objectivec
|
||
// AVOID:
|
||
|
||
__auto_type button = [self createButtonForInfo:info];
|
||
__auto_type viewController = [[MyCustomViewControllerClass alloc] initWith...];
|
||
|
||
typedef void(^SignInCallback)(Identity *, NSError *);
|
||
__auto_type signInCallback = ^(Identity *identity, NSError *error) { ... };
|
||
```
|
||
|
||
#### Approved Nonstandard Extensions
|
||
|
||
* The `__attribute__` keyword is approved as it is used in Apple API
|
||
declarations.
|
||
* The binary form of the conditional operator, `A ?: B`, is approved.
|
||
|
||
<a id="Cocoa_and_Objective-C_Features"></a>
|
||
|
||
## Cocoa and Objective-C Features
|
||
|
||
<a id="Identify_Designated_Initializer"></a>
|
||
|
||
### Identify Designated Initializers
|
||
|
||
Clearly identify your designated initializer(s).
|
||
|
||
It is important for subclassing that a class clearly identify its designated
|
||
initializers. This allows a subclass to override a subset of initializers to
|
||
initialize subclass state or invoke a new designated initializer provided by the
|
||
subclass. Clearly identified designated initializers also make tracing through
|
||
and debugging initialization code easier.
|
||
|
||
Prefer identifying designated initializers by annotating them with designated
|
||
initializer attributes, e.g., `NS_DESIGNATED_INITIALIZER`. Declare designated
|
||
initializers in comments when designated initializer attributes are not
|
||
available. Prefer a single designated initializer unless there is a compelling
|
||
reason or requirement for multiple designated initializers.
|
||
|
||
Support initializers inherited from superclasses by
|
||
[overriding superclass designated initializers](#Override_Designated_Initializer)
|
||
to ensure that all inherited initializers are directed through subclass
|
||
designated initializers. When there is a compelling reason or requirement that
|
||
an inherited initializer should not be supported, the initializer may be
|
||
annotated with availability attributes (e.g., `NS_UNAVAILABLE`) to discourage
|
||
usage; however, note that availability attributes alone do not completely
|
||
protect against invalid initialization.
|
||
|
||
<a id="Override_Designated_Initializer"></a>
|
||
|
||
### Override Designated Initializers
|
||
|
||
When writing a subclass that requires a new designated initializer, make sure
|
||
you override any designated initializers of the superclass.
|
||
|
||
When declaring designated initializers on a class, remember that any
|
||
initializers that were considered designated initializers on the superclass
|
||
become convenience initializers of the subclass unless declared otherwise.
|
||
Failure to override superclass designated initializers can result in bugs due to
|
||
invalid initialization using superclass initializers. To avoid invalid
|
||
initialization, ensure convenience initializers call through to a designated
|
||
initializer.
|
||
|
||
<a id="Overridden_NSObject_Method_Placement"></a>
|
||
|
||
### Overridden NSObject Method Placement
|
||
|
||
Put overridden methods of NSObject at the top of an `@implementation`.
|
||
|
||
This commonly applies to (but is not limited to) the `init...`, `copyWithZone:`,
|
||
and `dealloc` methods. The `init...` methods should be grouped together,
|
||
including those `init...` methods that are not `NSObject` overrides, followed by
|
||
other typical `NSObject` methods such as `description`, `isEqual:`, and `hash`.
|
||
|
||
Convenience class factory methods for creating instances may precede the
|
||
`NSObject` methods.
|
||
|
||
<a id="Initialization"></a>
|
||
|
||
### Initialization
|
||
|
||
Don't initialize instance variables to `0` or `nil` in the `init` method; doing
|
||
so is redundant.
|
||
|
||
All instance variables for a newly allocated object are [initialized
|
||
to](https://developer.apple.com/library/mac/documentation/General/Conceptual/CocoaEncyclopedia/ObjectAllocation/ObjectAllocation.html)
|
||
`0` (except for isa), so don't clutter up the init method by re-initializing
|
||
variables to `0` or `nil`.
|
||
|
||
<a id="Instance_Variables_In_Headers_Should_Be_@protected_or_@private"></a>
|
||
|
||
### Instance Variables In Headers Should Be @protected or @private
|
||
|
||
Instance variables should typically be declared in implementation files or
|
||
auto-synthesized by properties. When ivars are declared in a header file, they
|
||
should be marked `@protected` or `@private`.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
@interface MyClass : NSObject {
|
||
@protected
|
||
id _myInstanceVariable;
|
||
}
|
||
@end
|
||
```
|
||
|
||
<a id="Avoid_+new"></a>
|
||
|
||
### Do Not Use +new
|
||
|
||
Do not invoke the `NSObject` class method `new`, nor override it in a subclass.
|
||
`+new` is rarely used and contrasts greatly with initializer usage. Instead, use
|
||
`+alloc` and `-init` methods to instantiate retained objects.
|
||
|
||
<a id="Keep_the_Public_API_Simple"></a>
|
||
|
||
### Keep the Public API Simple
|
||
|
||
Keep your class simple; avoid "kitchen-sink" APIs. If a method doesn't need to
|
||
be public, keep it out of the public interface.
|
||
|
||
Unlike C++, Objective-C doesn't differentiate between public and private
|
||
methods; any message may be sent to an object. As a result, avoid placing
|
||
methods in the public API unless they are actually expected to be used by a
|
||
consumer of the class. This helps reduce the likelihood they'll be called when
|
||
you're not expecting it. This includes methods that are being overridden from
|
||
the parent class.
|
||
|
||
Since internal methods are not really private, it's easy to accidentally
|
||
override a superclass's "private" method, thus making a very difficult bug to
|
||
squash. In general, private methods should have a fairly unique name that will
|
||
prevent subclasses from unintentionally overriding them.
|
||
|
||
<a id="#import_and_#include"></a>
|
||
|
||
### #import and #include
|
||
|
||
`#import` Objective-C and Objective-C++ headers, and `#include` C/C++ headers.
|
||
|
||
C/C++ headers include other C/C++ headers using `#include`. Using `#import`
|
||
on C/C++ headers prevents future inclusions using `#include` and could result in
|
||
unintended compilation behavior.
|
||
|
||
C/C++ headers should provide their own `#define` guard.
|
||
|
||
<a id="Order_of_Includes"></a>
|
||
|
||
### Order of Includes
|
||
|
||
The standard order for header inclusion is the related header, operating system
|
||
headers, language library headers, and finally groups of headers for other
|
||
dependencies.
|
||
|
||
The related header precedes others to ensure it has no hidden dependencies.
|
||
For implementation files the related header is the header file.
|
||
For test files the related header is the header containing the tested interface.
|
||
|
||
Separate each non-empty group of includes with one blank line. Within each group
|
||
the includes should be ordered alphabetically.
|
||
|
||
Import headers using their path relative to the project's source directory.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
#import "ProjectX/BazViewController.h"
|
||
|
||
#import <Foundation/Foundation.h>
|
||
|
||
#include <unistd.h>
|
||
#include <vector>
|
||
|
||
#include "base/basictypes.h"
|
||
#include "base/integral_types.h"
|
||
#import "base/mac/FOOComplexNumberSupport"
|
||
#include "util/math/mathutil.h"
|
||
|
||
#import "ProjectX/BazModel.h"
|
||
#import "Shared/Util/Foo.h"
|
||
```
|
||
|
||
<a id="Use_Umbrella_Headers_for_System_Frameworks"></a>
|
||
|
||
### Use Umbrella Headers for System Frameworks
|
||
|
||
Import umbrella headers for system frameworks and system libraries rather than
|
||
include individual files.
|
||
|
||
While it may seem tempting to include individual system headers from a framework
|
||
such as Cocoa or Foundation, in fact it's less work on the compiler if you
|
||
include the top-level root framework. The root framework is generally
|
||
pre-compiled and can be loaded much more quickly. In addition, remember to use
|
||
`@import` or `#import` rather than `#include` for Objective-C frameworks.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
@import UIKit; // GOOD.
|
||
#import <Foundation/Foundation.h> // GOOD.
|
||
```
|
||
|
||
```objectivec
|
||
// AVOID:
|
||
|
||
#import <Foundation/NSArray.h> // AVOID.
|
||
#import <Foundation/NSString.h>
|
||
...
|
||
```
|
||
|
||
### Avoid Messaging the Current Object Within Initializers and `-dealloc`
|
||
|
||
Code in initializers and `-dealloc` should avoid invoking instance methods when
|
||
possible.
|
||
|
||
Superclass initialization completes before subclass initialization. Until all
|
||
classes have had a chance to initialize their instance state any method
|
||
invocation on self may lead to a subclass operating on uninitialized instance
|
||
state.
|
||
|
||
A similar issue exists for `-dealloc`, where a method invocation may cause a
|
||
class to operate on state that has been deallocated.
|
||
|
||
One case where this is less obvious is property accessors. These can be
|
||
overridden just like any other selector. Whenever practical, directly assign to
|
||
and release ivars in initializers and `-dealloc`, rather than rely on accessors.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
- (instancetype)init {
|
||
self = [super init];
|
||
if (self) {
|
||
_bar = 23; // GOOD.
|
||
}
|
||
return self;
|
||
}
|
||
```
|
||
|
||
Beware of factoring common initialization code into helper methods:
|
||
|
||
- Methods can be overridden in subclasses, either deliberately, or
|
||
accidentally due to naming collisions.
|
||
- When editing a helper method, it may not be obvious that the code is being
|
||
run from an initializer.
|
||
|
||
```objectivec
|
||
// AVOID:
|
||
|
||
- (instancetype)init {
|
||
self = [super init];
|
||
if (self) {
|
||
self.bar = 23; // AVOID.
|
||
[self sharedMethod]; // AVOID. Fragile to subclassing or future extension.
|
||
}
|
||
return self;
|
||
}
|
||
```
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
- (void)dealloc {
|
||
[_notifier removeObserver:self]; // GOOD.
|
||
}
|
||
```
|
||
|
||
```objectivec
|
||
// AVOID:
|
||
|
||
- (void)dealloc {
|
||
[self removeNotifications]; // AVOID.
|
||
}
|
||
```
|
||
|
||
There are common cases where a class may need to use properties and methods
|
||
provided by a superclass during initialization. This commonly occurs for classes
|
||
derived from UIKit and AppKit base classes, among other base classes. Use your
|
||
judgement and knowledge of common practice when deciding whether to make an
|
||
exception to this rule.
|
||
|
||
### Avoid redundant property access
|
||
|
||
Code should avoid redundant property access. Prefer to assign a property value
|
||
to a local variable when the property value is not expected to change and needs
|
||
to be used multiple times.
|
||
|
||
```objc
|
||
// GOOD:
|
||
|
||
UIView *view = self.view;
|
||
UIScrollView *scrollView = self.scrollView;
|
||
[scrollView.leadingAnchor constraintEqualToAnchor:view.leadingAnchor].active = YES;
|
||
[scrollView.trailingAnchor constraintEqualToAnchor:view.trailingAnchor].active = YES;
|
||
```
|
||
|
||
```objc
|
||
// AVOID:
|
||
|
||
[self.scrollView.loadingAnchor constraintEqualToAnchor:self.view.loadingAnchor].active = YES;
|
||
[self.scrollView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES;
|
||
```
|
||
|
||
When repeatedly referencing chained property invocations, prefer to capture the
|
||
repeated expression in a local variable:
|
||
|
||
```objc
|
||
// AVOID:
|
||
|
||
foo.bar.baz.field1 = 10;
|
||
foo.bar.baz.field2 = @"Hello";
|
||
foo.bar.baz.field3 = 2.71828183;
|
||
```
|
||
|
||
```objc
|
||
// GOOD:
|
||
|
||
Baz *baz = foo.bar.baz;
|
||
baz.field1 = 10;
|
||
baz.field2 = @"Hello";
|
||
baz.field3 = 2.71828183;
|
||
```
|
||
|
||
Redundantly accessing the same properties results in multiple message dispatches
|
||
to fetch the same value, and under ARC requires retains and releases of any
|
||
returned objects; the compiler cannot optimize away these extra operations,
|
||
leading to slower execution and substantial increases in binary size.
|
||
|
||
|
||
<a id="Mutables_Copies_Ownership"></a>
|
||
|
||
### Mutables, Copies and Ownership
|
||
|
||
For [Foundation and other hierarchies containing both immutable and mutable
|
||
subclasses](https://developer.apple.com/library/archive/documentation/General/Conceptual/CocoaEncyclopedia/ObjectMutability/ObjectMutability.html)
|
||
a mutable subclass may be substituted for an immutable so long as the
|
||
immutable's contract is honored.
|
||
|
||
The most common example of this sort of substitution are ownership transfers,
|
||
particularly for return values. In these cases an additional copy is not
|
||
necessary and returning the mutable subclass is more efficient.
|
||
[Callers are expected to treat return values as their declared type](https://developer.apple.com/library/archive/documentation/General/Conceptual/CocoaEncyclopedia/ObjectMutability/ObjectMutability.html#//apple_ref/doc/uid/TP40010810-CH5-SW67),
|
||
and thus the return value will be treated as an immutable going forward.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
- (NSArray *)listOfThings {
|
||
NSMutableArray *generatedList = [NSMutableArray array];
|
||
for (NSInteger i = 0; i < _someLimit; i++) {
|
||
[generatedList addObject:[self thingForIndex:i]];
|
||
}
|
||
// Copy not necessary, ownership of generatedList is transferred.
|
||
return generatedList;
|
||
}
|
||
```
|
||
|
||
This rule also applies to classes where only a mutable variant exists so long as
|
||
the ownership transfer is clear. Protos are a common example.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
- (SomeProtoMessage *)someMessageForValue:(BOOL)value {
|
||
SomeProtoMessage *message = [SomeProtoMessage message];
|
||
message.someValue = value;
|
||
return message;
|
||
}
|
||
```
|
||
|
||
It is not necessary to create a local immutable copy of a mutable type to match
|
||
the method signature of a method being called so long as the mutable argument
|
||
will not change for the duration of the method call. Called methods are expected
|
||
to treat arguments as the declared type, and take
|
||
[defensive copies](#Defensive_Copies)
|
||
([referred to by Apple as "snapshots"](https://developer.apple.com/library/archive/documentation/General/Conceptual/CocoaEncyclopedia/ObjectMutability/ObjectMutability.html#//apple_ref/doc/uid/TP40010810-CH5-SW68))
|
||
if they intend to retain those arguments beyond the duration of the call.
|
||
|
||
```objectivec
|
||
// AVOID:
|
||
|
||
NSMutableArray *updatedThings = [NSMutableArray array];
|
||
[updatedThings addObject:newThing];
|
||
[_otherManager updateWithCurrentThings:[updatedThings copy]]; // AVOID
|
||
```
|
||
|
||
<a id="Defensive_Copies"></a>
|
||
<a id="Setters_copy_NSStrings"></a>
|
||
|
||
### Copy Potentially Mutable Objects
|
||
|
||
Code receiving and retaining collections or other types with
|
||
[mutable variants](https://developer.apple.com/library/archive/documentation/General/Conceptual/CocoaEncyclopedia/ObjectMutability/ObjectMutability.html)
|
||
should consider that the passed object may be mutable, and thus an immutable or
|
||
mutable copy should be retained instead of the original object. In particular,
|
||
initializers and setters
|
||
[should copy instead of retaining objects whose types have mutable variants](https://developer.apple.com/library/archive/documentation/General/Conceptual/CocoaEncyclopedia/ObjectMutability/ObjectMutability.html#//apple_ref/doc/uid/TP40010810-CH5-SW68).
|
||
|
||
Synthesized accessors should use the `copy` keyword to ensure the generated code
|
||
matches these expectations.
|
||
|
||
NOTE: [The `copy` property keyword only affects the synthesized setter and has
|
||
no effect on
|
||
getters](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW27).
|
||
Since property keywords have no effect on direct ivar access custom accessors
|
||
must implement the same copy semantics.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
@property(nonatomic, copy) NSString *name;
|
||
@property(nonatomic, copy) NSSet<FilterThing *> *filters;
|
||
|
||
- (instancetype)initWithName:(NSString *)name
|
||
filters:(NSSet<FilterThing *> *)filters {
|
||
self = [super init];
|
||
if (self) {
|
||
_name = [name copy];
|
||
_filters = [filters copy];
|
||
}
|
||
return self;
|
||
}
|
||
|
||
- (void)setFilters:(NSSet<FilterThing *> *)filters {
|
||
// Ensure that we retain an immutable collection.
|
||
_filters = [filters copy];
|
||
}
|
||
```
|
||
|
||
Similarly, getters must return types that match the contract expectations of the
|
||
immutable types they return.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
|
||
@implementation Foo {
|
||
NSMutableArray<ContentThing *> *_currentContent;
|
||
}
|
||
|
||
- (NSArray<ContentThing *> *)currentContent {
|
||
return [_currentContent copy];
|
||
}
|
||
|
||
```
|
||
|
||
All Objective-C protos are mutable and typically should be copied rather than
|
||
retained
|
||
[except in clear cases of ownership transfer](#Mutables_Copies_Ownership).
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
- (void)setFooMessage:(FooMessage *)fooMessage {
|
||
// Copy proto to ensure no other retainer can mutate our value.
|
||
_fooMessage = [fooMessage copy];
|
||
}
|
||
|
||
- (FooMessage *)fooMessage {
|
||
// Copy proto to return so that caller cannot mutate our value.
|
||
return [_fooMessage copy];
|
||
}
|
||
```
|
||
|
||
Asynchronous code should copy potentially mutable objects prior to dispatch.
|
||
Objects captured by blocks are retained but not copied.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
- (void)doSomethingWithThings:(NSArray<Thing *> *)things {
|
||
NSArray<Thing *> *thingsToWorkOn = [things copy];
|
||
dispatch_async(_workQueue, ^{
|
||
for (id<Thing> thing in thingsToWorkOn) {
|
||
...
|
||
}
|
||
});
|
||
}
|
||
```
|
||
|
||
NOTE: It is unnecessary to copy objects that do not have mutable variants, e.g.
|
||
`NSURL`, `NSNumber`, `NSDate`, `UIColor`, etc.
|
||
|
||
<a id="Use_Lightweight_Generics_to_Document_Contained_Types"></a>
|
||
|
||
### Use Lightweight Generics to Document Contained Types
|
||
|
||
All projects compiling on Xcode 7 or newer versions should make use of the
|
||
Objective-C lightweight generics notation to type contained objects.
|
||
|
||
Every `NSArray`, `NSDictionary`, or `NSSet` reference should be declared using
|
||
lightweight generics for improved type safety and to explicitly document usage.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
@property(nonatomic, copy) NSArray<Location *> *locations;
|
||
@property(nonatomic, copy, readonly) NSSet<NSString *> *identifiers;
|
||
|
||
NSMutableArray<MyLocation *> *mutableLocations = [otherObject.locations mutableCopy];
|
||
```
|
||
|
||
If the fully-annotated types become complex, consider using a typedef to
|
||
preserve readability.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
typedef NSSet<NSDictionary<NSString *, NSDate *> *> TimeZoneMappingSet;
|
||
TimeZoneMappingSet *timeZoneMappings = [TimeZoneMappingSet setWithObjects:...];
|
||
```
|
||
|
||
Use the most descriptive common superclass or protocol available. In the most
|
||
generic case when nothing else is known, declare the collection to be explicitly
|
||
heterogeneous using id.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
@property(nonatomic, copy) NSArray<id> *unknowns;
|
||
```
|
||
|
||
<a id="Avoid_Throwing_Exceptions"></a>
|
||
|
||
### Avoid Throwing Exceptions
|
||
|
||
Don't `@throw` Objective-C exceptions, but you should be prepared to catch them
|
||
from third-party or OS calls.
|
||
|
||
This follows the recommendation to use error objects for error delivery in
|
||
[Apple's Introduction to Exception Programming Topics for
|
||
Cocoa](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Exceptions/Exceptions.html).
|
||
|
||
We do compile with `-fobjc-exceptions` (mainly so we get `@synchronized`), but
|
||
we don't `@throw`. Use of `@try`, `@catch`, and `@finally` are allowed when
|
||
required to properly use 3rd party code or libraries. If you do use them, please
|
||
document exactly which methods you expect to throw.
|
||
|
||
<a id="nil_Checks"></a>
|
||
|
||
### `nil` Checks
|
||
|
||
Avoid `nil` pointer checks that exist only to prevent sending messages to `nil`.
|
||
Sending a message to `nil` [reliably
|
||
returns](http://www.sealiesoftware.com/blog/archive/2012/2/29/objc_explain_return_value_of_message_to_nil.html)
|
||
`nil` as a pointer, zero as an integer or floating-point value, structs
|
||
initialized to `0`, and `_Complex` values equal to `{0, 0}`.
|
||
|
||
```objectivec
|
||
// AVOID:
|
||
|
||
if (dataSource) { // AVOID.
|
||
[dataSource moveItemAtIndex:1 toIndex:0];
|
||
}
|
||
```
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
[dataSource moveItemAtIndex:1 toIndex:0]; // GOOD.
|
||
```
|
||
|
||
Note that this applies to `nil` as a message target, not as a parameter value.
|
||
Individual methods may or may not safely handle `nil` parameter values.
|
||
|
||
Note too that this is distinct from checking C/C++ pointers and block pointers
|
||
against `NULL`, which the runtime does not handle and will cause your
|
||
application to crash. You still need to make sure you do not dereference a
|
||
`NULL` pointer.
|
||
|
||
### Nullability
|
||
|
||
Interfaces can be decorated with nullability annotations to describe how the
|
||
interface should be used and how it behaves. Use of nullability regions (e.g.,
|
||
`NS_ASSUME_NONNULL_BEGIN` and `NS_ASSUME_NONNULL_END`) and explicit nullability
|
||
annotations are both accepted. Prefer using the `_Nullable` and `_Nonnull`
|
||
keywords over the `__nullable` and `__nonnull` keywords. For Objective-C methods
|
||
and properties prefer using the context-sensitive, non-underscored keywords,
|
||
e.g., `nonnull` and `nullable`.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
/** A class representing an owned book. */
|
||
@interface GTMBook : NSObject
|
||
|
||
/** The title of the book. */
|
||
@property(nonatomic, readonly, copy, nonnull) NSString *title;
|
||
|
||
/** The author of the book, if one exists. */
|
||
@property(nonatomic, readonly, copy, nullable) NSString *author;
|
||
|
||
/** The owner of the book. Setting nil resets to the default owner. */
|
||
@property(nonatomic, copy, null_resettable) NSString *owner;
|
||
|
||
/** Initializes a book with a title and an optional author. */
|
||
- (nonnull instancetype)initWithTitle:(nonnull NSString *)title
|
||
author:(nullable NSString *)author
|
||
NS_DESIGNATED_INITIALIZER;
|
||
|
||
/** Returns nil because a book is expected to have a title. */
|
||
- (nullable instancetype)init;
|
||
|
||
@end
|
||
|
||
/** Loads books from the file specified by the given path. */
|
||
NSArray<GTMBook *> *_Nullable GTMLoadBooksFromFile(NSString *_Nonnull path);
|
||
```
|
||
|
||
```objectivec
|
||
// AVOID:
|
||
|
||
NSArray<GTMBook *> *__nullable GTMLoadBooksFromTitle(NSString *__nonnull path);
|
||
```
|
||
|
||
Do not assume that a pointer is not null based on a nonnull qualifier, because
|
||
the compiler only checks a subset of such cases, and does not guarantee that the
|
||
pointer is not null. Avoid intentionally violating nullability semantics
|
||
of function, method, and property declarations.
|
||
|
||
<a id="BOOL_Pitfalls"></a>
|
||
|
||
### BOOL Pitfalls
|
||
|
||
<a id="BOOL_Expressions_Conversions"></a>
|
||
#### BOOL Expressions and Conversions
|
||
|
||
Be careful when converting general integral values to `BOOL`. Avoid comparing
|
||
directly with `YES` or comparing multiple `BOOL` values with comparison
|
||
operators.
|
||
|
||
`BOOL` on some Apple platforms (notably Intel macOS, watchOS, and 32-bit iOS)
|
||
is defined as a signed `char`, so it may have values other than `YES` (`1`) and
|
||
`NO` (`0`). Do not cast or convert general integral values directly to `BOOL`.
|
||
|
||
Common mistakes include casting or converting an array's size, a pointer value,
|
||
or the result of a bitwise logic operation to a `BOOL`. These operations can
|
||
depend on the value of the last byte of the integer value and result in an
|
||
unexpected `NO` value. Operations with NS_OPTIONS values and flag masking are
|
||
especially common errors.
|
||
|
||
When converting a general integral value to a `BOOL`, use conditional operators
|
||
to return a `YES` or `NO` value.
|
||
|
||
You can safely interchange and convert `BOOL`, `_Bool` and `bool` (see C++ Std
|
||
4.7.4, 4.12 and C99 Std 6.3.1.2). Use `BOOL` in Objective-C method signatures.
|
||
|
||
Using logical operators (`&&`, `||` and `!`) with `BOOL` is also valid and will
|
||
return values that can be safely converted to `BOOL` without the need for a
|
||
conditional operator.
|
||
|
||
```objectivec
|
||
// AVOID:
|
||
|
||
- (BOOL)isBold {
|
||
return [self fontTraits] & NSFontBoldTrait; // AVOID.
|
||
}
|
||
- (BOOL)isValid {
|
||
return [self stringValue]; // AVOID.
|
||
}
|
||
- (BOOL)isLongEnough {
|
||
return (BOOL)([self stringValue].count); // AVOID.
|
||
}
|
||
```
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
- (BOOL)isBold {
|
||
return ([self fontTraits] & NSFontBoldTrait) ? YES : NO;
|
||
}
|
||
- (BOOL)isValid {
|
||
return [self stringValue] != nil;
|
||
}
|
||
- (BOOL)isLongEnough {
|
||
return [self stringValue].count > 0;
|
||
}
|
||
- (BOOL)isEnabled {
|
||
return [self isValid] && [self isBold];
|
||
}
|
||
```
|
||
|
||
Don't directly compare `BOOL` variables directly with `YES`. Not only is
|
||
it harder to read for those well-versed in C, but the first point above
|
||
demonstrates that return values may not always be what you expect.
|
||
|
||
```objectivec
|
||
// AVOID:
|
||
|
||
BOOL great = [foo isGreat];
|
||
if (great == YES) { // AVOID.
|
||
// ...be great!
|
||
}
|
||
```
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
BOOL great = [foo isGreat];
|
||
if (great) { // GOOD.
|
||
// ...be great!
|
||
}
|
||
```
|
||
|
||
Don't directly compare `BOOL` values using comparison operators. `BOOL`
|
||
values that are true may not be equal. Use logical operators in place
|
||
of bitwise comparisons of `BOOL` values.
|
||
|
||
```objectivec
|
||
// AVOID:
|
||
|
||
if (oldBOOLValue != newBOOLValue) { // AVOID.
|
||
// ... code that should only run when the value changes.
|
||
}
|
||
```
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
if ((!oldBoolValue && newBoolValue) || (oldBoolValue && !newBoolValue)) { // GOOD.
|
||
// ... code that should only run when the value changes.
|
||
}
|
||
|
||
// GOOD, the results of logical operators on BOOLs are safe to compare.
|
||
if (!oldBoolValue != !newBoolValue) {
|
||
// ... code that should only run when the value changes.
|
||
}
|
||
```
|
||
|
||
#### BOOL Literals
|
||
|
||
The [BOOL NSNumber literals](https://clang.llvm.org/docs/ObjectiveCLiterals.html#nsnumber-literals)
|
||
are `@YES` and `@NO` which are equivalent to `[NSNumber numberWithBool:...]`.
|
||
|
||
Avoid using [boxed expressions](https://clang.llvm.org/docs/ObjectiveCLiterals.html#boxed-expressions)
|
||
to create BOOL values, including simple expressions like `@(YES)`.
|
||
Boxed expressions suffer from [the same pitfalls as other BOOL expressions]
|
||
(#BOOL_Expressions_Conversions) as boxing general integral values can
|
||
produce true or false `NSNumbers` that are not equal to `@YES` and `@NO`.
|
||
|
||
When converting a general integral value to a BOOL literal, use conditional
|
||
operators to convert to `@YES` or `@NO`. Do not embed a conditional operator
|
||
inside a boxed expression as this is equivalent to boxing general integral
|
||
values even when the result of the operation is a BOOL.
|
||
|
||
```objectivec
|
||
// AVOID:
|
||
|
||
[_boolArray addValue:@(YES)]; // AVOID boxing even in simple cases.
|
||
NSNumber *isBold = @(self.fontTraits & NSFontBoldTrait); // AVOID.
|
||
NSNumber *hasContent = @([self stringValue].length); // AVOID.
|
||
NSNumber *isValid = @([self stringValue]); // AVOID.
|
||
NSNumber *isStringNotNil = @([self stringValue] ? YES : NO); // AVOID.
|
||
```
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
[_boolArray addValue:@YES]; // GOOD.
|
||
NSNumber *isBold = self.fontTraits & NSFontBoldTrait ? @YES : @NO; // GOOD.
|
||
NSNumber *hasContent = [self stringValue].length ? @YES : @NO; // GOOD.
|
||
NSNumber *isValid = [self stringValue] ? @YES : @NO; // GOOD.
|
||
NSNumber *isStringNotNil = [self stringValue] ? @YES : @NO; // GOOD.
|
||
```
|
||
|
||
<a id="Interfaces_Without_Instance_Variables"></a>
|
||
<a id="interfaces-without-instance-variables"></a>
|
||
|
||
### Containers Without Instance Variables
|
||
|
||
Omit the empty set of braces on interfaces, class extensions, and
|
||
implementations without any instance variable declarations.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
@interface MyClass : NSObject
|
||
// Does a lot of stuff.
|
||
- (void)fooBarBam;
|
||
@end
|
||
|
||
@interface MyClass ()
|
||
- (void)classExtensionMethod;
|
||
@end
|
||
|
||
@implementation MyClass
|
||
// Actual implementation.
|
||
@end
|
||
```
|
||
|
||
```objectivec
|
||
// AVOID:
|
||
|
||
@interface MyClass : NSObject {
|
||
}
|
||
// Does a lot of stuff.
|
||
- (void)fooBarBam;
|
||
@end
|
||
|
||
@interface MyClass () {
|
||
}
|
||
- (void)classExtensionMethod;
|
||
@end
|
||
|
||
@implementation MyClass {
|
||
}
|
||
// Actual implementation.
|
||
@end
|
||
```
|
||
|
||
<a id="Cocoa_Patterns"></a>
|
||
|
||
## Cocoa Patterns
|
||
|
||
<a id="Delegate_Pattern"></a>
|
||
|
||
### Delegate Pattern
|
||
|
||
Delegates, target objects, and block pointers should not be retained when doing
|
||
so would create a retain cycle.
|
||
|
||
To avoid causing a retain cycle, a delegate or target pointer should be released
|
||
as soon as it is clear there will no longer be a need to message the object.
|
||
|
||
If there is no clear time at which the delegate or target pointer is no longer
|
||
needed, the pointer should only be retained weakly.
|
||
|
||
Block pointers cannot be retained weakly. To avoid causing retain cycles in the
|
||
client code, block pointers should be used for callbacks only where they can be
|
||
explicitly released after they have been called or once they are no longer
|
||
needed. Otherwise, callbacks should be done via weak delegate or target
|
||
pointers.
|
||
|
||
<a id="Objective-C++"></a>
|
||
|
||
## Objective-C++
|
||
|
||
<a id="Style_Matches_the_Language"></a>
|
||
|
||
### Style Matches the Language
|
||
|
||
Within an Objective-C++ source file, follow the style for the language of the
|
||
function or method you're implementing. In order to minimize clashes between the
|
||
differing naming styles when mixing Cocoa/Objective-C and C++, follow the style
|
||
of the method being implemented.
|
||
|
||
For code in an `@implementation` block, use the Objective-C naming rules. For
|
||
code in a method of a C++ class, use the C++ naming rules.
|
||
|
||
For code in an Objective-C++ file outside of a class implementation, be
|
||
consistent within the file.
|
||
|
||
```objectivec++
|
||
// GOOD:
|
||
|
||
// file: cross_platform_header.h
|
||
|
||
class CrossPlatformAPI {
|
||
public:
|
||
...
|
||
int DoSomethingPlatformSpecific(); // impl on each platform
|
||
private:
|
||
int an_instance_var_;
|
||
};
|
||
|
||
// file: mac_implementation.mm
|
||
#include "cross_platform_header.h"
|
||
|
||
/** A typical Objective-C class, using Objective-C naming. */
|
||
@interface MyDelegate : NSObject {
|
||
@private
|
||
int _instanceVar;
|
||
CrossPlatformAPI* _backEndObject;
|
||
}
|
||
|
||
- (void)respondToSomething:(id)something;
|
||
|
||
@end
|
||
|
||
@implementation MyDelegate
|
||
|
||
- (void)respondToSomething:(id)something {
|
||
// bridge from Cocoa through our C++ backend
|
||
_instanceVar = _backEndObject->DoSomethingPlatformSpecific();
|
||
NSString* tempString = [NSString stringWithFormat:@"%d", _instanceVar];
|
||
NSLog(@"%@", tempString);
|
||
}
|
||
|
||
@end
|
||
|
||
/** The platform-specific implementation of the C++ class, using C++ naming. */
|
||
int CrossPlatformAPI::DoSomethingPlatformSpecific() {
|
||
NSString* temp_string = [NSString stringWithFormat:@"%d", an_instance_var_];
|
||
NSLog(@"%@", temp_string);
|
||
return [temp_string intValue];
|
||
}
|
||
```
|
||
|
||
Projects may opt to use an 80 column line length limit for consistency with
|
||
Google's C++ style guide.
|
||
|
||
<a id="Spacing_and_Formatting"></a>
|
||
|
||
## Spacing and Formatting
|
||
|
||
<a id="Spaces_vs._Tabs"></a>
|
||
|
||
### Spaces vs. Tabs
|
||
|
||
Use only spaces, and indent 2 spaces at a time. We use spaces for indentation.
|
||
Do not use tabs in your code.
|
||
|
||
You should set your editor to emit spaces when you hit the tab key, and to trim
|
||
trailing spaces on lines.
|
||
|
||
<a id="Line_Length"></a>
|
||
|
||
### Line Length
|
||
|
||
The maximum line length for Objective-C files is 100 columns.
|
||
|
||
<a id="Method_Declarations_and_Definitions"></a>
|
||
|
||
### Method Declarations and Definitions
|
||
|
||
One space should be used between the `-` or `+` and the return type. In general,
|
||
there should be no spacing in the parameter list except between parameters.
|
||
|
||
Methods should look like this:
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
- (void)doSomethingWithString:(NSString *)theString {
|
||
...
|
||
}
|
||
```
|
||
|
||
The spacing before the asterisk is optional. When adding new code, be consistent
|
||
with the surrounding file's style.
|
||
|
||
If a method declaration does not fit on a single line, put each parameter on its
|
||
own line. All lines except the first should be indented at least four spaces.
|
||
Colons before parameters should be aligned on all lines. If the colon before the
|
||
parameter on the first line of a method declaration is positioned such that
|
||
colon alignment would cause indentation on a subsequent line to be less than
|
||
four spaces, then colon alignment is only required for all lines except the
|
||
first. If a parameter declared after the `:` in a method declaration or
|
||
definition would cause the line limit to be exceeded, wrap the content to the
|
||
next line indented by at least four spaces.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
- (void)doSomethingWithFoo:(GTMFoo *)theFoo
|
||
rect:(NSRect)theRect
|
||
interval:(float)theInterval {
|
||
...
|
||
}
|
||
|
||
- (void)shortKeyword:(GTMFoo *)theFoo
|
||
longerKeyword:(NSRect)theRect
|
||
someEvenLongerKeyword:(float)theInterval
|
||
error:(NSError **)theError {
|
||
...
|
||
}
|
||
|
||
- (id<UIAdaptivePresentationControllerDelegate>)
|
||
adaptivePresentationControllerDelegateForViewController:(UIViewController *)viewController;
|
||
|
||
- (void)presentWithAdaptivePresentationControllerDelegate:
|
||
(id<UIAdaptivePresentationControllerDelegate>)delegate;
|
||
|
||
- (void)updateContentHeaderViewForExpansionToContentOffset:(CGPoint)contentOffset
|
||
withController:
|
||
(GTMCollectionExpansionController *)controller;
|
||
|
||
```
|
||
|
||
### Function Declarations and Definitions
|
||
|
||
Prefer putting the return type on the same line as the function name and append
|
||
all parameters on the same line if they will fit. Wrap parameter lists which do
|
||
not fit on a single line as you would wrap arguments in a [function
|
||
call](#Function_Calls).
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
NSString *GTMVersionString(int majorVersion, int minorVersion) {
|
||
...
|
||
}
|
||
|
||
void GTMSerializeDictionaryToFileOnDispatchQueue(
|
||
NSDictionary<NSString *, NSString *> *dictionary,
|
||
NSString *filename,
|
||
dispatch_queue_t queue) {
|
||
...
|
||
}
|
||
```
|
||
|
||
Function declarations and definitions should also satisfy the following
|
||
conditions:
|
||
|
||
* The opening parenthesis must always be on the same line as the function
|
||
name.
|
||
* If you cannot fit the return type and the function name on a single line,
|
||
break between them and do not indent the function name.
|
||
* There should never be a space before the opening parenthesis.
|
||
* There should never be a space between function parentheses and parameters.
|
||
* The open curly brace is always on the end of the last line of the function
|
||
declaration, not the start of the next line.
|
||
* The close curly brace is either on the last line by itself or on the same
|
||
line as the open curly brace.
|
||
* There should be a space between the close parenthesis and the open curly
|
||
brace.
|
||
* All parameters should be aligned if possible.
|
||
* Function scopes should be indented 2 spaces.
|
||
* Wrapped parameters should have a 4 space indent.
|
||
|
||
<a id="Conditionals"></a>
|
||
|
||
### Conditionals
|
||
|
||
Include a space after `if`, `while`, `for`, and `switch`, and around comparison
|
||
operators.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
for (int i = 0; i < 5; ++i) {
|
||
}
|
||
|
||
while (test) {};
|
||
```
|
||
|
||
Braces may be omitted when a loop body or conditional statement fits on a single
|
||
line.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
if (hasSillyName) LaughOutLoud();
|
||
|
||
for (int i = 0; i < 10; i++) {
|
||
BlowTheHorn();
|
||
}
|
||
```
|
||
|
||
```objectivec
|
||
// AVOID:
|
||
|
||
if (hasSillyName)
|
||
LaughOutLoud(); // AVOID.
|
||
|
||
for (int i = 0; i < 10; i++)
|
||
BlowTheHorn(); // AVOID.
|
||
```
|
||
|
||
If an `if` clause has an `else` clause, both clauses should use braces.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
if (hasBaz) {
|
||
foo();
|
||
} else { // The else goes on the same line as the closing brace.
|
||
bar();
|
||
}
|
||
```
|
||
|
||
```objectivec
|
||
// AVOID:
|
||
|
||
if (hasBaz) foo();
|
||
else bar(); // AVOID.
|
||
|
||
if (hasBaz) {
|
||
foo();
|
||
} else bar(); // AVOID.
|
||
```
|
||
|
||
Intentional fall-through to the next case should be documented with a comment
|
||
unless the case has no intervening code before the next case.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
switch (i) {
|
||
case 1:
|
||
...
|
||
break;
|
||
case 2:
|
||
j++;
|
||
// Falls through.
|
||
case 3: {
|
||
int k;
|
||
...
|
||
break;
|
||
}
|
||
case 4:
|
||
case 5:
|
||
case 6: break;
|
||
}
|
||
```
|
||
|
||
<a id="Expressions"></a>
|
||
|
||
### Expressions
|
||
|
||
Use a space around binary operators and assignments. Omit a space for a unary
|
||
operator. Do not add spaces inside parentheses.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
x = 0;
|
||
v = w * x + y / z;
|
||
v = -y * (x + z);
|
||
```
|
||
|
||
Factors in an expression may omit spaces.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
v = w*x + y/z;
|
||
```
|
||
|
||
<a id="Method_Invocations"></a>
|
||
|
||
### Method Invocations
|
||
|
||
Method invocations should be formatted much like method declarations.
|
||
|
||
When there's a choice of formatting styles, follow the convention already used
|
||
in a given source file. Invocations should have all arguments on one line:
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
[myObject doFooWith:arg1 name:arg2 error:arg3];
|
||
```
|
||
|
||
or have one argument per line, with colons aligned:
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
[myObject doFooWith:arg1
|
||
name:arg2
|
||
error:arg3];
|
||
```
|
||
|
||
Don't use any of these styles:
|
||
|
||
```objectivec
|
||
// AVOID:
|
||
|
||
[myObject doFooWith:arg1 name:arg2 // some lines with >1 arg
|
||
error:arg3];
|
||
|
||
[myObject doFooWith:arg1
|
||
name:arg2 error:arg3];
|
||
|
||
[myObject doFooWith:arg1
|
||
name:arg2 // aligning keywords instead of colons
|
||
error:arg3];
|
||
```
|
||
|
||
As with declarations and definitions, when the first keyword is shorter than the
|
||
others, indent the later lines by at least four spaces, maintaining colon
|
||
alignment:
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
[myObj short:arg1
|
||
longKeyword:arg2
|
||
evenLongerKeyword:arg3
|
||
error:arg4];
|
||
```
|
||
|
||
Invocations containing multiple inlined blocks may have their parameter names
|
||
left-aligned at a four space indent.
|
||
|
||
<a id="Function_Calls"></a>
|
||
|
||
### Function Calls
|
||
|
||
Function calls should include as many parameters as fit on each line, except
|
||
where shorter lines are needed for clarity or documentation of the parameters.
|
||
|
||
Continuation lines for function parameters may be indented to align with the
|
||
opening parenthesis, or may have a four-space indent.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
CFArrayRef array = CFArrayCreate(kCFAllocatorDefault, objects, numberOfObjects,
|
||
&kCFTypeArrayCallBacks);
|
||
|
||
NSString *string = NSLocalizedStringWithDefaultValue(@"FEET", @"DistanceTable",
|
||
resourceBundle, @"%@ feet", @"Distance for multiple feet");
|
||
|
||
UpdateTally(scores[x] * y + bases[x], // Score heuristic.
|
||
x, y, z);
|
||
|
||
TransformImage(image,
|
||
x1, x2, x3,
|
||
y1, y2, y3,
|
||
z1, z2, z3);
|
||
```
|
||
|
||
Use local variables with descriptive names to shorten function calls and reduce
|
||
nesting of calls.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
double scoreHeuristic = scores[x] * y + bases[x];
|
||
UpdateTally(scoreHeuristic, x, y, z);
|
||
```
|
||
|
||
<a id="Exceptions"></a>
|
||
|
||
### Exceptions
|
||
|
||
Format exceptions with `@catch` and `@finally` labels on the same line as the
|
||
preceding `}`. Add a space between the `@` label and the opening brace (`{`), as
|
||
well as between the `@catch` and the caught object declaration. If you must use
|
||
Objective-C exceptions, format them as follows. However, see [Avoid Throwing
|
||
Exceptions](#Avoid_Throwing_Exceptions) for reasons why you should not be using
|
||
exceptions.
|
||
|
||
```objectivec
|
||
// GOOD:
|
||
|
||
@try {
|
||
foo();
|
||
} @catch (NSException *ex) {
|
||
bar(ex);
|
||
} @finally {
|
||
baz();
|
||
}
|
||
```
|
||
|
||
<a id="Function_Length"></a>
|
||
|
||
### Function Length
|
||
|
||
Prefer small and focused functions.
|
||
|
||
Long functions and methods are occasionally appropriate, so no hard limit is
|
||
placed on function length. If a function exceeds about 40 lines, think about
|
||
whether it can be broken up without harming the structure of the program.
|
||
|
||
Even if your long function works perfectly now, someone modifying it in a few
|
||
months may add new behavior. This could result in bugs that are hard to find.
|
||
Keeping your functions short and simple makes it easier for other people to read
|
||
and modify your code.
|
||
|
||
When updating legacy code, consider also breaking long functions into smaller
|
||
and more manageable pieces.
|
||
|
||
<a id="Vertical_Whitespace"></a>
|
||
|
||
### Vertical Whitespace
|
||
|
||
Use vertical whitespace sparingly.
|
||
|
||
To allow more code to be easily viewed on a screen, avoid putting blank lines
|
||
just inside the braces of functions.
|
||
|
||
Limit blank lines to one or two between functions and between logical groups of
|
||
code.
|
||
|
||
<a id="Objective-C_Style_Exceptions"></a>
|
||
|
||
## Objective-C Style Exceptions
|
||
|
||
<a id="Indicating_style_exceptions"></a>
|
||
|
||
### Indicating style exceptions
|
||
|
||
Lines of code that are not expected to adhere to these style recommendations
|
||
require `// NOLINT` at the end of the line or `// NOLINTNEXTLINE` at the end of
|
||
the previous line. Sometimes it is required that parts of Objective-C code must
|
||
ignore these style recommendations (for example code may be machine generated or
|
||
code constructs are such that its not possible to style correctly).
|
||
|
||
A `// NOLINT` comment on that line or `// NOLINTNEXTLINE` on the previous line
|
||
can be used to indicate to the reader that code is intentionally ignoring style
|
||
guidelines. In addition these annotations can also be picked up by automated
|
||
tools such as linters and handle code correctly. Note that there is a single
|
||
space between `//` and `NOLINT*`.
|