简介
OC作为一门动态语言,它会把一些决定工作从编译推迟到运行时,这个时候就需要一个运行时系统来处理编译之后的代码,这就是runtime存在的意义.它是OC运行框架的一块基石.
我们可以在命令行中执行一下 xcrun -sdk iphonesimulator10.2 clang -rewrite-objc 命令(模拟器版本根据安装的版本来)编译一下某个OC文件,例如 ViewController.m
编译前
#import "ViewController.h"
#import "Person.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Person *p = [[Person alloc] init];
[p eat];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
@end
编译后
// @interface ViewController ()
/* @end */
// @implementation ViewController
static void _I_ViewController_viewDidLoad(ViewController * self, SEL _cmd) {
((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("ViewController"))}, sel_registerName("viewDidLoad"));
Person *p = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("alloc")), sel_registerName("init"));
((void (*)(id, SEL))(void *)objc_msgSend)((id)p, sel_registerName("eat"));
}
static void _I_ViewController_didReceiveMemoryWarning(ViewController * self, SEL _cmd) {
((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("ViewController"))}, sel_registerName("didReceiveMemoryWarning"));
}
// @end
我们可以看到,OC中的方法调用都被转换成了objc_msgSend方法,也就是消息发送.
Runtime基础数据结构
objc_msgSend
OBJC_EXPORT id objc_msgSend(id self, SEL op, ...)
id
typedef struct objc_object *id;
id是一个指向objc_object结构体的指针
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
typedef struct objc_class *Class;
objc_object结构体中有一个isa指针,指向objc_class结构体
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;
struct objc_method_list **methodLists OBJC2_UNAVAILABLE;
struct objc_cache *cache OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
objc_class结构体中包含了:
- isa:元类指针
- super_class:父类指针
- name:类名
- version:类版本信息
- info:供运行时使用的一些位标识
- instance_size:类实例大小
- ivars:成员变量列表,存储Ivar类型
- methodLists:方法列表,存储Method类型
- cache:缓存
- protocols:协议列表
SEL
typedef struct objc_selector *SEL;
可以理解为方法名.我们可以用@selector()或者sel_registerName函数来获取.
Method
表示类中某个方法的类型
typedef struct objc_method *Method;
struct objc_method {
SEL method_name OBJC2_UNAVAILABLE;
char *method_types OBJC2_UNAVAILABLE;
IMP method_imp OBJC2_UNAVAILABLE;
}
- method_name 方法名
- method_types 存储方法参数类型和返回值类型
- method_imp 函数指针
Ivar
表示类中成员变量的类型
typedef struct objc_ivar *Ivar;
struct objc_ivar {
char *ivar_name OBJC2_UNAVAILABLE;
char *ivar_type OBJC2_UNAVAILABLE;
int ivar_offset OBJC2_UNAVAILABLE;
#ifdef __LP64__
int space OBJC2_UNAVAILABLE;
#endif
}
- ivar_name 变量名
- ivar_type 变量类型
- ivar_offset 偏移量
- space 占用空间
IMP
指向方法实现的函数指针
#if !OBJC_OLD_DISPATCH_PROTOTYPES
typedef void (*IMP)(void /* id, SEL, ... */ );
#else
typedef id (*IMP)(id, SEL, ...);
#endif
objc_property_t
表示类属性的类型
typedef struct objc_property *objc_property_t;
Runtime操作函数
类常用操作函数
- 获取类名
OBJC_EXPORT const char *class_getName(Class cls)
- 判断是否是元类
OBJC_EXPORT BOOL class_isMetaClass(Class cls)
- 获取父类
OBJC_EXPORT Class class_getSuperclass(Class cls)
- 获取类指定名字成员变量(可以获取到私有变量)
OBJC_EXPORT Ivar class_getInstanceVariable(Class cls, const char *name)
- 获取类有所成员变量列表
OBJC_EXPORT Ivar *class_copyIvarList(Class cls, unsigned int *outCount)
- 获取类指定名字实例方法(可以获取到私有方法和父类方法)
OBJC_EXPORT Method class_getInstanceMethod(Class cls, SEL name)
- 获取类指定名字类方法(可以获取到私有方法和父类方法)
OBJC_EXPORT Method class_getClassMethod(Class cls, SEL name)
- 获取类指定方法名方法函数指针(可以获取到私有方法)
OBJC_EXPORT IMP class_getMethodImplementation(Class cls, SEL name)
- 判断类是否能响应方法
OBJC_EXPORT BOOL class_respondsToSelector(Class cls, SEL sel)
- 获取类方法列表
OBJC_EXPORT Method *class_copyMethodList(Class cls, unsigned int *outCount)
- 判断是否遵循协议
OBJC_EXPORT BOOL class_conformsToProtocol(Class cls, Protocol *protocol)
- 获取类协议列表
OBJC_EXPORT Protocol * __unsafe_unretained *class_copyProtocolList(Class cls, unsigned int *outCount)
- 获取类指定名字属性
OBJC_EXPORT objc_property_t class_getProperty(Class cls, const char *name)
- 获取类属性列表
OBJC_EXPORT objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)
- 类添加方法
OBJC_EXPORT BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
- 方法替换
OBJC_EXPORT IMP class_replaceMethod(Class cls, SEL name, IMP imp,const char *types)
- 添加成员变量(不能在已存在的类中添加)
OBJC_EXPORT BOOL class_addIvar(Class cls, const char *name, size_t size,uint8_t alignment, const char *types)
- 添加协议
OBJC_EXPORT BOOL class_addProtocol(Class cls, Protocol *protocol)
- 添加属性
OBJC_EXPORT BOOL class_addProperty(Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount)
objc操作函数
- 创建一个类和元类
OBJC_EXPORT Class objc_allocateClassPair(Class superclass, const char *name,size_t extraBytes)
- 注册由objc_allocateClassPair创建的类
OBJC_EXPORT void objc_registerClassPair(Class cls)
- 关联一个对象
OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
- 获取关联对象
OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key)
- 移除所有关联对象
OBJC_EXPORT void objc_removeAssociatedObjects(id object)
Method操作函数
- 获取函数名
OBJC_EXPORT SEL method_getName(Method m) OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
- 获取函数指针
OBJC_EXPORT IMP method_getImplementation(Method m) OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
- 获取方法类型
OBJC_EXPORT const char *method_getTypeEncoding(Method m) OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
- 指定函数指针
OBJC_EXPORT IMP method_setImplementation(Method m, IMP imp) OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
- 交换函数指针
OBJC_EXPORT void method_exchangeImplementations(Method m1, Method m2) OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
示例代码
- 利用runtime简单实现字典转模型
const char *propertyListKey = "PropertyListKey";
+ (NSArray *)getAllPropertyLists {
//获取关联对象
NSArray *proList = objc_getAssociatedObject(self, propertyListKey);
if (proList) {
return proList;
}
//获取类属性列表
unsigned int outCount;
objc_property_t *propertyList = class_copyPropertyList([self class], &outCount);
NSMutableArray *array = [NSMutableArray array];
for (unsigned int i = 0; i < outCount; i++) {
const char *propertyName = property_getName(propertyList[i]);
//转换成oc字符串
NSString *ocStr = [NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding];
[array addObject:ocStr];
}
//设置关联对象 源对象 关键字 关联的对象 关键策略
objc_setAssociatedObject(self, propertyListKey, array.copy, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
free(propertyList);
return array.copy;
}
+ (instancetype)dicChangeYXModel:(NSDictionary *)dic {
id objc = [[self alloc] init];
NSArray *propertyList = [self getAllPropertyLists];
//遍历字典
[dic enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
//判断字典中的key是否有模型中对应的属性
if ([propertyList containsObject:key]) {
[objc setValue:obj forKey:key];
}
}];
return objc;
}
- 利用runtime简单实现反序列化
+ (void)archiveDataWithClassCoder:(NSCoder *)aCoder {
unsigned int count = 0;
Ivar *ivars = class_copyIvarList([self class], &count);
for (int i = 0; i < count; i++) {
const char *str = ivar_getName(ivars[i]);
NSString *name = [NSString stringWithUTF8String:str];
[aCoder encodeObject:[self valueForKey:name] forKey:name];
}
free(ivars);
}
+ (void)unArchiveDataWithClassCoder:(NSCoder *)aDecoder {
unsigned int count = 0;
Ivar *ivars = class_copyIvarList([self class], &count);
for (int i = 0; i < count; i++) {
const char *str = ivar_getName(ivars[i]);
NSString *name = [NSString stringWithUTF8String:str];
[self setValue:[aDecoder decodeObjectForKey:name] forKey:name];
}
free(ivars);
}
- 利用runtime实现简单方法交换
+ (void)load {
SEL originalSel = @selector(viewWillAppear:);
SEL nowSel = @selector(yxLogViewDidLoad);
Method originalMethod = class_getInstanceMethod([self class], originalSel);
Method nowMethod = class_getInstanceMethod([self class], nowSel);
if (class_addMethod([self class], originalSel, method_getImplementation(nowMethod), method_getTypeEncoding(nowMethod))) {
class_replaceMethod([self class], nowSel, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, nowMethod);
}
}
- (void)yxLogViewDidLoad {
[self yxLogViewDidLoad];
NSLog(@"%@",NSStringFromClass([self class]));
}
- 一些自己学习runtime时测试的方法
ViewController.m
@interface ViewController ()
{
NSString *asd;
}
@end
static const char *qweasd = "asddas";
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Person *p = [[Person alloc] init];
[p eat];
//获取类名
const char * name = class_getName([self class]);
NSLog(@"%s",name);
//判断是否元类
BOOL isMetaClass = class_isMetaClass(objc_getMetaClass(name));
NSLog(@"是否是元类? %d 元类是%@",isMetaClass,objc_getMetaClass(name));
//获取指定名字成员变量
Ivar ivar = class_getInstanceVariable([Person class], "asd");
NSLog(@"某个名字的成员变量%s",ivar_getName(ivar));
//获取实例方法()可以获取私有方法
Method method = class_getInstanceMethod([Person class], @selector(laugh));
NSLog(@"实例方法名%@",NSStringFromSelector(method_getName(method)));
//获取类方法
Method classMethod = class_getClassMethod([Person class], @selector(imClassMethod));
NSLog(@"类方法名%@",NSStringFromSelector(method_getName(classMethod)));
//获取方法实现
IMP strMethod = class_getMethodImplementation_stret([Person class], @selector(laugh));
strMethod();
IMP impClassMethod = class_getMethodImplementation(objc_getMetaClass(class_getName([Person class])), @selector(imClassMethod));
impClassMethod();
//判断类是否能响应方法,注意:类方法只能通过元类来寻找,所以返回为0
NSLog(@"这个类知否能响应改方法? %d %d",class_respondsToSelector([Person class], @selector(laugh)),class_respondsToSelector([Person class], @selector(imClassMethod)));
//判断类是否遵循协议
NSLog(@"这个类是否遵循协议? %d",class_conformsToProtocol([Person class], objc_getProtocol("TestProtocol")));
//获取类属性
objc_property_t pro = class_getProperty([Person class], "privatePro");
NSLog(@"这个属性名字是 %s",property_getName(pro));
//动态创建类
Class mycls = objc_allocateClassPair([NSObject class], "MyNewClass", 0);
//class_addIvar(<#__unsafe_unretained Class cls#>, <#const char *name#>, 占用大小, 对齐方式, 类型)
if (class_addIvar(mycls, "myIvar", sizeof(NSString *), 0, "@")) {
NSLog(@"添加成员变量成功");
}
if(class_addMethod(mycls, @selector(myClassMethod:), (IMP)myClassMethod, "v:i")){
NSLog(@"添加方法成功");
}
objc_registerClassPair(mycls);
id myObj = [[mycls alloc] init];
NSString *shiyixia = @"呵呵";
objc_setAssociatedObject(myObj, qweasd, shiyixia, OBJC_ASSOCIATION_RETAIN);
[myObj setValue:@"asddsa" forKey:@"myIvar"];
[myObj performSelector:@selector(myClassMethod:) withObject:@10];
NSLog(@"%@",[myObj valueForKey:@"myIvar"]);
NSString *asd = objc_getAssociatedObject(myObj, qweasd);
NSLog(@"%@",asd);
// [myObj myClassMethod:10];
//关联属性
[NSObject setMyname:@"啦啦"];
NSLog(@"%@",[NSObject myname]);
/*
常用attribute name value
nonatomic "N" ""
strong/retain "&" ""
weak "W" ""
属性的类型type "T" "@TypeName", eg"@\"NSString\""
属性对应的实例变量Ivar "V" "Ivar_name", eg "_name"
readonly "R" ""
getter "G" "GetterName", eg"isRight"
setter "S" "SetterName", eg"setName"
assign/atomic 默认即为assign和retain
*/
objc_property_attribute_t proType = {"T","@\"NSString\""};
objc_property_attribute_t proVisit = {"C",""};
objc_property_attribute_t proIvar = {"V","_myProperty"};
objc_property_attribute_t attri[] = {proType,proVisit,proIvar};
//添加属性
if (class_addProperty([Person class], "myProperty", attri, 3)) {
NSLog(@"添加属性成功");
}
//实现setget方法
class_addMethod([Person class], @selector(myPropertyM), (IMP)myProperty, "@:");
class_addMethod([Person class], @selector(setMyPropertyM:), (IMP)setMyProperty, "v:@");
NSLog(@"获取属性 %@", [p myPropertyM]);
[p setMyPropertyM:@"wowowow"];
NSLog(@"获取属性 %@", [p myPropertyM]);
}
//- (void)myClassMethod:(int)asd {
// //这个方法不会实现,但是需要写(如果是直接调用的话,否则会崩溃)
//
//}
void myClassMethod(id self2,SEL _cmd,NSNumber *a) {
NSLog(@"传过来的值是: %@",a);
Ivar ivar = class_getInstanceVariable([self2 class], "myIvar");
NSString *ads = object_getIvar(objc_getClass("MyNewClass"),ivar);
ads = @"haha";
NSLog(@"%@,%s,%s",ads,ivar_getName(ivar),ivar_getTypeEncoding(ivar));
}
NSString * myProperty(id self1,SEL _cmd) {
Ivar ivar = class_getInstanceVariable([self1 class], "_myProperty");
return object_getIvar(self1, ivar);
}
void setMyProperty(id self1,SEL _cmd,NSString *str) {
Ivar ivar = class_getInstanceVariable([self1 class], "_myProperty");
object_setIvar(self1, ivar, str);
}
Person.h
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger age;
- (void)eat;
- (NSString *)myPropertyM;
- (void)setMyPropertyM:(NSString *)str;
@end
Person.m
@interface Person ()
{
NSString *asd;
NSString *_myProperty;
}
@property (nonatomic, copy) NSString *privatePro;
@end
@implementation Person
- (void)eat {
NSLog(@"吃呀吃");
}
- (void)laugh {
NSLog(@"哈哈");
}
+ (void)imClassMethod {
NSLog(@"我是私有类方法");
}
NSObject+test.h 类别添加属性
@interface NSObject (test)
@property (nonatomic, copy) NSString *myname;
+ (NSString *)myname;
+ (void)setMyname:(NSString *)myname;
@end
NSObject+test.m
const char *mynameV;
@implementation NSObject (test)
+ (NSString *)myname {
return objc_getAssociatedObject(self, mynameV);
}
+ (void)setMyname:(NSString *)myname {
objc_setAssociatedObject(self, mynameV, myname, OBJC_ASSOCIATION_RETAIN);
}
@end