跳轉至內容

Objective-C 程式設計/語法

來自 Wikibooks,開放世界中的開放書籍

Objective-C 是一種面向物件程式語言,它是在 C 程式語言 之上的一個層級。這意味著如果你知道如何編寫 C 程式碼,只需要學習一些語法上的變化。

在本節中,我們將探討如何在 Objective-C 中實現類並例項化物件。如果你不熟悉面向物件程式設計,請參考 Objective-C 概念.

基本語法

[編輯 | 編輯原始碼]

如果你已經學習過 C 語言,你可以跳過本節並繼續下一節,關於執行時的說明。如果你沒有學習過,或者有點生疏,請繼續閱讀。

在 C 語言中,程式碼包含在一個函式中。函式由多個語句組成,每個語句以分號結尾。例如,C 語言中一個簡單的加法函式可能如下所示

int add (int a, int b)
{
    int c;
    c = a + b;
    return c;
}

這個示例包含以下幾行

  1. 函式定義(返回一個 int(整數),名為 add,並接受兩個引數,都是整數)。// 整數是像 6、66 或 567 這樣的整數,而不是像 5.6 這樣的帶有小數位的數字。
  2. 函式的大括號開始
  3. 變數宣告
  4. 賦值語句
  5. return 語句,將 c 的值返回給呼叫函式/
  6. 函式的大括號結束

為了控制流,C 和 Objective-C 使用

  1. for (<initial>;<condition>;<increment>)
  2. while (<condition>)
  3. do ... while (<condition>)
  4. switch (<condition>)
  5. if (<condition>) then {<statements>} [else <statements>]

for、while 和 do 語句將繼續執行迴圈,直到條件為假。switch 和 if 語句根據條件跳轉到不同的語句。

Objective-C 預設情況下不會實現或匯入任何函式。相反,它們需要透過使用 #import 預處理指令來匯入。(#include 也可以工作,但通常在 Objective-C 中不使用它 - #import 工作得更好,因為它不會像 #include 那樣嘗試兩次匯入相同的東西)

關於執行時的說明

[編輯 | 編輯原始碼]

Objective-C 需要一個稱為 執行時系統 的東西來提供 Objective-C 特性。執行時負責物件的建立、管理和銷燬。

如果你有gcc編譯器,你應該已經安裝了 Objective-C 執行時。否則,你可能需要單獨安裝執行時。請注意,gcc 是一個編譯器集合;完整的安裝不僅包含 C 編譯器,還包含 C++、Java、Objective-C 甚至 Fortran-95 和 Ada 2005 編譯器。但是,可以只部分安裝 gcc,例如只安裝 C 編譯器。因此,Objective-C 執行時可能已安裝在 gcc 中,也可能未安裝。請檢查你的發行版。

兩個主要系統用於執行 Objective-C 程式

  • GNU 執行時,它作為 gcc 的一部分在 Unix 和類 Unix 作業系統上提供;
  • NeXT 執行時,它在 NeXTSTEP、OPENSTEP 和 Mac OS X 作業系統上提供。

本文件假設你使用的是 GNU 執行時,但這兩個執行時系統幾乎完全相同。

本文件沒有涵蓋 OPENSTEP、Cocoa 或 GNUstep 框架,但這裡學習到的技能在使用這些系統開發時會很有幫助。

在 Objective-C 中編寫類

[編輯 | 編輯原始碼]

編寫 Objective-C 類需要在開始編寫任何程式碼之前做出一些設計決策。假設我們正在編寫一個類來表示一個名為Point的點,它位於二維平面上。

我們需要問自己兩個問題

  1. 我們需要儲存和使用哪些資料?這與我們需要宣告的 例項變數 相關。
  2. 我們需要執行哪些操作?這與我們需要定義的 方法 相關。


對於這個示例,我們將使用double變數作為 xy 座標。我們將定義一個方法來獲取兩個座標,並將定義一個方法來獲取它們與原點的距離。

#import <objc/Object.h>

@interface Point : Object
{
@private
   double x;
   double y;
}

- (id) x: (double) x_value;
- (double) x;
- (id) y: (double) y_value;
- (double) y;
- (double) magnitude;
@end

讓我們檢查一下這個介面的每個元素的含義。

#import <objc/Object.h>
 
@interface Point : Object

@interface行表示我們開始宣告Point介面。我們從另一個名為Object的類繼承而來。Objective-C 為你提供了一個通用類,稱為Object。該Object類是一個 根類 ——它不從另一個類繼承。該Object類提供了一組方法,這些方法為物件提供關鍵功能,以便 Objective-C 執行時可以識別和使用它們。與 C 語言一樣,我們需要包含Object的標題檔案,Object.h,在我們使用標題檔案中宣告的方法之前。

如果你沒有顯式地從某個類繼承,你的類將成為一個根類。(在 Objective-C 中,可以有多個根類。)這可能不是你想要做的,因為建立根類是一個非常棘手且高階的主題,只有在非常特殊的情況下才有用。在大多數情況下,你將想要從Object或從Object繼承的某個類繼承,等等。如果你在 NeXTStep / GNUstep / Cocoa 中開發,你將主要使用另一個名為NSObject的根類,它提供了與Object.

不同的基本方法。該詞import意味著我們只包含該檔案 一次。這解決了遞迴包含問題。

{
@private
   double x;
   double y;
}

介面宣告中的大括號之間的任何內容都指定了類擁有的例項變數。

@private行是一個可見性修飾符:它表示它後面的例項變數是 私有 的,即它們只能被宣告它們的類訪問。將所有例項變數標記為私有是一種很好的做法:它們包含物件的狀態,它們不應被更改,除非由物件本身更改。

- (id) x: (double) x_value;

方法的宣告位於例項變數之後。這是一個設定 x 值的方法的宣告。在 Objective-C 中,通常使用與設定的變數相同的名稱命名 setter 方法。

連字元指定了一個例項方法(我們將在後面討論它們)。然後是方法的名稱(此方法稱為x- 注意冒號),冒號表示一個名為x_value的引數,其型別為double.

x_value引數的強制轉換是必要的,因為與 C 語言不同,預設型別是id,而不是int。型別id非常特殊——它是一種可以儲存 任何 物件的型別。第一個強制轉換嚴格來說不是必需的,但應用於清晰起見。第一個強制轉換告訴我們,該方法x返回一個物件。

- (double) x;

這是另一個名為x的方法(沒有冒號),但它返回一個double。這是獲取 x 變數值的規範。它與之前的方法沒有衝突,因為型別不同,並且之前的方法接受一個引數,而此方法不接受任何引數。

@end

在指定所有方法和例項變數之後,此符號標記宣告的結束。

介面規範位於.h檔案中——一個頭檔案。通常按照類名來命名檔案,因此我們將建立一個名為Point.h.

的檔案。

實現
#import "Point.h"
#import <math.h>

@implementation Point

- (id) x: (double) x_value
{
   x = x_value;
   return self;
}

- (double) x
{
   return x;
}

- (id) y: (double) y_value
{
   y = y_value;
   return self;
}

- (double) y
{
   return y;
}

- (double) magnitude
{
   return sqrt(x*x+y*y);
}

@end

[編輯 | 編輯原始碼]Point這是

#import "Point.h"

類的實現。我們在上面定義的介面中實現方法。讓我們依次檢視實現的每個元素。Point同樣,我們匯入

@implementation Point

的介面,就像我們在 C 語言中一樣。

- (id) x: (double) x_value
{
   x = x_value;
   return self;
}

這是一個標記,它標識實現的開始。x這是一個典型的方法實現。我們可以直接使用x_value變數,而無需宣告它,因為它已經在介面中宣告,並且只能被該類的 methods 訪問。總的來說,它的行為類似於普通的 C 函式。在這裡,我們將引數x.

的值分配給例項變數然後,該函式返回修改後的整個當前物件。關鍵字self

- (double) x
{
   return x;
}

代表當前物件。x這是獲取


變數值的簡單方法。我們只需返回它即可。其他方法的行為應該與上述方法類似。該@end

關鍵字結束實現。實現規範位於.m檔案中。通常按照類名來命名檔案,因此我們將建立一個名為.

Point.m

的檔案。

使用物件[編輯 | 編輯原始碼]這是使用我們剛剛建立的類的函式。這是一個典型的 main 函式。

#import "Point.h"
#import <math.h>
#import <stdio.h>

int main(void)
{
   Point *point = [Point new];
   [point x:10.0];
   [point y:12.0];
   printf("The distance from the point (%g, %g) to the origin is %g.\n",
      [point x], [point y], [point magnitude]);
    
   return 0;
}

讓我們來檢查一下這裡發生了什麼。

#import "Point.h"
#import <stdio.h>

我們匯入介面到Point以便我們可以使用它。我們匯入stdio.h以便我們可以使用printf.

    Point *point = [Point new];

這是一個典型的 Objective-C 方法呼叫

  • Point *point宣告,從技術上講,指向型別為Point的例項的指標。實際上,最好將其視為一個持有Point物件的變數,但請記住指標的概念。
  • [Point new]呼叫一個名為new的方法。空格之前的第一個部分表示我們呼叫方法的物件。第二個部分是方法名稱和引數。該new方法稱為類方法,因為它不針對類的例項執行操作,而是針對類本身執行操作。該new方法分配記憶體並初始化物件,使其可以使用。無需顯式刪除物件,因為 Objective-C 會跟蹤對給定物件的引用次數,並在必要時將其釋放。
    注意:該new方法是allocinit的簡寫,可能並不總是可用。如果不可用,則可以使用以下方式初始化物件並使其可以使用[[Point alloc] init]
    [point x:10.0];
    [point y:12.0];

這些是一些典型的例項方法呼叫。我們呼叫point的方法xy。在 Objective-C 術語中,我們說我們傳送point一條訊息以應用於該方法x.

這些訊息分配pointxy變數。回想一下,該xy方法包含return self;。這意味著我們可以將這兩個訊息連結在一起,如下所示

[[point x:10.0] y:12.0];

訊息[point x:10.0]返回一個物件,point,其x變數已設定。然後在該物件上,外部訊息將其y變數分配給它。

    printf("The distance from the point (%g, %g) to the origin is %g.\n",
       [point x], [point y], [point magnitude]);

printf語句包含方法呼叫[point x],它返回x變數的值以供列印,[point y],它對y變數執行相同的操作以供列印,以及[point magnitude]它計算距離並返回該值。


Objective-C 程式語言Objective-C 概念 - Objective-C 語法 - Objective-C 深入 - Objective-C 高階功能

華夏公益教科書