├── 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 |
--------------------------------------------------------------------------------