上一篇文章 java
結尾草草地寫了這麼個Demo:定義一個Student類,實例化出一個xiaoming的對象,並同時使用python和java與Objective-C實現它們。這段代碼只是演示了一些最基本的OC語法,但也留下了幾個令初學者費解的問題:python
NSObject
是什麼鬼?objective-c
並無寫構造方法, OC
裏真的沒有構造方法嗎?segmentfault
self
是什麼鬼?數組
OC
裏已經演示瞭如何繼承和封裝,但如何實現多態呢?框架
帶着這些問題,咱們繼續探討。this
NSObject
C語言中有相似對象的結構體,它能夠保存一些相關的數據,在 OC
裏則實打實地實現了類的概念。編碼
向類發送 alloc
消息後就能夠爲其分配一個對象的內存空間(從語法層面上看, Java
和 python
是沒有這一步的)。然而此時對象並無被「構造」出來,你還須要爲其發送 init
消息。 init
是什麼呢?答:是 NSObject
對象的構造方法。指針
NSObject
那麼 NSObject
是什麼呢?答:它是 OC
中大多數類的父類。儘管不像單根的 java
那樣是全部類的父類,但咱們暫時能夠不用在乎這些細節。另外要說明一點的就是, OC
是單繼承的,即一個子類不可能同時繼承自多個父類。code
諸如 alloc
和 init
這些方法都是 NSObject
自帶的,所以,理論上說,全部繼承自 NSObject
的子類都會自帶這些方法。
因而咱們回過頭來再看 xiaoming
的誕生過程,這裏面就大有文章了:
Student *xiaoming = [[Student alloc] init]; /* 1. 對Student類發送allc消息,告訴它分配內存; 2. 調用初始化方法init,完成構造。 3. 將完成構造的Student對象的內存地址賦給指針變量xiaoming */
這裏的 init
,實際上就是發送給 NSObject
發送的消息(或者說是調用了 NSObject
的構造方法,發送消息這種「術語」,提及來真彆扭~)。咱們徹底能夠爲本身的類指定本身的初始化方法,但在此以前,先了解一些別的東西。
id
有一種空虛叫 nil
id
是一個指向任何一個繼承了Object(或者NSObject)類的對象,由於能夠用來作泛型,有時候也叫泛型指針,但這裏所謂泛型的實現方式和 java
有比較大的差異。
須要注意, id
自己就表示指針,因此定義id類型的變量時請務必不要加 *
,不然會報錯。
nil
和 C
或 java
中的 NULL
相同,表明空對象, nil
並不會存在於內存中,因此當 *xiaoming=nil
時,指針 xiaoming
將不會指向內存中的任何一個區域。這也是釋放內存的方法之一——指向原對象的指針指向 nil
後,堆內存的那一坨對象就少了一處被引用,若是任何指針都沒有引用那坨對象,OC會自動釋放那坨對象所佔的內存。 OC
的內存管理我也搞不清,之後再探討。
還有一種比較少用的首字母大寫的 Nil
,它和 nil
的區別僅在於前者用來表示指向一個「不存在」的類。nil和Nil在使用上是沒有嚴格限定的,它們倆能夠相互替代。
再補充一個東西吧: NSNull
和 nil
同樣,也表示空,但前者擁有一個有效的內存地址,而且,這貨是繼承自 NSObject
的。實際應用中,它常在可變數組這類東東里出現,咱們暫時不去深刻,知道就好。
self
、 super
和 isa
self
和 java
中的 this
或 python
中的 self
相似,它是一個指向類或實例自己的指針,id類型。它是類或對象的隱藏參數。
super
和 java
或 python
中的 super
同樣,表示指向父類,書上說,它是個編譯器指示符,不明覺厲,然而這並不影響咱們使用。
isa
是對象指向本身的類的指針,也是 id
類型,每個繼承自 NSObject
的類的實例都有它。
以上只是對 NSObject
經常使用的一些概念的簡介,並不全。
咱們如今能夠寫一個類的構造方法了,上代碼:
#import <Foundation/Foundation.h> //------ interface ------ @interface Student: NSObject // 咱們用 property 替代 setter/getter @property NSString *name; @property int score; // 聲明構造方法1 -(id)initWithName:(NSString *) newName; // 聲明構造方法2 -(instancetype)initWithName:(NSString *) newName score:(int) newScore; @end //------ implementation ------ @implementation Student @synthesize name = _name; // 讓編譯器幫你生成getter/setter @synthesize score = _score; /* 構造方法1 start */ -(id)initWithName:(NSString *) newName{ /* 先調用父類指定的初始化方法 */ self = [super init]; /* 父類指定的初始化方法是否成功建立了父類對象? */ if(self){ // 初始化一些值 _name = newName; } // 返回初始化對象的新地址 return self; } /* 構造方法1 end */ /* 構造方法2 start */ -(instancetype)initWithName:(NSString *) newName score:(int) newScore{ /* 初始化方法的返回值類型也能夠是instancetype */ /* 這裏能夠調用另外一個指定的初始化方法 */ self = [this initWithName:newName]; /* 父類指定的初始化方法是否成功建立了父類對象? */ if(self){ // 初始化一些值 _score = newScore; } // 返回初始化對象的新地址 return self; } /* 構造方法2 end */ @end
但願經過上述代碼,能夠了解 OC
的類是如何實例化對象的,以及瞭解如何自定義構造方法。這裏要說明一點,按照 OC
的編碼習慣,構造方法名,或者叫初始化方法名,都是以 init
開頭的。
咱們再舉一個栗子,讓咱們的對象可以返回本身的類:
+ class { return self; // 類方法返回本身 } - class { return (id)isa; // 實例經過isa返回類 }
咱們知道 java
裏是有權限修飾的: protected
、 public
、 private
,這些權限在 OC 裏也存在,但方法略有不一樣。
對於屬性來講,OC提供了一些關鍵字修飾屬性,默認是protected: @protected
、 @public
、 @private
。另外還有 @package
權限——變量在框架內爲 protected,對於框架外則是私有的。
OC裏,沒有「包」的概念。
// ... { @public int i; @private NSString *name; } // ...
對於方法來講, OC
並無提供權限修飾符,但能夠經過聲明的位置來決定方法是不是私有:若是方法聲明在 *.h
文件中,就是公有,若是在 *.m
文件,則是私有。
關於 NSObject
的介紹,這裏還不是很全面,接下來該說說 OC
中的一些經常使用類型了。
未完待續。