這個系列的內容與官方文檔 Objective-C 語言介紹的內容一一對應,總共分為以下幾個部分:
- 對象、類型、訊息
- 定義一個類
- 為對象分配記憶體並初始化
- 協議
- 屬性申明
- 分類與擴充
- 相關引用
- 快速枚舉
- 實現靜態行為
- 選取器
- 錯誤處理
- 線程
總體說來 Objective-C 與主流物件導向的語言如C#, java 有許多共通之處,其核心是建立在C上的一套動態運行時系統,它協助程式實現動態類型推定,記憶體回收等任務。類似於 IronPython 這種用靜態語言去做了一個動態運行時。
以下是第一部分筆記:
一種物件導向的語言
一個物件程式庫
一套開發工具
一個運行時
在執行個體對象中,變數是私人的,如果需要訪問則需要提供一個專用存取方法。
對象的 id 是一種獨立的資料類型 id
不論是執行個體對象還是類本身都可能有一個id
id anObject;
在物件導向的方法返回中,id 替換了 int 成為預設的傳回值類型,而在嚴格的c果中,仍然還使用 int.
nil 的 id 是 0
id, nil 和其它oc 的類型定義在 objc/objc.h 這個檔案中。
isa pointer 這個指標指向了一個對象是何種 Class 的執行個體。
id 只對運行時的對象有效,它的值是“動態”的,因此不能在編譯時間通過它擷取更多的資訊。
動態類型體系在 oc 中被稱作 "dynamic binding" 動態類型綁定。
運行時在 isa 變數中儲存一些資料結構,因此你可以執行一個對象是否實現了一個方法或者擷取它的父級類等操作。
類是一種特殊的對象,它可以提供靜態方法的實現。
關於記憶體管理:
oc 提供兩種機制來完成記憶體管理:
1. 引用計數
2. 記憶體回收
關於對象訊息:
要讓一個對象執行一個 function ,方法是給它傳遞一個 “訊息”, 格式:
[receiver message];
因為方法名通常用來選定一個方法的實現,因此訊息中的方法名一般被稱為“選取器 selector”
使用舉例:
[myRectangle setOriginX: 20.0 y: 50.0];
在這個例子中,選取器就是 setOriginX:y: 注意它包含了冒號,但是並不指定傳回值。
在 oc 中,參數名不可省略,順序不可改變,也不能使用具名引數象python那樣。
必選參數用冒號,選擇性參數用逗號。
可以向 nil 發送 message 而不會報錯,這就是為何不使用“方法調用”而使用訊息的方式,因為nil 可以選擇不接受這個訊息,這是不是說就不用擔心在一個Null 物件上調用了方法而引發錯誤了?
下面這三段比較重要:
If the method returns any pointer type, any integer scalar of size less than or equal to sizeof(void*), a float, a double, a long double, or a long long, then a message sent to nil returns 0.
If the method returns a struct, as defined by the Mac OS X ABI Function Call Guide to be returned in registers, then a message sent to nil returns 0.0 for every field in the struct. Other struct data types will not be filled with zeros.
If the method returns anything other than the aforementioned value types, the return value of a message sent to nil is undefined.
方法天然獲得訊息接受方的執行個體變數訪問權。
關於多態
因為方法屬於對象,因此,訊息的結果取決於當前對象對此方法的實現。
關於動態綁定
一個方法調用與訊息模式的最大區別在於:在方法調用中,方法與它的調用對象之間的關係是確定的,而訊息傳遞中則不是這樣,它需要在運行時決定調用的到底是哪個方法。
當一個對象接受到一個訊息時,訊息息會掃描這個對象的方法表,找到匹配的方法並調用它,並且傳遞一個指向接受方襪例變數的指標給它(這個方法)
發送的訊息甚至都可以是一個動態。
動態解析
允許你在運行時實現一個 class 或者執行個體方法。
"." 運算子:
oc 提供使用“.”運算子來訪問 accessor methords:
myInstance.value = 10; 這個時候並不是真正地“訪問一個屬性”,只是一個文法糖,實際作用類同於 [myInstance setValue:10];
如查需要訪問一個對象的 its own instance variable:
self.age = 10;
如何理解一個對象“自己的屬性”?
即沒有在它的所屬 class 裡面定議過的屬性,因為沒有針對這個屬性的 accessor method ,所以要使用 self.XXX 的方法來訪問。
Graphic *graphic = [[Graphic alloc] init];
如何理解這段代碼?
是否相當於在類Graphic 上調用了一個 方法alloc 產生了一個執行個體,接著調用這個執行個體的 init 方法,最後將引用儲存在一個指標中。
不要使用“.”訪問非屬性的方法
不要使用“.”訪問唯讀屬性,因此你可能錯誤地給它賦值而造成一個執行階段錯誤。
關於類
每個類的建構函式相當於一個靜態方法,它負責產生這個類的執行個體,執行個體的方法是共用的,但是有自己的執行個體變數。
cocoa 提供超過 250個class, 有些你可以直接使用,有些需要你根據需要編寫子類來進行必要的擴充。
編寫基礎類是一件細緻的工具,不建議自己編寫基礎類,而應該使用 NSObject
Abstract Class 並不強制你執行個體化它, 但是你不應該那麼做。
可以使用靜態變數的方式實現單例模式。
initialization 方法提供在類型執行個體初始化的時候執行,為了保證它只執行一次,需要這樣寫:
+ (void)initialize
{
if (self == [ThisClass class]) {
// Perform initialization here.
...
}
}
這樣的話難道說在一個對象上調用一個方法,對象的方法和它的父級類的同名方法都會被依次調用?待確認。
下面這個是成立的:
[object class] != object_getClass(object) != *((Class*)object)
測試物件類型 :
if ([objectA class] == [objectB class]) { //...