和我一起來學iOS(一)ObjectC的文法

來源:互聯網
上載者:User

前言:
為什麼叫和我一起學呢?因為從開始寫這系列部落格中我就定了一個方向,不從最基本的講,而是挑一些如果從其他語言(C、C#、 Java、 Javascript等)轉過來的程式員容易出錯的地方。

假設你是有幾年其他語言的開發經驗,對我說的上述基礎語言有了不錯的瞭解。這其實也是我當初學這門語言時最希望別人告訴我的地方。

 

獨特的@符號

首先,ObjectC是C的超集,為了不和C中已有的東西衝突,ObjectC中特有的東西前面都帶有@符號

比如聲明字串 ,可以這麼聲明,這時就是一個C類型的字串

char *name = "langxue";

這麼聲明出來的字串不是一個ObjectC對象,因此不會帶有一些特定的方法,ObjejctC中字面量字串是這麼聲明的

NSString *name = @"langxue"

 

 

文法的差異

一、方法名

ObjectC中的方法名由多個段組成。

比如我們想初始化一個controller,最常用的是這個方法

initWithNibName:bundle:

看起來很奇怪是吧?方法具體簽名如下

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

參數更緊接著調用的謂語,這樣看起來更符合自然文法,在擁有多個參數的情況下即使沒有對參數的說明,也非常容易記住。

中括號運算式:

一個中括弧代表一次調用,看起來比較清晰。

具體調用如下:

[[MyViewController alloc] initWithNibName:@"MyViewController" bundle:nil];

我們先是根據MyViewController類所需的大小分配了一塊記憶體,然後發送訊息去初始化這塊記憶體。

因為方法名是包括:符號的,所以在通過selector選擇方法的時候,:符號不能忘記

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];

 

二、id

這類似於C中的通用指標void*,可以用來儲存任何類的對象。也像C#中的dynamic關鍵字,就是告訴編譯器在編譯時間無需檢查這個變數的類型,啟動並執行時候再檢查確定。換句話說就是動態綁定。由於對象總是帶著isa指標,所以即使我們無法從指標類型得出資訊,也總能從對象本身擷取類型資訊。

在ObjectC中哪裡會用到呢?

1.初始化的時候

ObjectC一個對象不能有兩個名字相同的方法,即使他們的參數和傳回型別不同。因此子類的init方法既不能返回子類,否則無法調用父類相同的init方法,當然也不能返回父類。

這時候就需要用到id這個通用的指標了。

2.不需要具體類型,只需要知道這個執行個體實現了某些方法。類似於C#中對介面編程的用法,常用聲明delegate屬性,以便使用不同的策略提供對象。

@property (nonatomic, weak) id<RequestDelegate> delegate;

 

需要提醒的是,雖然它可以儲存任何類的對象,如果濫用它,就會失去靜態類型時編譯器所提供的好處。

三、強弱引用( strong, week(ARC); retain, assign(非ARC) )

是否加入引用計數的一種方式。iOS中沒有自動記憶體回收機制,記憶體回收是根據引用計數來決定的。一個對象的引用計數為0的時候會被認為是垃圾馬上被銷毀,這和GC機制的有延遲的回收不一樣的地方。記憶體能更高效的被使用。

在ARC的項目中

@property (strong, nonatomic) MyController *myController;

 

 

四、協議 (protocol)

 類似於C#中的Interface,區別在於protocol中定義的方法可以選擇不需要實現,也就是@optional的。當然如果沒有標記那麼就是必須實現的。

@protocol BoardActionDelegate<NSObject>@required- (void) selectPressed:(UIView *)sender;@optional- (void) cancelPressed:(UIView *)sender;@end

 

五、範疇(Categories)

1.命名範疇,類似於C#中的擴充方法,用於給已有的類擴充自訂的方法,區別在於ObjectC中不限制方法的類型,可以是執行個體或者是類方法。但是不能帶成員變數。

 比如說我們擴充UIColor類

@interface UIColor (Extract)- (void)extract_getRed;       @end

這類檔案的命名最好為原類名 + 擴充類名,如 UIColor+Extract.h 、UIColor+Extract.m

2.類擴充(class extension),看起來就像一個沒有名字的範疇。可以帶變數成員,且必須實現。

如果根據良好的代碼劃分,我想放在標頭檔.h的往往是對外公開的方法和屬性,而自己內部使用的私人方法就不需要放在標頭檔裡。在像C#這種沒有標頭檔的語言裡,我們仍然會按照約定先寫Public 方法,然後用#region 把它標記起來,方便別人查看。

假設我們有一個CarStock類,在CarStock.m中有如下代碼,會遇到這麼一個問題,如果init中調用的方法聲明如果在init的位置下面,那麼編譯器就會報錯,因為它是從上往下解析的.

- (id)init {        if ((self = [super init])) {            [self refreshStock];        }       return self;    }- (void)refreshStock {      // ...  }

這時有幾種解決方式

1.refreshStock方法上移

2.refreshStock聲明在標頭檔CarStock.h裡

但這些都不符合我想要寫一個私人方法的想法。ObjectC中方法是不帶範圍聲明的,也就是你無法像下面這樣聲明

private - (void)refreshStoc

 所以可以在CarStock.m中,通過一個無命名的範疇,來解決這個問題

@interface CarStock ()- (void)refreshStock;       @end

 

六、@dynamic
告訴編譯器我們這個屬性會在其他地方產生相應的get和set方法(在ObjectC中是通過@synthesize(合成)關鍵字來合成屬性)

Super class中對這個屬性合成:

@property (nonatomic, retain) NSButton *someButton;...@synthesize someButton;

Subclass如果不對*someButton合成或者自己提供get,set方法,那麼編譯器就會提示有問題:

@property (nonatomic, retain) IBOutlet NSButton *someButton;...@dynamic someButton;

我們想用Super class中的合成方法來合成Subclass,我們這時候就可以通過@dynamic關鍵字來關閉編譯器的警告。

這在通常代碼中非常少用,往往在使用Core data(ObjectC中的ORM架構)中使用。我們繼承了NSManagedObject,希望相應的訪問器方法由它來完成。

 

七、@class

在標頭檔.h裡我們往往不需要知道所引用類的具體方法資訊,而只是需要知道有這麼一個類,便於我們聲明變數類型,我們這時候就可以用@class關鍵字來代替#import,這樣告訴編譯器我們肯定會有這麼一個類,你就不用檢查了。這樣在一些大型項目中可以加快編譯速度。也可以解決迴圈import可能帶來的問題。
當具體使用的使用我們才在.m裡import所需要的標頭檔。

 

八、nil
nil 類似於 null,區別在於給nil發送訊息並不會產生錯誤,它的預設實現是忽視這條資訊。在C#和其他語言中則會產生類似NullReference的錯誤。

原因是在底層C的實現中,nil不帶self指標,發送訊息調用selector的時候如果檢測self為空白,則直接返回。

我們通常在使用NSError的時候,通過檢測NSError是否為nil來判斷方法調用是否出錯

        NSError *error = nil;        self.responseString = [NSString stringWithContentsOfFile:zipFileName_ encoding:NSUTF8StringEncoding error:&error];        if (error)

還有就是在dealloc方法中把不用的變數設定為nil,可以防止在release後指標指向無效記憶體而導致錯誤。

Xcode 4.4版本(LLVM4編譯器)後編譯器新增的一些文法糖

Xcode是免費的,所以咱們可以升級到新版本來享受一下新編譯器的一些好處

1.更加多的字面量支援

原來我們在ObjectC中建立一個NSString類型的對象時,可以

NSString *myName=@"langxue";

現在我們建立其他對象也可以字面量文法了

NSNumber *myNumber =@3;NSNumber *yesValue =@YES;NSArray *array =@[@1,@2,@3,@4];NSDictionary *dictionary =@[@"key1":@"value1"                  ,@"key2":@"value2"]

 

2.下標訪問

我們可以通過下標來直接存取我們需要的元素,這在原來是不可以的。

int element3 = array[3]; int elementAt3 = dictionary [@"key3"]

 

3.自動合成@property

我們聲明了property以後

@property (strong, nonatomic) MyController *myController;@property (nonatomic, copy) void (^completionHandler)();

原來的情況下訪問器是通過@synthesize關鍵字合成的。

@synthesize myController = _myController;
@synthesize completionHandler = _completionHandler;

有了新的LLVM編譯器,就可以省略這些用於合成執行個體變數的代碼了。LLVM 4編譯器會自動合成這些執行個體變數。當然如果明確地寫了get,set方法,LLVM 4就不再自動產生@synthesize指令了。需要記住的是,自動合成的執行個體變數會按照ObjectC中的慣例以底線_開頭。

 

 最後,如果你覺得這篇文章有協助,請點右下角一下推薦,這是我繼續下去的動力,謝謝!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.