runtime 笔记
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 文件里了。
版权声明: 本文为 InfoQ 作者【Conan】的原创文章。
原文链接:【http://xie.infoq.cn/article/b5828dfffd2668c085a0b7d1e】。文章转载请联系作者。
评论