iOS点点滴滴码无界IOS And AndroidiOS

iOS高级开发 RunTime机制讲解五---runtime原理

2016-03-26  本文已影响219人  kevinLY

下载DEMO:https://github.com/sleepsheep/RunTimeDemo05
1、首先创建一个项目;
2、创建一个父类:Animal

@interface Animal : NSObject

- (void)say;

@end

@implementation Animal

- (void)say {
    NSLog(@"Animal say!");
}

@end

3、创建两个子类:Dog、DogOther

Dog:

消息的转发流程:

注意:必须重写methodSignatureForSelector才能走到forwardInvocation方法;
@class DogOther;
@interface Dog : Animal

@property (nonatomic, strong) DogOther *dogOther;

- (void)bark;

@end

#import "Dog.h"
#import <objc/runtime.h>
#import <objc/message.h>
#import "DogOther.h"

@implementation Dog

- (instancetype)init
{
    self = [super init];
    if (self) {
        self.dogOther = [DogOther new];
    }
    return self;
}

- (void)bark {
    NSLog(@"Dog bark!");
}

////1、类方法调用最终找不到 会走这个方法
//+ (BOOL)resolveClassMethod:(SEL)sel {
//    
//    return [super resolveClassMethod:sel];
//}
//
////对象调用最终找不到 会走这个方法 我们可以在该方法中实现对应的处理逻辑
//+ (BOOL)resolveInstanceMethod:(SEL)sel {
//    NSString *selStr = NSStringFromSelector(sel);//获取方法名
//    if ([selStr isEqualToString:@"says"]) {
//        //动态添加方法
//        class_addMethod([self class], @selector(says), (IMP)notFoundSaysMethod, "@:");
//    }
//    
//    return [super resolveInstanceMethod:sel];
//}
//
//void notFoundSaysMethod(id self, SEL _cmd) {
//    printf("notFoundSaysMethod\n");
//}

////2、备用的接收者--->消息转发
//- (id)forwardingTargetForSelector:(SEL)aSelector {
//    NSString *selStr = NSStringFromSelector(aSelector);
//    if ([selStr isEqualToString:@"says"]) {
//        return self.dogOther;
//    }
//    
//    return [super forwardingTargetForSelector:aSelector];
//}

//3、完整消息转发
- (void)forwardInvocation:(NSInvocation *)anInvocation {
    if ([DogOther instancesRespondToSelector:anInvocation.selector]) {
        [anInvocation invokeWithTarget:self.dogOther];
    } else {
        [super forwardInvocation:anInvocation];
    }
        
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    NSMethodSignature *signature = [super methodSignatureForSelector:aSelector];
    
    if (!signature) {
        if ([DogOther instancesRespondToSelector:aSelector]) {
            signature = [DogOther instanceMethodSignatureForSelector:aSelector];
        }
    }
    
    return signature;
}

DogOther:

@interface DogOther : Animal

- (void)says;

@end

@implementation DogOther

- (void)says {
    NSLog(@"DogOther-->says");
}

@end

main:

准备工作:
#import <objc/runtime.h>
#import <objc/message.h>
在Build Settings 中设置enable strict checking of objc_msgsend calls为 no
理解objc_class的结构体组成:
#struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !OBJC2
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;
struct objc_method_list **methodLists OBJC2_UNAVAILABLE;
struct objc_cache *cache OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
@brief 消息机制的运行原理 : 用[dog say] 为例来描述方法调用的流程

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        
        Dog *dog = [[Dog alloc] init];
//        [dog say];   //等价于 objc_msgSend(dog, @selector(say));
//        [dog bark];
        
        //这种情况属于7中的第二种,进入消息的转发流程 参考 Dog类中的注释
        [dog performSelector:@selector(says)];//notFoundSaysMethod
    }
    return 0;
}

不懂就药问

上一篇 下一篇

猜你喜欢

热点阅读