《禪與 Objective-C 編程藝術(shù) 》閱讀筆記

原文:禪與 Objective-C 編程藝術(shù)

條件語句

總是要用大括號

尤達表達式

不推薦

nil 和 BOOL

不要直接把對象跟nil或YES,NO比較,用 if(!xx)來即可

黃金大道

即不要嵌套if語句,可以使用return語句避免增加循環(huán)的復(fù)雜度

即推薦:

- (void)someMethod {
  if (![someOther boolValue]) {
      return;
  }

  //Do something important
}

不推薦

- (void)someMethod {
  if ([someOther boolValue]) {
    //Do something important
  }
}

其中有句原話是:

在使用條件語句編程時,代碼的左邊距應(yīng)該是一條“黃金”或者“快樂”的大道。

對黃金大道這個比喻不理解,不明白黃金大道的在這里的比喻。
但是上面的例子是比較清晰的。

復(fù)雜的表達式

if中的復(fù)雜表達式,提取出來賦值給BOOL,使之更清晰 。

BOOL nameContainsSwift  = [sessionName containsString:@"Swift"];
BOOL isCurrentYear      = [sessionDateCompontents year] == 2014;
BOOL isSwiftSession     = nameContainsSwift && isCurrentYear;

if (isSwiftSession) {
    // Do something very cool
}

三元運算符

三元運算符里的子句,應(yīng)該也只是求值后的變量,不要直接用復(fù)雜的句子。

推薦

result = a > b ? x : y;

不推薦

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

另外,推薦更靈活地表達方式:

result = object ? : [self createObject];

不推薦

result = object ? object : [self createObject];

錯誤處理

有些方法通過參數(shù)返回 error 的引用,使用這樣的方法時應(yīng)當檢查方法的返回值,而非 error 的引用。

推薦:

  NSError *error = nil;
  if (![self trySomethingWithError:&error]) {
      // Handle Error
  }

此外,一些蘋果的 API 在成功的情況下會對 error 參數(shù)(如果它非 NULL)寫入垃圾值(garbage values),所以如果檢查 error 的值可能導(dǎo)致錯誤 (甚至崩潰)。

Case語句

switch語句里是枚舉變量時,建議不要用default,因為當枚舉增加時,這些switch語句會收到警告

使用枚舉變量時,建議使用新的宏- NS_ENUM()

命名

通用的約定

駝峰法命名

內(nèi)存管理規(guī)則:

You create an object using a method whose name begins with “alloc”, “new”, “copy”, or “mutableCopy” (for example, alloc, newObject, or mutableCopy).

常量

駝峰法,類名做前綴,盡量用常量類型少用宏

方法

  • 方法名與方法類型 (-/+ 符號)之間應(yīng)該以空格間隔
  • 方法段之間也應(yīng)該以空格間隔(以符合 Apple 風(fēng)格)
  • 參數(shù)前應(yīng)該總是有一個描述性的關(guān)鍵詞。盡可能少用 "and" 這個詞

字面值

不推薦[@[] mutableCopy]這種寫法。

類名

  • 類名應(yīng)該以三個大寫字母作為前綴
  • 當你創(chuàng)建一個子類的時候,你應(yīng)該把說明性的部分放在前綴和父類名的在中間。如有一個 ZOCNetworkClient 類,子類的名字會是ZOCTwitterNetworkClient

Initializer 和 dealloc

  • dealloc函數(shù)應(yīng)該放在文件的最前面,init方法跟在后面。
  • allocinit方法解釋。

Designated 和 Secondary 初始化方法

  • 一個類應(yīng)該有且只有一個 designated 初始化方法
  • 子類的Designated Initializer應(yīng)該調(diào)用父類的Designated Initializer方法。
  • NS_DESIGNATED_INITIALIZER來指定為Designated Initializer(方法后加上該宏)。
  • Secondary Initializer應(yīng)該調(diào)用Designated Initializer
  • 初始化方法返回參數(shù)用instancetype替換id
  • 類簇 (class cluster)的解釋
  • 單例用dispatch_once()替代@synchronized

屬性

  • 命名用小寫字母開頭的駝峰命名
  • 在init方法里要直接用實例變量,不要用set/get方法訪問屬性變量。因為子類可能重載屬性變量。
  • 用點語法
  • 屬性的參數(shù)應(yīng)該按照下面的順序排列: 原子性,讀寫 和 內(nèi)存管理
  • NSString,NSArray,NSURLRequest等有可變對象的類,盡量用copy,防止用strong指向可變子類,導(dǎo)致值被修改出現(xiàn)問題
  • 用懶加載(Lazy Loading)時,注意副作用,如get方法里修改了一些類的全局變量,導(dǎo)致加載時機不同出現(xiàn)問題

方法

  • 用斷言NSAssert()NSParameterAssert()拋參數(shù)異常
  • 私有變量和私有方法不要用_前綴,蘋果已保留該前綴

相等性

當你要實現(xiàn)相等性的時候記住這個約定:你需要同時實現(xiàn)isEqual 和 hash方法。如果兩個對象是被isEqual認為相等的,它們的 hash 方法需要返回一樣的值。但是如果 hash 返回一樣的值,并不能確保他們相等。

Categories

category里的方法應(yīng)該用自己的小寫前綴加下劃線,如- (id)zoc_myCategoryMethod

Protocols

用協(xié)議提高代碼的復(fù)用性

NSNotification

通知名應(yīng)該用類名做前綴,用一個 Did/Will 這樣的動詞以及用 "Notifications" 后綴。如

// Foo.h
extern NSString * const ZOCFooDidBecomeBarNotification

// Foo.m
NSString * const ZOCFooDidBecomeBarNotification = @"ZOCFooDidBecomeBarNotification";

美化代碼

  • 空格,這里說用四個空格替代TAB,但是一般文章都是推薦用TAB,因為可以根據(jù)編譯的設(shè)定而改變,所以這里存疑
  • 方法的大括號和其他的大括號(if/else/switch/while 等) 總是在同一行開始
  • 方法之間要有空行
  • 參數(shù)換行

代碼組織

  • 善用代碼塊{}

  • 方法用#pragma mark -組織分離

  • 當用performSelector調(diào)用方法在ARC出現(xiàn)警告時,可用#pragma clang diagnostic去除警告,代碼示例:

      #pragma clang diagnostic push
      #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
      
      [myObj performSelector:mySelector withObject:name];
      
      #pragma clang diagnostic pop
    
  • 忽視未讀變量的方法:#pragma unused (foo)(如果foo變量未使用,用該方法不提示警告)

  • 注釋分兩種///** */。非公開、很短、顯而易見的函數(shù)一般用//,其它和對外暴露的一般用/** */

對象間的通訊

  • Block,這里說下“在 block 外定義一個 __weak 的 引用到 self,并在 block 內(nèi)部通過這個弱引用定義一個 __strong 的引用?!?/em>的情況。這種一般是需要持有self,但是又為了避免retain circle的情況。block內(nèi)的self強引用是Block執(zhí)行時創(chuàng)建的,
    示例代碼如下:

      @property (nonatomic,strong) NSString *testString;
      @property (nonatomic,copy) void(^BlockTest)();
    
    
      self.testString = @"testststs";
      __weak typeof(self)weakSelf = self;
      self.BlockTest = ^(){
          __strong typeof(self)strongSelf = weakSelf;
          NSLog(@"%@",strongSelf.testString);
      };
      
      self.BlockTest();
    

注:weakSelf是為了block不持有self,避免循環(huán)引用,而再聲明一個strongSelf是因為一旦進入block執(zhí)行,就不允許self在這個執(zhí)行過程中釋放。block執(zhí)行完后這個strongSelf會自動釋放,沒有循環(huán)引用問題。

  • 多重委托

面向切面編程

AOP,面向切面編程,統(tǒng)計與日志就是一個完美的例子。

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

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

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