文章

运行时

几个常见应用


1、交换方法的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@implementation UIImage (Image)

// 加载分类到内存的时候调用,在 init: 方法之前调用
+ (void)load {
    // 交换方法
    
    // 获取 imageWithName 方法地址
    Method imageWithName = class_getClassMethod(self, @selector(imageWithName:));
    
    // 获取 imageName 方法地址
    Method imageName = class_getClassMethod(self, @selector(imageNamed:));

    // 交换方法的实现
    method_exchangeImplementations(imageWithName, imageName);
}

// 不能在分类中重写系统方法 imageNamed,因为会把系统的功能给覆盖掉,而且分类中不能调用 super

// 可以先对图片做某些处理
+ (instancetype)imageWithName:(NSString *)name {
   
    // 这里调用 imageWithName,相当于调用 imageName 的实现。
    UIImage *image = [self imageWithName:name];
    
    if (image == nil) {
        NSLog(@"加载空的图片");
    }
    
    return image;
}

@end


2、给分类添加属性

  • 在分类中声明属性,实际上仅仅是声明,并没有实现,实现需要通过 runtime 来完成。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 定义关联的key
static const char *key = "name";

@implementation NSObject (Category)

- (NSString *)name {
    // 根据关联的 key,获取关联的值。
    return objc_getAssociatedObject(self, key);
}

- (void)setName:(NSString *)name {
    // 第一个参数:给哪个对象添加关联
    // 第二个参数:关联的key,通过这个key获取
    // 第三个参数:关联的value
    // 第四个参数:关联的策略
    objc_setAssociatedObject(self, key, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

@end


3、字典转模型 & 归解档实现

  • 通过 KVC 实现字典转模型不够灵活,模型的属性和字典的 key 必须一一对应,否则会报错,此时可以用 runtime 灵活的实现
  • 实现 NSCoping 协议时,在归档解档方法中获取类的所有属性,再遍历,一个个设置。
1
2
3
4
5
6
7
8
9
// class_copyIvarList:获取类中的所有成员属性(包括定义在 .m 文件中的私有属性)
// 第一个参数:表示获取哪个类中的成员属性
// 第二个参数:表示这个类有多少成员属性,传入一个Int变量地址,会自动给这个变量赋值
    
unsigned int count;
Ivar *ivarList = class_copyIvarList([self.person class], &count);

// 获取成员属性名
NSString *name = [NSString stringWithUTF8String:ivar_getName(ivarList[i])];
本文由作者按照 CC BY 4.0 进行授权