最近开始学习runtime,想挖掘iOS的运行机制,经过几天折腾,终于初窥门径,首先记录关于成员变量和属性的学习内容
1.获取成员变量
Ivar: 实例变量类型,是一个指向objc_ivar结构体的指针
typedef struct objc_ivar *Ivar;
model的声明:
#import <Foundation/Foundation.h>
@interface Model : NSObject
{
NSString * _string1;
}
@property NSString * string2;
@property (nonatomic, copy) NSDictionary * dict;
@end
关键代码:
#import "ViewController.h"
#import "Model.h"
#import <objc/runtime.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//获取成员变量
[self test1];
}
-(void)test1{
unsigned int outCount = 0;
Ivar * ivars =class_copyIvarList([Model class], &outCount);//获取该类中所有的成员变量
for (unsigned int i = 0; i < outCount; i++) {
Ivar ivar = ivars[i];
const char * name = ivar_getName(ivar);//获取成员变量的名称
const char * type = ivar_getTypeEncoding(ivar);//获取成员变量的类型
NSLog(@"类型:%s \n名称:%s ", type, name);
}
//释放内存
free(ivars);
}
2.获取属性
objc_property_t:声明的属性的类型,是一个指向objc_property结构体的指针
typedef struct objc_property *objc_property_t;
关键代码:
-(void)test2{
unsigned int outCount = 0;
objc_property_t * properties = class_copyPropertyList([Model class], &outCount);
for (unsigned int i = 0; i < outCount; i++) {
objc_property_t property = properties[i];
//属性名
const char * name = property_getName(property);
//属性描述
const char * propertyAttr = property_getAttributes(property);
NSLog(@"属性描述为 %s 的 %s ", propertyAttr, name);
//属性的特性
unsigned int attrCount = 0;
objc_property_attribute_t * attrs = property_copyAttributeList(property, &attrCount);
for (unsigned int j = 0; j < attrCount; j++) {
objc_property_attribute_t attr = attrs[j];
const char * name = attr.name;
const char * value = attr.value;
NSLog(@"属性的描述:%s 值:%s", name, value);
}
free(attrs);
NSLog(@"\n===============\n");
}
free(properties);
}
其他代码同test1。
3.获取在.m中声明的变量
#import "JsonToModelBaseClass.h"
@interface JsonToModelBaseClass ()
{
NSString * _string1;
}
@end
@implementation JsonToModelBaseClass
@end
关键代码:
-(void)test3{
JsonToModelBaseClass * baseModel = [[JsonToModelBaseClass alloc] init];
Ivar ivar = class_getInstanceVariable([baseModel class], "_string1");
NSString * str = object_getIvar(baseModel, ivar);
NSLog(@"%@", str);
}
4.json转model
首先创建一个NSObject+RunTime的分类
#import <Foundation/Foundation.h>
@interface NSObject (RunTime)
-(instancetype)initWithDict:(NSDictionary *)dict;
@end
关键代码
#import "NSObject+RunTime.h"
#import <objc/runtime.h>
@implementation NSObject (RunTime)
-(instancetype)initWithDict:(NSDictionary *)dict {
if (self == [self init]) {
[self setPropertyWithDict:dict];
}
return self;
}
-(void)setPropertyWithDict:(NSDictionary *)dict{
//(1)获取类的属性及属性对应的类型
NSMutableArray * keyArray = [NSMutableArray array];
NSMutableArray * attributeArray = [NSMutableArray array];
unsigned int outCount = 0;
objc_property_t * properties = class_copyPropertyList([self class], &outCount);
for (unsigned int i = 0; i < outCount; i++) {
objc_property_t property = properties[i];
//通过property_getName函数获得属性的名字
NSString * propertyName = [NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
[keyArray addObject:propertyName];
//通过property_getAttributes函数可以获得属性的名字和@encode编码
NSString * propertyAttribute = [NSString stringWithCString:property_getAttributes(property) encoding:NSUTF8StringEncoding];
[attributeArray addObject:propertyAttribute];
}
//释放properties
free(properties);
//(2)根据类型给属性赋值
for (NSString * key in keyArray) {
if ([dict valueForKey:key] == nil) {
continue;
}
[self setValue:[dict valueForKey:key] forKey:key];
}
}
然后创建model声明属性
#import <Foundation/Foundation.h>
@interface JsonToModelBaseClass : NSObject
@property (nonatomic, copy) NSString * name;
@property (nonatomic, copy) NSString * age;
@property (nonatomic, copy) NSString * intro;
@end
实现
-(void)test4{
NSDictionary * dict = @{@"name" : @"xiaoming",
@"age" : @"20",
@"intro" : @"SB"};
JsonToModelBaseClass * baseModel = [[JsonToModelBaseClass alloc] initWithDict:dict];
NSLog(@"%@", baseModel);
}
这样就会像KVC一样,直接把json中相应的数据赋值给model.