你好,歡迎來到IOS教程網

 Ios教程網 >> IOS使用技巧 >> IOS技巧綜合 >> 福利

福利

編輯:IOS技巧綜合
[摘要]本文是對福利->KVC+Runtime獲取類/對象的屬性/成員變量/方法/協議並實現字典轉模型的講解,對學習IOS蘋果軟件開發有所幫助,與大家分享。

我們知道,KVC+Runtime可以做非常多的事情。有了這個,我們可以實現很多的效果。

這裡來個福利,利用KVC+Runtime獲取類/對象的所有成員變量、屬性、方法及協議;

並利用它來實現字典轉模型。

廢話不多說,直接上代碼:

1、工具類(其實就是NSObject的一個分類)頭文件

 1 #import <Foundation/Foundation.h>
 2 
 3 @interface NSObject (YSRuntime)
 4 
 5 /**
 6  返回當前類的屬性數組
 7  
 8  @return 屬性數組(如:"name","age","address")
 9  */
10 + (NSArray *)ys_propertiesList;
11 
12 /**
13  返回當前類的成員變量數組
14  
15  @return 成員變量數組
16  */
17 + (NSArray *)ys_ivarsList;
18 
19 /**
20  返回當前類的對象方法數組
21  
22  @return 方法數組
23  */
24 + (NSArray *)ys_methodList;
25 
26 /**
27  返回當前類的協議數組
28  
29  @return 協議數組
30  */
31 + (NSArray *)ys_protocolList;
32 
33 /**
34  使用字典創建當前類的對象
35  
36  @param dictionary 字典
37  
38  @return 當前類的對象
39  */
40 + (instancetype)ys_objectWithDictionary:(NSDictionary *)dictionary;
41 
42 /**
43  使用字典數組創建當前類的對象數組
44  
45  @param dictArray 字典數組
46  
47  @return 當前類的對象數組
48  */
49 + (NSArray *)ys_objectsWithDictionaryArray:(NSArray<NSDictionary *> *)dictArray;
50 
51 @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” 獲取到所有成員變量,然後一級一級找的^_^

1     // 設置隨機顏色給Application的statusBar,從此媽媽再也不用擔心statusBar的背景色
2     id bgStyle = [[UIApplication sharedApplication] valueForKeyPath:@"statusBar.backgroundView.style"];
3     [bgStyle setValue:[UIColor redColor] forKey:@"backgroundColor"];
1     // frame = (5 649; 55 13)
2     // 修改高德地圖和logo,刪除和替換自己隨意定
3     UIImageView *imgV = [mapView valueForKey:@"logoImageView"]; // 這就就是高德地圖的logo
4     imgV.image = nil; //  我們把imageView的圖片置為nil
5     [mapView setValue:imgV forKey:@"logoImageView"]; // 哈哈,這個高德地圖的logo就不見了,媽媽從此再也不需要擔心logo了
  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved