美文网首页
runtime基础

runtime基础

作者: UILabelkell | 来源:发表于2017-04-18 14:14 被阅读20次

目前我所了解的Runtime内容大约有:动态获取类名、动态获取类的成员变量、动态获取类的属性列表、动态获取类的方法列表、动态获取类所遵循的协议列表、动态添加新的方法、类的实例方法实现的交换、动态属性关联、消息发送与消息转发机制
1、实现方法交换
<pre>
-(void)initWithVie
{
UIButton *btu = [UIButton buttonWithType:UIButtonTypeCustom];
btu.frame = CGRectMake(100, 100, 80, 40);
btu.backgroundColor = [UIColor orangeColor];
[btu addTarget:self action:@selector(clickent:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btu];
}

-(void)clickent:(UIButton *)btn
{
Method m1 = class_getInstanceMethod([self class], @selector(stringStr));
Method m2 = class_getInstanceMethod([self class], @selector(withview));
method_exchangeImplementations(m1, m2);

[self stringStr];
[self withview];

}

-(void)stringStr
{
NSLog(@"%s ---1",FUNCTION);
}

-(void)withview
{
NSLog(@"%s---2",FUNCTION);
}
</pre>
原理:OC的方法调用会在底层转换为向该对象发送消息。这由C语言的函数完成。是通过查找接收消息对象的方法列表,从方法列表中查找对应的SEL,这个SEL对应着一个IMP(一个IMP可以对应多个SEL),通过这个IMP找到对应的方法调用。

在每个类中都有一个Dispatch Table,这个Dispatch
Table本质是将类中的SEL和IMP(可以理解为函数指针)进行对应。而我们的Method
Swizzling就是对这个table进行了操作,让SEL对应另一个IMP。
如图
交换前:


003YMHs7gy72CEFH1e525&690.jpeg

交换后

003YMHs7gy72CEKEp7r51&690.jpeg

2.获取类名 方法
<pre>
/**
获取类名

@param class 相应类
@return NSString:类名
*/

  • (NSString *)fetchClassName:(Class)class {
    const char *className = class_getName(class);
    return [NSString stringWithUTF8String:className];
    }
    用法:
    const char *className = class_getName([TestClass class]);
    NSLog(@"%@",[NSString stringWithUTF8String:className]);
    </pre>

3.获取成员变量
<pre>/**
获取成员变量

@param class Class
@return NSArray
*/

  • (NSArray *)fetchIvarList:(Class)class {
    unsigned int count = 0;
    Ivar *ivarList = class_copyIvarList(class, &count);

    NSMutableArray *mutableList = [NSMutableArray arrayWithCapacity:count];
    for (unsigned int i = 0; i < count; i++ ) {
    NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithCapacity:2];
    const char *ivarName = ivar_getName(ivarList[i]);
    const char *ivarType = ivar_getTypeEncoding(ivarList[i]);
    dic[@"type"] = [NSString stringWithUTF8String: ivarType];
    dic[@"ivarName"] = [NSString stringWithUTF8String: ivarName];

      [mutableList addObject:dic];
    

    }
    free(ivarList);
    return [NSArray arrayWithArray:mutableList];
    }
    常量:共享一块内存空间,就算项目中N处用到,也不会分配N块内存空间,可以根据const修饰的位置设定能否修改,在编译阶段会执行类型检查
    调用方法
    [Ruck fetchIvaList:[TestClass class]]

    unsigned int count = 0;
    Ivar *ivarList = class_copyIvarList([TestClass class], &count);
    NSMutableArray *mutable = [NSMutableArray arrayWithCapacity:count];
    for (unsigned int i = 0; i < count; i++) {
    NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithCapacity:2];
    const char *ivarName = ivar_getName(ivarList[i]);
    const char *ivarType = ivar_getTypeEncoding(ivarList[i]);
    dic[@"type"] = [NSString stringWithUTF8String: ivarType];
    dic[@"ivarName"] = [NSString stringWithUTF8String: ivarName];
    [mutable addObject:dic];
    }
    free(ivarList);
    NSLog(@"is a mutable--%@",mutable);

</pre>

3.获取类的属性列表, 包括私有和公有属性,以及定义在延展中的属性
<pre>/**
获取类的属性列表, 包括私有和公有属性,以及定义在延展中的属性

@param class Class
@return 属性列表数组
*/

  • (NSArray *)fetchPropertyList:(Class)class {
    unsigned int count = 0;
    objc_property_t *propertyList = class_copyPropertyList(class, &count);

    NSMutableArray *mutableList = [NSMutableArray arrayWithCapacity:count];
    for (unsigned int i = 0; i < count; i++ ) {
    const char *propertyName = property_getName(propertyList[i]);
    [mutableList addObject:[NSString stringWithUTF8String: propertyName]];
    }
    free(propertyList);
    return [NSArray arrayWithArray:mutableList];
    }
    </pre>

4.获取类的实例方法列表:getter, setter, 对象方法等。但不能获取类方法
<pre>/**
获取类的实例方法列表:getter, setter, 对象方法等。但不能获取类方法

@param class <#class description#>
@return <#return value description#>
*/

  • (NSArray *)fetchMethodList:(Class)class {
    unsigned int count = 0;
    Method *methodList = class_copyMethodList(class, &count);

    NSMutableArray *mutableList = [NSMutableArray arrayWithCapacity:count];
    for (unsigned int i = 0; i < count; i++ ) {
    Method method = methodList[i];
    SEL methodName = method_getName(method);
    [mutableList addObject:NSStringFromSelector(methodName)];
    }
    free(methodList);
    return [NSArray arrayWithArray:mutableList];
    }
    </pre>

  1. 获取协议列表
    <pre>/**
    获取协议列表

@param class <#class description#>
@return <#return value description#>
*/

  • (NSArray *)fetchProtocolList:(Class)class {
    unsigned int count = 0;
    __unsafe_unretained Protocol **protocolList = class_copyProtocolList(class, &count);

    NSMutableArray *mutableList = [NSMutableArray arrayWithCapacity:count];
    for (unsigned int i = 0; i < count; i++ ) {
    Protocol *protocol = protocolList[i];
    const char *protocolName = protocol_getName(protocol);
    [mutableList addObject:[NSString stringWithUTF8String: protocolName]];
    }

    return [NSArray arrayWithArray:mutableList];
    return nil;
    }
    </pre>

  1. 往类上添加新的方法与其实现
    <pre>
    /**
    往类上添加新的方法与其实现

@param class 相应的类
@param methodSel 方法的名
@param methodSelImpl 对应方法实现的方法名
*/

  • (void)addMethod:(Class)class method:(SEL)methodSel method:(SEL)methodSelImpl {
    Method method = class_getInstanceMethod(class, methodSelImpl);
    IMP methodIMP = method_getImplementation(method);
    const char *types = method_getTypeEncoding(method);
    class_addMethod(class, methodSel, methodIMP, types);
    }
  • (void)method1 {
    NSLog(@"我是Method1的实现");
    }

//运行时方法拦截

  • (void)dynamicAddMethod: (NSString *) value {
    NSLog(@"OC替换的方法:%@", value);
    }

/**
没有找到SEL的IML实现时会执行下方的方法

@param sel 当前对象调用并且找不到IML的SEL
@return 找到其他的执行方法,并返回yes
*/

  • (BOOL)resolveInstanceMethod:(SEL)sel {
    return NO; //当返回NO时,会接着执行forwordingTargetForSelector:方法,
    [RuntimeKit addMethod:[self class] method:sel method:@selector(dynamicAddMethod:)];
    return YES;
    }

/**
将当前对象不存在的SEL传给其他存在该SEL的对象

@param aSelector 当前类中不存在的SEL
@return 存在该SEL的对象
*/

  • (id)forwardingTargetForSelector:(SEL)aSelector {
    return self;
    return [SecondClass new]; //让SecondClass中相应的SEL去执行该方法
    }

  • (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
    //查找父类的方法签名
    NSMethodSignature *signature = [super methodSignatureForSelector:selector];
    if(signature == nil) {
    signature = [NSMethodSignature signatureWithObjCTypes:"@@:"];

    }
    return signature;
    }

  • (void)forwardInvocation:(NSInvocation *)invocation {
    SecondClass * forwardClass = [SecondClass new];
    SEL sel = invocation.selector;
    if ([forwardClass respondsToSelector:sel]) {
    [invocation invokeWithTarget:forwardClass];
    } else {
    [self doesNotRecognizeSelector:sel];
    }
    }
    </pre>

相关文章

网友评论

      本文标题:runtime基础

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