Swift&Objective-C

Objective-C之我所理解的Runtime

2019-01-24  本文已影响6人  Bestmer

前言

Runtime,俗称运行时,是iOS非常核心的东西。我们都知道OC是一门动态的语言,它的动态其实就体现在运行时而不是编译时,通俗的说,在程序没有完全运行起来时,一切都有可能发生。正是因为这种机制,为我们提供了很多黑魔法,我们可以利用它做很多事情。由于runtime是基于C层面的一套API,所以学习它我们能够清楚很多OC层面代码的本质。本文不谈理论,不谈概念,只谈runtime在工作中的常用情景,毕竟理论的东西只有付诸于实践才能发挥价值。


1.为系统的类添加属性

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface NSObject (Custom)

@property NSString *name;

@end

NS_ASSUME_NONNULL_END
#import "NSObject+Custom.h"
#import <objc/message.h>

@implementation MSObject (Custom)

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

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


2.动态添加方法

// 方法调用


Person *person = [Person new];
// 无参数
[person performSelector:@selector(eat)];
// 1个参数
[person performSelector:@selector(drink:) withObject:@"cola"];
// 2个参数
[person performSelector:@selector(sleep:) withObject:@"Marry" withObject:@10];
    
#import "Person.h"
#import <objc/message.h>

void eat(id self, SEL _cmd) {
    NSLog(@"eat what tonight");
}

void drink(id self, SEL _cmd, NSString *name) {
    NSLog(@"I like dring %@", name);
}

void sleeps(id self, SEL _cmd, NSString *name, NSNumber *hours) {
    NSLog(@"Sleep with %@ for %@ hours", name, hours);
}

@implementation Person

+ (BOOL)resolveInstanceMethod:(SEL)sel {
    if (sel == NSSelectorFromString(@"eat")) {
        class_addMethod(self, sel, (IMP)eat, "v@:");
        return YES;
    } else if (sel == NSSelectorFromString(@"drink:")) {
        class_addMethod(self, sel, (IMP)drink, "v@:@");
    } else if (sel == NSSelectorFromString(@"sleep:")) {
        class_addMethod(self, sel, (IMP)sleeps, "v@:@");
    }
    return [super resolveInstanceMethod:sel];
}

@end


3.方法互换

image
#import "UIImage+Custom.h"
#import <objc/message.h>

@implementation UIImage (Custom)

// 把类加载进内存时调用,只调用一次
+ (void)load {
    Method imageNamedMethod = class_getClassMethod(self, sel_registerName("imageNamed:"));
    Method my_imageNamed = class_getClassMethod(self, @selector(my_imageNamed:));
    method_exchangeImplementations(imageNamedMethod, my_imageNamed);
}

+ (UIImage *)my_imageNamed:(NSString *)name {
    UIImage *image = [UIImage my_imageNamed:name];
    if (image) {
        NSLog(@"图片赋值成功,图片名称为:%@", name);
    } else {
        NSLog(@"图片赋值失败,找不到图片名称:%@", name);
    }
    return image;
}

@end

4.获取成员变量内部信息

 unsigned int count = 0;
    Ivar *varList = class_copyIvarList(self.class, &count);
    for (int i = 0; i < count; i++) {
        // 获取成员变量的名称
        NSString *ivarName = [NSString stringWithUTF8String:ivar_getName(varList[i])];
        // 获取成员变量的类型
        NSString *ivarType = [NSString stringWithUTF8String:ivar_getTypeEncoding(varList[i])];
    }

5.获取私有方法列表

unsigned int count = 0;
Method *methodList = class_copyMethodList(UIViewController.class, &count);
for (int i = 0; i < count; i++) {
    // 获取成员变量的名称
    SEL sel = method_getName(methodList[I]);
    NSString *selName = NSStringFromSelector(sel);
    NSLog(@"%@", selName);
}

6.消息处理


7.APP防crash处理


最后

温故而知新。

上一篇 下一篇

猜你喜欢

热点阅读