Objective-C 编程风格指南

一、

NYTimes Objective-C 编程风格指南。

来源:https://github.com/NYTimes/objective-c-style-guide


这篇指南总结了纽约时报iOS开发团队的编程风格。欢迎大家在github中提供建议和pull请求。


简介:

以下是形成本编程指南所涉及到的Apple官方文档。如果本文有未尽之处,可以参考以下链接:

The Objective-C Programming Language

Cocoa Fundamentals Guide

Coding Guidelines for Cocoa

iOS App Programming Guide


目录

01 点表示法

02 空格

03 条件语句

04 三元运算子

05 方法

06 变量

07 命名

08 下划线

09 注释

10 初始化&内存释放

11 Literals字面量

12 CGRect 函数

13 常量

14 枚举类型

15 私有属性

16 图片名称

17 布尔变量

18 单例

19 Xcode项目


01 “.”点表示法应用于获取和改变属性,而“[]”括号表示法用于所有其它实例。

例如:

恰当用法:

view.backgroundColor = [UIColor orangeColor];

[UIApplication sharedApplication].delegate;

不当用法:

[view setBackgroundColor:[UIColor orangeColor]];

UIApplication.sharedApplication.delegate;


02 空格,或换行

1)行缩进使用4个空格。禁止使用Tab键来缩进。请在Xcode偏好设置中进行设置。

2)方法大括号和其它大括号(比如if/else/switch/while等等)应在语句的同一行开始,而在新的一行关闭。

例如:

if (user.isHappy) {

    //Do something

}

else {

    //Do something else

}

3)为保证视觉上的整洁和代码组织,在方法之间应提供且仅提供一行空白。方法中的空白应用于区分功能,但空白行最好用于区分两个不同方法。

4@synthesize@dynamic应在方法实现的新一行中声明。


03 条件语句

为避免错误,条件语句体必须使用大括号,即便语句体中的语句可以不必使用大括号(比如只有一行语句)。常见的错误包括在不使用大括号的情况下添加第二行语句,以为它属于if语句

的一部分。此外,更可怕的事情是,如果条件语句中的代码行被注释,则本不术语条件语句的下一行代码将变成条件语句的一部分。此外,这种编码风格和所有其它条件语句均保持一致。

例如:

恰当用法:

if (!error) {

    return success;

}


不当用法:

if (!error)

return success;


不当用法2

if (!error) return success;


04 三元运算子

仅当使用该运算子可以让代码显得更清晰易懂时方可使用三元运算子。更多情况下应使用条件语句。使用类似if的条件语句对多种条件进行判断通常要更容易理解,或使用实例变量。


恰当用法:

result = a > b ? x : y;


不当用法:

result = a > b ? x = c > d ? c : d : y;


05 方法

在方法声明中,在(-/ )符号之后应加上一个空格。此外,在方法段之间应添加一个空格。

例如:

(void)setExampleText:(NSString *)text image:(UIImage *)image;


06 变量

变量的命名应尽可能具有自解释性。除了在for()循环语句中,应避免使用单个字母变量名称。

除非是常量,星号应紧贴变量名称表示指向变量的指针,比如:


正确用法:

NSString *text;


不当用法:

NSString* text;


NSString * text;


应尽可能使用属性定义替代单一的实例变量。避免在初始化方法,dealloc方法和自定义的settergetter方法中直接读取实例变量参数(init,initWithCoder:,等等)。更多信息

请参看here

例如:

恰当用法:

@interface NYTSection: NSObject


@property (nonatomic) NSString *headline;


@end


不当用法:

@interface NYTSection : NSObject {

    NSString *headline;

}


07 命名规范

苹果的命名规范应尽可能符合内存管理法则(NARCmemory management rules

                    

Objective-C中鼓励使用长的描述性的方法和变量名称。

例如:

恰当用法:UIButton *settingsButton;

                    

不当用法:

UIButton *setBut;

                    

对于类和常量名称,应尽量使用三大写字母前缀(比如NYT),但对Core Data的实体名称可不适用该法则。

                    

常量名称应将其中的所有单词的首字母大写,同时加上相关类的名称作为前缀。

例如:

恰当用法:

static const NSTimeInterval NYTArticleViewControllerNavigationFadeAnimationDuration = 0.3;


不当用法:

static const NSTimeInterval fadetime = 1.7;

                    

属性名称应使用camel-case(驼峰式)命名方法,且第一个单词的首字母应为小写。如果Xcode版本支持对变量的自动合成,则不必深究。否则与该属性对应的实例变量名称的第一个单

词的首字母应为小写,且在前面加上下划线。

例如:

恰当用法:

@synthesize descriptiveVariableName = _descriptiveVariableName;


不当用法:

id varnm;

                    

08 下划线

当使用属性变量时,应通过self.来获取和更改实例变量。这就意味着所有的属性将是独特的,因为它们的名称前会加上self.。本地变量名称中不应包含下划线。

                    

09 注释

在需要注释的地方,应使用注释来解释某一块特定的代码的功能。所有的代码注释必须是最新的,要吗就删掉。

应尽量使用行注释,而避免使用块注释。之所以这样是因为代码自身需要是自文档化的,因此只需要零散添加一些行注释。当然,对于用于生成文档的注释,该原则并不适用。

                    

10 初始化和内存释放

dealloc方法应放在方法实现文件的顶部,在@synthesize@dynamic语句之后。init初始化方法应放在dealloc方法之后。

                    

11 Literals字面量

在创建NSString,NSDictionary,NSArrayNSNumber等对象的immutable实例时,应使用字面量。需要注意的是,不应将nil传递给NSArrayNSDictionary字面量,否则会引

起程序崩溃。

                    

例如:

恰当用法:

NSArray *names = @[@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul"];

NSDictionary *productManagers = @{@"iPhone" : @"Kate", @"iPad" : @"Kamal", @"Mobile Web" : @"Bill"};

NSNumber *shouldUseLiterals = @YES;

NSNumber *buildingZIPCode = @10018;

                    

不当用法:

NSArray *names = [NSArray arrayWithObjects:@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul", nil];

NSDictionary *productManagers = [NSDictionary dictionaryWithObjectsAndKeys: @"Kate", @"iPhone", @"Kamal", @"iPad", @"Bill", @"Mobile Web", nil];

NSNumber *shouldUseLiterals = [NSNumber numberWithBool:YES];

NSNumber *ZIPCode = [NSNumber numberWithInteger:10018];

                    

12 CGRect函数

当需要获取一个CGRect矩形的x,y,width,height属性时,应使用CGGeometry函数,而非直接访问结构体成员。

例如:

恰当用法:

CGRect frame = self.view.frame;

                    

CGFloat x = CGRectGetMinX(frame);

CGFloat y = CGRectGetMinY(frame);

CGFloat width = CGRectGetWidth(frame);

CGFloat height = CGRectGetHeight(frame);

                    

不当用法:

CGRect frame = self.view.frame;

                    

CGFloat x = frame.origin.x;

CGFloat y = frame.origin.y;

CGFloat width = frame.size.width;

CGFloat height = frame.size.height;

                    

13 常量

相对字符串字面量或数字,我们更推荐适用常量。应使用static方式声明常量,而非使用#define的方式来定义宏。

例如:

恰当用法:

static NSString * const NYTAboutViewControllerCompanyName = @"The New York Times Company";

static const CGFloat NYTImageThumbnailHeight = 50.0;

                    

不当用法:

#define CompanyName @"The New York Times Company"

#define thumbnailHeight 2

                    

14 枚举类型

在使用enum的时候,推荐适用最新的fixed underlying type(WWDC 2012 session 405- Modern Objective-C)规范,因为它具备更强的类型检查和代码完成功能。

例如:

typedef NS_ENUM(NSInteger, NYTAdRequestState) {

NYTAdRequestStateInactive,

NYTAdRequestStateLoading

};

                    

15 私有属性

私有属性应在类实现文件的类扩展(匿名分类)中进行声明。应避免使用命名分类(比如NYTPrivateprivate)。

例如:

@interface NYTAdvertisement ()

                    

@property (nonatomic, strong) GADBannerView *googleAdView;

@property (nonatomic, strong) ADBannerView *iAdView;

@property (nonatomic, strong) UIWebView *adXWebView;

                    

@end

                    

16 图片名称

在命名图片名称的时候,应保持一致性,从而让开发团队和成员可以明白其含义。图片名称的第一个单词应描述其用途,并使用camel-case风格,然后是不带前缀的所属类名称或属性,

最后是色彩、位置和状态。

例如:

RefreshBarButtonItem / RefreshBarButtonItem@2x and RefreshBarButtonItemSelected / RefreshBarButtonItemSelected@2x

ArticleNavigationBarWhite / ArticleNavigationBarWhite@2x and ArticleNavigationBarBlackSelected / ArticleNavigationBarBlackSelected@2x.

                    

17 布尔变量

因为nil将被解析为NO,因此没有必要在条件语句中进行比较。永远不要将任何东西和YES进行直接比较,因为YES被定义为1,而一个BOOL变量可以有8个字节。

例如:

恰当用法:

if (!someObject) {

}

                    

不当用法:

if (someObject == nil) {

}

                    

以下是BOOL变量的使用:

恰当用法:

if (isAwesome)

if (![someObject boolValue])

                    

不当用法:

if ([someObject boolValue] == NO)

if (isAwesome == YES) // Never do this.

                    

如果一个BOOL属性使用形容词来表达,属性将忽略’is’前缀,但会强调惯用名称。

例如:

@property (assign, getter=isEditable) BOOL editable;

                    

18 单例

在创建单例对象的共享实例时,应使用线程安全模式。

例如:

+ (instancetype)sharedInstance {

    static id sharedInstance = nil;

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        sharedInstance = [[self alloc] init];

    });

                        

    return sharedInstance;

}

                    

19 Xcode项目

为避免文件混乱,实际的物理文件应和Xcode项目保持一直。在Xcode中所创建的任何group都应有文件系统中相对应的文件夹。不应仅根据文件类型来进行分组,还需要考虑到其作用。

                    

XcodetargetBuild Setting中,中尽量开启”Treat Warnings as Errors“,同时尽量开启其他的警告additional warnings。如果需要忽略某个特定的警告,可以使用

Clang's pragma feature


       

二、如果以上编码风格不合你的口味,还可以参考以下几个风格指南:

Google

GitHub

Adium

Sam Soffes

CocoaDevCentral

Luke Redpath

Marcus Zarra

                    

                    Google Objective-C Style Guide

                    

                    Revision 2.59

                    

                    Mike Pinkerton

                    Greg Miller

                    Dave MacLachlan

                    Each style point has a summary for which additional information is available by toggling the accompanying arrow button that looks this way: ▶. You may toggle all summaries with the big arrow button:

                    

                    ▶ Toggle all summaries

                    Table of Contents

                    Example

                    

                    Spacing And Formatting

                    Spaces vs. Tabs Line Length Method Declarations and Definitions Method Invocations @public and @private Exceptions Protocols Blocks Container Literals

                    Naming

                    File Names Objective-C++ Class Names Category Names Objective-C Method Names Variable Names

                    Comments

                    File Comments Declaration Comments Implementation Comments Object Ownership

                    Cocoa and Objective-C Features

                    Instance Variables In Headers Should Be @private Identify Designated Initializer Override Designated Initializer Overridden NSObject Method Placement Initialization Avoid +new Keep the Public API Simple #import and #include Use Root Frameworks Prefer To autorelease At Time of Creation Autorelease Then Retain Avoid Accessors During init and dealloc Dealloc Instance Variables in Declaration Order Setters copy NSStrings Avoid Throwing Exceptions nil Checks BOOL Pitfalls Properties Interfaces Without Instance Variables Automatically Synthesized Instance Variables Automatic Reference Counting (ARC) NSNumber Literals

                    Cocoa Patterns

                    Delegate Pattern Model/View/Controller

                    Historical Notes

                    Trailing vs Leading Underscores

                    Important Note

                    

                    Displaying Hidden Details in this Guide

                    

                    ▶

                    This style guide contains many details that are initially hidden from view. They are marked by the triangle icon, which you see here on your left. Click it now. You should see "Hooray" appear below.

                    

                    Background

                    

                    Objective-C is a very dynamic, object-oriented extension of C. It's designed to be easy to use and read, while enabling sophisticated object-oriented design. It is the primary development language for new applications on Mac OS X and the iPhone.

                    

                    Cocoa is one of the main application frameworks on Mac OS X. It is a collection of Objective-C classes that provide for rapid development of full-featured Mac OS X applications.

                    

                    Apple has already written a very good, and widely accepted, coding guide for Objective-C. Google has also written a similar guide for C++. This Objective-C guide aims to be a very natural combination of Apple's and Google's general recommendations. So, before reading this guide, please make sure you've read:

                    

                    Apple's Cocoa Coding Guidelines

                    Google's Open Source C++ Style Guide

                    

                    

                    Note that all things that are banned in Google's C++ guide are also banned in Objective-C++, unless explicitly noted in this document.

                    

                    The purpose of this document is to describe the Objective-C (and Objective-C++) coding guidelines and practices that should be used for all Mac OS X code. Many of 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.

                    

                    Google has already released open-source code that conforms to these guidelines as part of the Google Toolbox for Mac project (abbreviated GTM throughout this document). Code meant to be shared across different projects is a good candidate to be included in this repository.

                    

                    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 .

                    

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

                    

                    An example header file, demonstrating the correct commenting and spacing for an @interface declaration

                    

#import <Foundation/Foundation.h>

                    

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

                    //

                    // (no blank line between this comment and the interface)

                    @interface Foo : NSObject

                    

                    // Returns an autoreleased instance of Foo. See -initWithBar: for details

                    // about |bar|.

                    + (instancetype)fooWithBar:(NSString *)bar;

                    

                    // Designated initializer. |bar| is a thing that represents a thing that

                    // does a thing.

                    - (instancetype)initWithBar:(NSString *)bar;

                    

                    // Gets and sets |_bar|.

                    - (NSString *)bar;

                    - (void)setBar:(NSString *)bar;

                    

                    // Does some work with |blah| and returns YES if the work was completed

                    // successfully, and NO otherwise.

                    - (BOOL)doWorkWithBlah:(NSString *)blah;

                    

                    @end

                    An example source file, demonstrating the correct commenting and spacing for the @implementation of an interface. It also includes the reference implementations for important methods like getters and setters, init, and dealloc.

                    

#import "Foo.h"

                    

                    

                    @implementation Foo {

                        NSString *_bar;

                        NSString *_foo;

                    }

                    

                    + (instancetype)fooWithBar:(NSString *)bar {

                        return [[[self alloc] initWithBar:bar] autorelease];

                    }

                    

                    // Must always override super's designated initializer.

                    - (instancetype)init {

                        return [self initWithBar:nil];

                    }

                    

                    - (instancetype)initWithBar:(NSString *)bar {

                        if ((self = [super init])) {

                            _bar = [bar copy];

                            _bam = [[NSString alloc] initWithFormat:@"hi %d", 3];

                        }

                        return self;

                    }

                    

                    - (void)dealloc {

                        [_bar release];

                        [_bam release];

                        [super dealloc];

                    }

                    

                    - (NSString *)bar {

                        return _bar;

                    }

                    

                    - (void)setBar:(NSString *)bar {

                        [_bar autorelease];

                        _bar = [bar copy];

                    }

                    

                    - (BOOL)doWorkWithBlah:(NSString *)blah {

                        // ...

                        return NO;

                    }

                    

                    @end

                    Blank lines before and after @interface, @implementation, and @end are optional. If your @interface declares instance variables, a blank line should come after the closing brace (}).

                    

                    

                    

                    Unless an interface or implementation is very short, such as when declaring a handful of private methods or a bridge class, adding blank lines usually helps readability.

                    

                    Spacing And Formatting

                    

                    Spaces vs. Tabs

                    

                    link

                    ▽

                    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.

                    

                    Line Length

                    

                    link

                    ▽

                    The maximum line length for Objective-C and Objective-C++ files is 100 columns. Projects may opt to use an 80 column limit for consistency with the C++ style guide.

                    You can make violations easier to spot by enabling Preferences > Text Editing > Page guide at column: 100 in Xcode.

                    

                    Method Declarations and Definitions

                    

                    link

                    ▽

                    One space should be used between the - or + and the return type, and no spacing in the parameter list except between parameters.

                    Methods should look like this:

                    

                    - (void)doSomethingWithString:(NSString *)theString {

                        ...

                    }

                    The spacing before the asterisk is optional. When adding new code, be consistent with the surrounding file's style.

                    

                    If you have too many parameters to fit on one line, giving each its own line is preferred. If multiple lines are used, align each using the colon before the parameter.

                    

                    - (void)doSomethingWith:(GTMFoo *)theFoo

                    rect:(NSRect)theRect

                    interval:(float)theInterval {

                        ...

                    }

                    When the first keyword is shorter than the others, indent the later lines by at least four spaces, maintaining colon alignment:

                    

                    - (void)short:(GTMFoo *)theFoo

                    longKeyword:(NSRect)theRect

                    evenLongerKeyword:(float)theInterval

                    error:(NSError **)theError {

                        ...

                    }

                    Method Invocations

                    

                    link

                    ▽

                    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:

                    

                    [myObject doFooWith:arg1 name:arg2 error:arg3];

                    or have one argument per line, with colons aligned:

                    

                    [myObject doFooWith:arg1

                                   name:arg2

                                  error:arg3];

                    Don't use any of these styles:

                    

                    [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:

                    

                    [myObj short:arg1

                     longKeyword:arg2

                     evenLongerKeyword:arg3

                     error:arg4];

                    Invocations containing inlined blocks may have their segments left-aligned at a four space indent.

                    

                    @public and @private

                    

                    link

                    ▽

                    The @public and @private access modifiers should be indented by 1 space.

                    This is similar to public, private, and protected in C++.

                    

                    @interface MyClass : NSObject {

                    @public

                        ...

                    @private

                        ...

                    }

                    @end

                    Exceptions

                    

                    link

                    ▽

                    Format exceptions with each @ label on its own line and a space between the @ label and the opening brace ({), as well as between the @catch and the caught object declaration.

    If you must use Obj-C exceptions, format them as follows. However, see Avoid Throwing Exceptions for reasons why you should not be using exceptions.

        

        @try {

            foo();

        }

    @catch (NSException *ex) {

        bar(ex);

    }

    @finally {

        baz();

    }

    Protocols

    

    link

    ▽

    There should not be a space between the type identifier and the name of the protocol encased in angle brackets.

    This applies to class declarations, instance variables, and method declarations. For example:

    

    @interface MyProtocoledClass : NSObject<NSWindowDelegate> {

    @private

        id<MyFancyDelegate> _delegate;

    }

    - (void)setDelegate:(id<MyFancyDelegate>)aDelegate;

    @end

    Blocks

    

    link

    ▽

    Code inside blocks should be indented four spaces.

    There are several appropriate style rules, depending on how long the block is:

    

    If the block can fit on one line, no wrapping is necessary.

    If it has to wrap, the closing brace should line up with the first character of the line on which the block is declared.

    Code within the block should be indented four spaces.

    If the block is large, e.g. more than 20 lines, it is recommended to move it out-of-line into a local variable.

    If the block takes no parameters, there are no spaces between the characters ^{. If the block takes parameters, there is no space between the ^( characters, but there is one space between the ) { characters.

        Invocations containing inlined blocks may have their segments left-aligned at a four-space indent. This helps when invocations contain multiple inlined blocks.

        Two space indents inside blocks are also allowed, but should only be used when it's consistent with the rest of the project's code.

        // The entire block fits on one line.

        [operation setCompletionBlock:^{ [self onOperationDone]; }];

        

        // The block can be put on a new line, indented four spaces, with the

        // closing brace aligned with the first character of the line on which

        // block was declared.

        [operation setCompletionBlock:^{

            [self.delegate newDataAvailable];

        }];

        

        // Using a block with a C API follows the same alignment and spacing

        // rules as with Objective-C.

        dispatch_async(_fileIOQueue, ^{

            NSString* path = [self sessionFilePath];

            if (path) {

                // ...

            }

        });

        

        // An example where the parameter wraps and the block declaration fits

        // on the same line. Note the spacing of |^(SessionWindow *window) {|

        // compared to |^{| above.

        [[SessionService sharedService]

         loadWindowWithCompletionBlock:^(SessionWindow *window) {

             if (window) {

                 [self windowDidLoad:window];

             } else {

                 [self errorLoadingWindow];

             }

         }];

        

        // An example where the parameter wraps and the block declaration does

        // not fit on the same line as the name.

        [[SessionService sharedService]

         loadWindowWithCompletionBlock:

         ^(SessionWindow *window) {

             if (window) {

                 [self windowDidLoad:window];

             } else {

                 [self errorLoadingWindow];

             }

         }];

        

        // Large blocks can be declared out-of-line.

        void (^largeBlock)(void) = ^{

            // ...

        };

        [_operationQueue addOperationWithBlock:largeBlock];

        

        // An example with multiple inlined blocks in one invocation.

        [myObject doSomethingWith:arg1

                       firstBlock:^(Foo *a) {

                           // ...

                       }

                      secondBlock:^(Bar *b) {

                          // ...

                      }];

        Container Literals

        

        link

        ▽

        For projects using Xcode 4.4 or later and clang, the use of container (array and dictionary) literals is encouraged. If split across multiple lines, the contents should be indented two spaces.

        If the collection fits on one line, put a single space after the opening and before the closing brackets.

        

        NSArray* array = @[ [foo description], @"Another String", [bar description] ];

        

        NSDictionary* dict = @{ NSForegroundColorAttributeName : [NSColor redColor] };

    Not:

        

        NSArray* array = @[[foo description], [bar description]];

        

        NSDictionary* dict = @{NSForegroundColorAttributeName: [NSColor redColor]};

        If the collection spans more than a single line, place the opening bracket on the same line as the declaration, indent the body by two spaces, and place the closing bracket on a new line that is indented to the same level as the opening bracket.

        

        NSArray* array = @[

                           @"This",

                           @"is",

                           @"an",

                           @"array"

                           ];

        

        NSDictionary* dictionary = @{

                                     NSFontAttributeName : [NSFont fontWithName:@"Helvetica-Bold" size:12],

                                     NSForegroundColorAttributeName : fontColor

                                     };

        For dictionary literals, there should be one space before the colon and at least one space after it (to optionally align the values).

        

        NSDictionary* option1 = @{

                                  NSFontAttributeName : [NSFont fontWithName:@"Helvetica-Bold" size:12],

                                  NSForegroundColorAttributeName : fontColor

                                  };

        

        NSDictionary* option2 = @{

                                  NSFontAttributeName :            [NSFont fontWithName:@"Arial" size:12],

                                  NSForegroundColorAttributeName : fontColor

                                  };

        The following are all incorrect:

        

        // There should be a space before the colon.

        NSDictionary* wrong = @{

                                AKey:       @"b",

                                BLongerKey: @"c",

                                };

        

        // The items should each be on a new line, or the entire expression

        // should fit on one line.

        NSDictionary* alsoWrong= @{ AKey : @"a",

                                    BLongerKey : @"b" };

        

        // There should be no variable space before the colon, only after.

        NSDictionary* stillWrong = @{

                                     AKey       : @"b",

                                     BLongerKey : @"c",

                                     };

        Naming

        

        Naming rules are very important in maintainable code. 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 comments unnecessary.

        

        When writing pure Objective-C code, we mostly follow standard Objective-C naming rules. These naming guidelines may differ significantly from those outlined in the C++ style guide. For example, Google's C++ style guide recommends the use of underscores between words in variable names, whereas this guide recommends the use of intercaps, which is standard in the Objective-C community.

        

        Any class, category, method, or variable name may use all capitals for initialisms within the name. This follows Apple's standard of using all capitals within a name for initialisms such as URL, TIFF, and EXIF.

            

            When writing Objective-C++, however, things are not so cut and dry. Many projects need to implement cross-platform C++ APIs with some Objective-C or Cocoa, or bridge between a C++ back-end and a native Cocoa front-end. This leads to situations where the two guides are directly at odds.

            

            Our solution is that the style follows that of the method/function being implemented. If you're in an @implementation block, use the Objective-C naming rules. If you're implementing a method for a C++ class, use the C++ naming rules. This avoids the situation where instance variable and local variable naming rules are mixed within a single function, which would be a serious detriment to readability.

                

                File Names

                

                link

                ▽

                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:

                

                .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

                File names for categories should include the name of the class being extended, e.g. GTMNSString+Utils.h or GTMNSTextView+Autocomplete.h

                    

                    Objective-C++

                    

                    link

                    ▽

                    Within a source file, Objective-C++ follows the style of the function/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. If you're in an @implementation block, use the Objective-C naming rules. If you're implementing a method for a C++ class, use the C++ naming rules.

                        

                        // 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];

        }

        Class Names

        

        link

        ▽

        Class names (along with category and protocol names) should start as uppercase and use mixed case to delimit words.

        When designing code to be shared across multiple applications, prefixes are acceptable and recommended (e.g. GTMSendMessage). Prefixes are also recommended for classes of large applications that depend on external libraries.

            

            Category Names

            

            link

            ▽

            Category names should start with a 2 or 3 character prefix identifying the category as part of a project or open for general use. The category name should incorporate the name of the class it's extending.

                For example, if we want to create a category on NSString for parsing, we would put the category in a file named GTMNSString+Parsing.h, and the category itself would be named GTMStringParsingAdditions (yes, we know the file name and the category name do not match, but this file could have many separate categories related to parsing). Methods in that category should share the prefix (gtm_myCategoryMethodOnAString:) in order to prevent collisions in Objective-C which only has a single namespace. If the code isn't meant to be shared and/or doesn't run in a different address-space, the method naming isn't quite as important.

                    

                    There should be a single space between the class name and the opening parenthesis of the category.

                    

                    // Extending a framework class:

                    @interface NSString (GTMStringParsingAdditions)

                    - (NSString *)gtm_foobarString;

        @end

        

        // Making your methods and properties private:

        @interface FoobarViewController ()

        @property(nonatomic, retain) NSView *dongleView;

        - (void)performLayout;

        @end

        Objective-C Method Names

        

        link

        ▽

        Method names should start as lowercase and then use mixed case. Each named parameter should also start as lowercase.

        The method name should read like a sentence if possible, meaning you should choose parameter names that flow with the method name. (e.g. convertPoint:fromRect: or replaceCharactersInRange:withString:). See Apple's Guide to Naming Methods for more details.

            

            Accessor methods should be named the same as the variable they're "getting", but they should not be prefixed with the word "get". For example:

            

            - (id)getDelegate;  // AVOID

        - (id)delegate;    // GOOD

        

        

        This is for Objective-C methods only. C++ method names and functions continue to follow the rules set in the C++ style guide.

            

            Variable Names

            

            link

            ▽

            Variables names start with a lowercase and use mixed case to delimit words. Instance variables have leading underscores. For example: myLocalVariable, _myInstanceVariable.

            Common Variable Names

            

            Do not use Hungarian notation for syntactic attributes, such as the static type of a variable (int or pointer). Give as descriptive a name as possible, within reason. 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:

                

                int w;

        int nerr;

        int nCompConns;

        tix = [[NSMutableArray alloc] init];

        obj = [someObject object];

        p = [network port];

        int numErrors;

        int numCompletedConnections;

        tickets = [[NSMutableArray alloc] init];

        userInfo = [someObject object];

        port = [network port];

        

        

        Instance Variables

        

        Instance variables are mixed case and should be prefixed with an underscore e.g. _usernameTextField. Note that historically the convention was to put the underscore at the end of the name, and projects may opt to continue using trailing underscores in new code in order to maintain consistency within their codebase (see the Historical Notes section). It is recommended you leave old code as-is, unless doing so would create inconsistency within a class.

        

        

        

        Constants

        

        Constant names (#defines, enums, const local variables, etc.) should start with a lowercase k and then use mixed case to delimit words. For example:

        

        const int kNumberOfFiles = 12;

        NSString *const kUserKey = @"kUserKey";

        enum DisplayTinge {

            kDisplayTingeGreen = 1,

            kDisplayTingeBlue = 2

        };

        Because Objective-C does not provide namespacing, constants with global scope should have an appropriate prefix to minimize the chance of name collision, typically like kClassNameFoo.

        

        

        

        Comments

        

        Though a pain to write, they are absolutely vital to keeping our code readable. The following rules describe what you should comment and where. But remember: while comments are very 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.

            

            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!

                

                Remember that all of the rules and conventions listed in the C++ Style Guide are in effect here, with a few additional points, below.

                

                File Comments

                

                link

                ▽

                A file may optionally start with a description of its contents.

                Every file should contain the following items, in order:

                

                license boilerplate if neccessary. Choose the appropriate boilerplate for the license used by the project (e.g. Apache 2.0, BSD, LGPL, GPL).

                    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.

                        

                        Declaration Comments

                        

                        link

                        ▽

                        Every interface, category, and protocol declaration should have an accompanying comment describing its purpose and how it fits into the larger picture.

                        // A delegate for NSApplication to handle notifications about app

                        // launch and shutdown. Owned by the main app controller.

                        @interface MyAppDelegate : NSObject {

                            ...

                        }

        @end

        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 in the public interface should have a comment explaining its function, arguments, return value, and any side effects.

        

        Document the synchronization assumptions the class makes, 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.

            

            Implementation Comments

            

            link

            ▽

            Use vertical bars to quote variable names and symbols in comments rather than quotes or naming the symbol inline.

            This helps eliminate ambiguity, especially when the symbol is a common word that might make the sentence read like it was poorly constructed. E.g. for a symbol "count":

                

                // Sometimes we need |count| to be less than zero.

                or when quoting something which already contains quotes

                

                // Remember to call |StringWithoutSpaces("foo bar baz")|

                Object Ownership

                

                link

                ▽

                Make the pointer ownership model as explicit as possible when it falls outside the most common Objective-C usage idioms.

                Manual Reference Counting

                

                Instance variables which are pointers to objects derived from NSObject are presumed to be retained, and should be either commented as weak or declared with the __weak lifetime qualifier when applicable. Similarly, declared properties must specify an assign property attribute if they are not retained by the class. An exception is instance variables labeled as IBOutlets in desktop Mac software, 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 or garbage collection.

                        

                        Examples of strong and weak declarations:

                        

                        @interface MyDelegate : NSObject {

                        @private

                            IBOutlet NSButton *_okButton;  // Normal NSControl; implicitly weak on Mac only

                            

                            AnObjcObject* _doohickey;  // My doohickey

                            __weak MyObjcParent *_parent;  // So we can send msgs back (owns me)

                            

                            // non-NSObject pointers...

                            CWackyCPPClass *_wacky;  // Strong, some cross-platform object

                            CFDictionaryRef *_dict;  // Strong

                        }

        @property(strong, nonatomic) NSString *doohickey;

        @property(weak, nonatomic) NSString *parent;

        @end

        

        

        

        

        Automatic Reference Counting

        

        Object ownership and lifetime are explicit when using ARC, so no additional comments are required.

        

        

        

        Cocoa and Objective-C Features

        

        Instance Variables In Headers Should Be @private

        

        link

        ▽

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

        @interface MyClass : NSObject {

        @private

            id _myInstanceVariable;

        }

        @end

        Identify Designated Initializer

        

        link

        ▽

        Comment and clearly identify your designated initializer.

        It is important for those who might be subclassing your class that the designated initializer be clearly identified. That way, they only need to subclass a single initializer (of potentially several) to guarantee their subclass' initializer is called. It also helps those debugging your class in the future understand the flow of initialization code if they need to step through it.

            

            Override Designated Initializer

            

            link

            ▽

            When writing a subclass that requires an init... method, make sure you override the superclass' designated initializer.

            If you fail to override the superclass' designated initializer, your initializer may not be called in all cases, leading to subtle and very difficult to find bugs.

            

            Overridden NSObject Method Placement

            

            link

            ▽

            It is strongly recommended and typical practice to place overridden methods of NSObject at the top of an @implementation.

            This commonly applies (but is not limited) to the init..., copyWithZone:, and dealloc methods. init... methods should be grouped together, followed by other NSObject methods.

            

            Convenience class methods for creating instances may precede the NSObject methods.

                

                Initialization

                

                link

                ▽

                Don't initialize variables to 0 or nil in the init method; it's redundant.

                All memory for a newly allocated object is initialized to 0 (except for isa), so don't clutter up the init method by re-initializing variables to 0 or nil.

                    

                    Avoid +new

                    

                    link

                    ▽

                    Do not invoke the NSObject class method new, nor override it in a subclass. Instead, use alloc and init methods to instantiate retained objects.

                    Modern Objective-C code explicitly calls alloc and an init method to create and retain an object. As the new class method is rarely used, it makes reviewing code for correct memory management more difficult.

                        

                        Keep the Public API Simple

                        

                        link

                        ▽

                        Keep your class simple; avoid "kitchen-sink" APIs. If a method doesn't need to be public, don't make it so. Use a private category to prevent cluttering the public header.

        Unlike C++, Objective-C doesn't have a way to differentiate between public and private methods—everything is public. 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. For internal implementation methods, use a category defined in the implementation file as opposed to adding them to the public header.

        

#import "GTMFoo.h"

        

        @interface GTMFoo (PrivateDelegateHandling)

        - (NSString *)doSomethingWithDelegate;  // Declare private method

        @end

        

        @implementation GTMFoo (PrivateDelegateHandling)

        ...

        - (NSString *)doSomethingWithDelegate {

            // Implement this method

        }

        ...

        @end

        If you are using Objective-C 2.0, you should instead declare your private category using a class extension, for example:

            

            @interface GMFoo () { ... }

        which will guarantee that the declared methods are implemented in the @implementation section by issuing a compiler warning if they are not.

            

            Again, "private" methods are not really private. You could 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.

            

            Finally, Objective-C categories are a great way to segment a large @implementation section into more understandable chunks and to add new, application-specific functionality to the most appropriate class. For example, instead of adding "middle truncation" code to a random object in your app, make a new category on NSString).

            

#import and #include

            

            link

            ▽

#import Objective-C/Objective-C++ headers, and #include C/C++ headers.

            Choose between #import and #include based on the language of the header that you are including.

            

            When including a header that uses Objective-C or Objective-C++, use #import.

            When including a standard C or C++ header, use #include. The header should provide its own #define guard.

            Some Objective-C headers lack #define guards, and expect to be included only by #import. As Objective-C headers may only be included in Objective-C source files and other Objective-C headers, using #import across the board is appropriate.

            

            Standard C and C++ headers without any Objective-C in them can expect to be included by ordinary C and C++ files. Since there is no #import in standard C or C++, such files will be included by #include in those cases. Using #include for them in Objective-C source files as well means that these headers will always be included with the same semantics.

                

                This rule helps avoid inadvertent errors in cross-platform projects. A Mac developer introducing a new C or C++ header might forget to add #define guards, which would not cause problems on the Mac if the new header were included with #import, but would break builds on other platforms where #include is used. Being consistent by using #include on all platforms means that compilation is more likely to succeed everywhere or fail everywhere, and avoids the frustration of files working only on some platforms.

                    

#import <Cocoa/Cocoa.h>

#include <CoreFoundation/CoreFoundation.h>

#import "GTMFoo.h"

#include "base/basictypes.h"

                    Use Root Frameworks

                    

                    link

                    ▽

                    Include root frameworks over 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 rather than #include for Objective-C frameworks.

                    

#import <Foundation/Foundation.h>     // good

#import <Foundation/NSArray.h>        // avoid

#import <Foundation/NSString.h>

                    ...

                    Prefer To autorelease At Time of Creation

                    

                    link

                    ▽

                    When creating new temporary objects, autorelease them on the same line as you create them rather than a separate release later in the same method.

                    While ever so slightly slower, this prevents someone from accidentally removing the release or inserting a return before it and introducing a memory leak. E.g.:

                    

                    // AVOID (unless you have a compelling performance reason)

                    MyController* controller = [[MyController alloc] init];

        // ... code here that might return ...

        [controller release];

        // BETTER

        MyController* controller = [[[MyController alloc] init] autorelease];

        Autorelease Then Retain

        

        link

        ▽

        Assignment of objects follows the autorelease then retain pattern.

        When assigning a new object to a variable, one must first release the old object to avoid a memory leak. There are several "correct" ways to handle this. We've chosen the "autorelease then retain" approach because it's less prone to error. Be aware in tight loops it can fill up the autorelease pool, and may be slightly less efficient, but we feel the tradeoffs are acceptable.

        

        - (void)setFoo:(GMFoo *)aFoo {

            [_foo autorelease];  // Won't dealloc if |_foo| == |aFoo|

            _foo = [aFoo retain];

        }

        Avoid Accessors During init and dealloc

        

        link

        ▽

        Instance subclasses may be in an inconsistent state during init and dealloc method execution, so code in those methods should avoid invoking accessors.

        Subclasses have not yet been initialized or have already deallocated when init and dealloc methods execute, making accessor methods potentially unreliable. Whenever practical, directly assign to and release ivars in those methods rather than rely on accessors.

        

        - (instancetype)init {

            self = [super init];

            if (self) {

                _bar = [[NSMutableString alloc] init];  // good

            }

            return self;

        }

        

        - (void)dealloc {

            [_bar release];                           // good

            [super dealloc];

        }

        - (instancetype)init {

            self = [super init];

            if (self) {

                self.bar = [NSMutableString string];  // avoid

            }

            return self;

        }

        

        - (void)dealloc {

            self.bar = nil;                         // avoid

            [super dealloc];

        }

        Dealloc Instance Variables in Declaration Order

        

        link

        ▽

        dealloc should process instance variables in the same order the @interface declares them, so it is easier for a reviewer to verify.

            A code reviewer checking a new or revised dealloc implementation needs to make sure that every retained instance variable gets released.

            

            To simplify reviewing dealloc, order the code so that the retained instance variables get released in the same order that they are declared in the @interface. If dealloc invokes other methods that release instance variables, add comments describing what instance variables those methods handle.

            

            Setters copy NSStrings

            

            link

            ▽

            Setters taking an NSString, should always copy the string it accepts.

            Never just retain the string. This avoids the caller changing it under you without your knowledge. Don't assume that because you're accepting an NSString that it's not actually an NSMutableString.

            

            - (void)setFoo:(NSString *)aFoo {

                [_foo autorelease];

                _foo = [aFoo copy];

            }

        Avoid Throwing Exceptions

        

        link

        ▽

        Don't @throw Objective-C exceptions, but you should be prepared to catch them from third-party or OS calls.

        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.

            

            nil Checks

            

            link

            ▽

            Use nil checks for logic flow only.

                Use nil pointer checks for logic flow of the application, not for preventing crashes when sending messages. With current compilers ( as of LLVM 3.0/Xcode 4.2), sending a message to nil reliably returns nil as a pointer, zero as an integer or floating-point value, structs initialized to 0, and _Complex values equal to {0, 0}.

        

        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.

            

            BOOL Pitfalls

            

            link

            ▽

            Be careful when converting general integral values to BOOL. Avoid comparing directly with YES.

            BOOL is defined as a signed char in Objective-C which means that it can 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 which, depending on the value of the last byte of the integral result, could still result in a NO value. When converting a general integral value to a BOOL use ternery 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). You cannot safely interchange BOOL and Boolean so treat Booleans as a general integral value as discussed above. Only 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 ternery operator.

                

                - (BOOL)isBold {

                    return [self fontTraits] & NSFontBoldTrait;

                }

        - (BOOL)isValid {

            return [self stringValue];

        }

        - (BOOL)isBold {

            return ([self fontTraits] & NSFontBoldTrait) ? YES : NO;

        }

        - (BOOL)isValid {

            return [self stringValue] != nil;

        }

        - (BOOL)isEnabled {

            return [self isValid] && [self isBold];

        }

        Also, don't directly compare BOOL variables directly with YES. Not only is it harder to read for those well-versed in C, the first point above demonstrates that return values may not always be what you expect.

        

        BOOL great = [foo isGreat];

        if (great == YES)

            // ...be great!

            BOOL great = [foo isGreat];

        if (great)

            // ...be great!

            Properties

            

            link

            ▽

            Use of the @property directive is preferred, with the following caveat: properties are an Objective-C 2.0 feature which will limit your code to running on the iPhone and Mac OS X 10.5 (Leopard) and higher. Dot notation is allowed only for access to a declared @property.

                Naming

                

                A property's associated instance variable's name must conform to the leading _ requirement. The property's name should be the same as its associated instance variable without the leading _. The optional space between the @property and the opening parenthesis should be omitted, as seen in the examples.

                

                @interface MyClass : NSObject

                @property(copy, nonatomic) NSString *name;

        @end

        

        @implementation MyClass

        // No code required for auto-synthesis, else use:

        //   @synthesize name = _name;

        @end

        

        

        Location

        

        A property's declaration must come immediately after the instance variable block of a class interface. A property's definition (if not using automatic synthesis) must come immediately after the @implementation block in a class definition. They are indented at the same level as the @interface or @implementation statements that they are enclosed in.

        

        @interface MyClass : NSObject {

        @private

            NSString *_name;

        }

        @property(copy, nonatomic) NSString *name;

        @end

        

        @implementation MyClass

        @synthesize name = _name;

        

        - (instancetype)init {

            ...

        }

        @end

        

        

        Use Copy Attribute For Strings

        

        NSString properties should always be declared with the copy attribute.

        

        This logically follows from the requirement that setters for NSStrings always must use copy instead of retain.

            

            

            

            Atomicity

            

            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 nonatomic unless you require atomicity.

            

            

            

            Dot notation

            

            Dot notation is idiomatic style for Objective-C 2.0. It may be used when doing simple operations to get and set a @property of an object, but should not be used to invoke other object behavior.

                

                NSString *oldName = myObject.name;

        myObject.name = @"Alice";

        NSArray *array = [[NSArray arrayWithObject:@"hello"] retain];

        

        NSUInteger numberOfItems = array.count;  // not a property

        array.release;                           // not a property

        

        

        Interfaces Without Instance Variables

        

        link

        ▽

        Omit the empty set of braces on interfaces that do not declare any instance variables.

            @interface MyClass : NSObject

            // Does a lot of stuff

            - (void)fooBarBam;

        @end

        @interface MyClass : NSObject {

        }

        // Does a lot of stuff

        - (void)fooBarBam;

        @end

        Automatically Synthesized Instance Variables

        

        link

        ▽

        Use of automatically synthesized instance variables is preferred. Code that must support earlier versions of the compiler toolchain (Xcode 4.3 or earlier or when compiling with GCC) or is using properties inherited from a protocol should prefer the @synthesize directive.

        

        // Header file

        @protocol Thingy

        @property(nonatomic, copy) NSString *widgetName;

        @end

        

        @interface Foo : NSObject<Thingy>

        // A guy walks into a bar.

        @property(nonatomic, copy) NSString *bar;

        @end

        

        // Implementation file

        @interface Foo ()

        @property(nonatomic, retain) NSArray *baz;

        @end

        

        @implementation Foo

        @synthesize widgetName = _widgetName;

        @end

        Automatically synthesized instance variables take the form of the property's name prefixed with an underscore and so typically conform to the required variable naming style. If your property name is unusual, or you are otherwise unable to use automatically synthesized instance variables, use of the @synthesize directive is preferred, with the instance variable name specified explicitly (as @synthesize does not add a leading underscore by default).

        

        Automatic Reference Counting (ARC)

        

        link

        ▽

        For projects that use Xcode 4.2 or later and will run only on 64-bit Mac OS X 10.7 and iOS 5.0 and later, ARC is preferred. Use manual reference counting when supporting earlier environments where zeroing weak pointers are not available.

        

        Classes that require ARC should include a preprocessor directive to prevent compilation using manual reference counting.

        

        Ownership qualifiers like __unsafe_unretained and __weak should precede variable names. Specifying __strong for variables is not required since it is the default. Properties, on the other hand, should always specify the strong keyword rather than relying on the compiler default.

            

            Files that are compiled using ARC need to have preprocessor directives to prevent compilation without ARC. See the code snippet below for details.

                

                Example of an implementation file enforcing ARC style. Note that declaring instance variables in the @implementation is permitted when using ARC.

                

#if !defined(__has_feature) || !__has_feature(objc_arc)

#error "This file requires ARC support."

#endif

                

#import "Foo.h"

                

                @implementation Foo {

                    Bar* __weak _bar;

                    Baz* __unsafe_unretained _baz;

                }

        // ...

        @end

        

        

        NSNumber Literals

        

        link

        ▽

        For projects that use Xcode 4.4 or later with clang, the use of NSNumber literals is allowed. Note however that this will limit the portability of your code to other toolchains.

        

        NSNumber literals are used just like Objective C string literals. Boxing is used when necessary. Code using NSNumber literals can be deployed on any iOS/MacOS system.

        

        NSNumber *fortyTwo = @42;

        NSNumber *piOverTwo = @(M_PI / 2);

        enum {

            kMyEnum = 2;

        };

        NSNumber *myEnum = @(kMyEnum);

        

        

        Cocoa Patterns

        

        Delegate Pattern

        

        link

        ▽

        Delegate objects should not be retained when doing so would create a retain cycle.

        A class that implements the delegate pattern should typically:

        

        Have an instance variable named _delegate to reference the delegate.

        Thus, the accessor methods should be named delegate and setDelegate:.

        The _delegate object should be weak if the class is typically retained by its delegate, such that a strong delegate would create a retain cycle.

            

            

            Model/View/Controller

            

            link

            ▽

            Separate the model from the view. Separate the controller from the view and the model. Use @protocols for callback APIs.

                

                

                Separate model from view: don't build assumptions about the presentation into the model or data source. Keep the interface between the data source and the presentation abstract. Don't give the model knowledge of its view. (A good rule of thumb is to ask yourself if it's possible to have multiple presentations, with different states, on a single instance of your data source.)

                                                                                                                                                                                                                                               Separate controller from view and model: don't put all of the "business logic" into view-related classes; this makes the code very unusable. Make controller classes to host this code, but ensure that the controller classes don't make too many assumptions about the presentation.

                                                                                                                                                                                                                                               Define callback APIs with @protocol, using @optional if not all the methods are required.

                                                                                                                                                                                                                                               

                                                                                                                                                                                                                                               

                                                                                                                                                                                                                                               Historical Notes

                                                                                                                                                                                                                                               

                                                                                                                                                                                                                                               Trailing vs Leading Underscores

                                                                                                                                                                                                                                               

                                                                                                                                                                                                                                               link

                                                                                                                                                                                                                                               ▽

                                                                                                                                                                                                                                               Trailing underscores were once preferred for instance variable names.

                                                                                                                                                                                                                                               Our style guide used to have a rule saying that instance variables should be named with a trailing underscore, similar to the naming of member variables in C++. This was changed to leading underscores to be consistent with the broader Objective-C community, to better follow Apple's official guidelines, and to allow for use of new compiler features like automatic instance variable synthesis. New projects are strongly encouraged to use leading underscores. Existing projects may continue to use trailing underscores in new code to maintain consistency with the rest of their codebase.

你可能感兴趣的:(Objective-C 编程风格指南)