Răsfoiți Sursa

updated benchmark project and result

ibireme 9 ani în urmă
părinte
comite
4d2f1417b4
42 a modificat fișierele cu 1246 adăugiri și 703 ștergeri
  1. 1 1
      Benchmark/ModelBenchmark/GitHubUser.m
  2. 8 8
      Benchmark/ModelBenchmark/MJWeiboModel.m
  3. 15 15
      Benchmark/ModelBenchmark/ViewController.m
  4. BIN
      Benchmark/Result.numbers
  5. BIN
      Benchmark/Result.png
  6. 28 28
      Benchmark/Vendor/FastEasyMapping/Core/Mapping/FEMRelationship.h
  7. 9 3
      Benchmark/Vendor/FastEasyMapping/Core/Store/FEMManagedObjectStore.h
  8. 35 19
      Benchmark/Vendor/JSONModel/JSONModel/JSONModel.h
  9. 113 26
      Benchmark/Vendor/JSONModel/JSONModel/JSONModel.m
  10. 4 4
      Benchmark/Vendor/JSONModel/JSONModel/JSONModelArray.h
  11. 7 7
      Benchmark/Vendor/JSONModel/JSONModel/JSONModelArray.m
  12. 6 10
      Benchmark/Vendor/JSONModel/JSONModel/JSONModelClassProperty.h
  13. 17 5
      Benchmark/Vendor/JSONModel/JSONModel/JSONModelClassProperty.m
  14. 7 5
      Benchmark/Vendor/JSONModel/JSONModel/JSONModelError.h
  15. 4 4
      Benchmark/Vendor/JSONModel/JSONModel/JSONModelError.m
  16. 5 5
      Benchmark/Vendor/JSONModel/JSONModelCategories/NSArray+JSONModel.h
  17. 4 4
      Benchmark/Vendor/JSONModel/JSONModelCategories/NSArray+JSONModel.m
  18. 5 5
      Benchmark/Vendor/JSONModel/JSONModelLib.h
  19. 7 7
      Benchmark/Vendor/JSONModel/JSONModelNetworking/JSONAPI.h
  20. 4 4
      Benchmark/Vendor/JSONModel/JSONModelNetworking/JSONAPI.m
  21. 10 10
      Benchmark/Vendor/JSONModel/JSONModelNetworking/JSONHTTPClient.h
  22. 78 83
      Benchmark/Vendor/JSONModel/JSONModelNetworking/JSONHTTPClient.m
  23. 6 6
      Benchmark/Vendor/JSONModel/JSONModelNetworking/JSONModel+networking.h
  24. 4 4
      Benchmark/Vendor/JSONModel/JSONModelNetworking/JSONModel+networking.m
  25. 13 6
      Benchmark/Vendor/JSONModel/JSONModelTransformations/JSONKeyMapper.h
  26. 88 25
      Benchmark/Vendor/JSONModel/JSONModelTransformations/JSONKeyMapper.m
  27. 11 11
      Benchmark/Vendor/JSONModel/JSONModelTransformations/JSONValueTransformer.h
  28. 9 7
      Benchmark/Vendor/JSONModel/JSONModelTransformations/JSONValueTransformer.m
  29. 1 0
      Benchmark/Vendor/MJExtension/MJExtension.h
  30. 14 5
      Benchmark/Vendor/MJExtension/MJExtensionConst.h
  31. 9 2
      Benchmark/Vendor/MJExtension/MJProperty.m
  32. 4 1
      Benchmark/Vendor/MJExtension/MJPropertyKey.m
  33. 11 11
      Benchmark/Vendor/MJExtension/NSObject+MJClass.h
  34. 21 21
      Benchmark/Vendor/MJExtension/NSObject+MJClass.m
  35. 8 6
      Benchmark/Vendor/MJExtension/NSObject+MJCoding.h
  36. 10 10
      Benchmark/Vendor/MJExtension/NSObject+MJCoding.m
  37. 78 48
      Benchmark/Vendor/MJExtension/NSObject+MJKeyValue.h
  38. 432 225
      Benchmark/Vendor/MJExtension/NSObject+MJKeyValue.m
  39. 16 6
      Benchmark/Vendor/MJExtension/NSObject+MJProperty.h
  40. 88 44
      Benchmark/Vendor/MJExtension/NSObject+MJProperty.m
  41. 16 6
      Benchmark/Vendor/MJExtension/NSString+MJExtension.h
  42. 40 6
      Benchmark/Vendor/MJExtension/NSString+MJExtension.m

+ 1 - 1
Benchmark/ModelBenchmark/GitHubUser.m

@@ -269,7 +269,7 @@ SET_NUM(_following, @"following");
 
 
 @implementation MJGHUser
-+ (NSDictionary *)replacedKeyFromPropertyName {
++ (NSDictionary *)mj_replacedKeyFromPropertyName {
     return @{
         @"userID" : @"id",
         @"avatarURL" : @"avatar_url",

+ 8 - 8
Benchmark/ModelBenchmark/MJWeiboModel.m

@@ -19,7 +19,7 @@ MJExtensionCodingImplementation
 
 @implementation MJWeiboPicture
 MJExtensionCodingImplementation
-+ (NSDictionary *)replacedKeyFromPropertyName {
++ (NSDictionary *)mj_replacedKeyFromPropertyName {
     return @{@"picID" : @"pic_id",
              @"keepSize" : @"keep_size",
              @"photoTag" : @"photo_tag",
@@ -31,7 +31,7 @@ MJExtensionCodingImplementation
 
 @implementation MJWeiboURL
 MJExtensionCodingImplementation
-+ (NSDictionary *)replacedKeyFromPropertyName {
++ (NSDictionary *)mj_replacedKeyFromPropertyName {
     return @{@"oriURL" : @"ori_url",
              @"urlTitle" : @"url_title",
              @"urlTypePic" : @"url_type_pic",
@@ -46,7 +46,7 @@ MJExtensionCodingImplementation
 
 @implementation MJWeiboUser
 MJExtensionCodingImplementation
-+ (NSDictionary *)replacedKeyFromPropertyName {
++ (NSDictionary *)mj_replacedKeyFromPropertyName {
     return @{@"userID" : @"id",
              @"idString" : @"idstr",
              @"genderString" : @"gender",
@@ -90,7 +90,7 @@ MJExtensionCodingImplementation
              @"verifiedSource" : @"verified_source",
              @"userAbility" : @"user_ability"};
 }
-- (id)newValueFromOldValue:(id)oldValue property:(MJProperty *)property {
+- (id)mj_newValueFromOldValue:(id)oldValue property:(MJProperty *)property {
     if ([property.name isEqualToString:@"createdAt"]) {
         return [[DateFormatter weiboDataFormatter] dateFromString:oldValue];
     }
@@ -100,7 +100,7 @@ MJExtensionCodingImplementation
 
 @implementation MJWeiboStatus
 MJExtensionCodingImplementation
-+ (NSDictionary *)replacedKeyFromPropertyName {
++ (NSDictionary *)mj_replacedKeyFromPropertyName {
     return @{@"statusID" : @"id",
              @"createdAt" : @"created_at",
              @"attitudesStatus" : @"attitudes_status",
@@ -122,11 +122,11 @@ MJExtensionCodingImplementation
              @"picInfos" : @"pic_infos",
              @"inReplyToUserId" : @"in_reply_to_user_id"};
 }
-+ (NSDictionary *)objectClassInArray {
++ (NSDictionary *)mj_objectClassInArray {
     return @{@"picIds" : @"NSString",
              @"urlStruct" : @"MJWeiboURL"};
 }
-- (id)newValueFromOldValue:(id)oldValue property:(MJProperty *)property {
+- (id)mj_newValueFromOldValue:(id)oldValue property:(MJProperty *)property {
     if ([property.name isEqualToString:@"createdAt"]) {
         if ([oldValue isKindOfClass:[NSString class]]) {
             return [[DateFormatter weiboDataFormatter] dateFromString:oldValue];
@@ -138,7 +138,7 @@ MJExtensionCodingImplementation
         NSMutableDictionary *pics = [NSMutableDictionary new];
         [((NSDictionary *)oldValue) enumerateKeysAndObjectsUsingBlock:^(id key, NSDictionary *obj, BOOL *stop) {
             if ([obj isKindOfClass:[NSDictionary class]]) {
-                MJWeiboPicture *pic = [MJWeiboPicture objectWithKeyValues:obj];
+                MJWeiboPicture *pic = [MJWeiboPicture mj_objectWithKeyValues:obj];
                 if (pic) pics[key] = pic;
             }
         }];

+ 15 - 15
Benchmark/ModelBenchmark/ViewController.m

@@ -18,7 +18,7 @@
 //#import "ModelBenchmark-Swift.h"
 
 /*
- Benchmark: (update to 2015-09-18)
+ Benchmark: (update to 2016-01-15)
  YYModel: https://github.com/ibireme/YYKit
  Mantle: https://github.com/Mantle/Mantle
  JSONModel: https://github.com/icanzilb/JSONModel
@@ -83,7 +83,7 @@
             [adapter modelFromJSONDictionary:json error:nil];
             
             // MJExtension
-            [MJGHUser objectWithKeyValues:json];
+            [MJGHUser mj_objectWithKeyValues:json];
         }
     }
     /// warm up holder
@@ -327,7 +327,7 @@
         begin = CACurrentMediaTime();
         @autoreleasepool {
             for (int i = 0; i < count; i++) {
-                MJGHUser *user = [MJGHUser objectWithKeyValues:json];
+                MJGHUser *user = [MJGHUser mj_objectWithKeyValues:json];
                 [user class];
             }
         }
@@ -335,7 +335,7 @@
         printf("MJExtension:     %8.2f   ", (end - begin) * 1000);
         
         
-        MJGHUser *user = [MJGHUser objectWithKeyValues:json];
+        MJGHUser *user = [MJGHUser mj_objectWithKeyValues:json];
         if (user.userID == 0) NSLog(@"error!");
         if (!user.login) NSLog(@"error!");
         if (!user.htmlURL) NSLog(@"error");
@@ -344,12 +344,12 @@
         begin = CACurrentMediaTime();
         @autoreleasepool {
             for (int i = 0; i < count; i++) {
-                NSDictionary *json = [user JSONObject];
+                NSDictionary *json = [user mj_JSONObject];
                 [holder addObject:json];
             }
         }
         end = CACurrentMediaTime();
-        if ([NSJSONSerialization isValidJSONObject:[user JSONObject]]) {
+        if ([NSJSONSerialization isValidJSONObject:[user mj_JSONObject]]) {
             printf("%8.2f   ", (end - begin) * 1000);
         } else {
             printf("   error   ");
@@ -407,7 +407,7 @@
             [adapter modelFromJSONDictionary:json error:nil];
             
             // MJExtension
-            [MJWeiboStatus objectWithKeyValues:json];
+            [MJWeiboStatus mj_objectWithKeyValues:json];
         }
     }
     
@@ -589,7 +589,7 @@
         begin = CACurrentMediaTime();
         @autoreleasepool {
             for (int i = 0; i < count; i++) {
-                MJWeiboStatus *feed = [MJWeiboStatus objectWithKeyValues:json];
+                MJWeiboStatus *feed = [MJWeiboStatus mj_objectWithKeyValues:json];
                 [holder addObject:feed];
             }
         }
@@ -597,17 +597,17 @@
         printf("MJExtension:     %8.2f   ", (end - begin) * 1000);
         
         
-        MJWeiboStatus *feed = [MJWeiboStatus objectWithKeyValues:json];
+        MJWeiboStatus *feed = [MJWeiboStatus mj_objectWithKeyValues:json];
         [holder removeAllObjects];
         begin = CACurrentMediaTime();
         @autoreleasepool {
             for (int i = 0; i < count; i++) {
-                NSDictionary *json = [feed JSONObject];
+                NSDictionary *json = [feed mj_JSONObject];
                 [holder addObject:json];
             }
         }
         end = CACurrentMediaTime();
-        if ([NSJSONSerialization isValidJSONObject:[feed JSONObject]]) {
+        if ([NSJSONSerialization isValidJSONObject:[feed mj_JSONObject]]) {
             printf("%8.2f   ", (end - begin) * 1000);
         } else {
             printf("   error   ");
@@ -673,7 +673,7 @@
         logError(@"Mantle:         ", mtUser);
         
         // MJExtension
-        MJGHUser *mjUser = [MJGHUser objectWithKeyValues:json];
+        MJGHUser *mjUser = [MJGHUser mj_objectWithKeyValues:json];
         logError(@"MJExtension:    ", mjUser);
         
         printf("\n");
@@ -730,7 +730,7 @@
         logError(@"Mantle:         ", mtUser);
         
         // MJExtension
-        MJGHUser *mjUser = [MJGHUser objectWithKeyValues:json];
+        MJGHUser *mjUser = [MJGHUser mj_objectWithKeyValues:json];
         logError(@"MJExtension:    ", mjUser);
     }
     
@@ -777,7 +777,7 @@
         logError(@"Mantle:         ", mtUser);
         
         // MJExtension
-        MJGHUser *mjUser = [MJGHUser objectWithKeyValues:json];
+        MJGHUser *mjUser = [MJGHUser mj_objectWithKeyValues:json];
         logError(@"MJExtension:    ", mjUser);
         
         printf("\n");
@@ -830,7 +830,7 @@
         logError(@"Mantle:         ", mtUser);
         
         // MJExtension
-        MJGHUser *mjUser = [MJGHUser objectWithKeyValues:json];
+        MJGHUser *mjUser = [MJGHUser mj_objectWithKeyValues:json];
         logError(@"MJExtension:    ", mjUser);
         
         printf("\n");

BIN
Benchmark/Result.numbers


BIN
Benchmark/Result.png


+ 28 - 28
Benchmark/Vendor/FastEasyMapping/Core/Mapping/FEMRelationship.h

@@ -5,59 +5,59 @@
 #import "FEMAssignmentPolicy.h"
 #import "FEMProperty.h"
 
+NS_ASSUME_NONNULL_BEGIN
+
 @class FEMMapping;
 
 @interface FEMRelationship : NSObject <FEMProperty>
 
-@property (nonatomic, strong, nonnull) FEMMapping *mapping;
+@property (nonatomic, strong) FEMMapping *mapping;
 @property (nonatomic, getter=isToMany) BOOL toMany;
 
 @property (nonatomic) BOOL weak;
-@property (nonatomic, copy, nonnull) FEMAssignmentPolicy assignmentPolicy;
-
-- (nonnull instancetype)initWithProperty:(nonnull NSString *)property mapping:(nonnull FEMMapping *)mapping;
+@property (nonatomic, copy) FEMAssignmentPolicy assignmentPolicy;
 
-- (nonnull instancetype)initWithProperty:(nonnull NSString *)property
-                                 keyPath:(nullable NSString *)keyPath
-                                 mapping:(nonnull FEMMapping *)mapping NS_DESIGNATED_INITIALIZER;
+- (instancetype)init NS_UNAVAILABLE;
 
-- (nonnull instancetype)initWithProperty:(nonnull NSString *)property
-                                 keyPath:(nonnull NSString *)keyPath
-                                 mapping:(nonnull FEMMapping *)mapping
-                        assignmentPolicy:(nonnull FEMAssignmentPolicy)assignmentPolicy;
+- (instancetype)initWithProperty:(NSString *)property keyPath:(nullable NSString *)keyPath mapping:(FEMMapping *)mapping NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithProperty:(NSString *)property mapping:(FEMMapping *)mapping;
+- (instancetype)initWithProperty:(NSString *)property keyPath:(NSString *)keyPath mapping:(FEMMapping *)mapping assignmentPolicy:(FEMAssignmentPolicy)assignmentPolicy;
 
-- (void)setMapping:(nonnull FEMMapping *)mapping forKeyPath:(nullable NSString *)keyPath;
+- (void)setMapping:(FEMMapping *)mapping forKeyPath:(nullable NSString *)keyPath;
 
 @end
 
 @interface FEMRelationship (Deprecated)
 
-- (void)setObjectMapping:(nonnull FEMMapping *)objectMapping forKeyPath:(nullable NSString *)keyPath __attribute__((deprecated("Use -[FEMRelationship setMappaing:forKeyPath:] instead")));
+- (void)setObjectMapping:(FEMMapping *)objectMapping forKeyPath:(nullable NSString *)keyPath __attribute__((deprecated("Use -[FEMRelationship setMappaing:forKeyPath:] instead")));
 
-- (nonnull instancetype)initWithProperty:(nonnull NSString *)property
-                                 keyPath:(nullable NSString *)keyPath
-                        assignmentPolicy:(nullable FEMAssignmentPolicy)policy
-                           objectMapping:(nullable FEMMapping *)objectMapping __attribute__((deprecated("Use -[FEMRelationship initWithProperty:keyPath:mapping:assignmentPolicy:] instead")));
+- (instancetype)initWithProperty:(NSString *)property
+                         keyPath:(nullable NSString *)keyPath
+                assignmentPolicy:(nullable FEMAssignmentPolicy)policy
+                   objectMapping:(nullable FEMMapping *)objectMapping __attribute__((deprecated("Use -[FEMRelationship initWithProperty:keyPath:mapping:assignmentPolicy:] instead")));
 
 /**
 * same as + [FEMRelationship mappingOfProperty:property toKeyPath:nil mapping:mapping];
 */
-+ (nonnull instancetype)mappingOfProperty:(nonnull NSString *)property objectMapping:(nonnull FEMMapping *)objectMapping __attribute__((deprecated("Use -[FEMRelationship initWithProperty:mapping:] instead")));
-+ (nonnull instancetype)mappingOfProperty:(nonnull NSString *)property
-                                toKeyPath:(nullable NSString *)keyPath
-                            objectMapping:(nonnull FEMMapping *)objectMapping __attribute__((deprecated("Use -[FEMRelationship initWithProperty:keyPath:mapping:] instead")));
++ (instancetype)mappingOfProperty:(NSString *)property objectMapping:(FEMMapping *)objectMapping __attribute__((deprecated("Use -[FEMRelationship initWithProperty:mapping:] instead")));
+
++ (instancetype)mappingOfProperty:(NSString *)property
+                        toKeyPath:(nullable NSString *)keyPath
+                    objectMapping:(FEMMapping *)objectMapping __attribute__((deprecated("Use -[FEMRelationship initWithProperty:keyPath:mapping:] instead")));
 
-@property (nonatomic, strong, nonnull) FEMMapping *objectMapping __attribute__((deprecated("Use FEMRelationship.mapping instead")));
+@property (nonatomic, strong) FEMMapping *objectMapping __attribute__((deprecated("Use FEMRelationship.mapping instead")));
 
 @end
 
 @interface FEMRelationship (Unavailable)
 
-+ (nonnull instancetype)mappingOfProperty:(nonnull NSString *)property
-                            configuration:(nonnull void (^)(FEMRelationship * __nonnull mapping))configuration __attribute__((unavailable("Use -[FEMRelationship initWithProperty:keyPath:mapping:] instead")));
++ (instancetype)mappingOfProperty:(NSString *)property
+                    configuration:(void (^)(FEMRelationship *__mapping))configuration __attribute__((unavailable("Use -[FEMRelationship initWithProperty:keyPath:mapping:] instead")));
 
-+ (nonnull instancetype)mappingOfProperty:(nonnull NSString *)property
-                                toKeyPath:(nullable NSString *)keyPath
-                            configuration:(nonnull void (^)(FEMRelationship * __nonnull mapping))configuration __attribute__((unavailable("Use -[FEMRelationship initWithProperty:keyPath:mapping:] instead")));
++ (instancetype)mappingOfProperty:(NSString *)property
+                        toKeyPath:(nullable NSString *)keyPath
+                    configuration:(void (^)(FEMRelationship *__mapping))configuration __attribute__((unavailable("Use -[FEMRelationship initWithProperty:keyPath:mapping:] instead")));
+
+@end
 
-@end
+NS_ASSUME_NONNULL_END

+ 9 - 3
Benchmark/Vendor/FastEasyMapping/Core/Store/FEMManagedObjectStore.h

@@ -2,13 +2,19 @@
 
 #import "FEMObjectStore.h"
 
+NS_ASSUME_NONNULL_BEGIN
+
 @class NSManagedObjectContext;
 
 @interface FEMManagedObjectStore : FEMObjectStore
 
-- (nonnull instancetype)initWithContext:(nonnull NSManagedObjectContext *)context NS_DESIGNATED_INITIALIZER;
-@property (nonatomic, strong, readonly, nonnull) NSManagedObjectContext *context;
+- (instancetype)init NS_UNAVAILABLE;
+
+- (instancetype)initWithContext:(NSManagedObjectContext *)context NS_DESIGNATED_INITIALIZER;
+@property (nonatomic, strong, readonly) NSManagedObjectContext *context;
 
 @property (nonatomic) BOOL saveContextOnCommit;
 
-@end
+@end
+
+NS_ASSUME_NONNULL_END

+ 35 - 19
Benchmark/Vendor/JSONModel/JSONModel/JSONModel.h

@@ -1,18 +1,18 @@
 //
 //  JSONModel.h
 //
-//  @version 1.0.2
-//  @author Marin Todorov, http://www.touch-code-magazine.com
+//  @version 1.2
+//  @author Marin Todorov (http://www.underplot.com) and contributors
 //
 
-// Copyright (c) 2012-2014 Marin Todorov, Underplot ltd.
+// Copyright (c) 2012-2015 Marin Todorov, Underplot ltd.
 // This code is distributed under the terms and conditions of the MIT license.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// The MIT License in plain English: http://www.touch-code-magazine.com/JSONModel/MITLicense
+
 
 #import <Foundation/Foundation.h>
 
@@ -108,7 +108,7 @@ lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
  * should suffice, but developers have the option ot also overwrite it if needed.
  *
  * @param data representing a JSON response (usually fetched from web), to be imported in the model.
- * @param err an error or NULL
+ * @param error an error or NULL
  */
 -(instancetype)initWithData:(NSData*)data error:(NSError**)error;
 
@@ -152,7 +152,7 @@ lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
    * Create a new model instance and initialize it with the JSON from a text parameter. The method assumes UTF8 encoded input text.
    * @param string JSON text data
    * @param err an initialization error or nil
-   * @exception JSONModelTypeNotAllowedException thrown when unsported type is found in the incoming JSON, 
+   * @exception JSONModelTypeNotAllowedException thrown when unsupported type is found in the incoming JSON,
    * or a property type in your model is not supported by JSONValueTransformer and its categories
    * @see initWithString:usingEncoding:error: for use of custom text encodings
    */
@@ -163,7 +163,7 @@ lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
    * @param string JSON text data
    * @param encoding the text encoding to use when parsing the string (see NSStringEncoding)
    * @param err an initialization error or nil
-   * @exception JSONModelTypeNotAllowedException thrown when unsported type is found in the incoming JSON, 
+   * @exception JSONModelTypeNotAllowedException thrown when unsupported type is found in the incoming JSON,
    * or a property type in your model is not supported by JSONValueTransformer and its categories
    */
   -(instancetype)initWithString:(NSString *)string usingEncoding:(NSStringEncoding)encoding error:(JSONModelError**)err;
@@ -222,29 +222,30 @@ lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
    *
    * @param array list of dictionaries to be imported as models
    * @return list of initialized data model objects
-   * @exception JSONModelTypeNotAllowedException thrown when unsported type is found in the incoming JSON, 
+   * @exception JSONModelTypeNotAllowedException thrown when unsupported type is found in the incoming JSON,
    * or a property type in your model is not supported by JSONValueTransformer and its categories
    * @exception JSONModelInvalidDataException thrown when the input data does not include all required keys
    * @see arrayOfDictionariesFromModels:
    */
-  +(NSMutableArray*)arrayOfModelsFromDictionaries:(NSArray*)array;
-
+  +(NSMutableArray*)arrayOfModelsFromDictionaries:(NSArray*)array __attribute__((deprecated("use arrayOfModelsFromDictionaries:error:")));
   +(NSMutableArray*)arrayOfModelsFromDictionaries:(NSArray*)array error:(NSError**)err;
-
   +(NSMutableArray*)arrayOfModelsFromData:(NSData*)data error:(NSError**)err;
+  +(NSMutableArray*)arrayOfModelsFromString:(NSString*)string error:(NSError**)err;
+  +(NSMutableDictionary*)dictionaryOfModelsFromDictionary:(NSDictionary*)dictionary error:(NSError**)err;
+  +(NSMutableDictionary*)dictionaryOfModelsFromData:(NSData*)data error:(NSError**)err;
+  +(NSMutableDictionary*)dictionaryOfModelsFromString:(NSString*)string error:(NSError**)err;
 
   /**
    * If you have an NSArray of data model objects, this method takes it in and outputs a list of the 
    * matching dictionaries. This method does the opposite of arrayOfObjectsFromDictionaries:
    * @param array list of JSONModel objects
    * @return a list of NSDictionary objects
-   * @exception JSONModelTypeNotAllowedException thrown when unsported type is found in the incoming JSON, 
+   * @exception JSONModelTypeNotAllowedException thrown when unsupported type is found in the incoming JSON,
    * or a property type in your model is not supported by JSONValueTransformer and its categories
    * @see arrayOfModelsFromDictionaries:
    */
   +(NSMutableArray*)arrayOfDictionariesFromModels:(NSArray*)array;
-
-
+  +(NSMutableDictionary*)dictionaryOfDictionariesFromModels:(NSDictionary*)dictionary;
 
 /** @name Comparing models */
 
@@ -256,14 +257,14 @@ lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
   -(NSString*)indexPropertyName;
 
   /**
-   * Overriden NSObject method to compare model objects. Compares the &lt;Index&gt; property of the two models,
+   * Overridden NSObject method to compare model objects. Compares the &lt;Index&gt; property of the two models,
    * if an index property is defined.
    * @param object a JSONModel instance to compare to for equality
    */
   -(BOOL)isEqual:(id)object;
 
   /**
-   * Comparision method, which uses the defined &lt;Index&gt; property of the two models, to compare them.
+   * Comparison method, which uses the defined &lt;Index&gt; property of the two models, to compare them.
    * If there isn't an index property throws an exception. If the Index property does not have a compare: method
    * also throws an exception. NSString and NSNumber have compare: methods, and in case the Index property is 
    * a another custom class, the programmer should create a custom compare: method then.
@@ -276,7 +277,7 @@ lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
   /**
    * Overwrite the validate method in your own models if you need to perform some custom validation over the model data.
    * This method gets called at the very end of the JSONModel initializer, thus the model is in the state that you would
-   * get it back when initialzed. Check the values of any property that needs to be validated and if any invalid values
+   * get it back when initialized. Check the values of any property that needs to be validated and if any invalid values
    * are encountered return NO and set the error parameter to an NSError object. If the model is valid return YES.
    *
    * NB: Only setting the error parameter is not enough to fail the validation, you also need to return a NO value.
@@ -298,7 +299,7 @@ lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
  * Sets a key mapper which affects ALL the models in your project. Use this if you need only one mapper to work
  * with your API. For example if you are using the [JSONKeyMapper mapperFromUnderscoreCaseToCamelCase] it is more
  * likely that you will need to use it with ALL of your models.
- * NB: Custom key mappers take precendence over the global key mapper.
+ * NB: Custom key mappers take precedence over the global key mapper.
  * @param globalKeyMapper a key mapper to apply to all models in your project.
  *
  * Lookup JSONKeyMapper docs for more details.
@@ -323,12 +324,27 @@ lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
  */
 +(BOOL)propertyIsIgnored:(NSString*)propertyName;
 
+/**
+ * Indicates the protocol name for an array property.
+ * Rather than using:
+ *     @property (strong) NSArray<MyType>* things;
+ * You can implement protocolForArrayProperty: and keep your property 
+ * defined like:
+ *     @property (strong) NSArray* things;
+ * @param propertyName the name of the property
+ * @return an NSString result indicating the name of the protocol/class
+ * that should be contained in this array property. Return nil to indicate
+ * no contained protocol.
+ */
++(NSString*)protocolForArrayProperty:(NSString *)propertyName;
+
 /**
  * Merges values from the given dictionary into the model instance.
  * @param dict dictionary with values
  * @param useKeyMapping if YES the method will use the model's key mapper and the global key mapper, if NO 
  * it'll just try to match the dictionary keys to the model's properties
  */
--(void)mergeFromDictionary:(NSDictionary*)dict useKeyMapping:(BOOL)useKeyMapping;
+- (void)mergeFromDictionary:(NSDictionary *)dict useKeyMapping:(BOOL)useKeyMapping __attribute__((deprecated("use mergeFromDictionary:useKeyMapping:error:")));
+- (void)mergeFromDictionary:(NSDictionary *)dict useKeyMapping:(BOOL)useKeyMapping error:(NSError **)error;
 
 @end

+ 113 - 26
Benchmark/Vendor/JSONModel/JSONModel/JSONModel.m

@@ -1,18 +1,18 @@
 //
 //  JSONModel.m
 //
-//  @version 1.0.2
-//  @author Marin Todorov, http://www.touch-code-magazine.com
+//  @version 1.2
+//  @author Marin Todorov (http://www.underplot.com) and contributors
 //
 
-// Copyright (c) 2012-2014 Marin Todorov, Underplot ltd.
+// Copyright (c) 2012-2015 Marin Todorov, Underplot ltd.
 // This code is distributed under the terms and conditions of the MIT license.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// The MIT License in plain English: http://www.touch-code-magazine.com/JSONModel/MITLicense
+
 
 #if !__has_feature(objc_arc)
 #error The JSONMOdel framework is ARC only, you can enable ARC on per file basis.
@@ -214,7 +214,7 @@ static JSONKeyMapper* globalKeyMapper = nil;
     NSMutableSet* requiredProperties = [self __requiredPropertyNames].mutableCopy;
     NSSet* incomingKeys = [NSSet setWithArray: incomingKeysArray];
     
-    //transform the key names, if neccessary
+    //transform the key names, if necessary
     if (keyMapper || globalKeyMapper) {
         
         NSMutableSet* transformedIncomingKeys = [NSMutableSet setWithCapacity: requiredProperties.count];
@@ -225,7 +225,7 @@ static JSONKeyMapper* globalKeyMapper = nil;
             
             transformedName = (keyMapper||globalKeyMapper) ? [self __mapString:property.name withKeyMapper:keyMapper importing:YES] : property.name;
             
-            //chek if exists and if so, add to incoming keys
+            //check if exists and if so, add to incoming keys
             id value;
             @try {
                 value = [dict valueForKeyPath:transformedName];
@@ -393,7 +393,7 @@ static JSONKeyMapper* globalKeyMapper = nil;
             } else {
                 
                 // 2) check if there's a protocol to the property
-                //  ) might or not be the case there's a built in transofrm for it
+                //  ) might or not be the case there's a built in transform for it
                 if (property.protocol) {
                     
                     //JMLog(@"proto: %@", p.protocol);
@@ -476,7 +476,7 @@ static JSONKeyMapper* globalKeyMapper = nil;
                     } else {
                         
                         // it's not a JSON data type, and there's no transformer for it
-                        // if property type is not supported - that's a programmer mistaked -> exception
+                        // if property type is not supported - that's a programmer mistake -> exception
                         @throw [NSException exceptionWithName:@"Type not allowed"
                                                        reason:[NSString stringWithFormat:@"%@ type not supported for %@.%@", property.type, [self class], property.name]
                                                      userInfo:nil];
@@ -589,7 +589,7 @@ static JSONKeyMapper* globalKeyMapper = nil;
             
             //check for 64b BOOLs
             if ([propertyAttributes hasPrefix:@"Tc,"]) {
-                //mask BOOLs as structs so they can have custom convertors
+                //mask BOOLs as structs so they can have custom converters
                 p.structName = @"BOOL";
             }
             
@@ -660,7 +660,7 @@ static JSONKeyMapper* globalKeyMapper = nil;
                 
                 if (![allowedPrimitiveTypes containsObject:propertyType]) {
                     
-                    //type not allowed - programmer mistaked -> exception
+                    //type not allowed - programmer mistaken -> exception
                     @throw [NSException exceptionWithName:@"JSONModelProperty type not allowed"
                                                    reason:[NSString stringWithFormat:@"Property type of %@.%@ is not supported by JSONModel.", self.class, p.name]
                                                  userInfo:nil];
@@ -676,6 +676,11 @@ static JSONKeyMapper* globalKeyMapper = nil;
             if([[self class] propertyIsIgnored:nsPropertyName]){
                 p = nil;
             }
+
+            NSString* customProtocol = [[self class] protocolForArrayProperty:nsPropertyName];
+            if (customProtocol) {
+                p.protocol = customProtocol;
+            }
             
             //few cases where JSONModel will ignore properties automatically
             if ([propertyType isEqualToString:@"Block"]) {
@@ -794,7 +799,7 @@ static JSONKeyMapper* globalKeyMapper = nil;
     return value;
 }
 
-//built-in reverse transormations (export to JSON compliant objects)
+//built-in reverse transformations (export to JSON compliant objects)
 -(id)__reverseTransform:(id)value forProperty:(JSONModelClassProperty*)property
 {
     Class protocolClass = NSClassFromString(property.protocol);
@@ -832,31 +837,34 @@ static JSONKeyMapper* globalKeyMapper = nil;
 #pragma mark - custom transformations
 -(BOOL)__customSetValue:(id<NSObject>)value forProperty:(JSONModelClassProperty*)property
 {
-    if (property.setterType == kNotInspected) {
+    if (!property.customSetters)
+        property.customSetters = [NSMutableDictionary new];
+
+    NSString *className = NSStringFromClass([JSONValueTransformer classByResolvingClusterClasses:[value class]]);
+
+    if (!property.customSetters[className]) {
         //check for a custom property setter method
         NSString* ucfirstName = [property.name stringByReplacingCharactersInRange:NSMakeRange(0,1)
                                                                        withString:[[property.name substringToIndex:1] uppercaseString]];
-        NSString* selectorName = [NSString stringWithFormat:@"set%@With%@:", ucfirstName,
-                                  [JSONValueTransformer classByResolvingClusterClasses:[value class]]
-                                  ];
+        NSString* selectorName = [NSString stringWithFormat:@"set%@With%@:", ucfirstName, className];
 
         SEL customPropertySetter = NSSelectorFromString(selectorName);
         
         //check if there's a custom selector like this
         if (![self respondsToSelector: customPropertySetter]) {
-            property.setterType = kNo;
+            property.customSetters[className] = [NSNull null];
             return NO;
         }
         
         //cache the custom setter selector
-        property.setterType = kCustom;
-        property.customSetter = customPropertySetter;
+        property.customSetters[className] = selectorName;
     }
     
-    if (property.setterType==kCustom) {
+    if (property.customSetters[className] != [NSNull null]) {
         //call the custom setter
         //https://github.com/steipete
-        ((void (*) (id, SEL, id))objc_msgSend)(self, property.customSetter, value);
+        SEL selector = NSSelectorFromString(property.customSetters[className]);
+        ((void (*) (id, SEL, id))objc_msgSend)(self, selector, value);
         return YES;
     }
     
@@ -1040,7 +1048,7 @@ static JSONKeyMapper* globalKeyMapper = nil;
                 } else {
 
                     //in this case most probably a custom property was defined in a model
-                    //but no default reverse transofrmer for it
+                    //but no default reverse transformer for it
                     @throw [NSException exceptionWithName:@"Value transformer not found"
                                                    reason:[NSString stringWithFormat:@"[JSONValueTransformer %@] not found", selectorName]
                                                  userInfo:nil];
@@ -1086,7 +1094,7 @@ static JSONKeyMapper* globalKeyMapper = nil;
 	return [self arrayOfModelsFromDictionaries:array error:nil];
 }
 
-+(NSMutableArray*)arrayOfModelsFromData:(NSData *)data error:(NSError *__autoreleasing *)err
++ (NSMutableArray *)arrayOfModelsFromData:(NSData *)data error:(NSError **)err
 {
     id json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:err];
     if (!json || ![json isKindOfClass:[NSArray class]]) return nil;
@@ -1094,6 +1102,11 @@ static JSONKeyMapper* globalKeyMapper = nil;
     return [self arrayOfModelsFromDictionaries:json error:err];
 }
 
++ (NSMutableArray *)arrayOfModelsFromString:(NSString *)string error:(NSError **)err
+{
+    return [self arrayOfModelsFromData:[string dataUsingEncoding:NSUTF8StringEncoding] error:err];
+}
+
 // Same as above, but with error reporting
 +(NSMutableArray*)arrayOfModelsFromDictionaries:(NSArray*)array error:(NSError**)err
 {
@@ -1134,6 +1147,49 @@ static JSONKeyMapper* globalKeyMapper = nil;
     return list;
 }
 
++ (NSMutableDictionary *)dictionaryOfModelsFromString:(NSString *)string error:(NSError **)err
+{
+    return [self dictionaryOfModelsFromData:[string dataUsingEncoding:NSUTF8StringEncoding] error:err];
+}
+
++ (NSMutableDictionary *)dictionaryOfModelsFromData:(NSData *)data error:(NSError **)err
+{
+    id json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:err];
+    if (!json || ![json isKindOfClass:[NSDictionary class]]) return nil;
+
+    return [self dictionaryOfModelsFromDictionary:json error:err];
+}
+
++ (NSMutableDictionary *)dictionaryOfModelsFromDictionary:(NSDictionary *)dictionary error:(NSError **)err
+{
+    NSMutableDictionary *output = [NSMutableDictionary dictionaryWithCapacity:dictionary.count];
+
+    for (NSString *key in dictionary.allKeys)
+    {
+        id object = dictionary[key];
+
+        if ([object isKindOfClass:NSDictionary.class])
+        {
+            id obj = [[self alloc] initWithDictionary:object error:err];
+            if (obj == nil) return nil;
+            output[key] = obj;
+        }
+        else if ([object isKindOfClass:NSArray.class])
+        {
+            id obj = [self arrayOfModelsFromDictionaries:object error:err];
+            if (obj == nil) return nil;
+            output[key] = obj;
+        }
+        else
+        {
+            *err = [JSONModelError errorInvalidDataWithTypeMismatch:@"Only dictionaries and arrays are supported"];
+            return nil;
+        }
+    }
+
+    return output;
+}
+
 //loop over NSArray of models and export them to JSON objects
 +(NSMutableArray*)arrayOfDictionariesFromModels:(NSArray*)array
 {
@@ -1172,6 +1228,23 @@ static JSONKeyMapper* globalKeyMapper = nil;
     return list;
 }
 
++(NSMutableDictionary *)dictionaryOfDictionariesFromModels:(NSDictionary *)dictionary
+{
+    //bail early
+    if (isNull(dictionary)) return nil;
+
+    NSMutableDictionary *output = [NSMutableDictionary dictionaryWithCapacity:dictionary.count];
+
+    for (NSString *key in dictionary.allKeys) {
+        id <AbstractJSONModelProtocol> object = dictionary[key];
+        id obj = [object toDictionary];
+        if (!obj) return nil;
+        output[key] = obj;
+    }
+
+    return output;
+}
+
 #pragma mark - custom comparison methods
 -(NSString*)indexPropertyName
 {
@@ -1213,9 +1286,13 @@ static JSONKeyMapper* globalKeyMapper = nil;
 - (NSUInteger)hash
 {
     if (self.indexPropertyName) {
-        return [self.indexPropertyName hash];
+        id val = [self valueForKey:self.indexPropertyName];
+
+        if (val) {
+            return [val hash];
+        }
     }
-    
+
     return [super hash];
 }
 
@@ -1270,10 +1347,20 @@ static JSONKeyMapper* globalKeyMapper = nil;
     return NO;
 }
 
++(NSString*)protocolForArrayProperty:(NSString *)propertyName
+{
+    return nil;
+}
+
 #pragma mark - working with incomplete models
--(void)mergeFromDictionary:(NSDictionary*)dict useKeyMapping:(BOOL)useKeyMapping
+- (void)mergeFromDictionary:(NSDictionary *)dict useKeyMapping:(BOOL)useKeyMapping
+{
+    [self mergeFromDictionary:dict useKeyMapping:useKeyMapping error:nil];
+}
+
+- (void)mergeFromDictionary:(NSDictionary *)dict useKeyMapping:(BOOL)useKeyMapping error:(NSError **)error
 {
-    [self __importDictionary:dict withKeyMapper:(useKeyMapping)? self.__keyMapper:nil validation:NO error:nil];
+    [self __importDictionary:dict withKeyMapper:(useKeyMapping)? self.__keyMapper:nil validation:NO error:error];
 }
 
 #pragma mark - NSCopying, NSCoding

+ 4 - 4
Benchmark/Vendor/JSONModel/JSONModel/JSONModelArray.h

@@ -2,17 +2,17 @@
 //  JSONModelArray.h
 //
 //  @version 0.8.0
-//  @author Marin Todorov, http://www.touch-code-magazine.com
+//  @author Marin Todorov (http://www.underplot.com) and contributors
 //
 
-// Copyright (c) 2012-2014 Marin Todorov, Underplot ltd.
+// Copyright (c) 2012-2015 Marin Todorov, Underplot ltd.
 // This code is distributed under the terms and conditions of the MIT license.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// The MIT License in plain English: http://www.touch-code-magazine.com/JSONModel/MITLicense
+
 
 #import <Foundation/Foundation.h>
 
@@ -50,7 +50,7 @@
  *
  * Will return nil if no matching model is found. Will return nil if there's no index property
  * defined on the models found in the array (will sample the first object, assuming the array
- * contains homogenous collection of objects)
+ * contains homogeneous collection of objects)
  *
  * @param indexValue the id value to search for
  * @return the found model or nil

+ 7 - 7
Benchmark/Vendor/JSONModel/JSONModel/JSONModelArray.m

@@ -1,18 +1,18 @@
 //
 //  JSONModelArray.m
 //
-//  @version 1.0.2
-//  @author Marin Todorov, http://www.touch-code-magazine.com
+//  @version 1.2
+//  @author Marin Todorov (http://www.underplot.com) and contributors
 //
 
-// Copyright (c) 2012-2014 Marin Todorov, Underplot ltd.
+// Copyright (c) 2012-2015 Marin Todorov, Underplot ltd.
 // This code is distributed under the terms and conditions of the MIT license.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// The MIT License in plain English: http://www.touch-code-magazine.com/JSONModel/MITLicense
+
 
 #import "JSONModelArray.h"
 #import "JSONModel.h"
@@ -69,9 +69,9 @@
 
 -(id)forwardingTargetForSelector:(SEL)selector
 {
-    static NSArray* overridenMethods = nil;
-    if (!overridenMethods) overridenMethods = @[@"initWithArray:modelClass:",@"objectAtIndex:",@"objectAtIndexedSubscript:", @"count",@"modelWithIndexValue:",@"description",@"mutableCopy",@"firstObject",@"lastObject",@"countByEnumeratingWithState:objects:count:"];
-    if ([overridenMethods containsObject:NSStringFromSelector(selector)]) {
+    static NSArray *overriddenMethods = nil;
+    if (!overriddenMethods) overriddenMethods = @[@"initWithArray:modelClass:", @"objectAtIndex:", @"objectAtIndexedSubscript:", @"count", @"modelWithIndexValue:", @"description", @"mutableCopy", @"firstObject", @"lastObject", @"countByEnumeratingWithState:objects:count:"];
+    if ([overriddenMethods containsObject:NSStringFromSelector(selector)]) {
         return self;
     }
     return _storage;

+ 6 - 10
Benchmark/Vendor/JSONModel/JSONModel/JSONModelClassProperty.h

@@ -1,18 +1,18 @@
 //
 //  JSONModelClassProperty.h
 //
-//  @version 1.0.2
-//  @author Marin Todorov, http://www.touch-code-magazine.com
+//  @version 1.2
+//  @author Marin Todorov (http://www.underplot.com) and contributors
 //
 
-// Copyright (c) 2012-2014 Marin Todorov, Underplot ltd.
+// Copyright (c) 2012-2015 Marin Todorov, Underplot ltd.
 // This code is distributed under the terms and conditions of the MIT license.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// The MIT License in plain English: http://www.touch-code-magazine.com/JSONModel/MITLicense
+
 
 #import <Foundation/Foundation.h>
 
@@ -22,7 +22,6 @@ enum kCustomizationTypes {
     kNo
     };
 
-typedef enum kCustomizationTypes PropertySetterType;
 typedef enum kCustomizationTypes PropertyGetterType;
 
 /**
@@ -68,10 +67,7 @@ typedef enum kCustomizationTypes PropertyGetterType;
 /** a custom getter for this property, found in the owning model */
 @property (assign, nonatomic) SEL customGetter;
 
-/** The status of property setter introspection in a model */
-@property (assign, nonatomic) PropertySetterType setterType;
-
-/** a custom setter for this property, found in the owning model */
-@property (assign, nonatomic) SEL customSetter;
+/** custom setters for this property, found in the owning model */
+@property (strong, nonatomic) NSMutableDictionary<NSString *, id> *customSetters;
 
 @end

+ 17 - 5
Benchmark/Vendor/JSONModel/JSONModel/JSONModelClassProperty.m

@@ -1,18 +1,18 @@
 //
 //  JSONModelClassProperty.m
 //
-//  @version 1.0.2
-//  @author Marin Todorov, http://www.touch-code-magazine.com
+//  @version 1.2
+//  @author Marin Todorov (http://www.underplot.com) and contributors
 //
 
-// Copyright (c) 2012-2014 Marin Todorov, Underplot ltd.
+// Copyright (c) 2012-2015 Marin Todorov, Underplot ltd.
 // This code is distributed under the terms and conditions of the MIT license.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// The MIT License in plain English: http://www.touch-code-magazine.com/JSONModel/MITLicense
+
 
 #import "JSONModelClassProperty.h"
 
@@ -28,8 +28,20 @@
     if (self.isMutable) [properties addObject:@"Mutable"];
     if (self.convertsOnDemand) [properties addObject:@"ConvertOnDemand"];
     if (self.isStandardJSONType) [properties addObject:@"Standard JSON type"];
-    if (self.customSetter) [properties addObject:[NSString stringWithFormat: @"Setter = %@", NSStringFromSelector(self.customSetter)]];
     if (self.customGetter) [properties addObject:[NSString stringWithFormat: @"Getter = %@", NSStringFromSelector(self.customGetter)]];
+
+    if (self.customSetters)
+    {
+        NSMutableArray *setters = [NSMutableArray array];
+
+        for (id obj in self.customSetters.allValues)
+        {
+            if (obj != [NSNull null])
+                [setters addObject:obj];
+        }
+
+        [properties addObject:[NSString stringWithFormat: @"Setters = [%@]", [setters componentsJoinedByString:@", "]]];
+    }
     
     NSString* propertiesString = @"";
     if (properties.count>0) {

+ 7 - 5
Benchmark/Vendor/JSONModel/JSONModel/JSONModelError.h

@@ -1,18 +1,18 @@
 //
 //  JSONModelError.h
 //
-//  @version 1.0.2
-//  @author Marin Todorov, http://www.touch-code-magazine.com
+//  @version 1.2
+//  @author Marin Todorov (http://www.underplot.com) and contributors
 //
 
-// Copyright (c) 2012-2014 Marin Todorov, Underplot ltd.
+// Copyright (c) 2012-2015 Marin Todorov, Underplot ltd.
 // This code is distributed under the terms and conditions of the MIT license.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// The MIT License in plain English: http://www.touch-code-magazine.com/JSONModel/MITLicense
+
 
 #import <Foundation/Foundation.h>
 
@@ -62,6 +62,8 @@ extern NSString* const kJSONModelKeyPath;
 
 @property (strong, nonatomic) NSHTTPURLResponse* httpResponse;
 
+@property (strong, nonatomic) NSData* responseData;
+
 /**
  * Creates a JSONModelError instance with code kJSONModelErrorInvalidData = 1
  */
@@ -75,7 +77,7 @@ extern NSString* const kJSONModelKeyPath;
 
 /**
  * Creates a JSONModelError instance with code kJSONModelErrorInvalidData = 1
- * @param A description of the type mismatch that was encountered.
+ * @param mismatchDescription description of the type mismatch that was encountered.
  */
 +(id)errorInvalidDataWithTypeMismatch:(NSString*)mismatchDescription;
 

+ 4 - 4
Benchmark/Vendor/JSONModel/JSONModel/JSONModelError.m

@@ -1,18 +1,18 @@
 //
 //  JSONModelError.m
 //
-//  @version 1.0.2
-//  @author Marin Todorov, http://www.touch-code-magazine.com
+//  @version 1.2
+//  @author Marin Todorov (http://www.underplot.com) and contributors
 //
 
-// Copyright (c) 2012-2014 Marin Todorov, Underplot ltd.
+// Copyright (c) 2012-2015 Marin Todorov, Underplot ltd.
 // This code is distributed under the terms and conditions of the MIT license.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// The MIT License in plain English: http://www.touch-code-magazine.com/JSONModel/MITLicense
+
 
 #import "JSONModelError.h"
 

+ 5 - 5
Benchmark/Vendor/JSONModel/JSONModelCategories/NSArray+JSONModel.h

@@ -1,18 +1,18 @@
 //
 //  NSArray+JSONModel.h
 //
-//  @version 1.0.2
-//  @author Marin Todorov, http://www.touch-code-magazine.com
+//  @version 1.2
+//  @author Marin Todorov (http://www.underplot.com) and contributors
 //
 
-// Copyright (c) 2012-2014 Marin Todorov, Underplot ltd.
+// Copyright (c) 2012-2015 Marin Todorov, Underplot ltd.
 // This code is distributed under the terms and conditions of the MIT license.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// The MIT License in plain English: http://www.touch-code-magazine.com/JSONModel/MITLicense
+
 
 
 #import <Foundation/Foundation.h>
@@ -29,7 +29,7 @@
  * 
  * Will return nil if no matching model is found. Will return nil if there's no index property 
  * defined on the models found in the array (will sample the first object, assuming the array 
- * contains homogenous collection of objects)
+ * contains homogeneous collection of objects)
  *
  * @param indexValue the id value to search for
  * @return the found model or nil

+ 4 - 4
Benchmark/Vendor/JSONModel/JSONModelCategories/NSArray+JSONModel.m

@@ -1,18 +1,18 @@
 //
 //  NSArray+JSONModel.m
 //
-//  @version 1.0.2
-//  @author Marin Todorov, http://www.touch-code-magazine.com
+//  @version 1.2
+//  @author Marin Todorov (http://www.underplot.com) and contributors
 //
 
-// Copyright (c) 2012-2014 Marin Todorov, Underplot ltd.
+// Copyright (c) 2012-2015 Marin Todorov, Underplot ltd.
 // This code is distributed under the terms and conditions of the MIT license.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// The MIT License in plain English: http://www.touch-code-magazine.com/JSONModel/MITLicense
+
 
 
 #import "NSArray+JSONModel.h"

+ 5 - 5
Benchmark/Vendor/JSONModel/JSONModelLib.h

@@ -1,18 +1,18 @@
 //
 //  JSONModelLib.h
 //
-//  @version 1.0.2
-//  @author Marin Todorov, http://www.touch-code-magazine.com
+//  @version 1.2
+//  @author Marin Todorov (http://www.underplot.com) and contributors
 //
 
-// Copyright (c) 2012-2014 Marin Todorov, Underplot ltd.
+// Copyright (c) 2012-2015 Marin Todorov, Underplot ltd.
 // This code is distributed under the terms and conditions of the MIT license.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// The MIT License in plain English: http://www.touch-code-magazine.com/JSONModel/MITLicense
+
 
 #import <Foundation/Foundation.h>
 
@@ -32,4 +32,4 @@
 
 //models array
 #import "NSArray+JSONModel.h"
-#import "JSONModelArray.h"
+#import "JSONModelArray.h"

+ 7 - 7
Benchmark/Vendor/JSONModel/JSONModelNetworking/JSONAPI.h

@@ -1,18 +1,18 @@
 //
 //  JSONAPI.h
 //
-//  @version 1.0.2
-//  @author Marin Todorov, http://www.touch-code-magazine.com
+//  @version 1.2
+//  @author Marin Todorov (http://www.underplot.com) and contributors
 //
 
-// Copyright (c) 2012-2014 Marin Todorov, Underplot ltd.
+// Copyright (c) 2012-2015 Marin Todorov, Underplot ltd.
 // This code is distributed under the terms and conditions of the MIT license.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// The MIT License in plain English: http://www.touch-code-magazine.com/JSONModel/MITLicense
+
 
 #import <Foundation/Foundation.h>
 #import "JSONHTTPClient.h"
@@ -46,7 +46,7 @@
 
 /** @name Making GET API requests */
 /**
- * Makes an asynchronious GET request to the API
+ * Makes an asynchronous GET request to the API
  * @param path the URL path to add to the base API URL for this HTTP call
  * @param params the variables to pass to the API
  * @param completeBlock a JSONObjectBlock block to execute upon completion
@@ -68,7 +68,7 @@
 
 /** @name JSON RPC methods */
 /**
- * Makes an asynchronious JSON RPC request to the API. Read more: http://www.jsonrpc.org
+ * Makes an asynchronous JSON RPC request to the API. Read more: http://www.jsonrpc.org
  * @param method the HTTP method name; GET or POST only
  * @param args the list of arguments to pass to the API
  * @param completeBlock JSONObjectBlock to execute upon completion
@@ -77,7 +77,7 @@
 
 /** @name JSON RPC (2.0) request method */
 /**
- * Makes an asynchronious JSON RPC 2.0 request to the API. Read more: http://www.jsonrpc.org
+ * Makes an asynchronous JSON RPC 2.0 request to the API. Read more: http://www.jsonrpc.org
  * @param method the HTTP method name; GET or POST only
  * @param params the params to pass to the API - an NSArray or an NSDictionary, 
  * depending whether you're using named or unnamed parameters

+ 4 - 4
Benchmark/Vendor/JSONModel/JSONModelNetworking/JSONAPI.m

@@ -1,18 +1,18 @@
 //
 //  JSONAPI.m
 //
-//  @version 1.0.2
-//  @author Marin Todorov, http://www.touch-code-magazine.com
+//  @version 1.2
+//  @author Marin Todorov (http://www.underplot.com) and contributors
 //
 
-// Copyright (c) 2012-2014 Marin Todorov, Underplot ltd.
+// Copyright (c) 2012-2015 Marin Todorov, Underplot ltd.
 // This code is distributed under the terms and conditions of the MIT license.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// The MIT License in plain English: http://www.touch-code-magazine.com/JSONModel/MITLicense
+
 
 #import "JSONAPI.h"
 

+ 10 - 10
Benchmark/Vendor/JSONModel/JSONModelNetworking/JSONHTTPClient.h

@@ -1,18 +1,18 @@
 //
 //  JSONModelHTTPClient.h
 //
-//  @version 1.0.2
-//  @author Marin Todorov, http://www.touch-code-magazine.com
+//  @version 1.2
+//  @author Marin Todorov (http://www.underplot.com) and contributors
 //
 
-// Copyright (c) 2012-2014 Marin Todorov, Underplot ltd.
+// Copyright (c) 2012-2015 Marin Todorov, Underplot ltd.
 // This code is distributed under the terms and conditions of the MIT license.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// The MIT License in plain English: http://www.touch-code-magazine.com/JSONModel/MITLicense
+
 
 #import "JSONModel.h"
 
@@ -33,7 +33,7 @@ extern NSString* const kContentTypeWWWEncoded;
 
 /**
  * A block type to handle incoming JSON object and an error. 
- * You pass it to methods which fetch JSON asynchroniously. When the operation is finished
+ * You pass it to methods which fetch JSON asynchronously. When the operation is finished
  * you receive back the fetched JSON (or nil) and an error (or nil)
  *
  * @param json object derived from a JSON string
@@ -55,7 +55,7 @@ typedef void (^JSONObjectBlock)(id json, JSONModelError* err);
 
 /** @name HTTP Client configuration */
 /**
- * Returns a modifyable dictionary of the client's default HTTP headers.
+ * Returns a modifiable dictionary of the client's default HTTP headers.
  * @result A mutable dictionary of pairs - HTTP header names and values.
  * @discussion You can use the result to modify the http client headers like so:
  * <pre>
@@ -86,7 +86,7 @@ typedef void (^JSONObjectBlock)(id json, JSONModelError* err);
 +(void)setTimeoutInSeconds:(int)seconds;
 
 /**
- * A method to set the default conent type of the request body
+ * A method to set the default content type of the request body
  * By default the content type is set to kContentTypeAutomatic
  * which checks the body request and decides between "application/json"
  * and "application/x-www-form-urlencoded"
@@ -94,9 +94,9 @@ typedef void (^JSONObjectBlock)(id json, JSONModelError* err);
 +(void)setRequestContentType:(NSString*)contentTypeString;
 
 /////////////////////////////////////////////////////////////////////////////////////////////
-#pragma mark - GET asynchronious JSON calls
+#pragma mark - GET asynchronous JSON calls
 
-/** @name Making asynchronious HTTP requests */
+/** @name Making asynchronous HTTP requests */
 /**
  * Makes GET request to the given URL address and fetches a JSON response.
  * @param urlString the URL as a string
@@ -145,7 +145,7 @@ typedef void (^JSONObjectBlock)(id json, JSONModelError* err);
 +(void)JSONFromURLWithString:(NSString*)urlString method:(NSString*)method params:(NSDictionary *)params orBodyData:(NSData*)bodyData headers:(NSDictionary*)headers completion:(JSONObjectBlock)completeBlock;
 
 /////////////////////////////////////////////////////////////////////////////////////////////
-#pragma mark - POST synchronious JSON calls
+#pragma mark - POST asynchronous JSON calls
 
 /**
  * Makes POST request to the given URL address and fetches a JSON response. Sends the bodyString param as the POST request body.

+ 78 - 83
Benchmark/Vendor/JSONModel/JSONModelNetworking/JSONHTTPClient.m

@@ -1,21 +1,23 @@
 //
 //  JSONModelHTTPClient.m
 //
-//  @version 1.0.2
-//  @author Marin Todorov, http://www.touch-code-magazine.com
+//  @version 1.2
+//  @author Marin Todorov (http://www.underplot.com) and contributors
 //
 
-// Copyright (c) 2012-2014 Marin Todorov, Underplot ltd.
+// Copyright (c) 2012-2015 Marin Todorov, Underplot ltd.
 // This code is distributed under the terms and conditions of the MIT license.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// The MIT License in plain English: http://www.touch-code-magazine.com/JSONModel/MITLicense
+
 
 #import "JSONHTTPClient.h"
 
+typedef void (^RequestResultBlock)(NSData *data, JSONModelError *error);
+
 #pragma mark - constants
 NSString* const kHTTPMethodGET = @"GET";
 NSString* const kHTTPMethodPOST = @"POST";
@@ -118,17 +120,24 @@ static NSString* requestContentType = nil;
     }
     
     NSAssert([value isKindOfClass:[NSString class]], @"request parameters can be only of NSString or NSNumber classes. '%@' is of class %@.", value, [value class]);
-        
+
+    NSString *str = (NSString *)value;
+
+#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0 || __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_9
+    return [str stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
+
+#else
     return (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(
                                                                                  NULL,
-                                                                                 (__bridge CFStringRef) value,
+                                                                                 (__bridge CFStringRef)str,
                                                                                  NULL,
                                                                                  (CFStringRef)@"!*'();:@&=+$,/?%#[]",
                                                                                  kCFStringEncodingUTF8));
+#endif
 }
 
 #pragma mark - networking worker methods
-+(NSData*)syncRequestDataFromURL:(NSURL*)url method:(NSString*)method requestBody:(NSData*)bodyData headers:(NSDictionary*)headers etag:(NSString**)etag error:(JSONModelError**)err
++(void)requestDataFromURL:(NSURL*)url method:(NSString*)method requestBody:(NSData*)bodyData headers:(NSDictionary*)headers handler:(RequestResultBlock)handler
 {
     NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: url
                                                                 cachePolicy: defaultCachePolicy
@@ -160,50 +169,54 @@ static NSString* requestContentType = nil;
         [request setHTTPBody: bodyData];
         [request setValue:[NSString stringWithFormat:@"%lu", (unsigned long)bodyData.length] forHTTPHeaderField:@"Content-Length"];
     }
-    
-    //prepare output
-	NSHTTPURLResponse* response = nil;
-    
-    //fire the request
-	NSData *responseData = [NSURLConnection sendSynchronousRequest: request
-                                                 returningResponse: &response
-                                                             error: err];
-    //convert an NSError to a JSONModelError
-    if (*err != nil) {
-        NSError* errObj = *err;
-        *err = [JSONModelError errorWithDomain:errObj.domain code:errObj.code userInfo:errObj.userInfo];
-    }
-    
-    //special case for http error code 401
-    if ([*err code] == kCFURLErrorUserCancelledAuthentication) {
-        response = [[NSHTTPURLResponse alloc] initWithURL:url
-                                               statusCode:401
-                                              HTTPVersion:@"HTTP/1.1"
-                                             headerFields:@{}];
-    }
-    
-    //if not OK status set the err to a JSONModelError instance
-	if (response.statusCode >= 300 || response.statusCode < 200) {
-        //create a new error
-        if (*err==nil) *err = [JSONModelError errorBadResponse];
-    }
-    
-    //if there was an error, include the HTTP response and return
-    if (*err) {
-        //assign the response to the JSONModel instance
-        [*err setHttpResponse: [response copy]];
+
+    void (^completionHandler)(NSData *, NSURLResponse *, NSError *) = ^(NSData *data, NSURLResponse *origResponse, NSError *origError) {
+        NSHTTPURLResponse *response = (NSHTTPURLResponse *)origResponse;
+        JSONModelError *error = nil;
+
+        //convert an NSError to a JSONModelError
+        if (origError) {
+            error = [JSONModelError errorWithDomain:origError.domain code:origError.code userInfo:origError.userInfo];
+        }
+
+        //special case for http error code 401
+        if (error.code == NSURLErrorUserCancelledAuthentication) {
+            response = [[NSHTTPURLResponse alloc] initWithURL:url statusCode:401 HTTPVersion:@"HTTP/1.1" headerFields:@{}];
+        }
+
+        //if not OK status set the err to a JSONModelError instance
+        if (!error && (response.statusCode >= 300 || response.statusCode < 200)) {
+            error = [JSONModelError errorBadResponse];
+        }
+
+        //if there was an error, assign the response to the JSONModel instance
+        if (error) {
+            error.httpResponse = [response copy];
+        }
 
         //empty respone, return nil instead
-        if ([responseData length]<1) {
-            return nil;
+        if (!data.length) {
+            data = nil;
         }
-    }
-    
-    //return the data fetched from web
-    return responseData;
+        
+        handler(data, error);
+    };
+
+    //fire the request
+
+#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0 || __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_10
+    NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:completionHandler];
+    [task resume];
+#else
+    NSOperationQueue *queue = [NSOperationQueue new];
+
+    [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
+        completionHandler(data, response, error);
+    }];
+#endif
 }
 
-+(NSData*)syncRequestDataFromURL:(NSURL*)url method:(NSString*)method params:(NSDictionary*)params headers:(NSDictionary*)headers etag:(NSString**)etag error:(JSONModelError**)err
++(void)requestDataFromURL:(NSURL*)url method:(NSString*)method params:(NSDictionary*)params headers:(NSDictionary*)headers handler:(RequestResultBlock)handler
 {
     //create the request body
     NSMutableString* paramsString = nil;
@@ -231,12 +244,11 @@ static NSString* requestContentType = nil;
     }
     
     //call the more general synq request method
-    return [self syncRequestDataFromURL: url
-                                 method: method
-                            requestBody: [method isEqualToString:kHTTPMethodPOST]?[paramsString dataUsingEncoding:NSUTF8StringEncoding]:nil
-                                headers: headers
-                                   etag: etag
-                                  error: err];
+    [self requestDataFromURL: url
+                      method: method
+                 requestBody: [method isEqualToString:kHTTPMethodPOST]?[paramsString dataUsingEncoding:NSUTF8StringEncoding]:nil
+                     headers: headers
+                       handler:handler];
 }
 
 #pragma mark - Async network request
@@ -262,36 +274,9 @@ static NSString* requestContentType = nil;
 
 +(void)JSONFromURLWithString:(NSString*)urlString method:(NSString*)method params:(NSDictionary *)params orBodyData:(NSData*)bodyData headers:(NSDictionary*)headers completion:(JSONObjectBlock)completeBlock
 {
-    NSDictionary* customHeaders = headers;
-
-    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
-        
+    RequestResultBlock handler = ^(NSData *responseData, JSONModelError *error) {
         id jsonObject = nil;
-        JSONModelError* error = nil;
-        NSData* responseData = nil;
-        NSString* etag = nil;
-        
-        @try {
-            if (bodyData) {
-                responseData = [self syncRequestDataFromURL: [NSURL URLWithString:urlString]
-                                                     method: method
-                                                requestBody: bodyData
-                                                    headers: customHeaders
-                                                       etag: &etag
-                                                      error: &error];
-            } else {
-                responseData = [self syncRequestDataFromURL: [NSURL URLWithString:urlString]
-                                                     method: method
-                                                     params: params
-                                                    headers: customHeaders
-                                                       etag: &etag
-                                                      error: &error];
-            }
-        }
-        @catch (NSException *exception) {
-            error = [JSONModelError errorBadResponse];
-        }
-        
+
         //step 3: if there's no response so far, return a basic error
         if (!responseData && !error) {
             //check for false response, but no network error
@@ -310,8 +295,10 @@ static NSString* requestContentType = nil;
         }
         //step 4.5: cover an edge case in which meaningful content is return along an error HTTP status code
         else if (error && responseData && jsonObject==nil) {
-            //try to get the JSON object, while preserving the origianl error object
+            //try to get the JSON object, while preserving the original error object
             jsonObject = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:nil];
+            //keep responseData just in case it contains error information
+            error.responseData = responseData;
         }
         
         //step 5: invoke the complete block
@@ -320,7 +307,15 @@ static NSString* requestContentType = nil;
                 completeBlock(jsonObject, error);
             }
         });
-    });
+    };
+
+    NSURL *url = [NSURL URLWithString:urlString];
+
+    if (bodyData) {
+        [self requestDataFromURL:url method:method requestBody:bodyData headers:headers handler:handler];
+    } else {
+        [self requestDataFromURL:url method:method params:params headers:headers handler:handler];
+    }
 }
 
 #pragma mark - request aliases

+ 6 - 6
Benchmark/Vendor/JSONModel/JSONModelNetworking/JSONModel+networking.h

@@ -1,18 +1,18 @@
 //
 //  JSONModel+networking.h
 //
-//  @version 1.0.2
-//  @author Marin Todorov, http://www.touch-code-magazine.com
+//  @version 1.2
+//  @author Marin Todorov (http://www.underplot.com) and contributors
 //
 
-// Copyright (c) 2012-2014 Marin Todorov, Underplot ltd.
+// Copyright (c) 2012-2015 Marin Todorov, Underplot ltd.
 // This code is distributed under the terms and conditions of the MIT license.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// The MIT License in plain English: http://www.touch-code-magazine.com/JSONModel/MITLicense
+
 
 #import "JSONModel.h"
 #import "JSONHTTPClient.h"
@@ -28,9 +28,9 @@ typedef void (^JSONModelBlock)(id model, JSONModelError* err);
 @interface JSONModel(Networking)
 
 @property (assign, nonatomic) BOOL isLoading;
-/** @name Asynchroniously create a model over the network */
+/** @name Asynchronously create a model over the network */
 /**
- * Asynchroniously create a model over the network. Create a new model instance and initialize it with the JSON fetched from the given URL
+ * Asynchronously create a model over the network. Create a new model instance and initialize it with the JSON fetched from the given URL
  * @param urlString the absolute URL address of the JSON feed as a string
  * @param completeBlock JSONModelBlock executed upon completion. The JSONModelBlock type is defined as: void (^JSONModelBlock)(JSONModel* model, JSONModelError* e); the first parameter is the initialized model or nil, 
  * and second parameter holds the model initialization error, if any

+ 4 - 4
Benchmark/Vendor/JSONModel/JSONModelNetworking/JSONModel+networking.m

@@ -1,18 +1,18 @@
 //
 //  JSONModel+networking.m
 //
-//  @version 1.0.2
-//  @author Marin Todorov, http://www.touch-code-magazine.com
+//  @version 1.2
+//  @author Marin Todorov (http://www.underplot.com) and contributors
 //
 
-// Copyright (c) 2012-2014 Marin Todorov, Underplot ltd.
+// Copyright (c) 2012-2015 Marin Todorov, Underplot ltd.
 // This code is distributed under the terms and conditions of the MIT license.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// The MIT License in plain English: http://www.touch-code-magazine.com/JSONModel/MITLicense
+
 
 #import "JSONModel+networking.h"
 #import "JSONHTTPClient.h"

+ 13 - 6
Benchmark/Vendor/JSONModel/JSONModelTransformations/JSONKeyMapper.h

@@ -1,18 +1,18 @@
 //
 //  JSONKeyMapper.h
 //
-//  @version 1.0.2
-//  @author Marin Todorov, http://www.touch-code-magazine.com
+//  @version 1.2
+//  @author Marin Todorov (http://www.underplot.com) and contributors
 //
 
-// Copyright (c) 2012-2014 Marin Todorov, Underplot ltd.
+// Copyright (c) 2012-2015 Marin Todorov, Underplot ltd.
 // This code is distributed under the terms and conditions of the MIT license.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// The MIT License in plain English: http://www.touch-code-magazine.com/JSONModel/MITLicense
+
 
 #import <Foundation/Foundation.h>
 
@@ -50,14 +50,14 @@ typedef NSString* (^JSONModelKeyMapBlock)(NSString* keyName);
  */
 @interface JSONKeyMapper : NSObject
 
-/** @name Name convertors */
+/** @name Name converters */
 /** Block, which takes in a JSON key and converts it to the corresponding property name */
 @property (readonly, nonatomic) JSONModelKeyMapBlock JSONToModelKeyBlock;
 
 /** Block, which takes in a property name and converts it to the corresponding JSON key name */
 @property (readonly, nonatomic) JSONModelKeyMapBlock modelToJSONKeyBlock;
 
-/** Combined convertor method
+/** Combined converter method
 * @param value the source name
 * @param importing YES invokes JSONToModelKeyBlock, NO - modelToJSONKeyBlock
 * @return JSONKeyMapper instance
@@ -92,4 +92,11 @@ typedef NSString* (^JSONModelKeyMapBlock)(NSString* keyName);
 +(instancetype)mapperFromUnderscoreCaseToCamelCase;
 
 +(instancetype)mapperFromUpperCaseToLowerCase;
+
+/**
+ * Creates a JSONKeyMapper based on a built-in JSONKeyMapper, with specific exceptions.
+ * Use the original JSON key names as keys, and your JSONModel property names as values.
+ */
++ (instancetype)mapper:(JSONKeyMapper *)baseKeyMapper withExceptions:(NSDictionary *)exceptions;
+
 @end

+ 88 - 25
Benchmark/Vendor/JSONModel/JSONModelTransformations/JSONKeyMapper.m

@@ -1,24 +1,26 @@
 //
 //  JSONKeyMapper.m
 //
-//  @version 1.0.2
-//  @author Marin Todorov, http://www.touch-code-magazine.com
+//  @version 1.2
+//  @author Marin Todorov (http://www.underplot.com) and contributors
 //
 
-// Copyright (c) 2012-2014 Marin Todorov, Underplot ltd.
+// Copyright (c) 2012-2015 Marin Todorov, Underplot ltd.
 // This code is distributed under the terms and conditions of the MIT license.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// The MIT License in plain English: http://www.touch-code-magazine.com/JSONModel/MITLicense
+
 
 #import "JSONKeyMapper.h"
+#import <libkern/OSAtomic.h>
 
 @interface JSONKeyMapper()
 @property (nonatomic, strong) NSMutableDictionary *toModelMap;
 @property (nonatomic, strong) NSMutableDictionary *toJSONMap;
+@property (nonatomic, assign) OSSpinLock lock;
 @end
 
 @implementation JSONKeyMapper
@@ -40,59 +42,89 @@
     self = [self init];
     
     if (self) {
-        __weak JSONKeyMapper *myself = self;
-        //the json to model convertion block
-        _JSONToModelKeyBlock = ^NSString*(NSString* keyName) {
+        
+        __weak JSONKeyMapper* weakSelf = self;
+        
+        _JSONToModelKeyBlock = [^NSString* (NSString* keyName) {
+            
+            __strong JSONKeyMapper* strongSelf = weakSelf;
 
             //try to return cached transformed key
-            if (myself.toModelMap[keyName]) return myself.toModelMap[keyName];
+            if (strongSelf.toModelMap[keyName]) {
+                return strongSelf.toModelMap[keyName];
+            }
             
             //try to convert the key, and store in the cache
             NSString* result = toModel(keyName);
-            myself.toModelMap[keyName] = result;
+            
+            OSSpinLockLock(&strongSelf->_lock);
+            strongSelf.toModelMap[keyName] = result;
+            OSSpinLockUnlock(&strongSelf->_lock);
+            
             return result;
-        };
+            
+        } copy];
         
-        _modelToJSONKeyBlock = ^NSString*(NSString* keyName) {
+        _modelToJSONKeyBlock = [^NSString* (NSString* keyName) {
+            
+            __strong JSONKeyMapper *strongSelf = weakSelf;
             
             //try to return cached transformed key
-            if (myself.toJSONMap[keyName]) return myself.toJSONMap[keyName];
+            if (strongSelf.toJSONMap[keyName]) {
+                return strongSelf.toJSONMap[keyName];
+            }
             
             //try to convert the key, and store in the cache
             NSString* result = toJSON(keyName);
-            myself.toJSONMap[keyName] = result;
+            
+            OSSpinLockLock(&strongSelf->_lock);
+            strongSelf.toJSONMap[keyName] = result;
+            OSSpinLockUnlock(&strongSelf->_lock);
+            
             return result;
             
-        };
+        } copy];
         
     }
     
     return self;
 }
 
--(instancetype)initWithDictionary:(NSDictionary*)map
+-(instancetype)initWithDictionary:(NSDictionary *)map
 {
     self = [super init];
     if (self) {
-        //initialize
-
-        NSMutableDictionary* userToModelMap = [NSMutableDictionary dictionaryWithDictionary: map];
-        NSMutableDictionary* userToJSONMap  = [NSMutableDictionary dictionaryWithObjects:map.allKeys forKeys:map.allValues];
         
-        _JSONToModelKeyBlock = ^NSString*(NSString* keyName) {
-            NSString* result = [userToModelMap valueForKeyPath: keyName];
-            return result?result:keyName;
+        NSDictionary *userToModelMap = [map copy];
+        NSDictionary *userToJSONMap  = [self swapKeysAndValuesInDictionary:map];
+        
+        _JSONToModelKeyBlock = ^NSString *(NSString *keyName) {
+            NSString *result = [userToModelMap valueForKeyPath:keyName];
+            return result ? result : keyName;
         };
         
-        _modelToJSONKeyBlock = ^NSString*(NSString* keyName) {
-            NSString* result = [userToJSONMap valueForKeyPath: keyName];
-            return result?result:keyName;
+        _modelToJSONKeyBlock = ^NSString *(NSString *keyName) {
+            NSString *result = [userToJSONMap valueForKeyPath:keyName];
+            return result ? result : keyName;
         };
     }
     
     return self;
 }
 
+- (NSDictionary *)swapKeysAndValuesInDictionary:(NSDictionary *)dictionary
+{
+    NSMutableDictionary *swapped = [NSMutableDictionary new];
+    
+    [dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) {
+        NSAssert([value isKindOfClass:[NSString class]], @"Expect keys and values to be NSString");
+        NSAssert([key isKindOfClass:[NSString class]], @"Expect keys and values to be NSString");
+        swapped[value] = key;
+    }];
+    
+    return swapped;
+}
+
 -(NSString*)convertValue:(NSString*)value isImportingToModel:(BOOL)importing
 {
     return !importing?_JSONToModelKeyBlock(value):_modelToJSONKeyBlock(value);
@@ -171,4 +203,35 @@
 
 }
 
++ (instancetype)mapper:(JSONKeyMapper *)baseKeyMapper withExceptions:(NSDictionary *)exceptions
+{
+    NSArray *keys = exceptions.allKeys;
+    NSArray *values = [exceptions objectsForKeys:keys notFoundMarker:[NSNull null]];
+
+    NSDictionary *toModelMap = [NSDictionary dictionaryWithObjects:values forKeys:keys];
+    NSDictionary *toJsonMap = [NSDictionary dictionaryWithObjects:keys forKeys:values];
+
+    JSONModelKeyMapBlock toModel = ^NSString *(NSString *keyName) {
+        if (!keyName)
+            return nil;
+
+        if (toModelMap[keyName])
+            return toModelMap[keyName];
+
+        return baseKeyMapper.JSONToModelKeyBlock(keyName);
+    };
+
+    JSONModelKeyMapBlock toJson = ^NSString *(NSString *keyName) {
+        if (!keyName)
+            return nil;
+
+        if (toJsonMap[keyName])
+            return toJsonMap[keyName];
+
+        return baseKeyMapper.modelToJSONKeyBlock(keyName);
+    };
+
+    return [[self alloc] initWithJSONToModelBlock:toModel modelToJSONBlock:toJson];
+}
+
 @end

+ 11 - 11
Benchmark/Vendor/JSONModel/JSONModelTransformations/JSONValueTransformer.h

@@ -1,25 +1,25 @@
 //
 //  JSONValueTransformer.h
 //
-//  @version 1.0.2
-//  @author Marin Todorov, http://www.touch-code-magazine.com
+//  @version 1.2
+//  @author Marin Todorov (http://www.underplot.com) and contributors
 //
 
-// Copyright (c) 2012-2014 Marin Todorov, Underplot ltd.
+// Copyright (c) 2012-2015 Marin Todorov, Underplot ltd.
 // This code is distributed under the terms and conditions of the MIT license.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// The MIT License in plain English: http://www.touch-code-magazine.com/JSONModel/MITLicense
+
 
 #import <Foundation/Foundation.h>
 #import "JSONModelArray.h"
 
 /////////////////////////////////////////////////////////////////////////////////////////////
 
-#pragma mark - extern definitons
+#pragma mark - extern definitions
 /**
  * Boolean function to check for null values. Handy when you need to both check
  * for nil and [NSNUll null]
@@ -48,10 +48,10 @@ extern BOOL isNull(id value);
 
 /** @name Resolving cluster class names */
 /**
- * This method returns the ubmrella class for any standard class cluster members.
+ * This method returns the umbrella class for any standard class cluster members.
  * For example returns NSString when given as input NSString, NSMutableString, __CFString and __CFConstantString
  * The method currently looksup a pre-defined list.
- * @param sourceClass the class to get the umrella class for
+ * @param sourceClass the class to get the umbrella class for
  * @return Class
  */
 +(Class)classByResolvingClusterClasses:(Class)sourceClass;
@@ -59,7 +59,7 @@ extern BOOL isNull(id value);
 #pragma mark - NSMutableString <-> NSString
 /** @name Transforming to Mutable copies */
 /**
- * Trasnforms a string value to a mutable string value
+ * Transforms a string value to a mutable string value
  * @param string incoming string
  * @return mutable string
  */
@@ -67,7 +67,7 @@ extern BOOL isNull(id value);
 
 #pragma mark - NSMutableArray <-> NSArray
 /**
- * Trasnforms an array to a mutable array
+ * Transforms an array to a mutable array
  * @param array incoming array
  * @return mutable array
  */
@@ -75,7 +75,7 @@ extern BOOL isNull(id value);
 
 #pragma mark - NS(Mutable)Array <- JSONModelArray
 /**
- * Trasnforms an array to a JSONModelArray
+ * Transforms an array to a JSONModelArray
  * @param array incoming array
  * @return JSONModelArray
  */
@@ -84,7 +84,7 @@ extern BOOL isNull(id value);
 
 #pragma mark - NSMutableDictionary <-> NSDictionary
 /**
- * Trasnforms a dictionary to a mutable dictionary
+ * Transforms a dictionary to a mutable dictionary
  * @param dict incoming dictionary
  * @return mutable dictionary
  */

+ 9 - 7
Benchmark/Vendor/JSONModel/JSONModelTransformations/JSONValueTransformer.m

@@ -1,18 +1,18 @@
 //
 //  JSONValueTransformer.m
 //
-//  @version 1.0.2
-//  @author Marin Todorov, http://www.touch-code-magazine.com
+//  @version 1.2
+//  @author Marin Todorov (http://www.underplot.com) and contributors
 //
 
-// Copyright (c) 2012-2014 Marin Todorov, Underplot ltd.
+// Copyright (c) 2012-2015 Marin Todorov, Underplot ltd.
 // This code is distributed under the terms and conditions of the MIT license.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// The MIT License in plain English: http://www.touch-code-magazine.com/JSONModel/MITLicense
+
 
 #import "JSONValueTransformer.h"
 #import "JSONModelArray.h"
@@ -33,7 +33,7 @@ extern BOOL isNull(id value)
     self = [super init];
     if (self) {
         _primitivesNames = @{@"f":@"float", @"i":@"int", @"d":@"double", @"l":@"long", @"c":@"BOOL", @"s":@"short", @"q":@"long",
-                             //and some famos aliases of primitive types
+                             //and some famous aliases of primitive types
                              // BOOL is now "B" on iOS __LP64 builds
                              @"I":@"NSInteger", @"Q":@"NSUInteger", @"B":@"BOOL",
                              
@@ -179,7 +179,7 @@ extern BOOL isNull(id value)
 #pragma mark - string <-> number
 -(NSNumber*)NSNumberFromNSString:(NSString*)string
 {
-    return [NSNumber numberWithFloat: [string doubleValue]];
+    return [NSNumber numberWithDouble:[string doubleValue]];
 }
 
 -(NSString*)NSStringFromNSNumber:(NSNumber*)number
@@ -200,7 +200,9 @@ extern BOOL isNull(id value)
 #pragma mark - string <-> url
 -(NSURL*)NSURLFromNSString:(NSString*)string
 {
-    return [NSURL URLWithString:[string stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
+    // do not change this behavior - there are other ways of overriding it
+    // see: https://github.com/icanzilb/JSONModel/pull/119
+    return [NSURL URLWithString:string];
 }
 
 -(NSString*)JSONObjectFromNSURL:(NSURL*)url

+ 1 - 0
Benchmark/Vendor/MJExtension/MJExtension.h

@@ -12,3 +12,4 @@
 #import "NSObject+MJClass.h"
 #import "NSObject+MJKeyValue.h"
 #import "NSString+MJExtension.h"
+#import "MJExtensionConst.h"

+ 14 - 5
Benchmark/Vendor/MJExtension/MJExtensionConst.h

@@ -8,17 +8,26 @@
 #define MJExtensionDeprecated(instead) NS_DEPRECATED(2_0, 2_0, 2_0, 2_0, instead)
 
 // 构建错误
-#define MJExtensionBuildError(error, msg) \
-if (error) *error = [NSError errorWithDomain:msg code:250 userInfo:nil];
+#define MJExtensionBuildError(clazz, msg) \
+NSError *error = [NSError errorWithDomain:msg code:250 userInfo:nil]; \
+[clazz setMj_error:error];
+
+// 日志输出
+#ifdef DEBUG
+#define MJExtensionLog(...) NSLog(__VA_ARGS__)
+#else
+#define MJExtensionLog(...)
+#endif
 
 /**
  * 断言
  * @param condition   条件
  * @param returnValue 返回值
  */
-#define MJExtensionAssertError(condition, returnValue, error, msg) \
+#define MJExtensionAssertError(condition, returnValue, clazz, msg) \
+[clazz setMj_error:nil]; \
 if ((condition) == NO) { \
-    MJExtensionBuildError(error, msg); \
+    MJExtensionBuildError(clazz, msg); \
     return returnValue;\
 }
 
@@ -51,7 +60,7 @@ MJExtensionAssert2((param) != nil, returnValue)
 #define MJLogAllIvars \
 -(NSString *)description \
 { \
-    return [self keyValues].description; \
+    return [self mj_keyValues].description; \
 }
 #define MJExtensionLogAllProperties MJLogAllIvars
 

+ 9 - 2
Benchmark/Vendor/MJExtension/MJProperty.m

@@ -9,6 +9,7 @@
 #import "MJProperty.h"
 #import "MJFoundation.h"
 #import "MJExtensionConst.h"
+#import <objc/message.h>
 
 @interface MJProperty()
 @property (strong, nonatomic) NSMutableDictionary *propertyKeysDict;
@@ -58,9 +59,15 @@
     
     // 2.成员类型
     NSString *attrs = @(property_getAttributes(property));
+    NSUInteger dotLoc = [attrs rangeOfString:@","].location;
+    NSString *code = nil;
     NSUInteger loc = 1;
-    NSUInteger len = [attrs rangeOfString:@","].location - loc;
-    _type = [MJPropertyType cachedTypeWithCode:[attrs substringWithRange:NSMakeRange(loc, len)]];
+    if (dotLoc == NSNotFound) { // 没有,
+        code = [attrs substringFromIndex:loc];
+    } else {
+        code = [attrs substringWithRange:NSMakeRange(loc, dotLoc - loc)];
+    }
+    _type = [MJPropertyType cachedTypeWithCode:code];
 }
 
 /**

+ 4 - 1
Benchmark/Vendor/MJExtension/MJPropertyKey.m

@@ -15,7 +15,10 @@
     if ([object isKindOfClass:[NSDictionary class]] && self.type == MJPropertyKeyTypeDictionary) {
         return object[self.name];
     } else if ([object isKindOfClass:[NSArray class]] && self.type == MJPropertyKeyTypeArray) {
-        return [object count] ? object[self.name.intValue] : nil;
+        NSArray *array = object;
+        NSUInteger index = self.name.intValue;
+        if (index < array.count) return array[index];
+        return nil;
     }
     return nil;
 }

+ 11 - 11
Benchmark/Vendor/MJExtension/NSObject+MJClass.h

@@ -30,8 +30,8 @@ typedef NSArray * (^MJIgnoredCodingPropertyNames)();
 /**
  *  遍历所有的类
  */
-+ (void)enumerateClasses:(MJClassesEnumeration)enumeration;
-+ (void)enumerateAllClasses:(MJClassesEnumeration)enumeration;
++ (void)mj_enumerateClasses:(MJClassesEnumeration)enumeration;
++ (void)mj_enumerateAllClasses:(MJClassesEnumeration)enumeration;
 
 #pragma mark - 属性白名单配置
 /**
@@ -39,12 +39,12 @@ typedef NSArray * (^MJIgnoredCodingPropertyNames)();
  *
  *  @param allowedPropertyNames          这个数组中的属性名才会进行字典和模型的转换
  */
-+ (void)setupAllowedPropertyNames:(MJAllowedPropertyNames)allowedPropertyNames;
++ (void)mj_setupAllowedPropertyNames:(MJAllowedPropertyNames)allowedPropertyNames;
 
 /**
  *  这个数组中的属性名才会进行字典和模型的转换
  */
-+ (NSMutableArray *)totalAllowedPropertyNames;
++ (NSMutableArray *)mj_totalAllowedPropertyNames;
 
 #pragma mark - 属性黑名单配置
 /**
@@ -52,12 +52,12 @@ typedef NSArray * (^MJIgnoredCodingPropertyNames)();
  *
  *  @param ignoredPropertyNames          这个数组中的属性名将会被忽略:不进行字典和模型的转换
  */
-+ (void)setupIgnoredPropertyNames:(MJIgnoredPropertyNames)ignoredPropertyNames;
++ (void)mj_setupIgnoredPropertyNames:(MJIgnoredPropertyNames)ignoredPropertyNames;
 
 /**
  *  这个数组中的属性名将会被忽略:不进行字典和模型的转换
  */
-+ (NSMutableArray *)totalIgnoredPropertyNames;
++ (NSMutableArray *)mj_totalIgnoredPropertyNames;
 
 #pragma mark - 归档属性白名单配置
 /**
@@ -65,12 +65,12 @@ typedef NSArray * (^MJIgnoredCodingPropertyNames)();
  *
  *  @param allowedCodingPropertyNames          这个数组中的属性名才会进行归档
  */
-+ (void)setupAllowedCodingPropertyNames:(MJAllowedCodingPropertyNames)allowedCodingPropertyNames;
++ (void)mj_setupAllowedCodingPropertyNames:(MJAllowedCodingPropertyNames)allowedCodingPropertyNames;
 
 /**
  *  这个数组中的属性名才会进行字典和模型的转换
  */
-+ (NSMutableArray *)totalAllowedCodingPropertyNames;
++ (NSMutableArray *)mj_totalAllowedCodingPropertyNames;
 
 #pragma mark - 归档属性黑名单配置
 /**
@@ -78,13 +78,13 @@ typedef NSArray * (^MJIgnoredCodingPropertyNames)();
  *
  *  @param ignoredCodingPropertyNames          这个数组中的属性名将会被忽略:不进行归档
  */
-+ (void)setupIgnoredCodingPropertyNames:(MJIgnoredCodingPropertyNames)ignoredCodingPropertyNames;
++ (void)mj_setupIgnoredCodingPropertyNames:(MJIgnoredCodingPropertyNames)ignoredCodingPropertyNames;
 
 /**
  *  这个数组中的属性名将会被忽略:不进行归档
  */
-+ (NSMutableArray *)totalIgnoredCodingPropertyNames;
++ (NSMutableArray *)mj_totalIgnoredCodingPropertyNames;
 
 #pragma mark - 内部使用
-+ (void)setupBlockReturnValue:(id (^)())block key:(const char *)key;
++ (void)mj_setupBlockReturnValue:(id (^)())block key:(const char *)key;
 @end

+ 21 - 21
Benchmark/Vendor/MJExtension/NSObject+MJClass.m

@@ -20,7 +20,7 @@ static const char MJIgnoredCodingPropertyNamesKey = '\0';
 
 @implementation NSObject (MJClass)
 
-+ (void)enumerateClasses:(MJClassesEnumeration)enumeration
++ (void)mj_enumerateClasses:(MJClassesEnumeration)enumeration
 {
     // 1.没有block就直接返回
     if (enumeration == nil) return;
@@ -43,7 +43,7 @@ static const char MJIgnoredCodingPropertyNamesKey = '\0';
     }
 }
 
-+ (void)enumerateAllClasses:(MJClassesEnumeration)enumeration
++ (void)mj_enumerateAllClasses:(MJClassesEnumeration)enumeration
 {
     // 1.没有block就直接返回
     if (enumeration == nil) return;
@@ -65,50 +65,50 @@ static const char MJIgnoredCodingPropertyNamesKey = '\0';
 }
 
 #pragma mark - 属性黑名单配置
-+ (void)setupIgnoredPropertyNames:(MJIgnoredPropertyNames)ignoredPropertyNames
++ (void)mj_setupIgnoredPropertyNames:(MJIgnoredPropertyNames)ignoredPropertyNames
 {
-    [self setupBlockReturnValue:ignoredPropertyNames key:&MJIgnoredPropertyNamesKey];
+    [self mj_setupBlockReturnValue:ignoredPropertyNames key:&MJIgnoredPropertyNamesKey];
 }
 
-+ (NSMutableArray *)totalIgnoredPropertyNames
++ (NSMutableArray *)mj_totalIgnoredPropertyNames
 {
-    return [self totalObjectsWithSelector:@selector(ignoredPropertyNames) key:&MJIgnoredPropertyNamesKey];
+    return [self mj_totalObjectsWithSelector:@selector(mj_ignoredPropertyNames) key:&MJIgnoredPropertyNamesKey];
 }
 
 #pragma mark - 归档属性黑名单配置
-+ (void)setupIgnoredCodingPropertyNames:(MJIgnoredCodingPropertyNames)ignoredCodingPropertyNames
++ (void)mj_setupIgnoredCodingPropertyNames:(MJIgnoredCodingPropertyNames)ignoredCodingPropertyNames
 {
-    [self setupBlockReturnValue:ignoredCodingPropertyNames key:&MJIgnoredCodingPropertyNamesKey];
+    [self mj_setupBlockReturnValue:ignoredCodingPropertyNames key:&MJIgnoredCodingPropertyNamesKey];
 }
 
-+ (NSMutableArray *)totalIgnoredCodingPropertyNames
++ (NSMutableArray *)mj_totalIgnoredCodingPropertyNames
 {
-    return [self totalObjectsWithSelector:@selector(ignoredCodingPropertyNames) key:&MJIgnoredCodingPropertyNamesKey];
+    return [self mj_totalObjectsWithSelector:@selector(mj_ignoredCodingPropertyNames) key:&MJIgnoredCodingPropertyNamesKey];
 }
 
 #pragma mark - 属性白名单配置
-+ (void)setupAllowedPropertyNames:(MJAllowedPropertyNames)allowedPropertyNames;
++ (void)mj_setupAllowedPropertyNames:(MJAllowedPropertyNames)allowedPropertyNames;
 {
-    [self setupBlockReturnValue:allowedPropertyNames key:&MJAllowedPropertyNamesKey];
+    [self mj_setupBlockReturnValue:allowedPropertyNames key:&MJAllowedPropertyNamesKey];
 }
 
-+ (NSMutableArray *)totalAllowedPropertyNames
++ (NSMutableArray *)mj_totalAllowedPropertyNames
 {
-    return [self totalObjectsWithSelector:@selector(allowedPropertyNames) key:&MJAllowedPropertyNamesKey];
+    return [self mj_totalObjectsWithSelector:@selector(mj_allowedPropertyNames) key:&MJAllowedPropertyNamesKey];
 }
 
 #pragma mark - 归档属性白名单配置
-+ (void)setupAllowedCodingPropertyNames:(MJAllowedCodingPropertyNames)allowedCodingPropertyNames
++ (void)mj_setupAllowedCodingPropertyNames:(MJAllowedCodingPropertyNames)allowedCodingPropertyNames
 {
-    [self setupBlockReturnValue:allowedCodingPropertyNames key:&MJAllowedCodingPropertyNamesKey];
+    [self mj_setupBlockReturnValue:allowedCodingPropertyNames key:&MJAllowedCodingPropertyNamesKey];
 }
 
-+ (NSMutableArray *)totalAllowedCodingPropertyNames
++ (NSMutableArray *)mj_totalAllowedCodingPropertyNames
 {
-    return [self totalObjectsWithSelector:@selector(allowedCodingPropertyNames) key:&MJAllowedCodingPropertyNamesKey];
+    return [self mj_totalObjectsWithSelector:@selector(mj_allowedCodingPropertyNames) key:&MJAllowedCodingPropertyNamesKey];
 }
 #pragma mark - block和方法处理:存储block的返回值
-+ (void)setupBlockReturnValue:(id (^)())block key:(const char *)key
++ (void)mj_setupBlockReturnValue:(id (^)())block key:(const char *)key
 {
     if (block) {
         objc_setAssociatedObject(self, key, block(), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
@@ -120,7 +120,7 @@ static const char MJIgnoredCodingPropertyNamesKey = '\0';
     [[MJDictionaryCache dictWithDictId:key] removeAllObjects];
 }
 
-+ (NSMutableArray *)totalObjectsWithSelector:(SEL)selector key:(const char *)key
++ (NSMutableArray *)mj_totalObjectsWithSelector:(SEL)selector key:(const char *)key
 {
     NSMutableArray *array = [MJDictionaryCache objectForKey:NSStringFromClass(self) forDictId:key];
     if (array) return array;
@@ -138,7 +138,7 @@ static const char MJIgnoredCodingPropertyNamesKey = '\0';
         }
     }
     
-    [self enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
+    [self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
         NSArray *subArray = objc_getAssociatedObject(c, key);
         [array addObjectsFromArray:subArray];
     }];

+ 8 - 6
Benchmark/Vendor/MJExtension/NSObject+MJCoding.h

@@ -7,6 +7,8 @@
 //
 
 #import <Foundation/Foundation.h>
+#import "MJExtensionConst.h"
+
 /**
  *  Codeing协议
  */
@@ -15,22 +17,22 @@
 /**
  *  这个数组中的属性名才会进行归档
  */
-+ (NSArray *)allowedCodingPropertyNames;
++ (NSArray *)mj_allowedCodingPropertyNames;
 /**
  *  这个数组中的属性名将会被忽略:不进行归档
  */
-+ (NSArray *)ignoredCodingPropertyNames;
++ (NSArray *)mj_ignoredCodingPropertyNames;
 @end
 
 @interface NSObject (MJCoding) <MJCoding>
 /**
  *  解码(从文件中解析对象)
  */
-- (void)decode:(NSCoder *)decoder;
+- (void)mj_decode:(NSCoder *)decoder;
 /**
  *  编码(将对象写入文件中)
  */
-- (void)encode:(NSCoder *)encoder;
+- (void)mj_encode:(NSCoder *)encoder;
 @end
 
 /**
@@ -40,14 +42,14 @@
 - (id)initWithCoder:(NSCoder *)decoder \
 { \
 if (self = [super init]) { \
-[self decode:decoder]; \
+[self mj_decode:decoder]; \
 } \
 return self; \
 } \
 \
 - (void)encodeWithCoder:(NSCoder *)encoder \
 { \
-[self encode:encoder]; \
+[self mj_encode:encoder]; \
 }
 
 #define MJExtensionCodingImplementation MJCodingImplementation

+ 10 - 10
Benchmark/Vendor/MJExtension/NSObject+MJCoding.m

@@ -13,14 +13,14 @@
 
 @implementation NSObject (MJCoding)
 
-- (void)encode:(NSCoder *)encoder
+- (void)mj_encode:(NSCoder *)encoder
 {
-    Class aClass = [self class];
+    Class clazz = [self class];
     
-    NSArray *allowedCodingPropertyNames = [aClass totalAllowedCodingPropertyNames];
-    NSArray *ignoredCodingPropertyNames = [aClass totalIgnoredCodingPropertyNames];
+    NSArray *allowedCodingPropertyNames = [clazz mj_totalAllowedCodingPropertyNames];
+    NSArray *ignoredCodingPropertyNames = [clazz mj_totalIgnoredCodingPropertyNames];
     
-    [aClass enumerateProperties:^(MJProperty *property, BOOL *stop) {
+    [clazz mj_enumerateProperties:^(MJProperty *property, BOOL *stop) {
         // 检测是否被忽略
         if (allowedCodingPropertyNames.count && ![allowedCodingPropertyNames containsObject:property.name]) return;
         if ([ignoredCodingPropertyNames containsObject:property.name]) return;
@@ -31,14 +31,14 @@
     }];
 }
 
-- (void)decode:(NSCoder *)decoder
+- (void)mj_decode:(NSCoder *)decoder
 {
-    Class aClass = [self class];
+    Class clazz = [self class];
     
-    NSArray *allowedCodingPropertyNames = [aClass totalAllowedCodingPropertyNames];
-    NSArray *ignoredCodingPropertyNames = [aClass totalIgnoredCodingPropertyNames];
+    NSArray *allowedCodingPropertyNames = [clazz mj_totalAllowedCodingPropertyNames];
+    NSArray *ignoredCodingPropertyNames = [clazz mj_totalIgnoredCodingPropertyNames];
     
-    [aClass enumerateProperties:^(MJProperty *property, BOOL *stop) {
+    [clazz mj_enumerateProperties:^(MJProperty *property, BOOL *stop) {
         // 检测是否被忽略
         if (allowedCodingPropertyNames.count && ![allowedCodingPropertyNames containsObject:property.name]) return;
         if ([ignoredCodingPropertyNames containsObject:property.name]) return;

+ 78 - 48
Benchmark/Vendor/MJExtension/NSObject+MJKeyValue.h

@@ -19,33 +19,33 @@
 /**
  *  只有这个数组中的属性名才允许进行字典和模型的转换
  */
-+ (NSArray *)allowedPropertyNames;
++ (NSArray *)mj_allowedPropertyNames;
 
 /**
  *  这个数组中的属性名将会被忽略:不进行字典和模型的转换
  */
-+ (NSArray *)ignoredPropertyNames;
++ (NSArray *)mj_ignoredPropertyNames;
 
 /**
  *  将属性名换为其他key去字典中取值
  *
  *  @return 字典中的key是属性名,value是从字典中取值用的key
  */
-+ (NSDictionary *)replacedKeyFromPropertyName;
++ (NSDictionary *)mj_replacedKeyFromPropertyName;
 
 /**
  *  将属性名换为其他key去字典中取值
  *
  *  @return 从字典中取值用的key
  */
-+ (NSString *)replacedKeyFromPropertyName121:(NSString *)propertyName;
++ (NSString *)mj_replacedKeyFromPropertyName121:(NSString *)propertyName;
 
 /**
  *  数组中需要转换的模型类
  *
  *  @return 字典中的key是数组属性名,value是数组中存放模型的Class(Class类型或者NSString类型)
  */
-+ (NSDictionary *)objectClassInArray;
++ (NSDictionary *)mj_objectClassInArray;
 
 /**
  *  旧值换新值,用于过滤字典中的值
@@ -54,62 +54,61 @@
  *
  *  @return 新值
  */
-- (id)newValueFromOldValue:(id)oldValue property:(MJProperty *)property;
+- (id)mj_newValueFromOldValue:(id)oldValue property:(MJProperty *)property;
 
 /**
  *  当字典转模型完毕时调用
  */
-- (void)keyValuesDidFinishConvertingToObject;
+- (void)mj_keyValuesDidFinishConvertingToObject;
 
 /**
  *  当模型转字典完毕时调用
  */
-- (void)objectDidFinishConvertingToKeyValues;
+- (void)mj_objectDidFinishConvertingToKeyValues;
 @end
 
 @interface NSObject (MJKeyValue) <MJKeyValue>
+#pragma mark - 类方法
+/**
+ * 字典转模型过程中遇到的错误
+ */
++ (NSError *)mj_error;
+
+/**
+ *  模型转字典时,字典的key是否参考replacedKeyFromPropertyName等方法(父类设置了,子类也会继承下来)
+ */
++ (void)mj_referenceReplacedKeyWhenCreatingKeyValues:(BOOL)reference;
+
+#pragma mark - 对象方法
 /**
  *  将字典的键值对转成模型属性
  *  @param keyValues 字典(可以是NSDictionary、NSData、NSString)
  */
-- (instancetype)setKeyValues:(id)keyValues;
-- (instancetype)setKeyValues:(id)keyValues error:(NSError **)error;
+- (instancetype)mj_setKeyValues:(id)keyValues;
 
 /**
  *  将字典的键值对转成模型属性
  *  @param keyValues 字典(可以是NSDictionary、NSData、NSString)
  *  @param context   CoreData上下文
  */
-- (instancetype)setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context;
-- (instancetype)setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context error:(NSError **)error;
-
-/** 
- *  模型转字典时,字典的key是否参考replacedKeyFromPropertyName等方法(父类设置了,子类也会继承下来)
- */
-+ (void)referenceReplacedKeyWhenCreatingKeyValues:(BOOL)reference;
+- (instancetype)mj_setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context;
 
 /**
  *  将模型转成字典
  *  @return 字典
  */
-- (NSMutableDictionary *)keyValues;
-- (NSMutableDictionary *)keyValuesWithError:(NSError **)error;
-- (NSMutableDictionary *)keyValuesWithKeys:(NSArray *)keys;
-- (NSMutableDictionary *)keyValuesWithKeys:(NSArray *)keys error:(NSError **)error;
-- (NSMutableDictionary *)keyValuesWithIgnoredKeys:(NSArray *)ignoredKeys;
-- (NSMutableDictionary *)keyValuesWithIgnoredKeys:(NSArray *)ignoredKeys error:(NSError **)error;
+- (NSMutableDictionary *)mj_keyValues;
+- (NSMutableDictionary *)mj_keyValuesWithKeys:(NSArray *)keys;
+- (NSMutableDictionary *)mj_keyValuesWithIgnoredKeys:(NSArray *)ignoredKeys;
 
 /**
  *  通过模型数组来创建一个字典数组
  *  @param objectArray 模型数组
  *  @return 字典数组
  */
-+ (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray;
-+ (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray error:(NSError **)error;
-+ (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys;
-+ (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys error:(NSError **)error;
-+ (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray ignoredKeys:(NSArray *)ignoredKeys;
-+ (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray ignoredKeys:(NSArray *)ignoredKeys error:(NSError **)error;
++ (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray;
++ (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys;
++ (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray ignoredKeys:(NSArray *)ignoredKeys;
 
 #pragma mark - 字典转模型
 /**
@@ -117,8 +116,7 @@
  *  @param keyValues 字典(可以是NSDictionary、NSData、NSString)
  *  @return 新建的对象
  */
-+ (instancetype)objectWithKeyValues:(id)keyValues;
-+ (instancetype)objectWithKeyValues:(id)keyValues error:(NSError **)error;
++ (instancetype)mj_objectWithKeyValues:(id)keyValues;
 
 /**
  *  通过字典来创建一个CoreData模型
@@ -126,24 +124,21 @@
  *  @param context   CoreData上下文
  *  @return 新建的对象
  */
-+ (instancetype)objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context;
-+ (instancetype)objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context error:(NSError **)error;
++ (instancetype)mj_objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context;
 
 /**
  *  通过plist来创建一个模型
  *  @param filename 文件名(仅限于mainBundle中的文件)
  *  @return 新建的对象
  */
-+ (instancetype)objectWithFilename:(NSString *)filename;
-+ (instancetype)objectWithFilename:(NSString *)filename error:(NSError **)error;
++ (instancetype)mj_objectWithFilename:(NSString *)filename;
 
 /**
  *  通过plist来创建一个模型
  *  @param file 文件全路径
  *  @return 新建的对象
  */
-+ (instancetype)objectWithFile:(NSString *)file;
-+ (instancetype)objectWithFile:(NSString *)file error:(NSError **)error;
++ (instancetype)mj_objectWithFile:(NSString *)file;
 
 #pragma mark - 字典数组转模型数组
 /**
@@ -151,8 +146,7 @@
  *  @param keyValuesArray 字典数组(可以是NSDictionary、NSData、NSString)
  *  @return 模型数组
  */
-+ (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray;
-+ (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray error:(NSError **)error;
++ (NSMutableArray *)mj_objectArrayWithKeyValuesArray:(id)keyValuesArray;
 
 /**
  *  通过字典数组来创建一个模型数组
@@ -160,36 +154,72 @@
  *  @param context        CoreData上下文
  *  @return 模型数组
  */
-+ (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray context:(NSManagedObjectContext *)context;
-+ (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray context:(NSManagedObjectContext *)context error:(NSError **)error;
++ (NSMutableArray *)mj_objectArrayWithKeyValuesArray:(id)keyValuesArray context:(NSManagedObjectContext *)context;
 
 /**
  *  通过plist来创建一个模型数组
  *  @param filename 文件名(仅限于mainBundle中的文件)
  *  @return 模型数组
  */
-+ (NSMutableArray *)objectArrayWithFilename:(NSString *)filename;
-+ (NSMutableArray *)objectArrayWithFilename:(NSString *)filename error:(NSError **)error;
++ (NSMutableArray *)mj_objectArrayWithFilename:(NSString *)filename;
 
 /**
  *  通过plist来创建一个模型数组
  *  @param file 文件全路径
  *  @return 模型数组
  */
-+ (NSMutableArray *)objectArrayWithFile:(NSString *)file;
-+ (NSMutableArray *)objectArrayWithFile:(NSString *)file error:(NSError **)error;
++ (NSMutableArray *)mj_objectArrayWithFile:(NSString *)file;
 
 #pragma mark - 转换为JSON
 /**
  *  转换为JSON Data
  */
-- (NSData *)JSONData;
+- (NSData *)mj_JSONData;
 /**
  *  转换为字典或者数组
  */
-- (id)JSONObject;
+- (id)mj_JSONObject;
 /**
  *  转换为JSON 字符串
  */
-- (NSString *)JSONString;
+- (NSString *)mj_JSONString;
+@end
+
+@interface NSObject (MJKeyValueDeprecated_v_2_5_16)
+- (instancetype)setKeyValues:(id)keyValue MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
+- (instancetype)setKeyValues:(id)keyValues error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
+- (instancetype)setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
+- (instancetype)setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
++ (void)referenceReplacedKeyWhenCreatingKeyValues:(BOOL)reference MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
+- (NSMutableDictionary *)keyValues MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
+- (NSMutableDictionary *)keyValuesWithError:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
+- (NSMutableDictionary *)keyValuesWithKeys:(NSArray *)keys MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
+- (NSMutableDictionary *)keyValuesWithKeys:(NSArray *)keys error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
+- (NSMutableDictionary *)keyValuesWithIgnoredKeys:(NSArray *)ignoredKeys MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
+- (NSMutableDictionary *)keyValuesWithIgnoredKeys:(NSArray *)ignoredKeys error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
++ (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
++ (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
++ (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
++ (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
++ (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray ignoredKeys:(NSArray *)ignoredKeys MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
++ (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray ignoredKeys:(NSArray *)ignoredKeys error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
++ (instancetype)objectWithKeyValues:(id)keyValues MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
++ (instancetype)objectWithKeyValues:(id)keyValues error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
++ (instancetype)objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
++ (instancetype)objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
++ (instancetype)objectWithFilename:(NSString *)filename MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
++ (instancetype)objectWithFilename:(NSString *)filename error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
++ (instancetype)objectWithFile:(NSString *)file MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
++ (instancetype)objectWithFile:(NSString *)file error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
++ (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
++ (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
++ (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray context:(NSManagedObjectContext *)context MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
++ (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray context:(NSManagedObjectContext *)context error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
++ (NSMutableArray *)objectArrayWithFilename:(NSString *)filename MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
++ (NSMutableArray *)objectArrayWithFilename:(NSString *)filename error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
++ (NSMutableArray *)objectArrayWithFile:(NSString *)file MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
++ (NSMutableArray *)objectArrayWithFile:(NSString *)file error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
+- (NSData *)JSONData MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
+- (id)JSONObject MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
+- (NSString *)JSONString MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
 @end

+ 432 - 225
Benchmark/Vendor/MJExtension/NSObject+MJKeyValue.m

@@ -18,20 +18,32 @@
 
 @implementation NSObject (MJKeyValue)
 
+#pragma mark - 错误
+static const char MJErrorKey = '\0';
++ (NSError *)mj_error
+{
+    return objc_getAssociatedObject(self, &MJErrorKey);
+}
+
++ (void)setMj_error:(NSError *)error
+{
+    objc_setAssociatedObject(self, &MJErrorKey, error, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
 #pragma mark - 模型 -> 字典时的参考
 /** 模型转字典时,字典的key是否参考replacedKeyFromPropertyName等方法(父类设置了,子类也会继承下来) */
 static const char MJReferenceReplacedKeyWhenCreatingKeyValuesKey = '\0';
 
-+ (void)referenceReplacedKeyWhenCreatingKeyValues:(BOOL)reference
++ (void)mj_referenceReplacedKeyWhenCreatingKeyValues:(BOOL)reference
 {
     objc_setAssociatedObject(self, &MJReferenceReplacedKeyWhenCreatingKeyValuesKey, @(reference), OBJC_ASSOCIATION_ASSIGN);
 }
 
-+ (BOOL)isReferenceReplacedKeyWhenCreatingKeyValues
++ (BOOL)mj_isReferenceReplacedKeyWhenCreatingKeyValues
 {
     __block id value = objc_getAssociatedObject(self, &MJReferenceReplacedKeyWhenCreatingKeyValuesKey);
     if (!value) {
-        [self enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
+        [self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
             value = objc_getAssociatedObject(c, &MJReferenceReplacedKeyWhenCreatingKeyValuesKey);
             
             if (value) *stop = YES;
@@ -45,49 +57,42 @@ static NSNumberFormatter *numberFormatter_;
 + (void)load
 {
     numberFormatter_ = [[NSNumberFormatter alloc] init];
+    
+    // 默认设置
+    [self mj_referenceReplacedKeyWhenCreatingKeyValues:YES];
 }
 
 #pragma mark - --公共方法--
 #pragma mark - 字典 -> 模型
-- (instancetype)setKeyValues:(id)keyValues
-{
-    return [self setKeyValues:keyValues error:nil];
-}
-
-- (instancetype)setKeyValues:(id)keyValues error:(NSError *__autoreleasing *)error
-{
-    return [self setKeyValues:keyValues context:nil error:error];
-}
-
-- (instancetype)setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context
+- (instancetype)mj_setKeyValues:(id)keyValues
 {
-    return [self setKeyValues:keyValues context:context error:nil];
+    return [self mj_setKeyValues:keyValues context:nil];
 }
 
 /**
  核心代码:
  */
-- (instancetype)setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context error:(NSError *__autoreleasing *)error
+- (instancetype)mj_setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context
 {
     // 获得JSON对象
-    keyValues = [keyValues JSONObject];
+    keyValues = [keyValues mj_JSONObject];
     
-    MJExtensionAssertError([keyValues isKindOfClass:[NSDictionary class]], self, error, @"keyValues参数不是一个字典");
+    MJExtensionAssertError([keyValues isKindOfClass:[NSDictionary class]], self, [self class], @"keyValues参数不是一个字典");
     
-    @try {
-        Class aClass = [self class];
-        NSArray *allowedPropertyNames = [aClass totalAllowedPropertyNames];
-        NSArray *ignoredPropertyNames = [aClass totalIgnoredPropertyNames];
-        
-        //通过封装的方法回调一个通过运行时编写的,用于返回属性列表的方法。
-        [aClass enumerateProperties:^(MJProperty *property, BOOL *stop) {
+    Class clazz = [self class];
+    NSArray *allowedPropertyNames = [clazz mj_totalAllowedPropertyNames];
+    NSArray *ignoredPropertyNames = [clazz mj_totalIgnoredPropertyNames];
+    
+    //通过封装的方法回调一个通过运行时编写的,用于返回属性列表的方法。
+    [clazz mj_enumerateProperties:^(MJProperty *property, BOOL *stop) {
+        @try {
             // 0.检测是否被忽略
             if (allowedPropertyNames.count && ![allowedPropertyNames containsObject:property.name]) return;
             if ([ignoredPropertyNames containsObject:property.name]) return;
             
             // 1.取出属性值
             id value;
-            NSArray *propertyKeyses = [property propertyKeysForClass:aClass];
+            NSArray *propertyKeyses = [property propertyKeysForClass:clazz];
             for (NSArray *propertyKeys in propertyKeyses) {
                 value = keyValues;
                 for (MJPropertyKey *propertyKey in propertyKeys) {
@@ -97,163 +102,162 @@ static NSNumberFormatter *numberFormatter_;
             }
             
             // 值的过滤
-            id newValue = [aClass getNewValueFromObject:self oldValue:value property:property];
-            if (newValue) value = newValue;
+            id newValue = [clazz mj_getNewValueFromObject:self oldValue:value property:property];
+            if (newValue != value) { // 有过滤后的新值
+                [property setValue:newValue forObject:self];
+                return;
+            }
             
             // 如果没有值,就直接返回
             if (!value || value == [NSNull null]) return;
             
-            // 2.如果是模型属性
+            // 2.复杂处理
             MJPropertyType *type = property.type;
-            Class typeClass = type.typeClass;
+            Class propertyClass = type.typeClass;
             Class objectClass = [property objectClassInArrayForClass:[self class]];
-            if (!type.isFromFoundation && typeClass) {
-                value = [typeClass objectWithKeyValues:value context:context error:error];
+            
+            // 不可变 -> 可变处理
+            if (propertyClass == [NSMutableArray class] && [value isKindOfClass:[NSArray class]]) {
+                value = [NSMutableArray arrayWithArray:value];
+            } else if (propertyClass == [NSMutableDictionary class] && [value isKindOfClass:[NSDictionary class]]) {
+                value = [NSMutableDictionary dictionaryWithDictionary:value];
+            } else if (propertyClass == [NSMutableString class] && [value isKindOfClass:[NSString class]]) {
+                value = [NSMutableString stringWithString:value];
+            } else if (propertyClass == [NSMutableData class] && [value isKindOfClass:[NSData class]]) {
+                value = [NSMutableData dataWithData:value];
+            }
+            
+            if (!type.isFromFoundation && propertyClass) { // 模型属性
+                value = [propertyClass mj_objectWithKeyValues:value context:context];
             } else if (objectClass) {
-                // string array -> url array
                 if (objectClass == [NSURL class] && [value isKindOfClass:[NSArray class]]) {
+                    // string array -> url array
                     NSMutableArray *urlArray = [NSMutableArray array];
                     for (NSString *string in value) {
                         if (![string isKindOfClass:[NSString class]]) continue;
-                        [urlArray addObject:string.url];
+                        [urlArray addObject:string.mj_url];
                     }
                     value = urlArray;
-                } else {
-                    // 3.字典数组-->模型数组
-                    value = [objectClass objectArrayWithKeyValuesArray:value context:context error:error];
+                } else { // 字典数组-->模型数组
+                    value = [objectClass mj_objectArrayWithKeyValuesArray:value context:context];
                 }
-            } else if (typeClass == [NSString class]) {
-                if ([value isKindOfClass:[NSNumber class]]) {
-                    // NSNumber -> NSString
-                    value = [value description];
-                } else if ([value isKindOfClass:[NSURL class]]) {
-                    // NSURL -> NSString
-                    value = [value absoluteString];
-                }
-            } else if ([value isKindOfClass:[NSString class]]) {
-                if (typeClass == [NSURL class]) {
-                    // NSString -> NSURL
-                    // 字符串转码
-                    value = [value url];
-                } else if (type.isNumberType) {
-                    NSString *oldValue = value;
-                    
-                    // NSString -> NSNumber
-                    value = [numberFormatter_ numberFromString:oldValue];
-                    
-                    // 如果是BOOL
-                    if (type.isBoolType) {
-                        // 字符串转BOOL(字符串没有charValue方法)
-                        // 系统会调用字符串的charValue转为BOOL类型
-                        NSString *lower = [oldValue lowercaseString];
-                        if ([lower isEqualToString:@"yes"] || [lower isEqualToString:@"true"]) {
-                            value = @YES;
-                        } else if ([lower isEqualToString:@"no"] || [lower isEqualToString:@"false"]) {
-                            value = @NO;
+            } else {
+                if (propertyClass == [NSString class]) {
+                    if ([value isKindOfClass:[NSNumber class]]) {
+                        // NSNumber -> NSString
+                        value = [value description];
+                    } else if ([value isKindOfClass:[NSURL class]]) {
+                        // NSURL -> NSString
+                        value = [value absoluteString];
+                    }
+                } else if ([value isKindOfClass:[NSString class]]) {
+                    if (propertyClass == [NSURL class]) {
+                        // NSString -> NSURL
+                        // 字符串转码
+                        value = [value mj_url];
+                    } else if (type.isNumberType) {
+                        NSString *oldValue = value;
+                        
+                        // NSString -> NSNumber
+                        if (type.class == [NSDecimalNumber class]) {
+                            value = [NSDecimalNumber decimalNumberWithString:oldValue];
+                        } else {
+                            value = [numberFormatter_ numberFromString:oldValue];
+                        }
+                        
+                        // 如果是BOOL
+                        if (type.isBoolType) {
+                            // 字符串转BOOL(字符串没有charValue方法)
+                            // 系统会调用字符串的charValue转为BOOL类型
+                            NSString *lower = [oldValue lowercaseString];
+                            if ([lower isEqualToString:@"yes"] || [lower isEqualToString:@"true"]) {
+                                value = @YES;
+                            } else if ([lower isEqualToString:@"no"] || [lower isEqualToString:@"false"]) {
+                                value = @NO;
+                            }
                         }
                     }
                 }
+                
+                // value和property类型不匹配
+                if (propertyClass && ![value isKindOfClass:propertyClass]) {
+                    value = nil;
+                }
             }
             
-            // 4.赋值
+            // 3.赋值
             [property setValue:value forObject:self];
-        }];
-        
-        // 转换完毕
-        if ([self respondsToSelector:@selector(keyValuesDidFinishConvertingToObject)]) {
-            [self keyValuesDidFinishConvertingToObject];
+        } @catch (NSException *exception) {
+            MJExtensionBuildError([self class], exception.reason);
+            MJExtensionLog(@"%@", exception);
         }
-    } @catch (NSException *exception) {
-        MJExtensionBuildError(error, exception.reason);
-        NSLog(@"%@", exception);
+    }];
+    
+    // 转换完毕
+    if ([self respondsToSelector:@selector(mj_keyValuesDidFinishConvertingToObject)]) {
+        [self mj_keyValuesDidFinishConvertingToObject];
     }
     return self;
 }
 
-+ (instancetype)objectWithKeyValues:(id)keyValues
-{
-    return [self objectWithKeyValues:keyValues error:nil];
-}
-
-+ (instancetype)objectWithKeyValues:(id)keyValues error:(NSError *__autoreleasing *)error
++ (instancetype)mj_objectWithKeyValues:(id)keyValues
 {
-    return [self objectWithKeyValues:keyValues context:nil error:error];
+    return [self mj_objectWithKeyValues:keyValues context:nil];
 }
 
-+ (instancetype)objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context
-{
-    return [self objectWithKeyValues:keyValues context:context error:nil];
-}
-
-+ (instancetype)objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context error:(NSError *__autoreleasing *)error
++ (instancetype)mj_objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context
 {
-    if (keyValues == nil) return nil;
+    // 获得JSON对象
+    keyValues = [keyValues mj_JSONObject];
+    MJExtensionAssertError([keyValues isKindOfClass:[NSDictionary class]], nil, [self class], @"keyValues参数不是一个字典");
+    
     if ([self isSubclassOfClass:[NSManagedObject class]] && context) {
-        return [[NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass(self) inManagedObjectContext:context] setKeyValues:keyValues context:context error:error];
+        return [[NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass(self) inManagedObjectContext:context] mj_setKeyValues:keyValues context:context];
     }
-    return [[[self alloc] init] setKeyValues:keyValues error:error];
+    return [[[self alloc] init] mj_setKeyValues:keyValues];
 }
 
-+ (instancetype)objectWithFilename:(NSString *)filename
++ (instancetype)mj_objectWithFilename:(NSString *)filename
 {
-    return [self objectWithFilename:filename error:nil];
-}
-
-+ (instancetype)objectWithFilename:(NSString *)filename error:(NSError *__autoreleasing *)error
-{
-    MJExtensionAssertError(filename != nil, nil, error, @"filename参数为nil");
+    MJExtensionAssertError(filename != nil, nil, [self class], @"filename参数为nil");
     
-    return [self objectWithFile:[[NSBundle mainBundle] pathForResource:filename ofType:nil] error:error];
-}
-
-+ (instancetype)objectWithFile:(NSString *)file
-{
-    return [self objectWithFile:file error:nil];
+    return [self mj_objectWithFile:[[NSBundle mainBundle] pathForResource:filename ofType:nil]];
 }
 
-+ (instancetype)objectWithFile:(NSString *)file error:(NSError *__autoreleasing *)error
++ (instancetype)mj_objectWithFile:(NSString *)file
 {
-    MJExtensionAssertError(file != nil, nil, error, @"file参数为nil");
+    MJExtensionAssertError(file != nil, nil, [self class], @"file参数为nil");
     
-    return [self objectWithKeyValues:[NSDictionary dictionaryWithContentsOfFile:file] error:error];
+    return [self mj_objectWithKeyValues:[NSDictionary dictionaryWithContentsOfFile:file]];
 }
 
 #pragma mark - 字典数组 -> 模型数组
-+ (NSMutableArray *)objectArrayWithKeyValuesArray:(NSArray *)keyValuesArray
++ (NSMutableArray *)mj_objectArrayWithKeyValuesArray:(NSArray *)keyValuesArray
 {
-    return [self objectArrayWithKeyValuesArray:keyValuesArray error:nil];
+    return [self mj_objectArrayWithKeyValuesArray:keyValuesArray context:nil];
 }
 
-+ (NSMutableArray *)objectArrayWithKeyValuesArray:(NSArray *)keyValuesArray error:(NSError *__autoreleasing *)error
++ (NSMutableArray *)mj_objectArrayWithKeyValuesArray:(id)keyValuesArray context:(NSManagedObjectContext *)context
 {
-    return [self objectArrayWithKeyValuesArray:keyValuesArray context:nil error:error];
-}
-
-+ (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray context:(NSManagedObjectContext *)context
-{
-    return [self objectArrayWithKeyValuesArray:keyValuesArray context:context error:nil];
-}
-
-+ (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray context:(NSManagedObjectContext *)context error:(NSError *__autoreleasing *)error
-{
-    // 如果数组里面放的是NSString、NSNumber等数据
-    if ([MJFoundation isClassFromFoundation:self]) return keyValuesArray;
-    
     // 如果是JSON字符串
-    keyValuesArray = [keyValuesArray JSONObject];
+    keyValuesArray = [keyValuesArray mj_JSONObject];
     
     // 1.判断真实性
-    MJExtensionAssertError([keyValuesArray isKindOfClass:[NSArray class]], nil, error, @"keyValuesArray参数不是一个数组");
+    MJExtensionAssertError([keyValuesArray isKindOfClass:[NSArray class]], nil, [self class], @"keyValuesArray参数不是一个数组");
     
+    // 如果数组里面放的是NSString、NSNumber等数据
+    if ([MJFoundation isClassFromFoundation:self]) return [NSMutableArray arrayWithArray:keyValuesArray];
+    
+
     // 2.创建数组
     NSMutableArray *modelArray = [NSMutableArray array];
     
     // 3.遍历
     for (NSDictionary *keyValues in keyValuesArray) {
         if ([keyValues isKindOfClass:[NSArray class]]){
-            [modelArray addObject:[self objectArrayWithKeyValuesArray:keyValues context:context error:error]];
+            [modelArray addObject:[self mj_objectArrayWithKeyValuesArray:keyValues context:context]];
         } else {
-            id model = [self objectWithKeyValues:keyValues context:context error:error];
+            id model = [self mj_objectWithKeyValues:keyValues context:context];
             if (model) [modelArray addObject:model];
         }
     }
@@ -261,74 +265,49 @@ static NSNumberFormatter *numberFormatter_;
     return modelArray;
 }
 
-+ (NSMutableArray *)objectArrayWithFilename:(NSString *)filename
-{
-    return [self objectArrayWithFilename:filename error:nil];
-}
-
-+ (NSMutableArray *)objectArrayWithFilename:(NSString *)filename error:(NSError *__autoreleasing *)error
++ (NSMutableArray *)mj_objectArrayWithFilename:(NSString *)filename
 {
-    MJExtensionAssertError(filename != nil, nil, error, @"filename参数为nil");
+    MJExtensionAssertError(filename != nil, nil, [self class], @"filename参数为nil");
     
-    return [self objectArrayWithFile:[[NSBundle mainBundle] pathForResource:filename ofType:nil] error:error];
-}
-
-+ (NSMutableArray *)objectArrayWithFile:(NSString *)file
-{
-    return [self objectArrayWithFile:file error:nil];
+    return [self mj_objectArrayWithFile:[[NSBundle mainBundle] pathForResource:filename ofType:nil]];
 }
 
-+ (NSMutableArray *)objectArrayWithFile:(NSString *)file error:(NSError *__autoreleasing *)error
++ (NSMutableArray *)mj_objectArrayWithFile:(NSString *)file
 {
-    MJExtensionAssertError(file != nil, nil, error, @"file参数为nil");
+    MJExtensionAssertError(file != nil, nil, [self class], @"file参数为nil");
     
-    return [self objectArrayWithKeyValuesArray:[NSArray arrayWithContentsOfFile:file] error:error];
+    return [self mj_objectArrayWithKeyValuesArray:[NSArray arrayWithContentsOfFile:file]];
 }
 
 #pragma mark - 模型 -> 字典
-- (NSMutableDictionary *)keyValues
+- (NSMutableDictionary *)mj_keyValues
 {
-    return [self keyValuesWithError:nil];
+    return [self mj_keyValuesWithKeys:nil ignoredKeys:nil];
 }
 
-- (NSMutableDictionary *)keyValuesWithError:(NSError *__autoreleasing *)error
+- (NSMutableDictionary *)mj_keyValuesWithKeys:(NSArray *)keys
 {
-    return [self keyValuesWithIgnoredKeys:nil error:error];
+    return [self mj_keyValuesWithKeys:keys ignoredKeys:nil];
 }
 
-- (NSMutableDictionary *)keyValuesWithKeys:(NSArray *)keys
+- (NSMutableDictionary *)mj_keyValuesWithIgnoredKeys:(NSArray *)ignoredKeys
 {
-    return [self keyValuesWithKeys:keys error:nil];
+    return [self mj_keyValuesWithKeys:nil ignoredKeys:ignoredKeys];
 }
 
-- (NSMutableDictionary *)keyValuesWithKeys:(NSArray *)keys error:(NSError *__autoreleasing *)error
+- (NSMutableDictionary *)mj_keyValuesWithKeys:(NSArray *)keys ignoredKeys:(NSArray *)ignoredKeys
 {
-    return [self keyValuesWithKeys:keys ignoredKeys:nil error:error];
-}
-
-- (NSMutableDictionary *)keyValuesWithIgnoredKeys:(NSArray *)ignoredKeys
-{
-    return [self keyValuesWithIgnoredKeys:ignoredKeys error:nil];
-}
-
-- (NSMutableDictionary *)keyValuesWithIgnoredKeys:(NSArray *)ignoredKeys error:(NSError *__autoreleasing *)error
-{
-    return [self keyValuesWithKeys:nil ignoredKeys:ignoredKeys error:error];
-}
-
-- (NSMutableDictionary *)keyValuesWithKeys:(NSArray *)keys ignoredKeys:(NSArray *)ignoredKeys error:(NSError *__autoreleasing *)error
-{
-    // 如果自己不是模型类
-    if ([MJFoundation isClassFromFoundation:[self class]]) return (NSMutableDictionary *)self;
+    // 如果自己不是模型类, 那就返回自己
+    MJExtensionAssertError(![MJFoundation isClassFromFoundation:[self class]], (NSMutableDictionary *)self, [self class], @"不是自定义的模型类")
     
     id keyValues = [NSMutableDictionary dictionary];
     
-    @try {
-        Class aClass = [self class];
-        NSArray *allowedPropertyNames = [aClass totalAllowedPropertyNames];
-        NSArray *ignoredPropertyNames = [aClass totalIgnoredPropertyNames];
-        
-        [aClass enumerateProperties:^(MJProperty *property, BOOL *stop) {
+    Class clazz = [self class];
+    NSArray *allowedPropertyNames = [clazz mj_totalAllowedPropertyNames];
+    NSArray *ignoredPropertyNames = [clazz mj_totalIgnoredPropertyNames];
+    
+    [clazz mj_enumerateProperties:^(MJProperty *property, BOOL *stop) {
+        @try {
             // 0.检测是否被忽略
             if (allowedPropertyNames.count && ![allowedPropertyNames containsObject:property.name]) return;
             if ([ignoredPropertyNames containsObject:property.name]) return;
@@ -341,19 +320,19 @@ static NSNumberFormatter *numberFormatter_;
             
             // 2.如果是模型属性
             MJPropertyType *type = property.type;
-            Class typeClass = type.typeClass;
-            if (!type.isFromFoundation && typeClass) {
-                value = [value keyValues];
+            Class propertyClass = type.typeClass;
+            if (!type.isFromFoundation && propertyClass) {
+                value = [value mj_keyValues];
             } else if ([value isKindOfClass:[NSArray class]]) {
                 // 3.处理数组里面有模型的情况
-                value = [NSObject keyValuesArrayWithObjectArray:value];
-            } else if (typeClass == [NSURL class]) {
+                value = [NSObject mj_keyValuesArrayWithObjectArray:value];
+            } else if (propertyClass == [NSURL class]) {
                 value = [value absoluteString];
             }
             
             // 4.赋值
-            if ([aClass isReferenceReplacedKeyWhenCreatingKeyValues]) {
-                NSArray *propertyKeys = [[property propertyKeysForClass:aClass] firstObject];
+            if ([clazz mj_isReferenceReplacedKeyWhenCreatingKeyValues]) {
+                NSArray *propertyKeys = [[property propertyKeysForClass:clazz] firstObject];
                 NSUInteger keyCount = propertyKeys.count;
                 // 创建字典
                 __block id innerContainer = keyValues;
@@ -381,9 +360,10 @@ static NSNumberFormatter *numberFormatter_;
                         }
                         
                         if ([tempInnerContainer isKindOfClass:[NSMutableArray class]]) {
+                            NSMutableArray *tempInnerContainerArray = tempInnerContainer;
                             int index = nextPropertyKey.name.intValue;
-                            while ([tempInnerContainer count] < index + 1) {
-                                [tempInnerContainer addObject:[NSNull null]];
+                            while (tempInnerContainerArray.count < index + 1) {
+                                [tempInnerContainerArray addObject:[NSNull null]];
                             }
                         }
                         
@@ -399,74 +379,54 @@ static NSNumberFormatter *numberFormatter_;
             } else {
                 keyValues[property.name] = value;
             }
-        }];
-        
-        // 去除系统自动增加的元素
-        if ([keyValues isKindOfClass:[NSMutableDictionary class]]) {
-            [keyValues removeObjectsForKeys:@[@"superclass", @"debugDescription", @"description", @"hash"]];
-        }
-        
-        // 转换完毕
-        if ([self respondsToSelector:@selector(objectDidFinishConvertingToKeyValues)]) {
-            [self objectDidFinishConvertingToKeyValues];
+        } @catch (NSException *exception) {
+            MJExtensionBuildError([self class], exception.reason);
+            MJExtensionLog(@"%@", exception);
         }
-    } @catch (NSException *exception) {
-        MJExtensionBuildError(error, exception.reason);
-        NSLog(@"%@", exception);
+    }];
+    
+    // 转换完毕
+    if ([self respondsToSelector:@selector(mj_objectDidFinishConvertingToKeyValues)]) {
+        [self mj_objectDidFinishConvertingToKeyValues];
     }
     
     return keyValues;
 }
 #pragma mark - 模型数组 -> 字典数组
-+ (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray
-{
-    return [self keyValuesArrayWithObjectArray:objectArray error:nil];
-}
-
-+ (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray error:(NSError *__autoreleasing *)error
++ (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray
 {
-    return [self keyValuesArrayWithObjectArray:objectArray ignoredKeys:nil error:error];
+    return [self mj_keyValuesArrayWithObjectArray:objectArray keys:nil ignoredKeys:nil];
 }
 
-+ (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys
-{
-    return [self keyValuesArrayWithObjectArray:objectArray keys:keys error:nil];
-}
-
-+ (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray ignoredKeys:(NSArray *)ignoredKeys
-{
-    return [self keyValuesArrayWithObjectArray:objectArray ignoredKeys:ignoredKeys error:nil];
-}
-
-+ (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys error:(NSError *__autoreleasing *)error
++ (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys
 {
-    return [self keyValuesArrayWithObjectArray:objectArray keys:keys ignoredKeys:nil error:error];
+    return [self mj_keyValuesArrayWithObjectArray:objectArray keys:keys ignoredKeys:nil];
 }
 
-+ (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray ignoredKeys:(NSArray *)ignoredKeys error:(NSError *__autoreleasing *)error
++ (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray ignoredKeys:(NSArray *)ignoredKeys
 {
-    return [self keyValuesArrayWithObjectArray:objectArray keys:nil ignoredKeys:ignoredKeys error:error];
+    return [self mj_keyValuesArrayWithObjectArray:objectArray keys:nil ignoredKeys:ignoredKeys];
 }
 
-+ (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys ignoredKeys:(NSArray *)ignoredKeys error:(NSError *__autoreleasing *)error
++ (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys ignoredKeys:(NSArray *)ignoredKeys
 {
     // 0.判断真实性
-    MJExtensionAssertError([objectArray isKindOfClass:[NSArray class]], nil, error, @"objectArray参数不是一个数组");
+    MJExtensionAssertError([objectArray isKindOfClass:[NSArray class]], nil, [self class], @"objectArray参数不是一个数组");
     
     // 1.创建数组
     NSMutableArray *keyValuesArray = [NSMutableArray array];
     for (id object in objectArray) {
         if (keys) {
-            [keyValuesArray addObject:[object keyValuesWithKeys:keys error:error]];
+            [keyValuesArray addObject:[object mj_keyValuesWithKeys:keys]];
         } else {
-            [keyValuesArray addObject:[object keyValuesWithIgnoredKeys:ignoredKeys error:error]];
+            [keyValuesArray addObject:[object mj_keyValuesWithIgnoredKeys:ignoredKeys]];
         }
     }
     return keyValuesArray;
 }
 
 #pragma mark - 转换为JSON
-- (NSData *)JSONData
+- (NSData *)mj_JSONData
 {
     if ([self isKindOfClass:[NSString class]]) {
         return [((NSString *)self) dataUsingEncoding:NSUTF8StringEncoding];
@@ -474,10 +434,10 @@ static NSNumberFormatter *numberFormatter_;
         return (NSData *)self;
     }
     
-    return [NSJSONSerialization dataWithJSONObject:[self JSONObject] options:kNilOptions error:nil];
+    return [NSJSONSerialization dataWithJSONObject:[self mj_JSONObject] options:kNilOptions error:nil];
 }
 
-- (id)JSONObject
+- (id)mj_JSONObject
 {
     if ([self isKindOfClass:[NSString class]]) {
         return [NSJSONSerialization JSONObjectWithData:[((NSString *)self) dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil];
@@ -485,10 +445,10 @@ static NSNumberFormatter *numberFormatter_;
         return [NSJSONSerialization JSONObjectWithData:(NSData *)self options:kNilOptions error:nil];
     }
     
-    return self.keyValues;
+    return self.mj_keyValues;
 }
 
-- (NSString *)JSONString
+- (NSString *)mj_JSONString
 {
     if ([self isKindOfClass:[NSString class]]) {
         return (NSString *)self;
@@ -496,6 +456,253 @@ static NSNumberFormatter *numberFormatter_;
         return [[NSString alloc] initWithData:(NSData *)self encoding:NSUTF8StringEncoding];
     }
     
-    return [[NSString alloc] initWithData:[self JSONData] encoding:NSUTF8StringEncoding];
+    return [[NSString alloc] initWithData:[self mj_JSONData] encoding:NSUTF8StringEncoding];
 }
 @end
+
+@implementation NSObject (MJKeyValueDeprecated_v_2_5_16)
+- (instancetype)setKeyValues:(id)keyValues
+{
+    return [self mj_setKeyValues:keyValues];
+}
+
+- (instancetype)setKeyValues:(id)keyValues error:(NSError **)error
+{
+    id value = [self mj_setKeyValues:keyValues];
+    if (error != NULL) {
+    *error = [self.class mj_error];
+    }
+    return value;
+    
+}
+
+- (instancetype)setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context
+{
+    return [self mj_setKeyValues:keyValues context:context];
+}
+
+- (instancetype)setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context error:(NSError **)error
+{
+    id value = [self mj_setKeyValues:keyValues context:context];
+    if (error != NULL) {
+    *error = [self.class mj_error];
+    }
+    return value;
+}
+
++ (void)referenceReplacedKeyWhenCreatingKeyValues:(BOOL)reference
+{
+    [self mj_referenceReplacedKeyWhenCreatingKeyValues:reference];
+}
+
+- (NSMutableDictionary *)keyValues
+{
+    return [self mj_keyValues];
+}
+
+- (NSMutableDictionary *)keyValuesWithError:(NSError **)error
+{
+    id value = [self mj_keyValues];
+    if (error != NULL) {
+    *error = [self.class mj_error];
+    }
+    return value;
+}
+
+- (NSMutableDictionary *)keyValuesWithKeys:(NSArray *)keys
+{
+    return [self mj_keyValuesWithKeys:keys];
+}
+
+- (NSMutableDictionary *)keyValuesWithKeys:(NSArray *)keys error:(NSError **)error
+{
+    id value = [self mj_keyValuesWithKeys:keys];
+    if (error != NULL) {
+    *error = [self.class mj_error];
+    }
+    return value;
+}
+
+- (NSMutableDictionary *)keyValuesWithIgnoredKeys:(NSArray *)ignoredKeys
+{
+    return [self mj_keyValuesWithIgnoredKeys:ignoredKeys];
+}
+
+- (NSMutableDictionary *)keyValuesWithIgnoredKeys:(NSArray *)ignoredKeys error:(NSError **)error
+{
+    id value = [self mj_keyValuesWithIgnoredKeys:ignoredKeys];
+    if (error != NULL) {
+    *error = [self.class mj_error];
+    }
+    return value;
+}
+
++ (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray
+{
+    return [self mj_keyValuesArrayWithObjectArray:objectArray];
+}
+
++ (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray error:(NSError **)error
+{
+    id value = [self mj_keyValuesArrayWithObjectArray:objectArray];
+    if (error != NULL) {
+    *error = [self mj_error];
+    }
+    return value;
+}
+
++ (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys
+{
+    return [self mj_keyValuesArrayWithObjectArray:objectArray keys:keys];
+}
+
++ (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys error:(NSError **)error
+{
+    id value = [self mj_keyValuesArrayWithObjectArray:objectArray keys:keys];
+    if (error != NULL) {
+    *error = [self mj_error];
+    }
+    return value;
+}
+
++ (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray ignoredKeys:(NSArray *)ignoredKeys
+{
+    return [self mj_keyValuesArrayWithObjectArray:objectArray ignoredKeys:ignoredKeys];
+}
+
++ (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray ignoredKeys:(NSArray *)ignoredKeys error:(NSError **)error
+{
+    id value = [self mj_keyValuesArrayWithObjectArray:objectArray ignoredKeys:ignoredKeys];
+    if (error != NULL) {
+    *error = [self mj_error];
+    }
+    return value;
+}
+
++ (instancetype)objectWithKeyValues:(id)keyValues
+{
+    return [self mj_objectWithKeyValues:keyValues];
+}
+
++ (instancetype)objectWithKeyValues:(id)keyValues error:(NSError **)error
+{
+    id value = [self mj_objectWithKeyValues:keyValues];
+    if (error != NULL) {
+    *error = [self mj_error];
+    }
+    return value;
+}
+
++ (instancetype)objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context
+{
+    return [self mj_objectWithKeyValues:keyValues context:context];
+}
+
++ (instancetype)objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context error:(NSError **)error
+{
+    id value = [self mj_objectWithKeyValues:keyValues context:context];
+    if (error != NULL) {
+    *error = [self mj_error];
+    }
+    return value;
+}
+
++ (instancetype)objectWithFilename:(NSString *)filename
+{
+    return [self mj_objectWithFilename:filename];
+}
+
++ (instancetype)objectWithFilename:(NSString *)filename error:(NSError **)error
+{
+    id value = [self mj_objectWithFilename:filename];
+    if (error != NULL) {
+    *error = [self mj_error];
+    }
+    return value;
+}
+
++ (instancetype)objectWithFile:(NSString *)file
+{
+    return [self mj_objectWithFile:file];
+}
+
++ (instancetype)objectWithFile:(NSString *)file error:(NSError **)error
+{
+    id value = [self mj_objectWithFile:file];
+    if (error != NULL) {
+    *error = [self mj_error];
+    }
+    return value;
+}
+
++ (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray
+{
+    return [self mj_objectArrayWithKeyValuesArray:keyValuesArray];
+}
+
++ (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray error:(NSError **)error
+{
+    id value = [self mj_objectArrayWithKeyValuesArray:keyValuesArray];
+    if (error != NULL) {
+    *error = [self mj_error];
+    }
+    return value;
+}
+
++ (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray context:(NSManagedObjectContext *)context
+{
+    return [self mj_objectArrayWithKeyValuesArray:keyValuesArray context:context];
+}
+
++ (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray context:(NSManagedObjectContext *)context error:(NSError **)error
+{
+    id value = [self mj_objectArrayWithKeyValuesArray:keyValuesArray context:context];
+    if (error != NULL) {
+    *error = [self mj_error];
+    }
+    return value;
+}
+
++ (NSMutableArray *)objectArrayWithFilename:(NSString *)filename
+{
+    return [self mj_objectArrayWithFilename:filename];
+}
+
++ (NSMutableArray *)objectArrayWithFilename:(NSString *)filename error:(NSError **)error
+{
+    id value = [self mj_objectArrayWithFilename:filename];
+    if (error != NULL) {
+    *error = [self mj_error];
+    }
+    return value;
+}
+
++ (NSMutableArray *)objectArrayWithFile:(NSString *)file
+{
+    return [self mj_objectArrayWithFile:file];
+}
+
++ (NSMutableArray *)objectArrayWithFile:(NSString *)file error:(NSError **)error
+{
+    id value = [self mj_objectArrayWithFile:file];
+    if (error != NULL) {
+    *error = [self mj_error];
+    }
+    return value;
+}
+
+- (NSData *)JSONData
+{
+    return [self mj_JSONData];
+}
+
+- (id)JSONObject
+{
+    return [self mj_JSONObject];
+}
+
+- (NSString *)JSONString
+{
+    return [self mj_JSONString];
+}
+@end

+ 16 - 6
Benchmark/Vendor/MJExtension/NSObject+MJProperty.h

@@ -7,6 +7,7 @@
 //
 
 #import <Foundation/Foundation.h>
+#import "MJExtensionConst.h"
 
 @class MJProperty;
 
@@ -34,7 +35,7 @@ typedef id (^MJNewValueFromOldValue)(id object, id oldValue, MJProperty *propert
 /**
  *  遍历所有的成员
  */
-+ (void)enumerateProperties:(MJPropertiesEnumeration)enumeration;
++ (void)mj_enumerateProperties:(MJPropertiesEnumeration)enumeration;
 
 #pragma mark - 新值配置
 /**
@@ -42,8 +43,8 @@ typedef id (^MJNewValueFromOldValue)(id object, id oldValue, MJProperty *propert
  *
  *  @param newValueFormOldValue 用于过滤字典中的值
  */
-+ (void)setupNewValueFromOldValue:(MJNewValueFromOldValue)newValueFormOldValue;
-+ (id)getNewValueFromObject:(__weak id)object oldValue:(__weak id)oldValue property:(__weak MJProperty *)property;
++ (void)mj_setupNewValueFromOldValue:(MJNewValueFromOldValue)newValueFormOldValue;
++ (id)mj_getNewValueFromObject:(__unsafe_unretained id)object oldValue:(__unsafe_unretained id)oldValue property:(__unsafe_unretained MJProperty *)property;
 
 #pragma mark - key配置
 /**
@@ -51,13 +52,13 @@ typedef id (^MJNewValueFromOldValue)(id object, id oldValue, MJProperty *propert
  *
  *  @param replacedKeyFromPropertyName 将属性名换为其他key去字典中取值
  */
-+ (void)setupReplacedKeyFromPropertyName:(MJReplacedKeyFromPropertyName)replacedKeyFromPropertyName;
++ (void)mj_setupReplacedKeyFromPropertyName:(MJReplacedKeyFromPropertyName)replacedKeyFromPropertyName;
 /**
  *  将属性名换为其他key去字典中取值
  *
  *  @param replacedKeyFromPropertyName121 将属性名换为其他key去字典中取值
  */
-+ (void)setupReplacedKeyFromPropertyName121:(MJReplacedKeyFromPropertyName121)replacedKeyFromPropertyName121;
++ (void)mj_setupReplacedKeyFromPropertyName121:(MJReplacedKeyFromPropertyName121)replacedKeyFromPropertyName121;
 
 #pragma mark - array model class配置
 /**
@@ -65,5 +66,14 @@ typedef id (^MJNewValueFromOldValue)(id object, id oldValue, MJProperty *propert
  *
  *  @param objectClassInArray          数组中需要转换的模型类
  */
-+ (void)setupObjectClassInArray:(MJObjectClassInArray)objectClassInArray;
++ (void)mj_setupObjectClassInArray:(MJObjectClassInArray)objectClassInArray;
+@end
+
+@interface NSObject (MJPropertyDeprecated_v_2_5_16)
++ (void)enumerateProperties:(MJPropertiesEnumeration)enumeration MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
++ (void)setupNewValueFromOldValue:(MJNewValueFromOldValue)newValueFormOldValue MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
++ (id)getNewValueFromObject:(__unsafe_unretained id)object oldValue:(__unsafe_unretained id)oldValue property:(__unsafe_unretained MJProperty *)property MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
++ (void)setupReplacedKeyFromPropertyName:(MJReplacedKeyFromPropertyName)replacedKeyFromPropertyName MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
++ (void)setupReplacedKeyFromPropertyName121:(MJReplacedKeyFromPropertyName121)replacedKeyFromPropertyName121 MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
++ (void)setupObjectClassInArray:(MJObjectClassInArray)objectClassInArray MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
 @end

+ 88 - 44
Benchmark/Vendor/MJExtension/NSObject+MJProperty.m

@@ -15,6 +15,10 @@
 #import <objc/runtime.h>
 #import "MJDictionaryCache.h"
 
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wundeclared-selector"
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+
 @implementation NSObject (Property)
 
 static const char MJReplacedKeyFromPropertyNameKey = '\0';
@@ -31,13 +35,17 @@ static const char MJCachedPropertiesKey = '\0';
     
     __block NSString *key = nil;
     // 查看有没有需要替换的key
+    if ([self respondsToSelector:@selector(mj_replacedKeyFromPropertyName121:)]) {
+        key = [self mj_replacedKeyFromPropertyName121:propertyName];
+    }
+    // 兼容旧版本
     if ([self respondsToSelector:@selector(replacedKeyFromPropertyName121:)]) {
-        key = [self replacedKeyFromPropertyName121:propertyName];
+        key = [self performSelector:@selector(replacedKeyFromPropertyName121) withObject:propertyName];
     }
     
     // 调用block
     if (!key) {
-        [self enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
+        [self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
             MJReplacedKeyFromPropertyName121 block = objc_getAssociatedObject(c, &MJReplacedKeyFromPropertyName121Key);
             if (block) {
                 key = block(propertyName);
@@ -47,12 +55,16 @@ static const char MJCachedPropertiesKey = '\0';
     }
     
     // 查看有没有需要替换的key
+    if (!key && [self respondsToSelector:@selector(mj_replacedKeyFromPropertyName)]) {
+        key = [self mj_replacedKeyFromPropertyName][propertyName];
+    }
+    // 兼容旧版本
     if (!key && [self respondsToSelector:@selector(replacedKeyFromPropertyName)]) {
-        key = [self replacedKeyFromPropertyName][propertyName];
+        key = [self performSelector:@selector(replacedKeyFromPropertyName)][propertyName];
     }
     
     if (!key) {
-        [self enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
+        [self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
             NSDictionary *dict = objc_getAssociatedObject(c, &MJReplacedKeyFromPropertyNameKey);
             if (dict) {
                 key = dict[propertyName];
@@ -69,30 +81,34 @@ static const char MJCachedPropertiesKey = '\0';
 
 + (Class)propertyObjectClassInArray:(NSString *)propertyName
 {
-    __block id aClass = nil;
+    __block id clazz = nil;
+    if ([self respondsToSelector:@selector(mj_objectClassInArray)]) {
+        clazz = [self mj_objectClassInArray][propertyName];
+    }
+    // 兼容旧版本
     if ([self respondsToSelector:@selector(objectClassInArray)]) {
-        aClass = [self objectClassInArray][propertyName];
+        clazz = [self performSelector:@selector(objectClassInArray)][propertyName];
     }
     
-    if (!aClass) {
-        [self enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
+    if (!clazz) {
+        [self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
             NSDictionary *dict = objc_getAssociatedObject(c, &MJObjectClassInArrayKey);
             if (dict) {
-                aClass = dict[propertyName];
+                clazz = dict[propertyName];
             }
-            if (aClass) *stop = YES;
+            if (clazz) *stop = YES;
         }];
     }
     
     // 如果是NSString类型
-    if ([aClass isKindOfClass:[NSString class]]) {
-        aClass = NSClassFromString(aClass);
+    if ([clazz isKindOfClass:[NSString class]]) {
+        clazz = NSClassFromString(clazz);
     }
-    return aClass;
+    return clazz;
 }
 
 #pragma mark - --公共方法--
-+ (void)enumerateProperties:(MJPropertiesEnumeration)enumeration
++ (void)mj_enumerateProperties:(MJPropertiesEnumeration)enumeration
 {
     // 获得成员变量
     NSArray *cachedProperties = [self properties];
@@ -108,34 +124,26 @@ static const char MJCachedPropertiesKey = '\0';
 #pragma mark - 公共方法
 + (NSMutableArray *)properties
 {
-    // 获得成员变量
-    // 通过关联对象,以及提前定义好的MJCachedPropertiesKey来进行运行时,对所有属性的获取。
-
-    //***objc_getAssociatedObject 方法用于判断当前是否已经获取过MJCachedPropertiesKey对应的关联对象
-    //  1> 关联到的对象
-    //  2> 关联的属性 key
     NSMutableArray *cachedProperties = [MJDictionaryCache objectForKey:NSStringFromClass(self) forDictId:&MJCachedPropertiesKey];
     
-    //***
     if (cachedProperties == nil) {
         cachedProperties = [NSMutableArray array];
-
-        /** 遍历这个类的所有类()不包括NSObject这些基础类 */
-        [self enumerateClasses:^(__unsafe_unretained Class c, BOOL *stop) {
+        
+        [self mj_enumerateClasses:^(__unsafe_unretained Class c, BOOL *stop) {
             // 1.获得所有的成员变量
             unsigned int outCount = 0;
-            /**
-                class_copyIvarList 成员变量,提示有很多第三方框架会使用 Ivar,能够获得更多的信息
-                但是:在 swift 中,由于语法结构的变化,使用 Ivar 非常不稳定,经常会崩溃!
-                class_copyPropertyList 属性
-                class_copyMethodList 方法
-                class_copyProtocolList 协议
-                */
             objc_property_t *properties = class_copyPropertyList(c, &outCount);
             
             // 2.遍历每一个成员变量
             for (unsigned int i = 0; i<outCount; i++) {
                 MJProperty *property = [MJProperty cachedPropertyWithProperty:properties[i]];
+                // 过滤掉系统自动添加的元素
+                if ([property.name isEqualToString:@"hash"]
+                    || [property.name isEqualToString:@"superclass"]
+                    || [property.name isEqualToString:@"description"]
+                    || [property.name isEqualToString:@"debugDescription"]) {
+                    continue;
+                }
                 property.srcClass = c;
                 [property setOriginKey:[self propertyKey:property.name] forClass:self];
                 [property setObjectClassInArray:[self propertyObjectClassInArray:property.name] forClass:self];
@@ -146,29 +154,31 @@ static const char MJCachedPropertiesKey = '\0';
             free(properties);
         }];
         
-        //*** 在此时设置当前这个类为关联对象,这样下次就不会重复获取类的相关属性。
         [MJDictionaryCache setObject:cachedProperties forKey:NSStringFromClass(self) forDictId:&MJCachedPropertiesKey];
-        //***
     }
     
     return cachedProperties;
 }
 
 #pragma mark - 新值配置
-+ (void)setupNewValueFromOldValue:(MJNewValueFromOldValue)newValueFormOldValue
++ (void)mj_setupNewValueFromOldValue:(MJNewValueFromOldValue)newValueFormOldValue
 {
     objc_setAssociatedObject(self, &MJNewValueFromOldValueKey, newValueFormOldValue, OBJC_ASSOCIATION_COPY_NONATOMIC);
 }
 
-+ (id)getNewValueFromObject:(__weak id)object oldValue:(__weak id)oldValue property:(MJProperty *__weak)property{
++ (id)mj_getNewValueFromObject:(__unsafe_unretained id)object oldValue:(__unsafe_unretained id)oldValue property:(MJProperty *__unsafe_unretained)property{
     // 如果有实现方法
-    if ([object respondsToSelector:@selector(newValueFromOldValue:property:)]) {
-        return [object newValueFromOldValue:oldValue property:property];
+    if ([object respondsToSelector:@selector(mj_newValueFromOldValue:property:)]) {
+        return [object mj_newValueFromOldValue:oldValue property:property];
+    }
+    // 兼容旧版本
+    if ([self respondsToSelector:@selector(newValueFromOldValue:property:)]) {
+        return [self performSelector:@selector(newValueFromOldValue:property:)  withObject:oldValue  withObject:property];
     }
     
     // 查看静态设置
-    __block id newValue = nil;
-    [self enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
+    __block id newValue = oldValue;
+    [self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
         MJNewValueFromOldValue block = objc_getAssociatedObject(c, &MJNewValueFromOldValueKey);
         if (block) {
             newValue = block(object, oldValue, property);
@@ -179,25 +189,59 @@ static const char MJCachedPropertiesKey = '\0';
 }
 
 #pragma mark - array model class配置
-+ (void)setupObjectClassInArray:(MJObjectClassInArray)objectClassInArray
++ (void)mj_setupObjectClassInArray:(MJObjectClassInArray)objectClassInArray
 {
-    [self setupBlockReturnValue:objectClassInArray key:&MJObjectClassInArrayKey];
+    [self mj_setupBlockReturnValue:objectClassInArray key:&MJObjectClassInArrayKey];
     
     [[MJDictionaryCache dictWithDictId:&MJCachedPropertiesKey] removeAllObjects];
 }
 
 #pragma mark - key配置
-+ (void)setupReplacedKeyFromPropertyName:(MJReplacedKeyFromPropertyName)replacedKeyFromPropertyName
++ (void)mj_setupReplacedKeyFromPropertyName:(MJReplacedKeyFromPropertyName)replacedKeyFromPropertyName
 {
-    [self setupBlockReturnValue:replacedKeyFromPropertyName key:&MJReplacedKeyFromPropertyNameKey];
+    [self mj_setupBlockReturnValue:replacedKeyFromPropertyName key:&MJReplacedKeyFromPropertyNameKey];
     
     [[MJDictionaryCache dictWithDictId:&MJCachedPropertiesKey] removeAllObjects];
 }
 
-+ (void)setupReplacedKeyFromPropertyName121:(MJReplacedKeyFromPropertyName121)replacedKeyFromPropertyName121
++ (void)mj_setupReplacedKeyFromPropertyName121:(MJReplacedKeyFromPropertyName121)replacedKeyFromPropertyName121
 {
     objc_setAssociatedObject(self, &MJReplacedKeyFromPropertyName121Key, replacedKeyFromPropertyName121, OBJC_ASSOCIATION_COPY_NONATOMIC);
     
     [[MJDictionaryCache dictWithDictId:&MJCachedPropertiesKey] removeAllObjects];
 }
 @end
+
+@implementation NSObject (MJPropertyDeprecated_v_2_5_16)
++ (void)enumerateProperties:(MJPropertiesEnumeration)enumeration
+{
+    [self mj_enumerateProperties:enumeration];
+}
+
++ (void)setupNewValueFromOldValue:(MJNewValueFromOldValue)newValueFormOldValue
+{
+    [self mj_setupNewValueFromOldValue:newValueFormOldValue];
+}
+
++ (id)getNewValueFromObject:(__unsafe_unretained id)object oldValue:(__unsafe_unretained id)oldValue property:(__unsafe_unretained MJProperty *)property
+{
+    return [self mj_getNewValueFromObject:object oldValue:oldValue property:property];
+}
+
++ (void)setupReplacedKeyFromPropertyName:(MJReplacedKeyFromPropertyName)replacedKeyFromPropertyName
+{
+    [self mj_setupReplacedKeyFromPropertyName:replacedKeyFromPropertyName];
+}
+
++ (void)setupReplacedKeyFromPropertyName121:(MJReplacedKeyFromPropertyName121)replacedKeyFromPropertyName121
+{
+    [self mj_setupReplacedKeyFromPropertyName121:replacedKeyFromPropertyName121];
+}
+
++ (void)setupObjectClassInArray:(MJObjectClassInArray)objectClassInArray
+{
+    [self mj_setupObjectClassInArray:objectClassInArray];
+}
+@end
+
+#pragma clang diagnostic pop

+ 16 - 6
Benchmark/Vendor/MJExtension/NSString+MJExtension.h

@@ -7,26 +7,36 @@
 //
 
 #import <Foundation/Foundation.h>
+#import "MJExtensionConst.h"
 
 @interface NSString (MJExtension)
 /**
  *  驼峰转下划线(loveYou -> love_you)
  */
-- (NSString *)underlineFromCamel;
+- (NSString *)mj_underlineFromCamel;
 /**
  *  下划线转驼峰(love_you -> loveYou)
  */
-- (NSString *)camelFromUnderline;
+- (NSString *)mj_camelFromUnderline;
 /**
  * 首字母变大写
  */
-- (NSString *)firstCharUpper;
+- (NSString *)mj_firstCharUpper;
 /**
  * 首字母变小写
  */
-- (NSString *)firstCharLower;
+- (NSString *)mj_firstCharLower;
 
-- (BOOL)isPureInt;
+- (BOOL)mj_isPureInt;
 
-- (NSURL *)url;
+- (NSURL *)mj_url;
+@end
+
+@interface NSString (MJExtensionDeprecated_v_2_5_16)
+- (NSString *)underlineFromCamel MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
+- (NSString *)camelFromUnderline MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
+- (NSString *)firstCharUpper MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
+- (NSString *)firstCharLower MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
+- (BOOL)isPureInt MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
+- (NSURL *)url MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
 @end

+ 40 - 6
Benchmark/Vendor/MJExtension/NSString+MJExtension.m

@@ -9,7 +9,7 @@
 #import "NSString+MJExtension.h"
 
 @implementation NSString (MJExtension)
-- (NSString *)underlineFromCamel
+- (NSString *)mj_underlineFromCamel
 {
     if (self.length == 0) return self;
     NSMutableString *string = [NSMutableString string];
@@ -27,7 +27,7 @@
     return string;
 }
 
-- (NSString *)camelFromUnderline
+- (NSString *)mj_camelFromUnderline
 {
     if (self.length == 0) return self;
     NSMutableString *string = [NSMutableString string];
@@ -44,7 +44,7 @@
     return string;
 }
 
-- (NSString *)firstCharLower
+- (NSString *)mj_firstCharLower
 {
     if (self.length == 0) return self;
     NSMutableString *string = [NSMutableString string];
@@ -53,7 +53,7 @@
     return string;
 }
 
-- (NSString *)firstCharUpper
+- (NSString *)mj_firstCharUpper
 {
     if (self.length == 0) return self;
     NSMutableString *string = [NSMutableString string];
@@ -62,15 +62,49 @@
     return string;
 }
 
-- (BOOL)isPureInt
+- (BOOL)mj_isPureInt
 {
     NSScanner *scan = [NSScanner scannerWithString:self];
     int val;
     return [scan scanInt:&val] && [scan isAtEnd];
 }
 
-- (NSURL *)url
+- (NSURL *)mj_url
 {
+//    [self stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet characterSetWithCharactersInString:@"!$&'()*+,-./:;=?@_~%#[]"]];
+    
     return [NSURL URLWithString:(NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)self, (CFStringRef)@"!$&'()*+,-./:;=?@_~%#[]", NULL,kCFStringEncodingUTF8))];
 }
 @end
+
+@implementation NSString (MJExtensionDeprecated_v_2_5_16)
+- (NSString *)underlineFromCamel
+{
+    return self.mj_underlineFromCamel;
+}
+
+- (NSString *)camelFromUnderline
+{
+    return self.mj_camelFromUnderline;
+}
+
+- (NSString *)firstCharLower
+{
+    return self.mj_firstCharLower;
+}
+
+- (NSString *)firstCharUpper
+{
+    return self.mj_firstCharUpper;
+}
+
+- (BOOL)isPureInt
+{
+    return self.mj_isPureInt;
+}
+
+- (NSURL *)url
+{
+    return self.mj_url;
+}
+@end