Objective-C 是一门动态语言,有很多东西都是运行时才确定的。
比如这句代码首先声明testObject是一个NSString,然后创建了一个NSData对象,并且将这个对象的内存地址保存在test Object中。运行的时候textObject只想的就是一个NSData对象。
NSString *testObject = [[NSData alloc]]init];
Runtime,是一套运行机制。是拿C语言一套比较底层的API,里面于很多很好很强大的方法。我们平写的OC的代码转成Runtime进行实现。就像我们初始化一个对象的时候
OC : [[Person alloc] init] runtime : objc_msgSend(objc_msgSend("Person" , "alloc"), "init")还有我们调用方法的时候,是这个样子的 OC: [object method] Runtime: object_msgSend(obj,@selector(method));
既然Runtime是属于OC的底层,name他就可以进行一些比较底层的操作。Objective-C能做的事情他能做,runtime能做的事情object-C就不一定能做到了,比如我们可以在程序运行的时候添加一个类,遍历一个类的成员,或者为某一个类添加一个属性,修改属性值之类的操作。
下面我们就举个例子用Runtime遍历模型属性,对属性进行归档结档操作。
第一步我们需要倒入相关的头文件,运行时相关的头文件一般都存放在头文件的/objc中,比较常用的<objc/runtime.h>,<objc/message>。
1. 可以先做一个测试,我在控制器的viewDidLoad里面写了一段代码,
- (void)viewDidLoad { [super viewDidLoad]; unsigned int count = 0; Ivar *ivars = class_copyIvarList([SQKPerson class], &count); for (int i = 0; i<count; i++) { // 取出i位置对应的成员变量 Ivar ivar = ivars[i]; // 查看成员变量 const char *name = ivar_getName(ivar); NSLog(@"%s", name); }
打印的结果是
2015-10-28 22:47:41.186 runtime[2312:108141] _age2015-10-28 22:47:41.186 runtime[2312:108141] _height2015-10-28 22:47:41.186 runtime[2312:108141] _name
3. 创建一个Person的类,声明了三个属性,age,height,name。
//// SQKPerson.m// runtime//// Created by SQK on 15/10/28.// Copyright © 2015年 SQK. All rights reserved.//#import "SQKPerson.h"#import <objc/runtime.h>/** * 进行归档接档,需要遵守NSCoding协议 */@interface SQKPerson ()<NSCoding>//在这里声明了属性@property (nonatomic, assign) int age;@property (nonatomic, assign) int height;@property (nonatomic, copy) NSString *name;@end@implementation SQKPerson- (void)encodeWithCoder:(NSCoder *)encode{ unsigned int count = 0; Ivar *ivars = class_copyIvarList([SQKPerson class], &count); for (int i = 0; i<count; i++) { //获取Ivars成员变量 Ivar ivar = ivars[i]; //需要将name转成URTF8类型的 const char *name = ivar_getName(ivar); NSString *key = [NSString stringWithUTF8String:name]; //归档 id value = [self valueForKey:key]; [encode encodeObject:value forKey:key]; } //需要管理内存 free(ivars);}-(instancetype)initWithCoder:(NSCoder *)decoder{ if (self= [super init]) { unsigned int count = 0; Ivar *ivars = class_copyIvarList([SQKPerson class], &count); for (int i = 0; i<count; i++) { //取出对应的成员变量 Ivar ivar = ivars[i]; const char *name = ivar_getName(ivar); //结档 NSString *key = [NSString stringWithUTF8String:name]; //通过key取到成员变量(kvc) id value = [decoder decodeObjectForKey:key]; //设置value到成员变量身上 [self setValue:value forKey:key]; } free(ivars); } return self;}@end
如果我们模型中的属性很多的话,那么用这种方法进行操作是很方便的。
总之,runtime是很强大的一套语言库。在苹果的官方文档中也给出了详细的文档,对各种进行详细的解释
class_getName
class_addIvar
class_copyIvarList
class_getProperty
class_getPropertyList
....................
总而言之,Runtime是很好的一套东西,希望我们都能对他有所了解。我写这东西也是一边学一边写,难免避免有错误的见解。希望能和大家共同进步!