iOS 代碼規(guī)范

命名規(guī)范

????總的來(lái)說(shuō), iOS命名兩大原則是:可讀性高和防止命名沖突(通過加前綴來(lái)保證). Objective-C 的命名通常都比較長(zhǎng), 名稱遵循駝峰式命名法. 一個(gè)好的命名標(biāo)準(zhǔn)很簡(jiǎn)單, 就是做到在開發(fā)者一看到名字時(shí), 就能夠懂得它的含義和使用方法. 另外, 每個(gè)模塊都要加上自己的前綴, 前綴在編程接口中非常重要, 可以區(qū)分軟件的功能范疇并防止不同文件或者類之間命名發(fā)生沖突。

1). 常量的命名

????對(duì)于常量的命名最好在前面加上字母k作為標(biāo)記. 如:

static const NSTimeInterval kAnimationDuration = 0.5;

Tips:

????I. 若常量作用域超出編譯單元(實(shí)現(xiàn)文件), 需要在類外可見時(shí), 使用extern關(guān)鍵字, 并加上該類名作為前綴. 如 extern NSString *const PGThumbnailSize

????II.全局常量(通知或者關(guān)鍵字等)盡量用const來(lái)定義. 因?yàn)槿绻褂煤甓x, 一來(lái)宏可能被重定義. 二來(lái)引用不同的文件可能會(huì)導(dǎo)致宏的不同.

2). 枚舉的命名

????對(duì)于枚舉類型, 經(jīng)常會(huì)看到之前的C的,對(duì)與oc來(lái)說(shuō)是可以兼容c 的所以不會(huì)有問題定義方式:

typedef enum : {

     CameraModeFront,

     CameraModeLeft,

     CameraModeRight,

} CameraMode;

????上面定義枚舉的方法不能指定底層數(shù)據(jù)類型,所以沒有辦法向前聲明枚舉類型,因?yàn)榫幾g器不清楚底層數(shù)據(jù)類型的大小,用到枚舉類型時(shí),頁(yè)就不知道究竟該給變量分配多少空間。 那Objective-C定義枚舉如下:

typedef NS_ENUM(NSInteger, UIViewAnimationTransition) {

      UIViewAnimationTransitionNone,

      UIViewAnimationTransitionFlipFromLeft,

      UIViewAnimationTransitionFlipFromRight,

      UIViewAnimationTransitionCurlUp,

      UIViewAnimationTransitionCurlDown,

};

????這邊需要注意的是: 枚舉類型命名要加相關(guān)類名前綴并且枚舉值命名要加枚舉類型前綴.

3). 變量和對(duì)象的命名

????給一個(gè)對(duì)象命名時(shí)建議采用修飾+類型的方式. 如果只用修飾命名會(huì)引起歧義, 比如title ,不能看出來(lái)這個(gè)是什么樣的類型,可讀性極差. 正確的命名方式為:

????titleLabel //表示標(biāo)題的label, 是UILabel類型

????cancelButton //表示取消的button, 是UIButton類型

????對(duì)于BOOL類型, 應(yīng)加上is前綴, 比如- (BOOL)isEqualToString:(NSString *)aString這樣會(huì)更加清晰. 如果某方法返回非屬性的 BOOL 值, 那么應(yīng)根據(jù)其功能, 選用 has 或 is 當(dāng)前綴, 如- (BOOL)hasPrefix:(NSString *)aString

Tip:如果某個(gè)命名已經(jīng)很明確了, 為了簡(jiǎn)潔可以省去類型名. 比如scores, 很明顯是個(gè)array了, 就不必命名成scoreArray了

編碼規(guī)范

????編碼規(guī)范簡(jiǎn)單來(lái)說(shuō)就是為了保證寫出來(lái)的代碼具備三個(gè)原則:可復(fù)用, 易維護(hù), 可擴(kuò)展. 這其實(shí)也是面向?qū)ο蟮幕驹瓌t. 可復(fù)用, 簡(jiǎn)單來(lái)說(shuō)就是不要寫重復(fù)的代碼, 有重復(fù)的部分要盡量封裝起來(lái)重用. 易維護(hù), 就是不要把代碼復(fù)雜化, 不要去寫巨復(fù)雜邏輯的代碼, 而是把復(fù)雜的邏輯代碼拆分開一個(gè)個(gè)小的模塊, 每個(gè)模塊(或者函數(shù))職責(zé)要單一, 這樣的代碼會(huì)易于維護(hù), 也不容易出錯(cuò). 可擴(kuò)展則是要求寫代碼時(shí)要考慮后面的擴(kuò)展需求, 這個(gè)屬于架構(gòu)層面的東西, 利用對(duì)應(yīng)的設(shè)計(jì)模式來(lái)保證。

1). 判斷nil或者YES/NO

正確寫法:

if (someObject) { ... }

if (!someObject) { ... }

錯(cuò)誤寫法:

if (someObject == YES) { ...}

if (someObject != nil) { ...}

if (someObject == YES)容易誤寫成賦值語(yǔ)句if (someObject = YES)這樣在開發(fā)的過程中不好被發(fā)現(xiàn),造成時(shí)間的浪費(fèi)

2). 條件賦值

正確寫法

result = object ? : [self createObject];

錯(cuò)誤寫法:

result = object ? object : [self createObject];

????如果是存在就賦值本身, 那就可以這樣

3). 初始化方法

正確寫法:

NSArray *animals = @[@"cat", @"dog", @"mouse", @"badger"];

NSDictionary *personData = @{@"Matt" : @"firstName", @"Galloway" : @"lastName"};

錯(cuò)誤寫法:

NSArray *names =  [NSArray arrayWithObjects:@"cat", @"dog", @"mouse", @"badger",nil];

NSDictionary *personData = [NSDictionarydictionaryWithObjectsAndKeys:@"Matt" : @"firstName", @"Galloway" : @"lastName",nil];

????第一個(gè)好處還是簡(jiǎn)潔, 第二個(gè)好處是可以防止初始化進(jìn)去nil值造成crash,所以要多用字面量語(yǔ)法,雖然字面量語(yǔ)法有個(gè)小小的限制,就是除了字符串以外,所創(chuàng)建出來(lái)的對(duì)象必須屬于Foundation框架才行,如果自定義了這些類的子類,就無(wú)法用字面量語(yǔ)法實(shí)例化,但是一般也用不到自定義這種類的子類,整體還是有點(diǎn)大于缺點(diǎn)。

4). 定義屬性

正確寫法:

@property (nonatomic, readwrite, copy) NSString *name;

????蘋果官網(wǎng)上說(shuō)atomic可以保證線程的安全,因?yàn)樵趦?nèi)部實(shí)現(xiàn)了鎖的機(jī)制,但是并沒有什么用,并不能保證線程安全,還消耗了性能,所以應(yīng)該用nonatomic。
在.h文件中應(yīng)該將屬性定義成readonly,然后將這個(gè)屬性在.m文件中再次定義成readwrite,這樣外部只能通過set和get方法進(jìn)行操作屬性,使其更加安全。
對(duì)于擁有Mutable子類型的對(duì)象(e.g. NSString, NSArray, NSDictionary)一定要定義成copy屬性. Why? 示例: NSArray的array = NSMutableArray的mArray; 如果mArray在某個(gè)地方改變了, 那array也會(huì)跟著改變.
盡量不要暴露mutable類型的對(duì)象在public interface, 建議在.h定義一個(gè)Inmutable類型的屬性, 然后在.m的get函數(shù)里面返回一個(gè)內(nèi)部定義的mutable變量.

5). BOOL賦值

正確寫法:

BOOL isAdult = age > 18;

錯(cuò)誤寫法:

BOOL isAdult;

if (age > 18)

{

      isAdult = YES;

}

else

{

      isAdult = NO;

}

????明顯的可以看出第一種的寫法簡(jiǎn)練,易讀,邏輯性強(qiáng)

6) 拒絕死值

正確寫法:

if (car == Car.Nissan)

or

const int adultAge = 18; if (age > adultAge) { ... }

錯(cuò)誤寫法:

if (carName == "Nissan")

or

if (age > 18) { ... }

????應(yīng)該將這種值都提出去,每次要改變其值,只要改變定義的就可以了,降低了出現(xiàn)難以尋找,忘記更改造成的錯(cuò)誤。

7). 復(fù)雜的條件判斷

正確寫法:

if ([self canDeleteJob:job]) { ... }

- (BOOL)canDeleteJob:(Job *)job

{

      BOOL invalidJobState = job.JobState == JobState.New || job.JobState == JobState.Submitted || job.JobState == JobState.Expired;

      BOOL invalidJob = job.JobTitle && job.JobTitle.length;

      return invalidJobState || invalidJob;

}

錯(cuò)誤寫法:

if (job.JobState == JobState.New || job.JobState == JobState.Submitted || job.JobState == JobState.Expired || (job.JobTitle && job.JobTitle.length))

{

//....

}

8). 嵌套判斷

正確寫法:

if (!user.UserName) return NO;

if (!user.Password) return NO;

if (!user.Email) return NO;

return YES;

錯(cuò)誤寫法:

BOOL isValid = NO;

if (user.UserName)

{

      if (user.Password)

      {

            if (user.Email) isValid = YES;

      }

}

return isValid;

????一旦發(fā)現(xiàn)某個(gè)條件不符合, 立即返回,條理更清晰

9). 參數(shù)過多

正確寫法:

- (void)registerUser(User *user)

{

// to do...

}

錯(cuò)誤寫法:

- (void)registerUserName:(NSString *)userName password:(NSString *)password

email:(NSString *)email

{

// to do...

}

????當(dāng)發(fā)現(xiàn)實(shí)現(xiàn)某一功能需要傳遞的參數(shù)太多時(shí), 就預(yù)示著你應(yīng)該聚合成一個(gè)model類了...這樣代碼更整潔, 也不容易因?yàn)閰?shù)太多導(dǎo)致出錯(cuò)。

10). 回調(diào)方法

Preferred:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;

????函數(shù)調(diào)用的可知性, 回調(diào)時(shí)被調(diào)用者要知道其調(diào)用者, 方便信息的傳遞, 所以建議在回調(diào)方法中第一個(gè)參數(shù)中加上調(diào)用者。

????Block的循環(huán)引用問題

????Block確實(shí)是個(gè)好東西, 但是用起來(lái)一定要注意循環(huán)引用的問題,我們基本上都是通過weak-strong dancing方法來(lái)解決循環(huán)引用問題

__weak typeof(self) weakSelf = self;

dispatch_block_t block =  ^{

      [weakSelf doSomething]; // weakSelf != nil

      // preemption, weakSelf turned nil

      [weakSelf doSomethingElse]; // weakSelf == nil

};

????如此在上面定義一個(gè)weakSelf, 然后在block體里面使用該weakSelf就可以避免循環(huán)引用的問題. 那么問題來(lái)了...是不是這樣就完全木有問題了? 很不幸, 答案是NO, 還是有問題。問題是block體里面的self是weak的, 所以就有可能在某一個(gè)時(shí)段self已經(jīng)被釋放了, 這時(shí)block體里面再使用self那就是nil,

__weak typeof(self) weakSelf = self;

myObj.myBlock =  ^{

      __strong typeof(self) strongSelf = weakSelf;

      if (strongSelf) {

            [strongSelf doSomething]; // strongSelf != nil

            // preemption, strongSelf still not nil

            [strongSelf doSomethingElse]; // strongSelf != nil

      }

};

????那些年遇到的Crash

????多線程同步問題造成的Crash

????這個(gè)其實(shí)還蠻常見的, 尤其是在多線程泛濫使用的今天...你可以使用多線程, 但你要知道保護(hù)它呀, 哈哈. 對(duì)于數(shù)據(jù)源或model類一定要注意多線程同時(shí)訪問的情況, 我個(gè)人比較喜歡用GCD的串行隊(duì)列來(lái)同步線程.

????Observer的移除

????現(xiàn)在的代碼里面很多需要用到Observer, 根據(jù)被觀察對(duì)象的狀態(tài)來(lái)相應(yīng)的Update UI或者執(zhí)行某個(gè)操作. 注冊(cè)observer很簡(jiǎn)單, 但是移除的時(shí)候就出問題了, 要么是忘記移除observer了, 要么是移除的時(shí)機(jī)不對(duì). 如果某個(gè)被觀察對(duì)象已經(jīng)被釋放了, observer還在, 那結(jié)果只能是crash了, 所以切記至少在dealloc里面移除一下observer...

????NSArray, NSDictionary成員的判空保護(hù)
????在addObject或insertObject到NSArray或者NSDictionary時(shí)最好加一下判空保護(hù), 尤其是網(wǎng)絡(luò)相關(guān)的邏輯, 如果網(wǎng)絡(luò)返回為空(jason解析出來(lái)為空), 但你還是毅然決然的add到array里面, 那么...

????最后一點(diǎn)就是commit代碼之前一定要保證木有warning, 木有內(nèi)存泄露, 確保都OK之后再上傳代碼. 其實(shí)很簡(jiǎn)單, 上傳代碼之前Command + Shift + B靜態(tài)分析一下。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • iOS編程規(guī)范0規(guī)范 0.1前言 為??高產(chǎn)品代碼質(zhì)量,指導(dǎo)廣大軟件開發(fā)人員編寫出簡(jiǎn)潔、可維護(hù)、可靠、可 測(cè)試、高效...
    iOS行者閱讀 4,620評(píng)論 21 35
  • 概要 Objective-C是一門面向?qū)ο蟮膭?dòng)態(tài)編程語(yǔ)言,主要用于編寫iOS和Mac應(yīng)用程序。關(guān)于Objectiv...
    DreamMmMmM閱讀 1,281評(píng)論 0 7
  • 一、命名規(guī)范 1、統(tǒng)一要求含義清楚,盡量做到不需要注釋也能了解其作用,若做不到,就加注釋,使用全稱,不使用縮寫。 ...
    Untils閱讀 625評(píng)論 0 0
  • 課堂上我看到老師在黑板上寫了黃刺枚三個(gè)字,我在想:它是不是一種開黃色玫瑰 的植物呢?上面應(yīng)該還有刺,要不然怎么叫黃...
    小小的晴閱讀 1,104評(píng)論 0 1

友情鏈接更多精彩內(nèi)容