iOS底层原理runtime 方法列表 以及常用api调用

iOS底层原理runtime 方法列表 以及常用api调用

objc_系列函数关注于宏观使用,如类与协议的空间分配,注册,注销等操作


class_系列函数关注于类的内部,如实例变量,属性,方法,协议等相关问题

objcet_系列函数关注于对象的角度,如实例变量

method_系列函数关注于方法内部,如果方法的参数及返回值类型和方法的实现

property_系类函数关注与属性*内部,如属性的特性等

protocol_系类函数关注与协议相关



ivar_xxx函数关注与实例变量的东西

sel_xxx主要讨论关于方法编号相关的东西

imp_xxx主要讨论关于方法实现相关的

下面我们来玩一下这些常用的api

//交换方法
        Method m1 = class_getInstanceMethod(self, @selector(viewWillAppear:));
        Method m2 = class_getInstanceMethod(self, @selector(tz_viewWillAppear:));        
        method_exchangeImplementations(m1, m2);
// 关联属性
- (void)setViewColor:(NSString *)viewColor{
    
    objc_setAssociatedObject(self, &associatedObjectKey, @"addProperty", OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSString *)viewColor{
    return objc_getAssociatedObject(self, &associatedObjectKey);
}

 /// 创建一类对
    Class TZCat = objc_allocateClassPair([NSObject class], "TZCat", 0);
    
    /// 添加实例变量
    // const char* types= "v@:"
    NSString* name = @"name";
   
    class_addIvar(TZCat, name.UTF8String, sizeof(id), log2(sizeof(id)), @encode(id));
    
    // 添加方法
    class_addMethod(TZCat, @selector(hunting), (IMP)hunting, "v@:");
    
    /// 注册类
    objc_registerClassPair(TZCat);
    
    
    // 创建实例对象
    id cat = [[TZCat alloc] init];
    [cat setValue:@"Tom" forKey:@"name"];
    NSLog(@"name = %@", [cat valueForKey:name]);
    
    /// 方法调用
    [cat performSelector:@selector(hunting)];

  // 获取成员变量列表
    unsigned int count = 0;
    Ivar* ivars = class_copyIvarList([self class], &count);
    
    for (int i = 0; i < count; i++) {
        Ivar var = ivars[i];
        const char* name = ivar_getName(var);
        NSString* key = [NSString stringWithUTF8String:name];
        id value = [self valueForKey:key];
        [aCoder encodeObject:value forKey:key];
    }
    
    free(ivars);

消息转发机制

    /*
 * 第一步 实例方法专用  方法解析
 **/

+ (BOOL)resolveInstanceMethod:(SEL)sel{

    NSLog(@"%@",NSStringFromSelector(sel));

    if(sel == @selector(DoThings:Num:)){
        class_addMethod([self class], sel, (IMP)MyMethodIMP, "v@:");
        return YES;
    }

    return  [super resolveInstanceMethod:sel];
}

/*
 * 第二步 如果第一步未处理,那么让别的对象去处理这个方法
 **/
-(id)forwardingTargetForSelector:(SEL)aSelector{

    if([NSStringFromSelector(aSelector) isEqualToString:@"DoThings:Num:"]){
        return [[Tools alloc]init];
    }
    return [super forwardingTargetForSelector:aSelector];
}

/*
 * 第三步 如果前两步未处理,这是最后处理的机会将目标函数以其他形式执行
 **/
-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
  
    NSString *SelStr = NSStringFromSelector(aSelector);
    if([SelStr isEqualToString:@"DoThings:Num:"]){
        [NSMethodSignature signatureWithObjCTypes:"v@:"];
    }
    return [super methodSignatureForSelector:aSelector];
}

-(void)forwardInvocation:(NSInvocation *)anInvocation{

    //改变消息接受者对象
    [anInvocation invokeWithTarget:[[Tools alloc]init]];
    
    //改变消息的SEL
    anInvocation.selector = @selector(flyGame);
    [anInvocation invokeWithTarget:self];
    
}

- (void)flyGame{
    
    NSLog(@"我要飞翔追逐梦想!");
    
}

/*
 * 作为找不到函数实现的最后一步,NSObject实现这个函数只有一个功能,就是抛出异常。
 * 虽然理论上可以重载这个函数实现保证不抛出异常(不调用super实现),但是苹果文档着重提出“一定不能让这个函数就这么结束掉,必须抛出异常”。
 *
 ***/
- (void)doesNotRecognizeSelector:(SEL)aSelector{

}

消息机制

objc_msgSend("对象","SEL","参数"...)
objc_msgSend( id self, SEL op, ... )

runtime 源码地址:https://github.com/gongkuihua/objc4-750-master

来源地址

你可能感兴趣的:(iOS底层原理runtime 方法列表 以及常用api调用)