获取isa指向的Class,如果person是实例对象,获取得是类对象。如果person是类对象,获取得是元类对象
object_getClass(person)
获取父类
class_getSuperclass([person class])
//设置isa指向的Class
#import
#import
#import "Person.h"
#import "Cat.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *person = [[Person alloc]init];
[person run];
object_setClass(person,[Cat class]);
[person run];
}
return 0;
}
//运行结果为:
2021-09-29 11:29:14.438525+0800 Test[47604:2583284] -[Person run]
2021-09-29 11:29:14.439851+0800 Test[47604:2583284] -[Cat run]
iOS的KVO实现就使用到这个API,系统会将isa指针设置为被观察的衍生子类。
判断一个OC对象是否为Class
object_isClass(person)
判断一个class对象是否为元类
class_isMetaClass([person class]);
动态创建类、成员变量、方法
#import
#import
int main(int argc, const char * argv[]) {
@autoreleasepool {
//创建类
Class newClass = objc_allocateClassPair([NSObject class], "Gog", 0);
//添加成员变量,不能放到注册类的后面,成员变量存储在 class_ro_t只读的数据结构
// 8 : 代表成员变量占用内存大小 1 : 对齐方式,此处固定写1
class_addIvar(newClass, "_name", 8, 1, "@");
//添加方法。可以放在注册类后,方法放在class_rw_t中,是可读可写得数据结构
class_addMethod(newClass, @selector(run), (IMP)run, "v@:");
//注册类
objc_registerClassPair(newClass);
id dog = [[newClass alloc] init];
//成员变量没有set,get方法,不能使用点语法,只能使用Kvc进行赋值取值
[dog setValue:@"abc" forKey:@"_name"];
NSLog(@"%@",[dog valueForKey:@"_name"]);
[dog run];
}
return 0;
}
//运行结果为:
2021-09-29 15:58:49.216396+0800 Interview01-cache[48615:2661474] abc
2021-09-29 15:58:49.217449+0800 Interview01-cache[48615:2661474] run
获取成员变量信息及赋值与取值
#import
#import "Person.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *person = [[Person alloc]init];
//获取成员变量信息
Ivar ageIvar = class_getInstanceVariable([Person class], "_age");
Ivar nameIvar = class_getInstanceVariable([Person class], "_name");
NSLog(@"%s %s",ivar_getName(ageIvar),ivar_getName(nameIvar));
//设置和获取成员变量的值
object_setIvar(person, ageIvar, @10); //方法第三个参数必须传OC对象类型的值,如果传入基本类型的值会报错 No matching function for call to 'object_setIvar'
object_setIvar(person, ageIvar, (__bridge id)(void *)10) ; //经过这样转换就可以成功
object_setIvar(person, nameIvar, @"abc");
NSLog(@"%d %@",person.age,person.name);
}
return 0;
}
//运行结果为:
2021-09-29 16:51:37.145394+0800 Interview01-cache[48878:2680369] _age _name
2021-09-29 16:51:37.146843+0800 Interview01-cache[48878:2680369] -753417967 abc
从上面代码运行结果我们发现_age的值没有设置成功,因为我们在设置值时将它包装成了NSNumber类型,再赋值给int是会失败,object_setIvar 方法有不允许我们直接传int类型的值,所以我们想给基础类型的成员变量赋值是可以使用kvc
成员变量的数量
unsigned int count;
Ivar *ivars = class_copyIvarList([MJPerson class], &count); //返回的是数组,指针可以当做数组使用
for (int i = 0; i < count; i++) {
//取出i位置的成员变量
Ivar ivar = ivars[i];
NSLog(@"%s ",ivar_getName(ivar));
}
free(ivars);
什么是Runtime?平时项目中有用过么?
OC是一门动态性比较强的编程语言,允许很多操作推迟到程序运行时再进行
OC的动态性就是有Runtime来支撑和实现的,Runtime是一套C语言的API,封装了很多动态性相关的函数
平时编写的OC代码,底层都是转换成了RuntimeAPI进行调用的
利用关联对象给分类添加属性
遍历类的所有成员变量(修改私有变量,字典转模型,归档解档)
交换方法实现(交换系统的方法)
利用消息转发机制解决方法找不到的问题