Objective-C 學習筆記 (1) - 概念

Objective-C

Objective-C 是 C 的超集合(意即包含 C 在其內,並在其上加入自己的東西),是在 C 的基礎上加入物件導向的特性擴充而成,所以 Objective-C 可以使用任何 C 所寫的程式。Objective-C 的物件導向語法源於 Smalltalk 訊息傳遞風格,所有其他非物件導向的語法,包括變數型別、前處理器 (preprocessing)、流程控制、函式宣告與呼叫皆與 C 語言完全一致。(資料來源:Wiki Objective-C)
在 Mac OS X 上的 API 名稱為 Cocoa,在 iOS 上的 API 名稱為 Cocoa Touch。由於 NEXTSTEP 作業系統是使用 Objective-C 研發的,所以 API 中會保留 NS 的前綴字,例如:NSObject。

Objective-C 我也是第一次學,所以學習上我會習慣把其他物件導向語言 (例如 Java) 拿來類比,例如 Objective-C 中的方法稱作「訊息 (Message)」,但它其實和方法 (method) 或函式 (function) 的運作概念雷同,只是在 Java 中我們會「呼叫方法」,但在 Objective-C 中我們會說「傳遞訊息」。

類別

如果你有寫過 C 語言,那 Objective-C 的類別定義其實和 C 一樣,會分成 2 個檔案,一個是以 .h (header) 為副檔名的介面檔,一個是以 .m (implement) 為副檔名的實作檔。

分成兩個檔的用意是為了資訊隱藏,介面檔 (.h) 會告訴其他類別,它提供什麼訊息(方法)及屬性,在介面檔中看得到的訊息(方法)名稱才能夠被傳遞(呼叫),所以如果有類別內部自己要使用的訊息(方法),就可以不寫在介面檔,而寫在實作檔 (.m)。

實作檔會實做所有程式邏輯,這些內部怎麼運作的內容,其他類別完全不知道,它們只知道介面檔中所提供的訊息(方法),當它們需要某個類別為它們做事時,就會傳遞訊息(呼叫方法)給該類別的訊息(方法)名稱。

下面就是類別的範例:

Car.h

//定義以 @interface 起頭,後接類別名稱
//冒號表示繼承, NSObject 是 Objective-C 中所有物件的起源
@interface Car : NSObject
{
//在大括號中是屬性宣告
NSString *color;
int price;
}
//訊息(方法)放在大括號之下
- (void)move;

//結尾一定要有@end
@end

Car.m

//實作以 @implementation 起頭,後接類別名稱
@implementation Car
//所有訊息(方法)的實作全部寫在這裡,
//名稱格式要和介面中寫的一樣,
//然後在大括號中實作程式邏輯
- (void)move
{
//...
}
//一樣結尾要有 @end
@end
以上範例就是一個類別的基本結構。

屬性及資料型態

前面的範例中有宣告 2 個屬性,其中 NSString 及 int 就是資料型態,用來指定該變數能儲存什麼類型的資料。變數名稱前面加 * (星號)表示其為指標,在Objective-C 中只要是物件變數,其名稱前一律都要加 * (星號) 以指標方式存在,非物件變數像是 int,就沒有 * (星號) 表示它並非指標。

指標是什麼,可以看一下 wiki 中的解釋。但簡單來說,變數是用來儲存資料的,只是指標變數儲存的是記憶體位址,而非直接使用的資料。例如 *color 存的會是記憶體位址 1234,而 1234 這個位址的資料是"白色",白色才是我們要的資料。而 int 直接就會儲存 100,100就是我們要的資料。兩者的差別只在一個是直接儲存資料,而一個是儲存該資料的位址。

訊息(方法)

前面範例的方法宣告為
- (void)move;
訊息前面的符號有兩種:減號 (-) 及加號 (+) 。減號 (-) 表示這個方法是物件的方法,也就是將類別實體化成物件後才能呼叫。而加號 (+) 表示這個方法是類別的方法,不需實體化就可直接呼叫。

後面緊接著括號,是回傳值的資料型態,void 表示沒有回傳值。接著就是此方法的名稱了。

物件

將類別實體化就會成為物件,實體化的方式如下:
Car *car = [[Car alloc] init];
分解動作:
Car *car;
*car = [Car alloc];//這裡是呼叫類別方法,取得記憶體空間
car = [car init];//這裡是呼叫物件方法,初始化物件
一般來說都會使用上面的寫法,分解動作只是為了說明這裡面做了哪些事。

第 1 動:宣告一個可以儲存 Car 資料型態的物件 *car;
第 2 動:使用 alloc 訊息(方法) 向系統要一個記憶體空間,並儲存其位址;
第 3 動:將該位址所儲存的資料使用 init 訊息(方法)初始化。

物件必須分配一個記憶體空間並初始化後才可使用。所有物件的祖先都是 NSObject(都繼承它),而 NSObject 中有 alloc (allocate, 分配之意) 這個方法,所以每個類別都能呼叫 alloc 來實體化,alloc 之後,該物件就產生了。這時候還不能用,每個物件都有一個預設的初始化方法 init ,所以即使我們沒有宣告此方法,還是必須呼叫它,整個實體化過程才會完成。

Objective-C 中呼叫方法(或稱傳遞訊息)的方式非常獨特,它是使用中括號來呼叫,如下:
[類別 類別方法];
[物件 物件方法];

所以要讓車子移動就會這樣寫:
[car move];
如果轉換成 Java 會像這樣:
car.move();
而且方法的呼叫是可以套疊的,就像一開始的例子:
Car *car = [[Car alloc] init];
當 alloc 完後會回傳 car 實體,car 實體再呼叫 init,以套疊方式完成一連串動作。
一開始學的時候超不習慣,但後來習慣了反而還滿喜歡 Objective-C 的寫法。
本文網址:http://blog.tonycube.com/2012/11/objective-c-1.html
Tony Blog 撰寫,轉載時請註明出處及文章連結,謝謝 😀

我要留言

留言小提醒:
1.回覆時間通常在晚上,如果太忙可能要等幾天。
2.請先瀏覽一下其他人的留言,也許有人問過同樣的問題。
3.程式碼請先將它編碼後再貼上。(線上編碼:http://bit.ly/1DL6yog)
4.文字請加上標點符號及斷行,難以閱讀者恕難回覆。
5.感謝您的留言,您的問題也可能幫助到其他有相同問題的人。