美文网首页
OC Runtime

OC Runtime

作者: GTMYang | 来源:发表于2018-05-29 14:55 被阅读0次

Runtime核心之-数据结构

每个类的实例变量都有一个Class isa

typedef struct objc_class *Class;

struct 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;

类结构的关联关系(图),runtime的基础

1330553-81f64a11ad20c764.png

Runtime核心之-消息机制

关键方法:objc_msgSend
参数:id obj(接收者), SEL sel(方法选择器), arg1...(方法参数表)
通过obj->isa 可以遍历类的结构,包括父类。结合sel就可以找到对应的函数指针,结合后面的参数表就可以执行函数了,方法对应的c函数也包含id obj(接收者), SEL sel(方法选择器)这两个参数,编译器自动添加的被称为隐藏参数。oc中可以通过self和_cmd访问到。

Runtime-NSObject常用方法

/*一般方法*/
- (Class)class;   // 获取对象类型
- (BOOL)isKindOfClass:(Class)aClass; // 是否是类或者其子类的实例
- (BOOL)isMemberOfClass:(Class)aClass; // 是否当前类的实例
- (BOOL)conformsToProtocol:(Protocol *)aProtocol; // 对象是否实现了Protocol
- (BOOL)respondsToSelector:(SEL)aSelector; // 对象是否实现了方法

/*动态解析相关方法*/
+ (BOOL)resolveInstanceMethod:(SEL)sel;
+ (BOOL)resolveClassMethod:(SEL)sel;


/*消息转发相关方法*/
- (id)forwardingTargetForSelector:(SEL)aSelector;

- (void)forwardInvocation:(NSInvocation *)anInvocation;
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;

conformsToProtocol 使用demo

 ClassA *a = [ClassA new];
 NSLog(@"%d", [a conformsToProtocol:@protocol(MyProtocolName)]);  //1

Runtime-runtime常用源码方法

/*访问成员变量方法*/
Ivar * class_copyIvarList(Class cls, unsigned int *outCount)
objc_property_t * class_copyPropertyList(Class cls, unsigned int *outCount);
/*动态方法处理相关方法*/
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types);
IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types);
IMP method_getImplementation(Method m);
IMP method_setImplementation(Method m, IMP imp);
void method_exchangeImplementations(Method m1, Method m2);

Runtime-应用

方法动态解析

+ (BOOL)resolveInstanceMethod:(SEL)sel {
    NSString *selName = NSStringFromSelector(sel);
 
    if ([selName isEqualToString:@"nihao"]) {
        class_addMethod(self, sel, cfunc, "v@:");
        return YES;
    }
    
    return [super resolveInstanceMethod:sel];
}

void ifunc(id self, SEL _cmd) {
    NSLog(@"resolveInstanceMethod 新加的Instance方法");
}

消息转发

#pragma mark - forwardingTargetForSelector

- (id)forwardingTargetForSelector:(SEL)aSelector {
    NSString *selName = NSStringFromSelector(aSelector);
    
    if ([selName isEqualToString:@"ffunc"]) {
        return [ForwardingObj new];
    }
    
    return [super forwardingTargetForSelector:aSelector];
}


#pragma mark - forwardInvocation

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    NSString *selName = NSStringFromSelector(aSelector);
    
    if ([selName isEqualToString:@"fifunc"]) {
        return [NSMethodSignature signatureWithObjCTypes:"v@:"];
    }
    return [super methodSignatureForSelector:aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    NSString *selName = NSStringFromSelector(anInvocation.selector);
    if ([selName isEqualToString:@"fifunc"]) {
        [anInvocation invokeWithTarget:[ForwardingObj new]];
        return;
    }
    [super forwardInvocation:anInvocation];
}

/////ForwardingObj.h
@interface ForwardingObj: NSObject

- (void)ffunc;
- (void)fifunc;
@end
//// ForwardingObj.m
@implementation ForwardingObj


- (void)ffunc {
    NSLog(@"ForwardingObj 的ffunc方法");
}

- (void)fifunc {
    NSLog(@"ForwardingObj 的fifunc方法");
}

@end

对象归档解档

- (void)decode:(NSCoder *)aDecoder {
    // 一层层父类往上查找,对父类的属性执行归解档方法
    Class c = self.class;
    while (c &&c != [NSObject class]) {
        //解档
        unsigned int count = 0;
        Ivar *ivars = class_copyIvarList([self class], &count);
        for (int i = 0; i<count; i++) {
            //拿到Ivar
            Ivar ivar = ivars[i];
            const char *name = ivar_getName(ivar);
            NSString *key = [NSString stringWithUTF8String:name];
            //解档
            id value = [aDecoder decodeObjectForKey:key];
            // 利用KVC赋值
            [self setValue:value forKey:key];
        }
        free(ivars);
        
        c = [c superclass];
    }
    
}

- (void)encode:(NSCoder *)aCoder {
    // 一层层父类往上查找,对父类的属性执行归解档方法
    Class c = self.class;
    while (c &&c != [NSObject class]) {
        //告诉系统归档的属性是哪些
        unsigned int count = 0;//表示对象的属性个数
        Ivar *ivars = class_copyIvarList([self class], &count);
        for (int i = 0; i<count; i++) {
            //拿到Ivar
            Ivar ivar = ivars[i];
            const char *name = ivar_getName(ivar);//获取到属性的C字符串名称
            NSString *key = [NSString stringWithUTF8String:name];//转成对应的OC名称
            //归档 -- 利用KVC
            [aCoder encodeObject:[self valueForKey:key] forKey:key];
        }
        free(ivars);
        c = [c superclass];
    }
}

json转换model
...
hook系统类方法


+ (void)load {
    Method old = class_getInstanceMethod(self, @selector(viewDidLoad));
    Method new = class_getInstanceMethod(self, @selector(viewDidLoad_new));
    method_exchangeImplementations(old, new);
}

- (void)viewDidLoad_new {
    NSLog(@"before viewDidLoad method excute");
    [self viewDidLoad_new];
    NSLog(@"after viewDidLoad method excute");
}

- (void)viewDidLoad {
    [super viewDidLoad];
}

相关文章

网友评论

      本文标题:OC Runtime

      本文链接:https://www.haomeiwen.com/subject/zntajftx.html