Objective-C 程式設計/概念
| 請更正此作品的標題,使其符合華夏公益教科書的命名規則。 您可以透過重新命名所有受影響的頁面和連結(包括此頁面)來提供幫助。 您也可以分享您的想法,或在專案室尋求幫助。 |
有一些關鍵的Objective-C概念與面向物件程式設計的實踐密切相關。目前,我們不會先看具體的語法。
- 如果您有面向物件程式設計的經驗,您可能希望跳過這些部分並檢視“摘要”部分。
Objective-C 中的面向物件與 C++ 有些相似,是一種像 C 樣式結構體一樣組織記憶體的方式,不同的是,它預期這些結構體包含指向函式的指標,這些函式可以引用定義為例項變數或函式指標的任何偏移量,因此物件是一個記憶體位置,從中可以找到例項變數的偏移量,並且有一個指向類定義的指標,該指標給出類函式的地址。
在 C++ 中,要從類的一個成員函式呼叫一個成員函式,語法是
this -> func ( a, b );
或
(*this).func (a, b);
這表示指向“this”物件的指標,它是定義了使用“this”的函式的類的例項。
在 Objective-C 中,'self' 是替換 'this' 的關鍵字,呼叫方式為
[self func: a, b ]
因此在這裡,函式的引數沒有像大多數其他基於 C 的語言那樣用括號括起來,而是
當需要呼叫父類的建構函式時,Java 中的建構函式在子類的建構函式中這樣呼叫。
Child( a, b, c ) { super(a); this.b = b; this.c = c; }
類似地,在 Objective-C 中,對於類介面
@interface MyClass : MyParentClass {
MyClassB * b;
int c;
}
@property (copy, nonatomic) NSInteger d;
-(void) func1; -(void) func2: (int)param1, (id) param2; @end
有一個省略的 init 建構函式,以及
建構函式可能是
- (id) init: (id)a, (id) b, (int) c , (NSInteger) d {
self = [super init:a ]; // -(2)
if (self) {
_b = [[B alloc] initByCopy:b] ;
_c = c;
self.d = d;
}
return self;
}
並且存在 MyParentClass 的建構函式,它是
- (id) init: (id) a // - (2a)
{ .. }
上面的例子展示了
- id 是類型別的佔位符。
- 在函式宣告或定義中,通常將圓括號放在返回值型別周圍,並在每個引數之前給出它們的型別。
- self 是一個提供的例項變數,引用類的一個物件,但最初可以是超型別的物件,如 (2) 和 (2a)。
- 慣例是呼叫 alloc,它是一個類函式,用於類獲取物件,然後透過呼叫一個物件函式來初始化物件,該函式通常是 'init' 或以 'init..' 開頭,因此模式是 my_object = [[A_Class alloc] init:a_param1, a_param2],這意味著“為由 A_Class 模板化的物件分配記憶體,然後使用 a_param1 和 a_param2 在物件上呼叫 init”。
- 一些簡單的 C 語言型別,例如 int、double、char*,可以用以 NS 開頭的更復雜的類來表示。
- 在上面的例子中,_b 和 _c 沒有 self 在前面,但 d 有。d 在類介面宣告部分定義為屬性。屬性具有省略的 set/get 函式,用於例項變數,並且可以具有屬性屬性,例如 (copy, nonatomic) - copy 表示 "self.d = d" 等效於 "self.d = [ [NSInteger alloc] initByCopy:d ],其中 NSInteger 是 d 的類。
- 記住 Objective-C 是 C 的擴充套件,變數名通常是指一個 4、8 或 16 位元組的短序列,它們要麼表示數字(int、long、float、double、char),要麼表示地址(char*、類例項指標)。這有點不像 Java,在 Java 中,變數是對物件的引用,物件是如何引用的,以及它們的記憶體是如何管理的,都被省略或隱藏了。Objective-c 框架後來在 NS.. 類家族中添加了引用計數自動釋放記憶體管理。
Objective C 中可以使用 C 中可用的任何標準 Unix 庫,因此這包括對服務(如檔案輸入/輸出、動態(malloc/free)分配、字串函式、數學函式、程序建立、同步和程序間通訊)的標準系統介面,透過檔案鎖、執行緒鎖、執行緒條件變數、訊號量、管道、套接字、共享記憶體管理、訊號。但是,Objective C 允許將資料結構與方法分組,併為 GUI 構建等領域提供面向物件模式(如多型性和委託(透過 Objective-c 的“協議”功能))的快捷組織結構化程式設計。其他功能還包括自動引用計數,因此動態分配的物件在沒有垃圾回收的情況下被自動釋放。這導致了標準作業系統介面函式 (malloc/free) 被標準 Objective c. 物件中的 NSObject 替換。面向物件習慣用法,例如
NS<some class>* p = [[NS<some class> alloc] init] ;
對於熟悉點語法(例如 Java)的人來說,意味著與以下相同
MYClass p = (MyClass.alloc()).init();
“呼叫靜態工廠類方法 alloc(),並在物件上呼叫 init()。”
在 C 中,只有
MyStruct * p = malloc ( size of(MyStruct));
稍後,指標 p 可能會與另一個指標(比如 q)共享記憶體地址,並且會有 2 個引用,然後如果稍後,q = z,甚至更晚 p= z,但等等,存在記憶體洩漏,所以必須對 p 呼叫 free(),因為它是對上面 malloc 呼叫產生的記憶體分配的最後一個引用。
free(p);
在舊的 Objective C 框架中,
[p dealloc];
但是,自動引用計數或 ARC,意味著當 p = z 時,在上面的例子中,p 指向的 NS 物件的引用計數降為零,並且在 ARC 支援框架持有的隱藏指標上呼叫 free()。
示例 2,而不是
char * charbuf[maxlength]; snprintf ( charbuf, maxlength-1, "hello %s , %d times!", "world", 2);
有
NSString* mystrbuf = [[NSString alloc] initWithFormat: "hello %s , %d times!", "world", 2];
面向物件程式設計(通常縮寫為 OO 或 OOP)是一種程式設計正規化,其中程式碼以稱為類的單元編寫,其中與資料結構相關的函式一起宣告和定義。例如,ANSI C 在structs 中有資料,類似地,面嚮物件語言將資料儲存在類或物件中,但也宣告對結構化資料(物件)的例項進行操作的函式。類本身可以是一個物件,具有相關的資料和類函式,但每個程序空間只有一個例項。(通常,作業系統為每個正在執行的程式提供一個程序,但允許多程序程式,這些程式是啟動其他程式的程式)。
例如,如果您正在建立一個文字處理器,您可以用一個物件來表示文件,該物件以文字作為其資料,並與其關聯不同的任務以對文件的資料執行操作,例如“拼寫檢查”。
然後,文字處理器將是一個小型程式,它可能會繪製視窗並顯示文件的文字。一個拼寫檢查按鈕將在該文件的物件上執行“拼寫檢查”任務。
但是,如果我們同時編輯兩個文件,它們可能在文件內容方面不同 - 資料。但所有文件或多或少都是相同的:每個文件都包含一個用於其文字的空間,並且具有幾個定義的任務,這些任務對文字進行操作。每個文件物件本質上具有相同的形式。我們稱這種形式為物件的類,並且我們通常給它一個名稱。讓我們呼叫文件類Document(風格說明:我們通常將類名大寫)。
現在,每個文件物件都具有Document的形式。我們說每個文件物件都是Document的一個例項。因此,例如,我們的文字處理器操作的是Document類的例項。有時,我們可能會將Document類的例項稱為“一個Document".
記住,每個物件都包含一些資料。例如,對於Document類,每個Document都包含用於儲存文件文字的資料。我們將每個物件儲存的資料稱為例項變數。因此,一個Document可以指定一個例項變數來儲存文字,或者指定一個例項變數來儲存字數統計、作者或我們可能要指定的任何其他資料。每個Document都擁有與任何其他可能存在的Document的例項變數分開的例項變數。
每個物件還可以執行一些針對其例項變數的操作。在 Objective-C 中,我們將這些操作稱為方法。物件的方法對物件的例項變數進行操作。
但是,物件不僅僅是這些。在 Objective-C 中,我們可以使用物件做很多有趣的事情。
讓我們繼續使用文字處理器的例子。假設我們要建立一個Document的新例項,以便我們可以對其進行操作。這個過程稱為例項化。
現在我們有了物件的一個活動例項,我們可以透過使用物件的方法來對其進行操作。我們將在後面學習定義和使用方法。每個方法只是像 C 中的函式一樣工作,在 Objective-C 中,只是語法略有變化。
當我們完全完成對物件的處理並想要刪除它(使其不再佔用記憶體)時,我們執行銷燬或釋放物件的操作。這就像free一個malloc的陣列,例如,在 C 中。但是,如果我們在使用物件方法的過程中為其例項變數分配了一些額外的記憶體,我們也必須釋放這些記憶體。
在建立新類時,我們可能希望將新物件的行為基於我們之前建立的類。例如,如果我們想建立一個包含樣式資訊細節的文件類,我們可能希望將該類基於我們之前建立的`Document`類。
這是一個非常常見的特性,它包含在面向物件的系統中,被稱為繼承。當一個類從另一個類繼承時,新類將繼承舊類的形式,並且可以新增額外的例項變數和方法。
因此,如果我們想建立一個`StyledDocument`類,我們將從`Document`類繼承。在 Objective-C 中,一個類只能從另一個類繼承。這被稱為單繼承。
與現實世界一樣,物件的使用方式和物件的工作方式之間存在著分隔。例如,對於我們的文字處理器,拼寫檢查器有一個一致的介面(如何使用它),例如,按鈕可以跳轉到下一個拼寫錯誤的單詞、返回和更正。但是,在幕後,拼寫檢查器的工作方式(實現)可以透過很多不同的方式完成。
在 Objective-C 中,介面和實現是分開的。這允許不同的物件以一種定義明確的方式協同工作和連結。例如,要切換電影片道,您使用電視機上按鈕的介面,而不是開啟電視機並擺弄電子裝置。
將實現與介面分開意味著我們可以更改實現中的任何內容(甚至用另一個實現替換它),並且一切仍然可以正常工作,因為物件(按鈕等)僅透過它們的介面相互互動。
因此,在我們學習 Objective-C 語法之前,讓我們回顧一下
- 物件是類的例項
- 它定義了稱為方法的任務
- 以及稱為例項變數的資料
- 它定義了稱為方法的任務
- 一個類可以從另一個(且僅一個)類(單繼承)繼承