標籤:
[精通Objective-C]對象和訊息傳遞
參考書籍:《精通Objective-C》【美】 Keith Lee
目錄
- 精通Objective-C對象和訊息傳遞
- 目錄
- 對象
- 建立對象
- 初始化對象
- 重構Atom類並建立子類
- Factory 方法
- 訊息傳遞
- 附錄前一章節建立的Atom類
對象建立對象
NSObject類中用於建立類執行個體(即對象)的方法
+(id) alloc
通過alloc方法,可以建立對象,下面以建立一個Atom對象為例
//建立一個屬於Atom類的對象,並為它分配一個資料類型為id的變數id atom = [Atom alloc];//與上面語句等價,顯示定義變數的類型,失去靈活性,但可以獲得靜態類型檢查Atom *atom = [Atom alloc];
初始化對象
alloc方法為對象分配了記憶體,並將它的執行個體變數設定為0,但是alloc方法既沒有將該對象的執行個體變數初始化為適當的值,也沒有為這個對象準備其他必須的對象和資源。因此自訂的類還應該實現完成初始化的過程的方法。
NSObject類中用於初始化對象的方法:
-(id) init
下面以Atom類的init方法為例:
-(id) init{ //調用父類的init方法,結果賦給調用對象 if ((self = [super init])) { //初始化 _chemicalElement = @"None"; } return self;}
重構Atom類並建立子類
編譯器自動補全屬性時,建立的是一個作用範圍為@private的支援執行個體變數,無法被該類的子類訪問。可以重構該類,將這個變數的作用範圍設定為@protected。
@interface Atom : NSObject//重構Atom類,聲明作用範圍為@protected的支援執行個體變數{ @protected NSUInteger _protons; @protected NSUInteger _neutrons; @protected NSUInteger _electrons; @protected NSString *_chemicalElement; @protected NSString *_atomicSymbol;}//之前聲明的屬性和方法@property(readonly) NSUInteger protons;@property(readonly) NSUInteger neutrons;@property(readonly) NSUInteger electrons;@property(readonly) NSString *chemicalElement;@property(readonly) NSString *atomicSymbol;-(NSUInteger) massNumber;@end
建立一個Atom類的子類Hydrogen,並使用新的可以接受參數的初始化方法。
Hydrogen.h
#import "Atom.h"@interface Hydrogen : Atom//聲明初始化方法-(id) initWithNeutrons:(NSUInteger)neutrons;@end
Hydrogen.m
#import "Hydrogen.h"@implementation Hydrogen{ @private HydrogenHelper *helper;}//實現初始化方法-(id) initWithNeutrons:(NSUInteger)neutrons{ if ((self = [super init])) { _chemicalElement = @"Hydrogen"; _atomicSymbol = @"H"; _protons = 1; //使用傳入參數為執行個體變數賦值 _neutrons = neutrons; } return self;}@end
Factory 方法
Factory 方法是指用於建立和初始化類的便捷方法
在Hydrogen.h中聲明
+(id) hydrogenWithNeutrons:(NSUInteger)neutrons;
在Hydrogen.m實現
+(id) hydrogenWithNeutrons:(NSUInteger)neutrons{ //建立一個Hydrogen對象並初始化,然後返回這個對象 return [[self alloc] initWithNeutrons:neutrons];}
之後我們就可以用兩種不同的方法來完成對象的初始化了
//普通方法 Hydrogen *atom1 = [[Hydrogen alloc] initWithNeutrons:1]; //Factory 方法 Hydrogen *atom2 = [Hydrogen hydrogenWithNeutrons:2];
訊息傳遞
訊息傳遞是OOP中的用於調用對象中方法的機制。接收訊息的對象(接收器)會在運行時決定調用其執行個體的哪個方法。執行個體方法可以訪問對象的執行個體變數和執行個體方法。
發送訊息
向對象發送訊息的格式:
[接收器 訊息名稱1:參數1 訊息名稱2:參數2 ...]
同時Objective-C還為類方法提供了語言級的支援:
[類名 訊息名稱1:參數1 訊息名稱2:參數2 ...]
之前的[Hydrogen hydrogenWithNeutrons:2]
就是向Hydrogen類發送訊息。
訊息轉寄
在運行時,接收器都會通過解釋訊息,確定需要調用哪個方法。Objective-C提供了訊息轉寄機制,當對象收到與其方法集不匹配的訊息時,通過訊息轉寄機制可以使對象能夠在收到無法識別的資訊時執行各種邏輯,如將訊息發送給能夠作出回應的其他接收器或是既不處理也不使程式拋出執行階段錯誤,默默吞下訊息。
Objective-C為NSObject類的子類提供了兩類訊息轉寄選項。
快速轉寄:
//重寫NSObject類的該方法,將該方法轉寄給其他對象,就像是將對象的實現代碼與轉寄對象合并到了一起,類似於類實現的多重繼承行為-(id) forwardingTargetForSelector:(SEL)aSelector
標準(完整)轉寄:
//重寫NSObject類的該方法,可以讓對象使用訊息中的全部內容(目標,方法名和參數)-(void) forwardInvocation:(NSInvocation *)anInvocation
下面來為Hydrogen類添加快速轉寄機制。
首先需要建立一個輔助類HydrogenHelper,該類負責處理一個名為factoid的Hydrogen類無法處理的方法。
HydrogenHelper.h
#import <Foundation/Foundation.h>@interface HydrogenHelper : NSObject-(NSString *) factoid;@end
HydrogenHelper.m
#import "HydrogenHelper.h"@implementation HydrogenHelper-(NSString *) factoid{ return @"The lightest element and most abundant chemical substance.";}@end
再更新Hydrogen類的代碼
@implementation Hydrogen//添加執行個體變數HydrogenHelper{ @private HydrogenHelper *helper;}-(id) initWithNeutrons:(NSUInteger)neutrons{ if ((self = [super init])) { _chemicalElement = @"Hydrogen"; _atomicSymbol = @"H"; _protons = 1; _neutrons = neutrons; //建立並初始化HydrogenHelper對象 helper = [[HydrogenHelper alloc] init]; } return self;}+(id) hydrogenWithNeutrons:(NSUInteger)neutrons{ return [[self alloc] initWithNeutrons:neutrons];}//重寫NSObject類的forwardingTargetForSelector:(SEL)aSelector方法-(id) forwardingTargetForSelector:(SEL)aSelector{ //如果HydrogenHelper對象能夠處理該訊息,則將訊息轉寄給HydrogenHelper對象 if ([helper respondsToSelector:aSelector]) { return helper; } return nil;}@end
為了使Hydrogen類能夠接收factoid方法,還需再添加一個分類,在其中聲明factoid方法(不需要實現)
Atom+Helper.h(由於不需要實現方法可以把自動建立出來的Atom+Helper.m刪掉)
#import "Atom.h"//也可以將Atom改為Hydrogen@interface Atom (Helper)//聲明factoid方法-(NSString *) factoid;@end
最後就可以通過訊息轉寄功能,向Hydrogen對象發送factoid方法了
Hydrogen *atom = [Hydrogen hydrogenWithNeutrons:2];[atom factoid];
附錄:前一章節建立的Atom類
Atom.h
#import <Foundation/Foundation.h>@interface Atom : NSObject@property(readonly) NSUInteger protons;@property(readonly) NSUInteger neutrons;@property(readonly) NSUInteger electrons;@property(readonly) NSString *chemicalElement;-(NSUInteger) massNumber;@end
Atom.m
#import "Atom.h"@implementation Atom-(id) init{ if ((self = [super init])) { _chemicalElement = @"None"; } return self;}-(NSUInteger) massNumber{ return self.protons + self.neutrons;}@end
[精通Objective-C]對象和訊息傳遞