ViewController.m 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869
  1. //
  2. // ViewController.m
  3. // ModelBenchmark
  4. //
  5. // Created by ibireme on 15/9/18.
  6. // Copyright (c) 2015 ibireme. All rights reserved.
  7. //
  8. #import <QuartzCore/QuartzCore.h>
  9. #import "ViewController.h"
  10. #import "DateFormatter.h"
  11. #import "GitHubUser.h"
  12. #import "YYWeiboModel.h"
  13. #import "FEWeiboModel.h"
  14. #import "MTWeiboModel.h"
  15. #import "JSWeiboModel.h"
  16. #import "MJWeiboModel.h"
  17. #import "ModelBenchmark-Swift.h"
  18. @implementation ViewController
  19. - (void)viewDidLoad {
  20. [super viewDidLoad];
  21. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  22. [self benchmarkGithubUser];
  23. [self benchmarkWeiboStatus];
  24. [self testRobustness];
  25. });
  26. }
  27. - (void)benchmarkGithubUser {
  28. printf("----------------------\n");
  29. printf("Benchmark (10000 times):\n");
  30. printf("GHUser from json to json archive\n");
  31. /// get json data
  32. NSString *path = [[NSBundle mainBundle] pathForResource:@"user" ofType:@"json"];
  33. NSData *data = [NSData dataWithContentsOfFile:path];
  34. NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
  35. /// Benchmark
  36. int count = 10000;
  37. NSTimeInterval begin, end;
  38. /// warm up (NSDictionary's hot cache, and JSON to model framework cache)
  39. FEMMapping *mapping = [FEGHUser defaultMapping];
  40. MTLJSONAdapter *adapter = [[MTLJSONAdapter alloc] initWithModelClass:[MTGHUser class]];
  41. @autoreleasepool {
  42. for (int i = 0; i < count; i++) {
  43. // Manually
  44. [[[[GHUser alloc] initWithJSONDictionary:json] description] length];
  45. // YYModel
  46. [YYGHUser yy_modelWithJSON:json];
  47. // FastEasyMapping
  48. [FEMDeserializer fillObject:[FEGHUser new] fromRepresentation:json mapping:mapping];
  49. // JSONModel
  50. [[[[JSGHUser alloc] initWithDictionary:json error:nil] description] length];
  51. // Mantle
  52. [adapter modelFromJSONDictionary:json error:nil];
  53. // MJExtension
  54. [MJGHUser mj_objectWithKeyValues:json];
  55. }
  56. }
  57. /// warm up holder
  58. NSMutableArray *holder = [NSMutableArray new];
  59. for (int i = 0; i < 1800; i++) {
  60. [holder addObject:[NSDate new]];
  61. }
  62. [holder removeAllObjects];
  63. /*------------------- JSON Serialization -------------------*/
  64. {
  65. [holder removeAllObjects];
  66. begin = CACurrentMediaTime();
  67. @autoreleasepool {
  68. for (int i = 0; i < count; i++) {
  69. NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
  70. [holder addObject:json];
  71. }
  72. }
  73. end = CACurrentMediaTime();
  74. printf("JSON(*): %8.2f ", (end - begin) * 1000);
  75. [holder removeAllObjects];
  76. begin = CACurrentMediaTime();
  77. @autoreleasepool {
  78. for (int i = 0; i < count; i++) {
  79. NSData *data = [NSJSONSerialization dataWithJSONObject:json options:kNilOptions error:nil];
  80. [holder addObject:json];
  81. }
  82. }
  83. end = CACurrentMediaTime();
  84. printf("%8.2f \n", (end - begin) * 1000);
  85. }
  86. /*------------------- Manually -------------------*/
  87. {
  88. [holder removeAllObjects];
  89. begin = CACurrentMediaTime();
  90. @autoreleasepool {
  91. for (int i = 0; i < count; i++) {
  92. GHUser *user = [[GHUser alloc] initWithJSONDictionary:json];
  93. [holder addObject:user];
  94. }
  95. }
  96. end = CACurrentMediaTime();
  97. printf("Manually(#): %8.2f ", (end - begin) * 1000);
  98. GHUser *user = [[GHUser alloc] initWithJSONDictionary:json];
  99. if (user.userID == 0) NSLog(@"error!");
  100. if (!user.login) NSLog(@"error!");
  101. if (!user.htmlURL) NSLog(@"error");
  102. [holder removeAllObjects];
  103. begin = CACurrentMediaTime();
  104. @autoreleasepool {
  105. for (int i = 0; i < count; i++) {
  106. NSDictionary *json = [user convertToJSONDictionary];
  107. [holder addObject:json];
  108. }
  109. }
  110. end = CACurrentMediaTime();
  111. if ([NSJSONSerialization isValidJSONObject:[user convertToJSONDictionary]]) {
  112. printf("%8.2f ", (end - begin) * 1000);
  113. } else {
  114. printf(" error ");
  115. }
  116. [holder removeAllObjects];
  117. begin = CACurrentMediaTime();
  118. @autoreleasepool {
  119. for (int i = 0; i < count; i++) {
  120. NSData *data = [NSKeyedArchiver archivedDataWithRootObject:user];
  121. [holder addObject:data];
  122. }
  123. }
  124. end = CACurrentMediaTime();
  125. printf("%8.2f\n", (end - begin) * 1000);
  126. }
  127. /*------------------- YYModel -------------------*/
  128. {
  129. [holder removeAllObjects];
  130. begin = CACurrentMediaTime();
  131. @autoreleasepool {
  132. for (int i = 0; i < count; i++) {
  133. YYGHUser *user = [YYGHUser yy_modelWithJSON:json];
  134. [holder addObject:user];
  135. }
  136. }
  137. end = CACurrentMediaTime();
  138. printf("YYModel(#): %8.2f ", (end - begin) * 1000);
  139. YYGHUser *user = [YYGHUser yy_modelWithJSON:json];
  140. if (user.userID == 0) NSLog(@"error!");
  141. if (!user.login) NSLog(@"error!");
  142. if (!user.htmlURL) NSLog(@"error");
  143. [holder removeAllObjects];
  144. begin = CACurrentMediaTime();
  145. @autoreleasepool {
  146. for (int i = 0; i < count; i++) {
  147. NSDictionary *json = [user yy_modelToJSONObject];
  148. [holder addObject:json];
  149. }
  150. }
  151. end = CACurrentMediaTime();
  152. if ([NSJSONSerialization isValidJSONObject:[user yy_modelToJSONObject]]) {
  153. printf("%8.2f ", (end - begin) * 1000);
  154. } else {
  155. printf(" error ");
  156. }
  157. [holder removeAllObjects];
  158. begin = CACurrentMediaTime();
  159. @autoreleasepool {
  160. for (int i = 0; i < count; i++) {
  161. NSData *data = [NSKeyedArchiver archivedDataWithRootObject:user];
  162. [holder addObject:data];
  163. }
  164. }
  165. end = CACurrentMediaTime();
  166. printf("%8.2f\n", (end - begin) * 1000);
  167. }
  168. /*------------------- FastEasyMapping -------------------*/
  169. {
  170. [holder removeAllObjects];
  171. begin = CACurrentMediaTime();
  172. @autoreleasepool {
  173. for (int i = 0; i < count; i++) {
  174. FEGHUser *user = [FEGHUser new];
  175. [FEMDeserializer fillObject:user fromRepresentation:json mapping:mapping];
  176. [user class];
  177. }
  178. }
  179. end = CACurrentMediaTime();
  180. printf("FastEasyMapping(#): %8.2f ", (end - begin) * 1000);
  181. FEGHUser *user = [FEGHUser new];
  182. [FEMDeserializer fillObject:user fromRepresentation:json mapping:mapping];
  183. if (user.userID == 0) NSLog(@"error!");
  184. if (!user.login) NSLog(@"error!");
  185. if (!user.htmlURL) NSLog(@"error");
  186. [holder removeAllObjects];
  187. begin = CACurrentMediaTime();
  188. @autoreleasepool {
  189. for (int i = 0; i < count; i++) {
  190. NSDictionary *json = [FEMSerializer serializeObject:user usingMapping:mapping];
  191. [holder addObject:json];
  192. }
  193. }
  194. end = CACurrentMediaTime();
  195. if ([NSJSONSerialization isValidJSONObject: [FEMSerializer serializeObject:user usingMapping:mapping]]) {
  196. printf("%8.2f ", (end - begin) * 1000);
  197. } else {
  198. printf(" error ");
  199. }
  200. // FastEasyMapping does not support NSCoding?
  201. printf(" N/A\n");
  202. }
  203. /*------------------- JSONModel -------------------*/
  204. {
  205. NSError *jsErr = nil;
  206. [holder removeAllObjects];
  207. begin = CACurrentMediaTime();
  208. @autoreleasepool {
  209. for (int i = 0; i < count; i++) {
  210. JSGHUser *user = [[JSGHUser alloc] initWithDictionary:json error:&jsErr];
  211. [user class];
  212. }
  213. }
  214. end = CACurrentMediaTime();
  215. printf("JSONModel(#): %8.2f ", (end - begin) * 1000);
  216. JSGHUser *user = [[JSGHUser alloc] initWithDictionary:json error:&jsErr];
  217. if (user.userID == 0) NSLog(@"error!");
  218. if (!user.login) NSLog(@"error!");
  219. if (!user.htmlURL) NSLog(@"error");
  220. [holder removeAllObjects];
  221. begin = CACurrentMediaTime();
  222. @autoreleasepool {
  223. for (int i = 0; i < count; i++) {
  224. NSDictionary *json = [user toDictionary];
  225. [holder addObject:json];
  226. }
  227. }
  228. end = CACurrentMediaTime();
  229. if ([NSJSONSerialization isValidJSONObject:[user toDictionary]]) {
  230. printf("%8.2f ", (end - begin) * 1000);
  231. } else {
  232. printf(" error ");
  233. }
  234. [holder removeAllObjects];
  235. begin = CACurrentMediaTime();
  236. @autoreleasepool {
  237. for (int i = 0; i < count; i++) {
  238. NSData *data = [NSKeyedArchiver archivedDataWithRootObject:user];
  239. [holder addObject:data];
  240. }
  241. }
  242. end = CACurrentMediaTime();
  243. printf("%8.2f\n", (end - begin) * 1000);
  244. }
  245. /*------------------- Mantle -------------------*/
  246. {
  247. [holder removeAllObjects];
  248. begin = CACurrentMediaTime();
  249. @autoreleasepool {
  250. for (int i = 0; i < count; i++) {
  251. MTGHUser *user = [adapter modelFromJSONDictionary:json error:nil];
  252. [user class];
  253. }
  254. }
  255. end = CACurrentMediaTime();
  256. printf("Mantle(#): %8.2f ", (end - begin) * 1000);
  257. MTGHUser *user = [adapter modelFromJSONDictionary:json error:nil];
  258. if (user.userID == 0) NSLog(@"error!");
  259. if (!user.login) NSLog(@"error!");
  260. if (!user.htmlURL) NSLog(@"error");
  261. [holder removeAllObjects];
  262. begin = CACurrentMediaTime();
  263. @autoreleasepool {
  264. for (int i = 0; i < count; i++) {
  265. NSDictionary *json = [adapter JSONDictionaryFromModel:user error:nil];
  266. [holder addObject:json];
  267. }
  268. }
  269. end = CACurrentMediaTime();
  270. if ([NSJSONSerialization isValidJSONObject:[adapter JSONDictionaryFromModel:user error:nil]]) {
  271. printf("%8.2f ", (end - begin) * 1000);
  272. } else {
  273. printf(" error ");
  274. }
  275. [holder removeAllObjects];
  276. begin = CACurrentMediaTime();
  277. @autoreleasepool {
  278. for (int i = 0; i < count; i++) {
  279. NSData *data = [NSKeyedArchiver archivedDataWithRootObject:user];
  280. [holder addObject:data];
  281. }
  282. }
  283. end = CACurrentMediaTime();
  284. printf("%8.2f\n", (end - begin) * 1000);
  285. }
  286. /*------------------- MJExtension -------------------*/
  287. {
  288. [holder removeAllObjects];
  289. begin = CACurrentMediaTime();
  290. @autoreleasepool {
  291. for (int i = 0; i < count; i++) {
  292. MJGHUser *user = [MJGHUser mj_objectWithKeyValues:json];
  293. [user class];
  294. }
  295. }
  296. end = CACurrentMediaTime();
  297. printf("MJExtension(#): %8.2f ", (end - begin) * 1000);
  298. MJGHUser *user = [MJGHUser mj_objectWithKeyValues:json];
  299. if (user.userID == 0) NSLog(@"error!");
  300. if (!user.login) NSLog(@"error!");
  301. if (!user.htmlURL) NSLog(@"error");
  302. [holder removeAllObjects];
  303. begin = CACurrentMediaTime();
  304. @autoreleasepool {
  305. for (int i = 0; i < count; i++) {
  306. NSDictionary *json = [user mj_JSONObject];
  307. [holder addObject:json];
  308. }
  309. }
  310. end = CACurrentMediaTime();
  311. if ([NSJSONSerialization isValidJSONObject:[user mj_JSONObject]]) {
  312. printf("%8.2f ", (end - begin) * 1000);
  313. } else {
  314. printf(" error ");
  315. }
  316. [holder removeAllObjects];
  317. begin = CACurrentMediaTime();
  318. @autoreleasepool {
  319. for (int i = 0; i < count; i++) {
  320. NSData *data = [NSKeyedArchiver archivedDataWithRootObject:user];
  321. [holder addObject:data];
  322. }
  323. }
  324. end = CACurrentMediaTime();
  325. printf("%8.2f\n", (end - begin) * 1000);
  326. }
  327. /// Benchmark swift
  328. [GithubUserBenchmark benchmark];
  329. printf("----------------------\n");
  330. printf("\n");
  331. }
  332. - (void)benchmarkWeiboStatus {
  333. printf("----------------------\n");
  334. printf("Benchmark (1000 times):\n");
  335. printf("WeiboStatus from json to json archive\n");
  336. /// get json data
  337. NSString *path = [[NSBundle mainBundle] pathForResource:@"weibo" ofType:@"json"];
  338. NSData *data = [NSData dataWithContentsOfFile:path];
  339. NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
  340. /// Benchmark
  341. int count = 1000;
  342. NSTimeInterval begin, end;
  343. /// warm up (NSDictionary's hot cache, and JSON to model framework cache)
  344. FEMMapping *mapping = [FEWeiboStatus defaultMapping];
  345. MTLJSONAdapter *adapter = [[MTLJSONAdapter alloc] initWithModelClass:[MTWeiboStatus class]];
  346. @autoreleasepool {
  347. for (int i = 0; i < count * 2; i++) {
  348. // YYModel
  349. [YYWeiboStatus yy_modelWithJSON:json];
  350. // FastEasyMapping
  351. [FEMDeserializer fillObject:[FEWeiboStatus new] fromRepresentation:json mapping:mapping];
  352. // JSONModel
  353. [[[JSWeiboStatus alloc] initWithDictionary:json error:nil] description];
  354. // Mantle
  355. [adapter modelFromJSONDictionary:json error:nil];
  356. // MJExtension
  357. [MJWeiboStatus mj_objectWithKeyValues:json];
  358. }
  359. }
  360. /// warm up holder
  361. NSMutableArray *holder = [NSMutableArray new];
  362. for (int i = 0; i < count; i++) {
  363. [holder addObject:[NSData new]];
  364. }
  365. [holder removeAllObjects];
  366. /*------------------- YYModel -------------------*/
  367. {
  368. [holder removeAllObjects];
  369. begin = CACurrentMediaTime();
  370. @autoreleasepool {
  371. for (int i = 0; i < count; i++) {
  372. YYWeiboStatus *feed = [YYWeiboStatus yy_modelWithJSON:json];
  373. [holder addObject:feed];
  374. }
  375. }
  376. end = CACurrentMediaTime();
  377. printf("YYModel: %8.2f ", (end - begin) * 1000);
  378. YYWeiboStatus *feed = [YYWeiboStatus yy_modelWithJSON:json];
  379. [holder removeAllObjects];
  380. begin = CACurrentMediaTime();
  381. @autoreleasepool {
  382. for (int i = 0; i < count; i++) {
  383. NSDictionary *json = [feed yy_modelToJSONObject];
  384. [holder addObject:json];
  385. }
  386. }
  387. end = CACurrentMediaTime();
  388. if ([NSJSONSerialization isValidJSONObject:[feed yy_modelToJSONObject]]) {
  389. printf("%8.2f ", (end - begin) * 1000);
  390. } else {
  391. printf(" error ");
  392. }
  393. [holder removeAllObjects];
  394. begin = CACurrentMediaTime();
  395. @autoreleasepool {
  396. for (int i = 0; i < count; i++) {
  397. NSData *data = [NSKeyedArchiver archivedDataWithRootObject:feed];
  398. [holder addObject:data];
  399. }
  400. }
  401. end = CACurrentMediaTime();
  402. printf("%8.2f\n", (end - begin) * 1000);
  403. }
  404. /*------------------- FastEasyMapping -------------------*/
  405. {
  406. [holder removeAllObjects];
  407. begin = CACurrentMediaTime();
  408. @autoreleasepool {
  409. for (int i = 0; i < count; i++) {
  410. FEWeiboStatus *feed = [FEWeiboStatus new];
  411. [FEMDeserializer fillObject:feed fromRepresentation:json mapping:mapping];
  412. [holder addObject:feed];
  413. }
  414. }
  415. end = CACurrentMediaTime();
  416. printf("FastEasyMapping: %8.2f ", (end - begin) * 1000);
  417. FEWeiboStatus *feed = [FEWeiboStatus new];
  418. [FEMDeserializer fillObject:feed fromRepresentation:json mapping:mapping];
  419. [holder removeAllObjects];
  420. begin = CACurrentMediaTime();
  421. @autoreleasepool {
  422. for (int i = 0; i < count; i++) {
  423. NSDictionary *json = [FEMSerializer serializeObject:feed usingMapping:mapping];
  424. [holder addObject:json];
  425. }
  426. }
  427. end = CACurrentMediaTime();
  428. if ([NSJSONSerialization isValidJSONObject: [FEMSerializer serializeObject:feed usingMapping:mapping]]) {
  429. printf("%8.2f ", (end - begin) * 1000);
  430. } else {
  431. printf(" error ");
  432. }
  433. // FastEasyMapping does not support NSCoding?
  434. printf(" N/A\n");
  435. }
  436. /*------------------- JSONModel -------------------*/
  437. {
  438. [holder removeAllObjects];
  439. begin = CACurrentMediaTime();
  440. @autoreleasepool {
  441. for (int i = 0; i < count; i++) {
  442. JSWeiboStatus *feed = [[JSWeiboStatus alloc] initWithDictionary:json error:nil];
  443. [holder addObject:feed];
  444. }
  445. }
  446. end = CACurrentMediaTime();
  447. printf("JSONModel: %8.2f ", (end - begin) * 1000);
  448. JSWeiboStatus *feed = [[JSWeiboStatus alloc] initWithDictionary:json error:nil];
  449. [holder removeAllObjects];
  450. begin = CACurrentMediaTime();
  451. @autoreleasepool {
  452. for (int i = 0; i < count; i++) {
  453. NSDictionary *json = [feed toDictionary];
  454. [holder addObject:json];
  455. }
  456. }
  457. end = CACurrentMediaTime();
  458. if ([NSJSONSerialization isValidJSONObject:[feed toDictionary]]) {
  459. printf("%8.2f ", (end - begin) * 1000);
  460. } else {
  461. printf(" error ");
  462. }
  463. [holder removeAllObjects];
  464. begin = CACurrentMediaTime();
  465. @autoreleasepool {
  466. for (int i = 0; i < count; i++) {
  467. NSData *data = [NSKeyedArchiver archivedDataWithRootObject:feed];
  468. [holder addObject:data];
  469. }
  470. }
  471. end = CACurrentMediaTime();
  472. printf("%8.2f\n", (end - begin) * 1000);
  473. }
  474. /*------------------- Mantle -------------------*/
  475. {
  476. [holder removeAllObjects];
  477. begin = CACurrentMediaTime();
  478. @autoreleasepool {
  479. for (int i = 0; i < count; i++) {
  480. MTWeiboStatus *feed = [adapter modelFromJSONDictionary:json error:nil];
  481. [holder addObject:feed];
  482. }
  483. }
  484. end = CACurrentMediaTime();
  485. printf("Mantle: %8.2f ", (end - begin) * 1000);
  486. MTWeiboStatus *feed = [adapter modelFromJSONDictionary:json error:nil];
  487. [holder removeAllObjects];
  488. begin = CACurrentMediaTime();
  489. @autoreleasepool {
  490. for (int i = 0; i < count; i++) {
  491. NSDictionary *json = [adapter JSONDictionaryFromModel:feed error:nil];
  492. [holder addObject:json];
  493. }
  494. }
  495. end = CACurrentMediaTime();
  496. if ([NSJSONSerialization isValidJSONObject:[adapter JSONDictionaryFromModel:feed error:nil]]) {
  497. printf("%8.2f ", (end - begin) * 1000);
  498. } else {
  499. printf(" error ");
  500. }
  501. [holder removeAllObjects];
  502. begin = CACurrentMediaTime();
  503. @autoreleasepool {
  504. for (int i = 0; i < count; i++) {
  505. NSData *data = [NSKeyedArchiver archivedDataWithRootObject:feed];
  506. [holder addObject:data];
  507. }
  508. }
  509. end = CACurrentMediaTime();
  510. printf("%8.2f\n", (end - begin) * 1000);
  511. }
  512. /*------------------- MJExtension -------------------*/
  513. {
  514. [holder removeAllObjects];
  515. begin = CACurrentMediaTime();
  516. @autoreleasepool {
  517. for (int i = 0; i < count; i++) {
  518. MJWeiboStatus *feed = [MJWeiboStatus mj_objectWithKeyValues:json];
  519. [holder addObject:feed];
  520. }
  521. }
  522. end = CACurrentMediaTime();
  523. printf("MJExtension: %8.2f ", (end - begin) * 1000);
  524. MJWeiboStatus *feed = [MJWeiboStatus mj_objectWithKeyValues:json];
  525. [holder removeAllObjects];
  526. begin = CACurrentMediaTime();
  527. @autoreleasepool {
  528. for (int i = 0; i < count; i++) {
  529. NSDictionary *json = [feed mj_JSONObject];
  530. [holder addObject:json];
  531. }
  532. }
  533. end = CACurrentMediaTime();
  534. if ([NSJSONSerialization isValidJSONObject:[feed mj_JSONObject]]) {
  535. printf("%8.2f ", (end - begin) * 1000);
  536. } else {
  537. printf(" error ");
  538. }
  539. [holder removeAllObjects];
  540. begin = CACurrentMediaTime();
  541. @autoreleasepool {
  542. for (int i = 0; i < count; i++) {
  543. NSData *data = [NSKeyedArchiver archivedDataWithRootObject:feed];
  544. [holder addObject:data];
  545. }
  546. }
  547. end = CACurrentMediaTime();
  548. printf("%8.2f\n", (end - begin) * 1000);
  549. }
  550. printf("----------------------\n");
  551. printf("\n");
  552. }
  553. - (void)testRobustness {
  554. {
  555. printf("----------------------\n");
  556. printf("The property is NSString, but the json value is number:\n");
  557. NSString *jsonStr = @"{\"type\":1}";
  558. NSDictionary *json = [NSJSONSerialization JSONObjectWithData:[jsonStr dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil];
  559. void (^logError)(NSString *model, id user) = ^(NSString *model, id user){
  560. printf("%s ",model.UTF8String);
  561. if (!user) {
  562. printf("⚠️ model is nil\n");
  563. } else {
  564. NSString *type = ((YYGHUser *)user).type;
  565. if (type == nil || type == (id)[NSNull null]) {
  566. printf("⚠️ property is nil\n");
  567. } else if ([type isKindOfClass:[NSString class]]) {
  568. printf("✅ property is %s\n",NSStringFromClass(type.class).UTF8String);
  569. } else {
  570. printf("🚫 property is %s\n",NSStringFromClass(type.class).UTF8String);
  571. }
  572. }
  573. };
  574. // YYModel
  575. YYGHUser *yyUser = [YYGHUser yy_modelWithJSON:json];
  576. logError(@"YYModel: ", yyUser);
  577. // FastEasyMapping
  578. FEGHUser *feUser = [FEGHUser new];
  579. FEMMapping *mapping = [FEGHUser defaultMapping];
  580. [FEMDeserializer fillObject:feUser fromRepresentation:json mapping:mapping];
  581. logError(@"FastEasyMapping:", feUser);
  582. // JSONModel
  583. JSGHUser *jsUser = [[JSGHUser alloc] initWithDictionary:json error:nil];
  584. logError(@"JSONModel: ", jsUser);
  585. // Mantle
  586. MTLJSONAdapter *adapter = [[MTLJSONAdapter alloc] initWithModelClass:[MTGHUser class]];
  587. MTGHUser *mtUser = [adapter modelFromJSONDictionary:json error:nil];
  588. logError(@"Mantle: ", mtUser);
  589. // MJExtension
  590. MJGHUser *mjUser = [MJGHUser mj_objectWithKeyValues:json];
  591. logError(@"MJExtension: ", mjUser);
  592. printf("\n");
  593. }
  594. {
  595. printf("----------------------\n");
  596. printf("The property is int, but the json value is string:\n");
  597. NSString *jsonStr = @"{\"followers\":\"100\"}";
  598. NSDictionary *json = [NSJSONSerialization JSONObjectWithData:[jsonStr dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil];
  599. void (^logError)(NSString *model, id user) = ^(NSString *model, id user){
  600. printf("%s ",model.UTF8String);
  601. if (!user) {
  602. printf("⚠️ model is nil\n");
  603. } else {
  604. UInt32 num = ((YYGHUser *)user).followers;
  605. if (num != 100) {
  606. printf("🚫 property is %u\n",(unsigned int)num);
  607. } else {
  608. printf("✅ property is %u\n",(unsigned int)num);
  609. }
  610. }
  611. };
  612. // YYModel
  613. YYGHUser *yyUser = [YYGHUser yy_modelWithJSON:json];
  614. logError(@"YYModel: ", yyUser);
  615. // FastEasyMapping
  616. @try {
  617. FEGHUser *feUser = [FEGHUser new];
  618. FEMMapping *mapping = [FEGHUser defaultMapping];
  619. [FEMDeserializer fillObject:feUser fromRepresentation:json mapping:mapping];
  620. logError(@"FastEasyMapping:", feUser);
  621. }
  622. @catch (NSException *exception) {
  623. printf("FastEasyMapping: 🚫crash\n");
  624. }
  625. @try {
  626. // JSONModel
  627. JSGHUser *jsUser = [[JSGHUser alloc] initWithDictionary:json error:nil];
  628. logError(@"JSONModel: ", jsUser);
  629. }
  630. @catch (NSException *exception) {
  631. printf("JSONModel: 🚫crash\n");
  632. }
  633. // Mantle
  634. MTLJSONAdapter *adapter = [[MTLJSONAdapter alloc] initWithModelClass:[MTGHUser class]];
  635. MTGHUser *mtUser = [adapter modelFromJSONDictionary:json error:nil];
  636. logError(@"Mantle: ", mtUser);
  637. // MJExtension
  638. MJGHUser *mjUser = [MJGHUser mj_objectWithKeyValues:json];
  639. logError(@"MJExtension: ", mjUser);
  640. }
  641. {
  642. printf("----------------------\n");
  643. printf("The property is NSDate, and the json value is string:\n");
  644. NSString *jsonStr = @"{\"updated_at\":\"2009-04-02T03:35:22Z\"}";
  645. NSDictionary *json = [NSJSONSerialization JSONObjectWithData:[jsonStr dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil];
  646. void (^logError)(NSString *model, id user) = ^(NSString *model, id user){
  647. printf("%s ",model.UTF8String);
  648. if (!user) {
  649. printf("⚠️ model is nil\n");
  650. } else {
  651. NSDate *date = ((YYGHUser *)user).updatedAt;
  652. if (date == nil || date == (id)[NSNull null]) {
  653. printf("⚠️ property is nil\n");
  654. } else if ([date isKindOfClass:[NSDate class]]) {
  655. printf("✅ property is %s\n",NSStringFromClass(date.class).UTF8String);
  656. } else {
  657. printf("🚫 property is %s\n",NSStringFromClass(date.class).UTF8String);
  658. }
  659. }
  660. };
  661. // YYModel
  662. YYGHUser *yyUser = [YYGHUser yy_modelWithJSON:json];
  663. logError(@"YYModel: ", yyUser);
  664. // FastEasyMapping
  665. FEGHUser *feUser = [FEGHUser new];
  666. FEMMapping *mapping = [FEGHUser defaultMapping];
  667. [FEMDeserializer fillObject:feUser fromRepresentation:json mapping:mapping];
  668. logError(@"FastEasyMapping:", feUser);
  669. // JSONModel
  670. JSGHUser *jsUser = [[JSGHUser alloc] initWithDictionary:json error:nil];
  671. logError(@"JSONModel: ", jsUser);
  672. // Mantle
  673. MTLJSONAdapter *adapter = [[MTLJSONAdapter alloc] initWithModelClass:[MTGHUser class]];
  674. MTGHUser *mtUser = [adapter modelFromJSONDictionary:json error:nil];
  675. logError(@"Mantle: ", mtUser);
  676. // MJExtension
  677. MJGHUser *mjUser = [MJGHUser mj_objectWithKeyValues:json];
  678. logError(@"MJExtension: ", mjUser);
  679. printf("\n");
  680. }
  681. {
  682. printf("----------------------\n");
  683. printf("The property is NSValue, and the json value is string:\n");
  684. NSString *jsonStr = @"{\"test\":\"https://github.com\"}";
  685. NSDictionary *json = [NSJSONSerialization JSONObjectWithData:[jsonStr dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil];
  686. void (^logError)(NSString *model, id user) = ^(NSString *model, id user){
  687. printf("%s ",model.UTF8String);
  688. if (!user) {
  689. printf("⚠️ model is nil\n");
  690. } else {
  691. NSValue *valur = ((YYGHUser *)user).test;
  692. if (valur == nil || valur == (id)[NSNull null]) {
  693. printf("✅ property is nil\n");
  694. } else if ([valur isKindOfClass:[NSURLRequest class]]) {
  695. printf("✅ property is %s\n",NSStringFromClass(valur.class).UTF8String);
  696. } else {
  697. printf("🚫 property is %s\n",NSStringFromClass(valur.class).UTF8String);
  698. }
  699. }
  700. };
  701. // YYModel
  702. YYGHUser *yyUser = [YYGHUser yy_modelWithJSON:json];
  703. logError(@"YYModel: ", yyUser);
  704. // FastEasyMapping
  705. FEGHUser *feUser = [FEGHUser new];
  706. FEMMapping *mapping = [FEGHUser defaultMapping];
  707. [FEMDeserializer fillObject:feUser fromRepresentation:json mapping:mapping];
  708. logError(@"FastEasyMapping:", feUser);
  709. @try {
  710. // JSONModel
  711. NSError *err = nil;
  712. JSGHUser *jsUser = [[JSGHUser alloc] initWithDictionary:json error:&err];
  713. logError(@"JSONModel: ", jsUser);
  714. }
  715. @catch (NSException *exception) {
  716. printf("JSONModel: 🚫crash\n");
  717. }
  718. // Mantle
  719. MTLJSONAdapter *adapter = [[MTLJSONAdapter alloc] initWithModelClass:[MTGHUser class]];
  720. MTGHUser *mtUser = [adapter modelFromJSONDictionary:json error:nil];
  721. logError(@"Mantle: ", mtUser);
  722. // MJExtension
  723. MJGHUser *mjUser = [MJGHUser mj_objectWithKeyValues:json];
  724. logError(@"MJExtension: ", mjUser);
  725. printf("\n");
  726. }
  727. }
  728. @end