Objective-C軟件編碼規(guī)范

根據(jù)蘋果官方cocoa的文檔總結(jié)的Objective-C軟件編碼規(guī)范。

1.目的...3

2.適用范圍...3

3.定義...3

4.示例...3

5.代碼布局...5

5.1.間隔與格式化...5

5.2.行長(zhǎng)度...5

5.3.方法聲明與定義...5

5.4.方法...6

5.5.@public和@private.7

5.6.異常...7

5.7.Protocols.7

6.命名...7

6.1.文件命名...8

6.2.Objective-C++.8

6.3.類命名...9

6.4.類別命名...9

6.5.Objective-C方法命名...9

6.6.變量命名...9

6.7.實(shí)體變量...10

6.8.常量...10

7.注釋...10

7.1.聲明注釋...11

7.2.注釋內(nèi)容...11

8.Cocoa和Objective-C特性...11

8.1.成員變量應(yīng)該定義為@private.11

8.2.明確指定初始化...12

8.3.重寫指定初始化...12

8.4.重寫NSObject的方法...12

8.5.避免調(diào)用new方法...12

8.6.初始化變量...12

8.7.保持公有API簡(jiǎn)明...12

8.8.#import和#include.13

8.9.使用根框架...14

8.10.構(gòu)建時(shí)即設(shè)定autorelease.14

8.11.優(yōu)先autorelease而非retain.14

8.12.以聲明時(shí)的順序dealloc處理實(shí)例變量...14

8.13.Setters copyNSStrings.15

8.14.避免拋出異常...15

8.15.nil檢查...16

8.16.BOOL類型陷阱...16

8.17.屬性...17

8.18.為NSString使用Copy屬性...18

1.目的

統(tǒng)一編程風(fēng)格雌贱,提高的可讀性與編碼效率庄新,避免團(tuán)隊(duì)開發(fā)可能帶來的混亂。

2.適用范圍

本規(guī)范適用于公司項(xiàng)目產(chǎn)品運(yùn)用Objective-C作為開發(fā)語言的編碼活動(dòng)澄峰。

3.定義

規(guī)則:編程時(shí)必須遵守的約定

建議:編程時(shí)需要考慮的約定

綠色代碼:對(duì)此規(guī)則或建議給出的正確例子

紅色代碼:對(duì)此規(guī)則或建議給出的反面例子

匈牙利命名法:是一種編程時(shí)的命名規(guī)范嫉沽。基本原則是:變量名=屬性+類型+對(duì)象描述俏竞,其中每一對(duì)象的名稱都要求有明確含義绸硕,可以取對(duì)象名字全稱或名字的一部分

駝峰命名法:就是當(dāng)變量名或函式名是由一個(gè)或多個(gè)單字連結(jié)在一起,而構(gòu)成的唯一識(shí)別字時(shí)魂毁,駝峰命名法第一個(gè)單字以小寫字母開始玻佩;第二個(gè)單字的首字母大寫或每一個(gè)單字的首字母都采用大寫字母

4.示例

先看一個(gè)實(shí)例對(duì)代碼的基本格式有大致了解,可以看到基本的間距席楚,命名等等咬崔。

下例是一份頭文件,展示對(duì)@interface聲明正確的注釋和留間距烦秩。

//GTMFoo.h

//FooProject

//

//Created by Greg Miller on 6/13/08.

//Copyright 2008 Google, Inc. All rightsreserved.

//

#import

// A sample classdemonstrating good Objective-C style. All interfaces,

// categories, andprotocols (read: all top-level declarations in a header)

// MUST becommented. Comments must also be adjacent to the object they're

// documenting.

//

// (no blank linebetween this comment and the interface)

@interface GTMFoo: NSObject {

@private

NSString *foo_;

NSString *bar_;

}

// Returns anautoreleased instance of GMFoo. See -initWithString: for details

// about theargument.

+(id)fooWithString:(NSString *)string;

// Designatedinitializer. |string| will be copied and assigned to |foo_|.

-(id)initWithString:(NSString *)string;

// Gets and setsthe string for |foo_|.

- (NSString *)foo;

-(void)setFoo:(NSString *)newFoo;

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

// successfuly,and NO otherwise.

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

@end

下例是一份源文件垮斯,展示對(duì)接口的@implementation的實(shí)現(xiàn)的正確注釋和留間隔。它也包括了主要方法如getters只祠,setters兜蠕,init和dealloc的相關(guān)實(shí)現(xiàn)。

//

//GTMFoo.m

//FooProject

//

//Created by Greg Miller on 6/13/08.

//Copyright 2008 Google, Inc. All rightsreserved.

//

#import"GTMFoo.h"

@implementationGTMFoo

+(id)fooWithString:(NSString *)string {

return [[[selfalloc] initWithString:string] autorelease];

}

// Must alwaysoverride super's designated initializer.

- (id)init {

return [selfinitWithString:nil];

}

- (id)initWithString:(NSString*)string {

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

foo_ = [stringcopy];

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

}

returnself;

}

- (void)dealloc {

[foo_ release];

[bar_ release];

[super dealloc];

}

- (NSString *)foo{

return foo_;

}

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

[foo_autorelease];

foo_ = [newFoocopy];

}

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

// ...

return NO;

}

@end

5.代碼布局

5.1.間隔與格式化

空格對(duì)tab鍵抛寝,僅使用空格熊杨,縮進(jìn)兩個(gè)。

使用空格用于縮進(jìn)盗舰,不要在編碼時(shí)使用tab鍵猴凹。如果要使用應(yīng)該設(shè)置你的編輯器將tab鍵轉(zhuǎn)換成對(duì)應(yīng)的空格。

5.2.行長(zhǎng)度

代碼中的每行文本不要超過80個(gè)字符的長(zhǎng)度岭皂。

盡管Objective-C正變得比C++更加繁冗郊霎,為了保持規(guī)范的互通性,還是決定保持80字符長(zhǎng)度的限制爷绘。

你可以在Xcode里清楚地發(fā)現(xiàn)代碼中的違規(guī)书劝,設(shè)置Xcode>Preferences>TextEditing>Showpageguide进倍。(之后就可以在代碼編輯區(qū)域里看到一條指定字符長(zhǎng)度的指示線了)

5.3.方法聲明與定義

留一個(gè)空格在-或+和返回類型之間,但參數(shù)列表里的參數(shù)之間不要留間隔购对。

參數(shù)對(duì)象的星號(hào)前需要加空格猾昆。

方法應(yīng)該寫成這樣:

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

...

}

如果參數(shù)過多,推薦每個(gè)參數(shù)各占一行骡苞。使用多行的情況下垂蜗,在參數(shù)前加冒號(hào)用于對(duì)齊:

- (void)doSomethingWith:(GTMFoo *)theFoo

rect:(NSRect)theRect

interval:(float)theInterval {

...

}

當(dāng)?shù)谝粋€(gè)關(guān)鍵字比其他的短時(shí),后續(xù)行至少縮進(jìn)四個(gè)空格解幽。這樣你可以讓后續(xù)的關(guān)鍵字垂直對(duì)齊贴见,而不是用冒號(hào)對(duì)齊:

- (void)short:(GTMFoo *)theFoo

longKeyword:(NSRect)theRect

evenLongerKeyword:(float)theInterval {

...

}

5.4.方法

方法調(diào)用的格式和方法聲明時(shí)的格式時(shí)一致的,如果格式風(fēng)格可選躲株,遵從原有代碼的風(fēng)格片部。

調(diào)用應(yīng)該將所有參數(shù)寫在一行:

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

或者每個(gè)參數(shù)一行,用冒號(hào)對(duì)齊(對(duì)齊效果如前說明):

[myObject doFooWith:arg1

name:arg2

error:arg3];

不要使用如下風(fēng)格的寫法:

[myObjectdoFooWith:arg1 name:arg2// some lineswith >1 arg

error:arg3];

[myObjectdoFooWith:arg1

name:arg2 error:arg3];

[myObjectdoFooWith:arg1

name:arg2// aligning keywords instead of colons

error:arg3];

在聲明和定義時(shí)霜定,如果因?yàn)殛P(guān)鍵字長(zhǎng)度使就算有四個(gè)空格在前仍然無法用冒號(hào)對(duì)齊档悠,那么就讓后續(xù)行縮進(jìn)四個(gè)空格而不是冒號(hào)對(duì)齊:

[myObj short:arg1

longKeyword:arg2

evenLongerKeyword:arg3];

5.5.@public和@private

權(quán)限控制符@public和@private縮進(jìn)一個(gè)空格:

@interface MyClass : NSObject {

@public

...

@private

...

}

@end

5.6.異常

每個(gè)異常標(biāo)簽的@和開括號(hào)({)寫在統(tǒng)一行,標(biāo)簽和開括號(hào)間隔一個(gè)空格望浩,同樣適用于@catch語句辖所。

@interface MyClass : NSObject {

@public

...

@private

...

}

@end

5.7.Protocols

在類型定義和被中括號(hào)括起來的Protocols名稱之間不需要空格。

本規(guī)矩適用于類定義磨德,變量聲明和方法聲明時(shí)使用缘回。參考代碼:

@interface MyProtocoledClass :NSObject {

@private

id delegate_;

}

- (void)setDelegate:(id)aDelegate;

@end

6.命名

所有類,類別剖张,方法,以及變量如包括縮寫揩环,則縮寫部分使用全大寫的縮寫(Initialisms)形式搔弄。這遵守Apple的標(biāo)準(zhǔn),比如URL丰滑,TIFF以及EXIF顾犹。

當(dāng)寫Objective-C++代碼時(shí),情況就不是那么單一了褒墨。許多項(xiàng)目需要實(shí)現(xiàn)帶一些Objective-C代碼的跨平臺(tái)的C++APIs或者連接后臺(tái)的C++代碼與前臺(tái)的原生Cocoa代碼炫刷,這會(huì)造成兩種規(guī)范直接沖突。

解決方法是根據(jù)方法/函數(shù)風(fēng)格來決定郁妈。如果在@implementation塊浑玛,就使用Objective-C的命名規(guī)則;如果在C++的方法實(shí)現(xiàn)塊噩咪,就使用C++的命名規(guī)則顾彰。避免了實(shí)體變量和本地變量在一個(gè)函數(shù)內(nèi)命名規(guī)則沖突的情況极阅,而這種情況是對(duì)可讀性的極大損害。

6.1.文件命名

文件名反映了它所包含的實(shí)現(xiàn)類的名字涨享,遵從你所在項(xiàng)目的習(xí)慣筋搏。

文件擴(kuò)展名使用如下規(guī)則

.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

類別的文件名應(yīng)該包含擴(kuò)展類的名字,比如GTMNSString+Utils.h or

GTMNSTextView+Autocomplete.h厕隧。

6.2.Objective-C++

在一份源文件里奔脐,Objective-C++代碼遵守當(dāng)前方法/函數(shù)的風(fēng)格

為了盡量減少不同命名風(fēng)格間的沖突,使用當(dāng)前方法的風(fēng)格吁讨。如果在@implementation塊髓迎,使用Objective-C命名規(guī)則,如果在C++類的函數(shù)實(shí)現(xiàn)塊挡爵,使用C++命名規(guī)則竖般。

// file: cross_platform_header.h

class CrossPlatformAPI {

public:

...

intDoSomethingPlatformSpecific();// implon each platform

private:

intan_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 fromCocoa through our C++ backend

instanceVar_ =backEndObject->DoSomethingPlatformSpecific();

NSString*tempString = [NSString stringWithInt:instanceVar_];

NSLog(@"%@", tempString);

}

@end

// The platform-specific implementation of the C++ class,using

// C++ naming.

int CrossPlatformAPI::DoSomethingPlatformSpecific() {

NSString*temp_string = [NSString stringWithInt:an_instance_var_];

NSLog(@"%@", temp_string);

return[temp_string intValue];

}

6.3.類命名

類名(不包括類別和協(xié)議名)應(yīng)該用大寫開頭的駝峰命名法。

在應(yīng)用級(jí)別的代碼里茶鹃,盡量不要使用帶前綴的類名涣雕。每個(gè)類都有相同的前綴不能提高可讀性。不過如果是編寫多個(gè)應(yīng)用間的共享代碼闭翩,前綴就是可接受并推薦的做法了(型如GTMSendMessage)挣郭。

6.4.類別命名

類別命名應(yīng)該以兩三個(gè)字符的分類前綴作為一個(gè)項(xiàng)目或通用的公用部分。類別名應(yīng)該包含類的擴(kuò)展疗韵。

舉個(gè)例子兑障,如果我們想要?jiǎng)?chuàng)建一個(gè)基于NSString的類別用于解析,我們應(yīng)該把類別放到名字是GTMNSString+Parsing.h的文件里蕉汪,而類別本身的名字則是GTMStringParsingAdditions(是的流译,我們明白這個(gè)類別和其文件名字不匹配,但這個(gè)文件可能還包括其他用于解析相關(guān)的類別)者疤。類別的方法應(yīng)該都使用一個(gè)前綴(型如gtm_myCategoryMethodOnAString)福澡,以防止Objective-C代碼在單名空間里沖突。如果代碼本來就不考慮共享或在不同的地址空間(address-space)驹马,方法命名規(guī)則就沒必要恪守了革砸。

6.5.Objective-C方法命名

方法使用小寫開頭的駝峰法命名,每個(gè)參數(shù)都應(yīng)該小寫開頭糯累。

方法名應(yīng)該盡可能讀起來像一句話算利,參數(shù)名就相對(duì)方法名的補(bǔ)充說明(比如convertPoing:fromRect:或者replaceCharactersInRange:withString:)。

存取(Accessor)方法應(yīng)該一致的在"取(getting)"的時(shí)候直接用變量名而不是在簽名加"get"泳姐,如下:

- (id)getDelegate;// AVOID

- (id)delegate;// GOOD

不過這僅針對(duì)Objective-C代碼效拭,C++代碼仍然遵循自己的代碼規(guī)范。

6.6.變量命名

變量名使用小寫開頭的駝峰法,類成員變量名最后加一個(gè)下劃線允耿,比如:myLovalVariable借笙,myInstanceVariable_。

不要使用匈牙利命名法去標(biāo)記語法较锡,比如靜態(tài)類型或變量類型(int或pointer之類的)业稼。使變量名盡量可以推測(cè)其用途屬性具有描述性。別一心想著少打幾個(gè)字母蚂蕴,讓你的代碼可以迅速被理解更加重要低散。比如:

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

6.7.實(shí)體變量

實(shí)體變量用駝峰法命名并后綴下劃線,就像usernameTextField_骡楼。允許一種例外就是用KVO/KVC去綁定一個(gè)實(shí)體變量而Objective-C2.0不能用(因?yàn)椴僮飨到y(tǒng)的限制)的情況熔号,此時(shí)也可用前綴下劃線的方法給每個(gè)變量命名。如果可以使用Objective-C2.0鸟整,@property和@synthesize提供了遵守命名規(guī)范的解決方法引镊。

6.8.常量

常量(預(yù)定義,枚舉篮条,局部常量等)使用小寫k開頭的駝峰法弟头,比如kInvalidHandle,kWritePerm涉茧。

7.注釋

注釋是使代碼保持可讀性的極端重要的方式赴恨。下面的條款描述了你應(yīng)該注釋什么以及在哪里做注釋。但是記住:即使注釋是如此重要伴栓,最好的代碼還是自說明式的伦连。起一個(gè)有意義的名字比起一個(gè)晦澀的名字然后在用注釋去解釋它好的多。

寫注釋的時(shí)候钳垮,記住注釋是寫給讀者惑淳,即下一個(gè)要理解你的代碼并繼續(xù)開發(fā)的人。"下一個(gè)"完全可能就是你自己饺窿。

同樣歧焦,所有C++編程規(guī)范的條款仍然適用,只是增加了一些條款短荐,如下:

文件注釋:

每個(gè)文件的開頭都是版權(quán)聲明倚舀,接著是文件內(nèi)容的描述叹哭。

法律聲明和作者欄:

每個(gè)文件都必須包含如下信息:

本文件內(nèi)容描述和作者欄

如果你把別人寫的文件做了相當(dāng)大的改動(dòng)忍宋,就把自己添加到作者欄去。這樣別的開發(fā)者就方便聯(lián)系這個(gè)文件的實(shí)際開發(fā)人員了风罩。

7.1.聲明注釋

每個(gè)接口糠排,類別,協(xié)議都必須伴隨描述它的用途以及如何整合的注釋超升。

// A delegate for NSApplication to handle notificationsabout app

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

@interface MyAppDelegate : NSObject {

...

}

@end

如果已經(jīng)在文件的頂部寫了接口的詳細(xì)描述入宦,你也可以簡(jiǎn)單的寫如"見文件頂部的完整描述"哺徊,當(dāng)然要有這些注釋的順序安排。

此外public接口的每個(gè)方法都應(yīng)該添加關(guān)于函數(shù)乾闰,參數(shù)落追,返回值以及副作用的注釋。

文檔默認(rèn)類都是同步的涯肩,如果類實(shí)例可以多線程訪問轿钠,必須要加上額外的說明。

7.2.注釋內(nèi)容

使用豎線引用變量或符號(hào)病苗,而不是用引號(hào)疗垛。

這可以減少歧義,特別是當(dāng)符號(hào)本身就是個(gè)常見的詞時(shí)硫朦,可能使句子顯得支離破碎贷腕,比如符號(hào)是"count":

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

或者是對(duì)于那些已經(jīng)存在引號(hào)的情況:

// Remember to call |StringWithoutSpaces("foo barbaz")|

8.CocoaObjective-C特性

8.1.成員變量應(yīng)該定義為@private

參考代碼:

@interface MyClass : NSObject {

@private

idmyInstanceVariable_;

}

// public accessors, setter takes ownership

- (id)myInstanceVariable;

- (void)setMyInstanceVariable:(id)theVar;

@end

8.2.明確指定初始化

注釋并說明指定的初始化。

明確指定初始化對(duì)想要子類化你的類的時(shí)候時(shí)很重要的咬展。那樣泽裳,子類化時(shí)只需要做一個(gè)或多個(gè)初始化去保證初值即可。這也有助于在以后調(diào)試你的類時(shí)明了初始化流程挚赊。

8.3.重寫指定初始化

當(dāng)重寫一個(gè)子類并需要init...方法诡壁,注意要重寫父類的指定初始化方法。

如果你沒有正確重寫父類的指定初始化方法荠割,你的初始化方法可能不會(huì)被調(diào)用妹卿,這會(huì)導(dǎo)致很多微妙而難以排除的錯(cuò)誤。

8.4.重寫NSObject的方法

強(qiáng)烈建議在@implementation之后就立即重寫NSObject的方法蔑鹦。建議重寫init...夺克,copyWithZone:和dealloc方法。init...相關(guān)的方法寫在一起嚎朽,接下來是copyWithZone:铺纽,最后是dealloc。

8.5.避免調(diào)用new方法

不要調(diào)用NSObject的new方法哟忍,也不要在子類中重寫它狡门,而是應(yīng)該使用alloc和init方法來初始化retained的對(duì)象。

Objective-C代碼顯式調(diào)用alloc和init方法來創(chuàng)建和retain一個(gè)對(duì)象锅很。new的方法可能會(huì)帶來內(nèi)存上調(diào)試的麻煩其馏。

8.6.初始化變量

沒必要在初始化方法里把變量初始化為0或者nil,這是多余的爆安。

所有新分配內(nèi)存的對(duì)象內(nèi)容都初始化為0(除了isa)叛复,所以不要在init方法里做無謂的重初始化為0的操作。

8.7.保持公有API簡(jiǎn)明

保持你的類簡(jiǎn)單,如果一個(gè)方法沒必要公開就不要公開褐奥。使用私有類別保證公開頭文件的簡(jiǎn)潔咖耘。

和C++不同,Objective-C無法區(qū)分公有私有方法撬码,因?yàn)樗枪械亩埂R虼耍蔷褪菫榱俗層脩粽{(diào)用所設(shè)計(jì)呜笑,不要把其他的方法放到公有API里义桂。這樣可以減少不期調(diào)用的可能性。這還包括重寫父類的方法蹈垢。對(duì)于那些內(nèi)部實(shí)現(xiàn)的方法慷吊,在實(shí)現(xiàn)文件里使用類別而不是將方法定義在公有頭文件里。

// GTMFoo.m

#import "GTMFoo.h"

@interface GTMFoo (PrivateDelegateHandling)

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

@end

@implementation GTMFoo(PrivateDelegateHandling)

...

- (NSString *)doSomethingWithDelegate {

// Implement thismethod

}

...

@end

8.8.#import#include

用#import導(dǎo)入Objective-C或Objective-C++頭文件曹抬,用#include導(dǎo)入C或C++頭文件

根據(jù)頭文件的語言去選擇合適的導(dǎo)入方式溉瓶。

當(dāng)導(dǎo)入的頭文件使用Objective-C或Objective-C++語言時(shí),使用#import谤民。

當(dāng)導(dǎo)入標(biāo)準(zhǔn)C或C++頭文件時(shí)堰酿,使用#include。頭文件應(yīng)該使用自己的#define重加載保護(hù)张足。

有些Objective-C頭文件沒有#define重加載保護(hù)触创,所以只應(yīng)該用#import導(dǎo)入。因此Objective-C頭文件只應(yīng)該被Objective-C源文件或其他的Objective-C頭文件所導(dǎo)入为牍。這種情況下全部使用#import是合適的哼绑。

標(biāo)準(zhǔn)C和C++頭文件不包含任何Objective-C元素都可以被一般的C或C++文件導(dǎo)入。因?yàn)闃?biāo)準(zhǔn)C和C++里根本沒有#import碉咆,所以也只能用#include導(dǎo)入抖韩。在Objective-C代碼中使用#include一致的導(dǎo)入這些頭文件。

本條款有助于跨平臺(tái)項(xiàng)目的無意錯(cuò)誤疫铜。一位Mac開發(fā)者引入一份新C或C++頭文件時(shí)可能會(huì)忘記添加#define重加載保護(hù)茂浮,因?yàn)樵贛ac上用#import導(dǎo)入文件不會(huì)引發(fā)問題,但在別的使用#include的平臺(tái)就可能出問題壳咕。在所有平臺(tái)一致的使用#include意味著要么全部成功要么全部失敗席揽,避免了那種一些平臺(tái)上可以運(yùn)作而另一些不行的情況。

#import

#include

#import "GTMFoo.h"

#include "base/basictypes.h"

8.9.使用根框架

導(dǎo)入框架根的頭文件而不是分別導(dǎo)入框架頭文件

看起來從Cocoa或Foundation這些框架里導(dǎo)入個(gè)別的文件很不錯(cuò)谓厘,但實(shí)際上你直接導(dǎo)入框架根頭文件效率更高幌羞。框架根已經(jīng)被預(yù)編譯故可更快的被加載庞呕。還有新翎,記住用#import指令而不是#include導(dǎo)入Objective-C的框架。

#import // good

#import // avoid

#import

...

8.10.構(gòu)建時(shí)即設(shè)定autorelease

當(dāng)創(chuàng)建新的臨時(shí)對(duì)象時(shí)住练,在同一行代碼里就設(shè)定autorelease而不是寫到這個(gè)方法的后面幾行去

即使這樣可能會(huì)造成一些輕微的延遲地啰,但這樣避免了誰不小心把release去掉,或在release之前就return而造成的內(nèi)存泄露讲逛,如下:

// AVOID (unless you have a compelling performancereason)

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

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

[controller release];

// BETTER

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

8.11.優(yōu)先autorelease而非retain

對(duì)象賦值時(shí)盡量采用autorelease而不是retian模式亏吝。

當(dāng)把一個(gè)新創(chuàng)建的對(duì)象賦予一個(gè)變量的時(shí)候,第一件要做的事情就是先釋放原來變量指向的對(duì)象以防止內(nèi)存泄露盏混。這里也有很多"正確的"方法去做這件事蔚鸥。我們選擇autorelease時(shí)因?yàn)樗粌A向于出錯(cuò)。小心在密集的循環(huán)里可能會(huì)很快填滿autorelease池许赃,而且它也確實(shí)會(huì)降低效率止喷,但權(quán)衡下來還是可以接受的。

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

[foo_autorelease];// Won't dealloc if |foo_|== |aFoo|

foo_ = [aFooretain];

}

8.12.以聲明時(shí)的順序dealloc處理實(shí)例變量

dealloc應(yīng)該用在@interface聲明時(shí)同樣的順序處理實(shí)例變量混聊,這也有助于評(píng)審者鑒別弹谁。

代碼評(píng)審者檢查或修正dealloc的實(shí)現(xiàn)要確保所有retain的實(shí)例變量都獲得了釋放。

為了簡(jiǎn)化評(píng)審dealloc句喜,將釋放retain的實(shí)例變量代碼保持和@interface里聲明的順序一致预愤。如果dealloc調(diào)用了其他方法去釋放實(shí)例變量,添加注釋說明那些實(shí)例變量被這些方法所處理了咳胃。

8.13.Setters copy

NSStrings

在NSString上調(diào)用Setters方法時(shí)植康,永遠(yuǎn)使用copy方式。永遠(yuǎn)不要retain一個(gè)字符串展懈,這可以防止調(diào)用者在你不知到的情況下修改了字符串销睁。不要以為你可以改變NSString的值,只有NSMutableString才能做到存崖。

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

[foo_autorelease];

foo_ = [aFoocopy];

}

8.14.避免拋出異常

不要@throwObjective-C的異常榄攀,不過你還是要做好準(zhǔn)備捕獲第三方以及系統(tǒng)調(diào)用拋出的異常。

我們的確在編譯時(shí)加入了-fobjc-exceptions指令(主要是為了獲得@synchronized)金句,但我們并不@throw檩赢。當(dāng)然在使用第三方庫(kù)的時(shí)候是允許使用@try,@catch违寞,以及@finally的贞瞒。如果你確實(shí)使用了,請(qǐng)務(wù)必明確到文檔中哪個(gè)方向你想拋出什么異常趁曼。

除非你寫的代碼想要泡在MacOS10.2或更之前军浆,否則不要使用NS_DURING,NS_HANDLER挡闰,NS_ENDHANDLER乒融,NS_VALUERETURNandNS_VOIDRETURN這些宏掰盘。

另外你要小心當(dāng)寫Objective-C++代碼的時(shí)候,如果拋出Objective-C異常赞季,那些棧上的對(duì)象不會(huì)被清理愧捕。示例:

class exceptiontest {

public:

exceptiontest() {NSLog(@"Created"); }

~exceptiontest(){ NSLog(@"Destroyed"); }

};

void foo() {

exceptiontest a;

NSException*exception = [NSException exceptionWithName:@"foo"

reason:@"bar"

userInfo:nil];

@throw exception;

}

int main(int argc, char *argv[]) {

GMAutoreleasePoolpool;

@try {

foo();

}

@catch(NSException *ex) {

NSLog(@"exception raised");

}

return 0;

}

將會(huì)有如下輸出:

2006-09-28 12:34:29.244 exceptiontest[23661] Created

2006-09-28 12:34:29.244 exceptiontest[23661] exceptionraised

注意這里的析構(gòu)函數(shù)永遠(yuǎn)沒有機(jī)會(huì)被調(diào)用。這是在你想用棧上的智能指針比如shared_ptr申钩,linked_ptr次绘,還有STL對(duì)象的時(shí)候不得不關(guān)注的一個(gè)核心問題。如果你一定要在Objective-C++代碼里拋出異常撒遣,那就請(qǐng)一定使用C++的異常邮偎。永遠(yuǎn)不要重新拋出一個(gè)Objective-C的異常,也不允許在異常塊即@try义黎,@catch禾进,@finally里生成棧上的C++對(duì)象(比如std::string,std::vector等)廉涕。

8.15.nil檢查

僅在校驗(yàn)邏輯流程時(shí)做nil檢查命迈。

使用nil檢查不是為了防止程序崩潰,而是校驗(yàn)邏輯流程火的。向一個(gè)空對(duì)象發(fā)送一條消息是由Objective-C運(yùn)行時(shí)處理的壶愤。方法沒有返回結(jié)果,你也可以安心走下去馏鹤。

注意這里和C/C++的空指針檢查是完全不同的征椒,在那些環(huán)境里,并不處理空指針情況并可能導(dǎo)致你的應(yīng)用程序崩潰湃累。不過你仍要自己確保提領(lǐng)的指針不為空勃救。

8.16.BOOL類型陷阱

整形的轉(zhuǎn)換為BOOL型的時(shí)候要小心。不要直接和YES做比較治力。

BOOL在Objective-C里被定義為unsignedchar蒙秒,這意味著它不僅僅只有YES(1)和NO(0)兩個(gè)值。不要直接把整形強(qiáng)制轉(zhuǎn)換為BOOL型宵统。常見的錯(cuò)誤發(fā)生在把數(shù)組大小晕讲,指針的值或者邏輯位運(yùn)算的結(jié)果賦值到BOOL型中,而這樣就導(dǎo)致BOOL值的僅取決于之前整形值的最后一個(gè)字節(jié)马澈,有可能出現(xiàn)整形值不為0但被轉(zhuǎn)為NO的情況瓢省。應(yīng)此把整形轉(zhuǎn)為BOOL型的時(shí)候請(qǐng)使用ternery操作符,保證返回YES或NO值痊班。

在BOOL勤婚,_BOOL以及bool(見C++Std4.7.4,4.12以及C99Std6.3.1.2)之間可以安全的交換值或轉(zhuǎn)型涤伐。但BOOL和Boolean之間不可馒胆,所以對(duì)待Boolean就像上面講的整形一樣就可以了缨称。在Objective-C函數(shù)簽名里僅使用BOOL。

對(duì)BOOL值使用邏輯運(yùn)算(&&祝迂,||睦尽,!)都是有效的,返回值也可以安全的轉(zhuǎn)為BOOL型而不需要ternery操作符液兽。

- (BOOL)isBold {

return [selffontTraits] & NSFontBoldTrait;

}

- (BOOL)isValid {

return [selfstringValue];

}

- (BOOL)isBold {

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

}

- (BOOL)isValid {

return [selfstringValue] != nil;

}

- (BOOL)isEnabled {

return [selfisValid] && [self isBold];

}

還有,不要把BOOL型變量直接與YES比較掌动。這樣不僅對(duì)于精通C的人很有難度四啰,而且此條款的第一點(diǎn)也說明了這樣做未必能得到你想要的結(jié)果。

BOOL great = [foo isGreat];

if (great == YES)

// ...be great!

BOOL great = [foo isGreat];

if (great)

// ...be great!

8.17.屬性

屬性遵循如下規(guī)則:屬性是Objective-C2.0的特性粗恢,所以只能跑在iPhone以及MacOSX10.5(leopard)或更高的版本柑晒。

一個(gè)有屬性關(guān)聯(lián)實(shí)例變量都要在后面加下劃線,而該屬性的名稱就是實(shí)例變量不加尾部的下劃線的名字眷射。

使用@synthesize標(biāo)識(shí)以正確的重命名屬性匙赞。

@interface MyClass : NSObject {

@private

NSString *name_;

}

@property(copy, nonatomic) NSString *name;

@end

@implementation MyClass

@synthesize name = name_;

@end

屬性的聲明必須緊接變量申明的括號(hào)后。屬性的定義應(yīng)該緊接@implementation模塊后面妖碉。它和@interface或者@implementation的縮進(jìn)是相同的涌庭。

@interface MyClass : NSObject {

@private

NSString *name_;

}

@property(copy, nonatomic) NSString *name;

@end

@implementation MyClass

@synthesize name = name_;

- (id)init {

...

}

@end

8.18.為NSString使用Copy屬性

NSString的屬性定義為copy。

如果自己實(shí)現(xiàn)setters方法欧宜,也請(qǐng)使用copy而不是retain坐榆。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市冗茸,隨后出現(xiàn)的幾起案子席镀,更是在濱河造成了極大的恐慌,老刑警劉巖夏漱,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件豪诲,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡挂绰,警方通過查閱死者的電腦和手機(jī)屎篱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來葵蒂,“玉大人芳室,你說我怎么就攤上這事∩膊” “怎么了堪侯?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)荔仁。 經(jīng)常有香客問我伍宦,道長(zhǎng)芽死,這世上最難降的妖魔是什么册赛? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任阳懂,我火速辦了婚禮觅捆,結(jié)果婚禮上阻塑,老公的妹妹穿的比我還像新娘泼橘。我一直安慰自己民晒,他們只是感情好尾序,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布悯许。 她就那樣靜靜地躺著亥啦,像睡著了一般炭剪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上翔脱,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天奴拦,我揣著相機(jī)與錄音,去河邊找鬼届吁。 笑死错妖,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的疚沐。 我是一名探鬼主播暂氯,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼亮蛔!你這毒婦竟也來了株旷?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤尔邓,失蹤者是張志新(化名)和其女友劉穎晾剖,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體梯嗽,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡齿尽,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了灯节。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片循头。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖炎疆,靈堂內(nèi)的尸體忽然破棺而出卡骂,到底是詐尸還是另有隱情,我是刑警寧澤形入,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布全跨,位于F島的核電站,受9級(jí)特大地震影響亿遂,放射性物質(zhì)發(fā)生泄漏浓若。R本人自食惡果不足惜渺杉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望挪钓。 院中可真熱鬧是越,春花似錦、人聲如沸碌上。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽馏予。三九已至天梧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間吗蚌,已是汗流浹背腿倚。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工纯出, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蚯妇,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓暂筝,卻偏偏與公主長(zhǎng)得像箩言,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子焕襟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容