《Effective Objective-C 2.0》—(第1-5條)—熟悉Objective-C

來源:互聯網
上載者:User

標籤:objective-c起源   static const   枚舉   

    Objective-C通過一套全新的文法,在C語言基礎上添加了物件導向特性。OC的文法中頻繁使用中括弧([  ]),而且不吝於寫出極長的方法名,這通常令許多人覺得此語言較為冗長。這是這樣寫出來的代碼非常易讀,只是C++和Java程式員不太適應。

    OC語言學起來很快,但有很多微妙細節需要注意,而且還有許多容易為人所忽略的特性。另一方面,有些開發人員並未完全理解或是容易濫用某些特性,導致寫出來的代碼難以維護,難以調試。本章講解基礎知識,後續各章語言及其相關架構的各個特定話題。

第1條:瞭解OC語言的起源

    OC與C++,Java等物件導向語言類似,不過很多方面有差別。若是用過另一種物件導向語言,那麼就能理解OC所用的許多範式與模板了。然而文法上也許會顯得陌生,因為OC使用訊息結構(messaging structure)而非函數調用(function calling)。OC由SmallTalk演化而來,後者是訊息型語言的鼻祖。訊息與函數調用之間的區別看上去就像這樣:

//Messaging (OC)Object *obj = [Object new];[obj perfromWith:parameter1 and:parameter2];//Function calling(C++)Object *obj = new object;obj->perform(parameter1,parameter2);

    關鍵區別在於:使用訊息結構的語言,其運行時所應執行的代碼由運行環境決定;而使用函數調用的語言,由編譯器決定。如果範例代碼中調用函數是多態的,那麼在運行時就要按照“虛函數表”(virtual table)來尋找到底應該執行哪個函數。而採用訊息結構的語言,不論是否多態,總是在運行時才會去尋找所要執行的方法。實際上,編譯器甚至不關心接受訊息的對象是何種類型。接受訊息的對象問題也要在運行時處理,其過程叫做“動態綁定”(dynamic binding)見第11條

    OC的重要工作都由“運行期組件”(runtime component)而非編譯器來完成。使用OC的物件導向特性所需的全部資料結構及函數都在運行期組件裡面。舉例來說,運行期組件中含有全部記憶體管理方法。運行期組件本質上就是一種與開發人員所編代碼相連結的“動態庫”(dynamic library),其代碼能把開發人員編寫的所有程式戰粘和起來。這樣,只需更新執行期組件,即可提升應用程式效能。

     OC是C的超集,所以C語言中的所有功能在編寫OC代碼時依然適用。

     OC只能在堆上聲明變數,不能在棧上聲明(CGRect可以聲明在棧上,因為CGRect是C結構體),OC將堆記憶體管理抽象出來了。不需要malloc及free來分配或釋放對象所佔記憶體。OC運行期環境把這部分工作抽象為一套記憶體管理架構,名叫“引用計數”,見第29條

第2條:在類的標頭檔中盡量少引入其他標頭檔

    與C和C++一樣,OC使用標頭檔與“實現檔案”來區隔代碼。用OC語言編寫任何類幾乎都要引入Foundation.h。

    盡量在標頭檔中使用類聲明,防止迴圈標頭檔引用,過多的引用標頭檔也會增加編譯時間。

第3條:多用字面量文法,少用與之等價的方法

舉例:

NSNumber *someNumber = @1;NSNumber *intNumber = @1;NSNumber *floatNumber = @2.5f;NSArray * animals = @[@"cat",@"dog",@"mouse",@"badger"];NSString *dog = animals[1];//----------------------id object1 = /*......*/;id object2 = /*......*/;id object3 = /*......*/;NSArray* arrayA = [NSArray ArrayWithObjects:object1,object2,object3,nil];NSArray* arrayB = @[object1,object2,object3];//如果object2 = nil那麼arrayB拋出異常,array中只有object1和object2。//----------------------NSDictionary *personData = @{@"firstName":@"Matt",@"lastName":@"Galloway",@"age":@28};

第4條:多用類型常量,少用#define預先處理指令

    編寫代碼經常需要定義常量。例如:

#define ANIMATION_DURATION 0.3

    #define會編譯期簡單替換文本,會造成很多不必要的麻煩。要像解決此問題,應該設法利用編譯器的某些特性才行。比如:

static const NSTimeInterval kAnimationDuration = 0.3;

    這種方式定義常量包含了類型資訊,且最好將這個聲明放到.m檔案中。static const的聲明不應該出現在標頭檔裡。因為OC沒有命名空間,所以那樣就等於聲明了一個全域變數。static修飾表示該變數僅定義在此.m檔案中(一個編譯單元),如果不加static,則編譯器會為他建立一個“外部符號”(external symbol)。此時若另外一個.m檔案也有了同名變數,就會造成符號重複(duplicate symbol)。

    實際上,如果一個變數既聲明為static,又聲明為const,那麼編譯器根本不會建立符號,而是會像#define一樣預先處理指令一樣,把所有遇到的變數都替換為常量。

    有時候需要對外公開某個常量,例如:

//in the header fileextern NSString *const EOCStringConstant;//in the implement fileNSString* const EOCStringConstant = @"VALUE";

    EOCStringConstant是一個常量指標,編譯器會看到標頭檔中的extern關鍵字,這個關鍵字是要告訴編譯器,在全域符號表中將會有有一個名叫EOCStringConstant的符號。當連結成二進位檔案之後,肯定能找到這個常量。因為符號要放在全域符號表裡,所以命名常量時需謹慎。

本節要點:

● 不要用預先處理指令定義常量。即使有人重新定義了常量值,編譯器頁不會產生警告資訊,這將導致程式中常量不一致。

● 在實現檔案中使用static const來定義“只在編譯單元內可見的常量”(translation-unitspecific constant)。此類常量不在全域符號表中。

● 在標頭檔中使用extern來聲明全域常量,並在實現檔案中定義其值。

第5條:用枚舉表示狀態、選項、狀態代碼

    直接舉例    

typedef NS_ENUM(NSUInteger,EOCConnectionState){    EOCConectionStateDisconnected,    EOCConectionStateConnecting,    EOCConectionStateConnected,};

● 用NS_ENUM與NS_OPTIONS宏來定義枚舉類型,並指明底層資料類型。這樣做可以確保枚舉是開發人員所選的底層資料類型實現出來的,而不會採用編譯器所選的類型。


其餘章節點擊這裡

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.