Objective-C Posing


Posing,顧名思義,意思是「冒充」,它跟categories類似,但本質上不一樣,Posing存在的目的在於子類可以冒充父類別,使得後續的程式碼無需把父類別修改為子類,就可以很方便的讓父類別表現成子類的行為,從而實現非常方便的冒充,這在一般的語言中是難以想象的。

在開始在Objective-C中進行構建之前,提醒讀者注意,在Mac OS X 10.5中宣告已經棄用了冒充(Posing),並且之後無法使用它。 因此對於那些不關心這些棄用方法的人可以跳過本章。

Objective-C允許類完全替換程式中的另一個類。替換類被稱為「冒充」目標類。 對於支援冒充的版本,傳送到目標類的所有訊息都由冒充類接收。

NSObject包含poseAsClass - 使我們能夠替換現有類的方法,如上所述。

它允許擴充套件一個類,並且全面的冒充這個超類,比如:有一個擴充套件NSArrayNSArrayChild物件,如果讓NSArrayChild冒充NSArray,則程式程式碼所在的NSArray都會自動替換為NSArrayChild
注意,這裡不是指程式碼替換,而是NSArray所在地方的行為都跟NSArrayChild一樣了。

冒充限制

  • 一個類只能構成其直接或間接超類之一。
  • 冒充類不得定義目標類中不存在的任何新範例變數(儘管它可以定義或覆蓋方法)。
  • 目標類在冒充之前可能沒有收到任何訊息。
  • 冒充類可以通過super呼叫重寫的方法,從而結合目標類的實現。
  • 冒充類可以覆蓋類別中定義的方法。

範例程式碼:

#import <Foundation/Foundation.h>

@interface MyString : NSString

@end

@implementation MyString

- (NSString *)stringByReplacingOccurrencesOfString:(NSString *)target
withString:(NSString *)replacement {
   NSLog(@"The Target string is %@",target);
   NSLog(@"The Replacement string is %@",replacement);
}

@end

int main() {
   NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
   [MyString poseAsClass:[NSString class]];
   NSString *string = @"Test";
   [string stringByReplacingOccurrencesOfString:@"a" withString:@"c"];

   [pool drain];
   return 0;
}

執行上面範例程式碼,得到以下結果:

2018-11-22 21:23:44.729 Posing[372:306] The Target string is a
2018-11-22 21:23:44.730 Posing[372:306] The Replacement string is c

在上面的例子中,只是用實現汙染了原始方法,並且這將通過上述方法在所有NSString操作中受到影響。