OC 中一個類只有一個父類, 這就是單一繼承, 但是我們可以用協議和 NSProxy 實現多繼承
比如我有兩個協議, 分別是 YFPerson,YFChild
#import @protocol YFPerson @required @property (nonatomic,copy,readonly)NSString *name; - (NSInteger) age; - (void)eat; - (void)sleep; @optional - (void)play; - (void)setName:(NSString *)newName; @end
#import @protocol YFChild @required - (NSString *)nickname; - (void)introduceMyselfWithName:(NSString *)name nickname:(NSString *)nickname age:(NSInteger)age; @optional - (void)study; @end
那麼, 我在新創建的一個 YFStudent 類中, 只要遵守上面兩個協議, 實現協議裡的方法, 就可以在一個類中,實現多個協議中的方法了.
YFStudent.m
- (NSString *)nickname { return @"龍兒"; } - (NSInteger)age { return 19; } - (void)sleep{ NSLog(@"sleep"); } - (void)eat{ NSLog(@"eat"); } - (void)introduceMyselfWithName:(NSString *)name nickname:(NSString *)nickname age:(NSInteger)age { NSLog(@"我叫%@,小名%@,今天%@歲了", name,nickname,@(age)); }
這樣, 我在控制器的 viewDidLoad 方法中,創建 YFStudent 對象, 然後就可以調協議中的任何方法了
- (void)viewDidLoad { [super viewDidLoad]; YFStudent *student = [[YFStudent alloc]init]; student.name = @"小龍女"; [student eat]; [student sleep]; [student introduceMyselfWithName:student.name nickname:student.nickname age:student.age]; }
運行後,正確輸出
這個類是和 NSObject 平起平坐的, 而且這個類沒有 init 方法,也就是說,它只可以開辟一塊內存空間,而不能初始化. 那麼,我怎麼樣這個類可以變成任意一個類呢?
主要有這樣幾步,
我先設置一個類 YFProxy, 繼承自 NSProxy
為 YFProxy 設置一個 NSObject 屬性
自定義一個轉換方法,相當於給 NSObject 屬性賦值
然後通過這個屬性獲得調用方法的方法簽名
為調用設置目標
調用
我一步步說一遍
1.為外界暴露一個變身方法:
#import @interface YFProxy : NSProxy - (id)transformToObject:(NSObject *)object; @end
2.設置一個 NSObject 屬性
#import "YFProxy.h" @interface YFProxy () @property (nonatomic,strong)NSObject *object; @end
3.實現變身方法
- (id)transformToObject:(NSObject *)object { self.object = object; return self.object; }
4.重寫- (NSMethodSignature *)methodSignatureForSelector:(SEL)see
方法獲得方法簽名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel { NSMethodSignature *methodSignature; if (self.object) { methodSignature = [self.object methodSignatureForSelector:sel]; }else{ methodSignature = [super methodSignatureForSelector:sel]; } return methodSignature; }
5.重寫- (void)forwardInvocation:(NSInvocation *)invocation
方法改變調用對象,也就是說,讓消息實際上發給真正的實現這個方法的類
- (void)forwardInvocation:(NSInvocation *)invocation { if (self.object) { [invocation setTarget:self.object]; [invocation invoke]; } }
假設我現在有兩個類,
YFPerson
#import "YFPerson.h" @interface YFPerson () @property (nonatomic,copy)NSString *name; @end @implementation YFPerson - (void)eat { NSLog(@"%@正在吃飯",self.name); } @end
YFStudent
#import "YFStudent.h" @interface YFStudent () @property (nonatomic,copy)NSString *studentNum; @end @implementation YFStudent - (void)study { NSLog(@"哥正在學習"); } @end
那麼我怎麼用 YFProxy"繼承"這連個類呢?
先初始化兩個純潔的對象
YFPerson *person = [[YFPerson alloc]init]; YFStudent *student = [[YFStudent alloc]init];
為 YFProxy 開辟一塊內存空間
YFProxy *proxy = [YFProxy alloc];
變身
[proxy transformToObject:person];
這樣就可以自由自在地調用 Person 類的方法了,person 類的方法甚至是真私有的,都可以調得到,雖然報警告了
[proxy performSelector:@selector(setName:) withObject:@"小明"]; [proxy performSelector:@selector(eat)];
再變
[proxy transformToObject:student];
這樣又可以調 Student類的方法了
[proxy performSelector:@selector(study)];
是不是很神奇,當然,這只是初步的探討,還有很多基於 OC 運行時的東西值得我們去挖掘