iOS學習筆記之 Objective-C (二)

上一篇文章 java

結尾草草地寫了這麼個Demo:定義一個Student類,實例化出一個xiaoming的對象,並同時使用python和java與Objective-C實現它們。這段代碼只是演示了一些最基本的OC語法,但也留下了幾個令初學者費解的問題:python

  1. NSObject 是什麼鬼?objective-c

  2. 並無寫構造方法, OC 裏真的沒有構造方法嗎?segmentfault

  3. self 是什麼鬼?數組

  4. OC 裏已經演示瞭如何繼承和封裝,但如何實現多態呢?框架

帶着這些問題,咱們繼續探討。this

Objective-C中的類和 NSObject

C語言中有相似對象的結構體,它能夠保存一些相關的數據,在 OC 裏則實打實地實現了類的概念。編碼

向類發送 alloc 消息後就能夠爲其分配一個對象的內存空間(從語法層面上看, Javapython 是沒有這一步的)。然而此時對象並無被「構造」出來,你還須要爲其發送 init 消息。 init 是什麼呢?答:是 NSObject 對象的構造方法。指針

初識 NSObject

那麼 NSObject 是什麼呢?答:它是 OC 中大多數類的父類。儘管不像單根的 java 那樣是全部類的父類,但咱們暫時能夠不用在乎這些細節。另外要說明一點的就是, OC 是單繼承的,即一個子類不可能同時繼承自多個父類。code

諸如 allocinit 這些方法都是 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類型的變量時請務必不要加 * ,不然會報錯。

nilCjava 中的 NULL 相同,表明空對象, nil 並不會存在於內存中,因此當 *xiaoming=nil 時,指針 xiaoming 將不會指向內存中的任何一個區域。這也是釋放內存的方法之一——指向原對象的指針指向 nil 後,堆內存的那一坨對象就少了一處被引用,若是任何指針都沒有引用那坨對象,OC會自動釋放那坨對象所佔的內存。 OC 的內存管理我也搞不清,之後再探討。

還有一種比較少用的首字母大寫的 Nil ,它和 nil 的區別僅在於前者用來表示指向一個「不存在」的類。nil和Nil在使用上是沒有嚴格限定的,它們倆能夠相互替代。

再補充一個東西吧: NSNullnil 同樣,也表示空,但前者擁有一個有效的內存地址,而且,這貨是繼承自 NSObject 的。實際應用中,它常在可變數組這類東東里出現,咱們暫時不去深刻,知道就好。

瞭解 selfsuperisa

selfjava 中的 thispython 中的 self 相似,它是一個指向類或實例自己的指針,id類型。它是類或對象的隱藏參數。

superjavapython 中的 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 裏是有權限修飾的: protectedpublicprivate ,這些權限在 OC 裏也存在,但方法略有不一樣。

對於屬性來講,OC提供了一些關鍵字修飾屬性,默認是protected: @protected@public@private 。另外還有 @package 權限——變量在框架內爲 protected,對於框架外則是私有的。

OC裏,沒有「包」的概念。

// ...
  {
  @public 
    int i;
  @private 
    NSString *name;
  }
  // ...

對於方法來講, OC 並無提供權限修飾符,但能夠經過聲明的位置來決定方法是不是私有:若是方法聲明在 *.h 文件中,就是公有,若是在 *.m 文件,則是私有。

關於 NSObject 的介紹,這裏還不是很全面,接下來該說說 OC 中的一些經常使用類型了。

未完待續。

相關文章
相關標籤/搜索