iOS 編寫高質量Objective-C代碼(一)—— 簡介

《編寫高質量OC代碼》已順利完成一二三四五六七八篇!
附上連接:
iOS 編寫高質量Objective-C代碼(一)—— 簡介
iOS 編寫高質量Objective-C代碼(二)—— 面向對象
iOS 編寫高質量Objective-C代碼(三)—— 接口和API設計
iOS 編寫高質量Objective-C代碼(四)—— 協議與分類
iOS 編寫高質量Objective-C代碼(五)—— 內存管理機制
iOS 編寫高質量Objective-C代碼(六)—— block專欄
iOS 編寫高質量Objective-C代碼(七)—— GCD專欄
iOS 編寫高質量Objective-C代碼(八)—— 系統框架html


目前iOS開發主推的官方語言有兩種:Objective-CSwift。 今天,小編幫助你們更加熟悉Objective-C,而且聊一聊如何才能編寫高質量的OC代碼。程序員

1、Objective-C的起源

談到Objective-C語言的起源,可要比Java還要早十多年。 ~Java在1995年推出,而Objective-C早在1980年代就已經出現了。~數組

Objective-C (OC) 由Smalltalk語言演化而來,後者是消息傳遞型語言的鼻祖。bash

  • 消息傳遞?是的!引入了今天的第一個Key。 OC與C++、Java等面嚮對象語言相似,但又有很大區別。爲何這麼說呢?首先要引入的話題就是OC使用消息傳遞機制,而並不是C++、Java使用函數調用機制。
// Objective-C : messaging (消息傳遞)
Object *obj = [Object new];
[obj performWith:parameter1 and:parameter2];

// C++: function calling(函數調用)
Object *obj = new Object;
obj->perform(parameter1, parameter2);
複製代碼

區別: 消息傳遞:運行時所執行的代碼由運行時環境決定(runtime) 函數調用:運行時所執行的代碼由編譯器決定架構

簡單來講,OC總在運行時纔會去查找真正所要調用的方法,編譯器並不用關心接收消息的對象是什麼類型,接收消息的對象也是在運行時才工做,其過程叫作動態綁定(dynamic binding)。而其餘大部分面嚮對象語言,會在運行時查找「虛方法表」(virtual table)來查出執行的方法(是調用子類的方法?仍是父類的方法?)。框架


OC是C語言的超集,若是你熟悉C語言,那C語言裏的大部分知識在編寫OC代碼時依然適用。 那麼,今天的第二個Key:指針函數

OC裏的指針主要用來指示對象,基本語法和C語言相似。ui

  • 例如:聲明一個字符串
NSString *str1 = @"QiShare";
複製代碼

語法解釋:聲明瞭一個名爲str1的變量,其類型爲NSString*。是一個指向NSString的指針。spa

  • 錯誤案例:
NSString str2;
複製代碼

報錯:error:interface type cannot be statically allocated 解釋:對象不容許聲明在棧空間上設計

不能在棧中分配OC對象,由於OC對象所佔的內存會被分配在堆空間(heap space)上,由程序員來控制它的內存分配。而棧中的臨時基本數據由編譯器控制。

  • 再舉一個典型案例:
xxxClass *Qi = [[xxxClass alloc] init];
xxxClass *Share = Qi;
複製代碼

這裏有兩個分配在棧空間的xxxClass指針:Qi和Share指向了堆空間中的同一塊內存地址。

內存結構,圖解以下:

分配在堆中的對象,內存必須由開發者管理。而分配在棧空間上的指針會在其棧幀彈出時自動清理。

OC將堆內存的管理抽象成了一個機制:ARC(Automatic Reference Counting)。在OC中,不須要用malloc及free來分配或釋放對象所佔的內存。OC在運行期環境中把這部分工做抽象爲一套內存管理架構,咱們稱之爲「引用計數」。~以後,咱們會有專門的一篇博客講解ARC機制~

2、爲了減小編譯時間,.h文件中儘可能少引入其餘頭文件。

必要時能夠考慮在.h文件裏"向前聲明"該類。

@class QiShareClass;

@interface xxx : xxx

// ...

@end
複製代碼

在.m文件裏再引入該類

#import "QiShareClass.h"

// ....
複製代碼

同時,向前聲明也解決了兩個類可能存在互相引用的問題。 例如:

  • Qi.h中
#import "Share.h"
複製代碼
  • Share.h中
#import "Qi.h"
複製代碼

當解析"Qi.h"時,編譯器發現"Share.h",再導回本身自己"Qi.h"。 從而形成循環引用。這樣會致使兩個類中有一個類不能正確編譯。 推薦:若是用到協議,必要時能夠把協議封裝在一個單獨的頭文件裏。不只能夠減小編譯時間,還能避免循環引用的問題。

3、多用字面量語法,少用等價方法

  • 好處:簡明易讀,提升代碼的可讀性和可維護性
  • 侷限性:用字面量預防建立數組或字典時,值不能有nil,不然會拋出異常。

For Example:

// 字面量字符串
NSString *str = @"QiShare";

// 字面量數值
NSNumber *num = @(1);
NSNumber *floatNum = @(1.0);
int x = 5;
float y = 3.14;
NSNumber *num = @(x * y);

// 字面量數組
NSArray *animals = @[@"cat", @"dog", @"tiger", @"monkey"];
NSString *cat = animals[0];

// 字面量字典
NSDictionary *qiShareDic = @{@"englishName": @"QiShare",
                             @"chineseName": @"奇分享"}];
NSString *englishName = qiShareDic[@"englishName"];
NSString *chineseName = qiShareDic[@"chineseName"];
複製代碼
  • 注意:用字面量語法創造出來的對象默認都是不可變對象,若是須要可變對象,執行一步 mutableCopy
NSMutableString *mutableStr = [@"QiShare" mutableCopy];
複製代碼

4、多用類型常量,少用#define預處理指令

  • 好處:定義出來的常量包含類型信息,不可變,可讀性高。
  • 而#define定義的值只是在編譯前做字符串替換操做,並不包含類型信息。而且若是一不當心被從新定義了常量值,編譯器不會產生任何警告⚠️,最終致使常量值不一致。

For Example:

#define ANIMATION_DURATION 0.5

// 替換成
static const NSTimeInterval kAnimationDuration = 0.5;

// 全局常量
// QiShare.h
extern const NSTimeInterval QiShareAnimationDuration;

// QiShare.m
const NSTimeInterval QiShareAnimationDuration = 0.3;
複製代碼

5、多用枚舉表示狀態、選項、狀態碼

  • 經過枚舉表示狀態機的狀態、傳遞給方法的選項以及狀態碼等值,加強了代碼的可讀性。
  • 枚舉的值若是存在多選的可能,將選項值定義爲2的冪。便於底層轉成二進制存儲。
  • 用NS_ENUM 與 NS_OPTIONS 宏來定義枚舉類型能夠指明底層的數據類型。由開發者決定,而不是編譯器決定。 For Example:
typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
    UIViewAutoresizingNone                 = 0,
    UIViewAutoresizingFlexibleLeftMargin   = 1 << 0,
    UIViewAutoresizingFlexibleWidth        = 1 << 1,
    UIViewAutoresizingFlexibleRightMargin  = 1 << 2,
    UIViewAutoresizingFlexibleTopMargin    = 1 << 3,
    UIViewAutoresizingFlexibleHeight       = 1 << 4,
    UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};
複製代碼

最後,特別緻謝《Effective Objective-C 2.0》第一章

相關文章
相關標籤/搜索