美文网首页
OC Runtime实践

OC Runtime实践

作者: 谁知洛神赋 | 来源:发表于2018-06-17 14:22 被阅读0次

    导入<objc/runtime.h>开启外挂功能
    1.获取属性和方法列表

    #define CLASS_NAME NSStringFromClass([self class])
    
    @implementation NSObject (NSObject_extention)
    
    //判断有没有属性
    - (BOOL)hasProperty:(NSString *)str
    {
        BOOL flag = NO;
        u_int count = 0;
        //class_copyIvarList出来的都是带下划线的, class_copyPropertyList是不带下划线的(只能得到@property声明的)
        Ivar *ivars = class_copyIvarList(objc_getClass([CLASS_NAME UTF8String]), &count);  
        for (int i = 0; i < count; i++) {
            NSString *name = [NSString stringWithUTF8String:ivar_getName(ivars[i])];
            if ([str isEqualToString:name]) {
                flag = YES;
                break;
            }
        }
        return flag;
    }
    
    //判断有没有方法
    - (BOOL)hasMethod:(NSString *)str
    {
        BOOL flag = NO;
        u_int count = 0;
        Method *method = class_copyMethodList(objc_getClass([CLASS_NAME UTF8String]), &count);
        for (int i = 0; i < count; i++) {
            SEL sel = method_getName(method[i]);
            NSString *name = [NSString stringWithUTF8String:sel_getName(sel)];
            if ([name isEqualToString:str]) {
                flag = YES;
                break;
            }
        }
        return flag;
    }
    
    @end
    
    

    2.消息转发处理

        Person *p = [Person new];
        id obj = [p performSelector:@selector(drive) withObject:@"fuck" withObject:@"fuck"];
        
      //在Person类或者类目中,用resolveInstanceMethod处理未实现的消息
    + (BOOL)resolveInstanceMethod:(SEL)sel
    {
        class_addMethod([self class], sel, class_getMethodImplementation(self, @selector(eat:param:)), "v@:@");  //最后一个参数的含义 v:void @:对象->self :表示SEL->_cmd
    
    
        return [super resolveInstanceMethod:sel];
    }
    - (id)eat:(NSString *)str param:(NSString *)str2{
        NSLog(@"%@-%@", str, str2);
        return @"123";
    }
    
    
    1. 替换原生的方法实现(以防止数组指针越界为例)
         NSArray *arr = [NSArray arrayWithObjects:@"123", @"456", nil];
        id obj = [arr objectAtIndex:3];
    
        //在NSArray的类目中实现
    + (void)load { //load方法必执行
        /*
         由于 NSArray是一个类簇,需要把所有的入口都封住才算完美 . 方法还是很常见的,用了runtime的方法替换 . 然后 给NSArray加类别
        __NSSingleObjectArray __NSArray0 __NSArrayI __NSArrayM
         */
        Method oldM = class_getInstanceMethod(objc_getClass("__NSArrayI"), @selector(objectAtIndex:));
        Method newM = class_getInstanceMethod(objc_getClass("__NSArrayI"), @selector(safe_objectAtIndex:));
        method_exchangeImplementations(oldM, newM);
        static dispatch_once_t onceToken;   //将原生函数与自定义函数实现对换
    }
    
    - (instancetype)safe_objectAtIndex:(NSUInteger)index
    {
        if (self.count < (index + 1)) {
            NSLog(@"指针越界,下标:%ld",index);
            return nil;
        }
        
        return [self safe_objectAtIndex:index];
    }
    

    相关文章

      网友评论

          本文标题:OC Runtime实践

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