美文网首页
runtime-03runtime的几个应用场景

runtime-03runtime的几个应用场景

作者: 十一遥 | 来源:发表于2019-01-23 16:23 被阅读16次

runtime 的几个应用场景

1.查看成员变量

2.字典转模型

3.方法交换

  • 1.查看成员变量01-修改textField展位文本颜色,给textView添加占位提醒
把textField改成红色 详情点这里
  • 2.字典转模型
 // 假如这是后台收到的数据
        NSDictionary *json = @{
                               @"tagId" : @45676000,
                               @"age3" : @2,        //这个是age3,与本地的模型字段不一样
                               @"weight" : @10.3,
                               @"name" : @"wangcai"
                               };
        
        JFDog *dog = [JFDog jf_objectWithJson:json];

        NSLog(@"\n--tagid:%ld\n--age:%ld\n--weight:%f\n--name:%@\n",dog.tagId,dog.age, dog.weight, dog.name);

//本地模型类
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface JFDog : NSObject

@property (assign, nonatomic) NSInteger tagId;
@property (assign, nonatomic) CGFloat weight;
@property (assign, nonatomic) NSInteger age;
@property (copy, nonatomic) NSString *name;

@end
NS_ASSUME_NONNULL_END
//写个NSObject分类,实现字典转模型
#import "NSObject+JFJson.h"
#import <objc/runtime.h>

@implementation NSObject (JFJson)

+ (instancetype)jf_objectWithJson:(NSDictionary *)json{

    id obj = [[self alloc] init];
    
    unsigned int count;
    Ivar *ivars = class_copyIvarList(self, &count);
    for (int i = 0; i < count; i++) {
        // 取出i位置的成员变量
        Ivar ivar = ivars[I];
        NSMutableString *name = [NSMutableString stringWithUTF8String:ivar_getName(ivar)];
        [name deleteCharactersInRange:NSMakeRange(0, 1)];//删除取出的_字符
        
        // 设值
        id value = json[name];
        
        if ([name isEqualToString:@"age"]) {//处理本地与网络字符不匹配的问题
            value = json[@"age3"];
        }
        [obj setValue:value forKey:name];
    }
    free(ivars);
    
    return obj;
}
@end

//这只是帮助理解字典转模型库的基本实现,离真正意义上的字典转模型库差的还很远,模型嵌套了,复杂数据结果等一大堆问题需要处理。
  • 3.方法交换01-扫盲

方法交换Method Swizzling又叫黑魔法,

#import "ViewController.h"
#import "JFDog.h"

@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];    
   
 JFDog *dog = [JFDog new];
    [dog eat];
}
@end
///JFDog.h
#import <Foundation/Foundation.h>
@interface JFDog : NSObject

- (void)eat;

-(void)play;

+(void)play2;
@end
#import "JFDog.h"
#import <objc/runtime.h>
@implementation JFDog

- (void)eat{
    NSLog(@"dog--eat");
}

-(void)play{
    NSLog(@"dog--play");
}

+(void)play2{
    NSLog(@"classFunc--dog--play");
}

///load 会在类或者类的分类添加到 Objective-c runtime 时调用,
///父类的 +load 方法先于子类的 +load 方法调用,
///分类的 +load 方法先于类本身的 +load 方法调用。
+(void)load{
    
    Method method1 = class_getInstanceMethod(self.class, @selector(eat));
    Method method2 = class_getInstanceMethod(self.class, @selector(play));
//    Method method3 = class_getClassMethod(self, @selector(play2)); //当然你也可以交换类方法和对象方法的实现
    
    //进行交换
    method_exchangeImplementations(method1, method2);
}
@end

///这会打印dog--play,说明方法交换成功了
  • 3.方法交换02-hook
//hook翻译是钩子,吧自己的方法挂载在系统方法中,
//理念就是,先拦截住系统方法,加入处理方案,然后再转到系统方法里

需求:数组添加空对象不会崩溃

//在main函数里创建一个数组调用
    NSString *obj = nil;
    NSMutableArray *array = [NSMutableArray array];
    [array addObject:@"jack"];
    [array insertObject:obj atIndex:0];
//NSMutableArray写个分类
#import "NSMutableArray+Extension.h"
#import <objc/runtime.h>

@implementation NSMutableArray (Extension)

+ (void)load
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        // 类簇:NSString、NSArray、NSDictionary,真实类型是其他类型
        Class cls = NSClassFromString(@"__NSArrayM");
        Method method1 = class_getInstanceMethod(cls, @selector(insertObject:atIndex:));
        Method method2 = class_getInstanceMethod(cls, @selector(jf_insertObject:atIndex:));
        method_exchangeImplementations(method1, method2);
    });
}

- (void)jf_insertObject:(id)anObject atIndex:(NSUInteger)index{

    if (anObject == nil) return;//如果是空对象,就不添加,防止奔溃

    //拦截之后,再调用系统的实现,由于不知道底层实现逻辑,自己实现系统方法可能会出各种意想不到的错
    [self jf_insertObject:anObject atIndex:index];//这儿看似死循环,细理逻辑,方法实现已经交换过了的
}

@end

相关文章

  • runtime-03runtime的几个应用场景

    runtime 的几个应用场景 1.查看成员变量2.字典转模型3.方法交换 1.查看成员变量01-修改textFi...

  • Redis应用的几个场景

    在这篇文章中,我们将阐述 Redis 最常用的使用场景,以及那些影响我们选择的不同特性。 1、会话缓存(Sessi...

  • 详解proxy_pass、upstream与resolver

    应用场景 这里列举几个应用场景,下文会针对这几个场景并结合代码进行分析。 proxy_pass + upstrea...

  • AOP 几个应用场景

    aop 几个应用场景:1、用于日志打印2、用于全局异常处理拦截3、返回值统一处理4、多数据源切换 executio...

  • 直白的表达应用的几个场景

    直白的表达有时候比委婉地表达的效果好。 有以下几个场景: 第一,当沟通无法进行的时候,有些事情没有头绪,...

  • 浅谈runtime的几个应用场景

    前言 写这篇文章也是因为我一个朋友觉得学runtime没啥用处,平时开发也用不到,学了也就是为了应付面试而已,我不...

  • Runtime常用的几个应用场景

    概述 接上篇《Runtime基本原理及Demo》,了解了Runtime相关基础知识后,我们谈一下Runtime常见...

  • Runtime常用的几个应用场景

    概述 接上篇《Runtime基本原理及Demo》,了解了Runtime相关基础知识后,我们谈一下Runtime常见...

  • 必然阶段

    从技术出发,从行业应用出发, 应用场景,新的应用场景,系统观。 所有技术,包括区块链,必然要经历几个过程。想明白了...

  • redis 部分详解

    这里我们通过几个场景,不同维度说下Redis的应用。 高性能适合当做缓存 缓存是Redis最常见的应用场景,之所有...

网友评论

      本文标题:runtime-03runtime的几个应用场景

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