通过runtime 动态生成 getter setter

起因

由于oc 的动态性,支持在运行时生成函数,于是想测试下如何生成setter,getter。下方代码是一个简单的例子。

我把 property 声明成了 dynamic ,这样编译器就不会再替我们生成 getter setter ivar了,然后我在运行时动态追加 getter setter ,并测试是否会导致 crash,如果没有出现 unrecognized selector 报错,就成功了。

当然我这只是一个demo,有很多硬编码,真实运用不能这样写,得追加一个NSObject的分类进行全局 hook

源码

//
//  ViewController.m
//  TestDynamicProperty
//
//  Created by zhiyunyu on 2019/6/10.
//  Copyright © 2019年 zhiyunyu. All rights reserved.
//

#import "ViewController.h"
#import "CodeZipper.h"
#import  

@interface ViewController ()
@property(nonatomic, assign) NSUInteger num;

@end

@implementation ViewController {
    CZ_DYNAMIC_PROPERTYS_FLAG_VAR
    NSUInteger _num;
}

@dynamic num;

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    // 测试setter
    self.num = 100;
    // 测试getter
    NSLog(@"self.num = %@", @(self.num));
}

+ (BOOL)resolveInstanceMethod:(SEL)sel {
    NSString *ivarName = @"_num";
    Ivar ivar = class_getInstanceVariable([self class], [ivarName UTF8String]);
    ptrdiff_t offset = ivar_getOffset(ivar);
    
    if (sel == @selector(setNum:)) {
        IMP imp = NULL;
        imp = imp_implementationWithBlock(^(id receive, unsigned long value){
            char *ptr = ((char *)(__bridge void*)receive) + offset;
            memcpy(ptr, &value, sizeof(value));
        });
        class_addMethod([self class], sel, imp, "v@:L");
        return YES;
    } else if (sel == @selector(num)) {
        IMP imp = NULL;
        imp = imp_implementationWithBlock(^(id receive){
            char *ptr = ((char *)(__bridge void*)receive) + offset;
            unsigned long value;
            memcpy(&value, ptr, sizeof(value));
            return value;
        });
        class_addMethod([self class], sel, imp, "L@:");
        return YES;
    }
    
    return [super resolveInstanceMethod:sel];
}

@end


你可能感兴趣的:(通过runtime 动态生成 getter setter)