├── RFJModel ├── RFJModel │ ├── Example │ │ ├── ExampleCustomStorageModelJson.txt │ │ ├── ExampleUD.m │ │ ├── ExampleUD.h │ │ ├── ExampleModel.m │ │ ├── ExampleCustomStorageModel.m │ │ ├── result_CustomStorage.txt │ │ ├── ExampleCustomStorageModel.h │ │ ├── ExampleJson.txt │ │ ├── ExampleType.txt │ │ ├── result_Type.txt │ │ ├── ExampleModel.h │ │ ├── result_Json.txt │ │ └── result_Inherit.txt │ ├── AppDelegate.h │ ├── main.m │ ├── RFJModel │ │ ├── RFJModel.h │ │ ├── NSString+RFSafeTransform.h │ │ ├── NSObject+RFJModelProperty.h │ │ ├── NSObject+RFAssociatedValue.h │ │ ├── RFJUserDefaults.h │ │ ├── RFJModel.m │ │ ├── RFJUserDefaults.m │ │ ├── NSString+RFSafeTransform.m │ │ ├── NSObject+RFAssociatedValue.m │ │ ├── NSObject+RFJModel.h │ │ ├── RFJModelProperty.h │ │ ├── NSObject+RFSafeTransform.h │ │ ├── NSObject+RFSafeTransform.m │ │ ├── RFJModelProperty.m │ │ ├── NSObject+RFJModelProperty.m │ │ └── NSObject+RFJModel.m │ ├── ViewController.h │ ├── Info.plist │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── AppDelegate.m │ ├── Base.lproj │ │ ├── LaunchScreen.xib │ │ └── Main.storyboard │ └── ViewController.m ├── RFJModel.xcodeproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── project.pbxproj └── RFJModelTests │ ├── Info.plist │ └── RFJModelTests.m ├── .gitignore ├── LICENSE └── README.md /RFJModel/RFJModel/Example/ExampleCustomStorageModelJson.txt: -------------------------------------------------------------------------------- 1 | { 2 | "jpValueJsonKey":"XiaoMing", 3 | "jpStorageValueJsonKey":"XiaoGang", 4 | "jpStorageCharValueJsonKey1": 120003, 5 | "jpStorageCharValueJsonKey2": "120003", 6 | } 7 | -------------------------------------------------------------------------------- /RFJModel/RFJModel.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/Example/ExampleUD.m: -------------------------------------------------------------------------------- 1 | // 2 | // ExampleUD.m 3 | // RFJModel 4 | // 5 | // Created by GZH on 2017/8/30. 6 | // Copyright © 2017年 TechAtk. All rights reserved. 7 | // 8 | 9 | #import "ExampleUD.h" 10 | 11 | @implementation ExampleUD 12 | @dynamic testString; 13 | @dynamic testInt; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // RFJModel 4 | // 5 | // Created by gouzhehua on 14-12-31. 6 | // Copyright (c) 2014年 TechAtk. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // RFJModel 4 | // 5 | // Created by gouzhehua on 14-12-31. 6 | // Copyright (c) 2014年 TechAtk. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/Example/ExampleUD.h: -------------------------------------------------------------------------------- 1 | // 2 | // ExampleUD.h 3 | // RFJModel 4 | // 5 | // Created by GZH on 2017/8/30. 6 | // Copyright © 2017年 TechAtk. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "RFJUserDefaults.h" 11 | 12 | @interface ExampleUD : RFJUserDefaults 13 | 14 | @property (nonatomic, strong) NSString *testString; 15 | @property (nonatomic, assign) NSInteger testInt; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/RFJModel/RFJModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // RFJModel.h 3 | // RFJModel 4 | // 5 | // Created by gouzhehua on 14-12-5. 6 | // Copyright (c) 2014年 GZH. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "NSObject+RFJModel.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface RFJModel : NSObject 15 | { 16 | 17 | } 18 | 19 | - (id)initWithJsonDict:(NSDictionary *)jsonDict; 20 | 21 | @end 22 | 23 | NS_ASSUME_NONNULL_END 24 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/Example/ExampleModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // ExampleModel1.m 3 | // RFJModel 4 | // 5 | // Created by gouzhehua on 14-12-10. 6 | // Copyright (c) 2014年 TechAtk. All rights reserved. 7 | // 8 | 9 | #import "ExampleModel.h" 10 | 11 | @implementation ExampleModelTestType 12 | @end 13 | 14 | @implementation ExampleModelTestJson 15 | @end 16 | 17 | @implementation ExampleModelTestChild 18 | @end 19 | 20 | @implementation ExampleModelTestSub 21 | @end 22 | 23 | @implementation GrandsonModel 24 | @end 25 | 26 | @implementation ExampleProtocolModel 27 | @end 28 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/Example/ExampleCustomStorageModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // ExampleCustomStorageModel.m 3 | // RFJModel 4 | // 5 | // Created by GZH on 2017/6/29. 6 | // Copyright © 2017年 TechAtk. All rights reserved. 7 | // 8 | 9 | #import "ExampleCustomStorageModel.h" 10 | 11 | @implementation ExampleCustomStorageModel 12 | @dynamic jpStorageValue; 13 | @dynamic normalStorageValue; 14 | @dynamic weakStorageValue; 15 | @dynamic assignDoubleStorageValue; 16 | @dynamic getterSetterIntStorageValue; 17 | @dynamic jpStorageCharValue1; 18 | @dynamic jpStorageCharValue2; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | # Pods/ 27 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // RFJModel 4 | // 5 | // Created by gouzhehua on 14-12-10. 6 | // Copyright (c) 2014年 TechAtk. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | { 13 | 14 | } 15 | @property (nonatomic, strong) IBOutlet UITextView *tvJson; 16 | @property (nonatomic, strong) IBOutlet UITextView *tvResult; 17 | 18 | - (IBAction)btnType_Click:(id)sender; 19 | - (IBAction)btnJson_Click:(id)sender; 20 | - (IBAction)btnInherit_Click:(id)sender; 21 | - (IBAction)btnCustomStorage_Click:(id)sender; 22 | 23 | @end 24 | 25 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/RFJModel/NSString+RFSafeTransform.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+RFSafeTransform.h 3 | // RFJModel 4 | // 5 | // Created by GZH on 2017/7/4. 6 | // Copyright © 2017年 TechAtk. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface NSString (RFSafeTransform) 14 | 15 | + (BOOL)isEmpty:(NSString *)value; 16 | + (NSString *)ifNilToStr:(NSString *)value; 17 | 18 | + (NSString *)stringWithInteger:(NSInteger)value; 19 | + (NSString *)stringWithLong:(long)value; 20 | + (NSString *)stringWithLongLong:(int64_t)value; 21 | + (NSString *)stringWithFloat:(float)value; 22 | + (NSString *)stringWithDouble:(double)value; 23 | 24 | @end 25 | 26 | NS_ASSUME_NONNULL_END 27 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/RFJModel/NSObject+RFJModelProperty.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+RFJModelProperty.h 3 | // RFJModel 4 | // 5 | // Created by GZH on 2017/7/4. 6 | // Copyright © 2017年 TechAtk. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "RFJModelProperty.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface NSObject (RFJModelProperty) 15 | 16 | + (void)rfj_analyseModelWithClass:(Class)cls rootModelClass:(Class)rootModelClass; 17 | 18 | + (BOOL)rfj_isRFJModel:(Class)cls; 19 | - (NSString *)rfj_getClassName; 20 | - (NSString *)rfj_getRootModelClassName; 21 | - (BOOL)rfj_isRFJModel; 22 | - (NSMutableDictionary *)rfj_getPropertyInfos; 23 | - (NSMutableDictionary *)rfj_getSelector2PropertyInfos; 24 | 25 | @end 26 | 27 | NS_ASSUME_NONNULL_END 28 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/RFJModel/NSObject+RFAssociatedValue.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+RFAssociatedValue.h 3 | // RFJModel 4 | // 5 | // Created by GZH on 2017/7/4. 6 | // Copyright © 2017年 TechAtk. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | typedef NS_ENUM(NSUInteger, RFModelPropertyAccessType) 14 | { 15 | RFModelPropertyAccessTypeAssign = 0, 16 | RFModelPropertyAccessTypeStrong, 17 | RFModelPropertyAccessTypeWeak, 18 | RFModelPropertyAccessTypeCopy, 19 | }; 20 | 21 | @interface NSObject (RFAssociatedValue) 22 | - (void)rfj_setAssociatedValue:(nullable id)value forKey:(const void *)key access:(RFModelPropertyAccessType)access atomic:(BOOL)bAtomic; 23 | - (id)rfj_getAssociatedValueOfKey:(const void *)key; 24 | @end 25 | 26 | NS_ASSUME_NONNULL_END 27 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/RFJModel/RFJUserDefaults.h: -------------------------------------------------------------------------------- 1 | // 2 | // RFJUserDefaults.h 3 | // RFJModel 4 | // 5 | // Created by GZH on 2017/7/7. 6 | // Copyright © 2017年 GZH. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "NSObject+RFJModel.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface RFJUserDefaults : NSObject 15 | 16 | @property (nonatomic, strong) NSString *domain; 17 | @property (nonatomic, strong) NSUserDefaults *userDefaults; 18 | 19 | - (instancetype)initWithDomain:(NSString *)domain; 20 | 21 | - (nullable id)rfj_objectForKey:(nonnull NSString *)key ofModel:(nonnull id)rfjModel; 22 | - (void)rfj_setObject:(nullable id)value forKey:(nonnull NSString *)key ofModel:(nonnull id)rfjModel; 23 | - (NSString *)rfj_transformKey:(NSString *)key; 24 | 25 | @end 26 | 27 | NS_ASSUME_NONNULL_END 28 | -------------------------------------------------------------------------------- /RFJModel/RFJModelTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/Example/result_CustomStorage.txt: -------------------------------------------------------------------------------- 1 | 2 | input: 3 | { 4 | "jpValueJsonKey":"XiaoMing", 5 | "jpStorageValueJsonKey":"XiaoGang", 6 | "jpStorageCharValueJsonKey1": 120003, 7 | "jpStorageCharValueJsonKey2": "120003", 8 | } 9 | 10 | 11 | output: 12 | 13 | JP name:jpValue type:RFJModelPropertyTypeString map:jpValueJsonKey value:XiaoMing 14 | JP name:jpStorageValue type:RFJModelPropertyTypeString map:jpStorageValueJsonKey value:XiaoGang 15 | P name:normalValue value:(null) 16 | P name:normalStorageValue value:(null) 17 | P name:weakStorageValue value:(null) 18 | P name:assignIntValue value:0 19 | P name:assignDoubleStorageValue value:(null) 20 | P name:getterSetterIntValue value:0 21 | P name:getterSetterIntStorageValue value:(null) 22 | P name:copyGetterSetterStringStorageValue value:(null) 23 | JP name:jpStorageCharValue1 type:RFJModelPropertyTypeChar map:jpStorageCharValueJsonKey1 value:-61 24 | JP name:jpStorageCharValue2 type:RFJModelPropertyTypeChar map:jpStorageCharValueJsonKey2 value:-61 -------------------------------------------------------------------------------- /RFJModel/RFJModelTests/RFJModelTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // RFJModelTests.m 3 | // RFJModelTests 4 | // 5 | // Created by gouzhehua on 14-12-31. 6 | // Copyright (c) 2014年 TechAtk. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface RFJModelTests : XCTestCase 13 | 14 | @end 15 | 16 | @implementation RFJModelTests 17 | 18 | - (void)setUp { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | [super tearDown]; 26 | } 27 | 28 | - (void)testExample { 29 | // This is an example of a functional test case. 30 | XCTAssert(YES, @"Pass"); 31 | } 32 | 33 | - (void)testPerformanceExample { 34 | // This is an example of a performance test case. 35 | [self measureBlock:^{ 36 | // Put the code you want to measure the time of here. 37 | }]; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 進撃の技術者 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/Example/ExampleCustomStorageModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // ExampleCustomStorageModel.h 3 | // RFJModel 4 | // 5 | // Created by GZH on 2017/6/29. 6 | // Copyright © 2017年 TechAtk. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "RFJModel.h" 11 | 12 | @interface ExampleCustomStorageModel : RFJModel 13 | 14 | JProperty(NSString *jpValue, jpValueJsonKey); 15 | JProperty(NSString *jpStorageValue, jpStorageValueJsonKey); 16 | 17 | @property (atomic, retain) NSString *normalValue; 18 | @property (nonatomic, strong) NSString *normalStorageValue; 19 | @property (nonatomic, weak) NSMutableString *weakStorageValue; 20 | @property (nonatomic, assign) NSInteger assignIntValue; 21 | @property (nonatomic, unsafe_unretained) double assignDoubleStorageValue; 22 | @property (getter=customGetter, setter=customSetter:, assign) NSInteger getterSetterIntValue; 23 | @property (getter=customGetter1, setter=customSetter1:) NSInteger getterSetterIntStorageValue; 24 | @property (getter=customGetter2, setter=customSetter2:, copy) NSString *copyGetterSetterStringStorageValue; 25 | JProperty(char jpStorageCharValue1, jpStorageCharValueJsonKey1); 26 | JProperty(char jpStorageCharValue2, jpStorageCharValueJsonKey2); 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/RFJModel/RFJModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // RFJModel.m 3 | // RFJModel 4 | // 5 | // Created by gouzhehua on 14-12-5. 6 | // Copyright (c) 2014年 GZH. All rights reserved. 7 | // 8 | 9 | #import "RFJModel.h" 10 | 11 | @interface RFJModel () 12 | 13 | @end 14 | 15 | @implementation RFJModel 16 | 17 | + (void)initialize 18 | { 19 | [NSObject rfj_initializeModelWithClass:[self class] rootModelClass:[RFJModel class]]; 20 | } 21 | 22 | - (id)init 23 | { 24 | self = [super init]; 25 | if (self) 26 | { 27 | 28 | } 29 | return self; 30 | } 31 | 32 | - (id)initWithJsonDict:(NSDictionary *)jsonDict 33 | { 34 | self = [self init]; 35 | if (self) 36 | { 37 | [self rfj_fillWithJsonDict:jsonDict usePropertyKey:NO]; 38 | } 39 | return self; 40 | } 41 | 42 | - (NSString *)description 43 | { 44 | NSMutableString *buffer = [NSMutableString string]; 45 | [self rfj_descriptionWithBuffer:buffer indent:0]; 46 | return buffer; 47 | } 48 | 49 | - (id)initWithCoder:(NSCoder *)aDecoder 50 | { 51 | self = [super init]; 52 | if (self) 53 | { 54 | [self rfj_decodeCoder:aDecoder]; 55 | } 56 | return self; 57 | } 58 | 59 | - (void)encodeWithCoder:(NSCoder *)aCoder 60 | { 61 | [self rfj_encodeCoder:aCoder]; 62 | } 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/RFJModel/RFJUserDefaults.m: -------------------------------------------------------------------------------- 1 | // 2 | // RFJUserDefaults.m 3 | // RFJModel 4 | // 5 | // Created by GZH on 2017/7/7. 6 | // Copyright © 2017年 GZH. All rights reserved. 7 | // 8 | 9 | #import "RFJUserDefaults.h" 10 | 11 | @implementation RFJUserDefaults 12 | 13 | + (void)initialize 14 | { 15 | [NSObject rfj_initializeModelWithClass:[self class] rootModelClass:[RFJUserDefaults class]]; 16 | } 17 | 18 | - (instancetype)initWithDomain:(NSString *)domain 19 | { 20 | self = [super init]; 21 | if (self) 22 | { 23 | self.rfj_storageDelegate = self; 24 | _domain = domain; 25 | if (IS_EMPTY_STR(domain)) 26 | _userDefaults = [NSUserDefaults standardUserDefaults]; 27 | else 28 | _userDefaults = [[NSUserDefaults alloc] initWithSuiteName:domain]; 29 | } 30 | return self; 31 | } 32 | 33 | - (nullable id)rfj_objectForKey:(nonnull NSString *)key ofModel:(nonnull id)rfjModel 34 | { 35 | return [self.userDefaults objectForKey:key]; 36 | } 37 | 38 | - (void)rfj_setObject:(nullable id)value forKey:(nonnull NSString *)key ofModel:(nonnull id)rfjMode 39 | { 40 | [self.userDefaults setObject:value forKey:key]; 41 | } 42 | 43 | - (NSString *)rfj_transformKey:(NSString *)key 44 | { 45 | return key; 46 | } 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/Example/ExampleJson.txt: -------------------------------------------------------------------------------- 1 | { 2 | "name":"XiaoMing", 3 | "sex":"1", 4 | "age": 123, 5 | "address":null, 6 | "uid":9876543210123456, 7 | "unuse":"unuse value", 8 | "list":[1,2,3,4,5,6], 9 | "dict": 10 | { 11 | "value1":"1", 12 | "value2":2 13 | }, 14 | "bYes":"Yes", 15 | "bTrue":true, 16 | "bTrue2":"true", 17 | "b0":0, 18 | "b1":1, 19 | "bNo":"no", 20 | "bFalse":false, 21 | "model": 22 | { 23 | "name":"SubModel", 24 | "size":123 25 | }, 26 | "models": 27 | [ 28 | { 29 | "name":"SubModel1", 30 | "size":1, 31 | "GrandsonModel": 32 | { 33 | "name":"GM1" 34 | }, 35 | }, 36 | { 37 | "name":"SubModel2", 38 | "size":2, 39 | "GrandsonModel": 40 | { 41 | "name":"GM2" 42 | }, 43 | }, 44 | { 45 | "name":"SubModel3", 46 | "size":3, 47 | "GrandsonModel": 48 | { 49 | "name":"GM3" 50 | }, 51 | }, 52 | ], 53 | "mstr":"mutableString", 54 | "mArray":[{"k":"v"}, "string", [1, 2],], 55 | "mDict":{"k1":"string", "k2":[1,2], "k3":{"k":"v"},}, 56 | "mModelArray":[{"name":"SubModel","size":123},{"name":"SubModel","size":123},], 57 | "errString" : [], 58 | "errArray" : {}, 59 | "errDict" : "errString", 60 | "errModelArray" : "errString", 61 | "errModel" : "errModel", 62 | } 63 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/Example/ExampleType.txt: -------------------------------------------------------------------------------- 1 | @interface ExampleModelTestType : RFJModel 2 | JProperty(NSInteger value_NSInteger, map_value_NSInteger); 3 | JProperty(NSUInteger value_NSUInteger, map_value_NSUInteger); 4 | JProperty(short value_short, map_value_short); 5 | JProperty(unsigned short value_ushort, map_value_ushort); 6 | JProperty(int value_int, map_value_int); 7 | JProperty(unsigned int value_uint, map_value_uint); 8 | JProperty(long value_long, map_value_long); 9 | JProperty(unsigned long value_long_u, map_value_long_u); 10 | JProperty(long long value_long_long, map_value_long_long); 11 | JProperty(unsigned long long value_long_long_u, map_value_long_long_u); 12 | JProperty(int32_t value_int32, map_value_int32); 13 | JProperty(uint32_t value_uint32, map_value_uint32); 14 | JProperty(int16_t value_int16, map_value_int16); 15 | JProperty(uint16_t value_uint16, map_value_uint16); 16 | JProperty(int64_t value_int64, map_value_int64); 17 | JProperty(uint64_t value_uint64, map_value_uint64); 18 | JProperty(NSString *value_NSString, map_value_NSString); 19 | JProperty(NSArray *value_NSArray, map_value_NSArray); 20 | JProperty(NSDictionary *value_NSDictionary, map_value_NSDictionary); 21 | JProperty(BOOL value_Bool, map_value_Bool); 22 | JProperty(ExampleModelTestType *value_Model, map_model); 23 | JProperty(NSArray *value_models, map_models); 24 | @end -------------------------------------------------------------------------------- /RFJModel/RFJModel/RFJModel/NSString+RFSafeTransform.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+RFSafeTransform.m 3 | // RFJModel 4 | // 5 | // Created by GZH on 2017/7/4. 6 | // Copyright © 2017年 TechAtk. All rights reserved. 7 | // 8 | 9 | #import "NSString+RFSafeTransform.h" 10 | 11 | @implementation NSString (RFSafeTransform) 12 | 13 | + (BOOL)isEmpty:(NSString *)value 14 | { 15 | if ((value == nil) || value == (NSString *)[NSNull null] || (value.length == 0)) 16 | { 17 | return YES; 18 | } 19 | return NO; 20 | } 21 | 22 | + (NSString *)ifNilToStr:(NSString *)value 23 | { 24 | if ((value == nil) || (value == (NSString *)[NSNull null])) 25 | { 26 | return @""; 27 | } 28 | 29 | if ([value isKindOfClass:[NSNumber class]]) 30 | { 31 | return [(NSNumber *)value stringValue]; 32 | } 33 | 34 | return value; 35 | } 36 | 37 | + (NSString *)stringWithInteger:(NSInteger)value 38 | { 39 | NSNumber *number = [NSNumber numberWithInteger:value]; 40 | return [number stringValue]; 41 | } 42 | 43 | + (NSString *)stringWithLong:(long)value 44 | { 45 | return [NSString stringWithFormat:@"%ld", value]; 46 | } 47 | 48 | + (NSString *)stringWithLongLong:(int64_t)value 49 | { 50 | return [NSString stringWithFormat:@"%lld", value]; 51 | } 52 | 53 | + (NSString *)stringWithFloat:(float)value 54 | { 55 | return [NSString stringWithFormat:@"%f", value]; 56 | } 57 | 58 | + (NSString *)stringWithDouble:(double)value 59 | { 60 | return [NSString stringWithFormat:@"%lf", value]; 61 | } 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | } 88 | ], 89 | "info" : { 90 | "version" : 1, 91 | "author" : "xcode" 92 | } 93 | } -------------------------------------------------------------------------------- /RFJModel/RFJModel/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // RFJModel 4 | // 5 | // Created by gouzhehua on 14-12-31. 6 | // Copyright (c) 2014年 TechAtk. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | 21 | return YES; 22 | } 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 26 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 27 | } 28 | 29 | - (void)applicationDidEnterBackground:(UIApplication *)application { 30 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 31 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 32 | } 33 | 34 | - (void)applicationWillEnterForeground:(UIApplication *)application { 35 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 36 | } 37 | 38 | - (void)applicationDidBecomeActive:(UIApplication *)application { 39 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 40 | } 41 | 42 | - (void)applicationWillTerminate:(UIApplication *)application { 43 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/RFJModel/NSObject+RFAssociatedValue.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+RFAssociatedValue.m 3 | // RFJModel 4 | // 5 | // Created by GZH on 2017/7/4. 6 | // Copyright © 2017年 TechAtk. All rights reserved. 7 | // 8 | 9 | #import "NSObject+RFAssociatedValue.h" 10 | #import 11 | 12 | @interface RFAssociatedWeakObject : NSObject 13 | @property (nonatomic, weak) id weakObject; 14 | @end 15 | @implementation RFAssociatedWeakObject 16 | @end 17 | 18 | @implementation NSObject (RFAssociatedValue) 19 | 20 | - (void)rfj_setAssociatedValue:(nullable id)value forKey:(const void *)key access:(RFModelPropertyAccessType)access atomic:(BOOL)bAtomic 21 | { 22 | objc_AssociationPolicy policy = OBJC_ASSOCIATION_ASSIGN; 23 | id inputValue = value; 24 | switch (access) 25 | { 26 | case RFModelPropertyAccessTypeAssign: 27 | policy = OBJC_ASSOCIATION_ASSIGN; 28 | break; 29 | case RFModelPropertyAccessTypeStrong: 30 | policy = bAtomic ? OBJC_ASSOCIATION_RETAIN : OBJC_ASSOCIATION_RETAIN_NONATOMIC; 31 | break; 32 | case RFModelPropertyAccessTypeWeak: 33 | { 34 | policy = bAtomic ? OBJC_ASSOCIATION_RETAIN : OBJC_ASSOCIATION_RETAIN_NONATOMIC; 35 | 36 | id obj = objc_getAssociatedObject(self, key); 37 | if (obj != nil && [obj isKindOfClass:[RFAssociatedWeakObject class]]) { 38 | RFAssociatedWeakObject *wo = obj; 39 | wo.weakObject = value; 40 | inputValue = wo; 41 | } 42 | else 43 | { 44 | RFAssociatedWeakObject *wo = [[RFAssociatedWeakObject alloc] init]; 45 | wo.weakObject = value; 46 | inputValue = wo; 47 | } 48 | } 49 | break; 50 | case RFModelPropertyAccessTypeCopy: 51 | policy = bAtomic ? OBJC_ASSOCIATION_COPY : OBJC_ASSOCIATION_COPY_NONATOMIC; 52 | break; 53 | default: 54 | break; 55 | } 56 | objc_setAssociatedObject(self, key, inputValue, policy); 57 | } 58 | 59 | - (id)rfj_getAssociatedValueOfKey:(const void *)key 60 | { 61 | id value = objc_getAssociatedObject(self, key); 62 | id outputValue = value; 63 | if (value != nil && [value isKindOfClass:[RFAssociatedWeakObject class]]) 64 | { 65 | RFAssociatedWeakObject *wo = value; 66 | outputValue = wo.weakObject; 67 | } 68 | return outputValue; 69 | } 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/RFJModel/NSObject+RFJModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+RFJModel.h 3 | // RFJModel 4 | // 5 | // Created by GZH on 2017/7/4. 6 | // Copyright © 2017年 TechAtk. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "NSObject+RFJModelProperty.h" 11 | #import "NSObject+RFSafeTransform.h" 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | #pragma mark - RFJModelStorageDelegate 16 | 17 | @protocol RFJModelStorageDelegate 18 | - (nullable id)rfj_objectForKey:(nonnull NSString *)key ofModel:(nonnull id)rfjModel; 19 | - (void)rfj_setObject:(nullable id)value forKey:(nonnull NSString *)key ofModel:(nonnull id)rfjModel; 20 | @optional 21 | - (NSString *)rfj_transformKey:(NSString *)key; // 经过该方法转换为storage对应的key,并存入缓存 22 | @end 23 | 24 | #pragma mark - NSObject (RFJModel) 25 | 26 | @interface NSObject (RFJModel) 27 | 28 | // 模型类initialize时调用一次,只有调用后才视为RFJModel,rfj_isRFJModel为YES。(优先使用) 29 | // 也可以在init时调用,内部做了防护,索引只创建一次。但是每次检查仍然有对象创建,不是0损耗。 30 | + (void)rfj_initializeModelWithClass:(Class)cls rootModelClass:(Class)rootModelClass; 31 | 32 | // Json字典装填到Model。usePropertyKey为NO使用属性定义的JSON Key,为YES使用属性名。 33 | - (void)rfj_fillWithJsonDict:(NSDictionary *)jsonDict usePropertyKey:(BOOL)bUsePropertyKey; 34 | 35 | // 深拷贝 36 | + (id)rfj_deepMutableCopyWithJson:(id)json; 37 | 38 | // 转换方法 39 | // fill的逆操作,空值不写入。usePropertyKey为NO使用属性定义的JSON Key,为YES使用属性名。 40 | - (NSMutableDictionary *)rfj_toMutableDictionaryUsePropertyKey:(BOOL)bUsePropertyKey; 41 | - (NSString *)rfj_toJsonStringUsePropertyKey:(BOOL)bUsePropertyKey; 42 | 43 | // 序列化用RFJModel版本 44 | + (NSUInteger)rfj_modelVersion; 45 | + (NSString *)rfj_modelVersionSerializeKey; 46 | 47 | // 序列化装填 48 | - (void)rfj_decodeCoder:(NSCoder *)coder; 49 | - (void)rfj_encodeCoder:(NSCoder *)coder; 50 | 51 | // Data转换 52 | + (NSData *)rfj_toDataWithModel:(id)rfjModel; 53 | + (id)rfj_toModelWithData:(NSData *)data class:(Class)cls; 54 | 55 | // 调试打印用 56 | - (void)rfj_descriptionWithBuffer:(NSMutableString *)buffer indent:(NSInteger)indent; 57 | 58 | #pragma mark - 自定义存储区 59 | 60 | @property (nonatomic, weak) id rfj_storageDelegate; 61 | 62 | // storage对应的key的缓存,每个Model种类对应一个字典 63 | - (NSMutableDictionary *)rfj_cachedTransformKeys; 64 | 65 | // Model所有的属性存储,无论静态动态均走这个方法。动态属性如果rfj_storageDelegate不为空,存取走rfj_storageDelegate,否则存取到自身关联对象。如果想自定义数据存取可以复写这个方法 66 | - (nullable id)rfj_valueForKey:(NSString *)key; 67 | - (void)rfj_setValue:(nullable id)value forKey:(NSString *)key; 68 | 69 | @end 70 | 71 | NS_ASSUME_NONNULL_END 72 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/RFJModel/RFJModelProperty.h: -------------------------------------------------------------------------------- 1 | // 2 | // RFJModelProperty.h 3 | // RFJModel 4 | // 5 | // Created by GZH on 2017/7/4. 6 | // Copyright © 2017年 TechAtk. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import "NSObject+RFAssociatedValue.h" 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | #define JProperty(Property, MapName) \ 16 | @property (nonatomic, setter=_rfjm_##MapName:) Property 17 | 18 | typedef NS_ENUM(NSUInteger, RFJModelPropertyType) 19 | { 20 | RFJModelPropertyTypeNone = 0, 21 | RFJModelPropertyTypeBOOL, 22 | RFJModelPropertyTypeChar, 23 | RFJModelPropertyTypeInt16, 24 | RFJModelPropertyTypeInt32, 25 | RFJModelPropertyTypeInt64, 26 | RFJModelPropertyTypeFloat, 27 | RFJModelPropertyTypeDouble, 28 | RFJModelPropertyTypeString, 29 | RFJModelPropertyTypeMutableString, 30 | RFJModelPropertyTypeArray, 31 | RFJModelPropertyTypeMutableArray, 32 | RFJModelPropertyTypeModelArray, 33 | RFJModelPropertyTypeMutableModelArray, 34 | RFJModelPropertyTypeDictionary, 35 | RFJModelPropertyTypeMutableDictionary, 36 | RFJModelPropertyTypeModel, 37 | RFJModelPropertyTypeObject, 38 | }; 39 | 40 | static char * _Nonnull s_RFJModelPropertyTypeName[] = 41 | { 42 | "RFJModelPropertyTypeNone", 43 | "RFJModelPropertyTypeBOOL", 44 | "RFJModelPropertyTypeChar", 45 | "RFJModelPropertyTypeInt16", 46 | "RFJModelPropertyTypeInt32", 47 | "RFJModelPropertyTypeInt64", 48 | "RFJModelPropertyTypeFloat", 49 | "RFJModelPropertyTypeDouble", 50 | "RFJModelPropertyTypeString", 51 | "RFJModelPropertyTypeMutableString", 52 | "RFJModelPropertyTypeArray", 53 | "RFJModelPropertyTypeMutableArray", 54 | "RFJModelPropertyTypeModelArray", 55 | "RFJModelPropertyTypeMutableModelArray", 56 | "RFJModelPropertyTypeDictionary", 57 | "RFJModelPropertyTypeMutableDictionary", 58 | "RFJModelPropertyTypeModel", 59 | "RFJModelPropertyTypeObject", 60 | }; 61 | 62 | @interface RFJModelPropertyInfo : NSObject 63 | 64 | @property (nonatomic, assign) NSInteger propertyIdx; 65 | @property (nonatomic, assign) const char * chName; 66 | @property (nonatomic, assign) BOOL isJsonProperty; 67 | @property (nonatomic, strong) NSString *name; 68 | @property (nonatomic, strong) NSString *mapName; 69 | @property (nonatomic, strong) NSString *var; 70 | @property (nonatomic, assign) RFJModelPropertyType type; 71 | @property (nonatomic, strong) NSString *typePropertyAttrib; 72 | @property (nonatomic, assign) const char *modelClassName; 73 | @property (nonatomic, weak) Class modelClass; 74 | @property (nonatomic, assign) BOOL isDynamic; 75 | @property (nonatomic, assign) SEL getterSelector; 76 | @property (nonatomic, strong) NSString *getterSelectorName; 77 | @property (nonatomic, assign) SEL setterSelector; 78 | @property (nonatomic, strong) NSString *setterSelectorName; 79 | @property (nonatomic, assign) BOOL isNonatomic; 80 | @property (nonatomic, assign) RFModelPropertyAccessType accessType; 81 | 82 | + (RFJModelPropertyInfo *)propertyInfoWithProperty:(objc_property_t _Nonnull *_Nonnull)property rootModelClass:(Class)rootModelClass; 83 | 84 | @end 85 | 86 | NS_ASSUME_NONNULL_END 87 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/Example/result_Type.txt: -------------------------------------------------------------------------------- 1 | 2 | input: 3 | @interface ExampleModelTestType : RFJModel 4 | JProperty(NSInteger value_NSInteger, map_value_NSInteger); 5 | JProperty(NSUInteger value_NSUInteger, map_value_NSUInteger); 6 | JProperty(short value_short, map_value_short); 7 | JProperty(unsigned short value_ushort, map_value_ushort); 8 | JProperty(int value_int, map_value_int); 9 | JProperty(unsigned int value_uint, map_value_uint); 10 | JProperty(long value_long, map_value_long); 11 | JProperty(unsigned long value_long_u, map_value_long_u); 12 | JProperty(long long value_long_long, map_value_long_long); 13 | JProperty(unsigned long long value_long_long_u, map_value_long_long_u); 14 | JProperty(int32_t value_int32, map_value_int32); 15 | JProperty(uint32_t value_uint32, map_value_uint32); 16 | JProperty(int16_t value_int16, map_value_int16); 17 | JProperty(uint16_t value_uint16, map_value_uint16); 18 | JProperty(int64_t value_int64, map_value_int64); 19 | JProperty(uint64_t value_uint64, map_value_uint64); 20 | JProperty(NSString *value_NSString, map_value_NSString); 21 | JProperty(NSArray *value_NSArray, map_value_NSArray); 22 | JProperty(NSDictionary *value_NSDictionary, map_value_NSDictionary); 23 | JProperty(BOOL value_Bool, map_value_Bool); 24 | JProperty(ExampleModelTestType *value_Model, map_model); 25 | JProperty(NSArray *value_models, map_models); 26 | @end 27 | 28 | output: 29 | 30 | JP name:value_NSInteger type:RFJModelPropertyTypeInt64 map:map_value_NSInteger value:0 31 | JP name:value_NSUInteger type:RFJModelPropertyTypeInt64 map:map_value_NSUInteger value:0 32 | JP name:value_short type:RFJModelPropertyTypeInt16 map:map_value_short value:0 33 | JP name:value_ushort type:RFJModelPropertyTypeInt16 map:map_value_ushort value:0 34 | JP name:value_int type:RFJModelPropertyTypeInt32 map:map_value_int value:0 35 | JP name:value_uint type:RFJModelPropertyTypeInt32 map:map_value_uint value:0 36 | JP name:value_long type:RFJModelPropertyTypeInt64 map:map_value_long value:0 37 | JP name:value_long_u type:RFJModelPropertyTypeInt64 map:map_value_long_u value:0 38 | JP name:value_long_long type:RFJModelPropertyTypeInt64 map:map_value_long_long value:0 39 | JP name:value_long_long_u type:RFJModelPropertyTypeInt64 map:map_value_long_long_u value:0 40 | JP name:value_int32 type:RFJModelPropertyTypeInt32 map:map_value_int32 value:0 41 | JP name:value_uint32 type:RFJModelPropertyTypeInt32 map:map_value_uint32 value:0 42 | JP name:value_int16 type:RFJModelPropertyTypeInt16 map:map_value_int16 value:0 43 | JP name:value_uint16 type:RFJModelPropertyTypeInt16 map:map_value_uint16 value:0 44 | JP name:value_int64 type:RFJModelPropertyTypeInt64 map:map_value_int64 value:0 45 | JP name:value_uint64 type:RFJModelPropertyTypeInt64 map:map_value_uint64 value:0 46 | JP name:value_NSString type:RFJModelPropertyTypeString map:map_value_NSString value:(null) 47 | JP name:value_NSArray type:RFJModelPropertyTypeArray map:map_value_NSArray value:(null) 48 | JP name:value_NSDictionary type:RFJModelPropertyTypeDictionary map:map_value_NSDictionary value:(null) 49 | JP name:value_Bool type:RFJModelPropertyTypeBOOL map:map_value_Bool value:0 50 | JP name:value_Model type:RFJModelPropertyTypeModel map:map_model value: 51 | JP name:value_models type:RFJModelPropertyTypeModelArray map:map_models value: -------------------------------------------------------------------------------- /RFJModel/RFJModel/Example/ExampleModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // ExampleModel1.h 3 | // RFJModel 4 | // 5 | // Created by gouzhehua on 14-12-10. 6 | // Copyright (c) 2014年 TechAtk. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import "RFJModel.h" 12 | 13 | @class ExampleModelTestType; 14 | @class ExampleModelTestJson; 15 | @class ExampleModelTestChild; 16 | @class ExampleModelTestSub; 17 | @class GrandsonModel; 18 | 19 | @protocol ExampleModelTestSub 20 | @end 21 | 22 | @interface ExampleModelTestType : RFJModel 23 | JProperty(NSInteger value_NSInteger, map_value_NSInteger); 24 | JProperty(NSUInteger value_NSUInteger, map_value_NSUInteger); 25 | JProperty(short value_short, map_value_short); 26 | JProperty(unsigned short value_ushort, map_value_ushort); 27 | JProperty(int value_int, map_value_int); 28 | JProperty(unsigned int value_uint, map_value_uint); 29 | JProperty(long value_long, map_value_long); 30 | JProperty(unsigned long value_long_u, map_value_long_u); 31 | JProperty(long long value_long_long, map_value_long_long); 32 | JProperty(unsigned long long value_long_long_u, map_value_long_long_u); 33 | JProperty(int32_t value_int32, map_value_int32); 34 | JProperty(uint32_t value_uint32, map_value_uint32); 35 | JProperty(int16_t value_int16, map_value_int16); 36 | JProperty(uint16_t value_uint16, map_value_uint16); 37 | JProperty(int64_t value_int64, map_value_int64); 38 | JProperty(uint64_t value_uint64, map_value_uint64); 39 | JProperty(NSString *value_NSString, map_value_NSString); 40 | JProperty(NSArray *value_NSArray, map_value_NSArray); 41 | JProperty(NSDictionary *value_NSDictionary, map_value_NSDictionary); 42 | JProperty(BOOL value_Bool, map_value_Bool); 43 | JProperty(ExampleModelTestType *value_Model, map_model); 44 | JProperty(NSArray *value_models, map_models); 45 | @end 46 | 47 | @interface ExampleModelTestJson : RFJModel 48 | JProperty(NSString *name, name); 49 | JProperty(short sex, sex); 50 | JProperty(int age, age); 51 | JProperty(NSString *address, address); 52 | JProperty(int64_t uid, uid); 53 | JProperty(NSInteger unset, unset); 54 | JProperty(NSArray *list, list); 55 | JProperty(NSDictionary *dict, dict); 56 | JProperty(ExampleModelTestSub *subModel, model); 57 | JProperty(NSArray *subModels, models); 58 | JProperty(NSMutableString *mstr, mstr); 59 | JProperty(NSMutableArray *mArray, mArray); 60 | JProperty(NSMutableDictionary *mDict, mDict); 61 | JProperty(NSMutableArray *mModelArray, mModelArray); 62 | JProperty(NSString *errString, errString); 63 | JProperty(NSArray *errArray, errArray); 64 | JProperty(NSDictionary *errDict, errDict); 65 | JProperty(NSArray *errModelArray, errModelArray); 66 | JProperty(ExampleModelTestSub *errModel, errModel); 67 | @end 68 | 69 | @interface ExampleModelTestChild : ExampleModelTestJson 70 | JProperty(NSString *unuse, unuse); 71 | JProperty(BOOL bYes, bYes); 72 | JProperty(BOOL bTrue, bTrue); 73 | JProperty(BOOL bTrue2, bTrue2); 74 | JProperty(BOOL b0, b0); 75 | JProperty(BOOL b1, b1); 76 | JProperty(BOOL bNo, bNo); 77 | JProperty(BOOL bFalse, bFalse); 78 | @property (nonatomic, strong) UIImage *picImg; 79 | @property (nonatomic, assign) int64_t tag; 80 | @end 81 | 82 | @interface ExampleModelTestSub : RFJModel 83 | JProperty(NSString *name, name); 84 | JProperty(NSInteger size, size); 85 | JProperty(GrandsonModel *gm, GrandsonModel); 86 | @end 87 | 88 | @interface GrandsonModel : RFJModel 89 | JProperty(NSString *name, name); 90 | @property (nonatomic, assign) int64_t tag; 91 | @end 92 | 93 | @protocol ExampleProtocol 94 | 95 | @end 96 | 97 | @interface ExampleProtocolModel : RFJModel 98 | @property (nonatomic, strong) NSString *name; 99 | @end 100 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/RFJModel/NSObject+RFSafeTransform.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+RFSafeTransform.h 3 | // RFJModel 4 | // 5 | // Created by GZH on 2017/7/4. 6 | // Copyright © 2017年 TechAtk. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "NSString+RFSafeTransform.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | #define IS_EMPTY_STR(value) \ 15 | [NSString isEmpty:value] 16 | 17 | #define J2Str(value) \ 18 | [NSObject rfj_toStringWithJsonValue:value] 19 | 20 | #define J2Integer(value) \ 21 | [NSObject rfj_toIntegerWithJsonValue:value] 22 | 23 | #define J2Bool(value) \ 24 | [NSObject rfj_toBoolWithJsonValue:value] 25 | 26 | #define J2Char(value) \ 27 | [NSObject rfj_toCharWithJsonValue:value] 28 | 29 | #define J2Int16(value) \ 30 | [NSObject rfj_toInt16WithJsonValue:value] 31 | 32 | #define J2Int32(value) \ 33 | [NSObject rfj_toInt32WithJsonValue:value] 34 | 35 | #define J2Int64(value) \ 36 | [NSObject rfj_toInt64WithJsonValue:value] 37 | 38 | #define J2Short(value) \ 39 | [NSObject rfj_toShortWithJsonValue:value] 40 | 41 | #define J2Float(value) \ 42 | [NSObject rfj_toFloatWithJsonValue:value] 43 | 44 | #define J2Double(value) \ 45 | [NSObject rfj_toDoubleWithJsonValue:value] 46 | 47 | #define J2Array(value) \ 48 | [NSObject rfj_toArrayWithJsonValue:value] 49 | 50 | #define J2Dict(value) \ 51 | [NSObject rfj_toDictionaryWithJsonValue:value] 52 | 53 | #define J2NumInteger(value) \ 54 | [NSNumber numberWithInteger:[NSObject rfj_toIntegerWithJsonValue:value]] 55 | 56 | #define J2NumBool(value) \ 57 | [NSNumber numberWithBool:[NSObject rfj_toBoolWithJsonValue:value]] 58 | 59 | #define J2NumChar(value) \ 60 | [NSNumber numberWithChar:[NSObject rfj_toCharWithJsonValue:value]] 61 | 62 | #define J2NumInt16(value) \ 63 | [NSNumber numberWithShort:[NSObject rfj_toInt16WithJsonValue:value]] 64 | 65 | #define J2NumInt32(value) \ 66 | [NSNumber numberWithInt:[NSObject rfj_toInt32WithJsonValue:value]] 67 | 68 | #define J2NumInt64(value) \ 69 | [NSNumber numberWithLongLong:[NSObject rfj_toInt64WithJsonValue:value]] 70 | 71 | #define J2NumShort(value) \ 72 | [NSNumber numberWithShort:[NSObject rfj_toShortWithJsonValue:value]] 73 | 74 | #define J2NumFloat(value) \ 75 | [NSNumber numberWithFloat:[NSObject rfj_toFloatWithJsonValue:value]] 76 | 77 | #define J2NumDouble(value) \ 78 | [NSNumber numberWithDouble:[NSObject rfj_toDoubleWithJsonValue:value]] 79 | 80 | #define V2Str(value) \ 81 | [NSString ifNilToStr:(value)] 82 | 83 | #define V2NumInteger(value) \ 84 | [NSNumber numberWithInteger:(value)] 85 | 86 | #define V2NumBool(value) \ 87 | [NSNumber numberWithBool:(value)] 88 | 89 | #define V2NumChar(value) \ 90 | [NSNumber numberWithChar:(value)] 91 | 92 | #define V2NumInt16(value) \ 93 | [NSNumber numberWithShort:(value)] 94 | 95 | #define V2NumInt32(value) \ 96 | [NSNumber numberWithInt:(value)] 97 | 98 | #define V2NumInt64(value) \ 99 | [NSNumber numberWithLongLong:(value)] 100 | 101 | #define V2NumShort(value) \ 102 | [NSNumber numberWithShort:(value)] 103 | 104 | #define V2NumFloat(value) \ 105 | [NSNumber numberWithFloat:(value)] 106 | 107 | #define V2NumDouble(value) \ 108 | [NSNumber numberWithDouble:(value)] 109 | 110 | #define V2Obj(value, class) \ 111 | [NSObject rfj_toValue:value ofClass:class] 112 | 113 | @interface NSObject (RFSafeTransform) 114 | 115 | + (NSString *)rfj_toStringWithJsonValue:(id)value; 116 | + (NSInteger)rfj_toIntegerWithJsonValue:(id)value; 117 | + (BOOL)rfj_toBoolWithJsonValue:(id)value; 118 | + (char)rfj_toCharWithJsonValue:(id)value; 119 | + (int16_t)rfj_toInt16WithJsonValue:(id)value; 120 | + (int32_t)rfj_toInt32WithJsonValue:(id)value; 121 | + (int64_t)rfj_toInt64WithJsonValue:(id)value; 122 | + (short)rfj_toShortWithJsonValue:(id)value; 123 | + (float)rfj_toFloatWithJsonValue:(id)value; 124 | + (double)rfj_toDoubleWithJsonValue:(id)value; 125 | + (id)rfj_toArrayWithJsonValue:(id)value; 126 | + (id)rfj_toDictionaryWithJsonValue:(id)value; 127 | + (id)rfj_toValue:(id)value ofClass:(Class)cls; 128 | 129 | @end 130 | 131 | NS_ASSUME_NONNULL_END 132 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/RFJModel/NSObject+RFSafeTransform.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+RFSafeTransform.m 3 | // RFJModel 4 | // 5 | // Created by GZH on 2017/7/4. 6 | // Copyright © 2017年 TechAtk. All rights reserved. 7 | // 8 | 9 | #import "NSObject+RFSafeTransform.h" 10 | 11 | @implementation NSObject (RFSafeTransform) 12 | 13 | + (NSString *)rfj_toStringWithJsonValue:(id)value 14 | { 15 | if (value == nil || value == [NSNull null]) 16 | { 17 | return nil; 18 | } 19 | 20 | if ([value isKindOfClass:[NSString class]]) 21 | { 22 | return value; 23 | } 24 | 25 | if ([value isKindOfClass:[NSNumber class]]) 26 | { 27 | return [value stringValue]; 28 | } 29 | 30 | return nil; 31 | } 32 | 33 | + (NSInteger)rfj_toIntegerWithJsonValue:(id)value 34 | { 35 | if (value == nil || value == [NSNull null]) 36 | { 37 | return 0; 38 | } 39 | 40 | if ([value isKindOfClass:[NSString class]] || [value isKindOfClass:[NSNumber class]]) 41 | { 42 | return [value integerValue]; 43 | } 44 | 45 | return 0; 46 | } 47 | 48 | + (BOOL)rfj_toBoolWithJsonValue:(id)value 49 | { 50 | if (value == nil || value == [NSNull null]) 51 | { 52 | return NO; 53 | } 54 | 55 | if ([value isKindOfClass:[NSNumber class]]) 56 | { 57 | return [value boolValue]; 58 | } 59 | 60 | if ([value isKindOfClass:[NSString class]]) 61 | { 62 | return [value boolValue]; 63 | } 64 | 65 | return NO; 66 | } 67 | 68 | + (char)rfj_toCharWithJsonValue:(id)value 69 | { 70 | if (value == nil || value == [NSNull null]) 71 | { 72 | return NO; 73 | } 74 | 75 | if ([value isKindOfClass:[NSNumber class]]) 76 | { 77 | return [value charValue]; 78 | } 79 | 80 | if ([value isKindOfClass:[NSString class]]) 81 | { 82 | return (char)[value intValue]; 83 | } 84 | 85 | return 0; 86 | } 87 | 88 | + (int16_t)rfj_toInt16WithJsonValue:(id)value 89 | { 90 | if (value == nil || value == [NSNull null]) 91 | { 92 | return 0; 93 | } 94 | 95 | if ([value isKindOfClass:[NSNumber class]]) 96 | { 97 | return [value shortValue]; 98 | } 99 | 100 | if ([value isKindOfClass:[NSString class]]) 101 | { 102 | return [value intValue]; 103 | } 104 | 105 | return 0; 106 | } 107 | 108 | + (int32_t)rfj_toInt32WithJsonValue:(id)value 109 | { 110 | if (value == nil || value == [NSNull null]) 111 | { 112 | return 0; 113 | } 114 | 115 | if ([value isKindOfClass:[NSNumber class]] || [value isKindOfClass:[NSString class]]) 116 | { 117 | return [value intValue]; 118 | } 119 | 120 | return 0; 121 | } 122 | 123 | + (int64_t)rfj_toInt64WithJsonValue:(id)value 124 | { 125 | if (value == nil || value == [NSNull null]) 126 | { 127 | return 0; 128 | } 129 | 130 | if ([value isKindOfClass:[NSNumber class]] || [value isKindOfClass:[NSString class]]) 131 | { 132 | return [value longLongValue]; 133 | } 134 | 135 | return 0; 136 | } 137 | 138 | + (short)rfj_toShortWithJsonValue:(id)value 139 | { 140 | if (value == nil || value == [NSNull null]) 141 | { 142 | return 0; 143 | } 144 | 145 | if ([value isKindOfClass:[NSNumber class]]) 146 | { 147 | return [value shortValue]; 148 | } 149 | 150 | if ([value isKindOfClass:[NSString class]]) 151 | { 152 | return [value intValue]; 153 | } 154 | 155 | return 0; 156 | } 157 | 158 | + (float)rfj_toFloatWithJsonValue:(id)value 159 | { 160 | if (value == nil || value == [NSNull null]) 161 | { 162 | return 0; 163 | } 164 | 165 | if ([value isKindOfClass:[NSNumber class]] || [value isKindOfClass:[NSString class]]) 166 | { 167 | return [value floatValue]; 168 | } 169 | 170 | return 0; 171 | } 172 | 173 | + (double)rfj_toDoubleWithJsonValue:(id)value 174 | { 175 | if (value == nil || value == [NSNull null]) 176 | { 177 | return 0; 178 | } 179 | 180 | if ([value isKindOfClass:[NSNumber class]] || [value isKindOfClass:[NSString class]]) 181 | { 182 | return [value doubleValue]; 183 | } 184 | 185 | return 0; 186 | } 187 | 188 | + (id)rfj_toArrayWithJsonValue:(id)value 189 | { 190 | if (value == nil || value == [NSNull null]) 191 | { 192 | return nil; 193 | } 194 | 195 | if ([value isKindOfClass:[NSArray class]]) 196 | { 197 | return value; 198 | } 199 | 200 | return nil; 201 | } 202 | 203 | + (id)rfj_toDictionaryWithJsonValue:(id)value 204 | { 205 | if (value == nil || value == [NSNull null]) 206 | { 207 | return nil; 208 | } 209 | 210 | if ([value isKindOfClass:[NSDictionary class]]) 211 | { 212 | return value; 213 | } 214 | 215 | return nil; 216 | } 217 | 218 | + (id)rfj_toValue:(id)value ofClass:(Class)cls 219 | { 220 | if ([value isKindOfClass:cls]) 221 | { 222 | return value; 223 | } 224 | return nil; 225 | } 226 | 227 | @end 228 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/Example/result_Json.txt: -------------------------------------------------------------------------------- 1 | 2 | input: 3 | { 4 | "name":"XiaoMing", 5 | "sex":"1", 6 | "age": 123, 7 | "address":null, 8 | "uid":9876543210123456, 9 | "unuse":"unuse value", 10 | "list":[1,2,3,4,5,6], 11 | "dict": 12 | { 13 | "value1":"1", 14 | "value2":2 15 | }, 16 | "bYes":"Yes", 17 | "bTrue":true, 18 | "bTrue2":"true", 19 | "b0":0, 20 | "b1":1, 21 | "bNo":"no", 22 | "bFalse":false, 23 | "model": 24 | { 25 | "name":"SubModel", 26 | "size":123 27 | }, 28 | "models": 29 | [ 30 | { 31 | "name":"SubModel1", 32 | "size":1, 33 | "GrandsonModel": 34 | { 35 | "name":"GM1" 36 | }, 37 | }, 38 | { 39 | "name":"SubModel2", 40 | "size":2, 41 | "GrandsonModel": 42 | { 43 | "name":"GM2" 44 | }, 45 | }, 46 | { 47 | "name":"SubModel3", 48 | "size":3, 49 | "GrandsonModel": 50 | { 51 | "name":"GM3" 52 | }, 53 | }, 54 | ], 55 | "mstr":"mutableString", 56 | "mArray":[{"k":"v"}, "string", [1, 2],], 57 | "mDict":{"k1":"string", "k2":[1,2], "k3":{"k":"v"},}, 58 | "mModelArray":[{"name":"SubModel","size":123},{"name":"SubModel","size":123},], 59 | "errString" : [], 60 | "errArray" : {}, 61 | "errDict" : "errString", 62 | "errModelArray" : "errString", 63 | "errModel" : "errModel", 64 | } 65 | 66 | 67 | output: 68 | 69 | JP name:name type:RFJModelPropertyTypeString map:name value:XiaoMing 70 | JP name:sex type:RFJModelPropertyTypeInt16 map:sex value:1 71 | JP name:age type:RFJModelPropertyTypeInt32 map:age value:123 72 | JP name:address type:RFJModelPropertyTypeString map:address value:(null) 73 | JP name:uid type:RFJModelPropertyTypeInt64 map:uid value:9876543210123456 74 | JP name:unset type:RFJModelPropertyTypeInt64 map:unset value:0 75 | JP name:list type:RFJModelPropertyTypeArray map:list value:( 76 | 1, 77 | 2, 78 | 3, 79 | 4, 80 | 5, 81 | 6 82 | ) 83 | JP name:dict type:RFJModelPropertyTypeDictionary map:dict value:{ 84 | value1 = 1; 85 | value2 = 2; 86 | } 87 | JP name:subModel type:RFJModelPropertyTypeModel map:model value: 88 | JP name:name type:RFJModelPropertyTypeString map:name value:SubModel 89 | JP name:size type:RFJModelPropertyTypeInt64 map:size value:123 90 | JP name:gm type:RFJModelPropertyTypeModel map:GrandsonModel value: 91 | JP name:subModels type:RFJModelPropertyTypeModelArray map:models value: 92 | - 93 | JP name:name type:RFJModelPropertyTypeString map:name value:SubModel1 94 | JP name:size type:RFJModelPropertyTypeInt64 map:size value:1 95 | JP name:gm type:RFJModelPropertyTypeModel map:GrandsonModel value: 96 | JP name:name type:RFJModelPropertyTypeString map:name value:GM1 97 | P name:tag value:0 98 | - 99 | JP name:name type:RFJModelPropertyTypeString map:name value:SubModel2 100 | JP name:size type:RFJModelPropertyTypeInt64 map:size value:2 101 | JP name:gm type:RFJModelPropertyTypeModel map:GrandsonModel value: 102 | JP name:name type:RFJModelPropertyTypeString map:name value:GM2 103 | P name:tag value:0 104 | - 105 | JP name:name type:RFJModelPropertyTypeString map:name value:SubModel3 106 | JP name:size type:RFJModelPropertyTypeInt64 map:size value:3 107 | JP name:gm type:RFJModelPropertyTypeModel map:GrandsonModel value: 108 | JP name:name type:RFJModelPropertyTypeString map:name value:GM3 109 | P name:tag value:0 110 | JP name:mstr type:RFJModelPropertyTypeMutableString map:mstr value:mutableString 111 | JP name:mArray type:RFJModelPropertyTypeMutableArray map:mArray value:( 112 | { 113 | k = v; 114 | }, 115 | string, 116 | ( 117 | 1, 118 | 2 119 | ) 120 | ) 121 | JP name:mDict type:RFJModelPropertyTypeMutableDictionary map:mDict value:{ 122 | k1 = string; 123 | k2 = ( 124 | 1, 125 | 2 126 | ); 127 | k3 = { 128 | k = v; 129 | }; 130 | } 131 | JP name:mModelArray type:RFJModelPropertyTypeMutableModelArray map:mModelArray value: 132 | - 133 | JP name:name type:RFJModelPropertyTypeString map:name value:SubModel 134 | JP name:size type:RFJModelPropertyTypeInt64 map:size value:123 135 | JP name:gm type:RFJModelPropertyTypeModel map:GrandsonModel value: 136 | - 137 | JP name:name type:RFJModelPropertyTypeString map:name value:SubModel 138 | JP name:size type:RFJModelPropertyTypeInt64 map:size value:123 139 | JP name:gm type:RFJModelPropertyTypeModel map:GrandsonModel value: 140 | JP name:errString type:RFJModelPropertyTypeString map:errString value:(null) 141 | JP name:errArray type:RFJModelPropertyTypeArray map:errArray value:(null) 142 | JP name:errDict type:RFJModelPropertyTypeDictionary map:errDict value:(null) 143 | JP name:errModelArray type:RFJModelPropertyTypeModelArray map:errModelArray value: 144 | JP name:errModel type:RFJModelPropertyTypeModel map:errModel value: -------------------------------------------------------------------------------- /RFJModel/RFJModel/Example/result_Inherit.txt: -------------------------------------------------------------------------------- 1 | 2 | input: 3 | { 4 | "name":"XiaoMing", 5 | "sex":"1", 6 | "age": 123, 7 | "address":null, 8 | "uid":9876543210123456, 9 | "unuse":"unuse value", 10 | "list":[1,2,3,4,5,6], 11 | "dict": 12 | { 13 | "value1":"1", 14 | "value2":2 15 | }, 16 | "bYes":"Yes", 17 | "bTrue":true, 18 | "bTrue2":"true", 19 | "b0":0, 20 | "b1":1, 21 | "bNo":"no", 22 | "bFalse":false, 23 | "model": 24 | { 25 | "name":"SubModel", 26 | "size":123 27 | }, 28 | "models": 29 | [ 30 | { 31 | "name":"SubModel1", 32 | "size":1, 33 | "GrandsonModel": 34 | { 35 | "name":"GM1" 36 | }, 37 | }, 38 | { 39 | "name":"SubModel2", 40 | "size":2, 41 | "GrandsonModel": 42 | { 43 | "name":"GM2" 44 | }, 45 | }, 46 | { 47 | "name":"SubModel3", 48 | "size":3, 49 | "GrandsonModel": 50 | { 51 | "name":"GM3" 52 | }, 53 | }, 54 | ], 55 | "mstr":"mutableString", 56 | "mArray":[{"k":"v"}, "string", [1, 2],], 57 | "mDict":{"k1":"string", "k2":[1,2], "k3":{"k":"v"},}, 58 | "mModelArray":[{"name":"SubModel","size":123},{"name":"SubModel","size":123},], 59 | "errString" : [], 60 | "errArray" : {}, 61 | "errDict" : "errString", 62 | "errModelArray" : "errString", 63 | "errModel" : "errModel", 64 | } 65 | 66 | 67 | output: 68 | 69 | JP name:unuse type:RFJModelPropertyTypeString map:unuse value:unuse value 70 | JP name:bYes type:RFJModelPropertyTypeBOOL map:bYes value:1 71 | JP name:bTrue type:RFJModelPropertyTypeBOOL map:bTrue value:1 72 | JP name:bTrue2 type:RFJModelPropertyTypeBOOL map:bTrue2 value:1 73 | JP name:b0 type:RFJModelPropertyTypeBOOL map:b0 value:0 74 | JP name:b1 type:RFJModelPropertyTypeBOOL map:b1 value:1 75 | JP name:bNo type:RFJModelPropertyTypeBOOL map:bNo value:0 76 | JP name:bFalse type:RFJModelPropertyTypeBOOL map:bFalse value:0 77 | P name:picImg value:(null) 78 | P name:tag value:0 79 | JP name:name type:RFJModelPropertyTypeString map:name value:XiaoMing 80 | JP name:sex type:RFJModelPropertyTypeInt16 map:sex value:1 81 | JP name:age type:RFJModelPropertyTypeInt32 map:age value:123 82 | JP name:address type:RFJModelPropertyTypeString map:address value:(null) 83 | JP name:uid type:RFJModelPropertyTypeInt64 map:uid value:9876543210123456 84 | JP name:unset type:RFJModelPropertyTypeInt64 map:unset value:0 85 | JP name:list type:RFJModelPropertyTypeArray map:list value:( 86 | 1, 87 | 2, 88 | 3, 89 | 4, 90 | 5, 91 | 6 92 | ) 93 | JP name:dict type:RFJModelPropertyTypeDictionary map:dict value:{ 94 | value1 = 1; 95 | value2 = 2; 96 | } 97 | JP name:subModel type:RFJModelPropertyTypeModel map:model value: 98 | JP name:name type:RFJModelPropertyTypeString map:name value:SubModel 99 | JP name:size type:RFJModelPropertyTypeInt64 map:size value:123 100 | JP name:gm type:RFJModelPropertyTypeModel map:GrandsonModel value: 101 | JP name:subModels type:RFJModelPropertyTypeModelArray map:models value: 102 | - 103 | JP name:name type:RFJModelPropertyTypeString map:name value:SubModel1 104 | JP name:size type:RFJModelPropertyTypeInt64 map:size value:1 105 | JP name:gm type:RFJModelPropertyTypeModel map:GrandsonModel value: 106 | JP name:name type:RFJModelPropertyTypeString map:name value:GM1 107 | P name:tag value:0 108 | - 109 | JP name:name type:RFJModelPropertyTypeString map:name value:SubModel2 110 | JP name:size type:RFJModelPropertyTypeInt64 map:size value:2 111 | JP name:gm type:RFJModelPropertyTypeModel map:GrandsonModel value: 112 | JP name:name type:RFJModelPropertyTypeString map:name value:GM2 113 | P name:tag value:0 114 | - 115 | JP name:name type:RFJModelPropertyTypeString map:name value:SubModel3 116 | JP name:size type:RFJModelPropertyTypeInt64 map:size value:3 117 | JP name:gm type:RFJModelPropertyTypeModel map:GrandsonModel value: 118 | JP name:name type:RFJModelPropertyTypeString map:name value:GM3 119 | P name:tag value:0 120 | JP name:mstr type:RFJModelPropertyTypeMutableString map:mstr value:mutableString 121 | JP name:mArray type:RFJModelPropertyTypeMutableArray map:mArray value:( 122 | { 123 | k = v; 124 | }, 125 | string, 126 | ( 127 | 1, 128 | 2 129 | ) 130 | ) 131 | JP name:mDict type:RFJModelPropertyTypeMutableDictionary map:mDict value:{ 132 | k1 = string; 133 | k2 = ( 134 | 1, 135 | 2 136 | ); 137 | k3 = { 138 | k = v; 139 | }; 140 | } 141 | JP name:mModelArray type:RFJModelPropertyTypeMutableModelArray map:mModelArray value: 142 | - 143 | JP name:name type:RFJModelPropertyTypeString map:name value:SubModel 144 | JP name:size type:RFJModelPropertyTypeInt64 map:size value:123 145 | JP name:gm type:RFJModelPropertyTypeModel map:GrandsonModel value: 146 | - 147 | JP name:name type:RFJModelPropertyTypeString map:name value:SubModel 148 | JP name:size type:RFJModelPropertyTypeInt64 map:size value:123 149 | JP name:gm type:RFJModelPropertyTypeModel map:GrandsonModel value: 150 | JP name:errString type:RFJModelPropertyTypeString map:errString value:(null) 151 | JP name:errArray type:RFJModelPropertyTypeArray map:errArray value:(null) 152 | JP name:errDict type:RFJModelPropertyTypeDictionary map:errDict value:(null) 153 | JP name:errModelArray type:RFJModelPropertyTypeModelArray map:errModelArray value: 154 | JP name:errModel type:RFJModelPropertyTypeModel map:errModel value: -------------------------------------------------------------------------------- /RFJModel/RFJModel/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // RFJModel 4 | // 5 | // Created by gouzhehua on 14-12-10. 6 | // Copyright (c) 2014年 TechAtk. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "ExampleModel.h" 11 | #import "ExampleCustomStorageModel.h" 12 | #import "ExampleUD.h" 13 | 14 | @interface ViewController () 15 | 16 | @end 17 | 18 | @implementation ViewController 19 | 20 | - (void)viewDidLoad 21 | { 22 | [super viewDidLoad]; 23 | // Do any additional setup after loading the view, typically from a nib. 24 | } 25 | 26 | - (void)didReceiveMemoryWarning 27 | { 28 | [super didReceiveMemoryWarning]; 29 | // Dispose of any resources that can be recreated. 30 | } 31 | 32 | - (IBAction)btnType_Click:(id)sender 33 | { 34 | NSString *filePath = [[NSBundle mainBundle] pathForResource:@"ExampleType" ofType:@"txt"]; 35 | NSString *content = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; 36 | self.tvJson.text = content; 37 | 38 | ExampleModelTestType *model = [[ExampleModelTestType alloc] init]; 39 | self.tvResult.text = [model description]; 40 | 41 | NSString *result1 = [NSString stringWithFormat:@"\ninput:\n%@\n\noutput:\n%@", self.tvJson.text, self.tvResult.text]; 42 | NSString *result2 = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"result_Type" ofType:@"txt"] 43 | encoding:NSUTF8StringEncoding error:nil]; 44 | NSLog(@"%@", result1); 45 | if ([result1 isEqualToString:result2]) 46 | { 47 | NSLog(@"result_Type OK"); 48 | } 49 | else 50 | { 51 | NSLog(@"result_Type FAIL"); 52 | } 53 | } 54 | 55 | - (IBAction)btnJson_Click:(id)sender 56 | { 57 | NSString *filePath = [[NSBundle mainBundle] pathForResource:@"ExampleJson" ofType:@"txt"]; 58 | NSString *content = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; 59 | self.tvJson.text = content; 60 | 61 | NSDictionary *json = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:filePath] options:NSJSONReadingMutableContainers error:nil]; 62 | ExampleModelTestJson *model = [[ExampleModelTestJson alloc] initWithJsonDict:json]; 63 | self.tvResult.text = [model description]; 64 | 65 | NSString *result1 = [NSString stringWithFormat:@"\ninput:\n%@\n\noutput:\n%@", self.tvJson.text, self.tvResult.text]; 66 | NSString *result2 = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"result_Json" ofType:@"txt"] 67 | encoding:NSUTF8StringEncoding error:nil]; 68 | NSLog(@"%@", result1); 69 | if ([result1 isEqualToString:result2]) 70 | { 71 | NSLog(@"result_Type OK"); 72 | } 73 | else 74 | { 75 | NSLog(@"result_Type FAIL"); 76 | } 77 | } 78 | 79 | - (IBAction)btnInherit_Click:(id)sender 80 | { 81 | NSString *filePath = [[NSBundle mainBundle] pathForResource:@"ExampleJson" ofType:@"txt"]; 82 | NSString *content = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; 83 | self.tvJson.text = content; 84 | 85 | NSDictionary *json = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:filePath] options:NSJSONReadingMutableContainers error:nil]; 86 | ExampleModelTestChild *model = [[ExampleModelTestChild alloc] initWithJsonDict:json]; 87 | self.tvResult.text = [model description]; 88 | 89 | NSString *result1 = [NSString stringWithFormat:@"\ninput:\n%@\n\noutput:\n%@", self.tvJson.text, self.tvResult.text]; 90 | NSString *result2 = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"result_Inherit" ofType:@"txt"] 91 | encoding:NSUTF8StringEncoding error:nil]; 92 | NSLog(@"%@", result1); 93 | if ([result1 isEqualToString:result2]) 94 | { 95 | NSLog(@"result_Type OK"); 96 | } 97 | else 98 | { 99 | NSLog(@"result_Type FAIL"); 100 | } 101 | 102 | // 序列化 103 | { 104 | NSData* saveData = [NSObject rfj_toDataWithModel:model]; 105 | ExampleModelTestChild *newModel = [NSObject rfj_toModelWithData:saveData class:[ExampleModelTestChild class]]; 106 | NSString *value1 = [model description]; 107 | NSString *value2 = [newModel description]; 108 | if ([value1 isEqualToString:value2]) 109 | { 110 | NSLog(@"序列化成功"); 111 | } 112 | else 113 | { 114 | NSLog(@"序列化失败"); 115 | } 116 | } 117 | 118 | // // NSObject属性排除测试 119 | // { 120 | // ExampleProtocolModel *oldM = [[ExampleProtocolModel alloc] init]; 121 | // oldM.name = [NSString stringWithFormat:@"test"]; 122 | // NSData *data = [RFJModel toDataWithModel:oldM]; 123 | // ExampleProtocolModel *newM = [RFJModel toModelWithData:data class:[ExampleProtocolModel class]]; 124 | // NSLog(@"%@", newM); 125 | // } 126 | } 127 | 128 | - (IBAction)btnCustomStorage_Click:(id)sender 129 | { 130 | // ExampleUD *ud = [[ExampleUD alloc] initWithDomain:@"www.test.com"]; 131 | // ud.testString = @"aaa"; 132 | // ud.testInt = 123; 133 | // 134 | // return; 135 | // 136 | // 137 | NSString *filePath = [[NSBundle mainBundle] pathForResource:@"ExampleCustomStorageModelJson" ofType:@"txt"]; 138 | NSString *content = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; 139 | self.tvJson.text = content; 140 | 141 | NSDictionary *json = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:filePath] options:NSJSONReadingMutableContainers error:nil]; 142 | ExampleCustomStorageModel *model = [[ExampleCustomStorageModel alloc] initWithJsonDict:json]; 143 | self.tvResult.text = [model description]; 144 | 145 | NSString *result1 = [NSString stringWithFormat:@"\ninput:\n%@\n\noutput:\n%@", self.tvJson.text, self.tvResult.text]; 146 | NSString *result2 = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"result_CustomStorage" ofType:@"txt"] 147 | encoding:NSUTF8StringEncoding error:nil]; 148 | NSLog(@"%@", result1); 149 | if ([result1 isEqualToString:result2]) 150 | { 151 | NSLog(@"result_Type OK"); 152 | } 153 | else 154 | { 155 | NSLog(@"result_Type FAIL"); 156 | } 157 | 158 | model.normalValue = @"hahaha"; 159 | model.normalStorageValue = @"aaaa"; 160 | model.weakStorageValue = [[NSMutableString alloc] initWithFormat:@"test%@", model.normalValue]; 161 | model.jpStorageCharValue1 = 'a'; 162 | model.jpStorageCharValue2 = 123; 163 | model.assignIntValue = J2Integer(@"01234567890"); 164 | 165 | static ExampleCustomStorageModel *s_model = nil; 166 | s_model = model; 167 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 168 | NSLog(@"%@", s_model.weakStorageValue); 169 | }); 170 | 171 | } 172 | 173 | @end 174 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/RFJModel/RFJModelProperty.m: -------------------------------------------------------------------------------- 1 | // 2 | // RFJModelProperty.m 3 | // RFJModel 4 | // 5 | // Created by GZH on 2017/7/4. 6 | // Copyright © 2017年 TechAtk. All rights reserved. 7 | // 8 | 9 | #import "RFJModelProperty.h" 10 | #import "NSObject+RFSafeTransform.h" 11 | 12 | @interface RFJModelPropertyInfo () 13 | 14 | + (NSMutableDictionary *)mapNSObjectProperties; 15 | - (void)setTypeAttrib:(NSString *)typeAttrib rootModelClass:(Class)rootModelClass; 16 | 17 | @end 18 | 19 | @implementation RFJModelPropertyInfo 20 | 21 | + (NSMutableDictionary *)mapNSObjectProperties 22 | { 23 | static NSMutableDictionary *s_map = nil; 24 | if (s_map == nil) 25 | { 26 | s_map = [NSMutableDictionary dictionary]; 27 | Protocol *protocol = objc_getProtocol("NSObject"); 28 | unsigned count = 0; 29 | objc_property_t *properties = protocol_copyPropertyList(protocol, &count); 30 | for (unsigned i = 0; i < count; i++) 31 | { 32 | objc_property_t property = properties[i]; 33 | NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)]; 34 | [s_map setObject:propertyName forKey:propertyName]; 35 | } 36 | free(properties); 37 | 38 | // IOS7及以前应对 39 | if (s_map.count == 0) 40 | { 41 | [s_map setObject:@"hash" forKey:@"hash"]; 42 | [s_map setObject:@"superclass" forKey:@"superclass"]; 43 | [s_map setObject:@"description" forKey:@"description"]; 44 | [s_map setObject:@"debugDescription" forKey:@"debugDescription"]; 45 | } 46 | } 47 | return s_map; 48 | } 49 | 50 | + (RFJModelPropertyInfo *)propertyInfoWithProperty:(objc_property_t _Nonnull *_Nonnull)property rootModelClass:(Class)rootModelClass 51 | { 52 | RFJModelPropertyInfo *info = [[RFJModelPropertyInfo alloc] init]; 53 | info.chName = property_getName(*property); 54 | info.name = [NSString stringWithUTF8String:info.chName]; 55 | info.accessType = RFModelPropertyAccessTypeAssign; 56 | 57 | // 系统协议属性跳过 58 | NSMutableDictionary *mapNSObjectProperties = [RFJModelPropertyInfo mapNSObjectProperties]; 59 | if ([mapNSObjectProperties objectForKey:info.name] != nil) 60 | return nil; 61 | 62 | NSString *propertyAttrString = [NSString stringWithUTF8String:property_getAttributes(*property)]; 63 | NSArray *propertyAttrArray = [propertyAttrString componentsSeparatedByString:@","]; 64 | for (NSString *attrib in propertyAttrArray) 65 | { 66 | if ([attrib hasPrefix:@"T"] && attrib.length > 1) 67 | { 68 | [info setTypeAttrib:attrib rootModelClass:rootModelClass]; 69 | if (info.isJsonProperty && info.type == RFJModelPropertyTypeNone) 70 | { 71 | NSException *e = [NSException exceptionWithName:@"Unsupport RFJModel Type" 72 | reason:[NSString stringWithFormat:@"Unsupport RFJModel Type (%@, %@)", info.name, attrib] 73 | userInfo:nil]; 74 | @throw e; 75 | } 76 | } 77 | else if ([attrib hasPrefix:@"S"] && attrib.length > 1) 78 | { 79 | info.setterSelectorName = [attrib substringFromIndex:1]; 80 | SEL sel = NSSelectorFromString(info.setterSelectorName); 81 | info.setterSelector = sel; 82 | if ([attrib hasPrefix:@"S_rfjm_"]) 83 | { 84 | // S_rfjm_mapName: 85 | info.mapName = [attrib substringWithRange:NSMakeRange(7, attrib.length-8)]; 86 | info.isJsonProperty = YES; 87 | } 88 | } 89 | else if ([attrib hasPrefix:@"G"] && attrib.length > 1) 90 | { 91 | info.getterSelectorName = [attrib substringFromIndex:1]; 92 | SEL sel = NSSelectorFromString(info.getterSelectorName); 93 | info.getterSelector = sel; 94 | } 95 | else if ([attrib hasPrefix:@"V"] && attrib.length > 1) 96 | { 97 | // V_name 98 | info.var = [attrib substringWithRange:NSMakeRange(1, attrib.length-1)]; 99 | } 100 | else if ([attrib isEqualToString:@"D"]) 101 | { 102 | info.isDynamic = YES; 103 | } 104 | else if ([attrib isEqualToString:@"N"]) 105 | { 106 | info.isNonatomic = YES; 107 | } 108 | else if ([attrib isEqualToString:@"&"]) 109 | { 110 | info.accessType = RFModelPropertyAccessTypeStrong; 111 | } 112 | else if ([attrib isEqualToString:@"W"]) 113 | { 114 | info.accessType = RFModelPropertyAccessTypeWeak; 115 | } 116 | else if ([attrib isEqualToString:@"C"]) 117 | { 118 | info.accessType = RFModelPropertyAccessTypeCopy; 119 | } 120 | } 121 | 122 | // 补充属性未声明存取SEL定义 123 | if (IS_EMPTY_STR(info.getterSelectorName)) 124 | { 125 | info.getterSelectorName = info.name; 126 | SEL sel = NSSelectorFromString(info.getterSelectorName); 127 | info.getterSelector = sel; 128 | } 129 | if (IS_EMPTY_STR(info.setterSelectorName)) 130 | { 131 | info.setterSelectorName = [NSString stringWithFormat:@"set%@%@:", 132 | [[info.name substringToIndex:1] uppercaseString], 133 | [info.name substringFromIndex:1]]; 134 | SEL sel = NSSelectorFromString(info.setterSelectorName); 135 | info.setterSelector = sel; 136 | } 137 | 138 | return info; 139 | } 140 | 141 | - (void)setTypeAttrib:(NSString *)typeAttrib rootModelClass:(Class)rootModelClass 142 | { 143 | self.typePropertyAttrib = typeAttrib; 144 | 145 | if ([typeAttrib hasPrefix:@"Tb"] || [typeAttrib hasPrefix:@"TB"]) 146 | { 147 | self.type = RFJModelPropertyTypeBOOL; 148 | } 149 | else if ([typeAttrib hasPrefix:@"Tc"] || [typeAttrib hasPrefix:@"TC"]) 150 | { 151 | self.type = RFJModelPropertyTypeChar; 152 | } 153 | else if ([typeAttrib hasPrefix:@"Ti"] || [typeAttrib hasPrefix:@"TI"]) 154 | { 155 | self.type = RFJModelPropertyTypeInt32; 156 | } 157 | else if ([typeAttrib hasPrefix:@"Tl"] || [typeAttrib hasPrefix:@"TL"]) 158 | { 159 | self.type = RFJModelPropertyTypeInt32; 160 | } 161 | else if ([typeAttrib hasPrefix:@"Tq"] || [typeAttrib hasPrefix:@"TQ"]) 162 | { 163 | self.type = RFJModelPropertyTypeInt64; 164 | } 165 | else if ([typeAttrib hasPrefix:@"Ts"] || [typeAttrib hasPrefix:@"TS"]) 166 | { 167 | self.type = RFJModelPropertyTypeInt16; 168 | } 169 | else if ([typeAttrib hasPrefix:@"Tf"] || [typeAttrib hasPrefix:@"TF"]) 170 | { 171 | self.type = RFJModelPropertyTypeFloat; 172 | } 173 | else if ([typeAttrib hasPrefix:@"Td"] || [typeAttrib hasPrefix:@"TD"]) 174 | { 175 | self.type = RFJModelPropertyTypeDouble; 176 | } 177 | else if ([typeAttrib hasPrefix:@"T@\"NSString\""]) 178 | { 179 | self.type = RFJModelPropertyTypeString; 180 | } 181 | else if ([typeAttrib hasPrefix:@"T@\"NSMutableString\""]) 182 | { 183 | self.type = RFJModelPropertyTypeMutableString; 184 | } 185 | else if ([typeAttrib hasPrefix:@"T@\"NSArray\""]) 186 | { 187 | self.type = RFJModelPropertyTypeArray; 188 | } 189 | else if ([typeAttrib hasPrefix:@"T@\"NSMutableArray\""]) 190 | { 191 | self.type = RFJModelPropertyTypeMutableArray; 192 | } 193 | else if ([typeAttrib hasPrefix:@"T@\"NSArray<"]) 194 | { 195 | // T@"NSArray" 196 | const char *className = [[typeAttrib substringWithRange:NSMakeRange(11, typeAttrib.length-13)] cStringUsingEncoding:NSUTF8StringEncoding]; 197 | Class cls = objc_getClass(className); 198 | if (cls != nil && [cls isSubclassOfClass:rootModelClass]) 199 | { 200 | self.type = RFJModelPropertyTypeModelArray; 201 | self.modelClassName = className; 202 | self.modelClass = cls; 203 | } 204 | } 205 | else if ([typeAttrib hasPrefix:@"T@\"NSMutableArray<"]) 206 | { 207 | // T@"NSMutableArray" 208 | const char *className = [[typeAttrib substringWithRange:NSMakeRange(18, typeAttrib.length-20)] cStringUsingEncoding:NSUTF8StringEncoding]; 209 | Class cls = objc_getClass(className); 210 | if (cls != nil && [cls isSubclassOfClass:rootModelClass]) 211 | { 212 | self.type = RFJModelPropertyTypeMutableModelArray; 213 | self.modelClassName = className; 214 | self.modelClass = cls; 215 | } 216 | } 217 | else if ([typeAttrib hasPrefix:@"T@\"NSDictionary\""]) 218 | { 219 | self.type = RFJModelPropertyTypeDictionary; 220 | } 221 | else if ([typeAttrib hasPrefix:@"T@\"NSMutableDictionary\""]) 222 | { 223 | self.type = RFJModelPropertyTypeMutableDictionary; 224 | } 225 | else if ([typeAttrib hasPrefix:@"T@"] && typeAttrib.length > 4) 226 | { 227 | const char *className = [[typeAttrib substringWithRange:NSMakeRange(3, typeAttrib.length-4)] cStringUsingEncoding:NSUTF8StringEncoding]; 228 | Class cls = objc_getClass(className); 229 | if (cls != nil) 230 | { 231 | // TODO:没测过不同基类的转换 232 | if ([cls isSubclassOfClass:rootModelClass]) { 233 | self.type = RFJModelPropertyTypeModel; 234 | self.modelClassName = className; 235 | self.modelClass = cls; 236 | } else { 237 | self.type = RFJModelPropertyTypeObject; 238 | } 239 | } 240 | } 241 | } 242 | 243 | @end 244 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | RFJModel 2 | ======== 3 | 4 | RFJModel is an easy-to-use JSON modelling library. In comparing with other libraries, it's much easiler and less restricted to use. RFJModel has the following characteristics. 5 | 6 | ####Note. Support ARC Only 7 | 8 | ####1. Defining loading rules in the class declaration. 9 | RFJModel uses a macro, called JProperty, to declare loading rules. JProperty declares loading properties, converted types and mapping keys in JSON. The following example is to declare a property called "value_NSString". When JSON is loading, RFJModel gets the value from field "map_value_NSString" in JSON, converts the field type to NSString, and sets the value to the property "value_NSString". 10 | 11 | ```objective-c 12 | @interface ExampleJModel : RFJModel 13 | JProperty(NSString *value_NSString, map_value_NSString); 14 | @end 15 | 16 | @implementation ExampleJModel 17 | @end 18 | ``` 19 | ```json 20 | { 21 | "map_value_NSString":"hello world", 22 | } 23 | ``` 24 | ```objective-c 25 | NSDictionary *json = ...; 26 | ExampleJModel *model = [[ExampleJModel alloc] initWithJsonDict:json]; 27 | NSLog(@"%@", model.value_NSString); 28 | ``` 29 | 30 | ####2. Supporting JProperty、@property mixing declaration without influencing each other. 31 | In the following example, only "value_NSString" will be loaded, not "tag". 32 | 33 | ```objective-c 34 | @interface ExampleJModel : RFJModel 35 | JProperty(NSString *value_NSString, map_value_NSString); 36 | @property (nonatomic, assign) int64_t tag; 37 | @end 38 | ``` 39 | ####3. Reducing crashes from errors returned by the servers 40 | * All [NSNull null] objects will be converted appropriately, and would not be set to JProperty. (Lacking protections to [NSNull null] is a main cause of the crashes.) 41 | * When setting the values, the value of JSON will be converted basing on the type of JProperty. For example, the Number in JSON will be converted into NSString in JProperty. 42 | * Extra or missing fields in a JSON dictionary would not be considered as an error. 43 | 44 | ####4. Supporting class inherits 45 | ```objective-c 46 | @interface ExampleJModel : RFJModel 47 | JProperty(NSString *value_NSString, map_value_NSString); 48 | @property (nonatomic, assign) int64_t tag; 49 | @end 50 | 51 | @interface ExampleJSubModel : ExampleJModel 52 | JProperty(NSString *name, name); 53 | @end 54 | ``` 55 | ```json 56 | { 57 | "map_value_NSString":"hello world", 58 | "name":"Tom", 59 | } 60 | ``` 61 | ```objective-c 62 | NSDictionary *json = ...; 63 | ExampleJModel *model = [[ExampleJModel alloc] initWithJsonDict:json]; 64 | NSLog(@"%@", model.value_NSString); // "hello world" 65 | 66 | NSDictionary *json = ...; 67 | ExampleJSubModel *model = [[ExampleJSubModel alloc] initWithJsonDict:json]; 68 | NSLog(@"%@", model.value_NSString); // "hello world" 69 | NSLog(@"%@", model.name); // "Tom" 70 | ``` 71 | ####5. Supporting RFJModel subclasses in JProperty 72 | ```objective-c 73 | @interface ExampleJModel : RFJModel 74 | JProperty(NSString *value_NSString, map_value_NSString); 75 | @property (nonatomic, assign) int64_t tag; 76 | JProperty(ExampleJUserInfo *userInfo, UserInfo); 77 | @end 78 | 79 | @interface ExampleJUserInfo : RFJModel 80 | JProperty(NSString *name, name); 81 | @end 82 | ``` 83 | ```json 84 | { 85 | "map_value_NSString":"hello world", 86 | "UserInfo": 87 | { 88 | "name":"Tom", 89 | }, 90 | } 91 | ``` 92 | ####6. Supporting arrays containing instances of RFJModel subclasses in JProperty 93 | ```objective-c 94 | @protocol ExampleJUserInfo 95 | @end 96 | 97 | @interface ExampleJModel : RFJModel 98 | JProperty(NSString *value_NSString, map_value_NSString); 99 | @property (nonatomic, assign) int64_t tag; 100 | JProperty(NSArray *userInfos, UserInfos); 101 | @end 102 | 103 | @interface ExampleJUserInfo : RFJModel 104 | JProperty(NSString *name, name); 105 | @end 106 | ``` 107 | ```json 108 | { 109 | "map_value_NSString":"hello world", 110 | "UserInfos":[ 111 | { 112 | "name":"Tom", 113 | }, 114 | { 115 | "name":"Alice", 116 | }, 117 | ], 118 | } 119 | ``` 120 | ####7. Supporting NSMutableString, NSMutableArray and NSMutableDictionary in JProperty and Converting nested containers to mutable containers. 121 | 122 | ####8. Supporting given types in JProperty only, and an execption will be thrown if any other type is in use 123 | * BOOL 124 | * Number(NSInteger, short, long long, double, etc) 125 | * NSString 126 | * NSMutableString 127 | * NSArray 128 | * NSMutableArray 129 | * NSDictionary 130 | * NSMutableDictionary 131 | * RFJModel's subclass 132 | * NSArray (RFJModel's subclass) 133 | * NSMutableArray (RFJModel's subclass) 134 | 135 | ####9. The RFJModel implements NSCoding protocol. Support automatic serialization. 136 | 137 | Finally, thanks to @sunpc for the translation. 138 | 139 | ======== 140 | 141 | RFJModel是一个IOS类库,可以将JSON字典自动装填到OBJC对象。相比其他JSON装填库,RFJModel使用上更为简单,限制更少。 142 | 143 | ####注意:仅支持ARC 144 | 145 | RFJModel有以下几个特点 146 | 147 | ####1、声明时确定装填行为。 148 | RFJModel使用JProperty宏,以声明此属性是否用于JSON装填,装填类型,以及在JSON中的KEY。 149 | 150 | 下面的例子声明了一个value_NSString属性,他会将字典中的map_value_NSString字段,转换为NSString,设置到属性value_NSString。 151 | 152 | ```objective-c 153 | @interface ExampleJModel : RFJModel 154 | JProperty(NSString *value_NSString, map_value_NSString); 155 | @end 156 | 157 | @implementation ExampleJModel 158 | @end 159 | ``` 160 | ```json 161 | { 162 | "map_value_NSString":"hello world", 163 | } 164 | ``` 165 | ```objective-c 166 | NSDictionary *json = ...; 167 | ExampleJModel *model = [[ExampleJModel alloc] initWithJsonDict:json]; 168 | NSLog(@"%@", model.value_NSString); 169 | ``` 170 | 171 | ####2、RFJModel支持JProperty、@property混合声明,不相互影响。 172 | 173 | 下面的例子中只有value_NSString属性被自动装填,tag属性不被RFJModel所管理 174 | ```objective-c 175 | @interface ExampleJModel : RFJModel 176 | JProperty(NSString *value_NSString, map_value_NSString); 177 | @property (nonatomic, assign) int64_t tag; 178 | @end 179 | ``` 180 | ####3、RFJModel设计的目的之一,是为了尽可能减少由于服务端接口定义或返回有误导致IOS客户端崩溃的问题。所以引入以下几个特性 181 | * 所有的[NSNull null]对象都会被适当转换,不会赋值到JProperty属性。(因缺乏对[NSNull null]防护导致的崩溃,是JSON解析崩溃最主要的原因) 182 | * 赋值时,会根据JProperty声明的属性类型对JSON值进行转换。比如JSON中的Number赋值时可以被自动转换为NSString。 183 | * JSON字典中多余或者缺失的字段不报错。 184 | 185 | ####4、RFJModel支持继承 186 | ```objective-c 187 | @interface ExampleJModel : RFJModel 188 | JProperty(NSString *value_NSString, map_value_NSString); 189 | @property (nonatomic, assign) int64_t tag; 190 | @end 191 | 192 | @interface ExampleJSubModel : ExampleJModel 193 | JProperty(NSString *name, name); 194 | @end 195 | ``` 196 | ```json 197 | { 198 | "map_value_NSString":"hello world", 199 | "name":"Tom", 200 | } 201 | ``` 202 | ```objective-c 203 | NSDictionary *json = ...; 204 | ExampleJModel *model = [[ExampleJModel alloc] initWithJsonDict:json]; 205 | NSLog(@"%@", model.value_NSString); // "hello world" 206 | 207 | NSDictionary *json = ...; 208 | ExampleJSubModel *model = [[ExampleJSubModel alloc] initWithJsonDict:json]; 209 | NSLog(@"%@", model.value_NSString); // "hello world" 210 | NSLog(@"%@", model.name); // "Tom" 211 | ``` 212 | ####5、JProperty支持的类型包括RFJModel的子类。 213 | ```objective-c 214 | @interface ExampleJModel : RFJModel 215 | JProperty(NSString *value_NSString, map_value_NSString); 216 | @property (nonatomic, assign) int64_t tag; 217 | JProperty(ExampleJUserInfo *userInfo, UserInfo); 218 | @end 219 | 220 | @interface ExampleJUserInfo : RFJModel 221 | JProperty(NSString *name, name); 222 | @end 223 | ``` 224 | ```json 225 | { 226 | "map_value_NSString":"hello world", 227 | "UserInfo": 228 | { 229 | "name":"Tom", 230 | }, 231 | } 232 | ``` 233 | ####6、JProperty支持的类型包括RFJModel子类的数组。 234 | ```objective-c 235 | @protocol ExampleJUserInfo 236 | @end 237 | 238 | @interface ExampleJModel : RFJModel 239 | JProperty(NSString *value_NSString, map_value_NSString); 240 | @property (nonatomic, assign) int64_t tag; 241 | JProperty(NSArray *userInfos, UserInfos); 242 | @end 243 | 244 | @interface ExampleJUserInfo : RFJModel 245 | JProperty(NSString *name, name); 246 | @end 247 | ``` 248 | ```json 249 | { 250 | "map_value_NSString":"hello world", 251 | "UserInfos":[ 252 | { 253 | "name":"Tom", 254 | }, 255 | { 256 | "name":"Alice", 257 | }, 258 | ], 259 | } 260 | ``` 261 | ####7、JProperty支持NSMutableString、NSMutableArray、NSMutableDictionary可变类型。同时NSMutableArray、NSMutableDictionary嵌套的容器也将尽可能转换为可变类型。 262 | 263 | ####8、JProperty只支持下面的类型声明。如非以下类型被声明,将在第一次使用时抛出异常 264 | * BOOL 265 | * Number(NSInteger, short, long long, double, etc) 266 | * NSString 267 | * NSMutableString 268 | * NSArray 269 | * NSMutableArray 270 | * NSDictionary 271 | * NSMutableDictionary 272 | * RFJModel's subclass 273 | * NSArray (RFJModel's subclass) 274 | * NSMutableArray (RFJModel's subclass) 275 | 276 | ####9. RFJModel实现了NSCoding协议。支持自动序列化。 277 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 49 | 62 | 75 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/RFJModel/NSObject+RFJModelProperty.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+RFJModelProperty.m 3 | // RFJModel 4 | // 5 | // Created by GZH on 2017/7/4. 6 | // Copyright © 2017年 TechAtk. All rights reserved. 7 | // 8 | 9 | #import "NSObject+RFJModelProperty.h" 10 | #import "NSObject+RFSafeTransform.h" 11 | #import 12 | 13 | @interface NSObject (RFJModelPropertyInner) 14 | 15 | + (NSMutableDictionary *)rfj_model2RootModel; 16 | + (NSMutableDictionary *)rfj_modelPropertyInfos; 17 | 18 | + (NSMutableDictionary *)rfj_modelSelector2PropertyInfos; 19 | + (void)rfj_generateUndefineGetterOfClass:(Class)cls byPropertyInfo:(RFJModelPropertyInfo *)pi; 20 | + (void)rfj_generateUndefineSetterOfClass:(Class)cls byPropertyInfo:(RFJModelPropertyInfo *)pi; 21 | 22 | @end 23 | 24 | static NSRecursiveLock *s_RFJModelLock = nil; 25 | 26 | @implementation NSObject (RFJModelProperty) 27 | 28 | + (void)load 29 | { 30 | static dispatch_once_t onceToken; 31 | dispatch_once(&onceToken, ^{ 32 | s_RFJModelLock = [[NSRecursiveLock alloc] init]; 33 | s_RFJModelLock.name = @"RFJModelLock"; 34 | }); 35 | } 36 | 37 | + (void)rfj_analyseModelWithClass:(Class)cls rootModelClass:(Class)rootModelClass 38 | { 39 | [s_RFJModelLock lock]; 40 | 41 | NSString *className = NSStringFromClass(cls); 42 | if ([[NSObject rfj_model2RootModel] objectForKey:className] == nil 43 | && [cls isSubclassOfClass:rootModelClass]) 44 | { 45 | NSString *rootModelClassName = NSStringFromClass(rootModelClass); 46 | NSMutableDictionary *mapProperInfos = [NSMutableDictionary dictionary]; 47 | NSMutableDictionary *mapJsonProperInfos = [NSMutableDictionary dictionary]; 48 | NSMutableDictionary *mapSelector2PropertyInfos = [NSMutableDictionary dictionary]; 49 | 50 | Class current = cls; 51 | NSInteger propertyIdx = 0; 52 | while (current != rootModelClass) 53 | { 54 | unsigned count = 0; 55 | objc_property_t *properties = class_copyPropertyList(current, &count); 56 | for (unsigned i = 0; i < count; i++) 57 | { 58 | objc_property_t property = properties[i]; 59 | RFJModelPropertyInfo *pi = [RFJModelPropertyInfo propertyInfoWithProperty:&property rootModelClass:rootModelClass]; 60 | if (pi != nil) 61 | { 62 | pi.propertyIdx = propertyIdx++; 63 | [mapProperInfos setObject:pi forKey:pi.name]; 64 | if (pi.isJsonProperty && !IS_EMPTY_STR(pi.mapName)) 65 | { 66 | [mapJsonProperInfos setObject:pi forKey:pi.mapName]; 67 | } 68 | 69 | // 建立SEL2Property映射关系 70 | mapSelector2PropertyInfos[pi.getterSelectorName] = pi; 71 | mapSelector2PropertyInfos[pi.setterSelectorName] = pi; 72 | 73 | // 生成未定义的Property方法 74 | [NSObject rfj_generateUndefineGetterOfClass:current byPropertyInfo:pi]; 75 | [NSObject rfj_generateUndefineSetterOfClass:current byPropertyInfo:pi]; 76 | } 77 | } 78 | free(properties); 79 | 80 | current = [current superclass]; 81 | } 82 | 83 | [[NSObject rfj_modelPropertyInfos] setObject:mapProperInfos forKey:className]; 84 | [[NSObject rfj_modelSelector2PropertyInfos] setObject:mapSelector2PropertyInfos forKey:className]; 85 | [[NSObject rfj_model2RootModel] setObject:rootModelClassName forKey:className]; 86 | } 87 | 88 | [s_RFJModelLock unlock]; 89 | } 90 | 91 | + (NSMutableDictionary *)rfj_model2RootModel 92 | { 93 | static NSMutableDictionary *s_instance = nil; 94 | 95 | static dispatch_once_t onceToken; 96 | dispatch_once(&onceToken, ^{ 97 | s_instance = [[NSMutableDictionary alloc] init]; 98 | }); 99 | 100 | return s_instance; 101 | } 102 | 103 | + (NSMutableDictionary *)rfj_modelPropertyInfos 104 | { 105 | static NSMutableDictionary *s_instance = nil; 106 | 107 | static dispatch_once_t onceToken; 108 | dispatch_once(&onceToken, ^{ 109 | s_instance = [[NSMutableDictionary alloc] init]; 110 | }); 111 | 112 | return s_instance; 113 | } 114 | 115 | + (BOOL)rfj_isRFJModel:(Class)cls 116 | { 117 | NSString *rootModelClassName = nil; 118 | [s_RFJModelLock lock]; 119 | { 120 | rootModelClassName = [[NSObject rfj_model2RootModel] objectForKey:NSStringFromClass(cls)]; 121 | } 122 | [s_RFJModelLock unlock]; 123 | return (rootModelClassName != nil); 124 | } 125 | 126 | - (NSString *)rfj_getClassName 127 | { 128 | static void *kRFJModelClassNameKey = "kRFJModelClassNameKey"; 129 | NSString *name = (NSString *)objc_getAssociatedObject(self, kRFJModelClassNameKey); 130 | if (name == nil) 131 | { 132 | name = NSStringFromClass([self class]); 133 | objc_setAssociatedObject(self, kRFJModelClassNameKey, name, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 134 | } 135 | return name; 136 | } 137 | 138 | - (NSString *)rfj_getRootModelClassName 139 | { 140 | NSString *rootModelClassName = nil; 141 | [s_RFJModelLock lock]; 142 | { 143 | rootModelClassName = [[NSObject rfj_model2RootModel] objectForKey:[self rfj_getClassName]]; 144 | } 145 | [s_RFJModelLock unlock]; 146 | return rootModelClassName; 147 | } 148 | 149 | - (BOOL)rfj_isRFJModel 150 | { 151 | return ([self rfj_getRootModelClassName] != nil); 152 | } 153 | 154 | - (NSMutableDictionary *)rfj_getPropertyInfos 155 | { 156 | NSMutableDictionary *infos = nil; 157 | [s_RFJModelLock lock]; 158 | { 159 | infos = [[NSObject rfj_modelPropertyInfos] objectForKey:[self rfj_getClassName]]; 160 | } 161 | [s_RFJModelLock unlock]; 162 | return infos; 163 | } 164 | 165 | #pragma mark - 自动为动态属性添加方法 166 | 167 | - (RFJModelPropertyInfo *)propertyInfoForSelector:(SEL)selector 168 | { 169 | NSString *key = NSStringFromSelector(selector); 170 | NSDictionary *mapSelector2PropertyInfos = [self rfj_getSelector2PropertyInfos]; 171 | return [mapSelector2PropertyInfos objectForKey:key]; 172 | } 173 | 174 | static short rfjModelMappingInt16Getter(id self, SEL _cmd) 175 | { 176 | RFJModelPropertyInfo *pi = [self propertyInfoForSelector:_cmd]; 177 | return [[self valueForKey:pi.name] shortValue]; 178 | } 179 | 180 | static void rfjModelMappingInt16Setter(id self, SEL _cmd, short value) 181 | { 182 | RFJModelPropertyInfo *pi = [self propertyInfoForSelector:_cmd]; 183 | [self setValue:V2NumInt16(value) forKey:pi.name]; 184 | } 185 | 186 | static int rfjModelMappingInt32Getter(id self, SEL _cmd) 187 | { 188 | RFJModelPropertyInfo *pi = [self propertyInfoForSelector:_cmd]; 189 | return [[self valueForKey:pi.name] intValue]; 190 | } 191 | 192 | static void rfjModelMappingInt32Setter(id self, SEL _cmd, int value) 193 | { 194 | RFJModelPropertyInfo *pi = [self propertyInfoForSelector:_cmd]; 195 | [self setValue:V2NumInt32(value) forKey:pi.name]; 196 | } 197 | 198 | static long long rfjModelMappingInt64Getter(id self, SEL _cmd) 199 | { 200 | RFJModelPropertyInfo *pi = [self propertyInfoForSelector:_cmd]; 201 | return [[self valueForKey:pi.name] longLongValue]; 202 | } 203 | 204 | static void rfjModelMappingInt64Setter(id self, SEL _cmd, long long value) 205 | { 206 | RFJModelPropertyInfo *pi = [self propertyInfoForSelector:_cmd]; 207 | [self setValue:V2NumInt64(value) forKey:pi.name]; 208 | } 209 | 210 | static BOOL rfjModelMappingBoolGetter(id self, SEL _cmd) 211 | { 212 | RFJModelPropertyInfo *pi = [self propertyInfoForSelector:_cmd]; 213 | return [[self valueForKey:pi.name] boolValue]; 214 | } 215 | 216 | static void rfjModelMappingBoolSetter(id self, SEL _cmd, BOOL value) 217 | { 218 | RFJModelPropertyInfo *pi = [self propertyInfoForSelector:_cmd]; 219 | [self setValue:V2NumBool(value) forKey:pi.name]; 220 | } 221 | 222 | static char rfjModelMappingCharGetter(id self, SEL _cmd) 223 | { 224 | RFJModelPropertyInfo *pi = [self propertyInfoForSelector:_cmd]; 225 | return [[self valueForKey:pi.name] charValue]; 226 | } 227 | 228 | static void rfjModelMappingCharSetter(id self, SEL _cmd, char value) 229 | { 230 | RFJModelPropertyInfo *pi = [self propertyInfoForSelector:_cmd]; 231 | [self setValue:V2NumChar(value) forKey:pi.name]; 232 | } 233 | 234 | static float rfjModelMappingFloatGetter(id self, SEL _cmd) 235 | { 236 | RFJModelPropertyInfo *pi = [self propertyInfoForSelector:_cmd]; 237 | return [[self valueForKey:pi.name] floatValue]; 238 | } 239 | 240 | static void rfjModelMappingFloatSetter(id self, SEL _cmd, float value) 241 | { 242 | RFJModelPropertyInfo *pi = [self propertyInfoForSelector:_cmd]; 243 | [self setValue:V2NumFloat(value) forKey:pi.name]; 244 | } 245 | 246 | static double rfjModelMappingDoubleGetter(id self, SEL _cmd) 247 | { 248 | RFJModelPropertyInfo *pi = [self propertyInfoForSelector:_cmd]; 249 | return [[self valueForKey:pi.name] doubleValue]; 250 | } 251 | 252 | static void rfjModelMappingDoubleSetter(id self, SEL _cmd, double value) 253 | { 254 | RFJModelPropertyInfo *pi = [self propertyInfoForSelector:_cmd]; 255 | [self setValue:V2NumDouble(value) forKey:pi.name]; 256 | } 257 | 258 | static id rfjModelMappingObjectGetter(id self, SEL _cmd) 259 | { 260 | RFJModelPropertyInfo *pi = [self propertyInfoForSelector:_cmd]; 261 | return [self valueForKey:pi.name]; 262 | } 263 | 264 | static void rfjModelMappingObjectSetter(id self, SEL _cmd, id object) 265 | { 266 | RFJModelPropertyInfo *pi = [self propertyInfoForSelector:_cmd]; 267 | [self setValue:object forKey:pi.name]; 268 | } 269 | 270 | + (NSMutableDictionary *)rfj_modelSelector2PropertyInfos 271 | { 272 | static NSMutableDictionary *s_instance = nil; 273 | 274 | static dispatch_once_t onceToken; 275 | dispatch_once(&onceToken, ^{ 276 | s_instance = [[NSMutableDictionary alloc] init]; 277 | }); 278 | 279 | return s_instance; 280 | } 281 | 282 | - (NSMutableDictionary *)rfj_getSelector2PropertyInfos 283 | { 284 | NSMutableDictionary *infos = nil; 285 | [s_RFJModelLock lock]; 286 | { 287 | infos = [[NSObject rfj_modelSelector2PropertyInfos] objectForKey:[self rfj_getClassName]]; 288 | } 289 | [s_RFJModelLock unlock]; 290 | return infos; 291 | } 292 | 293 | + (void)rfj_generateUndefineGetterOfClass:(Class)cls byPropertyInfo:(RFJModelPropertyInfo *)pi 294 | { 295 | if ([cls instancesRespondToSelector:pi.getterSelector]) { 296 | return; 297 | } 298 | 299 | const char *getter = [pi.getterSelectorName cStringUsingEncoding:NSASCIIStringEncoding]; 300 | SEL getterSel = sel_registerName(getter); 301 | 302 | IMP getterImp = NULL; 303 | switch (pi.type) { 304 | case RFJModelPropertyTypeInt16: 305 | getterImp = (IMP)rfjModelMappingInt16Getter; 306 | break; 307 | case RFJModelPropertyTypeInt32: 308 | getterImp = (IMP)rfjModelMappingInt32Getter; 309 | break; 310 | case RFJModelPropertyTypeInt64: 311 | getterImp = (IMP)rfjModelMappingInt64Getter; 312 | break; 313 | case RFJModelPropertyTypeBOOL: 314 | getterImp = (IMP)rfjModelMappingBoolGetter; 315 | break; 316 | case RFJModelPropertyTypeChar: 317 | getterImp = (IMP)rfjModelMappingCharGetter; 318 | break; 319 | case RFJModelPropertyTypeFloat: 320 | getterImp = (IMP)rfjModelMappingFloatGetter; 321 | break; 322 | case RFJModelPropertyTypeDouble: 323 | getterImp = (IMP)rfjModelMappingDoubleGetter; 324 | break; 325 | case RFJModelPropertyTypeString: 326 | case RFJModelPropertyTypeMutableString: 327 | case RFJModelPropertyTypeArray: 328 | case RFJModelPropertyTypeMutableArray: 329 | case RFJModelPropertyTypeModelArray: 330 | case RFJModelPropertyTypeMutableModelArray: 331 | case RFJModelPropertyTypeDictionary: 332 | case RFJModelPropertyTypeMutableDictionary: 333 | case RFJModelPropertyTypeModel: 334 | case RFJModelPropertyTypeObject: 335 | getterImp = (IMP)rfjModelMappingObjectGetter; 336 | break; 337 | default: 338 | return; 339 | } 340 | 341 | char types[5]; 342 | snprintf(types, 4, "%c@:", [pi.typePropertyAttrib characterAtIndex:1]); 343 | class_addMethod(cls, getterSel, getterImp, types); 344 | } 345 | 346 | + (void)rfj_generateUndefineSetterOfClass:(Class)cls byPropertyInfo:(RFJModelPropertyInfo *)pi 347 | { 348 | if ([cls instancesRespondToSelector:pi.setterSelector]) { 349 | return; 350 | } 351 | 352 | const char *setter = [pi.setterSelectorName cStringUsingEncoding:NSASCIIStringEncoding]; 353 | SEL setterSel = sel_registerName(setter); 354 | 355 | IMP setterImp = NULL; 356 | switch (pi.type) { 357 | case RFJModelPropertyTypeInt16: 358 | setterImp = (IMP)rfjModelMappingInt16Setter; 359 | break; 360 | case RFJModelPropertyTypeInt32: 361 | setterImp = (IMP)rfjModelMappingInt32Setter; 362 | break; 363 | case RFJModelPropertyTypeInt64: 364 | setterImp = (IMP)rfjModelMappingInt64Setter; 365 | break; 366 | case RFJModelPropertyTypeBOOL: 367 | setterImp = (IMP)rfjModelMappingBoolSetter; 368 | break; 369 | case RFJModelPropertyTypeChar: 370 | setterImp = (IMP)rfjModelMappingCharSetter; 371 | break; 372 | case RFJModelPropertyTypeFloat: 373 | setterImp = (IMP)rfjModelMappingFloatSetter; 374 | break; 375 | case RFJModelPropertyTypeDouble: 376 | setterImp = (IMP)rfjModelMappingDoubleSetter; 377 | break; 378 | case RFJModelPropertyTypeString: 379 | case RFJModelPropertyTypeMutableString: 380 | case RFJModelPropertyTypeArray: 381 | case RFJModelPropertyTypeMutableArray: 382 | case RFJModelPropertyTypeModelArray: 383 | case RFJModelPropertyTypeMutableModelArray: 384 | case RFJModelPropertyTypeDictionary: 385 | case RFJModelPropertyTypeMutableDictionary: 386 | case RFJModelPropertyTypeModel: 387 | case RFJModelPropertyTypeObject: 388 | setterImp = (IMP)rfjModelMappingObjectSetter; 389 | break; 390 | default: 391 | return; 392 | } 393 | 394 | char types[5]; 395 | snprintf(types, 5, "v@:%c", [pi.typePropertyAttrib characterAtIndex:1]); 396 | class_addMethod(cls, setterSel, setterImp, types); 397 | } 398 | 399 | @end 400 | -------------------------------------------------------------------------------- /RFJModel/RFJModel/RFJModel/NSObject+RFJModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+RFJModel.m 3 | // RFJModel 4 | // 5 | // Created by GZH on 2017/7/4. 6 | // Copyright © 2017年 TechAtk. All rights reserved. 7 | // 8 | 9 | #import "NSObject+RFJModel.h" 10 | 11 | @interface NSObject (RFJModelInner) 12 | + (NSMutableDictionary *)rfj_swizzledRootModels; 13 | @end 14 | 15 | static NSRecursiveLock *s_RFJModelTransformKeyLock = nil; 16 | static NSRecursiveLock *s_RFJModelSwizzledRootModelLock = nil; 17 | 18 | @implementation NSObject (RFJModel) 19 | @dynamic rfj_storageDelegate; 20 | 21 | + (void)load 22 | { 23 | static dispatch_once_t onceToken; 24 | dispatch_once(&onceToken, ^{ 25 | s_RFJModelTransformKeyLock = [[NSRecursiveLock alloc] init]; 26 | s_RFJModelTransformKeyLock.name = @"RFJModelTransformKeyLock"; 27 | s_RFJModelSwizzledRootModelLock = [[NSRecursiveLock alloc] init]; 28 | s_RFJModelSwizzledRootModelLock.name = @"RFJModelSwizzledRootModelLock"; 29 | }); 30 | } 31 | 32 | + (void)rfj_initializeModelWithClass:(Class)cls rootModelClass:(Class)rootModelClass 33 | { 34 | [s_RFJModelSwizzledRootModelLock lock]; 35 | { 36 | NSString *className = NSStringFromClass(rootModelClass); 37 | if ([[NSObject rfj_swizzledRootModels] objectForKey:className] == nil) 38 | { 39 | [NSObject rfj_swizzledNSObjectKeyValueMethodWithRootModelClass:rootModelClass]; 40 | [[NSObject rfj_swizzledRootModels] setObject:className forKey:className]; 41 | } 42 | } 43 | [s_RFJModelSwizzledRootModelLock unlock]; 44 | 45 | if (cls != rootModelClass) 46 | { 47 | [NSObject rfj_analyseModelWithClass:cls rootModelClass:rootModelClass]; 48 | } 49 | } 50 | 51 | - (void)rfj_fillWithJsonDict:(NSDictionary *)jsonDict usePropertyKey:(BOOL)bUsePropertyKey 52 | { 53 | NSDictionary *mapPropertyInfos = [self rfj_getPropertyInfos]; 54 | 55 | for (NSString *key in mapPropertyInfos) 56 | { 57 | RFJModelPropertyInfo *info = mapPropertyInfos[key]; 58 | if (info != nil) 59 | { 60 | if (!bUsePropertyKey && !info.isJsonProperty) 61 | continue; 62 | 63 | NSString *jsonKey = bUsePropertyKey ? info.name : info.mapName; 64 | if (IS_EMPTY_STR(jsonKey)) 65 | continue; 66 | id jsonValue = jsonDict[jsonKey]; 67 | if (jsonValue == nil) 68 | continue; 69 | 70 | switch (info.type) 71 | { 72 | case RFJModelPropertyTypeBOOL: 73 | [self setValue:J2NumBool(jsonValue) forKey:info.name]; 74 | break; 75 | case RFJModelPropertyTypeChar: 76 | [self setValue:J2NumChar(jsonValue) forKey:info.name]; 77 | break; 78 | case RFJModelPropertyTypeInt16: 79 | [self setValue:J2NumInt16(jsonValue) forKey:info.name]; 80 | break; 81 | case RFJModelPropertyTypeInt32: 82 | [self setValue:J2NumInt32(jsonValue) forKey:info.name]; 83 | break; 84 | case RFJModelPropertyTypeInt64: 85 | [self setValue:J2NumInt64(jsonValue) forKey:info.name]; 86 | break; 87 | case RFJModelPropertyTypeFloat: 88 | [self setValue:J2NumFloat(jsonValue) forKey:info.name]; 89 | break; 90 | case RFJModelPropertyTypeDouble: 91 | [self setValue:J2NumDouble(jsonValue) forKey:info.name]; 92 | break; 93 | case RFJModelPropertyTypeString: 94 | { 95 | NSString *value = J2Str(jsonValue); 96 | [self setValue:value forKey:info.name]; 97 | } 98 | break; 99 | case RFJModelPropertyTypeMutableString: 100 | { 101 | NSString *value = J2Str(jsonValue); 102 | if (value != nil) 103 | [self setValue:[NSObject rfj_deepMutableCopyWithJson:value] forKey:info.name]; 104 | else 105 | [self setValue:nil forKey:info.name]; 106 | } 107 | break; 108 | case RFJModelPropertyTypeArray: 109 | { 110 | NSArray *value = J2Array(jsonValue); 111 | [self setValue:value forKey:info.name]; 112 | } 113 | break; 114 | case RFJModelPropertyTypeMutableArray: 115 | { 116 | NSArray *value = J2Array(jsonValue); 117 | if (value != nil) 118 | [self setValue:[NSObject rfj_deepMutableCopyWithJson:value] forKey:info.name]; 119 | else 120 | [self setValue:nil forKey:info.name]; 121 | } 122 | break; 123 | case RFJModelPropertyTypeModelArray: 124 | case RFJModelPropertyTypeMutableModelArray: 125 | { 126 | NSArray *array = J2Array(jsonValue); 127 | if (array != nil) 128 | { 129 | NSMutableArray *models = [NSMutableArray array]; 130 | for (NSInteger i = 0; i < array.count; i++) 131 | { 132 | NSDictionary *dict = J2Dict(array[i]); 133 | if (dict != nil) 134 | { 135 | id model = [[info.modelClass alloc] init]; 136 | [model rfj_fillWithJsonDict:dict usePropertyKey:bUsePropertyKey]; 137 | [models addObject:model]; 138 | } 139 | } 140 | 141 | if (info.type == RFJModelPropertyTypeModelArray) 142 | [self setValue:[NSArray arrayWithArray:models] forKey:info.name]; 143 | else 144 | [self setValue:models forKey:info.name]; 145 | } 146 | else 147 | [self setValue:nil forKey:info.name]; 148 | } 149 | break; 150 | case RFJModelPropertyTypeDictionary: 151 | { 152 | NSDictionary *value = J2Dict(jsonValue); 153 | [self setValue:value forKey:info.name]; 154 | } 155 | break; 156 | case RFJModelPropertyTypeMutableDictionary: 157 | { 158 | NSDictionary *value = J2Dict(jsonValue); 159 | if (value != nil) 160 | [self setValue:[NSObject rfj_deepMutableCopyWithJson:value] forKey:info.name]; 161 | else 162 | [self setValue:nil forKey:info.name]; 163 | } 164 | break; 165 | case RFJModelPropertyTypeModel: 166 | { 167 | NSDictionary *dict = J2Dict(jsonValue); 168 | if (dict != nil) 169 | { 170 | id model = [[info.modelClass alloc] init]; 171 | [model rfj_fillWithJsonDict:dict usePropertyKey:bUsePropertyKey]; 172 | [self setValue:model forKey:info.name]; 173 | } 174 | else 175 | [self setValue:nil forKey:info.name]; 176 | } 177 | break; 178 | case RFJModelPropertyTypeObject: 179 | { 180 | // 不安全的 181 | [self setValue:jsonValue forKey:info.name]; 182 | } 183 | break; 184 | default: 185 | break; 186 | } 187 | } 188 | } 189 | } 190 | 191 | + (id)rfj_deepMutableCopyWithJson:(id)json 192 | { 193 | if (json == nil || [json isKindOfClass:[NSNull class]]) 194 | { 195 | return [NSMutableString stringWithFormat:@""]; 196 | } 197 | 198 | if ([json isKindOfClass:[NSString class]]) 199 | { 200 | return [NSMutableString stringWithFormat:@"%@", json]; 201 | } 202 | 203 | if ([json isKindOfClass:[NSNumber class]]) 204 | { 205 | return json; 206 | } 207 | 208 | if ([json isKindOfClass:[NSArray class]]) 209 | { 210 | NSMutableArray *array = [NSMutableArray array]; 211 | for (id value in json) 212 | { 213 | [array addObject:[NSObject rfj_deepMutableCopyWithJson:value]]; 214 | } 215 | return array; 216 | } 217 | 218 | if ([json isKindOfClass:[NSDictionary class]]) 219 | { 220 | NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 221 | for (NSString *key in json) 222 | { 223 | id value = [NSObject rfj_deepMutableCopyWithJson:json[key]]; 224 | [dict setObject:value forKey:key]; 225 | } 226 | return dict; 227 | } 228 | 229 | return json; 230 | } 231 | 232 | - (NSMutableDictionary *)rfj_toMutableDictionaryUsePropertyKey:(BOOL)bUsePropertyKey 233 | { 234 | NSMutableDictionary *container = [NSMutableDictionary dictionary]; 235 | NSDictionary *mapPropertyInfos = [self rfj_getPropertyInfos]; 236 | 237 | for (NSString *key in mapPropertyInfos) 238 | { 239 | RFJModelPropertyInfo *info = mapPropertyInfos[key]; 240 | if (!bUsePropertyKey && !info.isJsonProperty) 241 | continue; 242 | 243 | NSString *jsonKey = bUsePropertyKey ? info.name : info.mapName; 244 | if (IS_EMPTY_STR(jsonKey)) 245 | continue; 246 | 247 | id jsonValue = [self valueForKey:info.name]; 248 | if (jsonValue != nil) 249 | { 250 | switch (info.type) 251 | { 252 | case RFJModelPropertyTypeBOOL: 253 | case RFJModelPropertyTypeChar: 254 | case RFJModelPropertyTypeInt16: 255 | case RFJModelPropertyTypeInt32: 256 | case RFJModelPropertyTypeInt64: 257 | case RFJModelPropertyTypeFloat: 258 | case RFJModelPropertyTypeDouble: 259 | case RFJModelPropertyTypeString: 260 | case RFJModelPropertyTypeMutableString: 261 | case RFJModelPropertyTypeArray: 262 | case RFJModelPropertyTypeMutableArray: 263 | case RFJModelPropertyTypeDictionary: 264 | case RFJModelPropertyTypeMutableDictionary: 265 | { 266 | [container setObject:jsonValue forKey:jsonKey]; 267 | } 268 | break; 269 | case RFJModelPropertyTypeModelArray: 270 | case RFJModelPropertyTypeMutableModelArray: 271 | { 272 | NSMutableArray *newArray = [NSMutableArray array]; 273 | NSArray *array = jsonValue; 274 | for (NSInteger i = 0; i < array.count; i++) 275 | { 276 | id arrayValue = array[i]; 277 | if ([arrayValue rfj_isRFJModel]) 278 | { 279 | NSMutableDictionary *dict = [arrayValue rfj_toMutableDictionaryUsePropertyKey:bUsePropertyKey]; 280 | if (dict != nil) 281 | { 282 | [newArray addObject:dict]; 283 | } 284 | } 285 | } 286 | [container setObject:newArray forKey:jsonKey]; 287 | } 288 | break; 289 | case RFJModelPropertyTypeModel: 290 | { 291 | if ([jsonValue rfj_isRFJModel]) 292 | { 293 | NSMutableDictionary *dict = [jsonValue rfj_toMutableDictionaryUsePropertyKey:bUsePropertyKey]; 294 | if (dict != nil) 295 | { 296 | [container setObject:dict forKey:jsonKey]; 297 | } 298 | } 299 | } 300 | break; 301 | case RFJModelPropertyTypeObject: 302 | { 303 | // 不安全的 304 | [container setObject:jsonValue forKey:jsonKey]; 305 | } 306 | break; 307 | default: 308 | break; 309 | } 310 | } 311 | } 312 | 313 | return container; 314 | } 315 | 316 | - (NSString *)rfj_toJsonStringUsePropertyKey:(BOOL)bUsePropertyKey 317 | { 318 | NSMutableDictionary *dict = [self rfj_toMutableDictionaryUsePropertyKey:bUsePropertyKey]; 319 | NSData *buffer = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:nil]; 320 | return [[NSString alloc] initWithData:buffer encoding:NSUTF8StringEncoding]; 321 | } 322 | 323 | + (NSUInteger)rfj_modelVersion 324 | { 325 | return 2; 326 | } 327 | 328 | + (NSString *)rfj_modelVersionSerializeKey 329 | { 330 | return @"rfj_modelVersionSerializeKey"; 331 | } 332 | 333 | - (void)rfj_decodeCoder:(NSCoder *)coder 334 | { 335 | if ([coder isKindOfClass:[NSKeyedUnarchiver class]]) 336 | { 337 | NSDictionary *mapPropertyInfos = [self rfj_getPropertyInfos]; 338 | for (NSString *key in mapPropertyInfos) 339 | { 340 | RFJModelPropertyInfo *info = mapPropertyInfos[key]; 341 | id value = [coder decodeObjectForKey:info.name]; 342 | if (value != nil) 343 | { 344 | [self setValue:value forKey:info.name]; 345 | } 346 | } 347 | } 348 | } 349 | 350 | - (void)rfj_encodeCoder:(NSCoder *)coder 351 | { 352 | NSDictionary *mapPropertyInfos = [self rfj_getPropertyInfos]; 353 | for (NSString *key in mapPropertyInfos) 354 | { 355 | RFJModelPropertyInfo *info = mapPropertyInfos[key]; 356 | id value = [self valueForKey:info.name]; 357 | if (value != nil && [value conformsToProtocol:@protocol(NSCoding)]) 358 | { 359 | [coder encodeObject:value forKey:info.name]; 360 | } 361 | } 362 | 363 | [coder encodeObject:[NSNumber numberWithUnsignedInteger:[NSObject rfj_modelVersion]] 364 | forKey:[NSObject rfj_modelVersionSerializeKey]]; 365 | } 366 | 367 | + (NSData *)rfj_toDataWithModel:(id)rfjModel 368 | { 369 | if (rfjModel != nil && [rfjModel conformsToProtocol:@protocol(NSCoding)]) 370 | { 371 | @autoreleasepool 372 | { 373 | NSMutableData* saveData = [[NSMutableData alloc] init]; 374 | NSKeyedArchiver* archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:saveData]; 375 | [archiver encodeRootObject:rfjModel]; 376 | [archiver finishEncoding]; 377 | return saveData; 378 | } 379 | } 380 | return nil; 381 | } 382 | 383 | + (id)rfj_toModelWithData:(NSData *)data class:(Class)cls 384 | { 385 | @autoreleasepool 386 | { 387 | if (data != nil && data.length > 0) 388 | { 389 | NSKeyedUnarchiver *unArchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; 390 | id object = [unArchiver decodeObject]; 391 | if (cls == nil) 392 | return object; 393 | 394 | if ([object isKindOfClass:cls]) 395 | return object; 396 | } 397 | return nil; 398 | } 399 | } 400 | 401 | - (void)rfj_descriptionWithBuffer:(NSMutableString *)buffer indent:(NSInteger)indent 402 | { 403 | NSMutableString *indentString = [NSMutableString string]; 404 | for (NSInteger i = 0; i < indent; i++) 405 | { 406 | [indentString appendString:@"\t"]; 407 | } 408 | NSString *replaceString = [NSString stringWithFormat:@"\n%@", indentString]; 409 | 410 | NSDictionary *mapPropertyInfos = [self rfj_getPropertyInfos];; 411 | NSArray *values = [mapPropertyInfos allValues]; 412 | values = [values sortedArrayUsingComparator:^(RFJModelPropertyInfo *info1, RFJModelPropertyInfo *info2){ 413 | if (info1.propertyIdx < info2.propertyIdx) 414 | { 415 | return NSOrderedAscending; 416 | } 417 | else if (info1.propertyIdx == info2.propertyIdx) 418 | { 419 | return NSOrderedSame; 420 | } 421 | else 422 | { 423 | return NSOrderedDescending; 424 | } 425 | }]; 426 | 427 | for (RFJModelPropertyInfo *info in values) 428 | { 429 | if (info.isJsonProperty) 430 | { 431 | // JProperty 432 | id value = [self valueForKey:info.name]; 433 | switch (info.type) 434 | { 435 | case RFJModelPropertyTypeModel: 436 | { 437 | [buffer appendFormat:@"\n%@JP name:%@ type:%s map:%@ value:", indentString, info.name, s_RFJModelPropertyTypeName[info.type], info.mapName]; 438 | if ([value rfj_isRFJModel]) 439 | { 440 | [value rfj_descriptionWithBuffer:buffer indent:indent+1]; 441 | } 442 | } 443 | break; 444 | case RFJModelPropertyTypeModelArray: 445 | case RFJModelPropertyTypeMutableModelArray: 446 | { 447 | [buffer appendFormat:@"\n%@JP name:%@ type:%s map:%@ value:", indentString, info.name, s_RFJModelPropertyTypeName[info.type], info.mapName]; 448 | NSArray *models = value; 449 | for (NSInteger i = 0; i < models.count; i++) 450 | { 451 | id model = models[i]; 452 | [buffer appendFormat:@"\n\t%@-", indentString]; 453 | if ([model rfj_isRFJModel]) 454 | { 455 | [model rfj_descriptionWithBuffer:buffer indent:indent+1]; 456 | } 457 | } 458 | } 459 | break; 460 | default: 461 | { 462 | NSString *valueString = [value description]; 463 | valueString = [valueString stringByReplacingOccurrencesOfString:@"\n" withString:replaceString]; 464 | [buffer appendFormat:@"\n%@JP name:%@ type:%s map:%@ value:%@", indentString, info.name, s_RFJModelPropertyTypeName[info.type], info.mapName, valueString]; 465 | } 466 | break; 467 | } 468 | } 469 | else 470 | { 471 | // no JProperty 472 | id value = [self valueForKey:info.name]; 473 | NSString *valueString = [value description]; 474 | valueString = [valueString stringByReplacingOccurrencesOfString:@"\n" withString:replaceString]; 475 | [buffer appendFormat:@"\n%@ P name:%@ value:%@", indentString, info.name, valueString]; 476 | } 477 | } 478 | } 479 | 480 | #pragma mark - 自定义存储区 481 | 482 | + (NSMutableDictionary *)rfj_swizzledRootModels 483 | { 484 | static NSMutableDictionary *s_instance = nil; 485 | 486 | static dispatch_once_t onceToken; 487 | dispatch_once(&onceToken, ^{ 488 | s_instance = [[NSMutableDictionary alloc] init]; 489 | }); 490 | 491 | return s_instance; 492 | } 493 | 494 | + (void)rfj_swizzledNSObjectKeyValueMethodWithRootModelClass:(Class)rootModelClass 495 | { 496 | Class class = rootModelClass; 497 | { 498 | SEL originalSelector = @selector(valueForKey:); 499 | SEL swizzledSelector = @selector(rfj_valueForKey:); 500 | 501 | Method originalMethod = class_getInstanceMethod(class, originalSelector); 502 | Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector); 503 | 504 | BOOL success = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)); 505 | if (success) 506 | { 507 | class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)); 508 | } 509 | else 510 | { 511 | method_exchangeImplementations(originalMethod, swizzledMethod); 512 | } 513 | } 514 | { 515 | SEL originalSelector = @selector(setValue:forKey:); 516 | SEL swizzledSelector = @selector(rfj_setValue:forKey:); 517 | 518 | Method originalMethod = class_getInstanceMethod(class, originalSelector); 519 | Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector); 520 | 521 | BOOL success = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)); 522 | if (success) 523 | { 524 | class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)); 525 | } 526 | else 527 | { 528 | method_exchangeImplementations(originalMethod, swizzledMethod); 529 | } 530 | } 531 | } 532 | 533 | static void *kRFJModelStorageDelegate = "kRFJModelStorageDelegate"; 534 | 535 | - (void)setRfj_storageDelegate:(id)delegate 536 | { 537 | [self rfj_setAssociatedValue:delegate forKey:kRFJModelStorageDelegate access:RFModelPropertyAccessTypeWeak atomic:NO]; 538 | } 539 | 540 | - (id)rfj_storageDelegate 541 | { 542 | return [self rfj_getAssociatedValueOfKey:kRFJModelStorageDelegate]; 543 | } 544 | 545 | - (NSString *)_rfj_transformKey:(NSString *)key 546 | { 547 | NSMutableDictionary *dict = [self rfj_cachedTransformKeys]; 548 | NSString *newKey = dict[key]; 549 | if (IS_EMPTY_STR(newKey)) 550 | { 551 | if (self.rfj_storageDelegate != nil 552 | && [self.rfj_storageDelegate respondsToSelector:@selector(rfj_transformKey:)]) 553 | newKey = [self.rfj_storageDelegate rfj_transformKey:key]; 554 | else 555 | newKey = key; 556 | [s_RFJModelTransformKeyLock lock]; 557 | { 558 | dict[key] = newKey; 559 | } 560 | [s_RFJModelTransformKeyLock unlock]; 561 | } 562 | return newKey; 563 | } 564 | 565 | - (NSMutableDictionary *)rfj_cachedTransformKeys 566 | { 567 | static NSMutableDictionary *s_allDict = nil; 568 | NSMutableDictionary *dict = nil; 569 | 570 | [s_RFJModelTransformKeyLock lock]; 571 | { 572 | if (s_allDict == nil) { 573 | s_allDict = [[NSMutableDictionary alloc] init]; 574 | } 575 | dict = s_allDict[[self rfj_getClassName]]; 576 | if (dict == nil) { 577 | dict = [[NSMutableDictionary alloc] init]; 578 | s_allDict[[self rfj_getClassName]] = dict; 579 | } 580 | } 581 | [s_RFJModelTransformKeyLock unlock]; 582 | 583 | return dict; 584 | } 585 | 586 | - (nullable id)rfj_valueForKey:(NSString *)key 587 | { 588 | NSDictionary *mapPropertyInfos = [self rfj_getPropertyInfos]; 589 | 590 | // 动态属性存取 591 | RFJModelPropertyInfo *info = mapPropertyInfos[key]; 592 | if (info != nil && info.isDynamic) { 593 | // 优先自定义存取 594 | if (self.rfj_storageDelegate != nil) { 595 | return [self.rfj_storageDelegate rfj_objectForKey:[self _rfj_transformKey:key] ofModel:self]; 596 | } 597 | // 关联对象存取 598 | return [self rfj_getAssociatedValueOfKey:info.chName]; 599 | } 600 | 601 | // 静态属性存取 602 | return [self rfj_valueForKey:key]; 603 | } 604 | 605 | - (void)rfj_setValue:(nullable id)value forKey:(NSString *)key 606 | { 607 | NSDictionary *mapPropertyInfos = [self rfj_getPropertyInfos]; 608 | 609 | // 动态属性存取 610 | RFJModelPropertyInfo *info = mapPropertyInfos[key]; 611 | if (info != nil && info.isDynamic) { 612 | // 优先自定义存取 613 | if (self.rfj_storageDelegate != nil) { 614 | [self.rfj_storageDelegate rfj_setObject:value forKey:[self _rfj_transformKey:key] ofModel:self]; 615 | return; 616 | } 617 | // 关联对象存取 618 | [self willChangeValueForKey:key]; 619 | [self rfj_setAssociatedValue:value forKey:info.chName access:info.accessType atomic:!info.isNonatomic]; 620 | [self didChangeValueForKey:key]; 621 | return; 622 | } 623 | 624 | // 静态属性存取 625 | [self rfj_setValue:value forKey:key]; 626 | } 627 | 628 | 629 | @end 630 | -------------------------------------------------------------------------------- /RFJModel/RFJModel.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 3910A6B71F56A37B002E12F6 /* ExampleUD.m in Sources */ = {isa = PBXBuildFile; fileRef = 3910A6B61F56A37B002E12F6 /* ExampleUD.m */; }; 11 | 397C841B1F0B6202009982F8 /* result_Type.txt in Resources */ = {isa = PBXBuildFile; fileRef = 397C841A1F0B6202009982F8 /* result_Type.txt */; }; 12 | 397C841D1F0B620E009982F8 /* result_Json.txt in Resources */ = {isa = PBXBuildFile; fileRef = 397C841C1F0B620E009982F8 /* result_Json.txt */; }; 13 | 397C841F1F0B6227009982F8 /* result_Inherit.txt in Resources */ = {isa = PBXBuildFile; fileRef = 397C841E1F0B6227009982F8 /* result_Inherit.txt */; }; 14 | 397C84211F0B624B009982F8 /* result_CustomStorage.txt in Resources */ = {isa = PBXBuildFile; fileRef = 397C84201F0B624B009982F8 /* result_CustomStorage.txt */; }; 15 | 397C84271F0B67F8009982F8 /* NSObject+RFSafeTransform.m in Sources */ = {isa = PBXBuildFile; fileRef = 397C84261F0B67F8009982F8 /* NSObject+RFSafeTransform.m */; }; 16 | 397C842A1F0B6AA2009982F8 /* NSString+RFSafeTransform.m in Sources */ = {isa = PBXBuildFile; fileRef = 397C84291F0B6AA2009982F8 /* NSString+RFSafeTransform.m */; }; 17 | 397C842D1F0B6C11009982F8 /* NSObject+RFAssociatedValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 397C842C1F0B6C11009982F8 /* NSObject+RFAssociatedValue.m */; }; 18 | 397C84361F0B75CC009982F8 /* NSObject+RFJModelProperty.m in Sources */ = {isa = PBXBuildFile; fileRef = 397C84351F0B75CC009982F8 /* NSObject+RFJModelProperty.m */; }; 19 | 397D9AC41F0B9D1D0028E26E /* RFJModelProperty.m in Sources */ = {isa = PBXBuildFile; fileRef = 397D9AC31F0B9D1D0028E26E /* RFJModelProperty.m */; }; 20 | 397D9AC71F0BABE80028E26E /* NSObject+RFJModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 397D9AC61F0BABE80028E26E /* NSObject+RFJModel.m */; }; 21 | 3992C1F01F04D4D900433314 /* ExampleCustomStorageModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 3992C1EF1F04D4D900433314 /* ExampleCustomStorageModel.m */; }; 22 | 3992C1F21F04DA4900433314 /* ExampleCustomStorageModelJson.txt in Resources */ = {isa = PBXBuildFile; fileRef = 3992C1F11F04DA4900433314 /* ExampleCustomStorageModelJson.txt */; }; 23 | 39FFB9AF1F0F6646005B2783 /* RFJUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = 39FFB9AE1F0F6646005B2783 /* RFJUserDefaults.m */; }; 24 | 78DA97531A53951B006B0597 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 78DA97521A53951B006B0597 /* main.m */; }; 25 | 78DA97561A53951B006B0597 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 78DA97551A53951B006B0597 /* AppDelegate.m */; }; 26 | 78DA97591A53951B006B0597 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 78DA97581A53951B006B0597 /* ViewController.m */; }; 27 | 78DA975C1A53951B006B0597 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 78DA975A1A53951B006B0597 /* Main.storyboard */; }; 28 | 78DA975E1A53951B006B0597 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 78DA975D1A53951B006B0597 /* Images.xcassets */; }; 29 | 78DA97611A53951B006B0597 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 78DA975F1A53951B006B0597 /* LaunchScreen.xib */; }; 30 | 78DA976D1A53951B006B0597 /* RFJModelTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 78DA976C1A53951B006B0597 /* RFJModelTests.m */; }; 31 | 78DA977E1A539581006B0597 /* ExampleJson.txt in Resources */ = {isa = PBXBuildFile; fileRef = 78DA97771A539581006B0597 /* ExampleJson.txt */; }; 32 | 78DA977F1A539581006B0597 /* ExampleModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 78DA97791A539581006B0597 /* ExampleModel.m */; }; 33 | 78DA97801A539581006B0597 /* ExampleType.txt in Resources */ = {isa = PBXBuildFile; fileRef = 78DA977A1A539581006B0597 /* ExampleType.txt */; }; 34 | 78DA97811A539581006B0597 /* RFJModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 78DA977D1A539581006B0597 /* RFJModel.m */; }; 35 | /* End PBXBuildFile section */ 36 | 37 | /* Begin PBXContainerItemProxy section */ 38 | 78DA97671A53951B006B0597 /* PBXContainerItemProxy */ = { 39 | isa = PBXContainerItemProxy; 40 | containerPortal = 78DA97451A53951B006B0597 /* Project object */; 41 | proxyType = 1; 42 | remoteGlobalIDString = 78DA974C1A53951B006B0597; 43 | remoteInfo = RFJModel; 44 | }; 45 | /* End PBXContainerItemProxy section */ 46 | 47 | /* Begin PBXFileReference section */ 48 | 3910A6B51F56A37B002E12F6 /* ExampleUD.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExampleUD.h; sourceTree = ""; }; 49 | 3910A6B61F56A37B002E12F6 /* ExampleUD.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExampleUD.m; sourceTree = ""; }; 50 | 397C841A1F0B6202009982F8 /* result_Type.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = result_Type.txt; sourceTree = ""; }; 51 | 397C841C1F0B620E009982F8 /* result_Json.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = result_Json.txt; sourceTree = ""; }; 52 | 397C841E1F0B6227009982F8 /* result_Inherit.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = result_Inherit.txt; sourceTree = ""; }; 53 | 397C84201F0B624B009982F8 /* result_CustomStorage.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = result_CustomStorage.txt; sourceTree = ""; }; 54 | 397C84251F0B67F8009982F8 /* NSObject+RFSafeTransform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "NSObject+RFSafeTransform.h"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 55 | 397C84261F0B67F8009982F8 /* NSObject+RFSafeTransform.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = "NSObject+RFSafeTransform.m"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 56 | 397C84281F0B6AA2009982F8 /* NSString+RFSafeTransform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+RFSafeTransform.h"; sourceTree = ""; }; 57 | 397C84291F0B6AA2009982F8 /* NSString+RFSafeTransform.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+RFSafeTransform.m"; sourceTree = ""; }; 58 | 397C842B1F0B6C11009982F8 /* NSObject+RFAssociatedValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "NSObject+RFAssociatedValue.h"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 59 | 397C842C1F0B6C11009982F8 /* NSObject+RFAssociatedValue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = "NSObject+RFAssociatedValue.m"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 60 | 397C84341F0B75CC009982F8 /* NSObject+RFJModelProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "NSObject+RFJModelProperty.h"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 61 | 397C84351F0B75CC009982F8 /* NSObject+RFJModelProperty.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = "NSObject+RFJModelProperty.m"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 62 | 397D9AC21F0B9D1D0028E26E /* RFJModelProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RFJModelProperty.h; sourceTree = ""; }; 63 | 397D9AC31F0B9D1D0028E26E /* RFJModelProperty.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RFJModelProperty.m; sourceTree = ""; }; 64 | 397D9AC51F0BABE80028E26E /* NSObject+RFJModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+RFJModel.h"; sourceTree = ""; }; 65 | 397D9AC61F0BABE80028E26E /* NSObject+RFJModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+RFJModel.m"; sourceTree = ""; }; 66 | 3992C1EE1F04D4D900433314 /* ExampleCustomStorageModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExampleCustomStorageModel.h; sourceTree = ""; }; 67 | 3992C1EF1F04D4D900433314 /* ExampleCustomStorageModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExampleCustomStorageModel.m; sourceTree = ""; }; 68 | 3992C1F11F04DA4900433314 /* ExampleCustomStorageModelJson.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ExampleCustomStorageModelJson.txt; sourceTree = ""; }; 69 | 39FFB9AD1F0F6646005B2783 /* RFJUserDefaults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RFJUserDefaults.h; sourceTree = ""; }; 70 | 39FFB9AE1F0F6646005B2783 /* RFJUserDefaults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RFJUserDefaults.m; sourceTree = ""; }; 71 | 78DA974D1A53951B006B0597 /* RFJModel.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RFJModel.app; sourceTree = BUILT_PRODUCTS_DIR; }; 72 | 78DA97511A53951B006B0597 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 73 | 78DA97521A53951B006B0597 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 74 | 78DA97541A53951B006B0597 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 75 | 78DA97551A53951B006B0597 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 76 | 78DA97571A53951B006B0597 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 77 | 78DA97581A53951B006B0597 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 78 | 78DA975B1A53951B006B0597 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 79 | 78DA975D1A53951B006B0597 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 80 | 78DA97601A53951B006B0597 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 81 | 78DA97661A53951B006B0597 /* RFJModelTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RFJModelTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 82 | 78DA976B1A53951B006B0597 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 83 | 78DA976C1A53951B006B0597 /* RFJModelTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RFJModelTests.m; sourceTree = ""; }; 84 | 78DA97771A539581006B0597 /* ExampleJson.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ExampleJson.txt; sourceTree = ""; }; 85 | 78DA97781A539581006B0597 /* ExampleModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExampleModel.h; sourceTree = ""; }; 86 | 78DA97791A539581006B0597 /* ExampleModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExampleModel.m; sourceTree = ""; }; 87 | 78DA977A1A539581006B0597 /* ExampleType.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ExampleType.txt; sourceTree = ""; }; 88 | 78DA977C1A539581006B0597 /* RFJModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RFJModel.h; sourceTree = ""; }; 89 | 78DA977D1A539581006B0597 /* RFJModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = RFJModel.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 90 | 78DC80241A58DCB100D2019F /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; 91 | 78DC80261A590C5400D2019F /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = ""; }; 92 | /* End PBXFileReference section */ 93 | 94 | /* Begin PBXFrameworksBuildPhase section */ 95 | 78DA974A1A53951B006B0597 /* Frameworks */ = { 96 | isa = PBXFrameworksBuildPhase; 97 | buildActionMask = 2147483647; 98 | files = ( 99 | ); 100 | runOnlyForDeploymentPostprocessing = 0; 101 | }; 102 | 78DA97631A53951B006B0597 /* Frameworks */ = { 103 | isa = PBXFrameworksBuildPhase; 104 | buildActionMask = 2147483647; 105 | files = ( 106 | ); 107 | runOnlyForDeploymentPostprocessing = 0; 108 | }; 109 | /* End PBXFrameworksBuildPhase section */ 110 | 111 | /* Begin PBXGroup section */ 112 | 78DA97441A53951B006B0597 = { 113 | isa = PBXGroup; 114 | children = ( 115 | 78DC80261A590C5400D2019F /* LICENSE */, 116 | 78DC80241A58DCB100D2019F /* README.md */, 117 | 78DA974F1A53951B006B0597 /* RFJModel */, 118 | 78DA97691A53951B006B0597 /* RFJModelTests */, 119 | 78DA974E1A53951B006B0597 /* Products */, 120 | ); 121 | sourceTree = ""; 122 | }; 123 | 78DA974E1A53951B006B0597 /* Products */ = { 124 | isa = PBXGroup; 125 | children = ( 126 | 78DA974D1A53951B006B0597 /* RFJModel.app */, 127 | 78DA97661A53951B006B0597 /* RFJModelTests.xctest */, 128 | ); 129 | name = Products; 130 | sourceTree = ""; 131 | }; 132 | 78DA974F1A53951B006B0597 /* RFJModel */ = { 133 | isa = PBXGroup; 134 | children = ( 135 | 78DA97761A539581006B0597 /* Example */, 136 | 78DA977B1A539581006B0597 /* RFJModel */, 137 | 78DA97541A53951B006B0597 /* AppDelegate.h */, 138 | 78DA97551A53951B006B0597 /* AppDelegate.m */, 139 | 78DA97571A53951B006B0597 /* ViewController.h */, 140 | 78DA97581A53951B006B0597 /* ViewController.m */, 141 | 78DA975A1A53951B006B0597 /* Main.storyboard */, 142 | 78DA975D1A53951B006B0597 /* Images.xcassets */, 143 | 78DA975F1A53951B006B0597 /* LaunchScreen.xib */, 144 | 78DA97501A53951B006B0597 /* Supporting Files */, 145 | ); 146 | path = RFJModel; 147 | sourceTree = ""; 148 | }; 149 | 78DA97501A53951B006B0597 /* Supporting Files */ = { 150 | isa = PBXGroup; 151 | children = ( 152 | 78DA97511A53951B006B0597 /* Info.plist */, 153 | 78DA97521A53951B006B0597 /* main.m */, 154 | ); 155 | name = "Supporting Files"; 156 | sourceTree = ""; 157 | }; 158 | 78DA97691A53951B006B0597 /* RFJModelTests */ = { 159 | isa = PBXGroup; 160 | children = ( 161 | 78DA976C1A53951B006B0597 /* RFJModelTests.m */, 162 | 78DA976A1A53951B006B0597 /* Supporting Files */, 163 | ); 164 | path = RFJModelTests; 165 | sourceTree = ""; 166 | }; 167 | 78DA976A1A53951B006B0597 /* Supporting Files */ = { 168 | isa = PBXGroup; 169 | children = ( 170 | 78DA976B1A53951B006B0597 /* Info.plist */, 171 | ); 172 | name = "Supporting Files"; 173 | sourceTree = ""; 174 | }; 175 | 78DA97761A539581006B0597 /* Example */ = { 176 | isa = PBXGroup; 177 | children = ( 178 | 78DA97771A539581006B0597 /* ExampleJson.txt */, 179 | 78DA97781A539581006B0597 /* ExampleModel.h */, 180 | 78DA97791A539581006B0597 /* ExampleModel.m */, 181 | 78DA977A1A539581006B0597 /* ExampleType.txt */, 182 | 3992C1EE1F04D4D900433314 /* ExampleCustomStorageModel.h */, 183 | 3992C1EF1F04D4D900433314 /* ExampleCustomStorageModel.m */, 184 | 3992C1F11F04DA4900433314 /* ExampleCustomStorageModelJson.txt */, 185 | 397C841A1F0B6202009982F8 /* result_Type.txt */, 186 | 397C841C1F0B620E009982F8 /* result_Json.txt */, 187 | 397C841E1F0B6227009982F8 /* result_Inherit.txt */, 188 | 397C84201F0B624B009982F8 /* result_CustomStorage.txt */, 189 | 3910A6B51F56A37B002E12F6 /* ExampleUD.h */, 190 | 3910A6B61F56A37B002E12F6 /* ExampleUD.m */, 191 | ); 192 | path = Example; 193 | sourceTree = ""; 194 | }; 195 | 78DA977B1A539581006B0597 /* RFJModel */ = { 196 | isa = PBXGroup; 197 | children = ( 198 | 39FFB9AD1F0F6646005B2783 /* RFJUserDefaults.h */, 199 | 39FFB9AE1F0F6646005B2783 /* RFJUserDefaults.m */, 200 | 78DA977C1A539581006B0597 /* RFJModel.h */, 201 | 78DA977D1A539581006B0597 /* RFJModel.m */, 202 | 397D9AC51F0BABE80028E26E /* NSObject+RFJModel.h */, 203 | 397D9AC61F0BABE80028E26E /* NSObject+RFJModel.m */, 204 | 397C84251F0B67F8009982F8 /* NSObject+RFSafeTransform.h */, 205 | 397C84261F0B67F8009982F8 /* NSObject+RFSafeTransform.m */, 206 | 397C84281F0B6AA2009982F8 /* NSString+RFSafeTransform.h */, 207 | 397C84291F0B6AA2009982F8 /* NSString+RFSafeTransform.m */, 208 | 397C842B1F0B6C11009982F8 /* NSObject+RFAssociatedValue.h */, 209 | 397C842C1F0B6C11009982F8 /* NSObject+RFAssociatedValue.m */, 210 | 397C84341F0B75CC009982F8 /* NSObject+RFJModelProperty.h */, 211 | 397C84351F0B75CC009982F8 /* NSObject+RFJModelProperty.m */, 212 | 397D9AC21F0B9D1D0028E26E /* RFJModelProperty.h */, 213 | 397D9AC31F0B9D1D0028E26E /* RFJModelProperty.m */, 214 | ); 215 | path = RFJModel; 216 | sourceTree = ""; 217 | }; 218 | /* End PBXGroup section */ 219 | 220 | /* Begin PBXNativeTarget section */ 221 | 78DA974C1A53951B006B0597 /* RFJModel */ = { 222 | isa = PBXNativeTarget; 223 | buildConfigurationList = 78DA97701A53951B006B0597 /* Build configuration list for PBXNativeTarget "RFJModel" */; 224 | buildPhases = ( 225 | 78DA97491A53951B006B0597 /* Sources */, 226 | 78DA974A1A53951B006B0597 /* Frameworks */, 227 | 78DA974B1A53951B006B0597 /* Resources */, 228 | ); 229 | buildRules = ( 230 | ); 231 | dependencies = ( 232 | ); 233 | name = RFJModel; 234 | productName = RFJModel; 235 | productReference = 78DA974D1A53951B006B0597 /* RFJModel.app */; 236 | productType = "com.apple.product-type.application"; 237 | }; 238 | 78DA97651A53951B006B0597 /* RFJModelTests */ = { 239 | isa = PBXNativeTarget; 240 | buildConfigurationList = 78DA97731A53951B006B0597 /* Build configuration list for PBXNativeTarget "RFJModelTests" */; 241 | buildPhases = ( 242 | 78DA97621A53951B006B0597 /* Sources */, 243 | 78DA97631A53951B006B0597 /* Frameworks */, 244 | 78DA97641A53951B006B0597 /* Resources */, 245 | ); 246 | buildRules = ( 247 | ); 248 | dependencies = ( 249 | 78DA97681A53951B006B0597 /* PBXTargetDependency */, 250 | ); 251 | name = RFJModelTests; 252 | productName = RFJModelTests; 253 | productReference = 78DA97661A53951B006B0597 /* RFJModelTests.xctest */; 254 | productType = "com.apple.product-type.bundle.unit-test"; 255 | }; 256 | /* End PBXNativeTarget section */ 257 | 258 | /* Begin PBXProject section */ 259 | 78DA97451A53951B006B0597 /* Project object */ = { 260 | isa = PBXProject; 261 | attributes = { 262 | LastUpgradeCheck = 0830; 263 | ORGANIZATIONNAME = TechAtk; 264 | TargetAttributes = { 265 | 78DA974C1A53951B006B0597 = { 266 | CreatedOnToolsVersion = 6.1; 267 | ProvisioningStyle = Manual; 268 | }; 269 | 78DA97651A53951B006B0597 = { 270 | CreatedOnToolsVersion = 6.1; 271 | TestTargetID = 78DA974C1A53951B006B0597; 272 | }; 273 | }; 274 | }; 275 | buildConfigurationList = 78DA97481A53951B006B0597 /* Build configuration list for PBXProject "RFJModel" */; 276 | compatibilityVersion = "Xcode 3.2"; 277 | developmentRegion = English; 278 | hasScannedForEncodings = 0; 279 | knownRegions = ( 280 | en, 281 | Base, 282 | ); 283 | mainGroup = 78DA97441A53951B006B0597; 284 | productRefGroup = 78DA974E1A53951B006B0597 /* Products */; 285 | projectDirPath = ""; 286 | projectRoot = ""; 287 | targets = ( 288 | 78DA974C1A53951B006B0597 /* RFJModel */, 289 | 78DA97651A53951B006B0597 /* RFJModelTests */, 290 | ); 291 | }; 292 | /* End PBXProject section */ 293 | 294 | /* Begin PBXResourcesBuildPhase section */ 295 | 78DA974B1A53951B006B0597 /* Resources */ = { 296 | isa = PBXResourcesBuildPhase; 297 | buildActionMask = 2147483647; 298 | files = ( 299 | 397C84211F0B624B009982F8 /* result_CustomStorage.txt in Resources */, 300 | 397C841F1F0B6227009982F8 /* result_Inherit.txt in Resources */, 301 | 397C841B1F0B6202009982F8 /* result_Type.txt in Resources */, 302 | 78DA97801A539581006B0597 /* ExampleType.txt in Resources */, 303 | 78DA975C1A53951B006B0597 /* Main.storyboard in Resources */, 304 | 78DA97611A53951B006B0597 /* LaunchScreen.xib in Resources */, 305 | 78DA975E1A53951B006B0597 /* Images.xcassets in Resources */, 306 | 397C841D1F0B620E009982F8 /* result_Json.txt in Resources */, 307 | 3992C1F21F04DA4900433314 /* ExampleCustomStorageModelJson.txt in Resources */, 308 | 78DA977E1A539581006B0597 /* ExampleJson.txt in Resources */, 309 | ); 310 | runOnlyForDeploymentPostprocessing = 0; 311 | }; 312 | 78DA97641A53951B006B0597 /* Resources */ = { 313 | isa = PBXResourcesBuildPhase; 314 | buildActionMask = 2147483647; 315 | files = ( 316 | ); 317 | runOnlyForDeploymentPostprocessing = 0; 318 | }; 319 | /* End PBXResourcesBuildPhase section */ 320 | 321 | /* Begin PBXSourcesBuildPhase section */ 322 | 78DA97491A53951B006B0597 /* Sources */ = { 323 | isa = PBXSourcesBuildPhase; 324 | buildActionMask = 2147483647; 325 | files = ( 326 | 397C842D1F0B6C11009982F8 /* NSObject+RFAssociatedValue.m in Sources */, 327 | 397D9AC41F0B9D1D0028E26E /* RFJModelProperty.m in Sources */, 328 | 78DA97591A53951B006B0597 /* ViewController.m in Sources */, 329 | 78DA97561A53951B006B0597 /* AppDelegate.m in Sources */, 330 | 397C84271F0B67F8009982F8 /* NSObject+RFSafeTransform.m in Sources */, 331 | 3910A6B71F56A37B002E12F6 /* ExampleUD.m in Sources */, 332 | 397C842A1F0B6AA2009982F8 /* NSString+RFSafeTransform.m in Sources */, 333 | 39FFB9AF1F0F6646005B2783 /* RFJUserDefaults.m in Sources */, 334 | 78DA97811A539581006B0597 /* RFJModel.m in Sources */, 335 | 3992C1F01F04D4D900433314 /* ExampleCustomStorageModel.m in Sources */, 336 | 397C84361F0B75CC009982F8 /* NSObject+RFJModelProperty.m in Sources */, 337 | 78DA977F1A539581006B0597 /* ExampleModel.m in Sources */, 338 | 397D9AC71F0BABE80028E26E /* NSObject+RFJModel.m in Sources */, 339 | 78DA97531A53951B006B0597 /* main.m in Sources */, 340 | ); 341 | runOnlyForDeploymentPostprocessing = 0; 342 | }; 343 | 78DA97621A53951B006B0597 /* Sources */ = { 344 | isa = PBXSourcesBuildPhase; 345 | buildActionMask = 2147483647; 346 | files = ( 347 | 78DA976D1A53951B006B0597 /* RFJModelTests.m in Sources */, 348 | ); 349 | runOnlyForDeploymentPostprocessing = 0; 350 | }; 351 | /* End PBXSourcesBuildPhase section */ 352 | 353 | /* Begin PBXTargetDependency section */ 354 | 78DA97681A53951B006B0597 /* PBXTargetDependency */ = { 355 | isa = PBXTargetDependency; 356 | target = 78DA974C1A53951B006B0597 /* RFJModel */; 357 | targetProxy = 78DA97671A53951B006B0597 /* PBXContainerItemProxy */; 358 | }; 359 | /* End PBXTargetDependency section */ 360 | 361 | /* Begin PBXVariantGroup section */ 362 | 78DA975A1A53951B006B0597 /* Main.storyboard */ = { 363 | isa = PBXVariantGroup; 364 | children = ( 365 | 78DA975B1A53951B006B0597 /* Base */, 366 | ); 367 | name = Main.storyboard; 368 | sourceTree = ""; 369 | }; 370 | 78DA975F1A53951B006B0597 /* LaunchScreen.xib */ = { 371 | isa = PBXVariantGroup; 372 | children = ( 373 | 78DA97601A53951B006B0597 /* Base */, 374 | ); 375 | name = LaunchScreen.xib; 376 | sourceTree = ""; 377 | }; 378 | /* End PBXVariantGroup section */ 379 | 380 | /* Begin XCBuildConfiguration section */ 381 | 78DA976E1A53951B006B0597 /* Debug */ = { 382 | isa = XCBuildConfiguration; 383 | buildSettings = { 384 | ALWAYS_SEARCH_USER_PATHS = NO; 385 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 386 | CLANG_CXX_LIBRARY = "libc++"; 387 | CLANG_ENABLE_MODULES = YES; 388 | CLANG_ENABLE_OBJC_ARC = YES; 389 | CLANG_WARN_BOOL_CONVERSION = YES; 390 | CLANG_WARN_CONSTANT_CONVERSION = YES; 391 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 392 | CLANG_WARN_EMPTY_BODY = YES; 393 | CLANG_WARN_ENUM_CONVERSION = YES; 394 | CLANG_WARN_INFINITE_RECURSION = YES; 395 | CLANG_WARN_INT_CONVERSION = YES; 396 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 397 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 398 | CLANG_WARN_UNREACHABLE_CODE = YES; 399 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 400 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 401 | COPY_PHASE_STRIP = NO; 402 | ENABLE_STRICT_OBJC_MSGSEND = YES; 403 | ENABLE_TESTABILITY = YES; 404 | GCC_C_LANGUAGE_STANDARD = gnu99; 405 | GCC_DYNAMIC_NO_PIC = NO; 406 | GCC_NO_COMMON_BLOCKS = YES; 407 | GCC_OPTIMIZATION_LEVEL = 0; 408 | GCC_PREPROCESSOR_DEFINITIONS = ( 409 | "DEBUG=1", 410 | "$(inherited)", 411 | ); 412 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 413 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 414 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 415 | GCC_WARN_UNDECLARED_SELECTOR = YES; 416 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 417 | GCC_WARN_UNUSED_FUNCTION = YES; 418 | GCC_WARN_UNUSED_VARIABLE = YES; 419 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 420 | MTL_ENABLE_DEBUG_INFO = YES; 421 | ONLY_ACTIVE_ARCH = YES; 422 | SDKROOT = iphoneos; 423 | TARGETED_DEVICE_FAMILY = "1,2"; 424 | }; 425 | name = Debug; 426 | }; 427 | 78DA976F1A53951B006B0597 /* Release */ = { 428 | isa = XCBuildConfiguration; 429 | buildSettings = { 430 | ALWAYS_SEARCH_USER_PATHS = NO; 431 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 432 | CLANG_CXX_LIBRARY = "libc++"; 433 | CLANG_ENABLE_MODULES = YES; 434 | CLANG_ENABLE_OBJC_ARC = YES; 435 | CLANG_WARN_BOOL_CONVERSION = YES; 436 | CLANG_WARN_CONSTANT_CONVERSION = YES; 437 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 438 | CLANG_WARN_EMPTY_BODY = YES; 439 | CLANG_WARN_ENUM_CONVERSION = YES; 440 | CLANG_WARN_INFINITE_RECURSION = YES; 441 | CLANG_WARN_INT_CONVERSION = YES; 442 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 443 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 444 | CLANG_WARN_UNREACHABLE_CODE = YES; 445 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 446 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 447 | COPY_PHASE_STRIP = YES; 448 | ENABLE_NS_ASSERTIONS = NO; 449 | ENABLE_STRICT_OBJC_MSGSEND = YES; 450 | GCC_C_LANGUAGE_STANDARD = gnu99; 451 | GCC_NO_COMMON_BLOCKS = YES; 452 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 453 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 454 | GCC_WARN_UNDECLARED_SELECTOR = YES; 455 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 456 | GCC_WARN_UNUSED_FUNCTION = YES; 457 | GCC_WARN_UNUSED_VARIABLE = YES; 458 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 459 | MTL_ENABLE_DEBUG_INFO = NO; 460 | SDKROOT = iphoneos; 461 | TARGETED_DEVICE_FAMILY = "1,2"; 462 | VALIDATE_PRODUCT = YES; 463 | }; 464 | name = Release; 465 | }; 466 | 78DA97711A53951B006B0597 /* Debug */ = { 467 | isa = XCBuildConfiguration; 468 | buildSettings = { 469 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 470 | DEVELOPMENT_TEAM = ""; 471 | INFOPLIST_FILE = RFJModel/Info.plist; 472 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 473 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 474 | PRODUCT_BUNDLE_IDENTIFIER = "TechAtk.$(PRODUCT_NAME:rfc1034identifier)"; 475 | PRODUCT_NAME = "$(TARGET_NAME)"; 476 | PROVISIONING_PROFILE_SPECIFIER = ""; 477 | }; 478 | name = Debug; 479 | }; 480 | 78DA97721A53951B006B0597 /* Release */ = { 481 | isa = XCBuildConfiguration; 482 | buildSettings = { 483 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 484 | DEVELOPMENT_TEAM = ""; 485 | INFOPLIST_FILE = RFJModel/Info.plist; 486 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 487 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 488 | PRODUCT_BUNDLE_IDENTIFIER = "TechAtk.$(PRODUCT_NAME:rfc1034identifier)"; 489 | PRODUCT_NAME = "$(TARGET_NAME)"; 490 | PROVISIONING_PROFILE_SPECIFIER = ""; 491 | }; 492 | name = Release; 493 | }; 494 | 78DA97741A53951B006B0597 /* Debug */ = { 495 | isa = XCBuildConfiguration; 496 | buildSettings = { 497 | BUNDLE_LOADER = "$(TEST_HOST)"; 498 | FRAMEWORK_SEARCH_PATHS = ( 499 | "$(SDKROOT)/Developer/Library/Frameworks", 500 | "$(inherited)", 501 | ); 502 | GCC_PREPROCESSOR_DEFINITIONS = ( 503 | "DEBUG=1", 504 | "$(inherited)", 505 | ); 506 | INFOPLIST_FILE = RFJModelTests/Info.plist; 507 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 508 | PRODUCT_BUNDLE_IDENTIFIER = "TechAtk.$(PRODUCT_NAME:rfc1034identifier)"; 509 | PRODUCT_NAME = "$(TARGET_NAME)"; 510 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/RFJModel.app/RFJModel"; 511 | }; 512 | name = Debug; 513 | }; 514 | 78DA97751A53951B006B0597 /* Release */ = { 515 | isa = XCBuildConfiguration; 516 | buildSettings = { 517 | BUNDLE_LOADER = "$(TEST_HOST)"; 518 | FRAMEWORK_SEARCH_PATHS = ( 519 | "$(SDKROOT)/Developer/Library/Frameworks", 520 | "$(inherited)", 521 | ); 522 | INFOPLIST_FILE = RFJModelTests/Info.plist; 523 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 524 | PRODUCT_BUNDLE_IDENTIFIER = "TechAtk.$(PRODUCT_NAME:rfc1034identifier)"; 525 | PRODUCT_NAME = "$(TARGET_NAME)"; 526 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/RFJModel.app/RFJModel"; 527 | }; 528 | name = Release; 529 | }; 530 | /* End XCBuildConfiguration section */ 531 | 532 | /* Begin XCConfigurationList section */ 533 | 78DA97481A53951B006B0597 /* Build configuration list for PBXProject "RFJModel" */ = { 534 | isa = XCConfigurationList; 535 | buildConfigurations = ( 536 | 78DA976E1A53951B006B0597 /* Debug */, 537 | 78DA976F1A53951B006B0597 /* Release */, 538 | ); 539 | defaultConfigurationIsVisible = 0; 540 | defaultConfigurationName = Release; 541 | }; 542 | 78DA97701A53951B006B0597 /* Build configuration list for PBXNativeTarget "RFJModel" */ = { 543 | isa = XCConfigurationList; 544 | buildConfigurations = ( 545 | 78DA97711A53951B006B0597 /* Debug */, 546 | 78DA97721A53951B006B0597 /* Release */, 547 | ); 548 | defaultConfigurationIsVisible = 0; 549 | defaultConfigurationName = Release; 550 | }; 551 | 78DA97731A53951B006B0597 /* Build configuration list for PBXNativeTarget "RFJModelTests" */ = { 552 | isa = XCConfigurationList; 553 | buildConfigurations = ( 554 | 78DA97741A53951B006B0597 /* Debug */, 555 | 78DA97751A53951B006B0597 /* Release */, 556 | ); 557 | defaultConfigurationIsVisible = 0; 558 | defaultConfigurationName = Release; 559 | }; 560 | /* End XCConfigurationList section */ 561 | }; 562 | rootObject = 78DA97451A53951B006B0597 /* Project object */; 563 | } 564 | --------------------------------------------------------------------------------