天天看點

O“.NET研究”bjective-C入門

  Objective-C是一種簡單的計算機語言,設計為可以支援真正的面向對象程式設計。Objective-C通過提供類定義,方法以及屬性的文法,還有其他可以提高類的動态擴充能力的結構等,擴充了标準的ANSI C語言。類的文法和設計主要是基于Smalltalk,最早的面向對象程式設計語言之一。

  如果你以前使用過其他面向對象程式設計語言,那麼下面的資訊可以幫助你學習Objective-C的基本文法。許多傳統的面向對象概念,例如封裝,繼承以及多态,在Objective-C中都有所展現。這裡有一些重要的不同,但是這些不同在這文章會表現出來,而且如果你需要還有更多詳細的資訊存在。

  如果你從來沒有使用任何程式設計語言編過​​上海闵行企業網站制作​​程式,那麼你至少需要在開始之前,對相關概念進行一些基礎的了解。對象的使用和對象對象架構是iPhone程式設計的基礎,了解他們如何互動對建立你的程式非常重要。想了解面向對象概念的,請參看使用Objective-C進行面向對象程式設計。此外,參看Cocoa基礎指南可以獲得Cocoa中的面向對象設計模式的資訊。

  Objective-C: C的超集

  Objective-C是ANSI版本C程式設計語言的超集,支援C的基本文法。在C代碼中,你定義頭檔案和源代碼檔案,從代碼實作細節分離公共聲明。Objective-C頭檔案使用的檔案名列在表1中。  

  表1 Objective-C代碼的檔案擴充名

擴充名 内容類型
.h 上海闵行企業網站設計與制作dercolor="#000000">頭檔案。頭檔案包含類,類型,函數和常數的聲明。
.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*上海網站建設tyle="color: #000000;"> 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 類聲明

O“.NET研究”bjective-C入門

  清單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 typing
id        myObject2;    // Weak typing      

  方法

  Objective-C中的類可以聲明兩種類型的方法:執行個體方法和類方法。執行個體方法就是一個方法,它在類的一個具體執行個體的範圍内執行。也就是說,在你調用一個執行個體方法前,你必須首先建立類的一個執行個體。而類方法,比較起來,也就是說,不需要你建立一個執行個體。

  方法聲明包括方法類型辨別符,傳回值類型,一個或多個方法辨別關鍵字,參數類型和名資訊。圖2展示insertObject:atIndex:執行個體方法的聲明。聲明由一個減号(-)開始,這表明這是一個執行個體方法。方法實際的名字(insertObject:atIndex:)是所有方法辨別關鍵的級聯,包含了冒号。冒号表明了參數的出現。如果方法沒有參數,你可以省略第一個(也是唯一的)方法辨別關鍵字後面的冒号。本例中,這個方法有兩個參數。

圖2 方法聲明文法

O“.NET研究”bjective-C入門

  當你想調用一個方法,你傳遞消息到對應的對象。這裡消息就是方法辨別符,以及傳遞給方法的參數資訊。發送給對象的所有消息都會動态分發,這樣有利于實作Objective-C類的多态行為。也就是說,如果子類定義了跟父類的具有相同辨別符的方法,那麼子類首先收到消息,然後可以有選擇的把消息轉發(也可以不轉發)給他的父類。

  消息被中括号( [ 和 ] )包括。中括号中間,接收消息的對象在左邊,消息(包括消息需要的任何參數)在右邊。例如,給myArray變量傳遞消息insertObject:atIndex:消息,你需要使用如下的文法:

[myArray insertObject:anObj atIndex:0];      

  為了避免聲明過多的本地變量儲存臨時結果,Objective-C允許你使用嵌套消息。每個嵌套消息的傳回值可以作為其他消息的參數或者目标。例如,你可以用任何擷取這種值的消息來代替前面例子裡面的任何變量。是以,如果你有另外一個對象叫做myAppObject擁有方法,可以通路數組對象,以及插入對象到一個數組,你可以把前面的例子寫成如下的樣子:

[[myAppObject getArray] insertObject:[myAppObject getObjectToInsert] atIndex:0];      

  雖然前面的例子都是傳遞消息給某個類的執行個體,但是你也可以傳遞消息給類本身。當給類發消息,你指定的方法必須被定義為類方法,而不是執行個體方法。你可以認為類方法跟C++類裡面的靜态成員有點像(但是不是完全相同的)。

  類方法的典型用途是用做建立新的類執行個體的工廠方法,或者是通路類相關的共享資訊的途徑。類方法聲明的文法跟執行個體方法的幾乎完全一樣,隻有一點小差别。與執行個體方法使用減号作為方法類型辨別符不同,類方法使用加号( + )。

  下面的例子示範了一個類方法如何作為類的工廠方法。在這裡,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];      

  協定和代理

  協定聲明了可以被任何類實作的方法。協定不是那些類本身。他們僅是定義一個接口,其他的對象去負責實作。你實作了協定裡面的方法,就叫做符合協定。

  在iPhone OS中協定常用來實作委托對象。委托對象就是一個對象以其他的對象的模式行事。了解協定,委托和對象最好的辦法就是看一個例子。

  UIApplication類實作了一個程式需要的行為。如果想接收程式目前狀态的簡單消息,并不需要強制你建立UIApplication的一個子類,反之UIApplication類通過調用委托對象的指定方法來分發這些通知消息。實作UIApplicationDelegate方法的對象都可以接受這樣的通知,并進行響應的反應。

  協定的聲明跟類接口的聲明很像,隻是協定沒有父類,而且他們不會定義任何執行個體變量。下面的例子展示了一個有一個方法的協定聲明:

@protocol MyProtocol
- (void)myProtocolMethod;
@end