├── .codecov.yml
├── .gitignore
├── .travis.yml
├── Benchmark
├── ModelBenchmark.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ └── contents.xcworkspacedata
├── ModelBenchmark.xcworkspace
│ └── contents.xcworkspacedata
├── ModelBenchmark
│ ├── AppDelegate.h
│ ├── AppDelegate.m
│ ├── Assets.xcassets
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── GithubUserModel
│ │ ├── GitHubUser.h
│ │ ├── GitHubUser.m
│ │ ├── SwiftGithubUser.swift
│ │ └── user.json
│ ├── Info.plist
│ ├── ModelBenchmark-Bridging-Header.h
│ ├── SwiftModel.swift
│ ├── ViewController.h
│ ├── ViewController.m
│ ├── WeiboModel
│ │ ├── DateFormatter.h
│ │ ├── DateFormatter.m
│ │ ├── FEWeiboModel.h
│ │ ├── FEWeiboModel.m
│ │ ├── JSWeiboModel.h
│ │ ├── JSWeiboModel.m
│ │ ├── MJWeiboModel.h
│ │ ├── MJWeiboModel.m
│ │ ├── MTWeiboModel.h
│ │ ├── MTWeiboModel.m
│ │ ├── YYWeiboModel.h
│ │ ├── YYWeiboModel.m
│ │ └── weibo.json
│ └── main.m
├── Podfile
├── Result.numbers
└── Result.png
├── Framework
├── Info.plist
└── YYModel.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ └── contents.xcworkspacedata
│ └── xcshareddata
│ └── xcschemes
│ └── YYModel.xcscheme
├── LICENSE
├── README.md
├── YYModel.podspec
├── YYModel
├── NSObject+YYModel.h
├── NSObject+YYModel.m
├── YYClassInfo.h
├── YYClassInfo.m
└── YYModel.h
└── YYModelTests
├── Info.plist
├── YYTestAutoTypeConvert.m
├── YYTestBlacklistWhitelist.m
├── YYTestClassInfo.m
├── YYTestCopyingAndCoding.m
├── YYTestCustomClass.m
├── YYTestCustomTransform.m
├── YYTestDescription.m
├── YYTestHelper.h
├── YYTestHelper.m
├── YYTestModelMapper.m
├── YYTestModelToJSON.m
└── YYTestNestModel.m
/.codecov.yml:
--------------------------------------------------------------------------------
1 | coverage:
2 | ignore:
3 | - YYModelTests/*
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OS X
2 | .DS_Store
3 |
4 | # Xcode
5 | #
6 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
7 |
8 | ## Build generated
9 | build/
10 | DerivedData/
11 |
12 | ## Various settings
13 | *.pbxuser
14 | !default.pbxuser
15 | *.mode1v3
16 | !default.mode1v3
17 | *.mode2v3
18 | !default.mode2v3
19 | *.perspectivev3
20 | !default.perspectivev3
21 | xcuserdata/
22 |
23 | ## Other
24 | *.moved-aside
25 | *.xccheckout
26 | *.xcuserstate
27 | *.xcscmblueprint
28 |
29 | ## Obj-C/Swift specific
30 | *.hmap
31 | *.ipa
32 | *.dSYM.zip
33 | *.dSYM
34 |
35 | # CocoaPods
36 | #
37 | # We recommend against adding the Pods directory to your .gitignore. However
38 | # you should judge for yourself, the pros and cons are mentioned at:
39 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
40 | #
41 | # Pods/
42 |
43 | # Carthage
44 | #
45 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
46 | # Carthage/Checkouts
47 |
48 | Carthage/Build
49 |
50 | # fastlane
51 | #
52 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
53 | # screenshots whenever they are needed.
54 | # For more information about the recommended setup visit:
55 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
56 |
57 | fastlane/report.xml
58 | fastlane/Preview.html
59 | fastlane/screenshots
60 | fastlane/test_output
61 |
62 | # Code Injection
63 | #
64 | # After new code Injection tools there's a generated folder /iOSInjectionProject
65 | # https://github.com/johnno1962/injectionforxcode
66 |
67 | iOSInjectionProject/
68 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: objective-c
2 | osx_image: xcode8
3 | xcode_project: Framework/YYModel.xcodeproj
4 | xcode_scheme: YYModel
5 |
6 | before_install:
7 | - env
8 | - xcodebuild -version
9 | - xcodebuild -showsdks
10 | - xcpretty --version
11 | - xcrun instruments -w 'iPhone 7' || sleep 15
12 |
13 | script:
14 | - set -o pipefail
15 | - xcodebuild clean build -project "$TRAVIS_XCODE_PROJECT" -scheme "$TRAVIS_XCODE_SCHEME" | xcpretty
16 | - xcodebuild test -project "$TRAVIS_XCODE_PROJECT" -scheme "$TRAVIS_XCODE_SCHEME" -destination "name=iPhone 7" -enableCodeCoverage YES | xcpretty
17 |
18 | after_success:
19 | - bash <(curl -s https://codecov.io/bash)
20 |
--------------------------------------------------------------------------------
/Benchmark/ModelBenchmark.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Benchmark/ModelBenchmark.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Benchmark/ModelBenchmark/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // ModelBenchmark
4 | //
5 | // Created by ibireme on 15/9/18.
6 | // Copyright (c) 2015 ibireme. 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 |
--------------------------------------------------------------------------------
/Benchmark/ModelBenchmark/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // ModelBenchmark
4 | //
5 | // Created by ibireme on 15/9/18.
6 | // Copyright (c) 2015 ibireme. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 |
11 | @interface AppDelegate ()
12 | @end
13 |
14 | @implementation AppDelegate
15 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
16 | return YES;
17 | }
18 | @end
19 |
--------------------------------------------------------------------------------
/Benchmark/ModelBenchmark/Assets.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 | }
--------------------------------------------------------------------------------
/Benchmark/ModelBenchmark/Base.lproj/LaunchScreen.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 |
--------------------------------------------------------------------------------
/Benchmark/ModelBenchmark/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 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/Benchmark/ModelBenchmark/GithubUserModel/GitHubUser.h:
--------------------------------------------------------------------------------
1 | //
2 | // GitHubUser.h
3 | // ModelBenchmark
4 | //
5 | // Created by ibireme on 15/9/18.
6 | // Copyright (c) 2015 ibireme. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #import
12 | #import
13 | #import
14 |
15 | // https://api.github.com/users/facebook
16 |
17 | /// manually GHUser
18 | @interface GHUser : NSObject
19 | @property (nonatomic, strong) NSString *login;
20 | @property (nonatomic, assign) UInt64 userID;
21 | @property (nonatomic, strong) NSString *avatarURL;
22 | @property (nonatomic, strong) NSString *gravatarID;
23 | @property (nonatomic, strong) NSString *url;
24 | @property (nonatomic, strong) NSString *htmlURL;
25 | @property (nonatomic, strong) NSString *followersURL;
26 | @property (nonatomic, strong) NSString *followingURL;
27 | @property (nonatomic, strong) NSString *gistsURL;
28 | @property (nonatomic, strong) NSString *starredURL;
29 | @property (nonatomic, strong) NSString *subscriptionsURL;
30 | @property (nonatomic, strong) NSString *organizationsURL;
31 | @property (nonatomic, strong) NSString *reposURL;
32 | @property (nonatomic, strong) NSString *eventsURL;
33 | @property (nonatomic, strong) NSString *receivedEventsURL;
34 | @property (nonatomic, strong) NSString *type;
35 | @property (nonatomic, assign) BOOL siteAdmin;
36 | @property (nonatomic, strong) NSString *name;
37 | @property (nonatomic, strong) NSString *company;
38 | @property (nonatomic, strong) NSString *blog;
39 | @property (nonatomic, strong) NSString *location;
40 | @property (nonatomic, strong) NSString *email;
41 | @property (nonatomic, strong) NSString *hireable;
42 | @property (nonatomic, strong) NSString *bio;
43 | @property (nonatomic, assign) UInt32 publicRepos;
44 | @property (nonatomic, assign) UInt32 publicGists;
45 | @property (nonatomic, assign) UInt32 followers;
46 | @property (nonatomic, assign) UInt32 following;
47 | @property (nonatomic, strong) NSDate *createdAt;
48 | @property (nonatomic, strong) NSDate *updatedAt;
49 | @property (nonatomic, strong) NSValue *test;
50 | - (instancetype)initWithJSONDictionary:(NSDictionary *)dictionary;
51 | - (NSDictionary *)convertToJSONDictionary;
52 | @end
53 |
54 | /// YYModel GHUser
55 | @interface YYGHUser : NSObject
56 | @property (nonatomic, strong) NSString *login;
57 | @property (nonatomic, assign) UInt64 userID;
58 | @property (nonatomic, strong) NSString *avatarURL;
59 | @property (nonatomic, strong) NSString *gravatarID;
60 | @property (nonatomic, strong) NSString *url;
61 | @property (nonatomic, strong) NSString *htmlURL;
62 | @property (nonatomic, strong) NSString *followersURL;
63 | @property (nonatomic, strong) NSString *followingURL;
64 | @property (nonatomic, strong) NSString *gistsURL;
65 | @property (nonatomic, strong) NSString *starredURL;
66 | @property (nonatomic, strong) NSString *subscriptionsURL;
67 | @property (nonatomic, strong) NSString *organizationsURL;
68 | @property (nonatomic, strong) NSString *reposURL;
69 | @property (nonatomic, strong) NSString *eventsURL;
70 | @property (nonatomic, strong) NSString *receivedEventsURL;
71 | @property (nonatomic, strong) NSString *type;
72 | @property (nonatomic, assign) BOOL siteAdmin;
73 | @property (nonatomic, strong) NSString *name;
74 | @property (nonatomic, strong) NSString *company;
75 | @property (nonatomic, strong) NSString *blog;
76 | @property (nonatomic, strong) NSString *location;
77 | @property (nonatomic, strong) NSString *email;
78 | @property (nonatomic, strong) NSString *hireable;
79 | @property (nonatomic, strong) NSString *bio;
80 | @property (nonatomic, assign) UInt32 publicRepos;
81 | @property (nonatomic, assign) UInt32 publicGists;
82 | @property (nonatomic, assign) UInt32 followers;
83 | @property (nonatomic, assign) UInt32 following;
84 | @property (nonatomic, strong) NSDate *createdAt;
85 | @property (nonatomic, strong) NSDate *updatedAt;
86 | @property (nonatomic, strong) NSValue *test;
87 | @end
88 |
89 | /// JSONModel GHUser
90 | @interface JSGHUser : JSONModel
91 | @property (nonatomic, strong) NSString *login;
92 | @property (nonatomic, assign) UInt64 userID;
93 | @property (nonatomic, strong) NSString *avatarURL;
94 | @property (nonatomic, strong) NSString *gravatarID;
95 | @property (nonatomic, strong) NSString *url;
96 | @property (nonatomic, strong) NSString *htmlURL;
97 | @property (nonatomic, strong) NSString *followersURL;
98 | @property (nonatomic, strong) NSString *followingURL;
99 | @property (nonatomic, strong) NSString *gistsURL;
100 | @property (nonatomic, strong) NSString *starredURL;
101 | @property (nonatomic, strong) NSString *subscriptionsURL;
102 | @property (nonatomic, strong) NSString *organizationsURL;
103 | @property (nonatomic, strong) NSString *reposURL;
104 | @property (nonatomic, strong) NSString *eventsURL;
105 | @property (nonatomic, strong) NSString *receivedEventsURL;
106 | @property (nonatomic, strong) NSString *type;
107 | @property (nonatomic, assign) BOOL siteAdmin;
108 | @property (nonatomic, strong) NSString *name;
109 | @property (nonatomic, strong) NSString *company;
110 | @property (nonatomic, strong) NSString *blog;
111 | @property (nonatomic, strong) NSString *location;
112 | @property (nonatomic, strong) NSString *email;
113 | @property (nonatomic, strong) NSString *hireable;
114 | @property (nonatomic, strong) NSString *bio;
115 | @property (nonatomic, assign) unsigned publicRepos;
116 | @property (nonatomic, assign) unsigned publicGists;
117 | @property (nonatomic, assign) unsigned followers;
118 | @property (nonatomic, assign) unsigned following;
119 | @property (nonatomic, strong) NSDate *createdAt;
120 | @property (nonatomic, strong) NSDate *updatedAt;
121 | @property (nonatomic, strong) NSValue *test;
122 | // JSONModel doesn't support UInt32 in armv7... Replace UInt32 with unsigned
123 | @end
124 |
125 | /// Mantle GHUser
126 | @interface MTGHUser : MTLModel
127 | @property (nonatomic, strong) NSString *login;
128 | @property (nonatomic, assign) UInt64 userID;
129 | @property (nonatomic, strong) NSString *avatarURL;
130 | @property (nonatomic, strong) NSString *gravatarID;
131 | @property (nonatomic, strong) NSString *url;
132 | @property (nonatomic, strong) NSString *htmlURL;
133 | @property (nonatomic, strong) NSString *followersURL;
134 | @property (nonatomic, strong) NSString *followingURL;
135 | @property (nonatomic, strong) NSString *gistsURL;
136 | @property (nonatomic, strong) NSString *starredURL;
137 | @property (nonatomic, strong) NSString *subscriptionsURL;
138 | @property (nonatomic, strong) NSString *organizationsURL;
139 | @property (nonatomic, strong) NSString *reposURL;
140 | @property (nonatomic, strong) NSString *eventsURL;
141 | @property (nonatomic, strong) NSString *receivedEventsURL;
142 | @property (nonatomic, strong) NSString *type;
143 | @property (nonatomic, assign) BOOL siteAdmin;
144 | @property (nonatomic, strong) NSString *name;
145 | @property (nonatomic, strong) NSString *company;
146 | @property (nonatomic, strong) NSString *blog;
147 | @property (nonatomic, strong) NSString *location;
148 | @property (nonatomic, strong) NSString *email;
149 | @property (nonatomic, strong) NSString *hireable;
150 | @property (nonatomic, strong) NSString *bio;
151 | @property (nonatomic, assign) UInt32 publicRepos;
152 | @property (nonatomic, assign) UInt32 publicGists;
153 | @property (nonatomic, assign) UInt32 followers;
154 | @property (nonatomic, assign) UInt32 following;
155 | @property (nonatomic, strong) NSDate *createdAt;
156 | @property (nonatomic, strong) NSDate *updatedAt;
157 | @property (nonatomic, strong) NSValue *test;
158 | @end
159 |
160 | /// FastEasyMapping GHUser
161 | @interface FEGHUser : NSObject
162 | @property (nonatomic, strong) NSString *login;
163 | @property (nonatomic, assign) UInt64 userID;
164 | @property (nonatomic, strong) NSString *avatarURL;
165 | @property (nonatomic, strong) NSString *gravatarID;
166 | @property (nonatomic, strong) NSString *url;
167 | @property (nonatomic, strong) NSString *htmlURL;
168 | @property (nonatomic, strong) NSString *followersURL;
169 | @property (nonatomic, strong) NSString *followingURL;
170 | @property (nonatomic, strong) NSString *gistsURL;
171 | @property (nonatomic, strong) NSString *starredURL;
172 | @property (nonatomic, strong) NSString *subscriptionsURL;
173 | @property (nonatomic, strong) NSString *organizationsURL;
174 | @property (nonatomic, strong) NSString *reposURL;
175 | @property (nonatomic, strong) NSString *eventsURL;
176 | @property (nonatomic, strong) NSString *receivedEventsURL;
177 | @property (nonatomic, strong) NSString *type;
178 | @property (nonatomic, assign) BOOL siteAdmin;
179 | @property (nonatomic, strong) NSString *name;
180 | @property (nonatomic, strong) NSString *company;
181 | @property (nonatomic, strong) NSString *blog;
182 | @property (nonatomic, strong) NSString *location;
183 | @property (nonatomic, strong) NSString *email;
184 | @property (nonatomic, strong) NSString *hireable;
185 | @property (nonatomic, strong) NSString *bio;
186 | @property (nonatomic, assign) UInt32 publicRepos;
187 | @property (nonatomic, assign) UInt32 publicGists;
188 | @property (nonatomic, assign) UInt32 followers;
189 | @property (nonatomic, assign) UInt32 following;
190 | @property (nonatomic, strong) NSDate *createdAt;
191 | @property (nonatomic, strong) NSDate *updatedAt;
192 | @property (nonatomic, strong) NSValue *test;
193 | + (FEMMapping *)defaultMapping;
194 | @end
195 |
196 | /// MJExtension GHUser
197 | @interface MJGHUser : NSObject
198 | @property (nonatomic, strong) NSString *login;
199 | @property (nonatomic, assign) UInt64 userID;
200 | @property (nonatomic, strong) NSString *avatarURL;
201 | @property (nonatomic, strong) NSString *gravatarID;
202 | @property (nonatomic, strong) NSString *url;
203 | @property (nonatomic, strong) NSString *htmlURL;
204 | @property (nonatomic, strong) NSString *followersURL;
205 | @property (nonatomic, strong) NSString *followingURL;
206 | @property (nonatomic, strong) NSString *gistsURL;
207 | @property (nonatomic, strong) NSString *starredURL;
208 | @property (nonatomic, strong) NSString *subscriptionsURL;
209 | @property (nonatomic, strong) NSString *organizationsURL;
210 | @property (nonatomic, strong) NSString *reposURL;
211 | @property (nonatomic, strong) NSString *eventsURL;
212 | @property (nonatomic, strong) NSString *receivedEventsURL;
213 | @property (nonatomic, strong) NSString *type;
214 | @property (nonatomic, assign) BOOL siteAdmin;
215 | @property (nonatomic, strong) NSString *name;
216 | @property (nonatomic, strong) NSString *company;
217 | @property (nonatomic, strong) NSString *blog;
218 | @property (nonatomic, strong) NSString *location;
219 | @property (nonatomic, strong) NSString *email;
220 | @property (nonatomic, strong) NSString *hireable;
221 | @property (nonatomic, strong) NSString *bio;
222 | @property (nonatomic, assign) UInt32 publicRepos;
223 | @property (nonatomic, assign) UInt32 publicGists;
224 | @property (nonatomic, assign) UInt32 followers;
225 | @property (nonatomic, assign) UInt32 following;
226 | @property (nonatomic, strong) NSDate *createdAt;
227 | @property (nonatomic, strong) NSDate *updatedAt;
228 | @property (nonatomic, strong) NSValue *test;
229 | @end
230 |
--------------------------------------------------------------------------------
/Benchmark/ModelBenchmark/GithubUserModel/GitHubUser.m:
--------------------------------------------------------------------------------
1 | //
2 | // GitHubUser.m
3 | // ModelBenchmark
4 | //
5 | // Created by ibireme on 15/9/18.
6 | // Copyright (c) 2015 ibireme. All rights reserved.
7 | //
8 |
9 | #import "GitHubUser.h"
10 | #import "DateFormatter.h"
11 |
12 |
13 | @implementation GHUser
14 |
15 | #define GHUSER_MANUALLY_SETTER_LIST \
16 | SET_STR(_login, @"login"); \
17 | SET_NUM(_userID, @"id"); \
18 | SET_STR(_avatarURL, @"avatar_url"); \
19 | SET_STR(_gravatarID, @"gravatar_id"); \
20 | SET_STR(_url, @"url"); \
21 | SET_STR(_htmlURL, @"html_url"); \
22 | SET_STR(_followersURL, @"followers_url"); \
23 | SET_STR(_followingURL, @"following_url"); \
24 | SET_STR(_gistsURL, @"gists_url"); \
25 | SET_STR(_starredURL,@"starred_url"); \
26 | SET_STR(_subscriptionsURL, @"subscriptions_url"); \
27 | SET_STR(_organizationsURL, @"organizations_url"); \
28 | SET_STR(_reposURL, @"repos_url"); \
29 | SET_STR(_eventsURL, @"events_url"); \
30 | SET_STR(_receivedEventsURL, @"received_events_url"); \
31 | SET_STR(_type, @"type"); \
32 | SET_NUM(_siteAdmin, @"site_admin"); \
33 | SET_STR(_name, @"name"); \
34 | SET_STR(_company, @"company"); \
35 | SET_STR(_blog, @"blog"); \
36 | SET_STR(_location, @"location"); \
37 | SET_STR(_email, @"email"); \
38 | SET_STR(_hireable, @"hireable"); \
39 | SET_STR(_bio, @"bio"); \
40 | SET_NUM(_publicRepos, @"public_repos"); \
41 | SET_NUM(_publicGists, @"public_gists"); \
42 | SET_NUM(_followers, @"followers"); \
43 | SET_NUM(_following, @"following");
44 |
45 | - (instancetype)initWithJSONDictionary:(NSDictionary *)dic {
46 | self = [super init];
47 | if (![dic isKindOfClass:[NSDictionary class]]) return nil;
48 |
49 | NSString *str;
50 | NSNumber *num;
51 |
52 | #define SET_STR(_IVAR_, _JSON_KEY_) \
53 | str = dic[_JSON_KEY_]; \
54 | if ([str isKindOfClass:[NSString class]]) _IVAR_ = str;
55 |
56 | #define SET_NUM(_IVAR_, _JSON_KEY_) \
57 | num = dic[_JSON_KEY_]; \
58 | if ([num isKindOfClass:[NSNumber class]]) _IVAR_ = num.unsignedIntValue;
59 |
60 | GHUSER_MANUALLY_SETTER_LIST
61 |
62 | #undef SET_STR
63 | #undef SET_NUM
64 | return self;
65 | }
66 |
67 | - (NSDictionary *)convertToJSONDictionary {
68 | NSMutableDictionary *dic = [NSMutableDictionary new];
69 |
70 | #define SET_STR(_IVAR_, _JSON_KEY_) \
71 | if (_IVAR_) dic[_JSON_KEY_] = _IVAR_;
72 |
73 | #define SET_NUM(_IVAR_, _JSON_KEY_) \
74 | dic[_JSON_KEY_] = @(_IVAR_);
75 |
76 | GHUSER_MANUALLY_SETTER_LIST
77 |
78 | #undef SET_STR
79 | #undef SET_NUM
80 | return dic;
81 | }
82 |
83 | - (void)encodeWithCoder:(NSCoder *)aCoder {
84 | if (!aCoder) return;
85 |
86 | #define SET_STR(_IVAR_, _JSON_KEY_) \
87 | [aCoder encodeObject:_IVAR_ forKey:(__bridge NSString *)CFSTR(#_IVAR_)];
88 |
89 | #define SET_NUM(_IVAR_, _JSON_KEY_) \
90 | [aCoder encodeObject:@(_IVAR_) forKey:(__bridge NSString *)CFSTR(#_IVAR_)];
91 |
92 | GHUSER_MANUALLY_SETTER_LIST
93 |
94 | #undef SET_STR
95 | #undef SET_NUM
96 | }
97 |
98 | - (id)initWithCoder:(NSCoder *)aDecoder {
99 | self = [self init];
100 | if (!self) return nil;
101 |
102 | #define SET_STR(_IVAR_, _JSON_KEY_) \
103 | _IVAR_ = [aDecoder decodeObjectForKey:(__bridge NSString *)CFSTR(#_IVAR_)];
104 |
105 | #define SET_NUM(_IVAR_, _JSON_KEY_) \
106 | _IVAR_ = ((NSNumber *)[aDecoder decodeObjectForKey:(__bridge NSString *)CFSTR(#_IVAR_)]).unsignedIntValue;
107 |
108 | GHUSER_MANUALLY_SETTER_LIST
109 |
110 | #undef SET_STR
111 | #undef SET_NUM
112 | return self;
113 | }
114 |
115 | #undef GHUSER_MANUALLY_SETTER_LIST
116 | @end
117 |
118 |
119 |
120 |
121 |
122 | @implementation YYGHUser
123 | + (NSDictionary *)modelCustomPropertyMapper {
124 | return @{
125 | @"userID" : @"id",
126 | @"avatarURL" : @"avatar_url",
127 | @"gravatarID" : @"gravatar_id",
128 | @"htmlURL" : @"html_url",
129 | @"followersURL" : @"followers_url",
130 | @"followingURL" : @"following_url",
131 | @"gistsURL" : @"gists_url",
132 | @"starredURL" : @"starred_url",
133 | @"subscriptionsURL" : @"subscriptions_url",
134 | @"organizationsURL" : @"organizations_url",
135 | @"reposURL" : @"repos_url",
136 | @"eventsURL" : @"events_url",
137 | @"receivedEventsURL" : @"received_events_url",
138 | @"siteAdmin" : @"site_admin",
139 | @"publicRepos" : @"public_repos",
140 | @"publicGists" : @"public_gists",
141 | @"createdAt" : @"created_at",
142 | @"updatedAt" : @"updated_at",
143 | };
144 | }
145 | - (void)encodeWithCoder:(NSCoder *)aCoder { [self yy_modelEncodeWithCoder:aCoder]; }
146 | - (id)initWithCoder:(NSCoder *)aDecoder { return [self yy_modelInitWithCoder:aDecoder]; }
147 | @end
148 |
149 |
150 |
151 |
152 |
153 | @implementation JSGHUser
154 | + (JSONKeyMapper *)keyMapper {
155 | return [[JSONKeyMapper alloc] initWithModelToJSONDictionary:@{
156 | @"userID" : @"id",
157 | @"avatarURL" : @"avatar_url",
158 | @"gravatarID" : @"gravatar_id",
159 | @"htmlURL" : @"html_url",
160 | @"followersURL" : @"followers_url",
161 | @"followingURL" : @"following_url",
162 | @"gistsURL" : @"gists_url",
163 | @"starredURL" : @"starred_url",
164 | @"subscriptionsURL" : @"subscriptions_url",
165 | @"organizationsURL" : @"organizations_url",
166 | @"reposURL" : @"repos_url",
167 | @"eventsURL" : @"events_url",
168 | @"receivedEventsURL" : @"received_events_url",
169 | @"siteAdmin" : @"site_admin",
170 | @"publicRepos" : @"public_repos",
171 | @"publicGists" : @"public_gists",
172 | @"createdAt" : @"created_at",
173 | @"updatedAt" : @"updated_at",
174 | }];
175 | }
176 | + (BOOL)propertyIsOptional:(NSString *)propertyName {
177 | return YES;
178 | }
179 | @end
180 |
181 |
182 |
183 |
184 |
185 | @implementation MTGHUser
186 | + (NSDictionary *)JSONKeyPathsByPropertyKey {
187 | return @{
188 | @"login" : @"login",
189 | @"userID" : @"id",
190 | @"avatarURL" : @"avatar_url",
191 | @"gravatarID" : @"gravatar_id",
192 | @"url" : @"url",
193 | @"htmlURL" : @"html_url",
194 | @"followersURL" : @"followers_url",
195 | @"followingURL" : @"following_url",
196 | @"gistsURL" : @"gists_url",
197 | @"starredURL" : @"starred_url",
198 | @"subscriptionsURL" : @"subscriptions_url",
199 | @"organizationsURL" : @"organizations_url",
200 | @"reposURL" : @"repos_url",
201 | @"eventsURL" : @"events_url",
202 | @"receivedEventsURL" : @"received_events_url",
203 | @"type" : @"type",
204 | @"siteAdmin" : @"site_admin",
205 | @"name" : @"name",
206 | @"company" : @"company",
207 | @"blog" : @"blog",
208 | @"location" : @"location",
209 | @"email" : @"email",
210 | @"hireable" : @"hireable",
211 | @"bio" : @"bio",
212 | @"publicRepos" : @"public_repos",
213 | @"publicGists" : @"public_gists",
214 | @"followers" : @"followers",
215 | @"following" : @"following",
216 | @"createdAt" : @"created_at",
217 | @"updatedAt" : @"updated_at",
218 | @"test" : @"test"
219 | };
220 | }
221 | @end
222 |
223 |
224 |
225 |
226 |
227 | @implementation FEGHUser
228 | + (FEMMapping *)defaultMapping {
229 | FEMMapping *mapping = [[FEMMapping alloc] initWithEntityName:@"FEGHUser"];
230 | [mapping addAttributesFromDictionary:@{
231 | @"login" : @"login",
232 | @"userID" : @"id",
233 | @"avatarURL" : @"avatar_url",
234 | @"gravatarID" : @"gravatar_id",
235 | @"url" : @"url",
236 | @"htmlURL" : @"html_url",
237 | @"followersURL" : @"followers_url",
238 | @"followingURL" : @"following_url",
239 | @"gistsURL" : @"gists_url",
240 | @"starredURL" : @"starred_url",
241 | @"subscriptionsURL" : @"subscriptions_url",
242 | @"organizationsURL" : @"organizations_url",
243 | @"reposURL" : @"repos_url",
244 | @"eventsURL" : @"events_url",
245 | @"receivedEventsURL" : @"received_events_url",
246 | @"type" : @"type",
247 | @"siteAdmin" : @"site_admin",
248 | @"name" : @"name",
249 | @"company" : @"company",
250 | @"blog" : @"blog",
251 | @"location" : @"location",
252 | @"email" : @"email",
253 | @"hireable" : @"hireable",
254 | @"bio" : @"bio",
255 | @"publicRepos" : @"public_repos",
256 | @"publicGists" : @"public_gists",
257 | @"followers" : @"followers",
258 | @"following" : @"following",
259 | @"createdAt" : @"created_at",
260 | @"updatedAt" : @"updated_at",
261 | @"test" : @"test"
262 | }];
263 | return mapping;
264 | }
265 | @end
266 |
267 |
268 |
269 |
270 |
271 | @implementation MJGHUser
272 | + (NSDictionary *)mj_replacedKeyFromPropertyName {
273 | return @{
274 | @"userID" : @"id",
275 | @"avatarURL" : @"avatar_url",
276 | @"gravatarID" : @"gravatar_id",
277 | @"htmlURL" : @"html_url",
278 | @"followersURL" : @"followers_url",
279 | @"followingURL" : @"following_url",
280 | @"gistsURL" : @"gists_url",
281 | @"starredURL" : @"starred_url",
282 | @"subscriptionsURL" : @"subscriptions_url",
283 | @"organizationsURL" : @"organizations_url",
284 | @"reposURL" : @"repos_url",
285 | @"eventsURL" : @"events_url",
286 | @"receivedEventsURL" : @"received_events_url",
287 | @"siteAdmin" : @"site_admin",
288 | @"publicRepos" : @"public_repos",
289 | @"publicGists" : @"public_gists",
290 | @"createdAt" : @"created_at",
291 | @"updatedAt" : @"updated_at",
292 | };
293 | }
294 | MJExtensionCodingImplementation
295 | @end
296 |
--------------------------------------------------------------------------------
/Benchmark/ModelBenchmark/GithubUserModel/user.json:
--------------------------------------------------------------------------------
1 | {
2 | "login": "facebook",
3 | "id": 69631,
4 | "avatar_url": "https://avatars.githubusercontent.com/u/69631?v=3",
5 | "gravatar_id": "",
6 | "url": "https://api.github.com/users/facebook",
7 | "html_url": "https://github.com/facebook",
8 | "followers_url": "https://api.github.com/users/facebook/followers",
9 | "following_url": "https://api.github.com/users/facebook/following{/other_user}",
10 | "gists_url": "https://api.github.com/users/facebook/gists{/gist_id}",
11 | "starred_url": "https://api.github.com/users/facebook/starred{/owner}{/repo}",
12 | "subscriptions_url": "https://api.github.com/users/facebook/subscriptions",
13 | "organizations_url": "https://api.github.com/users/facebook/orgs",
14 | "repos_url": "https://api.github.com/users/facebook/repos",
15 | "events_url": "https://api.github.com/users/facebook/events{/privacy}",
16 | "received_events_url": "https://api.github.com/users/facebook/received_events",
17 | "type": "Organization",
18 | "site_admin": false,
19 | "name": "Facebook",
20 | "company": null,
21 | "blog": "https://code.facebook.com/projects/",
22 | "location": "Menlo Park, California",
23 | "email": null,
24 | "hireable": null,
25 | "bio": "We work hard to contribute our work back to the web, mobile, big data, & infrastructure communities. NB: members must have two-factor auth.",
26 | "public_repos": 147,
27 | "public_gists": 12,
28 | "followers": 0,
29 | "following": 0
30 | }
31 |
--------------------------------------------------------------------------------
/Benchmark/ModelBenchmark/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
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 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/Benchmark/ModelBenchmark/ModelBenchmark-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // Use this file to import your target's public headers that you would like to expose to Swift.
3 | //
4 |
5 |
--------------------------------------------------------------------------------
/Benchmark/ModelBenchmark/SwiftModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // File.swift
3 | // ModelBenchmark
4 | //
5 | // Created by ibireme on 2017/8/6.
6 | // Copyright © 2017年 ibireme. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | @objc class GithubUserBenchmark : NSObject {
12 | @objc static public func benchmark() {
13 |
14 | GithubUserObjectMapper.benchmark()
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Benchmark/ModelBenchmark/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // ModelBenchmark
4 | //
5 | // Created by ibireme on 15/9/18.
6 | // Copyright (c) 2015 ibireme. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/Benchmark/ModelBenchmark/WeiboModel/DateFormatter.h:
--------------------------------------------------------------------------------
1 | //
2 | // DateFormatter.h
3 | // ModelBenchmark
4 | //
5 | // Created by ibireme on 15/9/18.
6 | // Copyright (c) 2015 ibireme. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface DateFormatter : NSObject
12 | + (NSDateFormatter *)githubDataFormatter;
13 | + (NSDateFormatter *)weiboDataFormatter;
14 | @end
15 |
--------------------------------------------------------------------------------
/Benchmark/ModelBenchmark/WeiboModel/DateFormatter.m:
--------------------------------------------------------------------------------
1 | //
2 | // DateFormatter.m
3 | // ModelBenchmark
4 | //
5 | // Created by ibireme on 15/9/18.
6 | // Copyright (c) 2015 ibireme. All rights reserved.
7 | //
8 |
9 | #import "DateFormatter.h"
10 | #import "JSONModel.h"
11 |
12 | @implementation DateFormatter
13 | + (NSDateFormatter *)githubDataFormatter {
14 | static NSDateFormatter *formatter;
15 | static dispatch_once_t onceToken;
16 | dispatch_once(&onceToken, ^{
17 | formatter = [[NSDateFormatter alloc] init];
18 | formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
19 | formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ";
20 | });
21 | return formatter;
22 | }
23 | + (NSDateFormatter *)weiboDataFormatter {
24 | static NSDateFormatter *formatter;
25 | static dispatch_once_t onceToken;
26 | dispatch_once(&onceToken, ^{
27 | formatter = [[NSDateFormatter alloc] init];
28 | formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
29 | formatter.dateFormat = @"EEE MMM dd HH:mm:ss Z yyyy";
30 | });
31 | return formatter;
32 | }
33 | @end
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/Benchmark/ModelBenchmark/WeiboModel/FEWeiboModel.h:
--------------------------------------------------------------------------------
1 | //
2 | // FEWeiboModel.h
3 | // ModelBenchmark
4 | //
5 | // Created by ibireme on 15/9/18.
6 | // Copyright (c) 2015 ibireme. All rights reserved.
7 | //
8 |
9 | #import "FEMMapping.h"
10 |
11 |
12 | @interface FEWeiboPictureMetadata : NSObject
13 | @property (nonatomic, strong) NSString *url;
14 | @property (nonatomic, assign) int width;
15 | @property (nonatomic, assign) int height;
16 | @property (nonatomic, strong) NSString *type;
17 | @property (nonatomic, assign) int cutType;
18 | + (FEMMapping *)defaultMapping;
19 | @end
20 |
21 | @interface FEWeiboPicture : NSObject
22 | @property (nonatomic, strong) NSString *picID;
23 | @property (nonatomic, strong) NSString *objectID;
24 | @property (nonatomic, assign) int photoTag;
25 | @property (nonatomic, assign) BOOL keepSize;
26 | @property (nonatomic, strong) FEWeiboPictureMetadata *thumbnail;
27 | @property (nonatomic, strong) FEWeiboPictureMetadata *bmiddle;
28 | @property (nonatomic, strong) FEWeiboPictureMetadata *middlePlus;
29 | @property (nonatomic, strong) FEWeiboPictureMetadata *large;
30 | @property (nonatomic, strong) FEWeiboPictureMetadata *largest;
31 | @property (nonatomic, strong) FEWeiboPictureMetadata *original;
32 | + (FEMMapping *)defaultMapping;
33 | @end
34 |
35 | @interface FEWeiboURL : NSObject
36 | @property (nonatomic, assign) BOOL result;
37 | @property (nonatomic, strong) NSString *shortURL;
38 | @property (nonatomic, strong) NSString *oriURL;
39 | @property (nonatomic, strong) NSString *urlTitle;
40 | @property (nonatomic, strong) NSString *urlTypePic;
41 | @property (nonatomic, assign) int32_t urlType;
42 | @property (nonatomic, strong) NSString *log;
43 | @property (nonatomic, strong) NSDictionary *actionLog;
44 | @property (nonatomic, strong) NSString *pageID;
45 | @property (nonatomic, strong) NSString *storageType;
46 | + (FEMMapping *)defaultMapping;
47 | @end
48 |
49 | @interface FEWeiboUser : NSObject
50 | @property (nonatomic, assign) uint64_t userID;
51 | @property (nonatomic, strong) NSString *idString;
52 | @property (nonatomic, strong) NSString *genderString;
53 | @property (nonatomic, strong) NSString *desc;
54 | @property (nonatomic, strong) NSString *domain;
55 | @property (nonatomic, strong) NSString *name;
56 | @property (nonatomic, strong) NSString *screenName;
57 | @property (nonatomic, strong) NSString *remark;
58 | @property (nonatomic, assign) int32_t followersCount;
59 | @property (nonatomic, assign) int32_t friendsCount;
60 | @property (nonatomic, assign) int32_t biFollowersCount;
61 | @property (nonatomic, assign) int32_t favouritesCount;
62 | @property (nonatomic, assign) int32_t statusesCount;
63 | @property (nonatomic, assign) int32_t pagefriendsCount;
64 | @property (nonatomic, assign) BOOL followMe;
65 | @property (nonatomic, assign) BOOL following;
66 | @property (nonatomic, strong) NSString *province;
67 | @property (nonatomic, strong) NSString *city;
68 | @property (nonatomic, strong) NSString *url;
69 | @property (nonatomic, strong) NSString *profileImageURL;
70 | @property (nonatomic, strong) NSString *avatarLarge;
71 | @property (nonatomic, strong) NSString *avatarHD;
72 | @property (nonatomic, strong) NSString *coverImage;
73 | @property (nonatomic, strong) NSString *coverImagePhone;
74 | @property (nonatomic, strong) NSString *profileURL;
75 | @property (nonatomic, assign) int32_t type;
76 | @property (nonatomic, assign) int32_t ptype;
77 | @property (nonatomic, assign) int32_t mbtype;
78 | @property (nonatomic, assign) int32_t urank;
79 | @property (nonatomic, assign) int32_t uclass;
80 | @property (nonatomic, assign) int32_t ulevel;
81 | @property (nonatomic, assign) int32_t mbrank;
82 | @property (nonatomic, assign) int32_t star;
83 | @property (nonatomic, assign) int32_t level;
84 | @property (nonatomic, strong) NSDate *createdAt;
85 | @property (nonatomic, assign) BOOL allowAllActMsg;
86 | @property (nonatomic, assign) BOOL allowAllComment;
87 | @property (nonatomic, assign) BOOL geoEnabled;
88 | @property (nonatomic, assign) int32_t onlineStatus;
89 | @property (nonatomic, strong) NSString *location;
90 | @property (nonatomic, strong) NSArray *icons;
91 | @property (nonatomic, strong) NSString *weihao;
92 | @property (nonatomic, strong) NSString *badgeTop;
93 | @property (nonatomic, assign) int32_t blockWord;
94 | @property (nonatomic, assign) int32_t blockApp;
95 | @property (nonatomic, assign) int32_t hasAbilityTag;
96 | @property (nonatomic, assign) int32_t creditScore;
97 | @property (nonatomic, strong) NSDictionary *badge;
98 | @property (nonatomic, strong) NSString *lang;
99 | @property (nonatomic, assign) int32_t userAbility;
100 | @property (nonatomic, strong) NSDictionary *extend;
101 | @property (nonatomic, assign) BOOL verified;
102 | @property (nonatomic, assign) int32_t verifiedType;
103 | @property (nonatomic, assign) int32_t verifiedLevel;
104 | @property (nonatomic, assign) int32_t verifiedState;
105 | @property (nonatomic, strong) NSString *verifiedContactEmail;
106 | @property (nonatomic, strong) NSString *verifiedContactMobile;
107 | @property (nonatomic, strong) NSString *verifiedTrade;
108 | @property (nonatomic, strong) NSString *verifiedContactName;
109 | @property (nonatomic, strong) NSString *verifiedSource;
110 | @property (nonatomic, strong) NSString *verifiedSourceURL;
111 | @property (nonatomic, strong) NSString *verifiedReason;
112 | @property (nonatomic, strong) NSString *verifiedReasonURL;
113 | @property (nonatomic, strong) NSString *verifiedReasonModified;
114 | + (FEMMapping *)defaultMapping;
115 | @end
116 |
117 | @interface FEWeiboStatus : NSObject
118 | @property (nonatomic, assign) uint64_t statusID;
119 | @property (nonatomic, strong) NSString *idstr;
120 | @property (nonatomic, strong) NSString *mid;
121 | @property (nonatomic, strong) NSString *rid;
122 | @property (nonatomic, strong) NSDate *createdAt;
123 | @property (nonatomic, strong) FEWeiboUser *user;
124 | @property (nonatomic, assign) int32_t userType;
125 | @property (nonatomic, strong) NSString *text;
126 | @property (nonatomic, strong) NSArray *picIds; /// Array
127 | @property (nonatomic, strong) NSDictionary *picInfos; /// Dic
128 | @property (nonatomic, strong) NSArray *urlStruct; ///< Array
129 | @property (nonatomic, assign) BOOL favorited;
130 | @property (nonatomic, assign) BOOL truncated;
131 | @property (nonatomic, assign) int32_t repostsCount;
132 | @property (nonatomic, assign) int32_t commentsCount;
133 | @property (nonatomic, assign) int32_t attitudesCount;
134 | @property (nonatomic, assign) int32_t attitudesStatus;
135 | @property (nonatomic, assign) int32_t recomState;
136 | @property (nonatomic, strong) NSString *inReplyToScreenName;
137 | @property (nonatomic, strong) NSString *inReplyToStatusId;
138 | @property (nonatomic, strong) NSString *inReplyToUserId;
139 | @property (nonatomic, strong) NSString *source;
140 | @property (nonatomic, assign) int32_t sourceType;
141 | @property (nonatomic, assign) int32_t sourceAllowClick;
142 | @property (nonatomic, strong) NSString *geo;
143 | @property (nonatomic, strong) NSArray *annotations;
144 | @property (nonatomic, assign) int32_t bizFeature;
145 | @property (nonatomic, assign) int32_t mlevel;
146 | @property (nonatomic, strong) NSString *mblogid;
147 | @property (nonatomic, strong) NSString *mblogTypeName;
148 | @property (nonatomic, assign) int32_t mblogType;
149 | @property (nonatomic, strong) NSString *scheme;
150 | @property (nonatomic, strong) NSDictionary *visible;
151 | @property (nonatomic, strong) NSArray *darwinTags;
152 | + (FEMMapping *)defaultMapping;
153 | @end
154 |
--------------------------------------------------------------------------------
/Benchmark/ModelBenchmark/WeiboModel/FEWeiboModel.m:
--------------------------------------------------------------------------------
1 | //
2 | // FEWeiboModel.m
3 | // ModelBenchmark
4 | //
5 | // Created by ibireme on 15/9/18.
6 | // Copyright (c) 2015 ibireme. All rights reserved.
7 | //
8 |
9 | #import "FEWeiboModel.h"
10 | #import "FEMDeserializer.h"
11 | #import "DateFormatter.h"
12 | #import "FEMSerializer.h"
13 |
14 | @implementation FEWeiboPictureMetadata
15 | + (FEMMapping *)defaultMapping {
16 | static FEMMapping *mapping;
17 | static dispatch_once_t onceToken;
18 | dispatch_once(&onceToken, ^{
19 | mapping = [[FEMMapping alloc] initWithEntityName:@"FEWeiboPictureMetadata"];
20 | [mapping addAttributesFromDictionary:@{
21 | @"url" : @"url",
22 | @"width" : @"width",
23 | @"height" : @"height",
24 | @"type" : @"type",
25 | @"cutType" : @"cut_type"
26 | }];
27 |
28 | });
29 | return mapping;
30 | }
31 | @end
32 |
33 | @implementation FEWeiboPicture
34 | + (FEMMapping *)defaultMapping {
35 | static FEMMapping *mapping;
36 | static dispatch_once_t onceToken;
37 | dispatch_once(&onceToken, ^{
38 | mapping = [[FEMMapping alloc] initWithEntityName:@"FEWeiboPicture"];
39 | [mapping addAttributesFromDictionary:@{
40 | @"picID" : @"pic_id",
41 | @"keepSize" : @"keep_size",
42 | @"photoTag" : @"photo_tag",
43 | @"objectID" : @"object_id",
44 | // @"thumbnail" : @"thumbnail",
45 | // @"bmiddle" : @"bmiddle",
46 | // @"middlePlus" : @"middleplus",
47 | // @"large" : @"large",
48 | // @"largest" : @"largest",
49 | // @"original" : @"original"
50 | }];
51 |
52 | FEMMapBlock map = (id)^(NSDictionary *value) {
53 | if ([value isKindOfClass:[NSDictionary class]]) {
54 | FEMMapping *mapping = [FEWeiboPictureMetadata defaultMapping];
55 | FEWeiboPictureMetadata *meta = [FEWeiboPictureMetadata new];
56 | [FEMDeserializer fillObject:meta fromRepresentation:value mapping:mapping];
57 | return meta;
58 | }
59 | return (FEWeiboPictureMetadata*)nil;
60 | };
61 | FEMMapBlock reverseMap = (id)^(NSDictionary *value) {
62 | if ([value isKindOfClass:[FEWeiboPictureMetadata class]]) {
63 | FEMMapping *mapping = [FEWeiboPictureMetadata defaultMapping];
64 | id meta = [FEMSerializer serializeObject:value usingMapping:mapping];
65 | return meta;
66 | }
67 | return (id)nil;
68 | };
69 | [mapping addAttribute:[[FEMAttribute alloc] initWithProperty:@"thumbnail" keyPath:@"thumbnail" map:map reverseMap:reverseMap]];
70 | [mapping addAttribute:[[FEMAttribute alloc] initWithProperty:@"bmiddle" keyPath:@"bmiddle" map:map reverseMap:reverseMap]];
71 | [mapping addAttribute:[[FEMAttribute alloc] initWithProperty:@"middlePlus" keyPath:@"middleplus" map:map reverseMap:reverseMap]];
72 | [mapping addAttribute:[[FEMAttribute alloc] initWithProperty:@"large" keyPath:@"large" map:map reverseMap:reverseMap]];
73 | [mapping addAttribute:[[FEMAttribute alloc] initWithProperty:@"largest" keyPath:@"largest" map:map reverseMap:reverseMap]];
74 | [mapping addAttribute:[[FEMAttribute alloc] initWithProperty:@"original" keyPath:@"original" map:map reverseMap:reverseMap]];
75 | });
76 | return mapping;
77 | }
78 | @end
79 |
80 | @implementation FEWeiboURL
81 | + (FEMMapping *)defaultMapping {
82 | static FEMMapping *mapping;
83 | static dispatch_once_t onceToken;
84 | dispatch_once(&onceToken, ^{
85 | mapping = [[FEMMapping alloc] initWithEntityName:@"FEWeiboURL"];
86 | [mapping addAttributesFromDictionary:@{
87 | @"result" : @"result",
88 | @"log" : @"log",
89 | @"oriURL" : @"ori_url",
90 | @"urlTitle" : @"url_title",
91 | @"urlTypePic" : @"url_type_pic",
92 | @"urlType" : @"url_type",
93 | @"shortURL" : @"short_url",
94 | @"actionLog" : @"actionlog",
95 | @"pageID" : @"page_id",
96 | @"storageType" : @"storage_type"
97 | }];
98 |
99 | });
100 | return mapping;
101 | }
102 | @end
103 |
104 | @implementation FEWeiboUser
105 | + (FEMMapping *)defaultMapping {
106 | static FEMMapping *mapping;
107 | static dispatch_once_t onceToken;
108 | dispatch_once(&onceToken, ^{
109 | mapping = [[FEMMapping alloc] initWithEntityName:@"FEWeiboUser"];
110 | [mapping addAttributesFromDictionary:@{
111 | @"userID" : @"id",
112 | @"idString" : @"idstr",
113 | @"genderString" : @"gender",
114 | @"desc" : @"description",
115 | @"domain" : @"domain",
116 | @"name" : @"name",
117 | @"screenName" : @"screen_name",
118 | @"remark" : @"remark",
119 | @"followersCount" : @"followers_count",
120 | @"friendsCount" : @"friends_count",
121 | @"biFollowersCount" : @"bi_followers_count",
122 | @"favouritesCount" : @"favourites_count",
123 | @"statusesCount" : @"statuses_count",
124 | @"pagefriendsCount" : @"pagefriends_count",
125 | @"followMe" : @"follow_me",
126 | @"following" : @"following",
127 | @"province" : @"province",
128 | @"city" : @"city",
129 | @"url" : @"url",
130 | @"profileImageURL" : @"profile_image_url",
131 | @"avatarLarge" : @"avatar_large",
132 | @"avatarHD" : @"avatar_hd",
133 | @"coverImage" : @"cover_image",
134 | @"coverImagePhone" : @"cover_image_phone",
135 | @"profileURL" : @"profile_url",
136 | @"type" : @"type",
137 | @"ptype" : @"ptype",
138 | @"mbtype" : @"mbtype",
139 | @"urank" : @"urank",
140 | @"uclass" : @"class",
141 | @"ulevel" : @"ulevel",
142 | @"mbrank" : @"mbrank",
143 | @"star" : @"star",
144 | @"level" : @"level",
145 | //@"createdAt" : @"created_at",
146 | @"allowAllActMsg" : @"allow_all_act_msg",
147 | @"allowAllComment" : @"allow_all_comment",
148 | @"geoEnabled" : @"geo_enabled",
149 | @"onlineStatus" : @"online_status",
150 | @"location" : @"location",
151 | @"icons" : @"icons",
152 | @"weihao" : @"weihao",
153 | @"badgeTop" : @"badge_top",
154 | @"blockWord" : @"block_word",
155 | @"blockApp" : @"block_app",
156 | @"hasAbilityTag" : @"has_ability_tag",
157 | @"creditScore" : @"credit_score",
158 | @"badge" : @"badge",
159 | @"lang" : @"lang",
160 | @"userAbility" : @"user_ability",
161 | @"extend" : @"extend",
162 | @"verified" : @"verified",
163 | @"verifiedType" : @"verified_type",
164 | @"verifiedLevel" : @"verified_level",
165 | @"verifiedState" : @"verified_state",
166 | @"verifiedContactEmail" : @"verified_contact_email",
167 | @"verifiedContactMobile" : @"verified_contact_mobile",
168 | @"verifiedTrade" : @"verified_trade",
169 | @"verifiedContactName" : @"verified_contact_name",
170 | @"verifiedSource" : @"verified_source",
171 | @"verifiedSourceURL" : @"verified_source_url",
172 | @"verifiedReason" : @"verified_reason",
173 | @"verifiedReasonURL" : @"verified_reason_url",
174 | @"verifiedReasonModified" : @"verified_reason_modified"
175 | }];
176 | FEMAttribute *createdAt = [[FEMAttribute alloc] initWithProperty:@"createdAt" keyPath:@"created_at" map:(id)^(NSString *value) {
177 | if ([value isKindOfClass:[NSString class]]) {
178 | return [[DateFormatter weiboDataFormatter] dateFromString:value];
179 | }
180 | return (NSDate*)nil;
181 | } reverseMap:(id)^(id value) {
182 | if ([value isKindOfClass:[NSDate class]]) {
183 | return [[DateFormatter weiboDataFormatter] stringFromDate:value];
184 | }
185 | return (NSString *)[NSNull null];
186 | }];
187 | [mapping addAttribute:createdAt];
188 | });
189 | return mapping;
190 | }
191 | @end
192 |
193 | @implementation FEWeiboStatus
194 | + (FEMMapping *)defaultMapping {
195 | static FEMMapping *mapping;
196 | static dispatch_once_t onceToken;
197 | dispatch_once(&onceToken, ^{
198 | mapping = [[FEMMapping alloc] initWithEntityName:@"FEWeiboStatus"];
199 | [mapping addAttributesFromDictionary:@{
200 | @"statusID" : @"id",
201 | @"idstr" : @"idstr",
202 | @"mid" : @"mid",
203 | @"rid" : @"rid",
204 | //@"createdAt" : @"created_at",
205 | //@"user" : @"user",
206 | @"userType" : @"userType",
207 | @"text" : @"text",
208 | @"picIds" : @"pic_ids",
209 | //@"picInfos" : @"pic_infos",
210 | //@"urlStruct" : @"url_struct",
211 | @"favorited" : @"favorited",
212 | @"truncated" : @"truncated",
213 | @"repostsCount" : @"reposts_count",
214 | @"commentsCount" : @"comments_count",
215 | @"attitudesCount" : @"attitudes_count",
216 | @"attitudesStatus" : @"attitudes_status",
217 | @"recomState" : @"recom_state",
218 | @"inReplyToScreenName" : @"in_reply_to_screen_name",
219 | @"inReplyToStatusId" : @"in_reply_to_status_id",
220 | @"inReplyToUserId" : @"in_reply_to_user_id",
221 | @"source" : @"source",
222 | @"sourceType" : @"source_type",
223 | @"sourceAllowClick" : @"source_allowclick",
224 | @"geo" : @"geo",
225 | @"annotations" : @"annotations",
226 | @"bizFeature" : @"biz_feature",
227 | @"mblogid" : @"mblogid",
228 | @"mblogTypeName" : @"mblogtypename",
229 | @"mblogType" : @"mblogtype",
230 | @"scheme" : @"scheme",
231 | @"visible" : @"visible",
232 | @"darwinTags" : @"darwin_tags"
233 | }];
234 |
235 | FEMAttribute *createdAt = [[FEMAttribute alloc] initWithProperty:@"createdAt" keyPath:@"created_at" map:(id)^(NSString *value) {
236 | if ([value isKindOfClass:[NSString class]]) {
237 | return [[DateFormatter weiboDataFormatter] dateFromString:value];
238 | }
239 | return (NSDate*)nil;
240 | } reverseMap:(id)^(id value) {
241 | if ([value isKindOfClass:[NSDate class]]) {
242 | return [[DateFormatter weiboDataFormatter] stringFromDate:value];
243 | }
244 | return (NSString *)[NSNull null];
245 | }];
246 | [mapping addAttribute:createdAt];
247 |
248 | FEMAttribute *user = [[FEMAttribute alloc] initWithProperty:@"user" keyPath:@"user" map:(id)^(NSDictionary *value) {
249 | if ([value isKindOfClass:[NSDictionary class]]) {
250 | FEMMapping *mapping = [FEWeiboUser defaultMapping];
251 | FEWeiboUser *user = [FEWeiboUser new];
252 | [FEMDeserializer fillObject:user fromRepresentation:value mapping:mapping];
253 | return user;
254 | }
255 | return (FEWeiboUser*)nil;
256 | } reverseMap:(id)^(FEWeiboUser *value) {
257 | if ([value isKindOfClass:[FEWeiboUser class]]) {
258 | FEMMapping *mapping = [FEWeiboUser defaultMapping];
259 | id user = [FEMSerializer serializeObject:value usingMapping:mapping];
260 | return user;
261 | }
262 | return (id)nil;
263 | }];
264 | [mapping addAttribute:user];
265 |
266 | FEMAttribute *picInfos = [[FEMAttribute alloc] initWithProperty:@"picInfos" keyPath:@"pic_infos" map:(id)^(NSDictionary *value) {
267 | if ([value isKindOfClass:[NSDictionary class]]) {
268 | NSMutableDictionary *infos = [NSMutableDictionary new];
269 | FEMMapping *picMapping = [FEWeiboPicture defaultMapping];
270 | [value enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
271 | FEWeiboPicture *pic = [FEWeiboPicture new];
272 | [FEMDeserializer fillObject:pic fromRepresentation:obj mapping:picMapping];
273 | infos[key] = pic;
274 | }];
275 | return (id)infos;
276 | }
277 | return (id)nil;
278 | } reverseMap:(id) ^ (NSDictionary *value) {
279 | FEMMapping *picMapping = [FEWeiboPicture defaultMapping];
280 | NSMutableDictionary *infos = [NSMutableDictionary new];
281 | [value enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
282 | id pic = [FEMSerializer serializeObject:obj usingMapping:picMapping];
283 | if (pic) infos[key] = pic;
284 | }];
285 | return infos;
286 | }];
287 | [mapping addAttribute:picInfos];
288 |
289 | FEMAttribute *urlStruct = [[FEMAttribute alloc] initWithProperty:@"urlStruct" keyPath:@"url_struct" map:(id)^(NSArray *value) {
290 | if ([value isKindOfClass:[NSArray class]]) {
291 | NSMutableArray *urls = [NSMutableArray new];
292 | FEMMapping *picMapping = [FEWeiboURL defaultMapping];
293 | [value enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
294 | FEWeiboURL *url = [FEWeiboURL new];
295 | [FEMDeserializer fillObject:url fromRepresentation:obj mapping:picMapping];
296 | [urls addObject:url];
297 | }];
298 | return (id)urls;
299 | }
300 | return (id)nil;
301 | } reverseMap:(id) ^ (NSArray *value) {
302 | FEMMapping *picMapping = [FEWeiboURL defaultMapping];
303 | NSMutableArray *urls = [NSMutableArray new];
304 | [value enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
305 | id url = [FEMSerializer serializeObject:obj usingMapping:picMapping];
306 | if (url) [urls addObject:url];
307 | }];
308 | return urls;
309 | }];
310 | [mapping addAttribute:urlStruct];
311 |
312 | });
313 | return mapping;
314 | }
315 |
316 | @end
--------------------------------------------------------------------------------
/Benchmark/ModelBenchmark/WeiboModel/JSWeiboModel.h:
--------------------------------------------------------------------------------
1 | //
2 | // JSWeiboModel.h
3 | // ModelBenchmark
4 | //
5 | // Created by ibireme on 15/9/18.
6 | // Copyright (c) 2015 ibireme. All rights reserved.
7 | //
8 |
9 | #import "JSONModel.h"
10 |
11 |
12 | @interface JSWeiboPictureMetadata : JSONModel
13 | @property (nonatomic, strong) NSString *url;
14 | @property (nonatomic, assign) int width;
15 | @property (nonatomic, assign) int height;
16 | @property (nonatomic, strong) NSString *type;
17 | @property (nonatomic, assign) int cutType;
18 | @end
19 |
20 | @protocol JSWeiboPicture
21 | @end
22 | @interface JSWeiboPicture : JSONModel
23 | @property (nonatomic, strong) NSString *picID;
24 | @property (nonatomic, strong) NSString *objectID;
25 | @property (nonatomic, assign) int photoTag;
26 | @property (nonatomic, assign) BOOL keepSize;
27 | @property (nonatomic, strong) JSWeiboPictureMetadata *thumbnail;
28 | @property (nonatomic, strong) JSWeiboPictureMetadata *bmiddle;
29 | @property (nonatomic, strong) JSWeiboPictureMetadata *middlePlus;
30 | @property (nonatomic, strong) JSWeiboPictureMetadata *large;
31 | @property (nonatomic, strong) JSWeiboPictureMetadata *largest;
32 | @property (nonatomic, strong) JSWeiboPictureMetadata *original;
33 | @end
34 |
35 | @protocol JSWeiboURL
36 | @end
37 | @interface JSWeiboURL : JSONModel
38 | @property (nonatomic, assign) BOOL result;
39 | @property (nonatomic, strong) NSString *shortURL;
40 | @property (nonatomic, strong) NSString *oriURL;
41 | @property (nonatomic, strong) NSString *urlTitle;
42 | @property (nonatomic, strong) NSString *urlTypePic;
43 | @property (nonatomic, assign) int32_t urlType;
44 | @property (nonatomic, strong) NSString *log;
45 | @property (nonatomic, strong) NSDictionary *actionLog;
46 | @property (nonatomic, strong) NSString *pageID;
47 | @property (nonatomic, strong) NSString *storageType;
48 | @end
49 |
50 | @interface JSWeiboUser : JSONModel
51 | @property (nonatomic, assign) uint64_t userID;
52 | @property (nonatomic, strong) NSString *idString;
53 | @property (nonatomic, strong) NSString *genderString;
54 | @property (nonatomic, strong) NSString *desc;
55 | @property (nonatomic, strong) NSString *domain;
56 | @property (nonatomic, strong) NSString *name;
57 | @property (nonatomic, strong) NSString *screenName;
58 | @property (nonatomic, strong) NSString *remark;
59 | @property (nonatomic, assign) int32_t followersCount;
60 | @property (nonatomic, assign) int32_t friendsCount;
61 | @property (nonatomic, assign) int32_t biFollowersCount;
62 | @property (nonatomic, assign) int32_t favouritesCount;
63 | @property (nonatomic, assign) int32_t statusesCount;
64 | @property (nonatomic, assign) int32_t pagefriendsCount;
65 | @property (nonatomic, assign) BOOL followMe;
66 | @property (nonatomic, assign) BOOL following;
67 | @property (nonatomic, strong) NSString *province;
68 | @property (nonatomic, strong) NSString *city;
69 | @property (nonatomic, strong) NSString *url;
70 | @property (nonatomic, strong) NSString *profileImageURL;
71 | @property (nonatomic, strong) NSString *avatarLarge;
72 | @property (nonatomic, strong) NSString *avatarHD;
73 | @property (nonatomic, strong) NSString *coverImage;
74 | @property (nonatomic, strong) NSString *coverImagePhone;
75 | @property (nonatomic, strong) NSString *profileURL;
76 | @property (nonatomic, assign) int32_t type;
77 | @property (nonatomic, assign) int32_t ptype;
78 | @property (nonatomic, assign) int32_t mbtype;
79 | @property (nonatomic, assign) int32_t urank;
80 | @property (nonatomic, assign) int32_t uclass;
81 | @property (nonatomic, assign) int32_t ulevel;
82 | @property (nonatomic, assign) int32_t mbrank;
83 | @property (nonatomic, assign) int32_t star;
84 | @property (nonatomic, assign) int32_t level;
85 | @property (nonatomic, strong) NSDate *createdAt;
86 | @property (nonatomic, assign) BOOL allowAllActMsg;
87 | @property (nonatomic, assign) BOOL allowAllComment;
88 | @property (nonatomic, assign) BOOL geoEnabled;
89 | @property (nonatomic, assign) int32_t onlineStatus;
90 | @property (nonatomic, strong) NSString *location;
91 | @property (nonatomic, strong) NSArray *icons;
92 | @property (nonatomic, strong) NSString *weihao;
93 | @property (nonatomic, strong) NSString *badgeTop;
94 | @property (nonatomic, assign) int32_t blockWord;
95 | @property (nonatomic, assign) int32_t blockApp;
96 | @property (nonatomic, assign) int32_t hasAbilityTag;
97 | @property (nonatomic, assign) int32_t creditScore;
98 | @property (nonatomic, strong) NSDictionary *badge;
99 | @property (nonatomic, strong) NSString *lang;
100 | @property (nonatomic, assign) int32_t userAbility;
101 | @property (nonatomic, strong) NSDictionary *extend;
102 | @property (nonatomic, assign) BOOL verified;
103 | @property (nonatomic, assign) int32_t verifiedType;
104 | @property (nonatomic, assign) int32_t verifiedLevel;
105 | @property (nonatomic, assign) int32_t verifiedState;
106 | @property (nonatomic, strong) NSString *verifiedContactEmail;
107 | @property (nonatomic, strong) NSString *verifiedContactMobile;
108 | @property (nonatomic, strong) NSString *verifiedTrade;
109 | @property (nonatomic, strong) NSString *verifiedContactName;
110 | @property (nonatomic, strong) NSString *verifiedSource;
111 | @property (nonatomic, strong) NSString *verifiedSourceURL;
112 | @property (nonatomic, strong) NSString *verifiedReason;
113 | @property (nonatomic, strong) NSString *verifiedReasonURL;
114 | @property (nonatomic, strong) NSString *verifiedReasonModified;
115 | @end
116 |
117 | @interface JSWeiboStatus : JSONModel
118 | @property (nonatomic, assign) uint64_t statusID;
119 | @property (nonatomic, strong) NSString *idstr;
120 | @property (nonatomic, strong) NSString *mid;
121 | @property (nonatomic, strong) NSString *rid;
122 | @property (nonatomic, strong) NSDate *createdAt;
123 | @property (nonatomic, strong) JSWeiboUser *user;
124 | @property (nonatomic, assign) int32_t userType;
125 | @property (nonatomic, strong) NSString *text;
126 | @property (nonatomic, strong) NSArray *picIds; /// Array
127 | @property (nonatomic, strong) NSDictionary *picInfos; /// Dic
128 | @property (nonatomic, strong) NSArray *urlStruct; ///< Array
129 | @property (nonatomic, assign) BOOL favorited;
130 | @property (nonatomic, assign) BOOL truncated;
131 | @property (nonatomic, assign) int32_t repostsCount;
132 | @property (nonatomic, assign) int32_t commentsCount;
133 | @property (nonatomic, assign) int32_t attitudesCount;
134 | @property (nonatomic, assign) int32_t attitudesStatus;
135 | @property (nonatomic, assign) int32_t recomState;
136 | @property (nonatomic, strong) NSString *inReplyToScreenName;
137 | @property (nonatomic, strong) NSString *inReplyToStatusId;
138 | @property (nonatomic, strong) NSString *inReplyToUserId;
139 | @property (nonatomic, strong) NSString *source;
140 | @property (nonatomic, assign) int32_t sourceType;
141 | @property (nonatomic, assign) int32_t sourceAllowClick;
142 | @property (nonatomic, strong) NSString *geo;
143 | @property (nonatomic, strong) NSArray *annotations;
144 | @property (nonatomic, assign) int32_t bizFeature;
145 | @property (nonatomic, assign) int32_t mlevel;
146 | @property (nonatomic, strong) NSString *mblogid;
147 | @property (nonatomic, strong) NSString *mblogTypeName;
148 | @property (nonatomic, assign) int32_t mblogType;
149 | @property (nonatomic, strong) NSString *scheme;
150 | @property (nonatomic, strong) NSDictionary *visible;
151 | @property (nonatomic, strong) NSArray *darwinTags;
152 | @end
153 |
154 |
--------------------------------------------------------------------------------
/Benchmark/ModelBenchmark/WeiboModel/JSWeiboModel.m:
--------------------------------------------------------------------------------
1 | //
2 | // JSWeiboModel.m
3 | // ModelBenchmark
4 | //
5 | // Created by ibireme on 15/9/18.
6 | // Copyright (c) 2015 ibireme. All rights reserved.
7 | //
8 |
9 | #import "JSWeiboModel.h"
10 | #import "DateFormatter.h"
11 |
12 | @implementation JSWeiboPictureMetadata
13 | + (JSONKeyMapper *)keyMapper {
14 | return [[JSONKeyMapper alloc] initWithModelToJSONDictionary:@{ @"cut_type" : @"cutType" }];
15 | }
16 | +(BOOL)propertyIsOptional:(NSString*)propertyName {
17 | return YES;
18 | }
19 | @end
20 |
21 | @implementation JSWeiboPicture
22 | + (JSONKeyMapper *)keyMapper {
23 | return [[JSONKeyMapper alloc] initWithModelToJSONDictionary:@{
24 | @"url" : @"url",
25 | @"width" : @"width",
26 | @"height" : @"height",
27 | @"type" : @"type",
28 | @"cutType" : @"cut_type"
29 | }];
30 | }
31 | +(BOOL)propertyIsOptional:(NSString*)propertyName {
32 | return YES;
33 | }
34 | @end
35 |
36 | @implementation JSWeiboURL
37 | + (JSONKeyMapper *)keyMapper {
38 | return [[JSONKeyMapper alloc] initWithModelToJSONDictionary:@{
39 | @"oriURL" : @"ori_url",
40 | @"urlTitle" : @"url_title",
41 | @"urlTypePic" : @"url_type_pic",
42 | @"urlType" : @"url_type",
43 | @"shortURL" : @"short_url",
44 | @"actionLog" : @"actionlog",
45 | @"pageID" : @"page_id",
46 | @"storageType" : @"storage_type"
47 | }];
48 | }
49 | +(BOOL)propertyIsOptional:(NSString*)propertyName {
50 | return YES;
51 | }
52 | @end
53 |
54 | @implementation JSWeiboUser
55 | + (JSONKeyMapper *)keyMapper {
56 | return [[JSONKeyMapper alloc] initWithModelToJSONDictionary:@{
57 | @"userID" : @"id",
58 | @"idString" : @"idstr",
59 | @"genderString" : @"gender",
60 | @"biFollowersCount" : @"bi_followers_count",
61 | @"profileImageURL" : @"profile_image_url",
62 | @"uclass" : @"class",
63 | @"verifiedContactEmail" : @"verified_contact_email",
64 | @"statusesCount" : @"statuses_count",
65 | @"geoEnabled" : @"geo_enabled",
66 | @"followMe" : @"follow_me",
67 | @"coverImagePhone" : @"cover_image_phone",
68 | @"desc" : @"description",
69 | @"followersCount" : @"followers_count",
70 | @"verifiedContactMobile" : @"verified_contact_mobile",
71 | @"avatarLarge" : @"avatar_large",
72 | @"verifiedTrade" : @"verified_trade",
73 | @"profileURL" : @"profile_url",
74 | @"coverImage" : @"cover_image",
75 | @"onlineStatus" : @"online_status",
76 | @"badgeTop" : @"badge_top",
77 | @"verifiedContactName" : @"verified_contact_name",
78 | @"screenName" : @"screen_name",
79 | @"verifiedSourceURL" : @"verified_source_url",
80 | @"pagefriendsCount" : @"pagefriends_count",
81 | @"verifiedReason" : @"verified_reason",
82 | @"friendsCount" : @"friends_count",
83 | @"blockApp" : @"block_app",
84 | @"hasAbilityTag" : @"has_ability_tag",
85 | @"avatarHD" : @"avatar_hd",
86 | @"creditScore" : @"credit_score",
87 | @"createdAt" : @"created_at",
88 | @"blockWord" : @"block_word",
89 | @"allowAllActMsg" : @"allow_all_act_msg",
90 | @"verifiedState" : @"verified_state",
91 | @"verifiedReasonModified" : @"verified_reason_modified",
92 | @"allowAllComment" : @"allow_all_comment",
93 | @"verifiedLevel" : @"verified_level",
94 | @"verifiedReasonURL" : @"verified_reason_url",
95 | @"favouritesCount" : @"favourites_count",
96 | @"verifiedType" : @"verified_type",
97 | @"verifiedSource" : @"verified_source",
98 | @"userAbility" : @"user_ability"}];
99 | }
100 | +(BOOL)propertyIsOptional:(NSString*)propertyName {
101 | return YES;
102 | }
103 | @end
104 |
105 | @implementation JSWeiboStatus
106 | + (JSONKeyMapper *)keyMapper {
107 | return [[JSONKeyMapper alloc] initWithModelToJSONDictionary:@{
108 | @"statusID" : @"id",
109 | @"createdAt" : @"created_at",
110 | @"attitudesStatus" : @"attitudes_status",
111 | @"inReplyToScreenName" : @"in_reply_to_screen_name",
112 | @"sourceType" : @"source_type",
113 | @"commentsCount" : @"comments_count",
114 | @"urlStruct" : @"url_struct",
115 | @"recomState" : @"recom_state",
116 | @"sourceAllowClick" : @"source_allowclick",
117 | @"bizFeature" : @"biz_feature",
118 | @"mblogTypeName" : @"mblogtypename",
119 | @"mblogType" : @"mblogtype",
120 | @"inReplyToStatusId" : @"in_reply_to_status_id",
121 | @"picIds" : @"pic_ids",
122 | @"repostsCount" : @"reposts_count",
123 | @"attitudesCount" : @"attitudes_count",
124 | @"darwinTags" : @"darwin_tags",
125 | @"userType" : @"userType",
126 | @"picInfos" : @"pic_infos",
127 | @"inReplyToUserId" : @"in_reply_to_user_id"
128 | }];
129 | }
130 | +(BOOL)propertyIsOptional:(NSString*)propertyName {
131 | return YES;
132 | }
133 | @end
134 |
135 |
136 |
137 |
138 |
139 | /**
140 | JSONModel use a global transformer to transform value...
141 | But how to create a custom transformer for a specified model ?!!!!
142 | */
143 | @interface JSONValueTransformer(CustomDate)
144 | -(NSDate*)__NSDateFromNSString:(NSString*)string;
145 | @end
146 |
147 | #pragma clang diagnostic push
148 | #pragma clang diagnostic ignored "-Wincomplete-implementation"
149 | @implementation JSONValueTransformer (CustomDate)
150 | - (NSDate *)NSDateFromNSString:(NSString *)string {
151 | if (string.length == 30) {
152 | return [[DateFormatter weiboDataFormatter] dateFromString:string];
153 | } else {
154 | return [self __NSDateFromNSString:string];
155 | }
156 | }
157 | @end
158 | #pragma clang diagnostic pop
159 |
--------------------------------------------------------------------------------
/Benchmark/ModelBenchmark/WeiboModel/MJWeiboModel.h:
--------------------------------------------------------------------------------
1 | //
2 | // MJWeiboModel.h
3 | // ModelBenchmark
4 | //
5 | // Created by ibireme on 15/9/18.
6 | // Copyright (c) 2015 ibireme. All rights reserved.
7 | //
8 |
9 | #import "MJExtension.h"
10 |
11 |
12 | @interface MJWeiboPictureMetadata : NSObject
13 | @property (nonatomic, strong) NSString *url;
14 | @property (nonatomic, assign) int width;
15 | @property (nonatomic, assign) int height;
16 | @property (nonatomic, strong) NSString *type;
17 | @property (nonatomic, assign) int cutType;
18 | @end
19 |
20 | @interface MJWeiboPicture : NSObject
21 | @property (nonatomic, strong) NSString *picID;
22 | @property (nonatomic, strong) NSString *objectID;
23 | @property (nonatomic, assign) int photoTag;
24 | @property (nonatomic, assign) BOOL keepSize;
25 | @property (nonatomic, strong) MJWeiboPictureMetadata *thumbnail;
26 | @property (nonatomic, strong) MJWeiboPictureMetadata *bmiddle;
27 | @property (nonatomic, strong) MJWeiboPictureMetadata *middlePlus;
28 | @property (nonatomic, strong) MJWeiboPictureMetadata *large;
29 | @property (nonatomic, strong) MJWeiboPictureMetadata *largest;
30 | @property (nonatomic, strong) MJWeiboPictureMetadata *original;
31 | @end
32 |
33 | @interface MJWeiboURL : NSObject
34 | @property (nonatomic, assign) BOOL result;
35 | @property (nonatomic, strong) NSString *shortURL;
36 | @property (nonatomic, strong) NSString *oriURL;
37 | @property (nonatomic, strong) NSString *urlTitle;
38 | @property (nonatomic, strong) NSString *urlTypePic;
39 | @property (nonatomic, assign) int32_t urlType;
40 | @property (nonatomic, strong) NSString *log;
41 | @property (nonatomic, strong) NSDictionary *actionLog;
42 | @property (nonatomic, strong) NSString *pageID;
43 | @property (nonatomic, strong) NSString *storageType;
44 | @end
45 |
46 | @interface MJWeiboUser : NSObject
47 | @property (nonatomic, assign) uint64_t userID;
48 | @property (nonatomic, strong) NSString *idString;
49 | @property (nonatomic, strong) NSString *genderString;
50 | @property (nonatomic, strong) NSString *desc;
51 | @property (nonatomic, strong) NSString *domain;
52 | @property (nonatomic, strong) NSString *name;
53 | @property (nonatomic, strong) NSString *screenName;
54 | @property (nonatomic, strong) NSString *remark;
55 | @property (nonatomic, assign) int32_t followersCount;
56 | @property (nonatomic, assign) int32_t friendsCount;
57 | @property (nonatomic, assign) int32_t biFollowersCount;
58 | @property (nonatomic, assign) int32_t favouritesCount;
59 | @property (nonatomic, assign) int32_t statusesCount;
60 | @property (nonatomic, assign) int32_t pagefriendsCount;
61 | @property (nonatomic, assign) BOOL followMe;
62 | @property (nonatomic, assign) BOOL following;
63 | @property (nonatomic, strong) NSString *province;
64 | @property (nonatomic, strong) NSString *city;
65 | @property (nonatomic, strong) NSString *url;
66 | @property (nonatomic, strong) NSString *profileImageURL;
67 | @property (nonatomic, strong) NSString *avatarLarge;
68 | @property (nonatomic, strong) NSString *avatarHD;
69 | @property (nonatomic, strong) NSString *coverImage;
70 | @property (nonatomic, strong) NSString *coverImagePhone;
71 | @property (nonatomic, strong) NSString *profileURL;
72 | @property (nonatomic, assign) int32_t type;
73 | @property (nonatomic, assign) int32_t ptype;
74 | @property (nonatomic, assign) int32_t mbtype;
75 | @property (nonatomic, assign) int32_t urank;
76 | @property (nonatomic, assign) int32_t uclass;
77 | @property (nonatomic, assign) int32_t ulevel;
78 | @property (nonatomic, assign) int32_t mbrank;
79 | @property (nonatomic, assign) int32_t star;
80 | @property (nonatomic, assign) int32_t level;
81 | @property (nonatomic, strong) NSDate *createdAt;
82 | @property (nonatomic, assign) BOOL allowAllActMsg;
83 | @property (nonatomic, assign) BOOL allowAllComment;
84 | @property (nonatomic, assign) BOOL geoEnabled;
85 | @property (nonatomic, assign) int32_t onlineStatus;
86 | @property (nonatomic, strong) NSString *location;
87 | @property (nonatomic, strong) NSArray *icons;
88 | @property (nonatomic, strong) NSString *weihao;
89 | @property (nonatomic, strong) NSString *badgeTop;
90 | @property (nonatomic, assign) int32_t blockWord;
91 | @property (nonatomic, assign) int32_t blockApp;
92 | @property (nonatomic, assign) int32_t hasAbilityTag;
93 | @property (nonatomic, assign) int32_t creditScore;
94 | @property (nonatomic, strong) NSDictionary *badge;
95 | @property (nonatomic, strong) NSString *lang;
96 | @property (nonatomic, assign) int32_t userAbility;
97 | @property (nonatomic, strong) NSDictionary *extend;
98 | @property (nonatomic, assign) BOOL verified;
99 | @property (nonatomic, assign) int32_t verifiedType;
100 | @property (nonatomic, assign) int32_t verifiedLevel;
101 | @property (nonatomic, assign) int32_t verifiedState;
102 | @property (nonatomic, strong) NSString *verifiedContactEmail;
103 | @property (nonatomic, strong) NSString *verifiedContactMobile;
104 | @property (nonatomic, strong) NSString *verifiedTrade;
105 | @property (nonatomic, strong) NSString *verifiedContactName;
106 | @property (nonatomic, strong) NSString *verifiedSource;
107 | @property (nonatomic, strong) NSString *verifiedSourceURL;
108 | @property (nonatomic, strong) NSString *verifiedReason;
109 | @property (nonatomic, strong) NSString *verifiedReasonURL;
110 | @property (nonatomic, strong) NSString *verifiedReasonModified;
111 | @end
112 |
113 | @interface MJWeiboStatus : NSObject
114 | @property (nonatomic, assign) uint64_t statusID;
115 | @property (nonatomic, strong) NSString *idstr;
116 | @property (nonatomic, strong) NSString *mid;
117 | @property (nonatomic, strong) NSString *rid;
118 | @property (nonatomic, strong) NSDate *createdAt;
119 | @property (nonatomic, strong) MJWeiboUser *user;
120 | @property (nonatomic, assign) int32_t userType;
121 | @property (nonatomic, strong) NSString *text;
122 | @property (nonatomic, strong) NSArray *picIds; /// Array
123 | @property (nonatomic, strong) NSDictionary *picInfos; /// Dic
124 | @property (nonatomic, strong) NSArray *urlStruct; ///< Array
125 | @property (nonatomic, assign) BOOL favorited;
126 | @property (nonatomic, assign) BOOL truncated;
127 | @property (nonatomic, assign) int32_t repostsCount;
128 | @property (nonatomic, assign) int32_t commentsCount;
129 | @property (nonatomic, assign) int32_t attitudesCount;
130 | @property (nonatomic, assign) int32_t attitudesStatus;
131 | @property (nonatomic, assign) int32_t recomState;
132 | @property (nonatomic, strong) NSString *inReplyToScreenName;
133 | @property (nonatomic, strong) NSString *inReplyToStatusId;
134 | @property (nonatomic, strong) NSString *inReplyToUserId;
135 | @property (nonatomic, strong) NSString *source;
136 | @property (nonatomic, assign) int32_t sourceType;
137 | @property (nonatomic, assign) int32_t sourceAllowClick;
138 | @property (nonatomic, strong) NSString *geo;
139 | @property (nonatomic, strong) NSArray *annotations;
140 | @property (nonatomic, assign) int32_t bizFeature;
141 | @property (nonatomic, assign) int32_t mlevel;
142 | @property (nonatomic, strong) NSString *mblogid;
143 | @property (nonatomic, strong) NSString *mblogTypeName;
144 | @property (nonatomic, assign) int32_t mblogType;
145 | @property (nonatomic, strong) NSString *scheme;
146 | @property (nonatomic, strong) NSDictionary *visible;
147 | @property (nonatomic, strong) NSArray *darwinTags;
148 | @end
149 |
--------------------------------------------------------------------------------
/Benchmark/ModelBenchmark/WeiboModel/MJWeiboModel.m:
--------------------------------------------------------------------------------
1 | //
2 | // MJWeiboModel.m
3 | // ModelBenchmark
4 | //
5 | // Created by ibireme on 15/9/18.
6 | // Copyright (c) 2015 ibireme. All rights reserved.
7 | //
8 |
9 | #import "MJWeiboModel.h"
10 | #import "DateFormatter.h"
11 |
12 | @implementation MJWeiboPictureMetadata
13 | MJExtensionCodingImplementation
14 | + (NSDictionary *)replacedKeyFromPropertyName {
15 | return @{@"cutType" : @"cut_type"};
16 | }
17 |
18 | @end
19 |
20 | @implementation MJWeiboPicture
21 | MJExtensionCodingImplementation
22 | + (NSDictionary *)mj_replacedKeyFromPropertyName {
23 | return @{@"picID" : @"pic_id",
24 | @"keepSize" : @"keep_size",
25 | @"photoTag" : @"photo_tag",
26 | @"objectID" : @"object_id",
27 | @"middlePlus" : @"middleplus"};
28 | }
29 |
30 | @end
31 |
32 | @implementation MJWeiboURL
33 | MJExtensionCodingImplementation
34 | + (NSDictionary *)mj_replacedKeyFromPropertyName {
35 | return @{@"oriURL" : @"ori_url",
36 | @"urlTitle" : @"url_title",
37 | @"urlTypePic" : @"url_type_pic",
38 | @"urlType" : @"url_type",
39 | @"shortURL" : @"short_url",
40 | @"actionLog" : @"actionlog",
41 | @"pageID" : @"page_id",
42 | @"storageType" : @"storage_type"};
43 | }
44 |
45 | @end
46 |
47 | @implementation MJWeiboUser
48 | MJExtensionCodingImplementation
49 | + (NSDictionary *)mj_replacedKeyFromPropertyName {
50 | return @{@"userID" : @"id",
51 | @"idString" : @"idstr",
52 | @"genderString" : @"gender",
53 | @"biFollowersCount" : @"bi_followers_count",
54 | @"profileImageURL" : @"profile_image_url",
55 | @"uclass" : @"class",
56 | @"verifiedContactEmail" : @"verified_contact_email",
57 | @"statusesCount" : @"statuses_count",
58 | @"geoEnabled" : @"geo_enabled",
59 | @"followMe" : @"follow_me",
60 | @"coverImagePhone" : @"cover_image_phone",
61 | @"desc" : @"description",
62 | @"followersCount" : @"followers_count",
63 | @"verifiedContactMobile" : @"verified_contact_mobile",
64 | @"avatarLarge" : @"avatar_large",
65 | @"verifiedTrade" : @"verified_trade",
66 | @"profileURL" : @"profile_url",
67 | @"coverImage" : @"cover_image",
68 | @"onlineStatus" : @"online_status",
69 | @"badgeTop" : @"badge_top",
70 | @"verifiedContactName" : @"verified_contact_name",
71 | @"screenName" : @"screen_name",
72 | @"verifiedSourceURL" : @"verified_source_url",
73 | @"pagefriendsCount" : @"pagefriends_count",
74 | @"verifiedReason" : @"verified_reason",
75 | @"friendsCount" : @"friends_count",
76 | @"blockApp" : @"block_app",
77 | @"hasAbilityTag" : @"has_ability_tag",
78 | @"avatarHD" : @"avatar_hd",
79 | @"creditScore" : @"credit_score",
80 | @"createdAt" : @"created_at",
81 | @"blockWord" : @"block_word",
82 | @"allowAllActMsg" : @"allow_all_act_msg",
83 | @"verifiedState" : @"verified_state",
84 | @"verifiedReasonModified" : @"verified_reason_modified",
85 | @"allowAllComment" : @"allow_all_comment",
86 | @"verifiedLevel" : @"verified_level",
87 | @"verifiedReasonURL" : @"verified_reason_url",
88 | @"favouritesCount" : @"favourites_count",
89 | @"verifiedType" : @"verified_type",
90 | @"verifiedSource" : @"verified_source",
91 | @"userAbility" : @"user_ability"};
92 | }
93 | - (id)mj_newValueFromOldValue:(id)oldValue property:(MJProperty *)property {
94 | if ([property.name isEqualToString:@"createdAt"]) {
95 | return [[DateFormatter weiboDataFormatter] dateFromString:oldValue];
96 | }
97 | return oldValue;
98 | }
99 | @end
100 |
101 | @implementation MJWeiboStatus
102 | MJExtensionCodingImplementation
103 | + (NSDictionary *)mj_replacedKeyFromPropertyName {
104 | return @{@"statusID" : @"id",
105 | @"createdAt" : @"created_at",
106 | @"attitudesStatus" : @"attitudes_status",
107 | @"inReplyToScreenName" : @"in_reply_to_screen_name",
108 | @"sourceType" : @"source_type",
109 | @"commentsCount" : @"comments_count",
110 | @"urlStruct" : @"url_struct",
111 | @"recomState" : @"recom_state",
112 | @"sourceAllowClick" : @"source_allowclick",
113 | @"bizFeature" : @"biz_feature",
114 | @"mblogTypeName" : @"mblogtypename",
115 | @"mblogType" : @"mblogtype",
116 | @"inReplyToStatusId" : @"in_reply_to_status_id",
117 | @"picIds" : @"pic_ids",
118 | @"repostsCount" : @"reposts_count",
119 | @"attitudesCount" : @"attitudes_count",
120 | @"darwinTags" : @"darwin_tags",
121 | @"userType" : @"userType",
122 | @"picInfos" : @"pic_infos",
123 | @"inReplyToUserId" : @"in_reply_to_user_id"};
124 | }
125 | + (NSDictionary *)mj_objectClassInArray {
126 | return @{@"picIds" : @"NSString",
127 | @"urlStruct" : @"MJWeiboURL"};
128 | }
129 | - (id)mj_newValueFromOldValue:(id)oldValue property:(MJProperty *)property {
130 | if ([property.name isEqualToString:@"createdAt"]) {
131 | if ([oldValue isKindOfClass:[NSString class]]) {
132 | return [[DateFormatter weiboDataFormatter] dateFromString:oldValue];
133 | }
134 | return nil;
135 | } else if ([property.name isEqualToString:@"picInfos"]) {
136 | if (!oldValue || oldValue == [NSNull null]) return nil;
137 | if (![oldValue isKindOfClass:[NSDictionary class]]) return nil;
138 | NSMutableDictionary *pics = [NSMutableDictionary new];
139 | [((NSDictionary *)oldValue) enumerateKeysAndObjectsUsingBlock:^(id key, NSDictionary *obj, BOOL *stop) {
140 | if ([obj isKindOfClass:[NSDictionary class]]) {
141 | MJWeiboPicture *pic = [MJWeiboPicture mj_objectWithKeyValues:obj];
142 | if (pic) pics[key] = pic;
143 | }
144 | }];
145 | return pics;
146 | }
147 | return oldValue;
148 | }
149 | @end
150 |
--------------------------------------------------------------------------------
/Benchmark/ModelBenchmark/WeiboModel/MTWeiboModel.h:
--------------------------------------------------------------------------------
1 | //
2 | // MTWeiboModel.h
3 | // ModelBenchmark
4 | //
5 | // Created by ibireme on 15/9/18.
6 | // Copyright (c) 2015 ibireme. All rights reserved.
7 | //
8 |
9 | #import "Mantle.h"
10 |
11 | @interface MTWeiboPictureMetadata : MTLModel
12 | @property (nonatomic, strong) NSString *url;
13 | @property (nonatomic, assign) int width;
14 | @property (nonatomic, assign) int height;
15 | @property (nonatomic, strong) NSString *type;
16 | @property (nonatomic, assign) int cutType;
17 | @end
18 |
19 | @interface MTWeiboPicture : MTLModel
20 | @property (nonatomic, strong) NSString *picID;
21 | @property (nonatomic, strong) NSString *objectID;
22 | @property (nonatomic, assign) int photoTag;
23 | @property (nonatomic, assign) BOOL keepSize;
24 | @property (nonatomic, strong) MTWeiboPictureMetadata *thumbnail;
25 | @property (nonatomic, strong) MTWeiboPictureMetadata *bmiddle;
26 | @property (nonatomic, strong) MTWeiboPictureMetadata *middlePlus;
27 | @property (nonatomic, strong) MTWeiboPictureMetadata *large;
28 | @property (nonatomic, strong) MTWeiboPictureMetadata *largest;
29 | @property (nonatomic, strong) MTWeiboPictureMetadata *original;
30 | @end
31 |
32 | @interface MTWeiboURL : MTLModel
33 | @property (nonatomic, assign) BOOL result;
34 | @property (nonatomic, strong) NSString *shortURL;
35 | @property (nonatomic, strong) NSString *oriURL;
36 | @property (nonatomic, strong) NSString *urlTitle;
37 | @property (nonatomic, strong) NSString *urlTypePic;
38 | @property (nonatomic, assign) int32_t urlType;
39 | @property (nonatomic, strong) NSString *log;
40 | @property (nonatomic, strong) NSDictionary *actionLog;
41 | @property (nonatomic, strong) NSString *pageID;
42 | @property (nonatomic, strong) NSString *storageType;
43 | @end
44 |
45 | @interface MTWeiboUser : MTLModel
46 | @property (nonatomic, assign) uint64_t userID;
47 | @property (nonatomic, strong) NSString *idString;
48 | @property (nonatomic, strong) NSString *genderString;
49 | @property (nonatomic, strong) NSString *desc;
50 | @property (nonatomic, strong) NSString *domain;
51 | @property (nonatomic, strong) NSString *name;
52 | @property (nonatomic, strong) NSString *screenName;
53 | @property (nonatomic, strong) NSString *remark;
54 | @property (nonatomic, assign) int32_t followersCount;
55 | @property (nonatomic, assign) int32_t friendsCount;
56 | @property (nonatomic, assign) int32_t biFollowersCount;
57 | @property (nonatomic, assign) int32_t favouritesCount;
58 | @property (nonatomic, assign) int32_t statusesCount;
59 | @property (nonatomic, assign) int32_t pagefriendsCount;
60 | @property (nonatomic, assign) BOOL followMe;
61 | @property (nonatomic, assign) BOOL following;
62 | @property (nonatomic, strong) NSString *province;
63 | @property (nonatomic, strong) NSString *city;
64 | @property (nonatomic, strong) NSString *url;
65 | @property (nonatomic, strong) NSString *profileImageURL;
66 | @property (nonatomic, strong) NSString *avatarLarge;
67 | @property (nonatomic, strong) NSString *avatarHD;
68 | @property (nonatomic, strong) NSString *coverImage;
69 | @property (nonatomic, strong) NSString *coverImagePhone;
70 | @property (nonatomic, strong) NSString *profileURL;
71 | @property (nonatomic, assign) int32_t type;
72 | @property (nonatomic, assign) int32_t ptype;
73 | @property (nonatomic, assign) int32_t mbtype;
74 | @property (nonatomic, assign) int32_t urank;
75 | @property (nonatomic, assign) int32_t uclass;
76 | @property (nonatomic, assign) int32_t ulevel;
77 | @property (nonatomic, assign) int32_t mbrank;
78 | @property (nonatomic, assign) int32_t star;
79 | @property (nonatomic, assign) int32_t level;
80 | @property (nonatomic, strong) NSDate *createdAt;
81 | @property (nonatomic, assign) BOOL allowAllActMsg;
82 | @property (nonatomic, assign) BOOL allowAllComment;
83 | @property (nonatomic, assign) BOOL geoEnabled;
84 | @property (nonatomic, assign) int32_t onlineStatus;
85 | @property (nonatomic, strong) NSString *location;
86 | @property (nonatomic, strong) NSArray *icons;
87 | @property (nonatomic, strong) NSString *weihao;
88 | @property (nonatomic, strong) NSString *badgeTop;
89 | @property (nonatomic, assign) int32_t blockWord;
90 | @property (nonatomic, assign) int32_t blockApp;
91 | @property (nonatomic, assign) int32_t hasAbilityTag;
92 | @property (nonatomic, assign) int32_t creditScore;
93 | @property (nonatomic, strong) NSDictionary *badge;
94 | @property (nonatomic, strong) NSString *lang;
95 | @property (nonatomic, assign) int32_t userAbility;
96 | @property (nonatomic, strong) NSDictionary *extend;
97 | @property (nonatomic, assign) BOOL verified;
98 | @property (nonatomic, assign) int32_t verifiedType;
99 | @property (nonatomic, assign) int32_t verifiedLevel;
100 | @property (nonatomic, assign) int32_t verifiedState;
101 | @property (nonatomic, strong) NSString *verifiedContactEmail;
102 | @property (nonatomic, strong) NSString *verifiedContactMobile;
103 | @property (nonatomic, strong) NSString *verifiedTrade;
104 | @property (nonatomic, strong) NSString *verifiedContactName;
105 | @property (nonatomic, strong) NSString *verifiedSource;
106 | @property (nonatomic, strong) NSString *verifiedSourceURL;
107 | @property (nonatomic, strong) NSString *verifiedReason;
108 | @property (nonatomic, strong) NSString *verifiedReasonURL;
109 | @property (nonatomic, strong) NSString *verifiedReasonModified;
110 | @end
111 |
112 | @interface MTWeiboStatus : MTLModel
113 | @property (nonatomic, assign) uint64_t statusID;
114 | @property (nonatomic, strong) NSString *idstr;
115 | @property (nonatomic, strong) NSString *mid;
116 | @property (nonatomic, strong) NSString *rid;
117 | @property (nonatomic, strong) NSDate *createdAt;
118 | @property (nonatomic, strong) MTWeiboUser *user;
119 | @property (nonatomic, assign) int32_t userType;
120 | @property (nonatomic, strong) NSString *text;
121 | @property (nonatomic, strong) NSArray *picIds; /// Array
122 | @property (nonatomic, strong) NSDictionary *picInfos; /// Dic
123 | @property (nonatomic, strong) NSArray *urlStruct; ///< Array
124 | @property (nonatomic, assign) BOOL favorited;
125 | @property (nonatomic, assign) BOOL truncated;
126 | @property (nonatomic, assign) int32_t repostsCount;
127 | @property (nonatomic, assign) int32_t commentsCount;
128 | @property (nonatomic, assign) int32_t attitudesCount;
129 | @property (nonatomic, assign) int32_t attitudesStatus;
130 | @property (nonatomic, assign) int32_t recomState;
131 | @property (nonatomic, strong) NSString *inReplyToScreenName;
132 | @property (nonatomic, strong) NSString *inReplyToStatusId;
133 | @property (nonatomic, strong) NSString *inReplyToUserId;
134 | @property (nonatomic, strong) NSString *source;
135 | @property (nonatomic, assign) int32_t sourceType;
136 | @property (nonatomic, assign) int32_t sourceAllowClick;
137 | @property (nonatomic, strong) NSString *geo;
138 | @property (nonatomic, strong) NSArray *annotations;
139 | @property (nonatomic, assign) int32_t bizFeature;
140 | @property (nonatomic, assign) int32_t mlevel;
141 | @property (nonatomic, strong) NSString *mblogid;
142 | @property (nonatomic, strong) NSString *mblogTypeName;
143 | @property (nonatomic, assign) int32_t mblogType;
144 | @property (nonatomic, strong) NSString *scheme;
145 | @property (nonatomic, strong) NSDictionary *visible;
146 | @property (nonatomic, strong) NSArray *darwinTags;
147 | @end
148 |
--------------------------------------------------------------------------------
/Benchmark/ModelBenchmark/WeiboModel/MTWeiboModel.m:
--------------------------------------------------------------------------------
1 | //
2 | // MTWeiboModel.m
3 | // ModelBenchmark
4 | //
5 | // Created by ibireme on 15/9/18.
6 | // Copyright (c) 2015 ibireme. All rights reserved.
7 | //
8 |
9 | #import "MTWeiboModel.h"
10 | #import "DateFormatter.h"
11 |
12 | @implementation MTWeiboPictureMetadata
13 | + (NSDictionary *)JSONKeyPathsByPropertyKey {
14 | return @{@"url" : @"url",
15 | @"width" : @"width",
16 | @"height" : @"height",
17 | @"type" : @"type",
18 | @"cutType" : @"cut_type"};
19 | }
20 | + (NSValueTransformer *)widthJSONTransformer {
21 | return [MTLValueTransformer transformerUsingForwardBlock:^id(NSNumber *num, BOOL *success, NSError *__autoreleasing *error) {
22 | if ([num isKindOfClass:[NSString class]]) {
23 | num = @([((NSString *)num) integerValue]);
24 | }
25 | return num;
26 | } reverseBlock:^id(NSNumber *num, BOOL *success, NSError *__autoreleasing *error) {
27 | return num;
28 | }];
29 | return [MTLJSONAdapter dictionaryTransformerWithModelClass:MTWeiboPicture.class];
30 | }
31 | + (NSValueTransformer *)heightJSONTransformer {
32 | return [MTLValueTransformer transformerUsingForwardBlock:^id(NSNumber *num, BOOL *success, NSError *__autoreleasing *error) {
33 | if ([num isKindOfClass:[NSString class]]) {
34 | num = @([((NSString *)num) integerValue]);
35 | }
36 | return num;
37 | } reverseBlock:^id(NSNumber *num, BOOL *success, NSError *__autoreleasing *error) {
38 | return num;
39 | }];
40 | return [MTLJSONAdapter dictionaryTransformerWithModelClass:MTWeiboPicture.class];
41 | }
42 | @end
43 |
44 | @implementation MTWeiboPicture
45 | + (NSDictionary *)JSONKeyPathsByPropertyKey {
46 | return @{@"picID" : @"pic_id",
47 | @"keepSize" : @"keep_size",
48 | @"photoTag" : @"photo_tag",
49 | @"objectID" : @"object_id",
50 | @"thumbnail" : @"thumbnail",
51 | @"bmiddle" : @"bmiddle",
52 | @"middlePlus" : @"middleplus",
53 | @"large" : @"large",
54 | @"largest" : @"largest",
55 | @"original" : @"original"};
56 | }
57 | @end
58 |
59 | @implementation MTWeiboURL
60 | + (NSDictionary *)JSONKeyPathsByPropertyKey {
61 | return @{@"result" : @"result",
62 | @"log" : @"log",
63 | @"oriURL" : @"ori_url",
64 | @"urlTitle" : @"url_title",
65 | @"urlTypePic" : @"url_type_pic",
66 | @"urlType" : @"url_type",
67 | @"shortURL" : @"short_url",
68 | @"actionLog" : @"actionlog",
69 | @"pageID" : @"page_id",
70 | @"storageType" : @"storage_type"};
71 | }
72 | @end
73 |
74 | @implementation MTWeiboUser
75 | + (NSDictionary *)JSONKeyPathsByPropertyKey {
76 | return @{@"userID" : @"id",
77 | @"idString" : @"idstr",
78 | @"genderString" : @"gender",
79 | @"desc" : @"description",
80 | @"domain" : @"domain",
81 | @"name" : @"name",
82 | @"screenName" : @"screen_name",
83 | @"remark" : @"remark",
84 | @"followersCount" : @"followers_count",
85 | @"friendsCount" : @"friends_count",
86 | @"biFollowersCount" : @"bi_followers_count",
87 | @"favouritesCount" : @"favourites_count",
88 | @"statusesCount" : @"statuses_count",
89 | @"pagefriendsCount" : @"pagefriends_count",
90 | @"followMe" : @"follow_me",
91 | @"following" : @"following",
92 | @"province" : @"province",
93 | @"city" : @"city",
94 | @"url" : @"url",
95 | @"profileImageURL" : @"profile_image_url",
96 | @"avatarLarge" : @"avatar_large",
97 | @"avatarHD" : @"avatar_hd",
98 | @"coverImage" : @"cover_image",
99 | @"coverImagePhone" : @"cover_image_phone",
100 | @"profileURL" : @"profile_url",
101 | @"type" : @"type",
102 | @"ptype" : @"ptype",
103 | @"mbtype" : @"mbtype",
104 | @"urank" : @"urank",
105 | @"uclass" : @"class",
106 | @"ulevel" : @"ulevel",
107 | @"mbrank" : @"mbrank",
108 | @"star" : @"star",
109 | @"level" : @"level",
110 | @"createdAt" : @"created_at",
111 | @"allowAllActMsg" : @"allow_all_act_msg",
112 | @"allowAllComment" : @"allow_all_comment",
113 | @"geoEnabled" : @"geo_enabled",
114 | @"onlineStatus" : @"online_status",
115 | @"location" : @"location",
116 | @"icons" : @"icons",
117 | @"weihao" : @"weihao",
118 | @"badgeTop" : @"badge_top",
119 | @"blockWord" : @"block_word",
120 | @"blockApp" : @"block_app",
121 | @"hasAbilityTag" : @"has_ability_tag",
122 | @"creditScore" : @"credit_score",
123 | @"badge" : @"badge",
124 | @"lang" : @"lang",
125 | @"userAbility" : @"user_ability",
126 | @"extend" : @"extend",
127 | @"verified" : @"verified",
128 | @"verifiedType" : @"verified_type",
129 | @"verifiedLevel" : @"verified_level",
130 | @"verifiedState" : @"verified_state",
131 | @"verifiedContactEmail" : @"verified_contact_email",
132 | @"verifiedContactMobile" : @"verified_contact_mobile",
133 | @"verifiedTrade" : @"verified_trade",
134 | @"verifiedContactName" : @"verified_contact_name",
135 | @"verifiedSource" : @"verified_source",
136 | @"verifiedSourceURL" : @"verified_source_url",
137 | @"verifiedReason" : @"verified_reason",
138 | @"verifiedReasonURL" : @"verified_reason_url",
139 | @"verifiedReasonModified" : @"verified_reason_modified"};
140 | }
141 | + (NSValueTransformer *)createdAtJSONTransformer {
142 | return [MTLValueTransformer transformerUsingForwardBlock:^id(NSString *dateString, BOOL *success, NSError *__autoreleasing *error) {
143 | return [[DateFormatter weiboDataFormatter] dateFromString:dateString];
144 | } reverseBlock:^id(NSDate *date, BOOL *success, NSError *__autoreleasing *error) {
145 | return [[DateFormatter weiboDataFormatter] stringFromDate:date];
146 | }];
147 | }
148 | @end
149 |
150 | @implementation MTWeiboStatus
151 | + (NSDictionary *)JSONKeyPathsByPropertyKey {
152 | return @{@"statusID" : @"id",
153 | @"idstr" : @"idstr",
154 | @"mid" : @"mid",
155 | @"rid" : @"rid",
156 | @"createdAt" : @"created_at",
157 | @"user" : @"user",
158 | @"userType" : @"userType",
159 | @"text" : @"text",
160 | @"picIds" : @"pic_ids",
161 | @"picInfos" : @"pic_infos",
162 | @"urlStruct" : @"url_struct",
163 | @"favorited" : @"favorited",
164 | @"truncated" : @"truncated",
165 | @"repostsCount" : @"reposts_count",
166 | @"commentsCount" : @"comments_count",
167 | @"attitudesCount" : @"attitudes_count",
168 | @"attitudesStatus" : @"attitudes_status",
169 | @"recomState" : @"recom_state",
170 | @"inReplyToScreenName" : @"in_reply_to_screen_name",
171 | @"inReplyToStatusId" : @"in_reply_to_status_id",
172 | @"inReplyToUserId" : @"in_reply_to_user_id",
173 | @"source" : @"source",
174 | @"sourceType" : @"source_type",
175 | @"sourceAllowClick" : @"source_allowclick",
176 | @"geo" : @"geo",
177 | @"annotations" : @"annotations",
178 | @"bizFeature" : @"biz_feature",
179 | @"mblogid" : @"mblogid",
180 | @"mblogTypeName" : @"mblogtypename",
181 | @"mblogType" : @"mblogtype",
182 | @"scheme" : @"scheme",
183 | @"visible" : @"visible",
184 | @"darwinTags" : @"darwin_tags"};
185 | }
186 | + (NSValueTransformer *)picInfosJSONTransformer {
187 | static MTLJSONAdapter *pictureAdapter;
188 | static dispatch_once_t onceToken;
189 | dispatch_once(&onceToken, ^{
190 | pictureAdapter = [[MTLJSONAdapter alloc] initWithModelClass:[MTWeiboPicture class]];
191 | });
192 |
193 | return [MTLValueTransformer transformerUsingForwardBlock:^id(NSDictionary *dic, BOOL *success, NSError *__autoreleasing *error) {
194 | NSMutableDictionary *pics = [NSMutableDictionary new];
195 | [dic enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
196 | MTWeiboPicture *pic = [pictureAdapter modelFromJSONDictionary:obj error:nil];
197 | if (pic) pics[key] = pic;
198 | }];
199 | return pics;
200 | } reverseBlock:^id(NSDictionary *dic, BOOL *success, NSError *__autoreleasing *error) {
201 | NSMutableDictionary *ret = [NSMutableDictionary new];
202 | [dic enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
203 | if ([obj isKindOfClass:[MTWeiboPicture class]]) {
204 | NSDictionary *one = [pictureAdapter JSONDictionaryFromModel:obj error:nil];
205 | if (one) ret[key] = one;
206 | }
207 | }];
208 | return ret;
209 | }];
210 | return [MTLJSONAdapter dictionaryTransformerWithModelClass:MTWeiboPicture.class];
211 | }
212 | + (NSValueTransformer *)urlStructJSONTransformer {
213 | return [MTLJSONAdapter arrayTransformerWithModelClass:MTWeiboURL.class];
214 | }
215 | + (NSValueTransformer *)createdAtJSONTransformer {
216 | return [MTLValueTransformer transformerUsingForwardBlock:^id(NSString *dateString, BOOL *success, NSError *__autoreleasing *error) {
217 | return [[DateFormatter weiboDataFormatter] dateFromString:dateString];
218 | } reverseBlock:^id(NSDate *date, BOOL *success, NSError *__autoreleasing *error) {
219 | return [[DateFormatter weiboDataFormatter] stringFromDate:date];
220 | }];
221 | }
222 | @end
223 |
224 |
--------------------------------------------------------------------------------
/Benchmark/ModelBenchmark/WeiboModel/YYWeiboModel.h:
--------------------------------------------------------------------------------
1 | //
2 | // WBModel.h
3 | // ModelBenchmark
4 | //
5 | // Created by ibireme on 15/9/18.
6 | // Copyright (c) 2015 ibireme. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface YYWeiboPictureMetadata : NSObject
12 | @property (nonatomic, strong) NSString *url;
13 | @property (nonatomic, assign) int width;
14 | @property (nonatomic, assign) int height;
15 | @property (nonatomic, strong) NSString *type;
16 | @property (nonatomic, assign) int cutType;
17 | @end
18 |
19 | @interface YYWeiboPicture : NSObject
20 | @property (nonatomic, strong) NSString *picID;
21 | @property (nonatomic, strong) NSString *objectID;
22 | @property (nonatomic, assign) int photoTag;
23 | @property (nonatomic, assign) BOOL keepSize;
24 | @property (nonatomic, strong) YYWeiboPictureMetadata *thumbnail;
25 | @property (nonatomic, strong) YYWeiboPictureMetadata *bmiddle;
26 | @property (nonatomic, strong) YYWeiboPictureMetadata *middlePlus;
27 | @property (nonatomic, strong) YYWeiboPictureMetadata *large;
28 | @property (nonatomic, strong) YYWeiboPictureMetadata *largest;
29 | @property (nonatomic, strong) YYWeiboPictureMetadata *original;
30 | @end
31 |
32 | @interface YYWeiboURL : NSObject
33 | @property (nonatomic, assign) BOOL result;
34 | @property (nonatomic, strong) NSString *shortURL;
35 | @property (nonatomic, strong) NSString *oriURL;
36 | @property (nonatomic, strong) NSString *urlTitle;
37 | @property (nonatomic, strong) NSString *urlTypePic;
38 | @property (nonatomic, assign) int32_t urlType;
39 | @property (nonatomic, strong) NSString *log;
40 | @property (nonatomic, strong) NSDictionary *actionLog;
41 | @property (nonatomic, strong) NSString *pageID;
42 | @property (nonatomic, strong) NSString *storageType;
43 | @end
44 |
45 | @interface YYWeiboUser : NSObject
46 | @property (nonatomic, assign) uint64_t userID;
47 | @property (nonatomic, strong) NSString *idString;
48 | @property (nonatomic, strong) NSString *genderString;
49 | @property (nonatomic, strong) NSString *desc;
50 | @property (nonatomic, strong) NSString *domain;
51 | @property (nonatomic, strong) NSString *name;
52 | @property (nonatomic, strong) NSString *screenName;
53 | @property (nonatomic, strong) NSString *remark;
54 | @property (nonatomic, assign) int32_t followersCount;
55 | @property (nonatomic, assign) int32_t friendsCount;
56 | @property (nonatomic, assign) int32_t biFollowersCount;
57 | @property (nonatomic, assign) int32_t favouritesCount;
58 | @property (nonatomic, assign) int32_t statusesCount;
59 | @property (nonatomic, assign) int32_t pagefriendsCount;
60 | @property (nonatomic, assign) BOOL followMe;
61 | @property (nonatomic, assign) BOOL following;
62 | @property (nonatomic, strong) NSString *province;
63 | @property (nonatomic, strong) NSString *city;
64 | @property (nonatomic, strong) NSString *url;
65 | @property (nonatomic, strong) NSString *profileImageURL;
66 | @property (nonatomic, strong) NSString *avatarLarge;
67 | @property (nonatomic, strong) NSString *avatarHD;
68 | @property (nonatomic, strong) NSString *coverImage;
69 | @property (nonatomic, strong) NSString *coverImagePhone;
70 | @property (nonatomic, strong) NSString *profileURL;
71 | @property (nonatomic, assign) int32_t type;
72 | @property (nonatomic, assign) int32_t ptype;
73 | @property (nonatomic, assign) int32_t mbtype;
74 | @property (nonatomic, assign) int32_t urank;
75 | @property (nonatomic, assign) int32_t uclass;
76 | @property (nonatomic, assign) int32_t ulevel;
77 | @property (nonatomic, assign) int32_t mbrank;
78 | @property (nonatomic, assign) int32_t star;
79 | @property (nonatomic, assign) int32_t level;
80 | @property (nonatomic, strong) NSDate *createdAt;
81 | @property (nonatomic, assign) BOOL allowAllActMsg;
82 | @property (nonatomic, assign) BOOL allowAllComment;
83 | @property (nonatomic, assign) BOOL geoEnabled;
84 | @property (nonatomic, assign) int32_t onlineStatus;
85 | @property (nonatomic, strong) NSString *location;
86 | @property (nonatomic, strong) NSArray *icons;
87 | @property (nonatomic, strong) NSString *weihao;
88 | @property (nonatomic, strong) NSString *badgeTop;
89 | @property (nonatomic, assign) int32_t blockWord;
90 | @property (nonatomic, assign) int32_t blockApp;
91 | @property (nonatomic, assign) int32_t hasAbilityTag;
92 | @property (nonatomic, assign) int32_t creditScore;
93 | @property (nonatomic, strong) NSDictionary *badge;
94 | @property (nonatomic, strong) NSString *lang;
95 | @property (nonatomic, assign) int32_t userAbility;
96 | @property (nonatomic, strong) NSDictionary *extend;
97 | @property (nonatomic, assign) BOOL verified;
98 | @property (nonatomic, assign) int32_t verifiedType;
99 | @property (nonatomic, assign) int32_t verifiedLevel;
100 | @property (nonatomic, assign) int32_t verifiedState;
101 | @property (nonatomic, strong) NSString *verifiedContactEmail;
102 | @property (nonatomic, strong) NSString *verifiedContactMobile;
103 | @property (nonatomic, strong) NSString *verifiedTrade;
104 | @property (nonatomic, strong) NSString *verifiedContactName;
105 | @property (nonatomic, strong) NSString *verifiedSource;
106 | @property (nonatomic, strong) NSString *verifiedSourceURL;
107 | @property (nonatomic, strong) NSString *verifiedReason;
108 | @property (nonatomic, strong) NSString *verifiedReasonURL;
109 | @property (nonatomic, strong) NSString *verifiedReasonModified;
110 | @end
111 |
112 | @interface YYWeiboStatus : NSObject
113 | @property (nonatomic, assign) uint64_t statusID;
114 | @property (nonatomic, strong) NSString *idstr;
115 | @property (nonatomic, strong) NSString *mid;
116 | @property (nonatomic, strong) NSString *rid;
117 | @property (nonatomic, strong) NSDate *createdAt;
118 | @property (nonatomic, strong) YYWeiboUser *user;
119 | @property (nonatomic, assign) int32_t userType;
120 | @property (nonatomic, strong) NSString *text;
121 | @property (nonatomic, strong) NSArray *picIds; /// Array
122 | @property (nonatomic, strong) NSDictionary *picInfos; /// Dic
123 | @property (nonatomic, strong) NSArray *urlStruct; ///< Array
124 | @property (nonatomic, assign) BOOL favorited;
125 | @property (nonatomic, assign) BOOL truncated;
126 | @property (nonatomic, assign) int32_t repostsCount;
127 | @property (nonatomic, assign) int32_t commentsCount;
128 | @property (nonatomic, assign) int32_t attitudesCount;
129 | @property (nonatomic, assign) int32_t attitudesStatus;
130 | @property (nonatomic, assign) int32_t recomState;
131 | @property (nonatomic, strong) NSString *inReplyToScreenName;
132 | @property (nonatomic, strong) NSString *inReplyToStatusId;
133 | @property (nonatomic, strong) NSString *inReplyToUserId;
134 | @property (nonatomic, strong) NSString *source;
135 | @property (nonatomic, assign) int32_t sourceType;
136 | @property (nonatomic, assign) int32_t sourceAllowClick;
137 | @property (nonatomic, strong) NSString *geo;
138 | @property (nonatomic, strong) NSArray *annotations;
139 | @property (nonatomic, assign) int32_t bizFeature;
140 | @property (nonatomic, assign) int32_t mlevel;
141 | @property (nonatomic, strong) NSString *mblogid;
142 | @property (nonatomic, strong) NSString *mblogTypeName;
143 | @property (nonatomic, assign) int32_t mblogType;
144 | @property (nonatomic, strong) NSString *scheme;
145 | @property (nonatomic, strong) NSDictionary *visible;
146 | @property (nonatomic, strong) NSArray *darwinTags;
147 | @end
148 |
--------------------------------------------------------------------------------
/Benchmark/ModelBenchmark/WeiboModel/YYWeiboModel.m:
--------------------------------------------------------------------------------
1 | //
2 | // WBModel.m
3 | // ModelBenchmark
4 | //
5 | // Created by ibireme on 15/9/18.
6 | // Copyright (c) 2015 ibireme. All rights reserved.
7 | //
8 |
9 | #import "YYWeiboModel.h"
10 |
11 | #define YYModelSynthCoderAndHash \
12 | - (void)encodeWithCoder:(NSCoder *)aCoder { [self yy_modelEncodeWithCoder:aCoder]; } \
13 | - (id)initWithCoder:(NSCoder *)aDecoder { return [self yy_modelInitWithCoder:aDecoder]; } \
14 | - (id)copyWithZone:(NSZone *)zone { return [self yy_modelCopy]; } \
15 | - (NSUInteger)hash { return [self yy_modelHash]; } \
16 | - (BOOL)isEqual:(id)object { return [self yy_modelIsEqual:object]; }
17 |
18 |
19 | @implementation YYWeiboPictureMetadata
20 | + (NSDictionary *)modelCustomPropertyMapper {
21 | return @{@"cutType" : @"cut_type"};
22 | }
23 | YYModelSynthCoderAndHash
24 | @end
25 |
26 | @implementation YYWeiboPicture
27 | + (NSDictionary *)modelCustomPropertyMapper {
28 | return @{@"picID" : @"pic_id",
29 | @"keepSize" : @"keep_size",
30 | @"photoTag" : @"photo_tag",
31 | @"objectID" : @"object_id",
32 | @"middlePlus" : @"middleplus"};
33 | }
34 | YYModelSynthCoderAndHash
35 | @end
36 |
37 | @implementation YYWeiboURL
38 | + (NSDictionary *)modelCustomPropertyMapper {
39 | return @{@"oriURL" : @"ori_url",
40 | @"urlTitle" : @"url_title",
41 | @"urlTypePic" : @"url_type_pic",
42 | @"urlType" : @"url_type",
43 | @"shortURL" : @"short_url",
44 | @"actionLog" : @"actionlog",
45 | @"pageID" : @"page_id",
46 | @"storageType" : @"storage_type"};
47 | }
48 | YYModelSynthCoderAndHash
49 | @end
50 |
51 | @implementation YYWeiboUser
52 | + (NSDictionary *)modelCustomPropertyMapper {
53 | return @{@"userID" : @"id",
54 | @"idString" : @"idstr",
55 | @"genderString" : @"gender",
56 | @"biFollowersCount" : @"bi_followers_count",
57 | @"profileImageURL" : @"profile_image_url",
58 | @"uclass" : @"class",
59 | @"verifiedContactEmail" : @"verified_contact_email",
60 | @"statusesCount" : @"statuses_count",
61 | @"geoEnabled" : @"geo_enabled",
62 | @"followMe" : @"follow_me",
63 | @"coverImagePhone" : @"cover_image_phone",
64 | @"desc" : @"description",
65 | @"followersCount" : @"followers_count",
66 | @"verifiedContactMobile" : @"verified_contact_mobile",
67 | @"avatarLarge" : @"avatar_large",
68 | @"verifiedTrade" : @"verified_trade",
69 | @"profileURL" : @"profile_url",
70 | @"coverImage" : @"cover_image",
71 | @"onlineStatus" : @"online_status",
72 | @"badgeTop" : @"badge_top",
73 | @"verifiedContactName" : @"verified_contact_name",
74 | @"screenName" : @"screen_name",
75 | @"verifiedSourceURL" : @"verified_source_url",
76 | @"pagefriendsCount" : @"pagefriends_count",
77 | @"verifiedReason" : @"verified_reason",
78 | @"friendsCount" : @"friends_count",
79 | @"blockApp" : @"block_app",
80 | @"hasAbilityTag" : @"has_ability_tag",
81 | @"avatarHD" : @"avatar_hd",
82 | @"creditScore" : @"credit_score",
83 | @"createdAt" : @"created_at",
84 | @"blockWord" : @"block_word",
85 | @"allowAllActMsg" : @"allow_all_act_msg",
86 | @"verifiedState" : @"verified_state",
87 | @"verifiedReasonModified" : @"verified_reason_modified",
88 | @"allowAllComment" : @"allow_all_comment",
89 | @"verifiedLevel" : @"verified_level",
90 | @"verifiedReasonURL" : @"verified_reason_url",
91 | @"favouritesCount" : @"favourites_count",
92 | @"verifiedType" : @"verified_type",
93 | @"verifiedSource" : @"verified_source",
94 | @"userAbility" : @"user_ability"};
95 | }
96 | YYModelSynthCoderAndHash
97 | @end
98 |
99 | @implementation YYWeiboStatus
100 | + (NSDictionary *)modelCustomPropertyMapper {
101 | return @{@"statusID" : @"id",
102 | @"createdAt" : @"created_at",
103 | @"attitudesStatus" : @"attitudes_status",
104 | @"inReplyToScreenName" : @"in_reply_to_screen_name",
105 | @"sourceType" : @"source_type",
106 | @"commentsCount" : @"comments_count",
107 | @"recomState" : @"recom_state",
108 | @"urlStruct" : @"url_struct",
109 | @"sourceAllowClick" : @"source_allowclick",
110 | @"bizFeature" : @"biz_feature",
111 | @"mblogTypeName" : @"mblogtypename",
112 | @"mblogType" : @"mblogtype",
113 | @"inReplyToStatusId" : @"in_reply_to_status_id",
114 | @"picIds" : @"pic_ids",
115 | @"repostsCount" : @"reposts_count",
116 | @"attitudesCount" : @"attitudes_count",
117 | @"darwinTags" : @"darwin_tags",
118 | @"userType" : @"userType",
119 | @"picInfos" : @"pic_infos",
120 | @"inReplyToUserId" : @"in_reply_to_user_id"};
121 | }
122 | + (NSDictionary *)modelContainerPropertyGenericClass {
123 | return @{@"picIds" : [NSString class],
124 | @"picInfos" : [YYWeiboPicture class],
125 | @"urlStruct" : [YYWeiboURL class]};
126 | }
127 | YYModelSynthCoderAndHash
128 | @end
129 |
--------------------------------------------------------------------------------
/Benchmark/ModelBenchmark/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // ModelBenchmark
4 | //
5 | // Created by ibireme on 15/9/18.
6 | // Copyright (c) 2015 ibireme. 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 |
--------------------------------------------------------------------------------
/Benchmark/Podfile:
--------------------------------------------------------------------------------
1 | platform :ios, '8.0'
2 | use_frameworks!
3 |
4 | target 'ModelBenchmark' do
5 |
6 | # Objective-C
7 | pod 'FastEasyMapping'
8 | pod 'JSONModel'
9 | pod 'Mantle'
10 | pod 'MJExtension'
11 | pod 'YYModel'
12 |
13 | # Swift
14 | pod 'Argo'
15 | pod 'Gloss'
16 | pod 'HandyJSON'
17 | pod 'ObjectMapper'
18 | pod 'SwiftyJSON'
19 |
20 | # Generator
21 | # https://github.com/Ahmed-Ali/JSONExport
22 | # https://github.com/nixzhu/Coolie
23 | # https://github.com/johnlui/JSONNeverDie
24 |
25 | end
26 |
27 |
28 |
--------------------------------------------------------------------------------
/Benchmark/Result.numbers:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ibireme/YYModel/1230e605c1abdcd34bf0adb371d89783ff39a856/Benchmark/Result.numbers
--------------------------------------------------------------------------------
/Benchmark/Result.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ibireme/YYModel/1230e605c1abdcd34bf0adb371d89783ff39a856/Benchmark/Result.png
--------------------------------------------------------------------------------
/Framework/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.4
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | NSPrincipalClass
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Framework/YYModel.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Framework/YYModel.xcodeproj/xcshareddata/xcschemes/YYModel.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
34 |
40 |
41 |
42 |
43 |
44 |
50 |
51 |
52 |
53 |
54 |
55 |
65 |
66 |
72 |
73 |
74 |
75 |
76 |
77 |
83 |
84 |
90 |
91 |
92 |
93 |
95 |
96 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 ibireme
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 |
--------------------------------------------------------------------------------
/YYModel.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = 'YYModel'
3 | s.summary = 'High performance model framework for iOS/OSX.'
4 | s.version = '1.0.4'
5 | s.license = { :type => 'MIT', :file => 'LICENSE' }
6 | s.authors = { 'ibireme' => 'ibireme@gmail.com' }
7 | s.social_media_url = 'http://blog.ibireme.com'
8 | s.homepage = 'https://github.com/ibireme/YYModel'
9 |
10 | s.ios.deployment_target = '6.0'
11 | s.osx.deployment_target = '10.7'
12 | s.watchos.deployment_target = '2.0'
13 | s.tvos.deployment_target = '9.0'
14 |
15 | s.source = { :git => 'https://github.com/ibireme/YYModel.git', :tag => s.version.to_s }
16 |
17 | s.requires_arc = true
18 | s.source_files = 'YYModel/*.{h,m}'
19 | s.public_header_files = 'YYModel/*.{h}'
20 |
21 | s.frameworks = 'Foundation', 'CoreFoundation'
22 |
23 | end
24 |
--------------------------------------------------------------------------------
/YYModel/NSObject+YYModel.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+YYModel.h
3 | // YYModel
4 | //
5 | // Created by ibireme on 15/5/10.
6 | // Copyright (c) 2015 ibireme.
7 | //
8 | // This source code is licensed under the MIT-style license found in the
9 | // LICENSE file in the root directory of this source tree.
10 | //
11 |
12 | #import
13 |
14 | NS_ASSUME_NONNULL_BEGIN
15 |
16 | /**
17 | Provide some data-model method:
18 |
19 | * Convert json to any object, or convert any object to json.
20 | * Set object properties with a key-value dictionary (like KVC).
21 | * Implementations of `NSCoding`, `NSCopying`, `-hash` and `-isEqual:`.
22 |
23 | See `YYModel` protocol for custom methods.
24 |
25 |
26 | Sample Code:
27 |
28 | ********************** json convertor *********************
29 | @code
30 | @interface YYAuthor : NSObject
31 | @property (nonatomic, strong) NSString *name;
32 | @property (nonatomic, assign) NSDate *birthday;
33 | @end
34 | @implementation YYAuthor
35 | @end
36 |
37 | @interface YYBook : NSObject
38 | @property (nonatomic, copy) NSString *name;
39 | @property (nonatomic, assign) NSUInteger pages;
40 | @property (nonatomic, strong) YYAuthor *author;
41 | @end
42 | @implementation YYBook
43 | @end
44 |
45 | int main() {
46 | // create model from json
47 | YYBook *book = [YYBook yy_modelWithJSON:@"{\"name\": \"Harry Potter\", \"pages\": 256, \"author\": {\"name\": \"J.K.Rowling\", \"birthday\": \"1965-07-31\" }}"];
48 |
49 | // convert model to json
50 | NSString *json = [book yy_modelToJSONString];
51 | // {"author":{"name":"J.K.Rowling","birthday":"1965-07-31T00:00:00+0000"},"name":"Harry Potter","pages":256}
52 | }
53 | @endcode
54 |
55 | ********************** Coding/Copying/hash/equal *********************
56 | @code
57 | @interface YYShadow :NSObject
58 | @property (nonatomic, copy) NSString *name;
59 | @property (nonatomic, assign) CGSize size;
60 | @end
61 |
62 | @implementation YYShadow
63 | - (void)encodeWithCoder:(NSCoder *)aCoder { [self yy_modelEncodeWithCoder:aCoder]; }
64 | - (id)initWithCoder:(NSCoder *)aDecoder { self = [super init]; return [self yy_modelInitWithCoder:aDecoder]; }
65 | - (id)copyWithZone:(NSZone *)zone { return [self yy_modelCopy]; }
66 | - (NSUInteger)hash { return [self yy_modelHash]; }
67 | - (BOOL)isEqual:(id)object { return [self yy_modelIsEqual:object]; }
68 | @end
69 | @endcode
70 |
71 | */
72 | @interface NSObject (YYModel)
73 |
74 | /**
75 | Creates and returns a new instance of the receiver from a json.
76 | This method is thread-safe.
77 |
78 | @param json A json object in `NSDictionary`, `NSString` or `NSData`.
79 |
80 | @return A new instance created from the json, or nil if an error occurs.
81 | */
82 | + (nullable instancetype)yy_modelWithJSON:(id)json;
83 |
84 | /**
85 | Creates and returns a new instance of the receiver from a key-value dictionary.
86 | This method is thread-safe.
87 |
88 | @param dictionary A key-value dictionary mapped to the instance's properties.
89 | Any invalid key-value pair in dictionary will be ignored.
90 |
91 | @return A new instance created from the dictionary, or nil if an error occurs.
92 |
93 | @discussion The key in `dictionary` will mapped to the reciever's property name,
94 | and the value will set to the property. If the value's type does not match the
95 | property, this method will try to convert the value based on these rules:
96 |
97 | `NSString` or `NSNumber` -> c number, such as BOOL, int, long, float, NSUInteger...
98 | `NSString` -> NSDate, parsed with format "yyyy-MM-dd'T'HH:mm:ssZ", "yyyy-MM-dd HH:mm:ss" or "yyyy-MM-dd".
99 | `NSString` -> NSURL.
100 | `NSValue` -> struct or union, such as CGRect, CGSize, ...
101 | `NSString` -> SEL, Class.
102 | */
103 | + (nullable instancetype)yy_modelWithDictionary:(NSDictionary *)dictionary;
104 |
105 | /**
106 | Set the receiver's properties with a json object.
107 |
108 | @discussion Any invalid data in json will be ignored.
109 |
110 | @param json A json object of `NSDictionary`, `NSString` or `NSData`, mapped to the
111 | receiver's properties.
112 |
113 | @return Whether succeed.
114 | */
115 | - (BOOL)yy_modelSetWithJSON:(id)json;
116 |
117 | /**
118 | Set the receiver's properties with a key-value dictionary.
119 |
120 | @param dic A key-value dictionary mapped to the receiver's properties.
121 | Any invalid key-value pair in dictionary will be ignored.
122 |
123 | @discussion The key in `dictionary` will mapped to the reciever's property name,
124 | and the value will set to the property. If the value's type doesn't match the
125 | property, this method will try to convert the value based on these rules:
126 |
127 | `NSString`, `NSNumber` -> c number, such as BOOL, int, long, float, NSUInteger...
128 | `NSString` -> NSDate, parsed with format "yyyy-MM-dd'T'HH:mm:ssZ", "yyyy-MM-dd HH:mm:ss" or "yyyy-MM-dd".
129 | `NSString` -> NSURL.
130 | `NSValue` -> struct or union, such as CGRect, CGSize, ...
131 | `NSString` -> SEL, Class.
132 |
133 | @return Whether succeed.
134 | */
135 | - (BOOL)yy_modelSetWithDictionary:(NSDictionary *)dic;
136 |
137 | /**
138 | Generate a json object from the receiver's properties.
139 |
140 | @return A json object in `NSDictionary` or `NSArray`, or nil if an error occurs.
141 | See [NSJSONSerialization isValidJSONObject] for more information.
142 |
143 | @discussion Any of the invalid property is ignored.
144 | If the reciver is `NSArray`, `NSDictionary` or `NSSet`, it just convert
145 | the inner object to json object.
146 | */
147 | - (nullable id)yy_modelToJSONObject;
148 |
149 | /**
150 | Generate a json string's data from the receiver's properties.
151 |
152 | @return A json string's data, or nil if an error occurs.
153 |
154 | @discussion Any of the invalid property is ignored.
155 | If the reciver is `NSArray`, `NSDictionary` or `NSSet`, it will also convert the
156 | inner object to json string.
157 | */
158 | - (nullable NSData *)yy_modelToJSONData;
159 |
160 | /**
161 | Generate a json string from the receiver's properties.
162 |
163 | @return A json string, or nil if an error occurs.
164 |
165 | @discussion Any of the invalid property is ignored.
166 | If the reciver is `NSArray`, `NSDictionary` or `NSSet`, it will also convert the
167 | inner object to json string.
168 | */
169 | - (nullable NSString *)yy_modelToJSONString;
170 |
171 | /**
172 | Copy a instance with the receiver's properties.
173 |
174 | @return A copied instance, or nil if an error occurs.
175 | */
176 | - (nullable id)yy_modelCopy;
177 |
178 | /**
179 | Encode the receiver's properties to a coder.
180 |
181 | @param aCoder An archiver object.
182 | */
183 | - (void)yy_modelEncodeWithCoder:(NSCoder *)aCoder;
184 |
185 | /**
186 | Decode the receiver's properties from a decoder.
187 |
188 | @param aDecoder An archiver object.
189 |
190 | @return self
191 | */
192 | - (id)yy_modelInitWithCoder:(NSCoder *)aDecoder;
193 |
194 | /**
195 | Get a hash code with the receiver's properties.
196 |
197 | @return Hash code.
198 | */
199 | - (NSUInteger)yy_modelHash;
200 |
201 | /**
202 | Compares the receiver with another object for equality, based on properties.
203 |
204 | @param model Another object.
205 |
206 | @return `YES` if the reciever is equal to the object, otherwise `NO`.
207 | */
208 | - (BOOL)yy_modelIsEqual:(id)model;
209 |
210 | /**
211 | Description method for debugging purposes based on properties.
212 |
213 | @return A string that describes the contents of the receiver.
214 | */
215 | - (NSString *)yy_modelDescription;
216 |
217 | @end
218 |
219 |
220 |
221 | /**
222 | Provide some data-model method for NSArray.
223 | */
224 | @interface NSArray (YYModel)
225 |
226 | /**
227 | Creates and returns an array from a json-array.
228 | This method is thread-safe.
229 |
230 | @param cls The instance's class in array.
231 | @param json A json array of `NSArray`, `NSString` or `NSData`.
232 | Example: [{"name":"Mary"},{name:"Joe"}]
233 |
234 | @return A array, or nil if an error occurs.
235 | */
236 | + (nullable NSArray *)yy_modelArrayWithClass:(Class)cls json:(id)json;
237 |
238 | @end
239 |
240 |
241 |
242 | /**
243 | Provide some data-model method for NSDictionary.
244 | */
245 | @interface NSDictionary (YYModel)
246 |
247 | /**
248 | Creates and returns a dictionary from a json.
249 | This method is thread-safe.
250 |
251 | @param cls The value instance's class in dictionary.
252 | @param json A json dictionary of `NSDictionary`, `NSString` or `NSData`.
253 | Example: {"user1":{"name","Mary"}, "user2": {name:"Joe"}}
254 |
255 | @return A dictionary, or nil if an error occurs.
256 | */
257 | + (nullable NSDictionary *)yy_modelDictionaryWithClass:(Class)cls json:(id)json;
258 | @end
259 |
260 |
261 |
262 | /**
263 | If the default model transform does not fit to your model class, implement one or
264 | more method in this protocol to change the default key-value transform process.
265 | There's no need to add '' to your class header.
266 | */
267 | @protocol YYModel
268 | @optional
269 |
270 | /**
271 | Custom property mapper.
272 |
273 | @discussion If the key in JSON/Dictionary does not match to the model's property name,
274 | implements this method and returns the additional mapper.
275 |
276 | Example:
277 |
278 | json:
279 | {
280 | "n":"Harry Pottery",
281 | "p": 256,
282 | "ext" : {
283 | "desc" : "A book written by J.K.Rowling."
284 | },
285 | "ID" : 100010
286 | }
287 |
288 | model:
289 | @code
290 | @interface YYBook : NSObject
291 | @property NSString *name;
292 | @property NSInteger page;
293 | @property NSString *desc;
294 | @property NSString *bookID;
295 | @end
296 |
297 | @implementation YYBook
298 | + (NSDictionary *)modelCustomPropertyMapper {
299 | return @{@"name" : @"n",
300 | @"page" : @"p",
301 | @"desc" : @"ext.desc",
302 | @"bookID": @[@"id", @"ID", @"book_id"]};
303 | }
304 | @end
305 | @endcode
306 |
307 | @return A custom mapper for properties.
308 | */
309 | + (nullable NSDictionary *)modelCustomPropertyMapper;
310 |
311 | /**
312 | The generic class mapper for container properties.
313 |
314 | @discussion If the property is a container object, such as NSArray/NSSet/NSDictionary,
315 | implements this method and returns a property->class mapper, tells which kind of
316 | object will be add to the array/set/dictionary.
317 |
318 | Example:
319 | @code
320 | @class YYShadow, YYBorder, YYAttachment;
321 |
322 | @interface YYAttributes
323 | @property NSString *name;
324 | @property NSArray *shadows;
325 | @property NSSet *borders;
326 | @property NSDictionary *attachments;
327 | @end
328 |
329 | @implementation YYAttributes
330 | + (NSDictionary *)modelContainerPropertyGenericClass {
331 | return @{@"shadows" : [YYShadow class],
332 | @"borders" : YYBorder.class,
333 | @"attachments" : @"YYAttachment" };
334 | }
335 | @end
336 | @endcode
337 |
338 | @return A class mapper.
339 | */
340 | + (nullable NSDictionary *)modelContainerPropertyGenericClass;
341 |
342 | /**
343 | If you need to create instances of different classes during json->object transform,
344 | use the method to choose custom class based on dictionary data.
345 |
346 | @discussion If the model implements this method, it will be called to determine resulting class
347 | during `+modelWithJSON:`, `+modelWithDictionary:`, conveting object of properties of parent objects
348 | (both singular and containers via `+modelContainerPropertyGenericClass`).
349 |
350 | Example:
351 | @code
352 | @class YYCircle, YYRectangle, YYLine;
353 |
354 | @implementation YYShape
355 |
356 | + (Class)modelCustomClassForDictionary:(NSDictionary*)dictionary {
357 | if (dictionary[@"radius"] != nil) {
358 | return [YYCircle class];
359 | } else if (dictionary[@"width"] != nil) {
360 | return [YYRectangle class];
361 | } else if (dictionary[@"y2"] != nil) {
362 | return [YYLine class];
363 | } else {
364 | return [self class];
365 | }
366 | }
367 |
368 | @end
369 | @endcode
370 |
371 | @param dictionary The json/kv dictionary.
372 |
373 | @return Class to create from this dictionary, `nil` to use current class.
374 |
375 | */
376 | + (nullable Class)modelCustomClassForDictionary:(NSDictionary *)dictionary;
377 |
378 | /**
379 | All the properties in blacklist will be ignored in model transform process.
380 | Returns nil to ignore this feature.
381 |
382 | @return An array of property's name.
383 | */
384 | + (nullable NSArray *)modelPropertyBlacklist;
385 |
386 | /**
387 | If a property is not in the whitelist, it will be ignored in model transform process.
388 | Returns nil to ignore this feature.
389 |
390 | @return An array of property's name.
391 | */
392 | + (nullable NSArray *)modelPropertyWhitelist;
393 |
394 | /**
395 | This method's behavior is similar to `- (BOOL)modelCustomTransformFromDictionary:(NSDictionary *)dic;`,
396 | but be called before the model transform.
397 |
398 | @discussion If the model implements this method, it will be called before
399 | `+modelWithJSON:`, `+modelWithDictionary:`, `-modelSetWithJSON:` and `-modelSetWithDictionary:`.
400 | If this method returns nil, the transform process will ignore this model.
401 |
402 | @param dic The json/kv dictionary.
403 |
404 | @return Returns the modified dictionary, or nil to ignore this model.
405 | */
406 | - (NSDictionary *)modelCustomWillTransformFromDictionary:(NSDictionary *)dic;
407 |
408 | /**
409 | If the default json-to-model transform does not fit to your model object, implement
410 | this method to do additional process. You can also use this method to validate the
411 | model's properties.
412 |
413 | @discussion If the model implements this method, it will be called at the end of
414 | `+modelWithJSON:`, `+modelWithDictionary:`, `-modelSetWithJSON:` and `-modelSetWithDictionary:`.
415 | If this method returns NO, the transform process will ignore this model.
416 |
417 | @param dic The json/kv dictionary.
418 |
419 | @return Returns YES if the model is valid, or NO to ignore this model.
420 | */
421 | - (BOOL)modelCustomTransformFromDictionary:(NSDictionary *)dic;
422 |
423 | /**
424 | If the default model-to-json transform does not fit to your model class, implement
425 | this method to do additional process. You can also use this method to validate the
426 | json dictionary.
427 |
428 | @discussion If the model implements this method, it will be called at the end of
429 | `-modelToJSONObject` and `-modelToJSONString`.
430 | If this method returns NO, the transform process will ignore this json dictionary.
431 |
432 | @param dic The json dictionary.
433 |
434 | @return Returns YES if the model is valid, or NO to ignore this model.
435 | */
436 | - (BOOL)modelCustomTransformToDictionary:(NSMutableDictionary *)dic;
437 |
438 | @end
439 |
440 | NS_ASSUME_NONNULL_END
441 |
--------------------------------------------------------------------------------
/YYModel/YYClassInfo.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYClassInfo.h
3 | // YYModel
4 | //
5 | // Created by ibireme on 15/5/9.
6 | // Copyright (c) 2015 ibireme.
7 | //
8 | // This source code is licensed under the MIT-style license found in the
9 | // LICENSE file in the root directory of this source tree.
10 | //
11 |
12 | #import
13 | #import
14 |
15 | NS_ASSUME_NONNULL_BEGIN
16 |
17 | /**
18 | Type encoding's type.
19 | */
20 | typedef NS_OPTIONS(NSUInteger, YYEncodingType) {
21 | YYEncodingTypeMask = 0xFF, ///< mask of type value
22 | YYEncodingTypeUnknown = 0, ///< unknown
23 | YYEncodingTypeVoid = 1, ///< void
24 | YYEncodingTypeBool = 2, ///< bool
25 | YYEncodingTypeInt8 = 3, ///< char / BOOL
26 | YYEncodingTypeUInt8 = 4, ///< unsigned char
27 | YYEncodingTypeInt16 = 5, ///< short
28 | YYEncodingTypeUInt16 = 6, ///< unsigned short
29 | YYEncodingTypeInt32 = 7, ///< int
30 | YYEncodingTypeUInt32 = 8, ///< unsigned int
31 | YYEncodingTypeInt64 = 9, ///< long long
32 | YYEncodingTypeUInt64 = 10, ///< unsigned long long
33 | YYEncodingTypeFloat = 11, ///< float
34 | YYEncodingTypeDouble = 12, ///< double
35 | YYEncodingTypeLongDouble = 13, ///< long double
36 | YYEncodingTypeObject = 14, ///< id
37 | YYEncodingTypeClass = 15, ///< Class
38 | YYEncodingTypeSEL = 16, ///< SEL
39 | YYEncodingTypeBlock = 17, ///< block
40 | YYEncodingTypePointer = 18, ///< void*
41 | YYEncodingTypeStruct = 19, ///< struct
42 | YYEncodingTypeUnion = 20, ///< union
43 | YYEncodingTypeCString = 21, ///< char*
44 | YYEncodingTypeCArray = 22, ///< char[10] (for example)
45 |
46 | YYEncodingTypeQualifierMask = 0xFF00, ///< mask of qualifier
47 | YYEncodingTypeQualifierConst = 1 << 8, ///< const
48 | YYEncodingTypeQualifierIn = 1 << 9, ///< in
49 | YYEncodingTypeQualifierInout = 1 << 10, ///< inout
50 | YYEncodingTypeQualifierOut = 1 << 11, ///< out
51 | YYEncodingTypeQualifierBycopy = 1 << 12, ///< bycopy
52 | YYEncodingTypeQualifierByref = 1 << 13, ///< byref
53 | YYEncodingTypeQualifierOneway = 1 << 14, ///< oneway
54 |
55 | YYEncodingTypePropertyMask = 0xFF0000, ///< mask of property
56 | YYEncodingTypePropertyReadonly = 1 << 16, ///< readonly
57 | YYEncodingTypePropertyCopy = 1 << 17, ///< copy
58 | YYEncodingTypePropertyRetain = 1 << 18, ///< retain
59 | YYEncodingTypePropertyNonatomic = 1 << 19, ///< nonatomic
60 | YYEncodingTypePropertyWeak = 1 << 20, ///< weak
61 | YYEncodingTypePropertyCustomGetter = 1 << 21, ///< getter=
62 | YYEncodingTypePropertyCustomSetter = 1 << 22, ///< setter=
63 | YYEncodingTypePropertyDynamic = 1 << 23, ///< @dynamic
64 | };
65 |
66 | /**
67 | Get the type from a Type-Encoding string.
68 |
69 | @discussion See also:
70 | https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
71 | https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html
72 |
73 | @param typeEncoding A Type-Encoding string.
74 | @return The encoding type.
75 | */
76 | YYEncodingType YYEncodingGetType(const char *typeEncoding);
77 |
78 |
79 | /**
80 | Instance variable information.
81 | */
82 | @interface YYClassIvarInfo : NSObject
83 | @property (nonatomic, assign, readonly) Ivar ivar; ///< ivar opaque struct
84 | @property (nonatomic, strong, readonly) NSString *name; ///< Ivar's name
85 | @property (nonatomic, assign, readonly) ptrdiff_t offset; ///< Ivar's offset
86 | @property (nonatomic, strong, readonly) NSString *typeEncoding; ///< Ivar's type encoding
87 | @property (nonatomic, assign, readonly) YYEncodingType type; ///< Ivar's type
88 |
89 | /**
90 | Creates and returns an ivar info object.
91 |
92 | @param ivar ivar opaque struct
93 | @return A new object, or nil if an error occurs.
94 | */
95 | - (instancetype)initWithIvar:(Ivar)ivar;
96 | @end
97 |
98 |
99 | /**
100 | Method information.
101 | */
102 | @interface YYClassMethodInfo : NSObject
103 | @property (nonatomic, assign, readonly) Method method; ///< method opaque struct
104 | @property (nonatomic, strong, readonly) NSString *name; ///< method name
105 | @property (nonatomic, assign, readonly) SEL sel; ///< method's selector
106 | @property (nonatomic, assign, readonly) IMP imp; ///< method's implementation
107 | @property (nonatomic, strong, readonly) NSString *typeEncoding; ///< method's parameter and return types
108 | @property (nonatomic, strong, readonly) NSString *returnTypeEncoding; ///< return value's type
109 | @property (nullable, nonatomic, strong, readonly) NSArray *argumentTypeEncodings; ///< array of arguments' type
110 |
111 | /**
112 | Creates and returns a method info object.
113 |
114 | @param method method opaque struct
115 | @return A new object, or nil if an error occurs.
116 | */
117 | - (instancetype)initWithMethod:(Method)method;
118 | @end
119 |
120 |
121 | /**
122 | Property information.
123 | */
124 | @interface YYClassPropertyInfo : NSObject
125 | @property (nonatomic, assign, readonly) objc_property_t property; ///< property's opaque struct
126 | @property (nonatomic, strong, readonly) NSString *name; ///< property's name
127 | @property (nonatomic, assign, readonly) YYEncodingType type; ///< property's type
128 | @property (nonatomic, strong, readonly) NSString *typeEncoding; ///< property's encoding value
129 | @property (nonatomic, strong, readonly) NSString *ivarName; ///< property's ivar name
130 | @property (nullable, nonatomic, assign, readonly) Class cls; ///< may be nil
131 | @property (nullable, nonatomic, strong, readonly) NSArray *protocols; ///< may nil
132 | @property (nonatomic, assign, readonly) SEL getter; ///< getter (nonnull)
133 | @property (nonatomic, assign, readonly) SEL setter; ///< setter (nonnull)
134 |
135 | /**
136 | Creates and returns a property info object.
137 |
138 | @param property property opaque struct
139 | @return A new object, or nil if an error occurs.
140 | */
141 | - (instancetype)initWithProperty:(objc_property_t)property;
142 | @end
143 |
144 |
145 | /**
146 | Class information for a class.
147 | */
148 | @interface YYClassInfo : NSObject
149 | @property (nonatomic, assign, readonly) Class cls; ///< class object
150 | @property (nullable, nonatomic, assign, readonly) Class superCls; ///< super class object
151 | @property (nullable, nonatomic, assign, readonly) Class metaCls; ///< class's meta class object
152 | @property (nonatomic, readonly) BOOL isMeta; ///< whether this class is meta class
153 | @property (nonatomic, strong, readonly) NSString *name; ///< class name
154 | @property (nullable, nonatomic, strong, readonly) YYClassInfo *superClassInfo; ///< super class's class info
155 | @property (nullable, nonatomic, strong, readonly) NSDictionary *ivarInfos; ///< ivars
156 | @property (nullable, nonatomic, strong, readonly) NSDictionary *methodInfos; ///< methods
157 | @property (nullable, nonatomic, strong, readonly) NSDictionary *propertyInfos; ///< properties
158 |
159 | /**
160 | If the class is changed (for example: you add a method to this class with
161 | 'class_addMethod()'), you should call this method to refresh the class info cache.
162 |
163 | After called this method, `needUpdate` will returns `YES`, and you should call
164 | 'classInfoWithClass' or 'classInfoWithClassName' to get the updated class info.
165 | */
166 | - (void)setNeedUpdate;
167 |
168 | /**
169 | If this method returns `YES`, you should stop using this instance and call
170 | `classInfoWithClass` or `classInfoWithClassName` to get the updated class info.
171 |
172 | @return Whether this class info need update.
173 | */
174 | - (BOOL)needUpdate;
175 |
176 | /**
177 | Get the class info of a specified Class.
178 |
179 | @discussion This method will cache the class info and super-class info
180 | at the first access to the Class. This method is thread-safe.
181 |
182 | @param cls A class.
183 | @return A class info, or nil if an error occurs.
184 | */
185 | + (nullable instancetype)classInfoWithClass:(Class)cls;
186 |
187 | /**
188 | Get the class info of a specified Class.
189 |
190 | @discussion This method will cache the class info and super-class info
191 | at the first access to the Class. This method is thread-safe.
192 |
193 | @param className A class name.
194 | @return A class info, or nil if an error occurs.
195 | */
196 | + (nullable instancetype)classInfoWithClassName:(NSString *)className;
197 |
198 | @end
199 |
200 | NS_ASSUME_NONNULL_END
201 |
--------------------------------------------------------------------------------
/YYModel/YYClassInfo.m:
--------------------------------------------------------------------------------
1 | //
2 | // YYClassInfo.m
3 | // YYModel
4 | //
5 | // Created by ibireme on 15/5/9.
6 | // Copyright (c) 2015 ibireme.
7 | //
8 | // This source code is licensed under the MIT-style license found in the
9 | // LICENSE file in the root directory of this source tree.
10 | //
11 |
12 | #import "YYClassInfo.h"
13 | #import
14 |
15 | YYEncodingType YYEncodingGetType(const char *typeEncoding) {
16 | char *type = (char *)typeEncoding;
17 | if (!type) return YYEncodingTypeUnknown;
18 | size_t len = strlen(type);
19 | if (len == 0) return YYEncodingTypeUnknown;
20 |
21 | YYEncodingType qualifier = 0;
22 | bool prefix = true;
23 | while (prefix) {
24 | switch (*type) {
25 | case 'r': {
26 | qualifier |= YYEncodingTypeQualifierConst;
27 | type++;
28 | } break;
29 | case 'n': {
30 | qualifier |= YYEncodingTypeQualifierIn;
31 | type++;
32 | } break;
33 | case 'N': {
34 | qualifier |= YYEncodingTypeQualifierInout;
35 | type++;
36 | } break;
37 | case 'o': {
38 | qualifier |= YYEncodingTypeQualifierOut;
39 | type++;
40 | } break;
41 | case 'O': {
42 | qualifier |= YYEncodingTypeQualifierBycopy;
43 | type++;
44 | } break;
45 | case 'R': {
46 | qualifier |= YYEncodingTypeQualifierByref;
47 | type++;
48 | } break;
49 | case 'V': {
50 | qualifier |= YYEncodingTypeQualifierOneway;
51 | type++;
52 | } break;
53 | default: { prefix = false; } break;
54 | }
55 | }
56 |
57 | len = strlen(type);
58 | if (len == 0) return YYEncodingTypeUnknown | qualifier;
59 |
60 | switch (*type) {
61 | case 'v': return YYEncodingTypeVoid | qualifier;
62 | case 'B': return YYEncodingTypeBool | qualifier;
63 | case 'c': return YYEncodingTypeInt8 | qualifier;
64 | case 'C': return YYEncodingTypeUInt8 | qualifier;
65 | case 's': return YYEncodingTypeInt16 | qualifier;
66 | case 'S': return YYEncodingTypeUInt16 | qualifier;
67 | case 'i': return YYEncodingTypeInt32 | qualifier;
68 | case 'I': return YYEncodingTypeUInt32 | qualifier;
69 | case 'l': return YYEncodingTypeInt32 | qualifier;
70 | case 'L': return YYEncodingTypeUInt32 | qualifier;
71 | case 'q': return YYEncodingTypeInt64 | qualifier;
72 | case 'Q': return YYEncodingTypeUInt64 | qualifier;
73 | case 'f': return YYEncodingTypeFloat | qualifier;
74 | case 'd': return YYEncodingTypeDouble | qualifier;
75 | case 'D': return YYEncodingTypeLongDouble | qualifier;
76 | case '#': return YYEncodingTypeClass | qualifier;
77 | case ':': return YYEncodingTypeSEL | qualifier;
78 | case '*': return YYEncodingTypeCString | qualifier;
79 | case '^': return YYEncodingTypePointer | qualifier;
80 | case '[': return YYEncodingTypeCArray | qualifier;
81 | case '(': return YYEncodingTypeUnion | qualifier;
82 | case '{': return YYEncodingTypeStruct | qualifier;
83 | case '@': {
84 | if (len == 2 && *(type + 1) == '?')
85 | return YYEncodingTypeBlock | qualifier;
86 | else
87 | return YYEncodingTypeObject | qualifier;
88 | }
89 | default: return YYEncodingTypeUnknown | qualifier;
90 | }
91 | }
92 |
93 | @implementation YYClassIvarInfo
94 |
95 | - (instancetype)initWithIvar:(Ivar)ivar {
96 | if (!ivar) return nil;
97 | self = [super init];
98 | _ivar = ivar;
99 | const char *name = ivar_getName(ivar);
100 | if (name) {
101 | _name = [NSString stringWithUTF8String:name];
102 | }
103 | _offset = ivar_getOffset(ivar);
104 | const char *typeEncoding = ivar_getTypeEncoding(ivar);
105 | if (typeEncoding) {
106 | _typeEncoding = [NSString stringWithUTF8String:typeEncoding];
107 | _type = YYEncodingGetType(typeEncoding);
108 | }
109 | return self;
110 | }
111 |
112 | @end
113 |
114 | @implementation YYClassMethodInfo
115 |
116 | - (instancetype)initWithMethod:(Method)method {
117 | if (!method) return nil;
118 | self = [super init];
119 | _method = method;
120 | _sel = method_getName(method);
121 | _imp = method_getImplementation(method);
122 | const char *name = sel_getName(_sel);
123 | if (name) {
124 | _name = [NSString stringWithUTF8String:name];
125 | }
126 | const char *typeEncoding = method_getTypeEncoding(method);
127 | if (typeEncoding) {
128 | _typeEncoding = [NSString stringWithUTF8String:typeEncoding];
129 | }
130 | char *returnType = method_copyReturnType(method);
131 | if (returnType) {
132 | _returnTypeEncoding = [NSString stringWithUTF8String:returnType];
133 | free(returnType);
134 | }
135 | unsigned int argumentCount = method_getNumberOfArguments(method);
136 | if (argumentCount > 0) {
137 | NSMutableArray *argumentTypes = [NSMutableArray new];
138 | for (unsigned int i = 0; i < argumentCount; i++) {
139 | char *argumentType = method_copyArgumentType(method, i);
140 | NSString *type = argumentType ? [NSString stringWithUTF8String:argumentType] : nil;
141 | [argumentTypes addObject:type ? type : @""];
142 | if (argumentType) free(argumentType);
143 | }
144 | _argumentTypeEncodings = argumentTypes;
145 | }
146 | return self;
147 | }
148 |
149 | @end
150 |
151 | @implementation YYClassPropertyInfo
152 |
153 | - (instancetype)initWithProperty:(objc_property_t)property {
154 | if (!property) return nil;
155 | self = [super init];
156 | _property = property;
157 | const char *name = property_getName(property);
158 | if (name) {
159 | _name = [NSString stringWithUTF8String:name];
160 | }
161 |
162 | YYEncodingType type = 0;
163 | unsigned int attrCount;
164 | objc_property_attribute_t *attrs = property_copyAttributeList(property, &attrCount);
165 | for (unsigned int i = 0; i < attrCount; i++) {
166 | switch (attrs[i].name[0]) {
167 | case 'T': { // Type encoding
168 | if (attrs[i].value) {
169 | _typeEncoding = [NSString stringWithUTF8String:attrs[i].value];
170 | type = YYEncodingGetType(attrs[i].value);
171 |
172 | if ((type & YYEncodingTypeMask) == YYEncodingTypeObject && _typeEncoding.length) {
173 | NSScanner *scanner = [NSScanner scannerWithString:_typeEncoding];
174 | if (![scanner scanString:@"@\"" intoString:NULL]) continue;
175 |
176 | NSString *clsName = nil;
177 | if ([scanner scanUpToCharactersFromSet: [NSCharacterSet characterSetWithCharactersInString:@"\"<"] intoString:&clsName]) {
178 | if (clsName.length) _cls = objc_getClass(clsName.UTF8String);
179 | }
180 |
181 | NSMutableArray *protocols = nil;
182 | while ([scanner scanString:@"<" intoString:NULL]) {
183 | NSString* protocol = nil;
184 | if ([scanner scanUpToString:@">" intoString: &protocol]) {
185 | if (protocol.length) {
186 | if (!protocols) protocols = [NSMutableArray new];
187 | [protocols addObject:protocol];
188 | }
189 | }
190 | [scanner scanString:@">" intoString:NULL];
191 | }
192 | _protocols = protocols;
193 | }
194 | }
195 | } break;
196 | case 'V': { // Instance variable
197 | if (attrs[i].value) {
198 | _ivarName = [NSString stringWithUTF8String:attrs[i].value];
199 | }
200 | } break;
201 | case 'R': {
202 | type |= YYEncodingTypePropertyReadonly;
203 | } break;
204 | case 'C': {
205 | type |= YYEncodingTypePropertyCopy;
206 | } break;
207 | case '&': {
208 | type |= YYEncodingTypePropertyRetain;
209 | } break;
210 | case 'N': {
211 | type |= YYEncodingTypePropertyNonatomic;
212 | } break;
213 | case 'D': {
214 | type |= YYEncodingTypePropertyDynamic;
215 | } break;
216 | case 'W': {
217 | type |= YYEncodingTypePropertyWeak;
218 | } break;
219 | case 'G': {
220 | type |= YYEncodingTypePropertyCustomGetter;
221 | if (attrs[i].value) {
222 | _getter = NSSelectorFromString([NSString stringWithUTF8String:attrs[i].value]);
223 | }
224 | } break;
225 | case 'S': {
226 | type |= YYEncodingTypePropertyCustomSetter;
227 | if (attrs[i].value) {
228 | _setter = NSSelectorFromString([NSString stringWithUTF8String:attrs[i].value]);
229 | }
230 | } // break; commented for code coverage in next line
231 | default: break;
232 | }
233 | }
234 | if (attrs) {
235 | free(attrs);
236 | attrs = NULL;
237 | }
238 |
239 | _type = type;
240 | if (_name.length) {
241 | if (!_getter) {
242 | _getter = NSSelectorFromString(_name);
243 | }
244 | if (!_setter) {
245 | _setter = NSSelectorFromString([NSString stringWithFormat:@"set%@%@:", [_name substringToIndex:1].uppercaseString, [_name substringFromIndex:1]]);
246 | }
247 | }
248 | return self;
249 | }
250 |
251 | @end
252 |
253 | @implementation YYClassInfo {
254 | BOOL _needUpdate;
255 | }
256 |
257 | - (instancetype)initWithClass:(Class)cls {
258 | if (!cls) return nil;
259 | self = [super init];
260 | _cls = cls;
261 | _superCls = class_getSuperclass(cls);
262 | _isMeta = class_isMetaClass(cls);
263 | if (!_isMeta) {
264 | _metaCls = objc_getMetaClass(class_getName(cls));
265 | }
266 | _name = NSStringFromClass(cls);
267 | [self _update];
268 |
269 | _superClassInfo = [self.class classInfoWithClass:_superCls];
270 | return self;
271 | }
272 |
273 | - (void)_update {
274 | _ivarInfos = nil;
275 | _methodInfos = nil;
276 | _propertyInfos = nil;
277 |
278 | Class cls = self.cls;
279 | unsigned int methodCount = 0;
280 | Method *methods = class_copyMethodList(cls, &methodCount);
281 | if (methods) {
282 | NSMutableDictionary *methodInfos = [NSMutableDictionary new];
283 | _methodInfos = methodInfos;
284 | for (unsigned int i = 0; i < methodCount; i++) {
285 | YYClassMethodInfo *info = [[YYClassMethodInfo alloc] initWithMethod:methods[i]];
286 | if (info.name) methodInfos[info.name] = info;
287 | }
288 | free(methods);
289 | }
290 | unsigned int propertyCount = 0;
291 | objc_property_t *properties = class_copyPropertyList(cls, &propertyCount);
292 | if (properties) {
293 | NSMutableDictionary *propertyInfos = [NSMutableDictionary new];
294 | _propertyInfos = propertyInfos;
295 | for (unsigned int i = 0; i < propertyCount; i++) {
296 | YYClassPropertyInfo *info = [[YYClassPropertyInfo alloc] initWithProperty:properties[i]];
297 | if (info.name) propertyInfos[info.name] = info;
298 | }
299 | free(properties);
300 | }
301 |
302 | unsigned int ivarCount = 0;
303 | Ivar *ivars = class_copyIvarList(cls, &ivarCount);
304 | if (ivars) {
305 | NSMutableDictionary *ivarInfos = [NSMutableDictionary new];
306 | _ivarInfos = ivarInfos;
307 | for (unsigned int i = 0; i < ivarCount; i++) {
308 | YYClassIvarInfo *info = [[YYClassIvarInfo alloc] initWithIvar:ivars[i]];
309 | if (info.name) ivarInfos[info.name] = info;
310 | }
311 | free(ivars);
312 | }
313 |
314 | if (!_ivarInfos) _ivarInfos = @{};
315 | if (!_methodInfos) _methodInfos = @{};
316 | if (!_propertyInfos) _propertyInfos = @{};
317 |
318 | _needUpdate = NO;
319 | }
320 |
321 | - (void)setNeedUpdate {
322 | _needUpdate = YES;
323 | }
324 |
325 | - (BOOL)needUpdate {
326 | return _needUpdate;
327 | }
328 |
329 | + (instancetype)classInfoWithClass:(Class)cls {
330 | if (!cls) return nil;
331 | static CFMutableDictionaryRef classCache;
332 | static CFMutableDictionaryRef metaCache;
333 | static dispatch_once_t onceToken;
334 | static dispatch_semaphore_t lock;
335 | dispatch_once(&onceToken, ^{
336 | classCache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
337 | metaCache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
338 | lock = dispatch_semaphore_create(1);
339 | });
340 | dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
341 | YYClassInfo *info = CFDictionaryGetValue(class_isMetaClass(cls) ? metaCache : classCache, (__bridge const void *)(cls));
342 | if (info && info->_needUpdate) {
343 | [info _update];
344 | }
345 | dispatch_semaphore_signal(lock);
346 | if (!info) {
347 | info = [[YYClassInfo alloc] initWithClass:cls];
348 | if (info) {
349 | dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
350 | CFDictionarySetValue(info.isMeta ? metaCache : classCache, (__bridge const void *)(cls), (__bridge const void *)(info));
351 | dispatch_semaphore_signal(lock);
352 | }
353 | }
354 | return info;
355 | }
356 |
357 | + (instancetype)classInfoWithClassName:(NSString *)className {
358 | Class cls = NSClassFromString(className);
359 | return [self classInfoWithClass:cls];
360 | }
361 |
362 | @end
363 |
--------------------------------------------------------------------------------
/YYModel/YYModel.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYModel.h
3 | // YYModel
4 | //
5 | // Created by ibireme on 15/5/10.
6 | // Copyright (c) 2015 ibireme.
7 | //
8 | // This source code is licensed under the MIT-style license found in the
9 | // LICENSE file in the root directory of this source tree.
10 | //
11 |
12 | #import
13 |
14 | #if __has_include()
15 | FOUNDATION_EXPORT double YYModelVersionNumber;
16 | FOUNDATION_EXPORT const unsigned char YYModelVersionString[];
17 | #import
18 | #import
19 | #else
20 | #import "NSObject+YYModel.h"
21 | #import "YYClassInfo.h"
22 | #endif
23 |
--------------------------------------------------------------------------------
/YYModelTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
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 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/YYModelTests/YYTestBlacklistWhitelist.m:
--------------------------------------------------------------------------------
1 | //
2 | // YYTestBlacklistWhitelist.m
3 | // YYModel
4 | //
5 | // Created by ibireme on 15/11/29.
6 | // Copyright (c) 2015 ibireme.
7 | //
8 | // This source code is licensed under the MIT-style license found in the
9 | // LICENSE file in the root directory of this source tree.
10 | //
11 |
12 | #import
13 | #import "YYModel.h"
14 |
15 |
16 | @interface YYTestBlacklistModel : NSObject
17 | @property (nonatomic, strong) NSString *a;
18 | @property (nonatomic, strong) NSString *b;
19 | @property (nonatomic, strong) NSString *c;
20 | @end
21 |
22 | @implementation YYTestBlacklistModel
23 | + (NSArray *)modelPropertyBlacklist {
24 | return @[@"a", @"d"];
25 | }
26 | @end
27 |
28 | @interface YYTestWhitelistModel : NSObject
29 | @property (nonatomic, strong) NSString *a;
30 | @property (nonatomic, strong) NSString *b;
31 | @property (nonatomic, strong) NSString *c;
32 | @end
33 |
34 | @implementation YYTestWhitelistModel
35 | + (NSArray *)modelPropertyWhitelist {
36 | return @[@"a", @"d"];
37 | }
38 | @end
39 |
40 |
41 | @interface YYTestBlackWhitelistModel : NSObject
42 | @property (nonatomic, strong) NSString *a;
43 | @property (nonatomic, strong) NSString *b;
44 | @property (nonatomic, strong) NSString *c;
45 | @end
46 |
47 | @implementation YYTestBlackWhitelistModel
48 | + (NSArray *)modelPropertyBlacklist {
49 | return @[@"a", @"d"];
50 | }
51 | + (NSArray *)modelPropertyWhitelist {
52 | return @[@"a", @"b", @"d"];
53 | }
54 | @end
55 |
56 |
57 |
58 |
59 | @interface YYTestBlacklistWhitelist : XCTestCase
60 |
61 | @end
62 |
63 | @implementation YYTestBlacklistWhitelist
64 |
65 | - (void)testBlacklist {
66 | NSString *json = @"{\"a\":\"A\", \"b\":\"B\", \"c\":\"C\", \"d\":\"D\"}";
67 | YYTestBlacklistModel *model = [YYTestBlacklistModel yy_modelWithJSON:json];
68 | XCTAssert(model.a == nil);
69 | XCTAssert(model.b != nil);
70 | XCTAssert(model.c != nil);
71 |
72 | NSDictionary *dic = [model yy_modelToJSONObject];
73 | XCTAssert(dic[@"a"] == nil);
74 | XCTAssert(dic[@"b"] != nil);
75 | XCTAssert(dic[@"c"] != nil);
76 | }
77 |
78 | - (void)testWhitelist {
79 | NSString *json = @"{\"a\":\"A\", \"b\":\"B\", \"c\":\"C\", \"d\":\"D\"}";
80 | YYTestWhitelistModel *model = [YYTestWhitelistModel yy_modelWithJSON:json];
81 | XCTAssert(model.a != nil);
82 | XCTAssert(model.b == nil);
83 | XCTAssert(model.c == nil);
84 |
85 | NSDictionary *dic = [model yy_modelToJSONObject];
86 | XCTAssert(dic[@"a"] != nil);
87 | XCTAssert(dic[@"b"] == nil);
88 | XCTAssert(dic[@"c"] == nil);
89 | }
90 |
91 |
92 | - (void)testBlackWhitelist {
93 | NSString *json = @"{\"a\":\"A\", \"b\":\"B\", \"c\":\"C\", \"d\":\"D\"}";
94 | YYTestBlackWhitelistModel *model = [YYTestBlackWhitelistModel yy_modelWithJSON:json];
95 | XCTAssert(model.a == nil);
96 | XCTAssert(model.b != nil);
97 | XCTAssert(model.c == nil);
98 |
99 | NSDictionary *dic = [model yy_modelToJSONObject];
100 | XCTAssert(dic[@"a"] == nil);
101 | XCTAssert(dic[@"b"] != nil);
102 | XCTAssert(dic[@"c"] == nil);
103 | }
104 |
105 | @end
106 |
--------------------------------------------------------------------------------
/YYModelTests/YYTestClassInfo.m:
--------------------------------------------------------------------------------
1 | //
2 | // YYTestClassInfo.m
3 | // YYModel
4 | //
5 | // Created by ibireme on 15/11/27.
6 | // Copyright (c) 2015 ibireme.
7 | //
8 | // This source code is licensed under the MIT-style license found in the
9 | // LICENSE file in the root directory of this source tree.
10 | //
11 |
12 | #import
13 | #import
14 | #import "YYModel.h"
15 |
16 | typedef union yy_union{ char a; int b;} yy_union;
17 |
18 | @interface YYTestPropertyModel : NSObject
19 | @property bool boolValue;
20 | @property BOOL BOOLValue;
21 | @property char charValue;
22 | @property unsigned char unsignedCharValue;
23 | @property short shortValue;
24 | @property unsigned short unsignedShortValue;
25 | @property int intValue;
26 | @property unsigned int unsignedIntValue;
27 | @property long longValue;
28 | @property unsigned long unsignedLongValue;
29 | @property long long longLongValue;
30 | @property unsigned long long unsignedLongLongValue;
31 | @property float floatValue;
32 | @property double doubleValue;
33 | @property long double longDoubleValue;
34 | @property (strong) NSObject *objectValue;
35 | @property (strong) NSArray *arrayValue;
36 | @property (strong) Class classValue;
37 | @property SEL selectorValue;
38 | @property (copy) void (^blockValue)();
39 | @property void *pointerValue;
40 | @property CFArrayEqualCallBack functionPointerValue;
41 | @property CGRect structValue;
42 | @property yy_union unionValue;
43 | @property char *cStringValue;
44 |
45 | @property (nonatomic) NSObject *nonatomicValue;
46 | @property (copy) NSObject *aCopyValue;
47 | @property (assign) NSObject *assignValue;
48 | @property (strong) NSObject *strongValue;
49 | @property (retain) NSObject *retainValue;
50 | @property (weak) NSObject *weakValue;
51 | @property (readonly) NSObject *readonlyValue;
52 | @property (nonatomic) NSObject *dynamicValue;
53 | @property (unsafe_unretained) NSObject *unsafeValue;
54 | @property (nonatomic, getter=getValue) NSObject *getterValue;
55 | @property (nonatomic, setter=setValue:) NSObject *setterValue;
56 | @end
57 |
58 | @implementation YYTestPropertyModel {
59 | const NSObject *_constValue;
60 | }
61 |
62 | @dynamic dynamicValue;
63 |
64 | - (NSObject *)getValue {
65 | return _getterValue;
66 | }
67 |
68 | - (void)setValue:(NSObject *)value {
69 | _setterValue = value;
70 | }
71 |
72 | - (void)testConst:(const NSObject *)value {}
73 | - (void)testIn:(in NSObject *)value {}
74 | - (void)testOut:(out NSObject *)value {}
75 | - (void)testInout:(inout NSObject *)value {}
76 | - (void)testBycopy:(bycopy NSObject *)value {}
77 | - (void)testByref:(byref NSObject *)value {}
78 | - (void)testOneway:(oneway NSObject *)value {}
79 | @end
80 |
81 |
82 |
83 |
84 |
85 |
86 | @interface YYTestClassInfo : XCTestCase
87 | @end
88 |
89 | @implementation YYTestClassInfo
90 |
91 | - (void)testClassInfoCache {
92 | YYClassInfo *info1 = [YYClassInfo classInfoWithClass:[YYTestPropertyModel class]];
93 | [info1 setNeedUpdate];
94 | YYClassInfo *info2 = [YYClassInfo classInfoWithClassName:@"YYTestPropertyModel"];
95 | XCTAssertNotNil(info1);
96 | XCTAssertNotNil(info2);
97 | XCTAssertEqual(info1, info2);
98 | }
99 |
100 | - (void)testClassMeta {
101 | YYClassInfo *classInfo = [YYClassInfo classInfoWithClass:[YYTestPropertyModel class]];
102 | XCTAssertNotNil(classInfo);
103 | XCTAssertEqual(classInfo.cls, [YYTestPropertyModel class]);
104 | XCTAssertEqual(classInfo.superCls, [NSObject class]);
105 | XCTAssertEqual(classInfo.metaCls, objc_getMetaClass("YYTestPropertyModel"));
106 | XCTAssertEqual(classInfo.isMeta, NO);
107 |
108 | Class meta = object_getClass([YYTestPropertyModel class]);
109 | YYClassInfo *metaClassInfo = [YYClassInfo classInfoWithClass:meta];
110 | XCTAssertNotNil(metaClassInfo);
111 | XCTAssertEqual(metaClassInfo.cls, meta);
112 | XCTAssertEqual(metaClassInfo.superCls, object_getClass([NSObject class]));
113 | XCTAssertEqual(metaClassInfo.metaCls, nil);
114 | XCTAssertEqual(metaClassInfo.isMeta, YES);
115 | }
116 |
117 | - (void)testClassInfo {
118 | YYClassInfo *info = [YYClassInfo classInfoWithClass:[YYTestPropertyModel class]];
119 | XCTAssertEqual([self getType:info name:@"boolValue"] & YYEncodingTypeMask, YYEncodingTypeBool);
120 | #ifdef OBJC_BOOL_IS_BOOL
121 | XCTAssertEqual([self getType:info name:@"BOOLValue"] & YYEncodingTypeMask, YYEncodingTypeBool);
122 | #else
123 | XCTAssertEqual([self getType:info name:@"BOOLValue"] & YYEncodingTypeMask, YYEncodingTypeInt8);
124 | #endif
125 | XCTAssertEqual([self getType:info name:@"charValue"] & YYEncodingTypeMask, YYEncodingTypeInt8);
126 | XCTAssertEqual([self getType:info name:@"unsignedCharValue"] & YYEncodingTypeMask, YYEncodingTypeUInt8);
127 | XCTAssertEqual([self getType:info name:@"shortValue"] & YYEncodingTypeMask, YYEncodingTypeInt16);
128 | XCTAssertEqual([self getType:info name:@"unsignedShortValue"] & YYEncodingTypeMask, YYEncodingTypeUInt16);
129 | XCTAssertEqual([self getType:info name:@"intValue"] & YYEncodingTypeMask, YYEncodingTypeInt32);
130 | XCTAssertEqual([self getType:info name:@"unsignedIntValue"] & YYEncodingTypeMask, YYEncodingTypeUInt32);
131 | #ifdef __LP64__
132 | XCTAssertEqual([self getType:info name:@"longValue"] & YYEncodingTypeMask, YYEncodingTypeInt64);
133 | XCTAssertEqual([self getType:info name:@"unsignedLongValue"] & YYEncodingTypeMask, YYEncodingTypeUInt64);
134 | XCTAssertEqual(YYEncodingGetType("l") & YYEncodingTypeMask, YYEncodingTypeInt32); // long in 32 bit system
135 | XCTAssertEqual(YYEncodingGetType("L") & YYEncodingTypeMask, YYEncodingTypeUInt32); // unsingle long in 32 bit system
136 | #else
137 | XCTAssertEqual([self getType:info name:@"longValue"] & YYEncodingTypeMask, YYEncodingTypeInt32);
138 | XCTAssertEqual([self getType:info name:@"unsignedLongValue"] & YYEncodingTypeMask, YYEncodingTypeUInt32);
139 | #endif
140 | XCTAssertEqual([self getType:info name:@"longLongValue"] & YYEncodingTypeMask, YYEncodingTypeInt64);
141 | XCTAssertEqual([self getType:info name:@"unsignedLongLongValue"] & YYEncodingTypeMask, YYEncodingTypeUInt64);
142 | XCTAssertEqual([self getType:info name:@"floatValue"] & YYEncodingTypeMask, YYEncodingTypeFloat);
143 | XCTAssertEqual([self getType:info name:@"doubleValue"] & YYEncodingTypeMask, YYEncodingTypeDouble);
144 | XCTAssertEqual([self getType:info name:@"longDoubleValue"] & YYEncodingTypeMask, YYEncodingTypeLongDouble);
145 |
146 | XCTAssertEqual([self getType:info name:@"objectValue"] & YYEncodingTypeMask, YYEncodingTypeObject);
147 | XCTAssertEqual([self getType:info name:@"arrayValue"] & YYEncodingTypeMask, YYEncodingTypeObject);
148 | XCTAssertEqual([self getType:info name:@"classValue"] & YYEncodingTypeMask, YYEncodingTypeClass);
149 | XCTAssertEqual([self getType:info name:@"selectorValue"] & YYEncodingTypeMask, YYEncodingTypeSEL);
150 | XCTAssertEqual([self getType:info name:@"blockValue"] & YYEncodingTypeMask, YYEncodingTypeBlock);
151 | XCTAssertEqual([self getType:info name:@"pointerValue"] & YYEncodingTypeMask, YYEncodingTypePointer);
152 | XCTAssertEqual([self getType:info name:@"functionPointerValue"] & YYEncodingTypeMask, YYEncodingTypePointer);
153 | XCTAssertEqual([self getType:info name:@"structValue"] & YYEncodingTypeMask, YYEncodingTypeStruct);
154 | XCTAssertEqual([self getType:info name:@"unionValue"] & YYEncodingTypeMask, YYEncodingTypeUnion);
155 | XCTAssertEqual([self getType:info name:@"cStringValue"] & YYEncodingTypeMask, YYEncodingTypeCString);
156 |
157 | XCTAssertEqual(YYEncodingGetType(@encode(void)) & YYEncodingTypeMask, YYEncodingTypeVoid);
158 | XCTAssertEqual(YYEncodingGetType(@encode(int[10])) & YYEncodingTypeMask, YYEncodingTypeCArray);
159 | XCTAssertEqual(YYEncodingGetType("") & YYEncodingTypeMask, YYEncodingTypeUnknown);
160 | XCTAssertEqual(YYEncodingGetType(".") & YYEncodingTypeMask, YYEncodingTypeUnknown);
161 | XCTAssertEqual(YYEncodingGetType("ri") & YYEncodingTypeQualifierMask, YYEncodingTypeQualifierConst);
162 | XCTAssertEqual([self getMethodTypeWithName:@"testIn:"] & YYEncodingTypeQualifierMask, YYEncodingTypeQualifierIn);
163 | XCTAssertEqual([self getMethodTypeWithName:@"testOut:"] & YYEncodingTypeQualifierMask, YYEncodingTypeQualifierOut);
164 | XCTAssertEqual([self getMethodTypeWithName:@"testInout:"] & YYEncodingTypeQualifierMask, YYEncodingTypeQualifierInout);
165 | XCTAssertEqual([self getMethodTypeWithName:@"testBycopy:"] & YYEncodingTypeQualifierMask, YYEncodingTypeQualifierBycopy);
166 | XCTAssertEqual([self getMethodTypeWithName:@"testByref:"] & YYEncodingTypeQualifierMask, YYEncodingTypeQualifierByref);
167 | XCTAssertEqual([self getMethodTypeWithName:@"testOneway:"] & YYEncodingTypeQualifierMask, YYEncodingTypeQualifierOneway);
168 |
169 | XCTAssert([self getType:info name:@"nonatomicValue"] & YYEncodingTypePropertyMask &YYEncodingTypePropertyNonatomic);
170 | XCTAssert([self getType:info name:@"aCopyValue"] & YYEncodingTypePropertyMask & YYEncodingTypePropertyCopy);
171 | XCTAssert([self getType:info name:@"strongValue"] & YYEncodingTypePropertyMask & YYEncodingTypePropertyRetain);
172 | XCTAssert([self getType:info name:@"retainValue"] & YYEncodingTypePropertyMask & YYEncodingTypePropertyRetain);
173 | XCTAssert([self getType:info name:@"weakValue"] & YYEncodingTypePropertyMask & YYEncodingTypePropertyWeak);
174 | XCTAssert([self getType:info name:@"readonlyValue"] & YYEncodingTypePropertyMask & YYEncodingTypePropertyReadonly);
175 | XCTAssert([self getType:info name:@"dynamicValue"] & YYEncodingTypePropertyMask & YYEncodingTypePropertyDynamic);
176 | XCTAssert([self getType:info name:@"getterValue"] & YYEncodingTypePropertyMask &YYEncodingTypePropertyCustomGetter);
177 | XCTAssert([self getType:info name:@"setterValue"] & YYEncodingTypePropertyMask & YYEncodingTypePropertyCustomSetter);
178 | }
179 |
180 | - (YYEncodingType)getType:(YYClassInfo *)info name:(NSString *)name {
181 | return ((YYClassPropertyInfo *)info.propertyInfos[name]).type;
182 | }
183 |
184 | - (YYEncodingType)getMethodTypeWithName:(NSString *)name {
185 | YYTestPropertyModel *model = [YYTestPropertyModel new];
186 | NSMethodSignature *sig = [model methodSignatureForSelector:NSSelectorFromString(name)];
187 | const char *typeName = [sig getArgumentTypeAtIndex:2];
188 | return YYEncodingGetType(typeName);
189 | }
190 |
191 | @end
192 |
--------------------------------------------------------------------------------
/YYModelTests/YYTestCopyingAndCoding.m:
--------------------------------------------------------------------------------
1 | //
2 | // YYTestCopyingAndCoding.m
3 | // YYModel
4 | //
5 | // Created by ibireme on 15/11/29.
6 | // Copyright (c) 2015 ibireme.
7 | //
8 | // This source code is licensed under the MIT-style license found in the
9 | // LICENSE file in the root directory of this source tree.
10 | //
11 |
12 | #import
13 | #import "YYModel.h"
14 |
15 |
16 | typedef struct my_struct {
17 | int a;
18 | double b;
19 | long double c;
20 | } my_struct;
21 |
22 | @interface YYTestModelHashModel : NSObject
23 | @property bool boolValue;
24 | @property BOOL BOOLValue;
25 | @property char charValue;
26 | @property unsigned char unsignedCharValue;
27 | @property short shortValue;
28 | @property unsigned short unsignedShortValue;
29 | @property int intValue;
30 | @property unsigned int unsignedIntValue;
31 | @property long longValue;
32 | @property unsigned long unsignedLongValue;
33 | @property long long longLongValue;
34 | @property unsigned long long unsignedLongLongValue;
35 | @property float floatValue;
36 | @property double doubleValue;
37 | @property long double longDoubleValue;
38 | @property (strong) Class classValue;
39 | @property SEL selectorValue;
40 | @property (copy) void (^blockValue)();
41 | @property void *pointerValue;
42 | @property CFArrayRef cfArrayValue;
43 | @property NSValue *valueValue;
44 |
45 | @property CGSize sizeValue;
46 | @property CGPoint pointValue;
47 | @property CGRect rectValue;
48 | @property CGAffineTransform transformValue;
49 | @property UIEdgeInsets insetsValue;
50 | @property UIOffset offsetValue;
51 | @property CATransform3D transform3DValue; // invalid for NSKeyedArchiver/Unarchiver
52 | @property my_struct myStructValue; // invalid for NSKeyedArchiver/Unarchiver
53 |
54 |
55 |
56 | @property (nonatomic, strong) NSObject *object;
57 | @property (nonatomic, strong) NSNumber *number;
58 | @property (nonatomic, strong) NSDecimalNumber *decimal;
59 | @property (nonatomic, strong) NSString *string;
60 | @property (nonatomic, strong) NSString *string2;
61 | @property (nonatomic, strong) NSMutableString *mString;
62 | @property (nonatomic, strong) NSData *data;
63 | @property (nonatomic, strong) NSMutableData *mData;
64 | @property (nonatomic, strong) NSDate *date;
65 | @property (nonatomic, strong) NSValue *value;
66 | @property (nonatomic, strong) NSURL *url;
67 |
68 | @property (nonatomic, strong) NSArray *array;
69 | @property (nonatomic, strong) NSMutableArray *mArray;
70 | @property (nonatomic, strong) NSDictionary *dict;
71 | @property (nonatomic, strong) NSMutableDictionary *mDict;
72 | @property (nonatomic, strong) NSSet *set;
73 | @property (nonatomic, strong) NSMutableSet *mSet;
74 | @end
75 |
76 | @implementation YYTestModelHashModel
77 | - (void)encodeWithCoder:(NSCoder *)aCoder { [self yy_modelEncodeWithCoder:aCoder]; }
78 | - (id)initWithCoder:(NSCoder *)aDecoder { self = [super init]; return [self yy_modelInitWithCoder:aDecoder]; }
79 | - (id)copyWithZone:(NSZone *)zone { return [self yy_modelCopy]; }
80 | - (NSUInteger)hash { return [self yy_modelHash]; }
81 | - (BOOL)isEqual:(id)object { return [self yy_modelIsEqual:object]; }
82 | @end
83 |
84 |
85 |
86 |
87 | @interface YYTestEqualAndHash : XCTestCase
88 |
89 | @end
90 |
91 | @implementation YYTestEqualAndHash
92 |
93 | - (void)testHash {
94 | YYTestModelHashModel *model1 = [YYTestModelHashModel new];
95 | YYTestModelHashModel *model2 = [YYTestModelHashModel new];
96 |
97 | XCTAssertTrue([model1 isEqual:model2]);
98 |
99 | model1.intValue = 1;
100 | XCTAssertFalse([model1 isEqual:model2]);
101 |
102 | model2.intValue = 1;
103 | XCTAssertTrue([model1 isEqual:model2]);
104 |
105 | model1.string = @"Apple";
106 | XCTAssertFalse([model1 isEqual:model2]);
107 |
108 | model2.string = @"Apple";
109 | XCTAssertTrue([model1 isEqual:model2]);
110 |
111 | my_struct my = {0};
112 | my.b = 12.34;
113 |
114 | model1.myStructValue = my;
115 | XCTAssertFalse([model1 isEqual:model2]);
116 |
117 | model2.myStructValue = my;
118 | XCTAssertTrue([model1 isEqual:model2]);
119 |
120 | model1.string = @"Apple";
121 | model1.string2 = @"Apple";
122 | model2.string = @"Steve Jobs";
123 | model2.string2 = @"Steve Jobs";
124 | XCTAssertTrue(model1.hash == model2.hash);
125 | XCTAssertFalse([model1 isEqual:model2]);
126 | }
127 |
128 | - (void)testCopying {
129 | YYTestModelHashModel *model1 = [YYTestModelHashModel new];
130 | YYTestModelHashModel *model2 = nil;
131 |
132 | model1.intValue = 1;
133 | model1.floatValue = 12.34;
134 | model1.myStructValue = (my_struct){.b = 56.78};
135 | model1.string = @"Apple";
136 | model2 = model1.copy;
137 |
138 | XCTAssertEqual(model1.intValue, model2.intValue);
139 | XCTAssertEqual(model1.floatValue, model2.floatValue);
140 | XCTAssertEqual(model1.myStructValue.b, model2.myStructValue.b);
141 | XCTAssertTrue([model1.string isEqualToString:model2.string]);
142 | }
143 |
144 | - (void)testCoding {
145 | NSData *data = nil;
146 | YYTestModelHashModel *model1 = [YYTestModelHashModel new];
147 | YYTestModelHashModel *model2 = nil;
148 |
149 | model1.intValue = 1;
150 | model1.floatValue = 12.34;
151 | model1.number = @(1234);
152 | model1.string = @"Apple";
153 | model1.sizeValue = CGSizeMake(12, 34);
154 | model1.selectorValue = @selector(stringWithFormat:);
155 | model1.myStructValue = (my_struct){.b = 56.78};
156 | model1.valueValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
157 |
158 | data = [NSKeyedArchiver archivedDataWithRootObject:model1];
159 | model2 = [NSKeyedUnarchiver unarchiveObjectWithData:data];
160 |
161 | XCTAssertEqual(model1.intValue, model2.intValue);
162 | XCTAssertEqual(model1.floatValue, model2.floatValue);
163 | XCTAssertTrue([model1.number isEqual:model2.number]);
164 | XCTAssertTrue([model1.string isEqualToString:model2.string]);
165 | XCTAssertTrue(CGSizeEqualToSize(model1.sizeValue, model2.sizeValue));
166 | XCTAssertTrue(model2.selectorValue == @selector(stringWithFormat:));
167 | XCTAssertTrue(model2.myStructValue.b == 0); // ignore in NSKeyedArchiver
168 | XCTAssertTrue(model2.valueValue == nil); // ignore in NSKeyedArchiver
169 |
170 | // for code coverage
171 | NSArray *array = @[model1, model2];
172 | NSMutableData *mutableData = [NSMutableData new];
173 | NSKeyedArchiver *coder = [[NSKeyedArchiver alloc] initForWritingWithMutableData:mutableData];
174 | [array yy_modelEncodeWithCoder:coder];
175 | [coder finishEncoding];
176 | XCTAssertTrue(mutableData.length > 0);
177 |
178 | mutableData = [NSMutableData new];
179 | coder = [[NSKeyedArchiver alloc] initForWritingWithMutableData:mutableData];
180 | [[NSNull null] yy_modelEncodeWithCoder:coder];
181 | [coder finishEncoding];
182 | XCTAssertTrue(mutableData.length > 0);
183 | }
184 |
185 | @end
186 |
--------------------------------------------------------------------------------
/YYModelTests/YYTestCustomClass.m:
--------------------------------------------------------------------------------
1 | //
2 | // YYTestCustomClass.m
3 | // YYModel
4 | //
5 | // Created by ibireme on 15/11/29.
6 | // Copyright (c) 2015 ibireme.
7 | //
8 | // This source code is licensed under the MIT-style license found in the
9 | // LICENSE file in the root directory of this source tree.
10 | //
11 |
12 | #import
13 | #import "YYModel.h"
14 |
15 | @interface YYBaseUser : NSObject
16 | @property uint64_t uid;
17 | @property NSString *name;
18 | @end
19 |
20 |
21 | @interface YYLocalUser : YYBaseUser
22 | @property NSString *localName;
23 | @end
24 | @implementation YYLocalUser
25 | @end
26 |
27 | @interface YYRemoteUser : YYBaseUser
28 | @property NSString *remoteName;
29 | @end
30 | @implementation YYRemoteUser
31 | @end
32 |
33 |
34 | @implementation YYBaseUser
35 | + (Class)modelCustomClassForDictionary:(NSDictionary*)dictionary {
36 | if (dictionary[@"localName"]) {
37 | return [YYLocalUser class];
38 | } else if (dictionary[@"remoteName"]) {
39 | return [YYRemoteUser class];
40 | }
41 | return [YYBaseUser class];
42 | }
43 | @end
44 |
45 | @interface YYTestCustomClassModel : NSObject
46 | @property (nonatomic, strong) NSArray *users;
47 | @property (nonatomic, strong) NSDictionary *userDict;
48 | @property (nonatomic, strong) NSSet *userSet;
49 | @property (nonatomic, strong) YYBaseUser *user;
50 | @end
51 |
52 | @implementation YYTestCustomClassModel
53 |
54 | + (NSDictionary *)modelContainerPropertyGenericClass {
55 | return @{@"users" : YYBaseUser.class,
56 | @"userDict" : YYBaseUser.class,
57 | @"userSet" : YYBaseUser.class};
58 | }
59 | + (Class)modelCustomClassForDictionary:(NSDictionary*)dictionary {
60 | if (dictionary[@"localName"]) {
61 | return [YYLocalUser class];
62 | } else if (dictionary[@"remoteName"]) {
63 | return [YYRemoteUser class];
64 | }
65 | return nil;
66 | }
67 | @end
68 |
69 |
70 | @interface YYTestCustomClass : XCTestCase
71 |
72 | @end
73 |
74 | @implementation YYTestCustomClass
75 |
76 | - (void)test {
77 | YYTestCustomClassModel *model;
78 | YYBaseUser *user;
79 |
80 | NSDictionary *jsonUserBase = @{@"uid" : @123, @"name" : @"Harry"};
81 | NSDictionary *jsonUserLocal = @{@"uid" : @123, @"name" : @"Harry", @"localName" : @"HarryLocal"};
82 | NSDictionary *jsonUserRemote = @{@"uid" : @123, @"name" : @"Harry", @"remoteName" : @"HarryRemote"};
83 |
84 | user = [YYBaseUser yy_modelWithDictionary:jsonUserBase];
85 | XCTAssert([user isMemberOfClass:[YYBaseUser class]]);
86 |
87 | user = [YYBaseUser yy_modelWithDictionary:jsonUserLocal];
88 | XCTAssert([user isMemberOfClass:[YYLocalUser class]]);
89 |
90 | user = [YYBaseUser yy_modelWithDictionary:jsonUserRemote];
91 | XCTAssert([user isMemberOfClass:[YYRemoteUser class]]);
92 |
93 |
94 | model = [YYTestCustomClassModel yy_modelWithJSON:@{@"user" : jsonUserLocal}];
95 | XCTAssert([model.user isMemberOfClass:[YYLocalUser class]]);
96 |
97 | model = [YYTestCustomClassModel yy_modelWithJSON:@{@"users" : @[jsonUserBase, jsonUserLocal, jsonUserRemote]}];
98 | XCTAssert([model.users[0] isMemberOfClass:[YYBaseUser class]]);
99 | XCTAssert([model.users[1] isMemberOfClass:[YYLocalUser class]]);
100 | XCTAssert([model.users[2] isMemberOfClass:[YYRemoteUser class]]);
101 |
102 | model = [YYTestCustomClassModel yy_modelWithJSON:@{@"userDict" : @{@"a" : jsonUserBase, @"b" : jsonUserLocal, @"c" : jsonUserRemote}}];
103 | XCTAssert([model.userDict[@"a"] isKindOfClass:[YYBaseUser class]]);
104 | XCTAssert([model.userDict[@"b"] isKindOfClass:[YYLocalUser class]]);
105 | XCTAssert([model.userDict[@"c"] isKindOfClass:[YYRemoteUser class]]);
106 |
107 | model = [YYTestCustomClassModel yy_modelWithJSON:@{@"userSet" : @[jsonUserBase, jsonUserLocal, jsonUserRemote]}];
108 | XCTAssert([model.userSet.anyObject isKindOfClass:[YYBaseUser class]]);
109 | }
110 |
111 | @end
112 |
--------------------------------------------------------------------------------
/YYModelTests/YYTestCustomTransform.m:
--------------------------------------------------------------------------------
1 | //
2 | // YYTestCustomTransform.m
3 | // YYModel
4 | //
5 | // Created by ibireme on 15/11/29.
6 | // Copyright (c) 2015 ibireme.
7 | //
8 | // This source code is licensed under the MIT-style license found in the
9 | // LICENSE file in the root directory of this source tree.
10 | //
11 |
12 | #import
13 | #import "YYModel.h"
14 |
15 | @interface YYTestCustomTransformModel : NSObject
16 | @property uint64_t id;
17 | @property NSString *content;
18 | @property NSDate *time;
19 | @end
20 |
21 | @implementation YYTestCustomTransformModel
22 |
23 |
24 | -(NSDictionary *)modelCustomWillTransformFromDictionary:(NSDictionary *)dic{
25 | if (dic) {
26 | NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:dic];
27 | if (dict[@"date"]) {
28 | dict[@"time"] = dict[@"date"];
29 | }
30 | return dict;
31 | }
32 | return dic;
33 | }
34 |
35 | - (BOOL)modelCustomTransformFromDictionary:(NSDictionary *)dic {
36 | NSNumber *time = dic[@"time"];
37 | if ([time isKindOfClass:[NSNumber class]] && time.unsignedLongLongValue != 0) {
38 | _time = [NSDate dateWithTimeIntervalSince1970:time.unsignedLongLongValue / 1000.0];
39 | return YES;
40 | } else {
41 | return NO;
42 | }
43 | }
44 |
45 | - (BOOL)modelCustomTransformToDictionary:(NSMutableDictionary *)dic {
46 | if (_time) {
47 | dic[@"time"] = @((uint64_t)(_time.timeIntervalSince1970 * 1000));
48 | return YES;
49 | } else {
50 | return NO;
51 | }
52 | }
53 |
54 | @end
55 |
56 |
57 |
58 | @interface YYTestCustomTransform : XCTestCase
59 |
60 | @end
61 |
62 | @implementation YYTestCustomTransform
63 |
64 |
65 | - (void)test {
66 | NSString *json;
67 | YYTestCustomTransformModel *model;
68 | NSDictionary *jsonObject;
69 |
70 | json = @"{\"id\":5472746497,\"content\":\"Hello\",\"time\":1401234567000}";
71 | model = [YYTestCustomTransformModel yy_modelWithJSON:json];
72 | XCTAssert(model.time != nil);
73 |
74 | json = @"{\"id\":5472746497,\"content\":\"Hello\"}";
75 | model = [YYTestCustomTransformModel yy_modelWithJSON:json];
76 | XCTAssert(model == nil);
77 |
78 | model = [YYTestCustomTransformModel yy_modelWithDictionary:@{@"id":@5472746497,@"content":@"Hello"}];
79 | XCTAssert(model == nil);
80 |
81 | json = @"{\"id\":5472746497,\"content\":\"Hello\",\"time\":1401234567000}";
82 | model = [YYTestCustomTransformModel yy_modelWithJSON:json];
83 | jsonObject = [model yy_modelToJSONObject];
84 | XCTAssert([jsonObject[@"time"] isKindOfClass:[NSNumber class]]);
85 |
86 | model.time = nil;
87 | jsonObject = [model yy_modelToJSONObject];
88 | XCTAssert(jsonObject == nil);
89 |
90 | json = @"{\"id\":5472746497,\"content\":\"Hello\",\"date\":1401234567000}";
91 | model = [YYTestCustomTransformModel yy_modelWithJSON:json];
92 | XCTAssert(model.time != nil);
93 |
94 | }
95 |
96 | @end
97 |
--------------------------------------------------------------------------------
/YYModelTests/YYTestDescription.m:
--------------------------------------------------------------------------------
1 | //
2 | // YYTestDescription.m
3 | // YYModel
4 | //
5 | // Created by ibireme on 16/1/3.
6 | // Copyright (c) 2016 ibireme.
7 | //
8 | // This source code is licensed under the MIT-style license found in the
9 | // LICENSE file in the root directory of this source tree.
10 | //
11 |
12 | #import
13 | #import "YYModel.h"
14 |
15 |
16 | typedef struct my_struct {
17 | int a;
18 | double b;
19 | long double c;
20 | } my_struct;
21 |
22 | typedef struct my_union {
23 | int a;
24 | double b;
25 | long double c;
26 | } my_union;
27 |
28 |
29 |
30 | @interface YYTestDescriptionModel : NSObject
31 | @property bool boolValue;
32 | @property BOOL BOOLValue;
33 | @property char charValue;
34 | @property unsigned char unsignedCharValue;
35 | @property short shortValue;
36 | @property unsigned short unsignedShortValue;
37 | @property int intValue;
38 | @property unsigned int unsignedIntValue;
39 | @property long longValue;
40 | @property unsigned long unsignedLongValue;
41 | @property long long longLongValue;
42 | @property unsigned long long unsignedLongLongValue;
43 | @property float floatValue;
44 | @property double doubleValue;
45 | @property long double longDoubleValue;
46 | @property (strong) Class classValue;
47 | @property SEL selectorValue;
48 | @property (copy) void (^blockValue)();
49 | @property void *pointerValue;
50 | @property char *cString;
51 | @property CFArrayRef cfArrayValue;
52 | @property NSValue *valueValue;
53 |
54 | @property CGSize sizeValue;
55 | @property CGPoint pointValue;
56 | @property CGRect rectValue;
57 | @property CGAffineTransform transformValue;
58 | @property UIEdgeInsets insetsValue;
59 | @property UIOffset offsetValue;
60 | @property my_struct myStructValue; // invalid for NSKeyedArchiver/Unarchiver
61 | @property my_union myUnionValue; // invalid for NSKeyedArchiver/Unarchiver
62 |
63 |
64 | @property (nonatomic, strong) NSObject *object;
65 | @property (nonatomic, strong) NSNumber *number;
66 | @property (nonatomic, strong) NSDecimalNumber *decimal;
67 | @property (nonatomic, strong) NSString *string;
68 | @property (nonatomic, strong) NSString *string2;
69 | @property (nonatomic, strong) NSMutableString *mString;
70 | @property (nonatomic, strong) NSData *data;
71 | @property (nonatomic, strong) NSMutableData *mData;
72 | @property (nonatomic, strong) NSDate *date;
73 | @property (nonatomic, strong) NSValue *value;
74 | @property (nonatomic, strong) NSURL *url;
75 |
76 | @property (nonatomic, strong) NSArray *array;
77 | @property (nonatomic, strong) NSMutableArray *mArray;
78 | @property (nonatomic, strong) NSDictionary *dict;
79 | @property (nonatomic, strong) NSMutableDictionary *mDict;
80 | @property (nonatomic, strong) NSSet *set;
81 | @property (nonatomic, strong) NSMutableSet *mSet;
82 | @end
83 |
84 | @implementation YYTestDescriptionModel
85 | - (NSString *)description {
86 | return [self yy_modelDescription];
87 | }
88 | @end
89 |
90 |
91 |
92 |
93 | @interface YYTestDescription : XCTestCase
94 |
95 | @end
96 |
97 | @implementation YYTestDescription
98 |
99 | - (void)testDescription {
100 | YYTestDescriptionModel *model = [YYTestDescriptionModel new];
101 | model.string = @"test";
102 | model.intValue = 100;
103 |
104 | model.number = @(123);
105 | model.decimal = [NSDecimalNumber decimalNumberWithString:@"456"];
106 | model.value = [NSValue valueWithRange:NSMakeRange(10, 5)];
107 | model.date = [NSDate new];
108 | model.blockValue = ^{};
109 | model.mData = [NSMutableData data];
110 | for (int i = 0; i < 1024; i++) {
111 | [model.mData appendBytes:&i length:sizeof(int)];
112 | }
113 | model.array = @[];
114 | model.dict = @{};
115 | model.set = [NSSet new];
116 | model.mArray = [NSMutableArray new];
117 | model.mDict = [NSMutableDictionary new];
118 | model.mSet = [NSMutableSet new];
119 |
120 | for (int i = 0; i < 2; i++) {
121 | YYTestDescriptionModel *sub = [YYTestDescriptionModel new];
122 | sub.intValue = i;
123 | [model.mArray addObject:sub];
124 | model.mDict[@(i).description] = sub;
125 | [model.mSet addObject:sub];
126 | }
127 |
128 | NSLog(@"%@",model.description);
129 | }
130 |
131 | @end
132 |
--------------------------------------------------------------------------------
/YYModelTests/YYTestHelper.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYTestHelper.h
3 | // YYModel
4 | //
5 | // Created by ibireme on 15/11/28.
6 | // Copyright (c) 2015 ibireme.
7 | //
8 | // This source code is licensed under the MIT-style license found in the
9 | // LICENSE file in the root directory of this source tree.
10 | //
11 |
12 | #import
13 |
14 | @interface YYTestHelper : NSObject
15 | + (NSString *)jsonStringFromData:(NSData *)data;
16 | + (NSString *)jsonStringFromObject:(id)object;
17 | + (id)jsonObjectFromData:(NSData *)data;
18 | + (id)jsonObjectFromString:(NSString *)string;
19 | + (NSData *)jsonDataFromString:(NSString *)string;
20 | + (NSData *)jsonDataFromObject:(id)object;
21 | @end
22 |
--------------------------------------------------------------------------------
/YYModelTests/YYTestHelper.m:
--------------------------------------------------------------------------------
1 | //
2 | // YYTestHelper.m
3 | // YYModel
4 | //
5 | // Created by ibireme on 15/11/28.
6 | // Copyright (c) 2015 ibireme.
7 | //
8 | // This source code is licensed under the MIT-style license found in the
9 | // LICENSE file in the root directory of this source tree.
10 | //
11 |
12 | #import "YYTestHelper.h"
13 |
14 | @implementation YYTestHelper
15 |
16 | + (NSString *)jsonStringFromData:(NSData *)data {
17 | return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
18 | }
19 |
20 | + (NSString *)jsonStringFromObject:(id)object {
21 | NSData *data = [NSJSONSerialization dataWithJSONObject:object options:0 error:NULL];
22 | return [self jsonStringFromData:data];
23 | }
24 |
25 | + (id)jsonObjectFromData:(NSData *)data {
26 | return [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:NULL];
27 | }
28 |
29 | + (id)jsonObjectFromString:(NSString *)string {
30 | NSData *data = [self jsonDataFromString:string];
31 | return [self jsonObjectFromData:data];
32 | }
33 |
34 | + (NSData *)jsonDataFromString:(NSString *)string {
35 | return [string dataUsingEncoding:NSUTF8StringEncoding];
36 | }
37 |
38 | + (NSData *)jsonDataFromObject:(id)object {
39 | NSString *string = [self jsonStringFromObject:object];
40 | return [self jsonDataFromString:string];
41 | }
42 |
43 | @end
44 |
--------------------------------------------------------------------------------
/YYModelTests/YYTestModelMapper.m:
--------------------------------------------------------------------------------
1 | //
2 | // YYTestModelMapper.m
3 | // YYModel
4 | //
5 | // Created by ibireme on 15/11/27.
6 | // Copyright (c) 2015 ibireme.
7 | //
8 | // This source code is licensed under the MIT-style license found in the
9 | // LICENSE file in the root directory of this source tree.
10 | //
11 |
12 | #import
13 | #import "YYModel.h"
14 |
15 |
16 | @interface YYTestPropertyMapperModelAuto : NSObject
17 | @property (nonatomic, assign) NSString *name;
18 | @property (nonatomic, assign) NSNumber *count;
19 | @end
20 |
21 | @implementation YYTestPropertyMapperModelAuto
22 | @end
23 |
24 | @interface YYTestPropertyMapperModelCustom : NSObject
25 | @property (nonatomic, assign) NSString *name;
26 | @property (nonatomic, assign) NSNumber *count;
27 | @property (nonatomic, assign) NSString *desc1;
28 | @property (nonatomic, assign) NSString *desc2;
29 | @property (nonatomic, assign) NSString *desc3;
30 | @property (nonatomic, assign) NSString *desc4;
31 | @property (nonatomic, assign) NSString *modelID;
32 | @end
33 |
34 | @implementation YYTestPropertyMapperModelCustom
35 | + (NSDictionary *)modelCustomPropertyMapper {
36 | return @{ @"name" : @"n",
37 | @"count" : @"ext.c",
38 | @"desc1" : @"ext.d", // mapped to same key path
39 | @"desc2" : @"ext.d", // mapped to same key path
40 | @"desc3" : @"ext.d.e",
41 | @"desc4" : @".ext",
42 | @"modelID" : @[@"ID", @"Id", @"id", @"ext.id"]};
43 | }
44 | @end
45 |
46 | @interface YYTestPropertyMapperModelWarn : NSObject {
47 | NSString *_description;
48 | }
49 | @property (nonatomic, strong) NSString *description;
50 | @property (nonatomic, strong) NSNumber *id;
51 | @end
52 |
53 | @implementation YYTestPropertyMapperModelWarn
54 | @synthesize description = _description;
55 | @end
56 |
57 |
58 |
59 |
60 |
61 |
62 | @protocol YYTestPropertyMapperModelAuto
63 | @end
64 |
65 | @protocol YYTestPropertyMapperModelCustom
66 | @end
67 |
68 | @protocol YYSimpleProtocol
69 | @end
70 |
71 |
72 | @interface YYTestPropertyMapperModelContainer : NSObject
73 | @property (nonatomic, strong) NSArray *array;
74 | @property (nonatomic, strong) NSMutableArray *mArray;
75 | @property (nonatomic, strong) NSDictionary *dict;
76 | @property (nonatomic, strong) NSMutableDictionary *mDict;
77 | @property (nonatomic, strong) NSSet *set;
78 | @property (nonatomic, strong) NSMutableSet *mSet;
79 |
80 | @property (nonatomic, strong) NSArray *pArray1;
81 | @property (nonatomic, strong) NSArray *pArray2;
82 | @property (nonatomic, strong) NSArray *pArray3;
83 | @end
84 |
85 | @implementation YYTestPropertyMapperModelContainer
86 | @end
87 |
88 | @interface YYTestPropertyMapperModelContainerGeneric : YYTestPropertyMapperModelContainer
89 | @end
90 |
91 | @implementation YYTestPropertyMapperModelContainerGeneric
92 | + (NSDictionary *)modelCustomPropertyMapper {
93 | return @{ @"mArray" : @"array",
94 | @"mDict" : @"dict",
95 | @"mSet" : @"set",
96 | @"pArray1" : @"array",
97 | @"pArray2" : @"array",
98 | @"pArray3" : @"array"};
99 | }
100 | + (NSDictionary *)modelContainerPropertyGenericClass {
101 | return @{@"array" : YYTestPropertyMapperModelAuto.class,
102 | @"mArray" : YYTestPropertyMapperModelAuto.class,
103 | @"dict" : YYTestPropertyMapperModelAuto.class,
104 | @"mDict" : YYTestPropertyMapperModelAuto.class,
105 | @"set" : @"YYTestPropertyMapperModelAuto",
106 | @"mSet" : @"YYTestPropertyMapperModelAuto",
107 | @"pArray3" : @"YYTestPropertyMapperModelAuto"};
108 | }
109 | @end
110 |
111 |
112 |
113 | @interface YYTestModelPropertyMapper : XCTestCase
114 |
115 | @end
116 |
117 | @implementation YYTestModelPropertyMapper
118 |
119 | - (void)testAuto {
120 | NSString *json;
121 | YYTestPropertyMapperModelAuto *model;
122 |
123 | json = @"{\"name\":\"Apple\",\"count\":12}";
124 | model = [YYTestPropertyMapperModelAuto yy_modelWithJSON:json];
125 | XCTAssertTrue([model.name isEqualToString:@"Apple"]);
126 | XCTAssertTrue([model.count isEqual:@12]);
127 |
128 | json = @"{\"n\":\"Apple\",\"count\":12, \"description\":\"hehe\"}";
129 | model = [YYTestPropertyMapperModelAuto yy_modelWithJSON:json];
130 | XCTAssertTrue(model.name == nil);
131 | XCTAssertTrue([model.count isEqual:@12]);
132 | }
133 |
134 | - (void)testCustom {
135 | NSString *json;
136 | NSDictionary *jsonObject;
137 | YYTestPropertyMapperModelCustom *model;
138 |
139 | json = @"{\"n\":\"Apple\",\"ext\":{\"c\":12}}";
140 | model = [YYTestPropertyMapperModelCustom yy_modelWithJSON:json];
141 | XCTAssertTrue([model.name isEqualToString:@"Apple"]);
142 | XCTAssertTrue([model.count isEqual:@12]);
143 |
144 | json = @"{\"n\":\"Apple\",\"count\":12}";
145 | model = [YYTestPropertyMapperModelCustom yy_modelWithJSON:json];
146 | XCTAssertTrue(model.count == nil);
147 |
148 | json = @"{\"n\":\"Apple\",\"ext\":12}";
149 | model = [YYTestPropertyMapperModelCustom yy_modelWithJSON:json];
150 | XCTAssertTrue(model.count == nil);
151 |
152 | json = @"{\"n\":\"Apple\",\"ext\":@{}}";
153 | model = [YYTestPropertyMapperModelCustom yy_modelWithJSON:json];
154 | XCTAssertTrue(model.count == nil);
155 |
156 | json = @"{\"ext\":{\"d\":\"Apple\"}}";
157 | model = [YYTestPropertyMapperModelCustom yy_modelWithJSON:json];
158 | XCTAssertTrue([model.desc1 isEqualToString:@"Apple"]);
159 | XCTAssertTrue([model.desc2 isEqualToString:@"Apple"]);
160 |
161 | jsonObject = [model yy_modelToJSONObject];
162 | XCTAssertTrue([((NSDictionary *)jsonObject[@"ext"])[@"d"] isEqualToString:@"Apple"]);
163 |
164 | json = @"{\"ext\":{\"d\":{ \"e\" : \"Apple\"}}}";
165 | model = [YYTestPropertyMapperModelCustom yy_modelWithJSON:json];
166 | XCTAssertTrue([model.desc3 isEqualToString:@"Apple"]);
167 |
168 | json = @"{\".ext\":\"Apple\"}";
169 | model = [YYTestPropertyMapperModelCustom yy_modelWithJSON:json];
170 | XCTAssertTrue([model.desc4 isEqualToString:@"Apple"]);
171 |
172 | json = @"{\".ext\":\"Apple\", \"name\":\"Apple\", \"count\":\"10\", \"desc1\":\"Apple\", \"desc2\":\"Apple\", \"desc3\":\"Apple\", \"desc4\":\"Apple\", \"modelID\":\"Apple\"}";
173 | model = [YYTestPropertyMapperModelCustom yy_modelWithJSON:json];
174 | XCTAssertTrue([model.desc4 isEqualToString:@"Apple"]);
175 |
176 | json = @"{\"id\":\"abcd\"}";
177 | model = [YYTestPropertyMapperModelCustom yy_modelWithJSON:json];
178 | XCTAssertTrue([model.modelID isEqualToString:@"abcd"]);
179 |
180 | json = @"{\"ext\":{\"id\":\"abcd\"}}";
181 | model = [YYTestPropertyMapperModelCustom yy_modelWithJSON:json];
182 | XCTAssertTrue([model.modelID isEqualToString:@"abcd"]);
183 |
184 | json = @"{\"id\":\"abcd\",\"ID\":\"ABCD\",\"Id\":\"Abcd\"}";
185 | model = [YYTestPropertyMapperModelCustom yy_modelWithJSON:json];
186 | XCTAssertTrue([model.modelID isEqualToString:@"ABCD"]);
187 |
188 | jsonObject = [model yy_modelToJSONObject];
189 | XCTAssertTrue(jsonObject[@"id"] == nil);
190 | XCTAssertTrue([jsonObject[@"ID"] isEqualToString:@"ABCD"]);
191 | }
192 |
193 | - (void)testWarn {
194 | NSString *json = @"{\"description\":\"Apple\",\"id\":12345}";
195 | YYTestPropertyMapperModelWarn *model = [YYTestPropertyMapperModelWarn yy_modelWithJSON:json];
196 | XCTAssertTrue([model.description isEqualToString:@"Apple"]);
197 | XCTAssertTrue([model.id isEqual:@12345]);
198 | }
199 |
200 | - (void)testContainer {
201 | NSString *json;
202 | NSDictionary *jsonObject = nil;
203 | YYTestPropertyMapperModelContainer *model;
204 |
205 | json = @"{\"array\":[\n {\"name\":\"Apple\", \"count\":10},\n {\"name\":\"Banana\", \"count\":11},\n {\"name\":\"Pear\", \"count\":12},\n null\n]}";
206 |
207 | model = [YYTestPropertyMapperModelContainer yy_modelWithJSON:json];
208 | XCTAssertTrue([model.array isKindOfClass:[NSArray class]]);
209 | XCTAssertTrue(model.array.count == 4);
210 |
211 | jsonObject = [model yy_modelToJSONObject];
212 | XCTAssertTrue([jsonObject[@"array"] isKindOfClass:[NSArray class]]);
213 |
214 | model = [YYTestPropertyMapperModelContainerGeneric yy_modelWithJSON:json];
215 | XCTAssertTrue([model.array isKindOfClass:[NSArray class]]);
216 | XCTAssertTrue(model.array.count == 3);
217 | XCTAssertTrue([((YYTestPropertyMapperModelAuto *)model.array[0]).name isEqualToString:@"Apple"]);
218 | XCTAssertTrue([((YYTestPropertyMapperModelAuto *)model.array[0]).count isEqual:@10]);
219 | XCTAssertTrue([((YYTestPropertyMapperModelAuto *)model.array[2]).name isEqualToString:@"Pear"]);
220 | XCTAssertTrue([((YYTestPropertyMapperModelAuto *)model.array[2]).count isEqual:@12]);
221 | XCTAssertTrue([model.mArray isKindOfClass:[NSMutableArray class]]);
222 |
223 | XCTAssertTrue(model.pArray1.count == 3);
224 | XCTAssertTrue([((YYTestPropertyMapperModelAuto *)model.pArray1[0]).name isEqualToString:@"Apple"]);
225 | XCTAssertTrue([((YYTestPropertyMapperModelAuto *)model.pArray1[0]).count isEqual:@10]);
226 | XCTAssertTrue(model.pArray2.count == 3);
227 | XCTAssertTrue([((YYTestPropertyMapperModelAuto *)model.pArray2[0]).name isEqualToString:@"Apple"]);
228 | XCTAssertTrue([((YYTestPropertyMapperModelAuto *)model.pArray2[0]).count isEqual:@10]);
229 | XCTAssertTrue(model.pArray3.count == 3);
230 | XCTAssertTrue([((YYTestPropertyMapperModelAuto *)model.pArray3[0]).name isEqualToString:@"Apple"]);
231 | XCTAssertTrue([((YYTestPropertyMapperModelAuto *)model.pArray3[0]).count isEqual:@10]);
232 |
233 |
234 | jsonObject = [model yy_modelToJSONObject];
235 | XCTAssertTrue([jsonObject[@"array"] isKindOfClass:[NSArray class]]);
236 |
237 | json = @"{\"dict\":{\n \"A\":{\"name\":\"Apple\", \"count\":10},\n \"B\":{\"name\":\"Banana\", \"count\":11},\n \"P\":{\"name\":\"Pear\", \"count\":12},\n \"N\":null\n}}";
238 |
239 | model = [YYTestPropertyMapperModelContainer yy_modelWithJSON:json];
240 | XCTAssertTrue([model.dict isKindOfClass:[NSDictionary class]]);
241 | XCTAssertTrue(model.dict.count == 4);
242 |
243 | jsonObject = [model yy_modelToJSONObject];
244 | XCTAssertTrue(jsonObject != nil);
245 |
246 | model = [YYTestPropertyMapperModelContainerGeneric yy_modelWithJSON:json];
247 | XCTAssertTrue([model.dict isKindOfClass:[NSDictionary class]]);
248 | XCTAssertTrue(model.dict.count == 3);
249 | XCTAssertTrue([((YYTestPropertyMapperModelAuto *)model.dict[@"A"]).name isEqualToString:@"Apple"]);
250 | XCTAssertTrue([((YYTestPropertyMapperModelAuto *)model.dict[@"A"]).count isEqual:@10]);
251 | XCTAssertTrue([((YYTestPropertyMapperModelAuto *)model.dict[@"P"]).name isEqualToString:@"Pear"]);
252 | XCTAssertTrue([((YYTestPropertyMapperModelAuto *)model.dict[@"P"]).count isEqual:@12]);
253 | XCTAssertTrue([model.mDict isKindOfClass:[NSMutableDictionary class]]);
254 |
255 | jsonObject = [model yy_modelToJSONObject];
256 | XCTAssertTrue(jsonObject != nil);
257 |
258 | json = @"{\"set\":[\n {\"name\":\"Apple\", \"count\":10},\n {\"name\":\"Banana\", \"count\":11},\n {\"name\":\"Pear\", \"count\":12},\n null\n]}";
259 |
260 | model = [YYTestPropertyMapperModelContainer yy_modelWithJSON:json];
261 | XCTAssertTrue([model.set isKindOfClass:[NSSet class]]);
262 | XCTAssertTrue(model.set.count == 4);
263 |
264 | jsonObject = [model yy_modelToJSONObject];
265 | XCTAssertTrue(jsonObject != nil);
266 |
267 | model = [YYTestPropertyMapperModelContainerGeneric yy_modelWithJSON:json];
268 | XCTAssertTrue([model.set isKindOfClass:[NSSet class]]);
269 | XCTAssertTrue(model.set.count == 3);
270 | XCTAssertTrue([((YYTestPropertyMapperModelAuto *)model.set.anyObject).name isKindOfClass:[NSString class]]);
271 | XCTAssertTrue([model.mSet isKindOfClass:[NSMutableSet class]]);
272 |
273 | jsonObject = [model yy_modelToJSONObject];
274 | XCTAssertTrue(jsonObject != nil);
275 |
276 | model = [YYTestPropertyMapperModelContainerGeneric yy_modelWithJSON:@{@"set" : @[[YYTestPropertyMapperModelAuto new]]}];
277 | XCTAssertTrue([model.set isKindOfClass:[NSSet class]]);
278 | XCTAssertTrue([[model.set anyObject] isKindOfClass:[YYTestPropertyMapperModelAuto class]]);
279 |
280 | model = [YYTestPropertyMapperModelContainerGeneric yy_modelWithJSON:@{@"array" : [NSSet setWithArray:@[[YYTestPropertyMapperModelAuto new]]]}];
281 | XCTAssertTrue([model.array isKindOfClass:[NSArray class]]);
282 | XCTAssertTrue([[model.array firstObject] isKindOfClass:[YYTestPropertyMapperModelAuto class]]);
283 |
284 | model = [YYTestPropertyMapperModelContainer yy_modelWithJSON:@{@"mArray" : @[[YYTestPropertyMapperModelAuto new]]}];
285 | XCTAssertTrue([model.mArray isKindOfClass:[NSMutableArray class]]);
286 | XCTAssertTrue([[model.mArray firstObject] isKindOfClass:[YYTestPropertyMapperModelAuto class]]);
287 |
288 | model = [YYTestPropertyMapperModelContainer yy_modelWithJSON:@{@"mArray" : [NSSet setWithArray:@[[YYTestPropertyMapperModelAuto new]]]}];
289 | XCTAssertTrue([model.mArray isKindOfClass:[NSMutableArray class]]);
290 | XCTAssertTrue([[model.mArray firstObject] isKindOfClass:[YYTestPropertyMapperModelAuto class]]);
291 | }
292 |
293 | @end
294 |
--------------------------------------------------------------------------------
/YYModelTests/YYTestModelToJSON.m:
--------------------------------------------------------------------------------
1 | //
2 | // YYTestModelToJSON.m
3 | // YYModel
4 | //
5 | // Created by ibireme on 15/11/29.
6 | // Copyright (c) 2015 ibireme.
7 | //
8 | // This source code is licensed under the MIT-style license found in the
9 | // LICENSE file in the root directory of this source tree.
10 | //
11 |
12 | #import
13 | #import
14 | #import "YYModel.h"
15 | #import "YYTestHelper.h"
16 |
17 | @interface YYTestModelToJSONModel : NSObject
18 | @property bool boolValue;
19 | @property BOOL BOOLValue;
20 | @property char charValue;
21 | @property unsigned char unsignedCharValue;
22 | @property short shortValue;
23 | @property unsigned short unsignedShortValue;
24 | @property int intValue;
25 | @property unsigned int unsignedIntValue;
26 | @property long longValue;
27 | @property unsigned long unsignedLongValue;
28 | @property long long longLongValue;
29 | @property unsigned long long unsignedLongLongValue;
30 | @property float floatValue;
31 | @property double doubleValue;
32 | @property long double longDoubleValue;
33 | @property (strong) Class classValue;
34 | @property SEL selectorValue;
35 | @property (copy) void (^blockValue)();
36 | @property void *pointerValue;
37 | @property CGRect structValue;
38 | @property CGPoint pointValue;
39 |
40 | @property (nonatomic, strong) NSObject *object;
41 | @property (nonatomic, strong) NSNumber *number;
42 | @property (nonatomic, strong) NSDecimalNumber *decimal;
43 | @property (nonatomic, strong) NSString *string;
44 | @property (nonatomic, strong) NSMutableString *mString;
45 | @property (nonatomic, strong) NSData *data;
46 | @property (nonatomic, strong) NSMutableData *mData;
47 | @property (nonatomic, strong) NSDate *date;
48 | @property (nonatomic, strong) NSValue *value;
49 | @property (nonatomic, strong) NSURL *url;
50 |
51 | @property (nonatomic, strong) NSArray *array;
52 | @property (nonatomic, strong) NSMutableArray *mArray;
53 | @property (nonatomic, strong) NSDictionary *dict;
54 | @property (nonatomic, strong) NSMutableDictionary *mDict;
55 | @property (nonatomic, strong) NSSet *set;
56 | @property (nonatomic, strong) NSMutableSet *mSet;
57 | @property (nonatomic, strong) UIColor *color;
58 | @end
59 |
60 | @implementation YYTestModelToJSONModel
61 | + (NSDictionary *)modelCustomPropertyMapper {
62 | return @{
63 | @"intValue" : @"int",
64 | @"longValue" : @"long", // mapped to same key
65 | @"unsignedLongLongValue" : @"long", // mapped to same key
66 | @"shortValue" : @"ext.short" // mapped to key path
67 | };
68 | }
69 | @end
70 |
71 |
72 |
73 | @interface YYTestKeyPathModelToJSONModel : NSObject
74 | @property (nonatomic, strong) NSString *a;
75 | @property (nonatomic, strong) NSString *b;
76 | @property (nonatomic, strong) NSString *c;
77 | @property (nonatomic, strong) NSString *d;
78 | @property (nonatomic, strong) NSString *e;
79 | @property (nonatomic, strong) NSDictionary *f;
80 | @property (nonatomic, strong) NSString *g;
81 | @end
82 |
83 | @implementation YYTestKeyPathModelToJSONModel
84 | + (NSDictionary *)modelCustomPropertyMapper {
85 | return @{
86 | @"a" : @"ext.a",
87 | @"b" : @"ext.b",
88 | @"c" : @"ext.a",
89 | @"e" : @"d.e",
90 | @"g" : @"f.g.g"
91 | };
92 | }
93 | @end
94 |
95 |
96 |
97 | @interface YYTestModelToJSON : XCTestCase
98 |
99 | @end
100 |
101 | @implementation YYTestModelToJSON
102 |
103 |
104 | - (void)testToJSON {
105 | YYTestModelToJSONModel *model = [YYTestModelToJSONModel new];
106 | model.intValue = 1;
107 | model.longValue = 2;
108 | model.unsignedLongLongValue = 3;
109 | model.shortValue = 4;
110 | model.array = @[@1,@"2",[NSURL URLWithString:@"https://github.com"]];
111 | model.set = [NSSet setWithArray:model.array];
112 | model.color = [UIColor colorWithRed:1 green:0 blue:0 alpha:0.5];
113 |
114 | NSDictionary *jsonObject = [model yy_modelToJSONObject];
115 | XCTAssert([jsonObject isKindOfClass:[NSDictionary class]]);
116 | XCTAssert([jsonObject[@"int"] isEqual:@(1)]);
117 | XCTAssert([jsonObject[@"long"] isEqual:@(2)] || [jsonObject[@"long"] isEqual:@(3)]);
118 | XCTAssert([ ((NSDictionary *)jsonObject[@"ext"])[@"short"] isEqual:@(4)]);
119 | XCTAssert(jsonObject[@"color"] != nil);
120 |
121 | NSString *jsonString = [model yy_modelToJSONString];
122 | XCTAssert([[YYTestHelper jsonObjectFromString:jsonString] isKindOfClass:[NSDictionary class]]);
123 |
124 | NSData *jsonData = [model yy_modelToJSONData];
125 | XCTAssert([[YYTestHelper jsonObjectFromData:jsonData] isKindOfClass:[NSDictionary class]]);
126 |
127 | model = [YYTestModelToJSONModel yy_modelWithJSON:jsonData];
128 | XCTAssert(model.intValue == 1);
129 | }
130 |
131 | - (void)testKeyPath {
132 | YYTestKeyPathModelToJSONModel *model = [YYTestKeyPathModelToJSONModel new];
133 | model.a = @"a";
134 | model.b = @"b";
135 | model.c = @"c";
136 | model.d = @"d";
137 | model.e = @"e";
138 | model.f = @{};
139 |
140 | NSDictionary *dic = [model yy_modelToJSONObject];
141 | NSDictionary *ext = dic[@"ext"];
142 | XCTAssert([ext[@"b"] isEqualToString:@"b"]);
143 | XCTAssert([ext[@"a"] isEqualToString:@"a"] || [ext[@"a"] isEqualToString:@"c"]);
144 |
145 | model.f = @{@"g" : @""};
146 | dic = [model yy_modelToJSONObject];
147 |
148 | }
149 |
150 | - (void)testDate {
151 | NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
152 | formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
153 | formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ";
154 |
155 | NSDate *date = [NSDate dateWithTimeIntervalSince1970:100000000];
156 | NSString *dateString = [formatter stringFromDate:date];
157 |
158 | YYTestModelToJSONModel *model = [YYTestModelToJSONModel new];
159 | model.date = date;
160 |
161 | NSDictionary *jsonObject = [model yy_modelToJSONObject];
162 | XCTAssert([jsonObject[@"date"] isEqual:dateString]);
163 |
164 | NSString *jsonString = [model yy_modelToJSONString];
165 | YYTestModelToJSONModel *newModel = [YYTestModelToJSONModel yy_modelWithJSON:jsonString];
166 | XCTAssert([newModel.date isEqualToDate:date]);
167 | }
168 |
169 | @end
170 |
--------------------------------------------------------------------------------
/YYModelTests/YYTestNestModel.m:
--------------------------------------------------------------------------------
1 | //
2 | // YYTestNestModel.m
3 | // YYModel
4 | //
5 | // Created by ibireme on 15/11/29.
6 | // Copyright (c) 2015 ibireme.
7 | //
8 | // This source code is licensed under the MIT-style license found in the
9 | // LICENSE file in the root directory of this source tree.
10 | //
11 |
12 | #import
13 | #import "YYModel.h"
14 |
15 |
16 | @interface YYTestNestUser : NSObject
17 | @property uint64_t uid;
18 | @property NSString *name;
19 | @end
20 | @implementation YYTestNestUser
21 | @end
22 |
23 | @interface YYTestNestRepo : NSObject
24 | @property uint64_t repoID;
25 | @property NSString *name;
26 | @property YYTestNestUser *user;
27 | @end
28 | @implementation YYTestNestRepo
29 | @end
30 |
31 |
32 |
33 | @interface YYTestNestModel : XCTestCase
34 |
35 | @end
36 |
37 | @implementation YYTestNestModel
38 |
39 | - (void)test {
40 | NSString *json = @"{\"repoID\":1234,\"name\":\"YYModel\",\"user\":{\"uid\":5678,\"name\":\"ibireme\"}}";
41 | YYTestNestRepo *repo = [YYTestNestRepo yy_modelWithJSON:json];
42 | XCTAssert(repo.repoID == 1234);
43 | XCTAssert([repo.name isEqualToString:@"YYModel"]);
44 | XCTAssert(repo.user.uid == 5678);
45 | XCTAssert([repo.user.name isEqualToString:@"ibireme"]);
46 |
47 | NSDictionary *jsonObject = [repo yy_modelToJSONObject];
48 | XCTAssert([((NSString *)jsonObject[@"name"]) isEqualToString:@"YYModel"]);
49 | XCTAssert([((NSString *)((NSDictionary *)jsonObject[@"user"])[@"name"]) isEqualToString:@"ibireme"]);
50 |
51 | [repo yy_modelSetWithJSON:@{@"name" : @"YYImage", @"user" : @{@"name": @"bot"}}];
52 | XCTAssert(repo.repoID == 1234);
53 | XCTAssert([repo.name isEqualToString:@"YYImage"]);
54 | XCTAssert(repo.user.uid == 5678);
55 | XCTAssert([repo.user.name isEqualToString:@"bot"]);
56 | }
57 |
58 | @end
59 |
--------------------------------------------------------------------------------