写点什么

runtime 笔记

用户头像
Conan
关注
发布于: 2021 年 02 月 24 日

Person *p = [Person alloc];

p = [p init];


可以写成

Person *p = objc_msgSend(objc_getClass("Person"), sel_registerName("alloc"));

p = objc_msgSend(p, @selector(init));


获取一个类的所有方法(包括属性的 get 和 set 的方法),必须导入库 #import <objc/runtime.h>

unsigned int count = 0;

    // 调用完这个方法,count 就有值,记录方法列表总数

    // 获取仅仅是当前类

    // 返回指向方法列表数组

    Method *methodList = class_copyMethodList([Person class], &count);

    // 2 0 1

    for (int i = 0; i < count; i++) {

        // 取出对应的方法

        Method method = methodList[i];

        // 获取方法名(方法编号)

        SEL methodSel =  method_getName(method);

        NSLog(@"%@",NSStringFromSelector(methodSel));

    }

//通过 runtime 获得类中属性的列表 不包含.m 中的 @property 属性

    //就是返回的属性个数,也就是返回值的数组的 count

    unsigned int outCount;

    objc_property_t * propertys = class_copyPropertyList(clazz, &outCount);

    for(int i = 0; i < outCount;i++)

    {

        //取出具体的某一个属性

        objc_property_t property = propertys[i];

        //获得类属性的名称

        const char * propertyName = property_getName(property);

        //转换成 oc 字符串

        NSString * propertyNameOC = [NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding];

        //NSLog(@"%@",propertyNameOC);

        //attributes 中获得重要信息

        //1.属性的数据类型是什么

        //2.属性与那个成员变量相关联

        const char * attributes = property_getAttributes(property);

        NSString * attributesString = [NSString stringWithCString:attributes encoding:NSUTF8StringEncoding];

        //NSLog(@"%@",attributesString);

    }

    方法交换适用于重写初始化

    Method imageNameMethod = class_getClassMethod(self, @selector(imageNamed:));

    // 获取 yc_imageNamed 方法

    Method yc_imageNameMethod = class_getClassMethod(self, @selector(yc_imageNamed:));

    // 交换方法实现

    method_exchangeImplementations(imageNameMethod, yc_imageNameMethod);

动态添加属性

#import "NSObject+Property.h"

#import <objc/message.h>

@implementation NSObject (Property)

- (void)setName:(NSString *)name

{

    // name 保存到对应对象

    // 动态添加属性

    // object:给那个对象添加属性

    // key:属性名

    // value:把什么对象保存起来

    // policy:策略,用什么策略

    objc_setAssociatedObject(self, @"name", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

}

- (NSString *)name

{

    return objc_getAssociatedObject(self, @"name");

}


 案例请查看 uitextfiled 扩展类修改 placeholder 的颜色

动态添加方法带参数  开发场景:如果一个类方法非常多,加载了到内存的时候也比较耗费资源,需给每个方法生成映射表,可以使用动态给某个类,添加方法解决

#Person.m文件中

// C 语言中所有对象类型用 id

void conan_eat(id self, SEL _cmd, id prame1){

    NSLog(@“调用 eat 方法 %@ %@ %@",self,NSStringFromSelector(_cmd),prame1);

}

+ (BOOL)resolveInstanceMethod:(SEL)sel{

    // 动态添加未实现的方法

    if (sel == @selector(eat:)) {

        /**

         v : void         @ : 对象         : : SEL         */

        class_addMethod(self, sel, (IMP)conan_eat, "v@:@");

        // 处理完

        return YES;

    }

    return [super resolveInstanceMethod:sel];

}

#ViewControllers 中

 [p performSelector:@selector(eat:) withObject:@11];


动态添加方法不带参数

#import "Person.h"

#import <objc/message.h>

@implementation Person

/**

 默认一个方法都有两个参数,self,_cmd,为隐式参数,不显示 self :方法的调用者 _cmd :调用方法的编号,即方法名 */

//1. 定义一个函数(函数名随便写)

// 无返回值,参数(id,SEL)

void tangtang_eat(id self, SEL _cmd){

    NSLog(@"调用糖糖的 eat 方法 %@ %@",self,NSStringFromSelector(_cmd));

}

/**

 2.处理为实现的实例方法 动态添加方法,首先实现这个resolveInstanceMethod方法 resolveInstanceMethod调用的情况:当调用了一个没有实现的方法,就会调用resolveInstanceMethod这个方法 <#sel#>:没有实现的方法 */

+ (BOOL)resolveInstanceMethod:(SEL)sel{

    // 动态添加未实现的方法

    if (sel == @selector(eat)) {

        /**

         v : void         @ : 对象         : : SEL         */

        class_addMethod(self, sel, (IMP)tangtang_eat, "v@:");

        // 处理完

        return YES;

    }

    return [super resolveInstanceMethod:sel];

}

@end

#在 viewController 中

- (void)viewDidLoad {

    [super viewDidLoad];

    Person *p = [[Person alloc]init];

    //performSelector:即为动态添加方法

    [p performSelector:@selector(eat)];

}

获取加方法  :  class_getClassMethod 

获取减方法   :  class_getInstanceMethod   

method_exchangeImplementations( 方法 1,方法 2 );

Class 的各项操作

3.1 add*(增加)

        3.1.1 static IMP addMethod(Class cls, SEL name, IMP imp, const char *types, BOOL replace);//增加方法

        3.1.2 BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types);//增加类方法

        3.1.3 BOOL class_addIvar(Class cls, const char *name, size_t size,uint8_t alignment, const char *type);//增加实例变量

        3.1.4 static BOOL _class_addProperty(Class cls, const char *name,const objc_property_attribute_t *attrs, unsigned int count,BOOL replace);//增加属性

    3.2 replace*(修改)

        3.2.1 IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types); //修改方法

        3.2.2 void class_replaceProperty(Class cls, const char *name,const objc_property_attribute_t *attrs, unsigned int n);//修改属性

    3.3 get*(获取)

        3.3.1 static Class getClass(const char *name);//获取类

        3.3.2 static ivar_t *getIvar(Class cls, const char *name);//获取类变量(static 相当于“+“)

        3.3.3 Method class_getInstanceMethod(Class cls, SEL sel);//获取实例方法

        3.3.4 static Method _class_getMethod(Class cls, SEL sel);;//获取类方法

        3.3.5 static Protocol *getProtocol(const char *name);//获取协议方法

    3.4 set*(设置)

        3.4.1 objc_class::setInitialized();//set 的 initialized 初始化

        3.4.2 static Class setSuperclass(Class cls, Class newSuper);//设置父类

    3.5 其他还有类似于 void *objc_destructInstance(id obj);//摧毁实例对象等等

Class 的重要函数

4.1 get*(获取)        4.1.1 object_getClass(id obj);        4.1.2 IMP object_getMethodImplementation(id obj, SEL name);//获得实例方法实现        4.1.3 Ivar object_getInstanceVariable(id obj, const char *name, void **value)//获取实例属性    4.2 set*(设置)        4.2.1 Class object_setClass(id obj, Class cls);        4.2.2 Ivar object_setInstanceVariable(id obj, const char *name, void *value);//设置实例属性        4.2.3 void object_setIvar(id obj, Ivar ivar, id value);//设置实例变量    4.3 其他        4.3.1 static void _class_resolveClassMethod(Class cls, SEL sel, id inst);//动态添加类方法,不必在乎方法是否存在        4.3.2 static void _class_resolveInstanceMethod(Class cls, SEL sel, id inst);//动态添加实现方法,不必在乎方法是否存在        4.3.3 unsigned _class_createInstancesFromZone(Class cls, size_t extraBytes, void *zone,id *results, unsigned num_requested);//创建实例存储空间    4.4 消息转发

        4.4.1 void    instrumentObjcMessageSends(BOOL flag);//flag 传入 YES,运行时发送的所有消息都会打印到/tmp/msgSend-xxxx 文件里了。


发布于: 2021 年 02 月 24 日阅读数: 19
用户头像

Conan

关注

还未添加个人签名 2021.02.24 加入

还未添加个人简介

评论

发布
暂无评论
runtime笔记