前言

iOS开发者都知道,runtime和GCD在实际开发中有多重要,在此仅记录我本人在开发中对于前者最常用的应用和感受,具体详细介绍不在赘述。想了解可自行百度,谷歌。
iOS Runtime详解
iOS 模式详解—「runtime&runloop 面试、工作」
Objective-C Runtime 深入了解

正题

关联对象(Objective-C Associated Objects)给类增加属性。即在既有类中使用关联对象存放自定义数据。
使用关联对象时,若想令两个键匹配到同一个值,则两者需为完全相同的指针,鉴于此,通常用静态全局变量做键。
实际开发中,有以下几中写法:

#import "objc/runtime.h"
@interface NSObject (runtime)
@property (nonatomic, copy) NSString *test;
@end  
 
@implementation NSObject (runtime)
//1.使用静态常量
//static char kTestKey;
//static void * const kTestKey = &kTestKey;
static const void * kTestKey = "kTestKey";
- (void)setTest:(NSString *)test {
    objc_setAssociatedObject(self, kTestKey, test, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    //2.使用方法名
    //objc_setAssociatedObject(self, @selector(setTest:), test, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSString *)test {
    return objc_getAssociatedObject(self, kTestKey);
    //return objc_getAssociatedObject(self, _cmd);
    //return objc_getAssociatedObject(self, @selector(setTest:));
}
@end

方法调配(Method Swizzling)给类添加或替换方法。

@implementation ViewController

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class class = [self class];
        SEL originalSelector = @selector(viewDidLoad);
        SEL swizzledSelector = @selector(testViewDidLoad);

        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

        //判断原方法存在
        BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
        // if swizzledMethod is already existed.
        if (didAddMethod) {
            class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
        }
        else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    });
}

- (void)testViewDidLoad {
    //替换方法 
    [self testViewDidLoad];
}

- (void)viewDidLoad {
    //原方法
    [super viewDidLoad];
}

@end

看上去好像陷入递归调用的死循环,但是此方法是和原方法互换的,所以在运行期,替换方法的选择子(selector)实际上对应于原有方法的实现。

其他应用

动态变量控制,私有属性赋值/取值
实现NSCoding的自动归/解档
实现字典和模型的自动转换 等等
以上应用并不频繁,不再多说。
总之runtime在实际开发中十分便捷,不过我了解的只是皮毛,对于对象、消息、运行期还需要更深层次的理解。