使用运行时实现字典转模型和关联对象objc_get/setAssociatedObject()
创建一个类Person,重写它的description方法,打印出它的属性值。
XZPerson.m
@implementation
XZPerson
- (
NSString
*)description {
NSArray
*keys =
@[
@"name"
,
@"age"
,
@"weight"
,
@"sex"
]
;
return
[
self
dictionaryWithValuesForKeys
:keys].
description
;
}
@end
NSObject+XZRuntime.h
#import
<Foundation/Foundation.h>
@interface
NSObject (XZRuntime)
//
获取类的属性列表
// @return
类的属性列表数组
+ (
NSArray
*)xz_objcProperties;
//
给定一个字典,创建
self
类对应的对象
// @param dict
字典
@return
对象
+ (
instancetype
)xz_objWithDic:(
NSDictionary
*)dict;
@end
NSObject+XZRuntime.m
#import
"NSObject+XZRuntime.h"
#import
<objc/runtime.h>
@implementation
NSObject (XZRuntime)
//
所有字典转模型框架的核心算法
//
运行时字典转模型的基本方法的实现
+ (
instancetype
)xz_objWithDic:(
NSDictionary
*)dict {
//
实例化对象
id
object = [[
self
alloc
]
init
];
//
使用字典,设置对象信息
// 1>
获得
self
的属性列表
NSArray
*proList = [
self
xz_objcProperties
];
// 2>
遍历字典
[dict
enumerateKeysAndObjectsUsingBlock
:^(
id
_Nonnull
key,
id
_Nonnull
obj,
BOOL
*
_Nonnull
stop) {
NSLog
(
@"key %@ ---- value %@"
,key,obj);
// 3>
判断
key
是否存在
proList
中
if
([proList
containsObject
:key]) {
//
说明属性存在,可以使用
‘KVC’
设置数值
[object
setValue
:obj
forKey
:key];
}
}];
return
object;
}
const
char
*kPropertiesListKey =
"CZPropertiesListKey"
;
+ (
NSArray
*)xz_objcProperties {
//
因为属性列表在运行的过程中不会改变,所以使用运行时关联对象,提高效率
//
①、从
‘
关联对象
’
中获取对象属性,如果有,直接返回!
/**
获取关联对象
--
动态添加的属性
参数
1
:对象
:self
参数
2
:动态属性的
key
返回值:动态添加的
‘
属性值
’ id
*/
NSArray
*ptyList =
objc_getAssociatedObject
(
self
,
kPropertiesListKey
);
if
(ptyList !=
nil
) {
return
ptyList;
}
//
使用运行时获取对象的属性数组
// class_copyIvarList Ivar
成员变量
// class_copyPropertyList Property
属性
// class_copyMethodList Method
方法
// class_copyProtocolList Protocol
协议
//
参数一:要获取的类
参数二:类属性的个数指针
//
返回值:所有属性的
'
数组
'
,
C
语言中,数组的名字,就是指向第一个元素的地址
unsigned
int
outCount =
0
;
//
调用运行时方法,取得类的属性列表
objc_property_t
*proList =
class_copyPropertyList
([
self
class
], &outCount);
NSLog
(
@"
属性列表的数量
%d"
,outCount);
NSMutableArray
*array = [
NSMutableArray
array
];
//
遍历所有的属性
for
(
unsigned
int
i =
0
; i < outCount; i++) {
//1.
从数组中取得属性
C
语言的结构体指针,通常不需要
'*'
objc_property_t
pty = proList[i];
// 2.
从
pty
中获得属性的名称
const
char
*cName =
property_getName
(pty);
//
将
C
语言字符串转化成
OC
字符串
NSString
*name = [
NSString
stringWithCString
:cName
encoding
:
NSUTF8StringEncoding
];
// 3.
属性名称添加到数组
[array
addObject
:name];
}
// retain/create/copy
需要
release
,点击
option + click
查看
//
释放数组
free
(proList);
//
②、到此为止,对象的属性数组已经获取完毕,利用关联对象,动态添加属性
/**
参数
1.
对象
self [OC
中
class
也是一个特殊的对象
]
2.
动态添加的属性的
key
,获取值的时候也使用
3.
动态添加的属性值
4.
对象的引用关系
*/
objc_setAssociatedObject
(
self
,
kPropertiesListKey
, array.
copy
,
OBJC_ASSOCIATION_RETAIN_NONATOMIC
);
return
array.
copy
;
}
@end
XZRunTimeController.m
//
字典转模型
XZPerson
*person = [
XZPerson
xz_objWithDic
:
@{
@"name"
:
@"zhangsan"
,
@"age"
:
@18
,
@"sex"
:
@"female"
,
@"height"
:
@1.8
,
@"weight"
:
@100
,
}
];