iOS runtime介绍、使用(基本方法篇)

*看完本篇之后你将获得:

1.了解什么是runtime
2.知道可以利用runtime做到哪些事情
3.掌握用runtime开发的常用方法

*定义

1.RunTime简称运行时,就是系统在运行的时候的一些机制,其中最主要的是消息机制。
2.对于C语言,函数的调用在编译的时候会决定调用哪个函数,编译完成之后直接顺序执行,无任何二义性。
3.OC的函数调用成为消息发送。属于动态调用过程。在编译的时候并不能决定真正调用哪个函数(事实证明,在编 译阶段,OC可以调用任何函数,即使这个函数并未实现,只要申明过就不会报错。而C语言在编译阶段就会报错)。
4.只有在真正运行的时候才会根据函数的名称找 到对应的函数来调用。

*进阶

我们为什么要学习runtime
1.runtime可以遍历类和对象的属性、成员变量、方法、协议列表
2.runtime可以动态添加/修改属性,动态添加/修改/替换方法,动态添加/修改/替换协议
3.runtime可以方法拦截调用

1.遍历类和对象的属性、成员变量、方法
通过使用runtime获取类或对象的所有属性、成员变量,包括我们在"command+左击"进去看不到,然后通过

[object setValue:forKeyPath:@""];

进行属性赋值。最常见的应该是TextField的placeholder字体颜色了:

[textField setValue:[UIColor redColor] forKeyPath:@"_placeholderLabel.textColor"];

具体代码如下:

*遍历属性:
    unsigned int count;
    objc_property_t *properties = class_copyPropertyList([UIView class], &count);
    for (int i = 0; i < count; i++) {
        const char *propertiesName = property_getName(properties[i]);
        NSString *str = [NSString stringWithCString:propertiesName encoding:NSUTF8StringEncoding];
        NSLog(@"propertyName : %@", str);
    }

*遍历成员变量:
    typedef struct objc_ivar *Ivar;
    unsigned int count;
    Ivar *ivars = class_copyIvarList([UIView class], &count);
    for (int i = 0; i < count; i++) {
        const char *ivarName = ivar_getName(ivars[i]);
        NSString *str = [NSString stringWithCString:ivarName encoding:NSUTF8StringEncoding];
        NSLog(@"ivarName : %@", str);
    }

*遍历方法:
unsigned count = 0;
    // 获取所有方法
    Method *methods = class_copyMethodList([UIView class], &count);
    for (int i = 0; i < count; i++) {
        Method method = methods[i];
        // 方法类型是SEL选择器类型
        SEL methodName = method_getName(method);
        NSString *str = [NSString stringWithCString:sel_getName(methodName) encoding:NSUTF8StringEncoding];
        
        int arguments = method_getNumberOfArguments(method);
        NSLog(@"methodName : %@, arguments Count: %d", str, arguments);
    }

*遍历协议:
__unsafe_unretained Protocol **protocolList = class_copyProtocolList([self class], &count);
    for (unsigned int i; i%@", [NSString stringWithUTF8String:protocolName]);
    }

2.runtime可以动态添加/修改属性,动态添加/修改/替换方法,动态添加/修改/替换协议

*替换方法(拦截系统方法):
Method origin = class_getInstanceMethod([UIView class], @selector(touchesBegan:withEvent:)); 
Method custom = class_getInstanceMethod([UIView class], @selector(custom_touchesBegan:withEvent:)); 
method_exchangeImplementations(origin, custom);

- (void)custom_touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 
}

*动态添加方法:(为什么动态添加方法)
使用场景:一个类方法非常多,一次性加载到内存比较耗费资源, OC都是懒加载,有些方法可能很久不会调用(只有满足特定条件才会调用),所以就要动态添加方法。

调用eat方法
    Person *p = [[Person alloc] init];
    [p performSelector:@selector(eat)];

// 当一个对象调用未实现的方法,会调用这个方法处理,并且会把对应的方法列表传过来.
// 刚好可以用来判断,未实现的方法是不是我们想要动态添加的方法
.m
#import "Person.h"
@implementation Person

void eat(id self,SEL sel){
    NSLog(@"---runtime---%@ %@",self,NSStringFromSelector(sel));
}

+ (BOOL)resolveInstanceMethod:(SEL)sel{
    if (sel == @selector(eat)) {
        // 动态添加eat方法
        // 第一个参数:给哪个类添加方法
        // 第二个参数:添加方法的方法编号
        // 第三个参数:添加方法的函数实现(函数地址)
        // 第四个参数:函数的类型,(返回值+参数类型) 
        class_addMethod(self, @selector(eat), (IMP)eat, "v@:");
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}
@end



*给category添加属性:

.h
#import 
@interface NSObject (Property){
}
@property (nonatomic,copy) NSString *name;
@end

.m
#import "NSObject+Property.h"
@implementation NSObject (Property)

- (void)setName:(NSString *)name
{
    /*
     object:保存到哪个对象中
     key:用什么属性保存 属性名
     value:保存值
     policy:策略,strong,weak
     */
    objc_setAssociatedObject(self, "name", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSString *)name
{
    return objc_getAssociatedObject(self, "name");
}

你可能感兴趣的:(iOS runtime介绍、使用(基本方法篇))