類
面向對象的程序通常都是有各種各樣的對象構成的。基于Cocoa框架的程序可能用到了NSMatrix對象,NSWindow對象,NSDictionary對象,NSFont對象,NSText對象以及其他的許多種類的對象。程序中通常也是使用某個類的多個對象,而不是一個。比如,多個NSArray類的對象或者是多個NSWindow類的對象。
在Objective-C中,通過定義對象所屬的類來定義對象。類是一種類型對象的原型。其中聲明了屬于該類的每個對象的成員變量,并定義了該類所有對象都能使用的方法。
編譯器只會為一個類創建一個可以訪問的對象,那就是類對象。類對象知道如何去生成該類的對象。正是基于這種原因,類對象通常都會被稱為是工廠對象。類對象是類在編譯時期的版本。類對象生成的對象才是類的實例。程序中進行實際工作的都是由該類對象創建出來的實例對象。
類的所有實例共有一套方法集,但是各自都含有自身的實例變量。每一個對象的實例變量是自己獨有的,但是所有方法是共享的。
按照慣例,類名稱首字母一般是大寫的,例如Rectangle。實例變量的名稱首字母通常是小寫的,如myRectangle。
繼承
類的定義是具有追加性的。每一個從其他類派生而來的新類都繼承了其中的方法和實例變量。新的類知識簡單地對這些繼承的東西進行追加或者修改,而不需要復制其對應的代碼。
繼承把所有的類都關聯起來,從而形成一個具有唯一一個根節點的繼承關系圖。當編寫基于“Foundation framework基礎框架”的程序的時候,這個跟類就是NSObject。繼承圖中出了跟類之外的所有類都有一個超類,這個超類在繼承關系圖上距離跟類更進一步。任何類,包括跟類都可以是多個類的超類,其子類在繼承關系圖上距離跟類更遠一步。圖1-1展示了在繪圖程序中可能用到得類的繼承關系圖:
從上圖中可以看出Square類是Rectangle類的子類;Rectangle類Shape類的子類;Shape類是Graphic類的子類;Graphic類是NSObject類的子類。 繼承關系具有累積性。因此,Square類的對象擁有在Rectangle類,Shape類,Graphic類已經NSObject類中定義的方法以及實例變量。當然Square類的對象擁有在Sqaure類自身中定義的實例變量和方法。簡而言之,一個Square類的對象不僅僅是一個方形(square),同時也是一個矩形(rectangle),也是一個形狀(shape),也是一個圖形(Graphic),還是一個對象(NSObject)。
除了NSObject類之外的每一個類都可以被看做是對其超類的具體化。其后的每一個子類都是對這種累積繼承的修改。Square類中定義的只是把一個矩形rectangle變成是一個方形所需的最小修改。
在定義類的時候是通過聲明其超類來把該類連接到類的繼承關系圖中的。我們創建的每一個類都應該是另外一個類的子類,除非我們想要定義的是跟類。其中可選的超類是很多的。Cocoa中包含了NSObject以及幾個框架。其中就包含了超過250多種的類。其中有很多類是我們可以直接拿來在我們的程序中使用的。還有一些其他的類,我們可以根據我們的需要,通過定義其子類來對其進行修改。
上面說到的一些框架類幾乎定義了我們所需的全部東西,但是把某些詳細的實現留個了子類。因此我們只需要根據我們的需要編寫少量的代碼,而復用這些已有的東西來快速地編寫出可靠的代碼。
NSObject類
NSObject類是一個跟類,他不需要超類。其中定義了Objective-C中的對象以及對象交互所需的基本框架。通過繼承NSObject類,這種對象的行為能力以及與運行時交互的能力在其子類中傳播
開來。
不需要從別的類中繼承特殊行為的類至少應該是NSObject類的子類。因為該類的實例至少在運行時應該具有Objective-C對象所具有的基本能力。從NSObject類繼承這種能力和在新類中重新定義這些能力先比則更簡單并且更可靠。
注意:實現一個全新的跟類是一件十分復雜的任務,并且具有潛在的危險性。該類必須重復在NSObject類中已經完成的大量工作。比如分配實例,并把它與對應的類相關聯,并在運行時對其進行鑒別等。正是如此,我們應該使用Cocoa中提供的NSObject類來作為跟類。更多信息參見《NSObject 協議參考》一書中的“NSObject 類參考”章節。
繼承實例變量
當一個類對象創建一個新的實例的時候,該實例不僅含有其類中所定義的實例變量,還含有其類的超類中所定義的實例變量,還含有其超類的超類中所定義的實例變量,這樣依此類推知道根類。這樣以來NSObject類中定義的實例變量就成了所有對象都擁有的變量。正是isa 把一個對象和其對應的類聯系起來了。
圖1-2展示了一種可能的Rectangle類的實現,其中包含包含了Rectangle類中定義的變量,Shape類中定義的變量,Graphic類中定義的變量以及NSObject類中定義的變量。
類中定義實例變量并不是必要的。一個類可以只定義新的方法,而完全依靠繼承而來的那些實例變量。例如,Square類自身中就可以不用定義任何實例變量。
繼承方法
對象不僅可以訪問其類中定義的方法,還可以訪問其超類中定義的方法,以及其超類的超類中定義的方法,依此類推知道根類。例如,Square類的對象就可以使用Rectangle類,Shape類,Graphic類以及NSObject類中定義的方法。
因此,程序中的新定義的類可以復用在繼承關系圖圖中位于其上方的所有超類的代碼。這種繼承機制是面型對象編程的一個很重要的好處。當我們Cocoa提供的面向對象的框架類的時候,我們的程序就可以利用這些已經為該框架類編寫好的代碼功能。我們在程序中只需要根據需要增加一些代碼來完成特性的功能。
在繼承關系圖中,類對象也繼承了位于其上方的超類。但是由于類對象沒有實例變量,因此他們只是繼承了方法。
方法的覆蓋
繼承機制中有一個很有用的特殊情況:在定義新的類的時候,我們可以在新的類中實現在繼承關系圖途中和其超類中同名的函數。這個新的方法就覆蓋了原來的方法。新的類的實例將執行的是該新的方法而不是原來的方法。該新類的派生類繼承的也將是該新的方法而不是原來的方法。
例如,Graphic類中定義了display方法,而在在Rectangle類中是可以通過定義新的display的實現而覆蓋繼承而來的原有的display方法。Graphic類中的方法對于它的所有派生類都是可用的,而Rectangle類除外,Rectangle類將執行的是自身的Rectangle類的display方法。
盡管這種覆蓋機制可以阻止原來的方法被繼承,但是新類中的其他方法卻是可以跳過這個新的方法而使用原來的方法的。更多信息參見“向self和super發送消息”章節。
新定義的方法中是可以使用被他覆蓋的原來的方法的。此時,新的方法是對原有方法的更新或者是修改,而不是對其進行完全的替換。當繼承關系圖中的多個類都定義了同樣的方法,但是如果每一個的實現都使用到了被覆蓋的原來的方法的話,原來方法中的實現便會在這些類中蔓延開來。
盡管派生類是可以覆蓋繼承而來的方法的,但是派生類不能覆蓋繼承而來的實例變量。這是因為在為對象分配空間的時候,是為對象的每個實例變量,包括繼承而來的實例變量都要分配空間。因此不能企圖通過在派生類中定義與超類中同名的實例變量來覆蓋超類的實例變量。如果確實遇到了這樣的代碼,編譯時,編譯器會報告告警或者錯誤的。
抽象類
一些類在設計的時候就是希望被別的類繼承。這種抽象的類只是方法和實例變量組合起來,以便于可以被更加通用的派生類使用。這種抽象類自身是不完全的,但是含有能夠減輕其派生類代碼負擔的有用代碼。由于抽象類必須有派生類才顯得有意義,因此它們有時會被成為抽象的超類。
與其他的語言不同的是Objective-C語言中沒有專門的語法來標識一個類是抽象類,因此也不會阻止我們在程序中創建抽象類的實例。
在Cocoa中,NSObject類就是公認的這樣的抽象類。在程序中我們是不會直接使用到NSObject類的實例的。因為這樣做沒有任何用,這樣的對象將是一個泛化的對象,他沒有任何具體的功能 ? ?。
NSView類也是抽象類的一個例子。該類的實例可能會被偶爾使用到。
抽象類中通常含有的是用于定義程序結構的代碼。當我們定義這些抽象類的派生類的以后,這些派生類可以很方便地適應程序框架工作,并自動地相互配合工作。
下圖為今年部分iOS開發的視頻教程,因為不定時更新中故不做多的截圖,如果有iOS開發上的問題不懂或者需要視頻教程可以看我的個人簡介。
因為三月還沒結束,故不截圖,不定時更新中。