runtime的基本使用

2016-07-28  本文已影响0人  隔壁家的老田

OC语言是基于C语言进行封装的一种面向对象的语言,因此OC的底层就是C,runtime则是用来链接OC与C,用C语言写的一个库,完成OC所不能完成的事,

以下是Runtime中比较常用的一些方法:
Ivar *class_copyIvarList(Class cls, unsigned int *outCount) //获取所有成员变量
const char *ivar_getName(Ivar v) 获取某个成员变量的名字
const char *ivar_getTypeEncoding(Ivar v) //获取某个成员变量的类型编码
Ivar class_getInstanceVariable(Class cls, const char *name) //获取某个类中指定名称的成员变量
id object_getIvar(id obj, Ivar ivar) //获取某个对象中的某个成员变量的值
void object_setIvar(id obj, Ivar ivar, id value) //设置某个对象的某个成员变量的值
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) //为某个类关联某个对象
id objc_getAssociatedObject(id object, const void *key) //获取到某个类的某个关联对象
void objc_removeAssociatedObjects(id object) //移除已经关联的对象

在OC中,给一个类添加方法和可以使用延展,但使用延展的方法通常只能在本类中使用,在外界就访问不到了,如何才能在其他类中也使用这个类的私有方法和属性呢?
首先必须导入#import <objc/runtime.h>

//编码
- (void)encodeWithCoder:(NSCoder *)aCoder
{
    unsigned int outCount;
    Ivar *ivarList = class_copyIvarList([Person class], &outCount);
    for (NSInteger i = 0; i < outCount; i++) {
        const char *cName = ivar_getName(ivarList[i]);
        NSString *name = [NSString stringWithUTF8String:cName];
        [aCoder encodeObject:[self valueForKey:name] forKey:name];
    }
}
//解码
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
    self = [super init];
    if (self) {
        unsigned int outCount;
        Ivar *ivarList = class_copyIvarList([Person class], &outCount);
        for (NSInteger i = 0; i < outCount; i ++) {
            const char *cName = ivar_getName(ivarList[i]);
            NSString *name = [NSString stringWithUTF8String:cName];
            [self setValue:[aDecoder decodeObjectForKey:name] forKey:name];
        }
        
    }
    return self;
}
- (NSString *)description
{
    /**
     *  class:要获取的类名
     *  @param outCount 通过这一个函数执行之后会将成员变量的个数赋值到此
     *  int *  char * 表示int,char数组
     */
    unsigned int outCount;
    //获取到所有的成员变量
    Ivar *ivarList = class_copyIvarList([Person class], &outCount);
    for (NSInteger i = 0; i < outCount; i++) {
        //每次获取一个成员变量
        Ivar ivar = ivarList[i];
        //获取成员变量的名字和类型编码
        NSLog(@"name = %s,type = %s",ivar_getName(ivar),ivar_getTypeEncoding(ivar));
    }
    return nil;
}

然后在外界就可以使用这个类里面的属性和方法了
有时候,调用值申明没有实现的方法就会造成了程序Cresh,runtime中提供了了几个方法来避免这一问题
1 + resolveInstanceMethod:(SEL)sel // 为一个实例方法动态添加实现 + resolveClassMethod:(SEL)sel // 为一个类方法动态添加实现
2 - (id)forwardingTargetForSelector:(SEL)aSelector
//为没有实现的方法指定一个对象
3 - (void)forwardInvocation:(NSInvocation *)anInvocation
//子类重载这个方法为消息指定其他对象
比如我在.h中定义了walkOnTheStreet:这个方法,但是并没有在.m中实现,那可以调用使用以上几个方法来添加实现

+ (BOOL)resolveInstanceMethod:(SEL)sel
{
    NSString *selString = NSStringFromSelector(sel);
    if ([selString isEqualToString:@"walkOnTheStreet:"]) {
            为一个没有实现的方法动态添加实现
            cls:类
            IMP:要添加的实现
            types:动态添加的实现的类型编码
 
        class_addMethod(self, @selector(walkOnTheStreet:), (IMP)walkFunc, "V@:@");
    }
    return [super resolveInstanceMethod:sel];
}

有了这个方法,即使我们在viewDidLoad中调用没实现的方法也不会Cresh,runtime会帮我们实现,它的强大之处是实现方法可以在别的类中,只要和class_addMethod指定的方法名相同即可

上一篇 下一篇

猜你喜欢

热点阅读