1. 寫在前面
YYModelMeta,嗯,又是一個meta,很明顯又是一層封裝,這個meta是對YYClassInfo進行了一些描述資訊的封裝,並且把所有Property都封裝成昨天說到的PropertyMetas,在這個程式碼中也驗證了昨天對next指標的使用。這節沒什麼多補充的知識點,我們就直接上程式碼
2.YYModelMeta
2.1 .h 檔案
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
/// YYModelMeta 對ClassInfo增加描述 @interface _YYModelMeta : NSObject { @package YYClassInfo *_classInfo; // json key 和 property Meta 的對映關係字典 NSDictionary *_mapper; // 所有屬性的propertyMeta NSArray *_allPropertyMetas; // 對映jsonkeyPath 的PropertyMetas NSArray *_keyPathPropertyMetas; // 對映多個jsonKey的propertyMeta NSArray *_multiKeysPropertyMetas; /// 需要對映的屬性的總個數 NSUInteger _keyMappedCount; /// Model對應的Foundation class型別 YYEncodingNSType _nsType; // 事否實現了自定義的對映關係表 這裡之前已經解釋過 就不再贅述 BOOL _hasCustomWillTransformFromDictionary; BOOL _hasCustomTransformFromDictionary; BOOL _hasCustomTransformToDictionary; BOOL _hasCustomClassFromDictionary; } @end |
2.2.m檔案
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
@implementation _YYModelMeta - (instancetype)initWithClass:(Class)cls { // 建立classInfo物件 YYClassInfo *classInfo = [YYClassInfo classInfoWithClass:cls]; // 1. 判斷是否合法 if (!classInfo) return nil; self = [super init]; // 2. 獲得黑名單 NSSet *blacklist = nil; if ([cls respondsToSelector:@selector(modelPropertyBlacklist)]) { NSArray *properties = [(id<YYModel>)cls modelPropertyBlacklist]; if (properties) { blacklist = [NSSet setWithArray:properties]; } } // 3. 獲得白名單 NSSet *whitelist = nil; if ([cls respondsToSelector:@selector(modelPropertyWhitelist)]) { NSArray *properties = [(id<YYModel>)cls modelPropertyWhitelist]; if (properties) { whitelist = [NSSet setWithArray:properties]; } } // 4. 獲取容器屬性中的對映關係字典 NSDictionary *genericMapper = nil; if ([cls respondsToSelector:@selector(modelContainerPropertyGenericClass)]) {// 判斷類中是否實現了對應的modelContainerPropertyGenericClass方法 /* 例如 @{@"shadows" : [YYShadow class], @"borders" : YYBorder.class, @"attachments" : @"YYAttachment" }; */ genericMapper = [(id<YYModel>)cls modelContainerPropertyGenericClass]; if (genericMapper) { // 將欄位名和對應的class存放在字典裡 NSMutableDictionary *tmp = [NSMutableDictionary new]; [genericMapper enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { if (![key isKindOfClass:[NSString class]]) return; Class meta = object_getClass(obj); if (!meta) return; if (class_isMetaClass(meta)) { tmp[key] = obj; } else if ([obj isKindOfClass:[NSString class]]) { Class cls = NSClassFromString(obj); if (cls) { tmp[key] = cls; } } }]; genericMapper = tmp; } } // 5. 建立Class中 所有屬性的PropertyMeta物件 加入到字典中 // 用來儲存class 和其父類的所有屬性 除了NSOject外 NSMutableDictionary *allPropertyMetas = [NSMutableDictionary new]; YYClassInfo *curClassInfo = classInfo; while (curClassInfo && curClassInfo.superCls != nil) { // recursive parse super class, but ignore root class (NSObject/NSProxy) // 遍歷當前ClassInfo 中的所有PropertyInfo, 將它們封裝成PropertyMeta for (YYClassPropertyInfo *propertyInfo in curClassInfo.propertyInfos.allValues) { // 檢查是否合法和黑名單白名單 if (!propertyInfo.name) continue; if (blacklist && [blacklist containsObject:propertyInfo.name]) continue; if (whitelist && ![whitelist containsObject:propertyInfo.name]) continue; // 通過propetyInfo來建立一個meta物件 _YYModelPropertyMeta *meta = [_YYModelPropertyMeta metaWithClassInfo:classInfo propertyInfo:propertyInfo generic:genericMapper[propertyInfo.name]]; // meta nanme必須非空 if (!meta || !meta->_name) continue; // 必須實現get方法和set方法 if (!meta->_getter || !meta->_setter) continue; // 字典中沒有這個欄位 避免重複操作 if (allPropertyMetas[meta->_name]) continue; allPropertyMetas[meta->_name] = meta; } // 遍歷父類的property curClassInfo = curClassInfo.superClassInfo; } // 判斷是否為空,不為空賦值給model宣告中的_allPropertyMetas if (allPropertyMetas.count) _allPropertyMetas = allPropertyMetas.allValues.copy; // 建立對映關係 jsonkey :propertyMeta NSMutableDictionary *mapper = [NSMutableDictionary new]; NSMutableArray *keyPathPropertyMetas = [NSMutableArray new]; NSMutableArray *multiKeysPropertyMetas = [NSMutableArray new]; // 是否實現自定義的對映表 if ([cls respondsToSelector:@selector(modelCustomPropertyMapper)]) { // 獲得自定義的對映表 NSDictionary *customMapper = [(id <YYModel>)cls modelCustomPropertyMapper]; // 遍歷自定義的字典 [customMapper enumerateKeysAndObjectsUsingBlock:^(NSString *propertyName, NSString *mappedToKey, BOOL *stop) { // 建立propetyMeta _YYModelPropertyMeta *propertyMeta = allPropertyMetas[propertyName]; if (!propertyMeta) return; // 由於使用者自定義對映,把原來對映的規則刪除 [allPropertyMetas removeObjectForKey:propertyName]; if ([mappedToKey isKindOfClass:[NSString class]]) { // 判斷key欄位是否為非空NSString if (mappedToKey.length == 0) return; // 直接儲存property對映的key propertyMeta->_mappedToKey = mappedToKey; // 如果是keyPath的情況, 用陣列來處理 NSArray *keyPath = [mappedToKey componentsSeparatedByString:@"."]; // {@"name":@"user.name"} => name : @[@"user",@"name"] if (keyPath.count > 1) { // 儲存keyPath對映關係 propertyMeta->_mappedToKeyPath = keyPath; // 新增到keyPathPropertyMetas陣列中 [keyPathPropertyMetas addObject:propertyMeta]; } // 多個屬性的時候,用next指標來指向前一個jsonKey對映的meta propertyMeta->_next = mapper[mappedToKey] ?: nil; // 儲存jsonKey對映到最新的meta物件 mapper[mappedToKey] = propertyMeta; } else if ([mappedToKey isKindOfClass:[NSArray class]]) { // 如果是陣列 屬於一個屬性對映多個jsonKey NSMutableArray *mappedToKeyArray = [NSMutableArray new]; for (NSString *oneKey in ((NSArray *)mappedToKey)) { if (![oneKey isKindOfClass:[NSString class]]) continue; if (oneKey.length == 0) continue; NSArray *keyPath = [oneKey componentsSeparatedByString:@"."]; if (keyPath.count > 1) { [mappedToKeyArray addObject:keyPath]; } else { [mappedToKeyArray addObject:oneKey]; } if (!propertyMeta->_mappedToKey) { propertyMeta->_mappedToKey = oneKey; propertyMeta->_mappedToKeyPath = keyPath.count > 1 ? keyPath : nil; } } if (!propertyMeta->_mappedToKey) return; propertyMeta->_mappedToKeyArray = mappedToKeyArray; [multiKeysPropertyMetas addObject:propertyMeta]; propertyMeta->_next = mapper[mappedToKey] ?: nil; mapper[mappedToKey] = propertyMeta; } }]; } // 處理沒有自定義對映規則的屬性 // 在上面的處理中 從allPropertyMetas中刪除了有自定義對映規則的meta // 剩下來的是沒有自定義規則的屬性,在這裡就讓這些屬性的mappedKey等於屬性名 [allPropertyMetas enumerateKeysAndObjectsUsingBlock:^(NSString *name, _YYModelPropertyMeta *propertyMeta, BOOL *stop) { // 直接讓mappedKey等於屬性名 propertyMeta->_mappedToKey = name; propertyMeta->_next = mapper[name] ?: nil; mapper[name] = propertyMeta; }]; // 對對映的資料做修正處理 if (mapper.count) _mapper = mapper; if (keyPathPropertyMetas) _keyPathPropertyMetas = keyPathPropertyMetas; if (multiKeysPropertyMetas) _multiKeysPropertyMetas = multiKeysPropertyMetas; _classInfo = classInfo; _keyMappedCount = _allPropertyMetas.count; _nsType = YYClassGetNSType(cls); _hasCustomWillTransformFromDictionary = ([cls instancesRespondToSelector:@selector(modelCustomWillTransformFromDictionary:)]); _hasCustomTransformFromDictionary = ([cls instancesRespondToSelector:@selector(modelCustomTransformFromDictionary:)]); _hasCustomTransformToDictionary = ([cls instancesRespondToSelector:@selector(modelCustomTransformToDictionary:)]); _hasCustomClassFromDictionary = ([cls respondsToSelector:@selector(modelCustomClassForDictionary:)]); return self; } |
3. 寫在後面
來實習了這麼久,終於要給我安排導師了,終於不用一個人自己做了,身邊兩個iOS都不交流每天都是自己折騰這氛圍太悶了。有個人指點一下方向感覺比自己一個人摸坑要好很多,定製一個十五天的計劃,每天學一點,每天讀一點,十五天後再回過頭來看,看看自己到底能進步多少。