1. runtime这个东西很多人都听说过,最近也比较火,面试的时候被问,做项目的时候对于特殊的需求也是很有用的一个东西。一直在想学习runtime正好趁现在新的项目在设计的阶段学习下。今天就先讲讲如何生成动态的module
2. 首先还是给一个数据源,既然是module那么肯定需要网络请求下来的数据去解析生成这个东西。而这种运行时的不确定性正是runtime的特性。我先定义一个数据源nsdicitonary:`userInfo = @{ @"class": @"testModule",@"property":@[@{@"color":@{@"ID": @"123",@"type": @"12",@"name": @"测试"}},@{@"length": @"32",@"size": @"23",@"color": @"red"}]};`
3. 接着就是创建类(module)
#pragma mark -创建新的类
-(Class)createClassWithClassName:(NSString *)objName
{
//通过获取字符串得到本地是否存在该字符串的module类
NSString *class =[NSString stringWithFormat:@"%@", objName];
const char *className = [class cStringUsingEncoding:NSASCIIStringEncoding];
//从一个字串返回一个类
Class newClass = objc_getClass(className);
if (!newClass) {
// 如果本地没有那么创建一个类
Class superClass = [NSObject class];
newClass = objc_allocateClassPair(superClass,className,0);
}
return newClass;
}
4.创建完类以后需要给module添加属性,这里我用的是这个方法:class_addIvar后面参数类型可以参考这里 动态获取的参数类型
#pragma mark -添加属性
-(void)createIvarsInclass:(Class)myClass withParams:(NSDictionary*)params
{
NSArray *keys = params.allKeys;
for (NSInteger i=0; i<keys.count; i++) {
NSString *key = keys[i];
const char * keyConst = [key UTF8String];
//添加一个NSString的变量,第四个参数是对其方式,第五个参数是参数类型
//class_addIvar(myClass, keyConst, sizeof(NSString *), 0, "@");
if ([key isEqualToString:@"property"]) {
//测试array属性
NSUInteger size;
NSUInteger alignment;
NSGetSizeAndAlignment("@", &size, &alignment);
class_addIvar(myClass, keyConst, size, alignment, "@");
}
else
{
class_addIvar(myClass, keyConst, sizeof(NSString *), 0, "@");
}
}
}
5.网上也有很多是用class_addProperty,因为我是创建module不是给已有的module动态添加属性,所以可以直接使用上面的方法,但是使用上面的方法,就会有一个问题,就是必须要在objc_allocateClassPair和objc_registerClassPair这两个方法之间才可以,否则是不成功的,而class_addProperty则不受此限制,也是因为class_addProperty是在已有的类里面添加属性的缘故。
6.接着就是5提到的objc_registerClassPair这个方法了。
#pragma mark-生成完整的新类
-(id)makeupNewClassWithClass:(Class)newClass
{
// 注册你创建的这个类
objc_registerClassPair(newClass);
//生成了一个实例化对象
id myobj = [newClass new];
return myobj;
}
7.生成完属性以后是需要给属性赋值的,那么代码如下
#pragma mark -给属性赋值
-(void)setIvarsIncontroller:(id)myController withParams:(NSDictionary*)params
{
NSArray *keys = params.allKeys;
NSArray *values = params.allValues;
__weak __typeof(self)weakSelf = self;
for (NSInteger i=0; i<keys.count; i++) {
NSString *key = keys[i];
NSString *value = values[i];
[myController setValue:result forKey:key];
}
}
8.在我们完成上面的内容以后需要检验下我们是否成功的动态创建了一个module,就需要如下这个方法
//打印所有的属性
-(void)printIvarList:(id)instance
{
u_int count;
Ivar *ivarList = class_copyIvarList([instance class], &count);
for (NSInteger i=0; i<count; i++) {
const char *ivarName =ivar_getName(ivarList[i]);
const char *ivarType =ivar_getTypeEncoding(ivarList[i]);
id ivarValue =object_getIvar(instance,ivarList[i]);
NSString *strName = [NSString stringWithCString:ivarName encoding:NSUTF8StringEncoding];
NSString *strType = [NSString stringWithCString:ivarType encoding:NSUTF8StringEncoding];
NSLog(@"ivarName =%@\n ivarType = %@\n ivarValue=%@",strName,strType,ivarValue);
}
}
到此就结束了,我也是刚刚接触runtime,网上说解决一些 不常见的底层需要克服的东西还是有必要的,但是不能常用。因为apple是不同意我们对它的底层框架有太多涉及的地方的。不过出于学习的态度,我自己感觉还是有必要继续探索的。
不过到此我自己也有些迷惑了,希望大神们能指导下,除了这种动态生成module之外,如何利用runtime更多的服务我们的需求?