美文网首页
runtime的基本使用

runtime的基本使用

作者: 隔壁家的老田 | 来源:发表于2016-07-28 21:31 被阅读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指定的方法名相同即可

    相关文章

      网友评论

          本文标题:runtime的基本使用

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