福利->KVC+Runtime擷取類/對象的屬性/成員變數/方法/協議並實現字典轉模型,kvcruntime

來源:互聯網
上載者:User

福利->KVC+Runtime擷取類/對象的屬性/成員變數/方法/協議並實現字典轉模型,kvcruntime

我們知道,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"]; // 這就就是高德地圖的logo4     imgV.image = nil; //  我們把imageView的圖片置為nil5     [mapView setValue:imgV forKey:@"logoImageView"]; // 哈哈,這個高德地圖的logo就不見了,媽媽從此再也不需要擔心logo了

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.