福利->KVC+Runtime获取类/对象的属性/成员变量/方法/协议并实现字典转模型
我们知道,KVC+Runtime可以做非常多的事情。有了这个,我们可以实现很多的效果。
这里来个福利,利用KVC+Runtime获取类/对象的所有成员变量、属性、方法及协议;
并利用它来实现字典转模型。
废话不多说,直接上代码:
1、工具类(其实就是NSObject的一个分类)头文件
#import <Foundation/Foundation.h> @interface NSObject (YSRuntime) /** 返回当前类的属性数组 @return 属性数组(如:"name","age","address") */ + (NSArray *)ys_propertiesList; /** 返回当前类的成员变量数组 @return 成员变量数组 */ + (NSArray *)ys_ivarsList; /** 返回当前类的对象方法数组 @return 方法数组 */ + (NSArray *)ys_methodList; /** 返回当前类的协议数组 @return 协议数组 */ + (NSArray *)ys_protocolList; /** 使用字典创建当前类的对象 @param dictionary 字典 @return 当前类的对象 */ + (instancetype)ys_objectWithDictionary:(NSDictionary *)dictionary; /** 使用字典数组创建当前类的对象数组 @param dictArray 字典数组 @return 当前类的对象数组 */ + (NSArray *)ys_objectsWithDictionaryArray:(NSArray<NSDictionary *> *)dictArray; @end
2、下面我们来实现里面的方法,以后就用它来获取类/对象的属性、成员变量、方法和协议
说明一下:最主要的方法是在objc/runtime.h,这里只是列举了一些,起到抛砖引玉的作用
1 #import "NSObject+YSRuntime.h"
2 #import <objc/runtime.h>
3
4 @implementation NSObject (YSRuntime)
5
6 #pragma mark - 属性数组
7 const char *propertiesKey = "ys.propertiesList";
8 + (NSArray *)ys_propertiesList {
9
10 // 获取关联对象
11 NSArray *result = objc_getAssociatedObject(self, propertiesKey);
12
13 if (result != nil) {
14 return result;
15 }
16
17 unsigned int count = 0;
18 objc_property_t *list = class_copyPropertyList([self class], &count);
19
20 NSMutableArray *arrayM = [NSMutableArray array];
21
22 for (unsigned int i = 0; i < count; i++) {
23
24 objc_property_t pty = list[i];
25
26 const char *cName = property_getName(pty);
27 NSString *name = [NSString stringWithUTF8String:cName];
28
29 [arrayM addObject:name];
30 }
31
32 free(list);
33
34 // 设置关联对象
35 objc_setAssociatedObject(self, propertiesKey, arrayM, OBJC_ASSOCIATION_COPY_NONATOMIC);
36
37 return objc_getAssociatedObject(self, propertiesKey);
38 }
39
40 #pragma mark - 私有方法,专门针对字典转模型中的自定义属性,{@"name":@"Dog"},name是属性名,Dog是自定义的模型类,属性名-属性类型
41 const char *propertiesTypeKey = "ys.propertiesTypeKey";
42 + (NSArray<NSDictionary *> *)ys_propertiesAndTypeList {
43
44 // 获取关联对象
45 NSArray *result = objc_getAssociatedObject(self, propertiesTypeKey);
46
47 if (result != nil) {
48 return result;
49 }
50
51 unsigned int count = 0;
52 objc_property_t *list = class_copyPropertyList([self class], &count);
53
54 NSMutableArray<NSDictionary *> *arrayM = [NSMutableArray<NSDictionary *> array];
55
56 for (unsigned int i = 0; i < count; i++) {
57
58 objc_property_t pty = list[i];
59
60 const char *cType = property_getAttributes(pty);
61 NSString *typeStr = [NSString stringWithUTF8String:cType];
62
63 if([typeStr containsString:@"\",&"]){
64 NSRange typeRange = [typeStr rangeOfString:@"\",&"];
65 NSString *type = [typeStr substringWithRange:NSMakeRange(3, typeRange.location - 3)];
66
67 const char *cName = property_getName(pty);
68 NSString *name = [NSString stringWithUTF8String:cName];
69
70 NSDictionary *dict = @{name:type};
71
72 [arrayM addObject:dict];
73 }
74 }
75
76 free(list);
77
78 // 设置关联对象
79 objc_setAssociatedObject(self, propertiesTypeKey, arrayM, OBJC_ASSOCIATION_COPY_NONATOMIC);
80
81 return objc_getAssociatedObject(self, propertiesTypeKey);
82 }
83
84
85 #pragma mark - 成员变量数组
86 const char *ivarsKey = "ys.ivarsList";
87 + (NSArray *)ys_ivarsList {
88
89 // 获取关联对象
90 NSArray *result = objc_getAssociatedObject(self, ivarsKey);
91
92 if (result != nil) {
93 return result;
94 }
95
96 unsigned int count = 0;
97 Ivar *list = class_copyIvarList([self class], &count);
98
99 NSMutableArray *arrayM = [NSMutableArray array];
100
101 for (unsigned int i = 0; i < count; i++) {
102
103 Ivar ivar = list[i];
104
105 const char *cName = ivar_getName(ivar);
106 NSString *name = [NSString stringWithUTF8String:cName];
107
108 [arrayM addObject:name];
109 }
110
111 free(list);
112
113 // 设置关联对象
114 objc_setAssociatedObject(self, ivarsKey, arrayM, OBJC_ASSOCIATION_COPY_NONATOMIC);
115
116 return objc_getAssociatedObject(self, ivarsKey);
117 }
118
119 #pragma mark - 方法数组
120 + (NSArray *)ys_methodList {
121
122 unsigned int count = 0;
123 Method *list = class_copyMethodList([self class], &count);
124
125 NSMutableArray *arrayM = [NSMutableArray array];
126
127 for (unsigned int i = 0; i < count; i++) {
128
129 Method method = list[i];
130
131 SEL selector = method_getName(method);
132 NSString *name = NSStringFromSelector(selector);
133
134 [arrayM addObject:name];
135 }
136
137 free(list);
138
139 return arrayM.copy;
140 }
141
142 #pragma mark - 协议数组
143 + (NSArray *)ys_protocolList {
144
145 unsigned int count = 0;
146 __unsafe_unretained Protocol **list = class_copyProtocolList([self class], &count);
147
148 NSMutableArray *arrayM = [NSMutableArray array];
149
150 for (unsigned int i = 0; i < count; i++) {
151
152 Protocol *protocol = list[i];
153
154 const char *cName = protocol_getName(protocol);
155 NSString *name = [NSString stringWithUTF8String:cName];
156
157 [arrayM addObject:name];
158 }
159
160 free(list);
161
162 return arrayM.copy;
163 }
164
165 #pragma mark - 字典 -> 当前类的对象
166 + (instancetype)ys_objectWithDictionary:(NSDictionary *)dictionary{
167
168 // 当前类的属性数组
169 NSArray *list = [self ys_propertiesList];
170
171 NSArray<NSDictionary *> *propertyTypeList = [self ys_propertiesAndTypeList];
172
173 id obj = [self new];
174
175 for (NSString *key in dictionary) {
176
177 if([list containsObject:key]){
178
179 if ([dictionary[key] isKindOfClass:[NSDictionary class]]){ // 属性值为字典
180
181 for(NSDictionary *dict in propertyTypeList){
182
183 if([key isEqualToString: [NSString stringWithFormat:@"%@",dict.allKeys.firstObject]]){
184
185 NSString *classTypeStr = dict[key];
186 Class class = NSClassFromString(classTypeStr);
187
188 id objChild = [class ys_objectWithDictionary:dictionary[key]];
189
190 [obj setValue:objChild forKey:key];
191 }
192 }
193
194 }
195 else if([dictionary[key] isKindOfClass:[NSArray<NSDictionary *> class]]){ // 属性值为字典数组
196
197 }
198 else{
199 [obj setValue:dictionary[key] forKey:key];
200 }
201 }
202 }
203
204 return obj;
205 }
206
207 #pragma mark - 字典数组 -> 当前类的对象数组
208 + (NSArray *)ys_objectsWithDictionaryArray:(NSArray<NSDictionary *> *)dictArray {
209
210 if (dictArray.count == 0) {
211 return nil;
212 }
213
214 // 当前类的属性数组
215 NSArray *list = [self ys_propertiesList];
216
217 NSArray<NSDictionary *> *propertyTypeList = [self ys_propertiesAndTypeList];
218
219 NSMutableArray *arrayM = [NSMutableArray array];
220 for (NSDictionary *dictionary in dictArray) {
221
222 id obj = [self new];
223
224 for (NSString *key in dictionary) {
225
226 if([list containsObject:key]){
227
228 if ([dictionary[key] isKindOfClass:[NSDictionary class]]){ // 属性值为字典
229
230 for(NSDictionary *dict in propertyTypeList){
231
232 if([key isEqualToString: [NSString stringWithFormat:@"%@",dict.allKeys.firstObject]]){
233
234 NSString *classTypeStr = dict[key];
235 Class class = NSClassFromString(classTypeStr);
236
237 id objChild = [class ys_objectWithDictionary:dictionary[key]];
238
239 [obj setValue:objChild forKey:key];
240 }
241 }
242
243 }
244 else if([dictionary[key] isKindOfClass:[NSArray<NSDictionary *> class]]){ // 属性值为字典数组
245
246 }
247 else{
248 [obj setValue:dictionary[key] forKey:key];
249 }
250 }
251 }
252
253 [arrayM addObject:obj];
254 }
255
256 return arrayM.copy;
257 }
258
259 @end
3、和YYModel一样,如果对象的一个属性为另一个自定义对象,那么同样可以起到连转的作用;
4、但比较遗憾的是,也是和YYModel一样,如果有一个属性是数组,又添加了泛型约束,没有取到这个数组的泛型约束。
我记得,YYModel就有这个问题,因为取不到泛型约束,所以当有属性为数组的时候,需要手动指定数组里面的元素类型。
希望各位大神看到后不吝赐教。
5、最后贴出一个小且非常有趣的小东东,里面的key就是我用上面的 “ys_ivarsList” 获取到所有成员变量,然后一级一级找的^_^
// 设置随机颜色给Application的statusBar,从此妈妈再也不用担心statusBar的背景色
id bgStyle = [[UIApplication sharedApplication] valueForKeyPath:@"statusBar.backgroundView.style"];
[bgStyle setValue:[UIColor redColor] forKey:@"backgroundColor"];
// frame = (5 649; 55 13)
// 修改高德地图和logo,删除和替换自己随意定
UIImageView *imgV = [mapView valueForKey:@"logoImageView"]; // 这就就是高德地图的logo
imgV.image = nil; // 我们把imageView的图片置为nil
[mapView setValue:imgV forKey:@"logoImageView"]; // 哈哈,这个高德地图的logo就不见了,妈妈从此再也不需要担心logo了
相关推荐
javamagicsun 2019-12-07
一亩半分地 2012-06-03
阿北的知识分享 2019-08-06
taotaoSi 2014-08-17
LittleMatches 2013-08-06
玻璃心 2013-08-03
ellende 2019-06-21
广西信息安全学会 2008-05-28
free0day 2018-08-06
CODEWORLD 2014-07-15
fkuevip 2016-04-05
世事一场大梦 2017-04-29
一亩半分地 2013-11-26
yaasshole 2014-04-25
小金屋 2019-04-16
xcxvbf 2013-01-11
linuxunix 2012-12-13
Pythonandme 2019-01-22
pythoncream 2019-01-11