objective-c 關鍵字和概念

weixin_33866037發表於2017-04-09

關鍵字

@

看到這個關鍵字,我們就應該想到,這是Object-C對C語言的擴充套件,例如@interface XXX。

@interface

宣告類

@implementation

實現類

@protocol

宣告協議

@optional

與@protocol配合使用,說明協議中的某個或者某幾個方法可以不實現

@required

與@protocol配合使用,說明協議中的某個方法或者某幾個方法必須實現

@end

與@interface ,@implementation,@protocol配合使用,代表宣告或者實現結束

@encode

@encode為編譯器巨集,它可以將型別轉換為相應的字串。

id

id是指向Objective-C類物件的指標,它可以宣告為任何類物件的指標,當在Objective-C中使用id時,編譯器會假定你知道,id指向哪個類的物件。與void*是不同的是,void*編譯器不知道也不假定指向任何型別的指標。

nil

定義為一個常量,如果一個指標的值為nil,代表這個指標沒有指向任何物件。

self

在Objective-C中,關鍵字self與c++中this是同一概念,就是類物件自身的地址,通過self可以呼叫自己的例項變數和方法

Super

當子類需要呼叫父類的方法時,會用到Super關鍵字. Super指向的是父類的指標,子類重寫父類的方法時,呼叫父類的方法是一個比較好的習慣。因為當我們不知道父類在該方法中實現的功能時,如果不呼叫父類的方法,有可能我們重寫的方法會失去該功能,這是我們不願意看到的情況。

NSNull

NSNull是沒有的意思,如果一個字典的值為NSNull,那說明與該值對應的Key是沒有值的,例如Key為address,說明與address對應的是值是沒有。

self super class public protected private id

[self class] [super class]  selector

objective-c runtime reference

標準用法

self = [super init]

new

1 Objective-C有一個特性,就是可以把類當成物件來傳送訊息,這種用法通常用於新建對像時,例如 XXX *object = [XXX new];

類方法 +

如果想宣告屬於類而不屬於類物件的方法,用+。+用來修飾類的方法,使用+修飾的類方法,是整個類的方法,不屬於哪一個類物件,這與C++中的static在類中使用的概念一樣,

%@

在NSLog中,使用%@表示要呼叫物件的description方法。

概念

是一種結構,它表示物件的型別,就像int與 char 一樣,也可以宣告類的變數(對像)

例項化

為類的物件分配記憶體和初始化,達到可以使用該 類物件的目的。

物件(例項)

類的例項化後的產物

訊息

在Object-C中,類的物件執行的操作,是通過給該類或者該類物件傳送訊息實現,如:[object func];就是給object物件傳送func訊息,類似C++中的方法呼叫。給object物件傳送func訊息後,object物件查詢所屬類的func方法執行。

方法排程

當向一個物件傳送訊息時(呼叫方法),這個方法是怎麼被呼叫的呢?這就依賴於方法高度程式,方法排程程式查詢的方法如下:

在本類的方法中,找被呼叫的方法,如果找到了,就呼叫,如果找不到被沿著繼承路徑去查詢,從哪個類找到,就呼叫哪個類的方法,如果到最根上的類還是沒有找到,那編譯就會出錯。

繼承與複合

在Objective-C中支援繼承,但只是支援單一繼承(有且只有一個父類有),如果想使用多繼承的特性,可以使用分類和協議技術。

繼承是is-a,複合是has-a。複合是通過包含指向物件的指標實現的,嚴格意義上講,複合是針對於物件間來說,對於基本資料型別來說,它們被認為是物件的一部分。

裝箱與拆箱

由於NSArray,NSDirectory等類不能直接儲存基本資料型別,所以要想在NSArray\NSDirectory中使用基本資料型別,就得使用裝箱與拆箱。

在Objective-C中,可以使用NSNumber和NSValue來實現對資料型別的包裝,NSNumber可以實現對基本資料型別的包裝,NSValue可以實現對任意型別資料的包裝。

將基本型別封裝成物件叫裝箱,從封裝的物件中提取基本型別叫拆箱(取消裝箱),其它語言如Java原生支援裝箱與拆箱,Ojbective-C不支援自動裝箱與拆箱,如果需要得需要自己來實現裝箱與拆箱。

存取方法

在使用類物件的例項變數(成員資料)時,不要直接使用物件中的例項,要使用存以方法來獲取或者修改例項,既setter和getter,在Cocoa中,存取方法有命名習慣,我們得符合這種習慣,以便於與其它團隊成員合作。setter方法是修改或者設定例項值,命名習慣為set+例項名,例有一個類有path例項變數,那setter命名為setPath,getter命名為Path,為什麼不是getPath,因為get在Cocoa中有特殊的含義,這個含義就是帶有get的方法就意味著這個方法通過形參指標(傳入函式的引數指標)來返回值。我們要遵守這個命名習慣或者說規則。

在Objective-C 2.0中加入了@property和@synthesize來代替setter和getter,這兩個關鍵字為編譯器指令。 還有點表示式,存取類成員的值時,可以使用點表示式。

Object.attribute,當點表示式在=號左邊時,呼叫的是setter方法,在=號右邊時,呼叫的是getter方法。

@property 語法為:@property (引數) 型別 變數名.

在這裡主要說明一下引數.

引數分為三種:

第一種:讀寫屬性包括(readonly/readwrite/)

第二種:setter屬性(assign,copy,retain),assign是簡單的賦值,copy是釋放舊成員變數,並新分配記憶體地址給成員變數,將傳入引數內容複製一份,給成員變數。retain是將傳 入引數引用計數加1,然後將原有的成員變數釋放,在將成員變數指向該傳入引數。

第三種:與多執行緒有關(atomic,nonatomic).當使用多執行緒時,使用atomic,在不使用多執行緒時使用nonatomic

物件建立與初始化

在Objective-C中建立物件有兩種方法,一種是[類 new];另一種是[[類 alloc] init],這兩種方法是等價的,但按慣例來講,使用[[類 alloc] init];

alloc操作是為物件分配記憶體空間,並將物件的資料成員都初始,int 為0,BOOL 為NO, float 為0.0等。

初始化,預設的初始化函式為init,init返回值為id,為什麼回返回id呢,因為要實現鏈式表示式,在Objective-C中叫巢狀呼叫。

為什麼要巢狀呼叫??因為初始化方法init返回值可能與alloc返回的物件不是同一個?為什麼會發生這種情況?基於類簇的初始化,因為init可以接受引數,在init內部有可能根據不同的引數來返回不同種型別的物件,所以最會發生上面說的情況。

在初始化時,建議使用if (self = [super init])

便利初始化

當一個類需要根據不同的情況來初始化資料成員時,就需要便利初始化函式,與init初始化不同的是,便利初始化函式有引數,引數個數可以有1到N個,N是類資料成員個數。

指定初始化函式:什麼是指定初始化函式?在類中,某個初始化函式會被指定為指定的初始化函式,�確定指定初始化函式的規則是初始化函式中,引數最多的為指定初始化函式,

其它未被指定為指定初始化函式的初始化函式要呼叫指定初始化函式來實現。對於該類的子類也是一樣,只要重寫或者直接使用父類的指定初始化函式。上述文字有些繞,來個例子吧

@interface A{

int x;

int y;

}

-(id) init;

-(id) initWithX:(int) xValue;

-(id) initWithY:(int) yValue;

-(id) initWithXY:(int) xValue

yVal:(int) yValue;

@end

這裡initWithXY被確定為指定初始化函式。

-(id) initWithXY:(int) xValue

yVal:(int) yValue{

if (self = [super init]){

x = xValue;

y = yValue;

}

return self;

}

-(id) init{

if (self = self initWithXY:10

yVal:20){

}

return self;

}

.......

@interface B: A{

int z;

}

-(jd) initWithXY......;

@end

@implementation B

-(id) initWithXY:(int) xValue

yVal:(int) yValue{

if (self = [super initWithXY:10

yVal=20]){

z= 40;

}

return self;

}

@end

自動釋放池

記憶體管理是軟體程式碼中的重中之重,記憶體管理的好壞,直接影響著軟體的穩定性。在Cocoa中,有自動釋放池,這類似於C++中的智慧指標。

NSObject有一個方法是autorelease,當一個物件呼叫這個方法時,就會將這個物件放入到自動釋放池中。

drain,該方法是清空自動釋放池,不是銷燬它。drain方法只適用於Mac OS X 10.4以上的版本,在我們寫的程式碼中要使用release,release適用於所有版本。

自動釋放池是以�棧的方式實現,當建立一個自動釋放池A時,A被壓入棧頂,這時將接入autorelease訊息的物件放入A自動釋放池,這時建立一個新的B自動釋放池,B被壓入棧頂,建立完成後刪除B,這個接收autorelease訊息的物件依然存在,因為A自動釋放池依然存在。

引用計數

每個物件都有一個與之相應的整數,稱它為引用計數,當該 引用計數為0時,Objective-C自動向該物件傳送dealloc,以銷燬該對向,與該引用計數相關的方法(訊息)有下面幾個

1 增加引用計數:通過alloc,new,copy建立一個物件時,該物件的引用計數加1(其實就是1,因為之前為0)

2 增加引用計數: retain

3 減少引用計數: release

區域性分配記憶體(臨時物件):

1 如果使用alloc,new,copy建立物件,則需要主動呼叫物件的release方法

2 如果使用非alloc,new,copy建立物件,我們認為該 物件引用計數為1,並已經加入了自動釋放池,我們不需要主動的呼叫物件的release方法。

擁有物件(在類中以成員的方法存在):

1 如果使用alloc,new,copy建立物件,則需要在dealloc方法中,釋放該物件

2 如果使用非alloc,new,copy建立物件,則在擁有該物件時,保留該物件(執行retain方法),在dealloc方法中,釋放該物件。

dealloc

當物件的引用計數為0時,Objective-C會自動傳送物件的dealloc訊息(自動呼叫物件的dealloc方法,類似於C++的解構函式),所以我們可以自己重寫dealloc方法,來實現類裡的對其它使用資源的釋放工作。

注意:不要直接在程式碼中顯示呼叫dealloc方法。

垃圾回收

在Objective-C 2.0中引入了垃圾回收機制(自動管理記憶體),在工程設定裡設定Objective-C Garbage Collection為Required[-fobjc-gc-only]就可以使用垃圾回收機制。

啟用垃圾回收機制後,通常的記憶體管理命令都變成了空操作指令,不執行任何操作。

Objective-C的垃圾回收機制是一種繼承性的垃圾回收器,垃圾回收器定期檢查變數和物件以及他們之間的指標,當發現沒有任何變數指向物件時,就將該物件視為被丟棄的垃圾。所以在不在使用一個物件時,將指標他的指標設定為nil,這時垃圾回收器就會清理該物件。

注意:如果開發iPhone軟體,則不能使用垃圾回收。在編寫iPhone軟體時,Apple公司建議不要在自己的程式碼中使用autorelease方法,並且不要使用建立自動釋放物件的函式。

類別

什麼是類別?類別是一種為現有類新增新方法的方式。

為什麼使用類別或者說使用類別的目的是什麼?有以下三點:

第一,可以將類的實現分散到多個不同的檔案或多個不同的框架中。

如果一個類需要實現很多個方法,我們可以將方法分類,把分好的類形成類別,可以有效的管理和駕馭程式碼。

第二,建立對私有方法的前向引用。

第三,向物件新增非正式協議。

委託

委託的意思就是你自己想做某事,你自己不做,你委託給別人做。

在Ojbective-C中,實現委託是通過類別(或非正式協議)或者協議來實現。

舉個例子:Apple要生產iPhone,Apple自己不生產(種種原因,其中之一就是在中國生產成本低,他們賺的銀子多),Apple委託富士康來生產,本來富士康原來不生產iPhone,現在要生產了,所以他得自己加一個生產iPhone的生產線(類別,增加生產iPhone方法),這就是通過類別來實現委託。下面用程式碼來說明這個例子。

.....

Apple *apple = [[Apple alloc ] init];

Foxconn *fox = [[Foxconn alloc] init];

[apple setDelegate:fox];

[apple produceIPhone];

........

@implementation Apple

-(...) setDelegate:(id) x{

delegate  = x; //! 將委託的生產物件指定為x

}

-(...) produceIPhone{

[delegate produceIPhone]; //! 委託物件生產iPhone

}

@interface Foxconn : NSObject

...

@end

@interface NSObject(ProduceIPhone) //! Foxconn之前就可以生產其它產品,有過宣告和定義

-(...) produceIPhone  //! 增加生產iPhone能力

@end

@implementation NSObject(ProduceIPhone)

//! 生產iPhone

-(...) produceIPhone{

......

}

@end

非正式協議

建立一個NSObject的類別, 稱為建立一個非正式協議。為什麼叫非正式協議呢?

也就是說可以實現,也可以不實現被委託的任務。

拿上面的例子來說,Apple要求Foxconn除了能生產iPhone外,還有一個要求是在一定時間內完成.由於雙方沒有籤合同,所以時間要求和生產要求規格都是非正式協議

選擇器

選擇器就是一個方法的名稱。選擇器是在Objective-C執行時使用的編碼方式,以實現快速查詢。可以使用@selector預編譯指令,獲取選擇器@selector(方法名)。NSObject提供了一個方法respondsToSelector:的方法,來訪問物件是否有該方法(響應該訊息)。

拿上面的Apple請Foxconn生產iPhone為例,Apple怎麼知道Foxconn有沒有生產iPhone的能力呢?Apple就通過respondsToSelector方法詢問Foxconn,是否可以生產iPhone(是否可以響應produceIPhone),詢問結果是可以,那Apple就委託Foxconn生產,Foxconn就生產出來了人們比較喜歡的iPhone產品。

正式協議

與非正式協議比較而言,在Ojbective-C中,正式協議規定的所有方法必須實現。在Ojbective-C2.0中,Apple又增加了兩個關鍵字,協議中的方法也可以不完全實現,是哪個關鍵字見關鍵字部份的@optional,@required。

正式協議宣告如下:

@protocol XXX

-(...) func1;

-(...) func2;

@end

使用協議:

@interface Object : NSObject //! Object從NSObject派生,並遵循XXX協議,要實現func1,func2函式。

...

@end

習慣用法

分配記憶體和初始化

self = [super init];

物件間互動

在Objective-C中,所有物件間的互動都是通過指標實現。

快速列舉

for (Type *p in array)

注意:

Objective-C不支援多繼承

下圖為今年部分iOS開發的視訊教程,因為不定時更新中故不做多的截圖,如果有iOS開發上的問題不懂或者需要視訊教程可以看我的個人簡介。

不定時更新中。


5458052-8a9acc9a39de2b6e.png

相關文章