NSObject+DKModel.m 82 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820
  1. //
  2. // NSObject+DKModel.m
  3. // DKModel
  4. //
  5. // Created by dongke on 17/5/9.
  6. // Copyright (c) 2017 dongke.
  7. //
  8. // This source code is licensed under the MIT-style license found in the
  9. // LICENSE file in the root directory of this source tree.
  10. //
  11. #import "NSObject+DKModel.h"
  12. #import "DKClassInfo.h"
  13. #import <objc/message.h>
  14. #define force_inline __inline__ __attribute__((always_inline))
  15. /// Foundation Class Type
  16. typedef NS_ENUM (NSUInteger, DKEncodingNSType) {
  17. DKEncodingTypeNSUnknown = 0,
  18. DKEncodingTypeNSString,
  19. DKEncodingTypeNSMutableString,
  20. DKEncodingTypeNSValue,
  21. DKEncodingTypeNSNumber,
  22. DKEncodingTypeNSDecimalNumber,
  23. DKEncodingTypeNSData,
  24. DKEncodingTypeNSMutableData,
  25. DKEncodingTypeNSDate,
  26. DKEncodingTypeNSURL,
  27. DKEncodingTypeNSArray,
  28. DKEncodingTypeNSMutableArray,
  29. DKEncodingTypeNSDictionary,
  30. DKEncodingTypeNSMutableDictionary,
  31. DKEncodingTypeNSSet,
  32. DKEncodingTypeNSMutableSet,
  33. };
  34. /// Get the Foundation class type from property info.
  35. static force_inline DKEncodingNSType DKClassGetNSType(Class cls) {
  36. if (!cls) return DKEncodingTypeNSUnknown;
  37. if ([cls isSubclassOfClass:[NSMutableString class]]) return DKEncodingTypeNSMutableString;
  38. if ([cls isSubclassOfClass:[NSString class]]) return DKEncodingTypeNSString;
  39. if ([cls isSubclassOfClass:[NSDecimalNumber class]]) return DKEncodingTypeNSDecimalNumber;
  40. if ([cls isSubclassOfClass:[NSNumber class]]) return DKEncodingTypeNSNumber;
  41. if ([cls isSubclassOfClass:[NSValue class]]) return DKEncodingTypeNSValue;
  42. if ([cls isSubclassOfClass:[NSMutableData class]]) return DKEncodingTypeNSMutableData;
  43. if ([cls isSubclassOfClass:[NSData class]]) return DKEncodingTypeNSData;
  44. if ([cls isSubclassOfClass:[NSDate class]]) return DKEncodingTypeNSDate;
  45. if ([cls isSubclassOfClass:[NSURL class]]) return DKEncodingTypeNSURL;
  46. if ([cls isSubclassOfClass:[NSMutableArray class]]) return DKEncodingTypeNSMutableArray;
  47. if ([cls isSubclassOfClass:[NSArray class]]) return DKEncodingTypeNSArray;
  48. if ([cls isSubclassOfClass:[NSMutableDictionary class]]) return DKEncodingTypeNSMutableDictionary;
  49. if ([cls isSubclassOfClass:[NSDictionary class]]) return DKEncodingTypeNSDictionary;
  50. if ([cls isSubclassOfClass:[NSMutableSet class]]) return DKEncodingTypeNSMutableSet;
  51. if ([cls isSubclassOfClass:[NSSet class]]) return DKEncodingTypeNSSet;
  52. return DKEncodingTypeNSUnknown;
  53. }
  54. /// Whether the type is c number.
  55. static force_inline BOOL DKEncodingTypeIsCNumber(DKEncodingType type) {
  56. switch (type & DKEncodingTypeMask) {
  57. case DKEncodingTypeBool:
  58. case DKEncodingTypeInt8:
  59. case DKEncodingTypeUInt8:
  60. case DKEncodingTypeInt16:
  61. case DKEncodingTypeUInt16:
  62. case DKEncodingTypeInt32:
  63. case DKEncodingTypeUInt32:
  64. case DKEncodingTypeInt64:
  65. case DKEncodingTypeUInt64:
  66. case DKEncodingTypeFloat:
  67. case DKEncodingTypeDouble:
  68. case DKEncodingTypeLongDouble: return YES;
  69. default: return NO;
  70. }
  71. }
  72. /// Parse a number value from 'id'.
  73. static force_inline NSNumber *DKNSNumberCreateFromID(__unsafe_unretained id value) {
  74. static NSCharacterSet *dot;
  75. static NSDictionary *dic;
  76. static dispatch_once_t onceToken;
  77. dispatch_once(&onceToken, ^{
  78. dot = [NSCharacterSet characterSetWithRange:NSMakeRange('.', 1)];
  79. dic = @{@"TRUE" : @(YES),
  80. @"True" : @(YES),
  81. @"true" : @(YES),
  82. @"FALSE" : @(NO),
  83. @"False" : @(NO),
  84. @"false" : @(NO),
  85. @"YES" : @(YES),
  86. @"Yes" : @(YES),
  87. @"yes" : @(YES),
  88. @"NO" : @(NO),
  89. @"No" : @(NO),
  90. @"no" : @(NO),
  91. @"NIL" : (id)kCFNull,
  92. @"Nil" : (id)kCFNull,
  93. @"nil" : (id)kCFNull,
  94. @"NULL" : (id)kCFNull,
  95. @"Null" : (id)kCFNull,
  96. @"null" : (id)kCFNull,
  97. @"(NULL)" : (id)kCFNull,
  98. @"(Null)" : (id)kCFNull,
  99. @"(null)" : (id)kCFNull,
  100. @"<NULL>" : (id)kCFNull,
  101. @"<Null>" : (id)kCFNull,
  102. @"<null>" : (id)kCFNull};
  103. });
  104. if (!value || value == (id)kCFNull) return nil;
  105. if ([value isKindOfClass:[NSNumber class]]) return value;
  106. if ([value isKindOfClass:[NSString class]]) {
  107. NSNumber *num = dic[value];
  108. if (num) {
  109. if (num == (id)kCFNull) return nil;
  110. return num;
  111. }
  112. if ([(NSString *)value rangeOfCharacterFromSet:dot].location != NSNotFound) {
  113. const char *cstring = ((NSString *)value).UTF8String;
  114. if (!cstring) return nil;
  115. double num = atof(cstring);
  116. if (isnan(num) || isinf(num)) return nil;
  117. return @(num);
  118. } else {
  119. const char *cstring = ((NSString *)value).UTF8String;
  120. if (!cstring) return nil;
  121. return @(atoll(cstring));
  122. }
  123. }
  124. return nil;
  125. }
  126. /// Parse string to date.
  127. static force_inline NSDate *DKNSDateFromString(__unsafe_unretained NSString *string) {
  128. typedef NSDate* (^DKNSDateParseBlock)(NSString *string);
  129. #define kParserNum 34
  130. static DKNSDateParseBlock blocks[kParserNum + 1] = {0};
  131. static dispatch_once_t onceToken;
  132. dispatch_once(&onceToken, ^{
  133. {
  134. /*
  135. 2014-01-20 // Google
  136. */
  137. NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
  138. formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
  139. formatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
  140. formatter.dateFormat = @"yyyy-MM-dd";
  141. blocks[10] = ^(NSString *string) { return [formatter dateFromString:string]; };
  142. }
  143. {
  144. /*
  145. 2014-01-20 12:24:48
  146. 2014-01-20T12:24:48 // Google
  147. 2014-01-20 12:24:48.000
  148. 2014-01-20T12:24:48.000
  149. */
  150. NSDateFormatter *formatter1 = [[NSDateFormatter alloc] init];
  151. formatter1.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
  152. formatter1.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
  153. formatter1.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss";
  154. NSDateFormatter *formatter2 = [[NSDateFormatter alloc] init];
  155. formatter2.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
  156. formatter2.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
  157. formatter2.dateFormat = @"yyyy-MM-dd HH:mm:ss";
  158. NSDateFormatter *formatter3 = [[NSDateFormatter alloc] init];
  159. formatter3.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
  160. formatter3.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
  161. formatter3.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss.SSS";
  162. NSDateFormatter *formatter4 = [[NSDateFormatter alloc] init];
  163. formatter4.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
  164. formatter4.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
  165. formatter4.dateFormat = @"yyyy-MM-dd HH:mm:ss.SSS";
  166. blocks[19] = ^(NSString *string) {
  167. if ([string characterAtIndex:10] == 'T') {
  168. return [formatter1 dateFromString:string];
  169. } else {
  170. return [formatter2 dateFromString:string];
  171. }
  172. };
  173. blocks[23] = ^(NSString *string) {
  174. if ([string characterAtIndex:10] == 'T') {
  175. return [formatter3 dateFromString:string];
  176. } else {
  177. return [formatter4 dateFromString:string];
  178. }
  179. };
  180. }
  181. {
  182. /*
  183. 2014-01-20T12:24:48Z // Github, Apple
  184. 2014-01-20T12:24:48+0800 // Facebook
  185. 2014-01-20T12:24:48+12:00 // Google
  186. 2014-01-20T12:24:48.000Z
  187. 2014-01-20T12:24:48.000+0800
  188. 2014-01-20T12:24:48.000+12:00
  189. */
  190. NSDateFormatter *formatter = [NSDateFormatter new];
  191. formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
  192. formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ";
  193. NSDateFormatter *formatter2 = [NSDateFormatter new];
  194. formatter2.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
  195. formatter2.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss.SSSZ";
  196. blocks[20] = ^(NSString *string) { return [formatter dateFromString:string]; };
  197. blocks[24] = ^(NSString *string) { return [formatter dateFromString:string]?: [formatter2 dateFromString:string]; };
  198. blocks[25] = ^(NSString *string) { return [formatter dateFromString:string]; };
  199. blocks[28] = ^(NSString *string) { return [formatter2 dateFromString:string]; };
  200. blocks[29] = ^(NSString *string) { return [formatter2 dateFromString:string]; };
  201. }
  202. {
  203. /*
  204. Fri Sep 04 00:12:21 +0800 2015 // Weibo, Twitter
  205. Fri Sep 04 00:12:21.000 +0800 2015
  206. */
  207. NSDateFormatter *formatter = [NSDateFormatter new];
  208. formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
  209. formatter.dateFormat = @"EEE MMM dd HH:mm:ss Z yyyy";
  210. NSDateFormatter *formatter2 = [NSDateFormatter new];
  211. formatter2.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
  212. formatter2.dateFormat = @"EEE MMM dd HH:mm:ss.SSS Z yyyy";
  213. blocks[30] = ^(NSString *string) { return [formatter dateFromString:string]; };
  214. blocks[34] = ^(NSString *string) { return [formatter2 dateFromString:string]; };
  215. }
  216. });
  217. if (!string) return nil;
  218. if (string.length > kParserNum) return nil;
  219. DKNSDateParseBlock parser = blocks[string.length];
  220. if (!parser) return nil;
  221. return parser(string);
  222. #undef kParserNum
  223. }
  224. /// Get the 'NSBlock' class.
  225. static force_inline Class DKNSBlockClass() {
  226. static Class cls;
  227. static dispatch_once_t onceToken;
  228. dispatch_once(&onceToken, ^{
  229. void (^block)(void) = ^{};
  230. cls = ((NSObject *)block).class;
  231. while (class_getSuperclass(cls) != [NSObject class]) {
  232. cls = class_getSuperclass(cls);
  233. }
  234. });
  235. return cls; // current is "NSBlock"
  236. }
  237. /**
  238. Get the ISO date formatter.
  239. ISO8601 format example:
  240. 2010-07-09T16:13:30+12:00
  241. 2011-01-11T11:11:11+0000
  242. 2011-01-26T19:06:43Z
  243. length: 20/24/25
  244. */
  245. static force_inline NSDateFormatter *DKISODateFormatter() {
  246. static NSDateFormatter *formatter = nil;
  247. static dispatch_once_t onceToken;
  248. dispatch_once(&onceToken, ^{
  249. formatter = [[NSDateFormatter alloc] init];
  250. formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
  251. formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ";
  252. });
  253. return formatter;
  254. }
  255. /// Get the value with key paths from dictionary
  256. /// The dic should be NSDictionary, and the keyPath should not be nil.
  257. static force_inline id DKValueForKeyPath(__unsafe_unretained NSDictionary *dic, __unsafe_unretained NSArray *keyPaths) {
  258. id value = nil;
  259. for (NSUInteger i = 0, max = keyPaths.count; i < max; i++) {
  260. value = dic[keyPaths[i]];
  261. if (i + 1 < max) {
  262. if ([value isKindOfClass:[NSDictionary class]]) {
  263. dic = value;
  264. } else {
  265. return nil;
  266. }
  267. }
  268. }
  269. return value;
  270. }
  271. /// Get the value with multi key (or key path) from dictionary
  272. /// The dic should be NSDictionary
  273. static force_inline id DKValueForMultiKeys(__unsafe_unretained NSDictionary *dic, __unsafe_unretained NSArray *multiKeys) {
  274. id value = nil;
  275. for (NSString *key in multiKeys) {
  276. if ([key isKindOfClass:[NSString class]]) {
  277. value = dic[key];
  278. if (value) break;
  279. } else {
  280. value = DKValueForKeyPath(dic, (NSArray *)key);
  281. if (value) break;
  282. }
  283. }
  284. return value;
  285. }
  286. /// A property info in object model.
  287. @interface _DKModelPropertyMeta : NSObject {
  288. @package
  289. NSString *_name; ///< property's name
  290. DKEncodingType _type; ///< property's type
  291. DKEncodingNSType _nsType; ///< property's Foundation type
  292. BOOL _isCNumber; ///< is c number type
  293. Class _cls; ///< property's class, or nil
  294. Class _genericCls; ///< container's generic class, or nil if threr's no generic class
  295. SEL _getter; ///< getter, or nil if the instances cannot respond
  296. SEL _setter; ///< setter, or nil if the instances cannot respond
  297. BOOL _isKVCCompatible; ///< YES if it can access with key-value coding
  298. BOOL _isStructAvailableForKeyedArchiver; ///< YES if the struct can encoded with keyed archiver/unarchiver
  299. BOOL _hasCustomClassFromDictionary; ///< class/generic class implements +modelCustomClassForDictionary:
  300. /*
  301. property->key: _mappedToKey:key _mappedToKeyPath:nil _mappedToKeyArray:nil
  302. property->keyPath: _mappedToKey:keyPath _mappedToKeyPath:keyPath(array) _mappedToKeyArray:nil
  303. property->keys: _mappedToKey:keys[0] _mappedToKeyPath:nil/keyPath _mappedToKeyArray:keys(array)
  304. */
  305. NSString *_mappedToKey; ///< the key mapped to
  306. NSArray *_mappedToKeyPath; ///< the key path mapped to (nil if the name is not key path)
  307. NSArray *_mappedToKeyArray; ///< the key(NSString) or keyPath(NSArray) array (nil if not mapped to multiple keys)
  308. DKClassPropertyInfo *_info; ///< property's info
  309. _DKModelPropertyMeta *_next; ///< next meta if there are multiple properties mapped to the same key.
  310. }
  311. @end
  312. @implementation _DKModelPropertyMeta
  313. + (instancetype)metaWithClassInfo:(DKClassInfo *)classInfo propertyInfo:(DKClassPropertyInfo *)propertyInfo generic:(Class)generic {
  314. _DKModelPropertyMeta *meta = [self new];
  315. meta->_name = propertyInfo.name;
  316. meta->_type = propertyInfo.type;
  317. meta->_info = propertyInfo;
  318. meta->_genericCls = generic;
  319. if ((meta->_type & DKEncodingTypeMask) == DKEncodingTypeObject) {
  320. meta->_nsType = DKClassGetNSType(propertyInfo.cls);
  321. } else {
  322. meta->_isCNumber = DKEncodingTypeIsCNumber(meta->_type);
  323. }
  324. if ((meta->_type & DKEncodingTypeMask) == DKEncodingTypeStruct) {
  325. /*
  326. It seems that NSKeyedUnarchiver cannot decode NSValue except these structs:
  327. */
  328. static NSSet *types = nil;
  329. static dispatch_once_t onceToken;
  330. dispatch_once(&onceToken, ^{
  331. NSMutableSet *set = [NSMutableSet new];
  332. // 32 bit
  333. [set addObject:@"{CGSize=ff}"];
  334. [set addObject:@"{CGPoint=ff}"];
  335. [set addObject:@"{CGRect={CGPoint=ff}{CGSize=ff}}"];
  336. [set addObject:@"{CGAffineTransform=ffffff}"];
  337. [set addObject:@"{UIEdgeInsets=ffff}"];
  338. [set addObject:@"{UIOffset=ff}"];
  339. // 64 bit
  340. [set addObject:@"{CGSize=dd}"];
  341. [set addObject:@"{CGPoint=dd}"];
  342. [set addObject:@"{CGRect={CGPoint=dd}{CGSize=dd}}"];
  343. [set addObject:@"{CGAffineTransform=dddddd}"];
  344. [set addObject:@"{UIEdgeInsets=dddd}"];
  345. [set addObject:@"{UIOffset=dd}"];
  346. types = set;
  347. });
  348. if ([types containsObject:propertyInfo.typeEncoding]) {
  349. meta->_isStructAvailableForKeyedArchiver = YES;
  350. }
  351. }
  352. meta->_cls = propertyInfo.cls;
  353. if (generic) {
  354. meta->_hasCustomClassFromDictionary = [generic respondsToSelector:@selector(modelCustomClassForDictionary:)];
  355. } else if (meta->_cls && meta->_nsType == DKEncodingTypeNSUnknown) {
  356. meta->_hasCustomClassFromDictionary = [meta->_cls respondsToSelector:@selector(modelCustomClassForDictionary:)];
  357. }
  358. if (propertyInfo.getter) {
  359. if ([classInfo.cls instancesRespondToSelector:propertyInfo.getter]) {
  360. meta->_getter = propertyInfo.getter;
  361. }
  362. }
  363. if (propertyInfo.setter) {
  364. if ([classInfo.cls instancesRespondToSelector:propertyInfo.setter]) {
  365. meta->_setter = propertyInfo.setter;
  366. }
  367. }
  368. if (meta->_getter && meta->_setter) {
  369. /*
  370. KVC invalid type:
  371. long double
  372. pointer (such as SEL/CoreFoundation object)
  373. */
  374. switch (meta->_type & DKEncodingTypeMask) {
  375. case DKEncodingTypeBool:
  376. case DKEncodingTypeInt8:
  377. case DKEncodingTypeUInt8:
  378. case DKEncodingTypeInt16:
  379. case DKEncodingTypeUInt16:
  380. case DKEncodingTypeInt32:
  381. case DKEncodingTypeUInt32:
  382. case DKEncodingTypeInt64:
  383. case DKEncodingTypeUInt64:
  384. case DKEncodingTypeFloat:
  385. case DKEncodingTypeDouble:
  386. case DKEncodingTypeObject:
  387. case DKEncodingTypeClass:
  388. case DKEncodingTypeBlock:
  389. case DKEncodingTypeStruct:
  390. case DKEncodingTypeUnion: {
  391. meta->_isKVCCompatible = YES;
  392. } break;
  393. default: break;
  394. }
  395. }
  396. return meta;
  397. }
  398. @end
  399. /// A class info in object model.
  400. @interface _DKModelMeta : NSObject {
  401. @package
  402. DKClassInfo *_classInfo;
  403. /// Key:mapped key and key path, Value:_DKModelPropertyInfo.
  404. NSDictionary *_mapper;
  405. /// Array<_DKModelPropertyMeta>, all property meta of this model.
  406. NSArray *_allPropertyMetas;
  407. /// Array<_DKModelPropertyMeta>, property meta which is mapped to a key path.
  408. NSArray *_keyPathPropertyMetas;
  409. /// Array<_DKModelPropertyMeta>, property meta which is mapped to multi keys.
  410. NSArray *_multiKeysPropertyMetas;
  411. /// The number of mapped key (and key path), same to _mapper.count.
  412. NSUInteger _keyMappedCount;
  413. /// Model class type.
  414. DKEncodingNSType _nsType;
  415. BOOL _hasCustomWillTransformFromDictionary;
  416. BOOL _hasCustomTransformFromDictionary;
  417. BOOL _hasCustomTransformToDictionary;
  418. BOOL _hasCustomClassFromDictionary;
  419. }
  420. @end
  421. @implementation _DKModelMeta
  422. - (instancetype)initWithClass:(Class)cls {
  423. DKClassInfo *classInfo = [DKClassInfo classInfoWithClass:cls];
  424. if (!classInfo) return nil;
  425. self = [super init];
  426. // Get black list
  427. NSSet *blacklist = nil;
  428. if ([cls respondsToSelector:@selector(modelPropertyBlacklist)]) {
  429. NSArray *properties = [(id<DKModel>)cls modelPropertyBlacklist];
  430. if (properties) {
  431. blacklist = [NSSet setWithArray:properties];
  432. }
  433. }
  434. // Get white list
  435. NSSet *whitelist = nil;
  436. if ([cls respondsToSelector:@selector(modelPropertyWhitelist)]) {
  437. NSArray *properties = [(id<DKModel>)cls modelPropertyWhitelist];
  438. if (properties) {
  439. whitelist = [NSSet setWithArray:properties];
  440. }
  441. }
  442. // Get container property's generic class
  443. NSDictionary *genericMapper = nil;
  444. if ([cls respondsToSelector:@selector(modelContainerPropertyGenericClass)]) {
  445. genericMapper = [(id<DKModel>)cls modelContainerPropertyGenericClass];
  446. if (genericMapper) {
  447. NSMutableDictionary *tmp = [NSMutableDictionary new];
  448. [genericMapper enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
  449. if (![key isKindOfClass:[NSString class]]) return;
  450. Class meta = object_getClass(obj);
  451. if (!meta) return;
  452. if (class_isMetaClass(meta)) {
  453. tmp[key] = obj;
  454. } else if ([obj isKindOfClass:[NSString class]]) {
  455. Class cls = NSClassFromString(obj);
  456. if (cls) {
  457. tmp[key] = cls;
  458. }
  459. }
  460. }];
  461. genericMapper = tmp;
  462. }
  463. }
  464. // Create all property metas.
  465. NSMutableDictionary *allPropertyMetas = [NSMutableDictionary new];
  466. DKClassInfo *curClassInfo = classInfo;
  467. while (curClassInfo && curClassInfo.superCls != nil) { // recursive parse super class, but ignore root class (NSObject/NSProxy)
  468. for (DKClassPropertyInfo *propertyInfo in curClassInfo.propertyInfos.allValues) {
  469. if (!propertyInfo.name) continue;
  470. if (blacklist && [blacklist containsObject:propertyInfo.name]) continue;
  471. if (whitelist && ![whitelist containsObject:propertyInfo.name]) continue;
  472. _DKModelPropertyMeta *meta = [_DKModelPropertyMeta metaWithClassInfo:classInfo
  473. propertyInfo:propertyInfo
  474. generic:genericMapper[propertyInfo.name]];
  475. if (!meta || !meta->_name) continue;
  476. if (!meta->_getter || !meta->_setter) continue;
  477. if (allPropertyMetas[meta->_name]) continue;
  478. allPropertyMetas[meta->_name] = meta;
  479. }
  480. curClassInfo = curClassInfo.superClassInfo;
  481. }
  482. if (allPropertyMetas.count) _allPropertyMetas = allPropertyMetas.allValues.copy;
  483. // create mapper
  484. NSMutableDictionary *mapper = [NSMutableDictionary new];
  485. NSMutableArray *keyPathPropertyMetas = [[NSMutableArray alloc]init];
  486. NSMutableArray *multiKeysPropertyMetas = [[NSMutableArray alloc]init];
  487. if ([cls respondsToSelector:@selector(modelCustomPropertyMapper)]) {
  488. NSDictionary *customMapper = [(id <DKModel>)cls modelCustomPropertyMapper];
  489. [customMapper enumerateKeysAndObjectsUsingBlock:^(NSString *propertyName, NSString *mappedToKey, BOOL *stop) {
  490. _DKModelPropertyMeta *propertyMeta = allPropertyMetas[propertyName];
  491. if (!propertyMeta) return;
  492. [allPropertyMetas removeObjectForKey:propertyName];
  493. if ([mappedToKey isKindOfClass:[NSString class]]) {
  494. if (mappedToKey.length == 0) return;
  495. propertyMeta->_mappedToKey = mappedToKey;
  496. NSArray *keyPath = [mappedToKey componentsSeparatedByString:@"."];
  497. if (keyPath.count > 1) {
  498. propertyMeta->_mappedToKeyPath = keyPath;
  499. [keyPathPropertyMetas addObject:propertyMeta];
  500. }
  501. propertyMeta->_next = mapper[mappedToKey] ?: nil;
  502. mapper[mappedToKey] = propertyMeta;
  503. } else if ([mappedToKey isKindOfClass:[NSArray class]]) {
  504. NSMutableArray *mappedToKeyArray = [[NSMutableArray alloc]init];
  505. for (NSString *oneKey in ((NSArray *)mappedToKey)) {
  506. if (![oneKey isKindOfClass:[NSString class]]) continue;
  507. if (oneKey.length == 0) continue;
  508. NSArray *keyPath = [oneKey componentsSeparatedByString:@"."];
  509. if (keyPath.count > 1) {
  510. [mappedToKeyArray addObject:keyPath];
  511. } else {
  512. [mappedToKeyArray addObject:oneKey];
  513. }
  514. if (!propertyMeta->_mappedToKey) {
  515. propertyMeta->_mappedToKey = oneKey;
  516. propertyMeta->_mappedToKeyPath = keyPath.count > 1 ? keyPath : nil;
  517. }
  518. }
  519. if (!propertyMeta->_mappedToKey) return;
  520. propertyMeta->_mappedToKeyArray = mappedToKeyArray;
  521. [multiKeysPropertyMetas addObject:propertyMeta];
  522. propertyMeta->_next = mapper[mappedToKey] ?: nil;
  523. mapper[mappedToKey] = propertyMeta;
  524. }
  525. }];
  526. }
  527. [allPropertyMetas enumerateKeysAndObjectsUsingBlock:^(NSString *name, _DKModelPropertyMeta *propertyMeta, BOOL *stop) {
  528. propertyMeta->_mappedToKey = name;
  529. propertyMeta->_next = mapper[name] ?: nil;
  530. mapper[name] = propertyMeta;
  531. }];
  532. if (mapper.count) _mapper = mapper;
  533. if (keyPathPropertyMetas) _keyPathPropertyMetas = keyPathPropertyMetas;
  534. if (multiKeysPropertyMetas) _multiKeysPropertyMetas = multiKeysPropertyMetas;
  535. _classInfo = classInfo;
  536. _keyMappedCount = _allPropertyMetas.count;
  537. _nsType = DKClassGetNSType(cls);
  538. _hasCustomWillTransformFromDictionary = ([cls instancesRespondToSelector:@selector(modelCustomWillTransformFromDictionary:)]);
  539. _hasCustomTransformFromDictionary = ([cls instancesRespondToSelector:@selector(modelCustomTransformFromDictionary:)]);
  540. _hasCustomTransformToDictionary = ([cls instancesRespondToSelector:@selector(modelCustomTransformToDictionary:)]);
  541. _hasCustomClassFromDictionary = ([cls respondsToSelector:@selector(modelCustomClassForDictionary:)]);
  542. return self;
  543. }
  544. /// Returns the cached model class meta
  545. + (instancetype)metaWithClass:(Class)cls {
  546. if (!cls) return nil;
  547. static CFMutableDictionaryRef cache;
  548. static dispatch_once_t onceToken;
  549. static dispatch_semaphore_t lock;
  550. dispatch_once(&onceToken, ^{
  551. cache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
  552. lock = dispatch_semaphore_create(1);
  553. });
  554. dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
  555. _DKModelMeta *meta = CFDictionaryGetValue(cache, (__bridge const void *)(cls));
  556. dispatch_semaphore_signal(lock);
  557. if (!meta || meta->_classInfo.needUpdate) {
  558. meta = [[_DKModelMeta alloc] initWithClass:cls];
  559. if (meta) {
  560. dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
  561. CFDictionarySetValue(cache, (__bridge const void *)(cls), (__bridge const void *)(meta));
  562. dispatch_semaphore_signal(lock);
  563. }
  564. }
  565. return meta;
  566. }
  567. @end
  568. /**
  569. Get number from property.
  570. @discussion Caller should hold strong reference to the parameters before this function returns.
  571. @param model Should not be nil.
  572. @param meta Should not be nil, meta.isCNumber should be YES, meta.getter should not be nil.
  573. @return A number object, or nil if failed.
  574. */
  575. static force_inline NSNumber *ModelCreateNumberFromProperty(__unsafe_unretained id model,
  576. __unsafe_unretained _DKModelPropertyMeta *meta) {
  577. switch (meta->_type & DKEncodingTypeMask) {
  578. case DKEncodingTypeBool: {
  579. return @(((bool (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
  580. }
  581. case DKEncodingTypeInt8: {
  582. return @(((int8_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
  583. }
  584. case DKEncodingTypeUInt8: {
  585. return @(((uint8_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
  586. }
  587. case DKEncodingTypeInt16: {
  588. return @(((int16_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
  589. }
  590. case DKEncodingTypeUInt16: {
  591. return @(((uint16_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
  592. }
  593. case DKEncodingTypeInt32: {
  594. return @(((int32_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
  595. }
  596. case DKEncodingTypeUInt32: {
  597. return @(((uint32_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
  598. }
  599. case DKEncodingTypeInt64: {
  600. return @(((int64_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
  601. }
  602. case DKEncodingTypeUInt64: {
  603. return @(((uint64_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
  604. }
  605. case DKEncodingTypeFloat: {
  606. float num = ((float (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter);
  607. if (isnan(num) || isinf(num)) return nil;
  608. return @(num);
  609. }
  610. case DKEncodingTypeDouble: {
  611. double num = ((double (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter);
  612. if (isnan(num) || isinf(num)) return nil;
  613. return @(num);
  614. }
  615. case DKEncodingTypeLongDouble: {
  616. double num = ((long double (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter);
  617. if (isnan(num) || isinf(num)) return nil;
  618. return @(num);
  619. }
  620. default: return nil;
  621. }
  622. }
  623. /**
  624. Set number to property.
  625. @discussion Caller should hold strong reference to the parameters before this function returns.
  626. @param model Should not be nil.
  627. @param num Can be nil.
  628. @param meta Should not be nil, meta.isCNumber should be YES, meta.setter should not be nil.
  629. */
  630. static force_inline void ModelSetNumberToProperty(__unsafe_unretained id model,
  631. __unsafe_unretained NSNumber *num,
  632. __unsafe_unretained _DKModelPropertyMeta *meta) {
  633. switch (meta->_type & DKEncodingTypeMask) {
  634. case DKEncodingTypeBool: {
  635. ((void (*)(id, SEL, bool))(void *) objc_msgSend)((id)model, meta->_setter, num.boolValue);
  636. } break;
  637. case DKEncodingTypeInt8: {
  638. ((void (*)(id, SEL, int8_t))(void *) objc_msgSend)((id)model, meta->_setter, (int8_t)num.charValue);
  639. } break;
  640. case DKEncodingTypeUInt8: {
  641. ((void (*)(id, SEL, uint8_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint8_t)num.unsignedCharValue);
  642. } break;
  643. case DKEncodingTypeInt16: {
  644. ((void (*)(id, SEL, int16_t))(void *) objc_msgSend)((id)model, meta->_setter, (int16_t)num.shortValue);
  645. } break;
  646. case DKEncodingTypeUInt16: {
  647. ((void (*)(id, SEL, uint16_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint16_t)num.unsignedShortValue);
  648. } break;
  649. case DKEncodingTypeInt32: {
  650. ((void (*)(id, SEL, int32_t))(void *) objc_msgSend)((id)model, meta->_setter, (int32_t)num.intValue);
  651. }
  652. case DKEncodingTypeUInt32: {
  653. ((void (*)(id, SEL, uint32_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint32_t)num.unsignedIntValue);
  654. } break;
  655. case DKEncodingTypeInt64: {
  656. if ([num isKindOfClass:[NSDecimalNumber class]]) {
  657. ((void (*)(id, SEL, int64_t))(void *) objc_msgSend)((id)model, meta->_setter, (int64_t)num.stringValue.longLongValue);
  658. } else {
  659. ((void (*)(id, SEL, uint64_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint64_t)num.longLongValue);
  660. }
  661. } break;
  662. case DKEncodingTypeUInt64: {
  663. if ([num isKindOfClass:[NSDecimalNumber class]]) {
  664. ((void (*)(id, SEL, int64_t))(void *) objc_msgSend)((id)model, meta->_setter, (int64_t)num.stringValue.longLongValue);
  665. } else {
  666. ((void (*)(id, SEL, uint64_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint64_t)num.unsignedLongLongValue);
  667. }
  668. } break;
  669. case DKEncodingTypeFloat: {
  670. float f = num.floatValue;
  671. if (isnan(f) || isinf(f)) f = 0;
  672. ((void (*)(id, SEL, float))(void *) objc_msgSend)((id)model, meta->_setter, f);
  673. } break;
  674. case DKEncodingTypeDouble: {
  675. double d = num.doubleValue;
  676. if (isnan(d) || isinf(d)) d = 0;
  677. ((void (*)(id, SEL, double))(void *) objc_msgSend)((id)model, meta->_setter, d);
  678. } break;
  679. case DKEncodingTypeLongDouble: {
  680. long double d = num.doubleValue;
  681. if (isnan(d) || isinf(d)) d = 0;
  682. ((void (*)(id, SEL, long double))(void *) objc_msgSend)((id)model, meta->_setter, (long double)d);
  683. } // break; commented for code coverage in next line
  684. default: break;
  685. }
  686. }
  687. /**
  688. Set value to model with a property meta.
  689. @discussion Caller should hold strong reference to the parameters before this function returns.
  690. @param model Should not be nil.
  691. @param value Should not be nil, but can be NSNull.
  692. @param meta Should not be nil, and meta->_setter should not be nil.
  693. */
  694. static void ModelSetValueForProperty(__unsafe_unretained id model,
  695. __unsafe_unretained id value,
  696. __unsafe_unretained _DKModelPropertyMeta *meta) {
  697. if (meta->_isCNumber) {
  698. NSNumber *num = DKNSNumberCreateFromID(value);
  699. ModelSetNumberToProperty(model, num, meta);
  700. if (num) [num class]; // hold the number
  701. } else if (meta->_nsType) {
  702. if (value == (id)kCFNull) {
  703. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, (id)nil);
  704. } else {
  705. switch (meta->_nsType) {
  706. case DKEncodingTypeNSString:
  707. case DKEncodingTypeNSMutableString: {
  708. if ([value isKindOfClass:[NSString class]]) {
  709. if (meta->_nsType == DKEncodingTypeNSString) {
  710. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
  711. } else {
  712. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, ((NSString *)value).mutableCopy);
  713. }
  714. } else if ([value isKindOfClass:[NSNumber class]]) {
  715. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
  716. meta->_setter,
  717. (meta->_nsType == DKEncodingTypeNSString) ?
  718. ((NSNumber *)value).stringValue :
  719. ((NSNumber *)value).stringValue.mutableCopy);
  720. } else if ([value isKindOfClass:[NSData class]]) {
  721. NSMutableString *string = [[NSMutableString alloc] initWithData:value encoding:NSUTF8StringEncoding];
  722. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, string);
  723. } else if ([value isKindOfClass:[NSURL class]]) {
  724. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
  725. meta->_setter,
  726. (meta->_nsType == DKEncodingTypeNSString) ?
  727. ((NSURL *)value).absoluteString :
  728. ((NSURL *)value).absoluteString.mutableCopy);
  729. } else if ([value isKindOfClass:[NSAttributedString class]]) {
  730. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
  731. meta->_setter,
  732. (meta->_nsType == DKEncodingTypeNSString) ?
  733. ((NSAttributedString *)value).string :
  734. ((NSAttributedString *)value).string.mutableCopy);
  735. }
  736. } break;
  737. case DKEncodingTypeNSValue:
  738. case DKEncodingTypeNSNumber:
  739. case DKEncodingTypeNSDecimalNumber: {
  740. if (meta->_nsType == DKEncodingTypeNSNumber) {
  741. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, DKNSNumberCreateFromID(value));
  742. } else if (meta->_nsType == DKEncodingTypeNSDecimalNumber) {
  743. if ([value isKindOfClass:[NSDecimalNumber class]]) {
  744. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
  745. } else if ([value isKindOfClass:[NSNumber class]]) {
  746. NSDecimalNumber *decNum = [NSDecimalNumber decimalNumberWithDecimal:[((NSNumber *)value) decimalValue]];
  747. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, decNum);
  748. } else if ([value isKindOfClass:[NSString class]]) {
  749. NSDecimalNumber *decNum = [NSDecimalNumber decimalNumberWithString:value];
  750. NSDecimal dec = decNum.decimalValue;
  751. if (dec._length == 0 && dec._isNegative) {
  752. decNum = nil; // NaN
  753. }
  754. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, decNum);
  755. }
  756. } else { // DKEncodingTypeNSValue
  757. if ([value isKindOfClass:[NSValue class]]) {
  758. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
  759. }
  760. }
  761. } break;
  762. case DKEncodingTypeNSData:
  763. case DKEncodingTypeNSMutableData: {
  764. if ([value isKindOfClass:[NSData class]]) {
  765. if (meta->_nsType == DKEncodingTypeNSData) {
  766. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
  767. } else {
  768. NSMutableData *data = ((NSData *)value).mutableCopy;
  769. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, data);
  770. }
  771. } else if ([value isKindOfClass:[NSString class]]) {
  772. NSData *data = [(NSString *)value dataUsingEncoding:NSUTF8StringEncoding];
  773. if (meta->_nsType == DKEncodingTypeNSMutableData) {
  774. data = ((NSData *)data).mutableCopy;
  775. }
  776. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, data);
  777. }
  778. } break;
  779. case DKEncodingTypeNSDate: {
  780. if ([value isKindOfClass:[NSDate class]]) {
  781. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
  782. } else if ([value isKindOfClass:[NSString class]]) {
  783. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, DKNSDateFromString(value));
  784. }
  785. } break;
  786. case DKEncodingTypeNSURL: {
  787. if ([value isKindOfClass:[NSURL class]]) {
  788. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
  789. } else if ([value isKindOfClass:[NSString class]]) {
  790. NSCharacterSet *set = [NSCharacterSet whitespaceAndNewlineCharacterSet];
  791. NSString *str = [value stringByTrimmingCharactersInSet:set];
  792. if (str.length == 0) {
  793. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, nil);
  794. } else {
  795. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, [[NSURL alloc] initWithString:str]);
  796. }
  797. }
  798. } break;
  799. case DKEncodingTypeNSArray:
  800. case DKEncodingTypeNSMutableArray: {
  801. if (meta->_genericCls) {
  802. NSArray *valueArr = nil;
  803. if ([value isKindOfClass:[NSArray class]]) valueArr = value;
  804. else if ([value isKindOfClass:[NSSet class]]) valueArr = ((NSSet *)value).allObjects;
  805. if (valueArr) {
  806. NSMutableArray *objectArr = [[NSMutableArray alloc]init];
  807. for (id one in valueArr) {
  808. if ([one isKindOfClass:meta->_genericCls]) {
  809. [objectArr addObject:one];
  810. } else if ([one isKindOfClass:[NSDictionary class]]) {
  811. Class cls = meta->_genericCls;
  812. if (meta->_hasCustomClassFromDictionary) {
  813. cls = [cls modelCustomClassForDictionary:one];
  814. if (!cls) cls = meta->_genericCls; // for xcode code coverage
  815. }
  816. NSObject *newOne = [cls new];
  817. [newOne dk_modelSetWithDictionary:one];
  818. if (newOne) [objectArr addObject:newOne];
  819. }
  820. }
  821. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, objectArr);
  822. }
  823. } else {
  824. if ([value isKindOfClass:[NSArray class]]) {
  825. if (meta->_nsType == DKEncodingTypeNSArray) {
  826. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
  827. } else {
  828. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
  829. meta->_setter,
  830. ((NSArray *)value).mutableCopy);
  831. }
  832. } else if ([value isKindOfClass:[NSSet class]]) {
  833. if (meta->_nsType == DKEncodingTypeNSArray) {
  834. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, ((NSSet *)value).allObjects);
  835. } else {
  836. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
  837. meta->_setter,
  838. ((NSSet *)value).allObjects.mutableCopy);
  839. }
  840. }
  841. }
  842. } break;
  843. case DKEncodingTypeNSDictionary:
  844. case DKEncodingTypeNSMutableDictionary: {
  845. if ([value isKindOfClass:[NSDictionary class]]) {
  846. if (meta->_genericCls) {
  847. NSMutableDictionary *dic = [NSMutableDictionary new];
  848. [((NSDictionary *)value) enumerateKeysAndObjectsUsingBlock:^(NSString *oneKey, id oneValue, BOOL *stop) {
  849. if ([oneValue isKindOfClass:[NSDictionary class]]) {
  850. Class cls = meta->_genericCls;
  851. if (meta->_hasCustomClassFromDictionary) {
  852. cls = [cls modelCustomClassForDictionary:oneValue];
  853. if (!cls) cls = meta->_genericCls; // for xcode code coverage
  854. }
  855. NSObject *newOne = [cls new];
  856. [newOne dk_modelSetWithDictionary:(id)oneValue];
  857. if (newOne) dic[oneKey] = newOne;
  858. }
  859. }];
  860. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, dic);
  861. } else {
  862. if (meta->_nsType == DKEncodingTypeNSDictionary) {
  863. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
  864. } else {
  865. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
  866. meta->_setter,
  867. ((NSDictionary *)value).mutableCopy);
  868. }
  869. }
  870. }
  871. } break;
  872. case DKEncodingTypeNSSet:
  873. case DKEncodingTypeNSMutableSet: {
  874. NSSet *valueSet = nil;
  875. if ([value isKindOfClass:[NSArray class]]) valueSet = [NSMutableSet setWithArray:value];
  876. else if ([value isKindOfClass:[NSSet class]]) valueSet = ((NSSet *)value);
  877. if (meta->_genericCls) {
  878. NSMutableSet *set = [NSMutableSet new];
  879. for (id one in valueSet) {
  880. if ([one isKindOfClass:meta->_genericCls]) {
  881. [set addObject:one];
  882. } else if ([one isKindOfClass:[NSDictionary class]]) {
  883. Class cls = meta->_genericCls;
  884. if (meta->_hasCustomClassFromDictionary) {
  885. cls = [cls modelCustomClassForDictionary:one];
  886. if (!cls) cls = meta->_genericCls; // for xcode code coverage
  887. }
  888. NSObject *newOne = [cls new];
  889. [newOne dk_modelSetWithDictionary:one];
  890. if (newOne) [set addObject:newOne];
  891. }
  892. }
  893. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, set);
  894. } else {
  895. if (meta->_nsType == DKEncodingTypeNSSet) {
  896. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, valueSet);
  897. } else {
  898. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
  899. meta->_setter,
  900. ((NSSet *)valueSet).mutableCopy);
  901. }
  902. }
  903. } // break; commented for code coverage in next line
  904. default: break;
  905. }
  906. }
  907. } else {
  908. BOOL isNull = (value == (id)kCFNull);
  909. switch (meta->_type & DKEncodingTypeMask) {
  910. case DKEncodingTypeObject: {
  911. if (isNull) {
  912. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, (id)nil);
  913. } else if ([value isKindOfClass:meta->_cls] || !meta->_cls) {
  914. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, (id)value);
  915. } else if ([value isKindOfClass:[NSDictionary class]]) {
  916. NSObject *one = nil;
  917. if (meta->_getter) {
  918. one = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter);
  919. }
  920. if (one) {
  921. [one dk_modelSetWithDictionary:value];
  922. } else {
  923. Class cls = meta->_cls;
  924. if (meta->_hasCustomClassFromDictionary) {
  925. cls = [cls modelCustomClassForDictionary:value];
  926. if (!cls) cls = meta->_genericCls; // for xcode code coverage
  927. }
  928. one = [cls new];
  929. [one dk_modelSetWithDictionary:value];
  930. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, (id)one);
  931. }
  932. }
  933. } break;
  934. case DKEncodingTypeClass: {
  935. if (isNull) {
  936. ((void (*)(id, SEL, Class))(void *) objc_msgSend)((id)model, meta->_setter, (Class)NULL);
  937. } else {
  938. Class cls = nil;
  939. if ([value isKindOfClass:[NSString class]]) {
  940. cls = NSClassFromString(value);
  941. if (cls) {
  942. ((void (*)(id, SEL, Class))(void *) objc_msgSend)((id)model, meta->_setter, (Class)cls);
  943. }
  944. } else {
  945. cls = object_getClass(value);
  946. if (cls) {
  947. if (class_isMetaClass(cls)) {
  948. ((void (*)(id, SEL, Class))(void *) objc_msgSend)((id)model, meta->_setter, (Class)value);
  949. }
  950. }
  951. }
  952. }
  953. } break;
  954. case DKEncodingTypeSEL: {
  955. if (isNull) {
  956. ((void (*)(id, SEL, SEL))(void *) objc_msgSend)((id)model, meta->_setter, (SEL)NULL);
  957. } else if ([value isKindOfClass:[NSString class]]) {
  958. SEL sel = NSSelectorFromString(value);
  959. if (sel) ((void (*)(id, SEL, SEL))(void *) objc_msgSend)((id)model, meta->_setter, (SEL)sel);
  960. }
  961. } break;
  962. case DKEncodingTypeBlock: {
  963. if (isNull) {
  964. ((void (*)(id, SEL, void (^)(void)))(void *) objc_msgSend)((id)model, meta->_setter, (void (^)(void))NULL);
  965. } else if ([value isKindOfClass:DKNSBlockClass()]) {
  966. ((void (*)(id, SEL, void (^)(void)))(void *) objc_msgSend)((id)model, meta->_setter, (void (^)(void))value);
  967. }
  968. } break;
  969. case DKEncodingTypeStruct:
  970. case DKEncodingTypeUnion:
  971. case DKEncodingTypeCArray: {
  972. if ([value isKindOfClass:[NSValue class]]) {
  973. const char *valueType = ((NSValue *)value).objCType;
  974. const char *metaType = meta->_info.typeEncoding.UTF8String;
  975. if (valueType && metaType && strcmp(valueType, metaType) == 0) {
  976. [model setValue:value forKey:meta->_name];
  977. }
  978. }
  979. } break;
  980. case DKEncodingTypePointer:
  981. case DKEncodingTypeCString: {
  982. if (isNull) {
  983. ((void (*)(id, SEL, void *))(void *) objc_msgSend)((id)model, meta->_setter, (void *)NULL);
  984. } else if ([value isKindOfClass:[NSValue class]]) {
  985. NSValue *nsValue = value;
  986. if (nsValue.objCType && strcmp(nsValue.objCType, "^v") == 0) {
  987. ((void (*)(id, SEL, void *))(void *) objc_msgSend)((id)model, meta->_setter, nsValue.pointerValue);
  988. }
  989. }
  990. } // break; commented for code coverage in next line
  991. default: break;
  992. }
  993. }
  994. }
  995. typedef struct {
  996. void *modelMeta; ///< _DKModelMeta
  997. void *model; ///< id (self)
  998. void *dictionary; ///< NSDictionary (json)
  999. } ModelSetContext;
  1000. /**
  1001. Apply function for dictionary, to set the key-value pair to model.
  1002. @param _key should not be nil, NSString.
  1003. @param _value should not be nil.
  1004. @param _context _context.modelMeta and _context.model should not be nil.
  1005. */
  1006. static void ModelSetWithDictionaryFunction(const void *_key, const void *_value, void *_context) {
  1007. ModelSetContext *context = _context;
  1008. __unsafe_unretained _DKModelMeta *meta = (__bridge _DKModelMeta *)(context->modelMeta);
  1009. __unsafe_unretained _DKModelPropertyMeta *propertyMeta = [meta->_mapper objectForKey:(__bridge id)(_key)];
  1010. __unsafe_unretained id model = (__bridge id)(context->model);
  1011. while (propertyMeta) {
  1012. if (propertyMeta->_setter) {
  1013. ModelSetValueForProperty(model, (__bridge __unsafe_unretained id)_value, propertyMeta);
  1014. }
  1015. propertyMeta = propertyMeta->_next;
  1016. };
  1017. }
  1018. /**
  1019. Apply function for model property meta, to set dictionary to model.
  1020. @param _propertyMeta should not be nil, _DKModelPropertyMeta.
  1021. @param _context _context.model and _context.dictionary should not be nil.
  1022. */
  1023. static void ModelSetWithPropertyMetaArrayFunction(const void *_propertyMeta, void *_context) {
  1024. ModelSetContext *context = _context;
  1025. __unsafe_unretained NSDictionary *dictionary = (__bridge NSDictionary *)(context->dictionary);
  1026. __unsafe_unretained _DKModelPropertyMeta *propertyMeta = (__bridge _DKModelPropertyMeta *)(_propertyMeta);
  1027. if (!propertyMeta->_setter) return;
  1028. id value = nil;
  1029. if (propertyMeta->_mappedToKeyArray) {
  1030. value = DKValueForMultiKeys(dictionary, propertyMeta->_mappedToKeyArray);
  1031. } else if (propertyMeta->_mappedToKeyPath) {
  1032. value = DKValueForKeyPath(dictionary, propertyMeta->_mappedToKeyPath);
  1033. } else {
  1034. value = [dictionary objectForKey:propertyMeta->_mappedToKey];
  1035. }
  1036. if (value) {
  1037. __unsafe_unretained id model = (__bridge id)(context->model);
  1038. ModelSetValueForProperty(model, value, propertyMeta);
  1039. }
  1040. }
  1041. /**
  1042. Returns a valid JSON object (NSArray/NSDictionary/NSString/NSNumber/NSNull),
  1043. or nil if an error occurs.
  1044. @param model Model, can be nil.
  1045. @return JSON object, nil if an error occurs.
  1046. */
  1047. static id ModelToJSONObjectRecursive(NSObject *model) {
  1048. if (!model || model == (id)kCFNull) return model;
  1049. if ([model isKindOfClass:[NSString class]]) return model;
  1050. if ([model isKindOfClass:[NSNumber class]]) return model;
  1051. if ([model isKindOfClass:[NSDictionary class]]) {
  1052. if ([NSJSONSerialization isValidJSONObject:model]) return model;
  1053. NSMutableDictionary *newDic = [NSMutableDictionary new];
  1054. [((NSDictionary *)model) enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
  1055. NSString *stringKey = [key isKindOfClass:[NSString class]] ? key : key.description;
  1056. if (!stringKey) return;
  1057. id jsonObj = ModelToJSONObjectRecursive(obj);
  1058. if (!jsonObj) jsonObj = (id)kCFNull;
  1059. newDic[stringKey] = jsonObj;
  1060. }];
  1061. return newDic;
  1062. }
  1063. if ([model isKindOfClass:[NSSet class]]) {
  1064. NSArray *array = ((NSSet *)model).allObjects;
  1065. if ([NSJSONSerialization isValidJSONObject:array]) return array;
  1066. NSMutableArray *newArray = [[NSMutableArray alloc]init];
  1067. for (id obj in array) {
  1068. if ([obj isKindOfClass:[NSString class]] || [obj isKindOfClass:[NSNumber class]]) {
  1069. [newArray addObject:obj];
  1070. } else {
  1071. id jsonObj = ModelToJSONObjectRecursive(obj);
  1072. if (jsonObj && jsonObj != (id)kCFNull) [newArray addObject:jsonObj];
  1073. }
  1074. }
  1075. return newArray;
  1076. }
  1077. if ([model isKindOfClass:[NSArray class]]) {
  1078. if ([NSJSONSerialization isValidJSONObject:model]) return model;
  1079. NSMutableArray *newArray = [[NSMutableArray alloc]init];
  1080. for (id obj in (NSArray *)model) {
  1081. if ([obj isKindOfClass:[NSString class]] || [obj isKindOfClass:[NSNumber class]]) {
  1082. [newArray addObject:obj];
  1083. } else {
  1084. id jsonObj = ModelToJSONObjectRecursive(obj);
  1085. if (jsonObj && jsonObj != (id)kCFNull) [newArray addObject:jsonObj];
  1086. }
  1087. }
  1088. return newArray;
  1089. }
  1090. if ([model isKindOfClass:[NSURL class]]) return ((NSURL *)model).absoluteString;
  1091. if ([model isKindOfClass:[NSAttributedString class]]) return ((NSAttributedString *)model).string;
  1092. if ([model isKindOfClass:[NSDate class]]) return [DKISODateFormatter() stringFromDate:(id)model];
  1093. if ([model isKindOfClass:[NSData class]]) return nil;
  1094. _DKModelMeta *modelMeta = [_DKModelMeta metaWithClass:[model class]];
  1095. if (!modelMeta || modelMeta->_keyMappedCount == 0) return nil;
  1096. NSMutableDictionary *result = [[NSMutableDictionary alloc] initWithCapacity:64];
  1097. __unsafe_unretained NSMutableDictionary *dic = result; // avoid retain and release in block
  1098. [modelMeta->_mapper enumerateKeysAndObjectsUsingBlock:^(NSString *propertyMappedKey, _DKModelPropertyMeta *propertyMeta, BOOL *stop) {
  1099. if (!propertyMeta->_getter) return;
  1100. id value = nil;
  1101. if (propertyMeta->_isCNumber) {
  1102. value = ModelCreateNumberFromProperty(model, propertyMeta);
  1103. } else if (propertyMeta->_nsType) {
  1104. id v = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter);
  1105. value = ModelToJSONObjectRecursive(v);
  1106. } else {
  1107. switch (propertyMeta->_type & DKEncodingTypeMask) {
  1108. case DKEncodingTypeObject: {
  1109. id v = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter);
  1110. value = ModelToJSONObjectRecursive(v);
  1111. if (value == (id)kCFNull) value = nil;
  1112. } break;
  1113. case DKEncodingTypeClass: {
  1114. Class v = ((Class (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter);
  1115. value = v ? NSStringFromClass(v) : nil;
  1116. } break;
  1117. case DKEncodingTypeSEL: {
  1118. SEL v = ((SEL (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter);
  1119. value = v ? NSStringFromSelector(v) : nil;
  1120. } break;
  1121. default: break;
  1122. }
  1123. }
  1124. if (!value) return;
  1125. if (propertyMeta->_mappedToKeyPath) {
  1126. NSMutableDictionary *superDic = dic;
  1127. NSMutableDictionary *subDic = nil;
  1128. for (NSUInteger i = 0, max = propertyMeta->_mappedToKeyPath.count; i < max; i++) {
  1129. NSString *key = propertyMeta->_mappedToKeyPath[i];
  1130. if (i + 1 == max) { // end
  1131. if (!superDic[key]) superDic[key] = value;
  1132. break;
  1133. }
  1134. subDic = superDic[key];
  1135. if (subDic) {
  1136. if ([subDic isKindOfClass:[NSDictionary class]]) {
  1137. subDic = subDic.mutableCopy;
  1138. superDic[key] = subDic;
  1139. } else {
  1140. break;
  1141. }
  1142. } else {
  1143. subDic = [NSMutableDictionary new];
  1144. superDic[key] = subDic;
  1145. }
  1146. superDic = subDic;
  1147. subDic = nil;
  1148. }
  1149. } else {
  1150. if (!dic[propertyMeta->_mappedToKey]) {
  1151. dic[propertyMeta->_mappedToKey] = value;
  1152. }
  1153. }
  1154. }];
  1155. if (modelMeta->_hasCustomTransformToDictionary) {
  1156. BOOL suc = [((id<DKModel>)model) modelCustomTransformToDictionary:dic];
  1157. if (!suc) return nil;
  1158. }
  1159. return result;
  1160. }
  1161. /// Add indent to string (exclude first line)
  1162. static NSMutableString *ModelDescriptionAddIndent(NSMutableString *desc, NSUInteger indent) {
  1163. for (NSUInteger i = 0, max = desc.length; i < max; i++) {
  1164. unichar c = [desc characterAtIndex:i];
  1165. if (c == '\n') {
  1166. for (NSUInteger j = 0; j < indent; j++) {
  1167. [desc insertString:@" " atIndex:i + 1];
  1168. }
  1169. i += indent * 4;
  1170. max += indent * 4;
  1171. }
  1172. }
  1173. return desc;
  1174. }
  1175. /// Generaate a description string
  1176. static NSString *ModelDescription(NSObject *model) {
  1177. static const int kDescMaxLength = 100;
  1178. if (!model) return @"<nil>";
  1179. if (model == (id)kCFNull) return @"<null>";
  1180. if (![model isKindOfClass:[NSObject class]]) return [NSString stringWithFormat:@"%@",model];
  1181. _DKModelMeta *modelMeta = [_DKModelMeta metaWithClass:model.class];
  1182. switch (modelMeta->_nsType) {
  1183. case DKEncodingTypeNSString: case DKEncodingTypeNSMutableString: {
  1184. return [NSString stringWithFormat:@"\"%@\"",model];
  1185. }
  1186. case DKEncodingTypeNSValue:
  1187. case DKEncodingTypeNSData: case DKEncodingTypeNSMutableData: {
  1188. NSString *tmp = model.description;
  1189. if (tmp.length > kDescMaxLength) {
  1190. tmp = [tmp substringToIndex:kDescMaxLength];
  1191. tmp = [tmp stringByAppendingString:@"..."];
  1192. }
  1193. return tmp;
  1194. }
  1195. case DKEncodingTypeNSNumber:
  1196. case DKEncodingTypeNSDecimalNumber:
  1197. case DKEncodingTypeNSDate:
  1198. case DKEncodingTypeNSURL: {
  1199. return [NSString stringWithFormat:@"%@",model];
  1200. }
  1201. case DKEncodingTypeNSSet: case DKEncodingTypeNSMutableSet: {
  1202. model = ((NSSet *)model).allObjects;
  1203. } // no break
  1204. case DKEncodingTypeNSArray: case DKEncodingTypeNSMutableArray: {
  1205. NSArray *array = (id)model;
  1206. NSMutableString *desc = [NSMutableString new];
  1207. if (array.count == 0) {
  1208. return [desc stringByAppendingString:@"[]"];
  1209. } else {
  1210. [desc appendFormat:@"[\n"];
  1211. for (NSUInteger i = 0, max = array.count; i < max; i++) {
  1212. NSObject *obj = array[i];
  1213. [desc appendString:@" "];
  1214. [desc appendString:ModelDescriptionAddIndent(ModelDescription(obj).mutableCopy, 1)];
  1215. [desc appendString:(i + 1 == max) ? @"\n" : @";\n"];
  1216. }
  1217. [desc appendString:@"]"];
  1218. return desc;
  1219. }
  1220. }
  1221. case DKEncodingTypeNSDictionary: case DKEncodingTypeNSMutableDictionary: {
  1222. NSDictionary *dic = (id)model;
  1223. NSMutableString *desc = [NSMutableString new];
  1224. if (dic.count == 0) {
  1225. return [desc stringByAppendingString:@"{}"];
  1226. } else {
  1227. NSArray *keys = dic.allKeys;
  1228. [desc appendFormat:@"{\n"];
  1229. for (NSUInteger i = 0, max = keys.count; i < max; i++) {
  1230. NSString *key = keys[i];
  1231. NSObject *value = dic[key];
  1232. [desc appendString:@" "];
  1233. [desc appendFormat:@"%@ = %@",key, ModelDescriptionAddIndent(ModelDescription(value).mutableCopy, 1)];
  1234. [desc appendString:(i + 1 == max) ? @"\n" : @";\n"];
  1235. }
  1236. [desc appendString:@"}"];
  1237. }
  1238. return desc;
  1239. }
  1240. default: {
  1241. NSMutableString *desc = [NSMutableString new];
  1242. [desc appendFormat:@"<%@: %p>", model.class, model];
  1243. if (modelMeta->_allPropertyMetas.count == 0) return desc;
  1244. // sort property names
  1245. NSArray *properties = [modelMeta->_allPropertyMetas
  1246. sortedArrayUsingComparator:^NSComparisonResult(_DKModelPropertyMeta *p1, _DKModelPropertyMeta *p2) {
  1247. return [p1->_name compare:p2->_name];
  1248. }];
  1249. [desc appendFormat:@" {\n"];
  1250. for (NSUInteger i = 0, max = properties.count; i < max; i++) {
  1251. _DKModelPropertyMeta *property = properties[i];
  1252. NSString *propertyDesc;
  1253. if (property->_isCNumber) {
  1254. NSNumber *num = ModelCreateNumberFromProperty(model, property);
  1255. propertyDesc = num.stringValue;
  1256. } else {
  1257. switch (property->_type & DKEncodingTypeMask) {
  1258. case DKEncodingTypeObject: {
  1259. id v = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, property->_getter);
  1260. propertyDesc = ModelDescription(v);
  1261. if (!propertyDesc) propertyDesc = @"<nil>";
  1262. } break;
  1263. case DKEncodingTypeClass: {
  1264. id v = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, property->_getter);
  1265. propertyDesc = ((NSObject *)v).description;
  1266. if (!propertyDesc) propertyDesc = @"<nil>";
  1267. } break;
  1268. case DKEncodingTypeSEL: {
  1269. SEL sel = ((SEL (*)(id, SEL))(void *) objc_msgSend)((id)model, property->_getter);
  1270. if (sel) propertyDesc = NSStringFromSelector(sel);
  1271. else propertyDesc = @"<NULL>";
  1272. } break;
  1273. case DKEncodingTypeBlock: {
  1274. id block = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, property->_getter);
  1275. propertyDesc = block ? ((NSObject *)block).description : @"<nil>";
  1276. } break;
  1277. case DKEncodingTypeCArray: case DKEncodingTypeCString: case DKEncodingTypePointer: {
  1278. void *pointer = ((void* (*)(id, SEL))(void *) objc_msgSend)((id)model, property->_getter);
  1279. propertyDesc = [NSString stringWithFormat:@"%p",pointer];
  1280. } break;
  1281. case DKEncodingTypeStruct: case DKEncodingTypeUnion: {
  1282. NSValue *value = [model valueForKey:property->_name];
  1283. propertyDesc = value ? value.description : @"{unknown}";
  1284. } break;
  1285. default: propertyDesc = @"<unknown>";
  1286. }
  1287. }
  1288. propertyDesc = ModelDescriptionAddIndent(propertyDesc.mutableCopy, 1);
  1289. [desc appendFormat:@" %@ = %@",property->_name, propertyDesc];
  1290. [desc appendString:(i + 1 == max) ? @"\n" : @";\n"];
  1291. }
  1292. [desc appendFormat:@"}"];
  1293. return desc;
  1294. }
  1295. }
  1296. }
  1297. @implementation NSObject (DKModel)
  1298. + (NSDictionary *)_dk_dictionaryWithJSON:(id)json {
  1299. if (!json || json == (id)kCFNull) return nil;
  1300. NSDictionary *dic = nil;
  1301. NSData *jsonData = nil;
  1302. if ([json isKindOfClass:[NSDictionary class]]) {
  1303. dic = json;
  1304. } else if ([json isKindOfClass:[NSString class]]) {
  1305. jsonData = [(NSString *)json dataUsingEncoding : NSUTF8StringEncoding];
  1306. } else if ([json isKindOfClass:[NSData class]]) {
  1307. jsonData = json;
  1308. }
  1309. if (jsonData) {
  1310. dic = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:NULL];
  1311. if (![dic isKindOfClass:[NSDictionary class]]) dic = nil;
  1312. }
  1313. return dic;
  1314. }
  1315. + (instancetype)dk_modelWithJSON:(id)json {
  1316. NSDictionary *dic = [self _dk_dictionaryWithJSON:json];
  1317. return [self dk_modelWithDictionary:dic];
  1318. }
  1319. + (instancetype)dk_modelWithDictionary:(NSDictionary *)dictionary {
  1320. if (!dictionary || dictionary == (id)kCFNull) return nil;
  1321. if (![dictionary isKindOfClass:[NSDictionary class]]) return nil;
  1322. Class cls = [self class];
  1323. _DKModelMeta *modelMeta = [_DKModelMeta metaWithClass:cls];
  1324. if (modelMeta->_hasCustomClassFromDictionary) {
  1325. cls = [cls modelCustomClassForDictionary:dictionary] ?: cls;
  1326. }
  1327. NSObject *one = [cls new];
  1328. if ([one dk_modelSetWithDictionary:dictionary]) return one;
  1329. return nil;
  1330. }
  1331. - (BOOL)dk_modelSetWithJSON:(id)json {
  1332. NSDictionary *dic = [NSObject _dk_dictionaryWithJSON:json];
  1333. return [self dk_modelSetWithDictionary:dic];
  1334. }
  1335. - (BOOL)dk_modelSetWithDictionary:(NSDictionary *)dic {
  1336. if (!dic || dic == (id)kCFNull) return NO;
  1337. if (![dic isKindOfClass:[NSDictionary class]]) return NO;
  1338. _DKModelMeta *modelMeta = [_DKModelMeta metaWithClass:object_getClass(self)];
  1339. if (modelMeta->_keyMappedCount == 0) return NO;
  1340. if (modelMeta->_hasCustomWillTransformFromDictionary) {
  1341. dic = [((id<DKModel>)self) modelCustomWillTransformFromDictionary:dic];
  1342. if (![dic isKindOfClass:[NSDictionary class]]) return NO;
  1343. }
  1344. ModelSetContext context = {0};
  1345. context.modelMeta = (__bridge void *)(modelMeta);
  1346. context.model = (__bridge void *)(self);
  1347. context.dictionary = (__bridge void *)(dic);
  1348. if (modelMeta->_keyMappedCount >= CFDictionaryGetCount((CFDictionaryRef)dic)) {
  1349. CFDictionaryApplyFunction((CFDictionaryRef)dic, ModelSetWithDictionaryFunction, &context);
  1350. if (modelMeta->_keyPathPropertyMetas) {
  1351. CFArrayApplyFunction((CFArrayRef)modelMeta->_keyPathPropertyMetas,
  1352. CFRangeMake(0, CFArrayGetCount((CFArrayRef)modelMeta->_keyPathPropertyMetas)),
  1353. ModelSetWithPropertyMetaArrayFunction,
  1354. &context);
  1355. }
  1356. if (modelMeta->_multiKeysPropertyMetas) {
  1357. CFArrayApplyFunction((CFArrayRef)modelMeta->_multiKeysPropertyMetas,
  1358. CFRangeMake(0, CFArrayGetCount((CFArrayRef)modelMeta->_multiKeysPropertyMetas)),
  1359. ModelSetWithPropertyMetaArrayFunction,
  1360. &context);
  1361. }
  1362. } else {
  1363. CFArrayApplyFunction((CFArrayRef)modelMeta->_allPropertyMetas,
  1364. CFRangeMake(0, modelMeta->_keyMappedCount),
  1365. ModelSetWithPropertyMetaArrayFunction,
  1366. &context);
  1367. }
  1368. if (modelMeta->_hasCustomTransformFromDictionary) {
  1369. return [((id<DKModel>)self) modelCustomTransformFromDictionary:dic];
  1370. }
  1371. return YES;
  1372. }
  1373. - (id)dk_modelToJSONObject {
  1374. /*
  1375. Apple said:
  1376. The top level object is an NSArray or NSDictionary.
  1377. All objects are instances of NSString, NSNumber, NSArray, NSDictionary, or NSNull.
  1378. All dictionary keys are instances of NSString.
  1379. Numbers are not NaN or infinity.
  1380. */
  1381. id jsonObject = ModelToJSONObjectRecursive(self);
  1382. if ([jsonObject isKindOfClass:[NSArray class]]) return jsonObject;
  1383. if ([jsonObject isKindOfClass:[NSDictionary class]]) return jsonObject;
  1384. return nil;
  1385. }
  1386. - (NSData *)dk_modelToJSONData {
  1387. id jsonObject = [self dk_modelToJSONObject];
  1388. if (!jsonObject) return nil;
  1389. return [NSJSONSerialization dataWithJSONObject:jsonObject options:0 error:NULL];
  1390. }
  1391. - (NSString *)dk_modelToJSONString {
  1392. NSData *jsonData = [self dk_modelToJSONData];
  1393. if (jsonData.length == 0) return nil;
  1394. return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
  1395. }
  1396. - (id)dk_modelCopy{
  1397. if (self == (id)kCFNull) return self;
  1398. _DKModelMeta *modelMeta = [_DKModelMeta metaWithClass:self.class];
  1399. if (modelMeta->_nsType) return [self copy];
  1400. NSObject *one = [self.class new];
  1401. for (_DKModelPropertyMeta *propertyMeta in modelMeta->_allPropertyMetas) {
  1402. if (!propertyMeta->_getter || !propertyMeta->_setter) continue;
  1403. if (propertyMeta->_isCNumber) {
  1404. switch (propertyMeta->_type & DKEncodingTypeMask) {
  1405. case DKEncodingTypeBool: {
  1406. bool num = ((bool (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
  1407. ((void (*)(id, SEL, bool))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
  1408. } break;
  1409. case DKEncodingTypeInt8:
  1410. case DKEncodingTypeUInt8: {
  1411. uint8_t num = ((bool (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
  1412. ((void (*)(id, SEL, uint8_t))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
  1413. } break;
  1414. case DKEncodingTypeInt16:
  1415. case DKEncodingTypeUInt16: {
  1416. uint16_t num = ((uint16_t (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
  1417. ((void (*)(id, SEL, uint16_t))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
  1418. } break;
  1419. case DKEncodingTypeInt32:
  1420. case DKEncodingTypeUInt32: {
  1421. uint32_t num = ((uint32_t (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
  1422. ((void (*)(id, SEL, uint32_t))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
  1423. } break;
  1424. case DKEncodingTypeInt64:
  1425. case DKEncodingTypeUInt64: {
  1426. uint64_t num = ((uint64_t (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
  1427. ((void (*)(id, SEL, uint64_t))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
  1428. } break;
  1429. case DKEncodingTypeFloat: {
  1430. float num = ((float (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
  1431. ((void (*)(id, SEL, float))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
  1432. } break;
  1433. case DKEncodingTypeDouble: {
  1434. double num = ((double (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
  1435. ((void (*)(id, SEL, double))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
  1436. } break;
  1437. case DKEncodingTypeLongDouble: {
  1438. long double num = ((long double (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
  1439. ((void (*)(id, SEL, long double))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
  1440. } // break; commented for code coverage in next line
  1441. default: break;
  1442. }
  1443. } else {
  1444. switch (propertyMeta->_type & DKEncodingTypeMask) {
  1445. case DKEncodingTypeObject:
  1446. case DKEncodingTypeClass:
  1447. case DKEncodingTypeBlock: {
  1448. id value = ((id (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
  1449. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)one, propertyMeta->_setter, value);
  1450. } break;
  1451. case DKEncodingTypeSEL:
  1452. case DKEncodingTypePointer:
  1453. case DKEncodingTypeCString: {
  1454. size_t value = ((size_t (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
  1455. ((void (*)(id, SEL, size_t))(void *) objc_msgSend)((id)one, propertyMeta->_setter, value);
  1456. } break;
  1457. case DKEncodingTypeStruct:
  1458. case DKEncodingTypeUnion: {
  1459. @try {
  1460. NSValue *value = [self valueForKey:NSStringFromSelector(propertyMeta->_getter)];
  1461. if (value) {
  1462. [one setValue:value forKey:propertyMeta->_name];
  1463. }
  1464. } @catch (NSException *exception) {}
  1465. } // break; commented for code coverage in next line
  1466. default: break;
  1467. }
  1468. }
  1469. }
  1470. return one;
  1471. }
  1472. - (void)dk_modelEncodeWithCoder:(NSCoder *)aCoder {
  1473. if (!aCoder) return;
  1474. if (self == (id)kCFNull) {
  1475. [((id<NSCoding>)self)encodeWithCoder:aCoder];
  1476. return;
  1477. }
  1478. _DKModelMeta *modelMeta = [_DKModelMeta metaWithClass:self.class];
  1479. if (modelMeta->_nsType) {
  1480. [((id<NSCoding>)self)encodeWithCoder:aCoder];
  1481. return;
  1482. }
  1483. for (_DKModelPropertyMeta *propertyMeta in modelMeta->_allPropertyMetas) {
  1484. if (!propertyMeta->_getter) return;
  1485. if (propertyMeta->_isCNumber) {
  1486. NSNumber *value = ModelCreateNumberFromProperty(self, propertyMeta);
  1487. if (value) [aCoder encodeObject:value forKey:propertyMeta->_name];
  1488. } else {
  1489. switch (propertyMeta->_type & DKEncodingTypeMask) {
  1490. case DKEncodingTypeObject: {
  1491. id value = ((id (*)(id, SEL))(void *)objc_msgSend)((id)self, propertyMeta->_getter);
  1492. if (value && (propertyMeta->_nsType || [value respondsToSelector:@selector(encodeWithCoder:)])) {
  1493. if ([value isKindOfClass:[NSValue class]]) {
  1494. if ([value isKindOfClass:[NSNumber class]]) {
  1495. [aCoder encodeObject:value forKey:propertyMeta->_name];
  1496. }
  1497. } else {
  1498. [aCoder encodeObject:value forKey:propertyMeta->_name];
  1499. }
  1500. }
  1501. } break;
  1502. case DKEncodingTypeSEL: {
  1503. SEL value = ((SEL (*)(id, SEL))(void *)objc_msgSend)((id)self, propertyMeta->_getter);
  1504. if (value) {
  1505. NSString *str = NSStringFromSelector(value);
  1506. [aCoder encodeObject:str forKey:propertyMeta->_name];
  1507. }
  1508. } break;
  1509. case DKEncodingTypeStruct:
  1510. case DKEncodingTypeUnion: {
  1511. if (propertyMeta->_isKVCCompatible && propertyMeta->_isStructAvailableForKeyedArchiver) {
  1512. @try {
  1513. NSValue *value = [self valueForKey:NSStringFromSelector(propertyMeta->_getter)];
  1514. [aCoder encodeObject:value forKey:propertyMeta->_name];
  1515. } @catch (NSException *exception) {}
  1516. }
  1517. } break;
  1518. default:
  1519. break;
  1520. }
  1521. }
  1522. }
  1523. }
  1524. - (id)dk_modelInitWithCoder:(NSCoder *)aDecoder {
  1525. if (!aDecoder) return self;
  1526. if (self == (id)kCFNull) return self;
  1527. _DKModelMeta *modelMeta = [_DKModelMeta metaWithClass:self.class];
  1528. if (modelMeta->_nsType) return self;
  1529. for (_DKModelPropertyMeta *propertyMeta in modelMeta->_allPropertyMetas) {
  1530. if (!propertyMeta->_setter) continue;
  1531. if (propertyMeta->_isCNumber) {
  1532. NSNumber *value = [aDecoder decodeObjectForKey:propertyMeta->_name];
  1533. if ([value isKindOfClass:[NSNumber class]]) {
  1534. ModelSetNumberToProperty(self, value, propertyMeta);
  1535. [value class];
  1536. }
  1537. } else {
  1538. DKEncodingType type = propertyMeta->_type & DKEncodingTypeMask;
  1539. switch (type) {
  1540. case DKEncodingTypeObject: {
  1541. id value = [aDecoder decodeObjectForKey:propertyMeta->_name];
  1542. ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)self, propertyMeta->_setter, value);
  1543. } break;
  1544. case DKEncodingTypeSEL: {
  1545. NSString *str = [aDecoder decodeObjectForKey:propertyMeta->_name];
  1546. if ([str isKindOfClass:[NSString class]]) {
  1547. SEL sel = NSSelectorFromString(str);
  1548. ((void (*)(id, SEL, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_setter, sel);
  1549. }
  1550. } break;
  1551. case DKEncodingTypeStruct:
  1552. case DKEncodingTypeUnion: {
  1553. if (propertyMeta->_isKVCCompatible) {
  1554. @try {
  1555. NSValue *value = [aDecoder decodeObjectForKey:propertyMeta->_name];
  1556. if (value) [self setValue:value forKey:propertyMeta->_name];
  1557. } @catch (NSException *exception) {}
  1558. }
  1559. } break;
  1560. default:
  1561. break;
  1562. }
  1563. }
  1564. }
  1565. return self;
  1566. }
  1567. - (NSUInteger)dk_modelHash {
  1568. if (self == (id)kCFNull) return [self hash];
  1569. _DKModelMeta *modelMeta = [_DKModelMeta metaWithClass:self.class];
  1570. if (modelMeta->_nsType) return [self hash];
  1571. NSUInteger value = 0;
  1572. NSUInteger count = 0;
  1573. for (_DKModelPropertyMeta *propertyMeta in modelMeta->_allPropertyMetas) {
  1574. if (!propertyMeta->_isKVCCompatible) continue;
  1575. value ^= [[self valueForKey:NSStringFromSelector(propertyMeta->_getter)] hash];
  1576. count++;
  1577. }
  1578. if (count == 0) value = (long)((__bridge void *)self);
  1579. return value;
  1580. }
  1581. - (BOOL)dk_modelIsEqual:(id)model {
  1582. if (self == model) return YES;
  1583. if (![model isMemberOfClass:self.class]) return NO;
  1584. _DKModelMeta *modelMeta = [_DKModelMeta metaWithClass:self.class];
  1585. if (modelMeta->_nsType) return [self isEqual:model];
  1586. if ([self hash] != [model hash]) return NO;
  1587. for (_DKModelPropertyMeta *propertyMeta in modelMeta->_allPropertyMetas) {
  1588. if (!propertyMeta->_isKVCCompatible) continue;
  1589. id this = [self valueForKey:NSStringFromSelector(propertyMeta->_getter)];
  1590. id that = [model valueForKey:NSStringFromSelector(propertyMeta->_getter)];
  1591. if (this == that) continue;
  1592. if (this == nil || that == nil) return NO;
  1593. if (![this isEqual:that]) return NO;
  1594. }
  1595. return YES;
  1596. }
  1597. - (NSString *)dk_modelDescription {
  1598. return ModelDescription(self);
  1599. }
  1600. @end
  1601. @implementation NSArray (DKModel)
  1602. + (NSArray *)dk_modelArrayWithClass:(Class)cls json:(id)json {
  1603. if (!json) return nil;
  1604. NSArray *arr = nil;
  1605. NSData *jsonData = nil;
  1606. if ([json isKindOfClass:[NSArray class]]) {
  1607. arr = json;
  1608. } else if ([json isKindOfClass:[NSString class]]) {
  1609. jsonData = [(NSString *)json dataUsingEncoding : NSUTF8StringEncoding];
  1610. } else if ([json isKindOfClass:[NSData class]]) {
  1611. jsonData = json;
  1612. }
  1613. if (jsonData) {
  1614. arr = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:NULL];
  1615. if (![arr isKindOfClass:[NSArray class]]) arr = nil;
  1616. }
  1617. return [self dk_modelArrayWithClass:cls array:arr];
  1618. }
  1619. + (NSArray *)dk_modelArrayWithClass:(Class)cls array:(NSArray *)arr {
  1620. if (!cls || !arr) return nil;
  1621. NSMutableArray *result = [[NSMutableArray alloc]init];
  1622. for (NSDictionary *dic in arr) {
  1623. if (![dic isKindOfClass:[NSDictionary class]]) continue;
  1624. NSObject *obj = [cls dk_modelWithDictionary:dic];
  1625. if (obj) [result addObject:obj];
  1626. }
  1627. return result;
  1628. }
  1629. @end
  1630. @implementation NSDictionary (DKModel)
  1631. + (NSDictionary *)dk_modelDictionaryWithClass:(Class)cls json:(id)json {
  1632. if (!json) return nil;
  1633. NSDictionary *dic = nil;
  1634. NSData *jsonData = nil;
  1635. if ([json isKindOfClass:[NSDictionary class]]) {
  1636. dic = json;
  1637. } else if ([json isKindOfClass:[NSString class]]) {
  1638. jsonData = [(NSString *)json dataUsingEncoding : NSUTF8StringEncoding];
  1639. } else if ([json isKindOfClass:[NSData class]]) {
  1640. jsonData = json;
  1641. }
  1642. if (jsonData) {
  1643. dic = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:NULL];
  1644. if (![dic isKindOfClass:[NSDictionary class]]) dic = nil;
  1645. }
  1646. return [self dk_modelDictionaryWithClass:cls dictionary:dic];
  1647. }
  1648. + (NSDictionary *)dk_modelDictionaryWithClass:(Class)cls dictionary:(NSDictionary *)dic {
  1649. if (!cls || !dic) return nil;
  1650. NSMutableDictionary *result = [NSMutableDictionary new];
  1651. for (NSString *key in dic.allKeys) {
  1652. if (![key isKindOfClass:[NSString class]]) continue;
  1653. NSObject *obj = [cls dk_modelWithDictionary:dic[key]];
  1654. if (obj) result[key] = obj;
  1655. }
  1656. return result;
  1657. }
  1658. @end