重拾iOS-多繼承

image

關(guān)鍵詞:多繼承,Protocol,Category,Runtime

面試題:

1)OC中可以多繼承嗎?

2)多繼承的實(shí)現(xiàn)方案有哪些?

一、概述

面向?qū)ο缶幊讨猿蔀橹髁鞯木幊趟枷牒退睦^承和多態(tài)是分不開的,只要是面向?qū)ο笳Z言都支持繼承和多態(tài),當(dāng)然不同的OOP語言之間都有其特點(diǎn)。OC中和Java類似,不支持多重繼承,但OOP語言C++就支持多繼承。

為什么Objective-C不支持多繼承?

Objective-C不支持多繼承,由于消息機(jī)制名字查找發(fā)生在運(yùn)行時而非編譯時,很難解決多個基類可能導(dǎo)致的二義性問題。

二、OC的多繼承實(shí)現(xiàn)方案

雖然OC不支持多繼承,但是可以通過其他方式間接地達(dá)到多繼承的效果。

  • 通過組合實(shí)現(xiàn)多繼承;
  • 通過協(xié)議實(shí)現(xiàn)多繼承;
  • 通過類別實(shí)現(xiàn)多繼承;
  • 通過Runtime消息轉(zhuǎn)發(fā)實(shí)現(xiàn)多繼承;
  • 通過NSProxy實(shí)現(xiàn)多繼承;

代碼演示如下:

1、通過組合實(shí)現(xiàn)多繼承

ClassA:

// .h
@interface ClassA : NSObject
- (void)funcA;
@end

// .m
#import "ClassA.h"

@implementation ClassA
- (void)funcA{
    NSLog(@"%s",__func__);
}
@end

ClassB:

// .h
@interface ClassB : NSObject
- (void)funcB;
@end

// .m
#import "ClassB.h"

@implementation ClassB
- (void)funcB{
    NSLog(@"%s",__func__);
}
@end

ClassC:(通過組合多個類來間接實(shí)現(xiàn)多繼承)

// .h
@interface ClassC : NSObject
- (void)funcA;
- (void)funcB;
@end

// .m
#import "ClassC.h"
#import "ClassA.h"
#import "ClassB.h"

@interface ClassC ()
@property (nonatomic, strong) ClassA *clsA;
@property (nonatomic, strong) ClassB *clsB;
@end

@implementation ClassC
- (instancetype)init{
    if (self = [super init]) {
        self.clsA = [[ClassA alloc]init];
        self.clsB = [[ClassB alloc]init];
    }
    return self;
}
- (void)funcA {
    [self.clsA funcA];
}
- (void)funcB{
    [self.clsB funcB];
}

@end

2、通過協(xié)議實(shí)現(xiàn)多繼承

ClassA:

// .h
@protocol ClassAProtocol <NSObject>
- (void)funcA;
@end

@interface ClassA : NSObject<ClassAProtocol>

@end

// .m
#import "ClassA.h"

@implementation ClassA
- (void)funcA{
    NSLog(@"%s",__func__);
}
@end

ClassB:

// .h
@protocol ClassBProtocol <NSObject>
- (void)funcB;
@end

@interface ClassB : NSObject<ClassBProtocol>

@end

// .m
#import "ClassB.h"

@implementation ClassB
- (void)funcB{
    NSLog(@"%s",__func__);
}
@end

ClassC:(通過遵循多個協(xié)議來間接實(shí)現(xiàn)多繼承)

// .h
@interface ClassC : NSObject
- (void)funcA;
- (void)funcB;
@end

// .m
#import "ClassC.h"
#import "ClassA.h"
#import "ClassB.h"

@interface ClassC ()<ClassAProtocol, ClassBProtocol>
@property (nonatomic, strong) ClassA *clsA;
@property (nonatomic, strong) ClassB *clsB;
@end

@implementation ClassC
- (instancetype)init{
    if (self = [super init]) {
        self.clsA = [[ClassA alloc]init];
        self.clsB = [[ClassB alloc]init];
    }
    return self;
}
- (void)funcA {
    [self.clsA funcA];
}
- (void)funcB{
    [self.clsB funcB];
}

@end

3、通過類別實(shí)現(xiàn)多繼承

ClassA:

// .h
@interface ClassA : NSObject
- (void)funcA;
@end

// .m
#import "ClassA.h"

@implementation ClassA
- (void)funcA{
    NSLog(@"%s",__func__);
}
@end

ClassB:

// .h
@interface ClassB : NSObject
- (void)funcB;
@end

// .m
#import "ClassB.h"

@implementation ClassB
- (void)funcB{
    NSLog(@"%s",__func__);
}
@end

ClassC:(通過添加多個類別來間接實(shí)現(xiàn)多繼承)

// .h
@interface ClassC : NSObject
- (void)funcA;
- (void)funcB;
@end

// .m
#import "ClassC.h"
#import "ClassA.h"
#import "ClassB.h"
#import "ClassC+A.h"
#import "ClassC+B.h"

@interface ClassC ()
@end

@implementation ClassC
- (instancetype)init{
    if (self = [super init]) {
        self.clsA = [[ClassA alloc]init];
        self.clsB = [[ClassB alloc]init];
    }
    return self;
}
- (void)funcA {
    [self.clsA funcA];
}
- (void)funcB{
    [self.clsB funcB];
}

@end

ClassC+A:

// .h
#import "ClassC.h"
@class ClassA;

@interface ClassC (A)
@property (nonatomic, strong) ClassA *clsA;
- (void)funcA;
@end

// .m
#import "ClassC+A.h"
#import "ClassA.h"
#import <objc/runtime.h>

@implementation ClassC (A)
- (void)setClsA:(ClassA *)clsA{
    objc_setAssociatedObject(self, @selector(clsA), clsA, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (ClassA *)clsA{
    return objc_getAssociatedObject(self, @selector(clsA));
}
- (void)funcA{
    [self.clsA funcA];
}
@end

ClassC+B:

// .h
#import "ClassC.h"
@class ClassB;

@interface ClassC (B)
@property (nonatomic, strong) ClassB *clsB;
- (void)funcB;
@end

// .m
#import "ClassC+B.h"
#import "ClassB.h"
#import <objc/runtime.h>

@implementation ClassC (B)
- (void)setClsB:(ClassB *)clsB{
    objc_setAssociatedObject(self, @selector(clsB), clsB, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (ClassB *)clsB{
    return objc_getAssociatedObject(self, @selector(clsB));
}
- (void)funcB{
    [self.clsB funcB];
}
@end

4、通過Runtime消息轉(zhuǎn)發(fā)實(shí)現(xiàn)多繼承

Runtime在經(jīng)歷「消息傳遞」階段仍未找到方法的實(shí)現(xiàn)時,會進(jìn)入「消息轉(zhuǎn)發(fā)」階段。大致的流程如下:

image

想了解更多Runtime相關(guān)知識,可以看看這篇:「重拾iOS-Runtime」

「消息轉(zhuǎn)發(fā)」

消息轉(zhuǎn)發(fā)會經(jīng)歷三個過程:

1)首先是「動態(tài)方法解析」,Objective-C運(yùn)行時會調(diào)用 resolveInstanceMethod:,讓你有機(jī)會提供一個函數(shù)實(shí)現(xiàn)。如果你添加了函數(shù)并返回YES, 那運(yùn)行時系統(tǒng)就會重新啟動一次消息發(fā)送的過程。

2)然后是「備用接收者」,如果目標(biāo)對象實(shí)現(xiàn)了forwardingTargetForSelector:,RunTime 這時就會調(diào)用這個方法,給你把這個消息轉(zhuǎn)發(fā)給其他對象的機(jī)會。

3)最后是「完整的消息轉(zhuǎn)發(fā)」,首先它會發(fā)送methodSignatureForSelector:消息獲得函數(shù)的參數(shù)和返回值類型。如果methodSignatureForSelector:返回nil ,Runtime則會發(fā)出 doesNotRecognizeSelector:消息,程序這時也就掛掉了。如果返回了一個函數(shù)簽名,Runtime就會創(chuàng)建一個NSInvocation 對象并發(fā)送 forwardInvocation:消息給目標(biāo)對象。

所以說我們有三次機(jī)會,去間接的實(shí)現(xiàn)多繼承。但是可想而知,越到后面的階段,代價也就越大。

ClassA和ClassB不變

ClassA:

// .h
@interface ClassA : NSObject
- (void)funcA;
@end

// .m
#import "ClassA.h"

@implementation ClassA
- (void)funcA{
    NSLog(@"%s",__func__);
}
@end

ClassB:

// .h
@interface ClassB : NSObject
- (void)funcB;
@end

// .m
#import "ClassB.h"

@implementation ClassB
- (void)funcB{
    NSLog(@"%s",__func__);
}
@end
1)通過「動態(tài)方法解析」來實(shí)現(xiàn)多繼承

ClassC:

// .h
@interface ClassC : NSObject

@end

// .m
#import "ClassC.h"
#import "ClassA.h"
#import "ClassB.h"
#import "objc/runtime.h"

@interface ClassC ()
@property (nonatomic, strong) ClassA *clsA;
@property (nonatomic, strong) ClassB *clsB;
@end

@implementation ClassC
- (instancetype)init{
    if (self = [super init]) {
        self.clsA = [[ClassA alloc]init];
        self.clsB = [[ClassB alloc]init];
    }
    return self;
}
// MARK: 動態(tài)方法解析
// 對象方法
+ (BOOL)resolveInstanceMethod:(SEL)sel {
    if (sel == @selector(funcA)) {
        Method method = class_getInstanceMethod(self, @selector(resolvedFuncA));
        class_addMethod(self, sel, method_getImplementation(method), method_getTypeEncoding(method));
        return YES;
    }
    if (sel == @selector(funcB)) {
        Method method = class_getInstanceMethod(self, @selector(resolvedFuncB));
        class_addMethod(self, sel, method_getImplementation(method), method_getTypeEncoding(method));
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}
// 類方法
+ (BOOL)resolveClassMethod:(SEL)sel {
    return [super resolveClassMethod:sel];
}

- (void)resolvedFuncA {
    [self.clsA funcA];
}
- (void)resolvedFuncB {
    [self.clsB funcB];
}

@end

調(diào)用方法

// 使用performSelector調(diào)用方法
ClassC *clsC = [[ClassC alloc]init];
[clsC performSelector:NSSelectorFromString(@"funcA") withObject:nil];
[clsC performSelector:NSSelectorFromString(@"funcB") withObject:nil];
2)通過「備用接收者」來實(shí)現(xiàn)多繼承

ClassC:

// .h
@interface ClassC : NSObject

@end

// .m
#import "ClassC.h"
#import "ClassA.h"
#import "ClassB.h"
#import "objc/runtime.h"

@interface ClassC ()
@property (nonatomic, strong) ClassA *clsA;
@property (nonatomic, strong) ClassB *clsB;
@end

@implementation ClassC
- (instancetype)init{
    if (self = [super init]) {
        self.clsA = [[ClassA alloc]init];
        self.clsB = [[ClassB alloc]init];
    }
    return self;
}
// MARK: 備用接受者
- (id)forwardingTargetForSelector:(SEL)aSelector {
    if (aSelector == @selector(funcA) && [self.clsA respondsToSelector:aSelector]) {
        return self.clsA;
    }
    if (aSelector == @selector(funcB) && [self.clsB respondsToSelector:aSelector]) {
        return self.clsB;
    }
    return [super forwardingTargetForSelector:aSelector];
}

@end
3)通過「完整的消息轉(zhuǎn)發(fā)」來實(shí)現(xiàn)多繼承

ClassC:

// .h
@interface ClassC : NSObject

@end

// .m
#import "ClassC.h"
#import "ClassA.h"
#import "ClassB.h"
#import "objc/runtime.h"

@interface ClassC ()
@property (nonatomic, strong) ClassA *clsA;
@property (nonatomic, strong) ClassB *clsB;
@end

@implementation ClassC
- (instancetype)init{
    if (self = [super init]) {
        self.clsA = [[ClassA alloc]init];
        self.clsB = [[ClassB alloc]init];
    }
    return self;
}
// MARK: 完整的消息轉(zhuǎn)發(fā)
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
    if (aSelector == @selector(funcA) && [self.clsA respondsToSelector:aSelector]) {
        return [self.clsA methodSignatureForSelector:aSelector];
    }
    if (aSelector == @selector(funcB) && [self.clsB respondsToSelector:aSelector]) {
        return [self.clsB methodSignatureForSelector:aSelector];
    }
    return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation{
    SEL aSelector = [anInvocation selector];
    if (aSelector == @selector(funcA) && [self.clsA respondsToSelector:aSelector]) {
        [anInvocation invokeWithTarget:self.clsA];
    }
    else if (aSelector == @selector(funcB) && [self.clsB respondsToSelector:aSelector]) {
        [anInvocation invokeWithTarget:self.clsB];
    }
    else {
        [super forwardInvocation:anInvocation];
    }
}

@end

5、通過NSProxy實(shí)現(xiàn)多繼承

SFProxy:

// .h
@interface SFProxy : NSProxy
-(void)transformToObject:(NSObject *)obj;
@end

// .m
#import "SFProxy.h"

@interface SFProxy ()
@property (nonatomic, strong) NSObject *obj;
@end

@implementation SFProxy
-(void)transformToObject:(NSObject *)obj {
    self.obj = obj;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
    if (self.obj && [self.obj respondsToSelector:aSelector]) {
        return [self.obj methodSignatureForSelector:aSelector];
    }
    return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation{
    SEL aSelector = [anInvocation selector];
    if (self.obj && [self.obj respondsToSelector:aSelector]) {
        [anInvocation invokeWithTarget:self.obj];
    }
    else {
        [super forwardInvocation:anInvocation];
    }
}

@end

方法調(diào)用:

ClassA *clsA = [[ClassA alloc]init];
ClassB *clsB = [[ClassB alloc]init];
SFProxy *proxy = [SFProxy alloc];
// 變身為clsA的代理
[proxy transformToObject:clsA];
[proxy performSelector:@selector(funcA) withObject:nil];
// 變身為clsB的代理
[proxy transformToObject:clsB];
[proxy performSelector:@selector(funcB) withObject:nil];

打?。?/p>

2020-07-04 12:44:49.893660+0800 OCTestDemo[71379:1458448] -[ClassA funcA]
2020-07-04 12:44:49.893836+0800 OCTestDemo[71379:1458448] -[ClassB funcB]

好了,以上就是間接實(shí)現(xiàn)多繼承的方案。綜合來講,個人覺得還是「通過協(xié)議來實(shí)現(xiàn)多繼承」較為直觀。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容