先看例子
Model
类
#import <Foundation/Foundation.h>
@interface NSObject (Hook)
+ (instancetype)modelWithDict:(NSDictionary *)dict;
@end
#import "TestModel.h"
@implementation TestModel
@end
NSObject
的分类
#import <Foundation/Foundation.h>
@interface NSObject (Hook)
+ (instancetype)modelWithDict:(NSDictionary *)dict;
@end
#import "NSObject+Hook.h"
#import <objc/runtime.h>
const char * kPropertyListKey = "PropertyListKey";
@implementation NSObject (Hook)
+ (NSArray *)getPropertyList{
//获取关联对象,根据关联值的 key 取出关联值,如果有值就返回,没有值,则继续。
NSArray *propertylistArr = objc_getAssociatedObject([self class], kPropertyListKey);
//如果有值,直接返回
if (propertylistArr) {
return propertylistArr;
}
//类属性的个数
unsigned int listOutCount = 0;
//注意 class_copyPropertyList 中是 copy 需要 release 释放一下(retain copy create--release)
objc_property_t *propertyList = class_copyPropertyList(self, &listOutCount);
NSMutableArray *temArray = [NSMutableArray array];
for (unsigned int i = 0; i < listOutCount; i++) {
//获取属性
objc_property_t property = propertyList[i];
//获取属性名称
const char *name = property_getName(property);
//名称转化为 OC 字符串
NSString *propertyName = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];
[temArray addObject:propertyName];
}
//设置关联对象,给 NSObject 分类动态添加属性,也就是 model 类的属性
objc_setAssociatedObject(self, kPropertyListKey, [temArray copy], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
//propertyList是通过 copy 方式获得的,需要释放。
free(propertyList);
return [temArray copy];
}
+ (instancetype)modelWithDict:(NSDictionary *)dict{
id objc = [[self alloc]init];
NSArray *properties = [self getPropertyList];
[dict enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
if ([properties containsObject:key]) {
[objc setValue:obj forKey:key];
}
}];
return objc;
}
@end
测试
- (void)viewDidLoad {
[super viewDidLoad];
NSDictionary *dic = @{
@"name":@"lilei",
@"age":@18,
};
TestModel *model = [TestModel modelWithDict:dic];
NSLog(@"== model:%@---%ld---%ld==",model.name,model.age,model.height);
}
class_copyPropertyList
的说明
/**
* 描述由类声明的属性。
*
* @param cls 你想要检查(获取)属性列表的类。
* @param outCount 属性列表的数组的个数指针
* If \e outCount is \c NULL, the length is not returned.
*
* @return
*描述由类声明的属性的类型为objc_property_t的指针数组。
*不包括由超类声明的任何属性。
*该数组包含outCount指针,后跟NULL结束符。
*你必须用free()释放数组。
*如果cls声明没有属性,或cls为零,则返回NULL,outCount为0。
*/
OBJC_EXPORT objc_property_t _Nonnull * _Nullable
class_copyPropertyList(Class _Nullable cls, unsigned int * _Nullable outCount)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
与此类似的还有
/* 成员变量:
* class_copyIvarList(__unsafe_unretained Class cls, unsigned int *outCount)
* 方法:
* class_copyMethodList(__unsafe_unretained Class cls, unsigned int *outCount)
* 属性:
* class_copyPropertyList(__unsafe_unretained Class cls, unsigned int *outCount)
* 协议:
* class_copyProtocolList(__unsafe_unretained Class cls, unsigned int *outCount)
*/
学习一个类的最好方式就是去查看它的API 文档,共勉。
网友评论