轉自:http://tiny4cocoa.com/doc/xcode-doc/learn-objective-c
Objective-C是一種簡單的電腦語言,設計為可以支援真正的物件導向編程。Objective-C通過提供類定義,方法以及屬性的文法,還有其他可以提高類的動態擴充能力的結構等,擴充了標準的ANSI C語言。類的文法和設計主要是基於Smalltalk,最早的物件導向程式設計語言之一。
如果你以前使用過其他物件導向程式設計語言,那麼下面的資訊可以協助你學習Objective-C的基本文法。許多傳統的物件導向概念,例如封裝,繼承以及多態,在Objective-C中都有所體現。這裡有一些重要的不同,但是這些不同在這文章會表現出來,而且如果你需要還有更多詳細的資訊存在。
如果你從來沒有使用任何程式設計語言編過程式,那麼你至少需要在開始之前,對相關概念進行一些基礎的瞭解。對象的使用和對象對象架構是iPhone程式設計的基礎,理解他們如何互動對建立你的程式非常重要。想瞭解物件導向概念的,請參看使用Objective-C進行物件導向編程。此外,參看Cocoa基礎指南可以獲得Cocoa中的物件導向設計模式的資訊。
想瞭解更多Objective-C語言和文法的細節介紹,請參看Objective-C 2.0程式設計語言。
Objective-C: C的超集
Objective-C是ANSI版本C程式設計語言的超集,支援C的基本文法。在C代碼中,你定義標頭檔和原始碼檔案,從代碼實現細節分離公用聲明。Objective-C標頭檔使用的檔案名稱列在表1中。
表1 Objective-C代碼的副檔名
副檔名 |
內容類型 |
.h |
標頭檔。標頭檔包含類,類型,函數和常數的聲明。 |
.m |
原始碼檔案。這是典型的原始碼副檔名,可以包含Objective-C和C代碼。 |
.mm |
原始碼檔案。帶有這種副檔名的原始碼檔案,除了可以包含Objective-C和C代碼以外還可以包含C++代碼。僅在你的Objective-C代碼中確實需要使用C++類或者特性的時候才用這種副檔名。 |
當你需要在原始碼中包含標頭檔的時候,你可以使用標準的#include編譯選項,但是Objective-C提供了更好的方法。#import選項和#include選項完全相同,只是它可以確保相同的檔案只會被包含一次。Objective-C的例子和文檔都傾向於使用#import,你的代碼也應該是這樣的。
字串
作為C語言的超集,Objective-C支援C語言字串方面的約定。也就是說,單個字元被單引號包括,字串被雙引號包括。然而,大多數Objective-C通常不使用C語言風格的字串。反之,大多數架構把字串傳遞給NSString對象。NSString類提供了字串的類封裝,包含了所有你期望的優點,包括對儲存任意長度字串的內建記憶體管理機制,支援Unicode,printf風格的格式化工具,等等。因為這種字串使用的非常頻繁,Objective-C提供了一個助記符可以方便地從常量值建立NSString對象。要使用這個助記符,你需要做的全部事情,是在普通的雙引號字串前放置一個@符號,如下面的例子所示:
NSString* myString = @"My String/n";NSString* anotherString = [NSString stringWithFormat:@"%d %s", 1, @"String"];// 從一個C語言字串建立Objective-C字串NSString* fromCString = [NSString stringWithCString:"A C string" encoding:NSASCIIStringEncoding];
類
如同所有其他的物件導向語言,類是Objective-C用來封裝資料,以及操作資料的行為的基礎結構。對象就是類的運行期間執行個體,它包含了類聲明的執行個體變數自己的記憶體拷貝,以及類成員的指標。Objective-C的類規格說明包含了兩個部分:介面和實現。介面部分包含了類聲明和執行個體變數的定義,以及類相關的方法。實現部分包含了類方法的實際代碼。圖1展現了聲明一個叫做MyClass的類的文法,這個類繼承自NSObject基礎類。類聲明總是由@interface編譯選項開始,由@end編譯選項結束。類名之後的(用冒號分隔的)是父類的名字。類的執行個體(或者成員)變數聲明在被大括弧包含的代碼塊中。執行個體變數塊後面就是類聲明的方法的列表。每個執行個體變數和方法聲明都以分號結尾。
圖1 類聲明
列表1展現了前面例子中MyClass類的實現。類同與類聲明,類實現的位置也由兩個編譯選項確定,@implementation和@end。這些選項給編譯器提供了要將方法和對應類聯絡起來,所需的範圍資訊。因此方法的定義和介面中對應的聲明是匹配的,只是多了個代碼塊而已。
列表1 類實現
@implementation MyClass - (id)initWithString:(NSString *) aName{ if (self = [super init]) { count count = 0; data = nil; name = [aName copy]; return self; }} + (MyClass *)createMyClassWithString: (NSString *) aName{ return [[[self alloc] initWithString:aName] autorelease];}@end
注意: 雖然前面的類只聲明了方法,但是類可以聲明屬性。想瞭解更多關於屬性的資訊,參看“屬性”。
當用變數儲存對象的時候,始終應該使用指標類型。Objective-C對變數包含的對象支援強弱兩種類型。強型別指標的變數型別宣告包含了類名。弱類型指標使用id作為對象的類型。弱類型指標常用於類的集合,在集合中對象精確的類型可以是未知的。如果你用過強型別語言,你也許覺得使用弱類型變數可能會帶來問題,但是他們實際上給了Objective-C程式巨大的靈活性,而且使它更強大。
下面的例子裡,展示了MyClass類的強型別和弱型別宣告變數:
MyClass* myObject1; // Strong typingid myObject2; // Weak typing
方法
Objective-C中的類可以聲明兩種類型的方法:執行個體方法和類方法。執行個體方法就是一個方法,它在類的一個具體執行個體的範圍內執行。也就是說,在你調用一個執行個體方法前,你必須首先建立類的一個執行個體。而類方法,比較起來,也就是說,不需要你建立一個執行個體。
方法聲明包括方法類型標識符,傳回值類型,一個或多個方法標識關鍵字,參數類型和名資訊。圖2展示insertObject:atIndex:執行個體方法的聲明。聲明由一個減號(-)開始,這表明這是一個執行個體方法。方法實際的名字(insertObject:atIndex:)是所有方法標識關鍵的級聯,包含了冒號。冒號表明了參數的出現。如果方法沒有參數,你可以省略第一個(也是唯一的)方法標識關鍵字後面的冒號。本例中,這個方法有兩個參數。
圖2 方法聲明文法
當你想調用一個方法,你傳遞訊息到對應的對象。這裡訊息就是方法標識符,以及傳遞給方法的參數資訊。發送給對象的所有訊息都會動態分發,這樣有利於實現Objective-C類的多態行為。也就是說,如果子類定義了跟父類的具有相同標識符的方法,那麼子類首先收到訊息,然後可以有選擇的把訊息轉寄(也可以不轉寄)給他的父類。
訊息被中括弧( [ 和 ] )包括。中括弧中間,接收訊息的對象在左邊,訊息(包括訊息需要的任何參數)在右邊。例如,給myArray變數傳遞訊息insertObject:atIndex:訊息,你需要使用如下的文法:
[myArray insertObject:anObj atIndex:0];
為了避免聲明過多的本地變數儲存臨時結果,Objective-C允許你使用嵌套訊息。每個嵌套訊息的傳回值可以作為其他訊息的參數或者目標。例如,你可以用任何擷取這種值的訊息來代替前面例子裡面的任何變數。所以,如果你有另外一個對象叫做myAppObject擁有方法,可以訪問數組對象,以及插入對象到一個數組,你可以把前面的例子寫成如下的樣子:
[[myAppObject getArray] insertObject:[myAppObject getObjectToInsert] atIndex:0];
雖然前面的例子都是傳遞訊息給某個類的執行個體,但是你也可以傳遞訊息給類本身。當給類發訊息,你指定的方法必須被定義為類方法,而不是執行個體方法。你可以認為類方法跟C++類裡面的靜態成員有點像(但是不是完全相同的)。
類方法的典型用途是用做建立新的類執行個體的Factory 方法,或者是訪問類相關的共用資訊的途徑。類方法聲明的文法跟執行個體方法的幾乎完全一樣,只有一點小差別。與執行個體方法使用減號作為方法類型標識符不同,類方法使用加號( + )。
下面的例子示範了一個類方法如何作為類的Factory 方法。在這裡,arrayWithCapacity是NSMutableArray類的類方法,為類的新執行個體分配內容並初始化,然後返回給你。
NSMutableArray* myArray = nil; // nil is essentially the same as NULL// Create a new array and assign it to the myArray variable.myArray = [NSMutableArray arrayWithCapacity:0];
屬性
屬性是用來代替聲明存取方法的便捷方式。屬性不會在你的類聲明中建立一個新的執行個體變數。他們僅僅是定義方法訪問已有的執行個體變數的速記方式而已。暴露執行個體變數的類,可以使用屬性記號代替getter和setter文法。類還可以使用屬性暴露一些“虛擬”的執行個體變數,他們是部分資料動態計算的結果,而不是確實儲存在執行個體變數內的。
實際上可以說,屬性節約了你必須要些的大量多餘的代碼。因為大多數存取方法都是用類似的方式實現的,屬性避免了為類暴露的每個執行個體變數提供不同的getter和setter的需求。取而代之的是,你用屬性聲明指定你希望的行為,然後在編譯期間合成基於聲明的實際的getter和setter方法。
屬性聲明應該放在類介面的方法聲明那裡。基本的定義使用@property編譯選項,緊跟著類型資訊和屬性的名字。你還可以用定製選項對屬性進行配置,這決定了存取方法的行為。下面的例子展示了一些簡單的屬性聲明:
@property BOOL flag;@property (copy) NSString* nameObject; // Copy the object during assignment.@property (readonly) UIView* rootView; // Create only a getter method.
使用屬性另外的好處就是你可以在代碼中訪問他們的時候,使用點文法,如下面的例子所示:
myObject.flag = YES;CGRect viewFrame = myObject.rootView.frame;
雖然前面例子裡面的對象和屬性名稱是故意這麼取的,他們還是展現了屬性的靈活性。點文法實際上隱藏了對應的方法調用。每個可讀的屬性由一個與屬性同名的方法支援。每個可寫屬性由一個叫做“set屬性名稱”的額外方法來支援,屬性名稱的第一個字母要大寫。(這些方法是屬性的實際實現方式,也是你可以聲明一個沒有任何執行個體變數支援的屬性聲明的原因。)如果用方法來代替前面代碼中的屬性,你就要下下面的代碼:
[myObject setFlag:YES];CGRect viewFrame = [[myObject rootView] frame];
要瞭解更多關於如何聲明屬性的資訊,參看Objective-C 2.0程式設計語言的屬性一章。
協議和代理
協議聲明了可以被任何類實現的方法。協議不是那些類本身。他們僅是定義一個介面,其他的對象去負責實現。你實現了協議裡面的方法,就叫做符合協議。
在iPhone OS中協議常用來實現委派物件。委派物件就是一個對象以其他的對象的模式行事。瞭解協議,委託和對象最好的辦法就是看一個例子。
UIApplication類實現了一個程式需要的行為。如果想接收程式目前狀態的簡單訊息,並不需要強制你建立UIApplication的一個子類,反之UIApplication類通過調用委派物件的指定方法來分發這些通知訊息。實現UIApplicationDelegate方法的對象都可以接受這樣的通知,並進行響應的反應。
協議的聲明跟類介面的聲明很像,只是協議沒有父類,而且他們不會定義任何執行個體變數。下面的例子展示了一個有一個方法的協議聲明:
@protocol MyProtocol- (void)myProtocolMethod;@end
在大多數委託協議情況下,使用某種協議僅僅是簡單的實現協議定義的方法而已。 有些協議要求你明確的表明你支援這種協議,協議可以指定必須或者可選的方法。在你深入開發的過程中,你應該花點時間學習協議以及他們的用途,請閱讀Objective-C 2.0程式設計語言的協議章節。
更多的資訊
前面的資訊是為了讓你對Objective-C語言的基礎所有瞭解。本文提到的語言特性,你可以在閱讀完整文檔的時候找到。但是這個語言不僅僅有這些特性,所以最好請仔細閱讀文檔Objective-C 2.0程式設計語言。