OC 如何实现多继承


由于OC是一门动态的语言,会尽可能将事件的调用延迟至运行时进行确定,所以如果OC支持多继承就有可能会在运行时发现多个父类出现具有二义性的方法实现时无法抉择的选择性困难,所以OC并不像其他静态语言一样支持多继承.虽然OC不支持多继承,但是由于OC的消息机制具有动态性,所以在需要的时候OC完全可以实现类似多继承的特性.为了方便说明,假设 Class Son 需要具备 class FatherAclass FatherB的能力。

在当前类中添加其他类的实现

  • 直接在当前类中定义class FatherAclass FatherB两个类的对象,用于外界Son对象调用方法
@interface Son : NSObjet
@end

@interface Son()
@property (strong, nonatomic) FatherA *a;
@property (strong, nonatomic) FatherB *b;
@end
@implementation
-(instanceType)init {
   self = [super init];
   if (self) {
   self.a = [[FatherA alloc] init];
   self.b = [[FatherB alloc] init];
   }
   return self;
}
// 调用FatherA的对象a的方法
-(id)methodA {
   return [self.a methodA];
}
// 调用FatherB的对象b的方法
-(NSString *)methodB {
return [self.b methodB];
}
  • 也可以在当前类的方法调用中直接调用原始类的实现
 @interface Son : NSObjet
@end

@implementation
// 调用FatherA的对象a的方法
-(id)methodA {
           Method method_a = class_getInstanceMethod(objc_getClass("FatherA"), sel_registerName("methodA"));
       // 需要根据具体方法参数和返回值类型进行转换
       void(*imp)(id, SEL) = ((void(*)(id , SEL))method_getImplementation(method_a));
       imp(self, cmd);
}
// 调用FatherB的对象b的方法
-(void)methodB {
       Method method_b = class_getInstanceMethod(objc_getClass("FatherB"), sel_registerName("methodB"));
       // 需要根据具体的类型进行转换
       NSString *(*imp)(id, SEL) = ((NSString *(*)(id , SEL))method_getImplementation(method_a));
       return imp(self, cmd);
} 

这种实现没有创建多余的对象,而是直接使用使用了保存在类结构中的实例方法实现,但是需要注意的是传入的对象并不是真实的FatherA/FatherB对象,所以如果在实现中用到了传入对象的属性或者方法,需要保证传入的Son也具备同名的属性或者方法,以免出现异常.

通过协议

通过协议将属于不同类的方法进行分类,然后让需要具备协议方法的类来遵守并实现协议,由于OC中的类可以服从多个协议可以简实现类似多继承的效果,但遵守协议的类必须都实现协议中定义的方法,这是一种伪实现.

@protocol FatherAProtocol : <NSObject>
- (void)methodA;
@end

@protocol FatherBProtocol : <NSObject>
- (void)methodB;
@end


@interface FatherA: NSObject <FatherAProtocol>
@end
@implementation FatherA
- (void)methodA {
	....
	....
}
@end

@interface FatherB: NSObject <FatherBProtocol>
@end
@implementation FatherB
- (void)methodB {
	....
	....
}
@end

@interface Son: NSObject <FatherAProtocol, FatherBProtocol>
@end
@implementation 
- (void)methodA {
	....
	....
}
- (NSString *)methodB {
	....
	....
}
@end

分类

分类(category)也是使用比较多的一个技术手段,比较简单的方法是,将需要多个类具备的方法添加到公共父类的分类上,这样只需要实现一次,所有的子类都可以具备调用的能力.

@interface NSObject(Methods)
 - (void)methodA;
 - (NSString *)methodB;
@end
@implementation NSObject(Methods)
 - (void)methodA {
	...
	...
}
 - (NSString *)methodB {
	...
	...
}
@end

通过消息转发机制

消息转发机制是OC运行时的一个重要特性,通过运行时的消息转发可以实现多继承的效果.
消息转发机制可以在三个阶段实现方法的动态的添加调用:
消息转发机制

  • 在动态方法解析阶段
@interface Son
@end

@implementation Son
 + (BOOL)resolveInstanceMethod:(SEL)sel {
    NSString *selName = [NSString stringWithCString:sel_getName(sel) encoding:(NSUTF8StringEncoding)];
    if ([selName isEqualToString:@"methodA"] ) {
        Method method_a = class_getInstanceMethod(objc_getClass("FatherA"), sel_registerName("methodA"));
        // 需要根据具体的类型进行转换
        IMP imp = method_getImplementation(method_a);
        // 给当前类添加对应的方法实现
        class_addMethod(self, sel, imp, method_getTypeEncoding(method_a));
        return true;
    } else if ([selName isEqualToString:@"methodB"]) {
        Method method_b = class_getInstanceMethod(objc_getClass("FatherB"), sel_registerName("methodB"));
        // 需要根据具体的类型进行转换
        IMP imp = method_getImplementation(method_b);
        // 给当前类添加对应的方法实现
        class_addMethod(self, sel, imp, method_getTypeEncoding(method_b));
        return true;
    }
    return false;
}
@end
  • 在快速消息转发阶段
@interface Son
@end
@implementation Son
+ (id)forwardingTargetForSelector:(SEL)aSelector {
   if (class_respondsToSelector(objc_getClass("FatherA"), aSelector)) {
       return [[FatherA alloc] init];
   }
   if (class_respondsToSelector(objc_getClass("FatherB"), aSelector)) {
       return [[FatherB alloc] init];
   }
   return [super forwardingTargetForSelector:aSelector];
}
@end
  • 在标准消息转发阶段
@interface Son
@end
@implementation Son

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
   NSMethodSignature *methodSignature = [super methodSignatureForSelector:aSelector];
   if (!methodSignature) {
       if ([selName isEqualToString:@"methodA"] ) {
           Method method_a = class_getInstanceMethod(objc_getClass("FatherA"), sel_registerName("methodA"));
           // 需要根据具体的类型进行转换
           IMP imp = method_getImplementation(method_a);
           // 给当前类添加对应的方法实现
           class_addMethod(self, sel, imp, method_getTypeEncoding(method_a));
       } else if ([selName isEqualToString:@"methodB"]) {
           Method method_b = class_getInstanceMethod(objc_getClass("FatherB"), sel_registerName("methodB"));
           // 需要根据具体的类型进行转换
           IMP imp = method_getImplementation(method_b);
           // 给当前类添加对应的方法实现
           class_addMethod(self, sel, imp, method_getTypeEncoding(method_b));
       }
       return [self methodSignatureForSelector:aSelector];
   }
   return methodSignature;
}

- (void)forwardInvocation:(NSInvocation *)anInvocation {
   [anInvocation invokeWithTarget:self];
}
@end

通过消息转发机制进行消息转发的实现可以不用多次实现同名的方法,但是要确保在非当前类中的方法实现中使用到的属性和方法在当前类中均有实现,才能保证方法的正常调用.

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值