《Objective-C編程全解》 讀書筆記 第四章 對象的類型和動態綁定

第四章 對象的類型和動態綁定

動態綁定:程序在執行時才確定對象的屬性和需要響應的信息。

多態:指同一操作作用於不同的類的實例時,將產生不同的執行結果。多態是面向對象的一個重要的特徵,大大增強了軟件的靈活性和擴展性。

把類作爲類型去聲明:NSObject *a;  nil表空對象,即這個對象的指針指向空,值爲0。

將對象作爲參數傳遞的時候,傳遞的並不是對象本身,而是指向對象的指針。

靜態類型:將一個變量聲明爲特定類的對象,這種情況稱爲靜態類型。使用靜態類型時,編譯器可以在編譯時檢查接受者是否可以響應收到的消息。

靜態類型檢查的總結:
  • 對於id類型的變量,調用任何方法都能夠通過編譯。
  • id類型的變量和被定義爲特定類的變量之間是可以相互賦值的。
  • 被定義爲特定類對象的變量(靜態類型),如果調用了類或父類中未定義的方法,編譯器就會提出警告。
  • 若是靜態類型的變量,子類類型的實例變量可以賦值給父類類型的實例變量。
  • 若是靜態類型的變量,父類類型的實例變量不可以賦值給子類類型的實例變量。
  • 若要判斷到底是哪個類的方法被執行了,不要看變量所聲明的類型,而要看實際執行時這個變量的類型。
  • id類型並不是(NSObject*)類型

編程中類型的定義:
[ obj msg ] 消息表達式
obj是消息接收者,是一個對象。   msg是消息。
消息名又稱爲消息選擇器,選擇器,或方法。消息選擇器中並不包含參數和返回值的類型信息,消息選擇器和這些類型的信息結合在一起構成簽名。簽名被用於在運行時標記一個方法,接口文件中方法的聲明也叫做簽名。

如果消息接受者和參數類型是運行時確定的,那麼消息簽名不唯一的話編譯就會出錯。也就是說,objective-c中選擇器相同的消息,參數和返回值的類型也應該相同。

類的前置聲明:
當定義一個類的時候,有時會將類的實例變量,類方法的參數和返回值的類型來指定另一個類。這種情況有兩種方法實現定義:
1.在新定義的類的接口文件中引入原有類的頭文件。(該方法的缺點是頭文件中除了類名還有其他信息的定義,此外還可能引入其他頭文件,增加了編譯時的負擔如果僅僅是在類型定義的時候使用一下類名,則使用方法2來解決)
2.@class + 類名+”;",class指令後可以一次接多個類,中間用逗號隔開。該方法叫做類的前置聲明。(@class可以提升程序的整體編譯速度,而且當多個接口出現類的嵌套定義時如果只是包含對方的頭文件無法解決,通過類的前置聲明可以解決。但要注意的是,如果新定義的類要使用原有類的具體成員或方法,就一定要引入原有類的頭文件)

強制類型轉換:?
有些情況下必須使用強制類型轉換,一個典型的例子就是父類類型的指針實際上指向了子類的變量。
(除了id之外,指針變量只能調用編譯時類型的方法,不能調用它運行時的類型方法,故強轉)
雖然強制轉換的功能很強大,但會讓編譯器的類型檢查變得沒有意義,所以儘量少用。不得不用時,要重新思考設計是否合理。

實例變量的訪問權限:
只能訪問靜態類型定義的實例對象的內部變量。因爲能否訪問實例對象的內部變量是需要經過檢查的,該檢查在編譯期完成。

訪問器:
OC不允許直接從外部訪問和修改實例對象的屬性,而僅僅可以訪問同一個類的其他實例對象的變量,需要定義專門的方法來訪問或修改實例變量:
getter方法(讀取):從外部訪問這個屬性的方法應和屬性同名。
setter方法(修改):定義修改該屬性的方法時,用set做前綴,之後接要更改的屬性的名稱,屬性名的首字母大寫。
雖然子類的方法可以直接訪問父類的實例變量,但我們要養成一個好的習慣,即儘量使用getter/setter 方法來訪問父類中的實例變量,這樣可以使程序做到儘可能的低耦合。
爲什麼不允許直接訪問成員屬性?一切都是爲了封裝,使程序儘可能地低耦合。

實例變量的可見性:
@private:只能在聲明它的類內訪問,子類不可以訪問。可以在方法中通過->來訪問同一個類的實例變量。
@protected:能夠被聲明它的類和任何子類訪問。類方法中可以通過->來訪問本類實例對象的實例變量。沒有顯式指定可見性的實例變量都是此屬性。
@package:類所在的框架內可以像@public一樣訪問。而框架外則同@private一樣,不允許訪問。
@public:作用範圍最大,本類和其他類都可以直接訪問。

在實現部分中定義實例變量:
採用這種方法後,子類無法訪問父類的實例變量。在實現文件中定義的實例變量的可見性默認是@private,也可用@public等來重設可見性。
所以讓一個變量對外不可見有兩種方法,一種是把變量的可見屬性設爲@private,另一種就是把變量定義在實現文件中。

類對象:
在OC中,對類的定義分爲兩部分,一部分定義所生成的實例的類型,另外一部分定義類自身的行爲。
類本身也作爲一個對象存在。類對象有自己的方法和變量,分別被稱爲類方法和類變量,在OC中,只有類方法的概念,沒有類變量。至今爲止我們一直把類的實例變量和方法稱爲實例變量和實例方法,這樣可以和類變量和類方法進行區分。OC中類對象也被稱爲factory,類方法稱爲factory method。類對象是在程序運行時自動生成的。每個類只有一個類對象,不需要手動生成。類方法可以訪問類對象管理的變量。

類對象的類型:
類對象可以用id類型來表示,也可以用OC爲其專門定義的Class類型來表示。NSObject中定義了類方法class,所有類都可以用這個方法來獲取類對象。除此之外,NSObject中還定義了實例方法class,所有的實例對象都可以使用class實例方法,這個方法返回的是對象所屬類的類對象。

類名的使用:
將類名定義爲消息接受者是類對象特有的功能,除此之外類名只能在類型定義時使用。

類方法的定義:
實例方法以“-”開頭,類方法以“+”開頭。類方法的一個典型操作就是創建類的實例對象,類對象收到alloc這種消息之後就會生成類的實例。繼承情況下,子類可以訪問父類的類方法。類方法不能訪問類中定義的實例變量和實例方法。因爲類對象只有一個,而類的實例對象有任意個,所以如果類對象可以訪問實例變量,就會不清楚到底訪問的是哪一個實例對象的變量。
其次,類方法執行時用self代表了類對象自身。
alloc是類方法,dealloc是實例方法。

類變量:
OC不支持類變量。OC通過在實現文件中定義靜態變量的方法來代替類變量。繼承情況下,可以通過定義類方法(getter,setter)來進行訪問父類中定義的變量。

類對象的初始化:
OC的根類NSObject中存在一個initialize類方法,可以使用這個方法對各類對象進行初始化。每個類接收到消息之前,爲這個類調用一次initialize,調用之前先調用父類的initialize方法。如果子類中沒有實現initialize方法,其父類的initialize方法就會被調用兩次,面向自己一次,面向子類一次。

初始化方法的返回值:
之所以將返回值類型定義爲id,是因爲考慮到初始化方法的返回值不是具體的類的類型,而是可變的,取決於上下文。例如父類初始化返回值定義爲Volume*,則其子類調用父類初始化方法時返回的也是Volume。所以應將其定義爲id。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章