├── .gitignore
├── Demo
├── Podfile
├── RealmJSONDemo.xcodeproj
│ └── project.pbxproj
├── RealmJSONDemo
│ ├── Base.lproj
│ │ └── Main.storyboard
│ ├── Images.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ └── Contents.json
│ │ └── LaunchImage.launchimage
│ │ │ └── Contents.json
│ ├── MCAppDelegate.h
│ ├── MCAppDelegate.m
│ ├── MCEpisode.h
│ ├── MCEpisode.m
│ ├── MCTableViewController.h
│ ├── MCTableViewController.m
│ ├── RealmJSONDemo-Info.plist
│ ├── RealmJSONDemo-Prefix.pch
│ ├── en.lproj
│ │ └── InfoPlist.strings
│ └── main.m
└── RealmJSONDemoTests
│ ├── RealmJSONDemoTests-Info.plist
│ ├── RealmJSONDemoTests.m
│ └── en.lproj
│ └── InfoPlist.strings
├── LICENSE
├── README.md
├── Realm+JSON.podspec
└── Realm+JSON
├── MCJSONDateTransformer.h
├── MCJSONDateTransformer.m
├── MCJSONNonNullStringTransformer.h
├── MCJSONNonNullStringTransformer.m
├── MCJSONPrimaryKeyTransformer.h
├── MCJSONPrimaryKeyTransformer.m
├── MCJSONValueTransformer.h
├── MCJSONValueTransformer.m
├── RLMObject+Copying.h
├── RLMObject+Copying.m
├── RLMObject+JSON.h
└── RLMObject+JSON.m
/.gitignore:
--------------------------------------------------------------------------------
1 | # OS X
2 | .DS_Store
3 |
4 | # Xcode
5 | .DS_Store
6 | build/
7 | *.pbxuser
8 | !default.pbxuser
9 | *.mode1v3
10 | !default.mode1v3
11 | *.mode2v3
12 | !default.mode2v3
13 | *.perspectivev3
14 | !default.perspectivev3
15 | *.xcworkspace
16 | !default.xcworkspace
17 | xcuserdata
18 | profile
19 | *.moved-aside
20 | DerivedData
21 | .idea/
22 |
23 | # CocoaPods
24 | Pods
25 | Podfile.lock
26 |
--------------------------------------------------------------------------------
/Demo/Podfile:
--------------------------------------------------------------------------------
1 | source 'https://github.com/CocoaPods/Specs.git'
2 | platform :ios, '7.0'
3 |
4 | pod 'AFNetworking'
5 | pod 'Realm+JSON', :path => '../'
6 |
--------------------------------------------------------------------------------
/Demo/RealmJSONDemo.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | archiveVersion
6 | 1
7 | classes
8 |
9 | objectVersion
10 | 46
11 | objects
12 |
13 | 1EF2988E0D4955BC37C2AB0C
14 |
15 | includeInIndex
16 | 1
17 | isa
18 | PBXFileReference
19 | lastKnownFileType
20 | text.xcconfig
21 | name
22 | Pods.debug.xcconfig
23 | path
24 | Pods/Target Support Files/Pods/Pods.debug.xcconfig
25 | sourceTree
26 | <group>
27 |
28 | 34D5F9921984ACD800BE1BBF
29 |
30 | children
31 |
32 | 34D5F9A41984ACD900BE1BBF
33 | 34D5F9C61984ACD900BE1BBF
34 | 34D5F99D1984ACD900BE1BBF
35 | 34D5F99C1984ACD900BE1BBF
36 | 9290BFDD1548386FF432BF83
37 |
38 | isa
39 | PBXGroup
40 | sourceTree
41 | <group>
42 |
43 | 34D5F9931984ACD800BE1BBF
44 |
45 | attributes
46 |
47 | CLASSPREFIX
48 | MC
49 | LastUpgradeCheck
50 | 0510
51 | ORGANIZATIONNAME
52 | Matthew Cheok
53 | TargetAttributes
54 |
55 | 34D5F9BE1984ACD900BE1BBF
56 |
57 | TestTargetID
58 | 34D5F99A1984ACD900BE1BBF
59 |
60 |
61 |
62 | buildConfigurationList
63 | 34D5F9961984ACD800BE1BBF
64 | compatibilityVersion
65 | Xcode 3.2
66 | developmentRegion
67 | English
68 | hasScannedForEncodings
69 | 0
70 | isa
71 | PBXProject
72 | knownRegions
73 |
74 | en
75 | Base
76 |
77 | mainGroup
78 | 34D5F9921984ACD800BE1BBF
79 | productRefGroup
80 | 34D5F99C1984ACD900BE1BBF
81 | projectDirPath
82 |
83 | projectReferences
84 |
85 | projectRoot
86 |
87 | targets
88 |
89 | 34D5F99A1984ACD900BE1BBF
90 | 34D5F9BE1984ACD900BE1BBF
91 |
92 |
93 | 34D5F9961984ACD800BE1BBF
94 |
95 | buildConfigurations
96 |
97 | 34D5F9CE1984ACD900BE1BBF
98 | 34D5F9CF1984ACD900BE1BBF
99 |
100 | defaultConfigurationIsVisible
101 | 0
102 | defaultConfigurationName
103 | Release
104 | isa
105 | XCConfigurationList
106 |
107 | 34D5F9971984ACD900BE1BBF
108 |
109 | buildActionMask
110 | 2147483647
111 | files
112 |
113 | 34D5F9D81984AEE300BE1BBF
114 | 34D5F9AF1984ACD900BE1BBF
115 | 34D5F9AB1984ACD900BE1BBF
116 | 34D5F9DB1984C84700BE1BBF
117 |
118 | isa
119 | PBXSourcesBuildPhase
120 | runOnlyForDeploymentPostprocessing
121 | 0
122 |
123 | 34D5F9981984ACD900BE1BBF
124 |
125 | buildActionMask
126 | 2147483647
127 | files
128 |
129 | 34D5F9A11984ACD900BE1BBF
130 | 34D5F9A31984ACD900BE1BBF
131 | 34D5F99F1984ACD900BE1BBF
132 | 81665805815743B5997ED31A
133 |
134 | isa
135 | PBXFrameworksBuildPhase
136 | runOnlyForDeploymentPostprocessing
137 | 0
138 |
139 | 34D5F9991984ACD900BE1BBF
140 |
141 | buildActionMask
142 | 2147483647
143 | files
144 |
145 | 34D5F9BA1984ACD900BE1BBF
146 | 34D5F9A91984ACD900BE1BBF
147 | 34D5F9B21984ACD900BE1BBF
148 |
149 | isa
150 | PBXResourcesBuildPhase
151 | runOnlyForDeploymentPostprocessing
152 | 0
153 |
154 | 34D5F99A1984ACD900BE1BBF
155 |
156 | buildConfigurationList
157 | 34D5F9D01984ACD900BE1BBF
158 | buildPhases
159 |
160 | 90A24D59A82C40FDA4D09950
161 | 34D5F9971984ACD900BE1BBF
162 | 34D5F9981984ACD900BE1BBF
163 | 34D5F9991984ACD900BE1BBF
164 | F0A39AD6E14A4087B2748160
165 |
166 | buildRules
167 |
168 | dependencies
169 |
170 | isa
171 | PBXNativeTarget
172 | name
173 | RealmJSONDemo
174 | productName
175 | RealmJSONDemo
176 | productReference
177 | 34D5F99B1984ACD900BE1BBF
178 | productType
179 | com.apple.product-type.application
180 |
181 | 34D5F99B1984ACD900BE1BBF
182 |
183 | explicitFileType
184 | wrapper.application
185 | includeInIndex
186 | 0
187 | isa
188 | PBXFileReference
189 | path
190 | RealmJSONDemo.app
191 | sourceTree
192 | BUILT_PRODUCTS_DIR
193 |
194 | 34D5F99C1984ACD900BE1BBF
195 |
196 | children
197 |
198 | 34D5F99B1984ACD900BE1BBF
199 | 34D5F9BF1984ACD900BE1BBF
200 |
201 | isa
202 | PBXGroup
203 | name
204 | Products
205 | sourceTree
206 | <group>
207 |
208 | 34D5F99D1984ACD900BE1BBF
209 |
210 | children
211 |
212 | 34D5F99E1984ACD900BE1BBF
213 | 34D5F9A01984ACD900BE1BBF
214 | 34D5F9A21984ACD900BE1BBF
215 | 34D5F9C01984ACD900BE1BBF
216 | CCDF13328EF748B29194D191
217 |
218 | isa
219 | PBXGroup
220 | name
221 | Frameworks
222 | sourceTree
223 | <group>
224 |
225 | 34D5F99E1984ACD900BE1BBF
226 |
227 | isa
228 | PBXFileReference
229 | lastKnownFileType
230 | wrapper.framework
231 | name
232 | Foundation.framework
233 | path
234 | System/Library/Frameworks/Foundation.framework
235 | sourceTree
236 | SDKROOT
237 |
238 | 34D5F99F1984ACD900BE1BBF
239 |
240 | fileRef
241 | 34D5F99E1984ACD900BE1BBF
242 | isa
243 | PBXBuildFile
244 |
245 | 34D5F9A01984ACD900BE1BBF
246 |
247 | isa
248 | PBXFileReference
249 | lastKnownFileType
250 | wrapper.framework
251 | name
252 | CoreGraphics.framework
253 | path
254 | System/Library/Frameworks/CoreGraphics.framework
255 | sourceTree
256 | SDKROOT
257 |
258 | 34D5F9A11984ACD900BE1BBF
259 |
260 | fileRef
261 | 34D5F9A01984ACD900BE1BBF
262 | isa
263 | PBXBuildFile
264 |
265 | 34D5F9A21984ACD900BE1BBF
266 |
267 | isa
268 | PBXFileReference
269 | lastKnownFileType
270 | wrapper.framework
271 | name
272 | UIKit.framework
273 | path
274 | System/Library/Frameworks/UIKit.framework
275 | sourceTree
276 | SDKROOT
277 |
278 | 34D5F9A31984ACD900BE1BBF
279 |
280 | fileRef
281 | 34D5F9A21984ACD900BE1BBF
282 | isa
283 | PBXBuildFile
284 |
285 | 34D5F9A41984ACD900BE1BBF
286 |
287 | children
288 |
289 | 34D5F9AD1984ACD900BE1BBF
290 | 34D5F9AE1984ACD900BE1BBF
291 | 34D5F9B01984ACD900BE1BBF
292 | 34D5F9D61984AEE300BE1BBF
293 | 34D5F9D71984AEE300BE1BBF
294 | 34D5F9D91984C84700BE1BBF
295 | 34D5F9DA1984C84700BE1BBF
296 | 34D5F9B91984ACD900BE1BBF
297 | 34D5F9A51984ACD900BE1BBF
298 |
299 | isa
300 | PBXGroup
301 | path
302 | RealmJSONDemo
303 | sourceTree
304 | <group>
305 |
306 | 34D5F9A51984ACD900BE1BBF
307 |
308 | children
309 |
310 | 34D5F9A61984ACD900BE1BBF
311 | 34D5F9A71984ACD900BE1BBF
312 | 34D5F9AA1984ACD900BE1BBF
313 | 34D5F9AC1984ACD900BE1BBF
314 |
315 | isa
316 | PBXGroup
317 | name
318 | Supporting Files
319 | sourceTree
320 | <group>
321 |
322 | 34D5F9A61984ACD900BE1BBF
323 |
324 | isa
325 | PBXFileReference
326 | lastKnownFileType
327 | text.plist.xml
328 | path
329 | RealmJSONDemo-Info.plist
330 | sourceTree
331 | <group>
332 |
333 | 34D5F9A71984ACD900BE1BBF
334 |
335 | children
336 |
337 | 34D5F9A81984ACD900BE1BBF
338 |
339 | isa
340 | PBXVariantGroup
341 | name
342 | InfoPlist.strings
343 | sourceTree
344 | <group>
345 |
346 | 34D5F9A81984ACD900BE1BBF
347 |
348 | isa
349 | PBXFileReference
350 | lastKnownFileType
351 | text.plist.strings
352 | name
353 | en
354 | path
355 | en.lproj/InfoPlist.strings
356 | sourceTree
357 | <group>
358 |
359 | 34D5F9A91984ACD900BE1BBF
360 |
361 | fileRef
362 | 34D5F9A71984ACD900BE1BBF
363 | isa
364 | PBXBuildFile
365 |
366 | 34D5F9AA1984ACD900BE1BBF
367 |
368 | isa
369 | PBXFileReference
370 | lastKnownFileType
371 | sourcecode.c.objc
372 | path
373 | main.m
374 | sourceTree
375 | <group>
376 |
377 | 34D5F9AB1984ACD900BE1BBF
378 |
379 | fileRef
380 | 34D5F9AA1984ACD900BE1BBF
381 | isa
382 | PBXBuildFile
383 |
384 | 34D5F9AC1984ACD900BE1BBF
385 |
386 | isa
387 | PBXFileReference
388 | lastKnownFileType
389 | sourcecode.c.h
390 | path
391 | RealmJSONDemo-Prefix.pch
392 | sourceTree
393 | <group>
394 |
395 | 34D5F9AD1984ACD900BE1BBF
396 |
397 | isa
398 | PBXFileReference
399 | lastKnownFileType
400 | sourcecode.c.h
401 | path
402 | MCAppDelegate.h
403 | sourceTree
404 | <group>
405 |
406 | 34D5F9AE1984ACD900BE1BBF
407 |
408 | isa
409 | PBXFileReference
410 | lastKnownFileType
411 | sourcecode.c.objc
412 | path
413 | MCAppDelegate.m
414 | sourceTree
415 | <group>
416 |
417 | 34D5F9AF1984ACD900BE1BBF
418 |
419 | fileRef
420 | 34D5F9AE1984ACD900BE1BBF
421 | isa
422 | PBXBuildFile
423 |
424 | 34D5F9B01984ACD900BE1BBF
425 |
426 | children
427 |
428 | 34D5F9B11984ACD900BE1BBF
429 |
430 | isa
431 | PBXVariantGroup
432 | name
433 | Main.storyboard
434 | sourceTree
435 | <group>
436 |
437 | 34D5F9B11984ACD900BE1BBF
438 |
439 | isa
440 | PBXFileReference
441 | lastKnownFileType
442 | file.storyboard
443 | name
444 | Base
445 | path
446 | Base.lproj/Main.storyboard
447 | sourceTree
448 | <group>
449 |
450 | 34D5F9B21984ACD900BE1BBF
451 |
452 | fileRef
453 | 34D5F9B01984ACD900BE1BBF
454 | isa
455 | PBXBuildFile
456 |
457 | 34D5F9B91984ACD900BE1BBF
458 |
459 | isa
460 | PBXFileReference
461 | lastKnownFileType
462 | folder.assetcatalog
463 | path
464 | Images.xcassets
465 | sourceTree
466 | <group>
467 |
468 | 34D5F9BA1984ACD900BE1BBF
469 |
470 | fileRef
471 | 34D5F9B91984ACD900BE1BBF
472 | isa
473 | PBXBuildFile
474 |
475 | 34D5F9BB1984ACD900BE1BBF
476 |
477 | buildActionMask
478 | 2147483647
479 | files
480 |
481 | 34D5F9CD1984ACD900BE1BBF
482 |
483 | isa
484 | PBXSourcesBuildPhase
485 | runOnlyForDeploymentPostprocessing
486 | 0
487 |
488 | 34D5F9BC1984ACD900BE1BBF
489 |
490 | buildActionMask
491 | 2147483647
492 | files
493 |
494 | 34D5F9C11984ACD900BE1BBF
495 | 34D5F9C31984ACD900BE1BBF
496 | 34D5F9C21984ACD900BE1BBF
497 |
498 | isa
499 | PBXFrameworksBuildPhase
500 | runOnlyForDeploymentPostprocessing
501 | 0
502 |
503 | 34D5F9BD1984ACD900BE1BBF
504 |
505 | buildActionMask
506 | 2147483647
507 | files
508 |
509 | 34D5F9CB1984ACD900BE1BBF
510 |
511 | isa
512 | PBXResourcesBuildPhase
513 | runOnlyForDeploymentPostprocessing
514 | 0
515 |
516 | 34D5F9BE1984ACD900BE1BBF
517 |
518 | buildConfigurationList
519 | 34D5F9D31984ACD900BE1BBF
520 | buildPhases
521 |
522 | 34D5F9BB1984ACD900BE1BBF
523 | 34D5F9BC1984ACD900BE1BBF
524 | 34D5F9BD1984ACD900BE1BBF
525 |
526 | buildRules
527 |
528 | dependencies
529 |
530 | 34D5F9C51984ACD900BE1BBF
531 |
532 | isa
533 | PBXNativeTarget
534 | name
535 | RealmJSONDemoTests
536 | productName
537 | RealmJSONDemoTests
538 | productReference
539 | 34D5F9BF1984ACD900BE1BBF
540 | productType
541 | com.apple.product-type.bundle.unit-test
542 |
543 | 34D5F9BF1984ACD900BE1BBF
544 |
545 | explicitFileType
546 | wrapper.cfbundle
547 | includeInIndex
548 | 0
549 | isa
550 | PBXFileReference
551 | path
552 | RealmJSONDemoTests.xctest
553 | sourceTree
554 | BUILT_PRODUCTS_DIR
555 |
556 | 34D5F9C01984ACD900BE1BBF
557 |
558 | isa
559 | PBXFileReference
560 | lastKnownFileType
561 | wrapper.framework
562 | name
563 | XCTest.framework
564 | path
565 | Library/Frameworks/XCTest.framework
566 | sourceTree
567 | DEVELOPER_DIR
568 |
569 | 34D5F9C11984ACD900BE1BBF
570 |
571 | fileRef
572 | 34D5F9C01984ACD900BE1BBF
573 | isa
574 | PBXBuildFile
575 |
576 | 34D5F9C21984ACD900BE1BBF
577 |
578 | fileRef
579 | 34D5F99E1984ACD900BE1BBF
580 | isa
581 | PBXBuildFile
582 |
583 | 34D5F9C31984ACD900BE1BBF
584 |
585 | fileRef
586 | 34D5F9A21984ACD900BE1BBF
587 | isa
588 | PBXBuildFile
589 |
590 | 34D5F9C41984ACD900BE1BBF
591 |
592 | containerPortal
593 | 34D5F9931984ACD800BE1BBF
594 | isa
595 | PBXContainerItemProxy
596 | proxyType
597 | 1
598 | remoteGlobalIDString
599 | 34D5F99A1984ACD900BE1BBF
600 | remoteInfo
601 | RealmJSONDemo
602 |
603 | 34D5F9C51984ACD900BE1BBF
604 |
605 | isa
606 | PBXTargetDependency
607 | target
608 | 34D5F99A1984ACD900BE1BBF
609 | targetProxy
610 | 34D5F9C41984ACD900BE1BBF
611 |
612 | 34D5F9C61984ACD900BE1BBF
613 |
614 | children
615 |
616 | 34D5F9CC1984ACD900BE1BBF
617 | 34D5F9C71984ACD900BE1BBF
618 |
619 | isa
620 | PBXGroup
621 | path
622 | RealmJSONDemoTests
623 | sourceTree
624 | <group>
625 |
626 | 34D5F9C71984ACD900BE1BBF
627 |
628 | children
629 |
630 | 34D5F9C81984ACD900BE1BBF
631 | 34D5F9C91984ACD900BE1BBF
632 |
633 | isa
634 | PBXGroup
635 | name
636 | Supporting Files
637 | sourceTree
638 | <group>
639 |
640 | 34D5F9C81984ACD900BE1BBF
641 |
642 | isa
643 | PBXFileReference
644 | lastKnownFileType
645 | text.plist.xml
646 | path
647 | RealmJSONDemoTests-Info.plist
648 | sourceTree
649 | <group>
650 |
651 | 34D5F9C91984ACD900BE1BBF
652 |
653 | children
654 |
655 | 34D5F9CA1984ACD900BE1BBF
656 |
657 | isa
658 | PBXVariantGroup
659 | name
660 | InfoPlist.strings
661 | sourceTree
662 | <group>
663 |
664 | 34D5F9CA1984ACD900BE1BBF
665 |
666 | isa
667 | PBXFileReference
668 | lastKnownFileType
669 | text.plist.strings
670 | name
671 | en
672 | path
673 | en.lproj/InfoPlist.strings
674 | sourceTree
675 | <group>
676 |
677 | 34D5F9CB1984ACD900BE1BBF
678 |
679 | fileRef
680 | 34D5F9C91984ACD900BE1BBF
681 | isa
682 | PBXBuildFile
683 |
684 | 34D5F9CC1984ACD900BE1BBF
685 |
686 | isa
687 | PBXFileReference
688 | lastKnownFileType
689 | sourcecode.c.objc
690 | path
691 | RealmJSONDemoTests.m
692 | sourceTree
693 | <group>
694 |
695 | 34D5F9CD1984ACD900BE1BBF
696 |
697 | fileRef
698 | 34D5F9CC1984ACD900BE1BBF
699 | isa
700 | PBXBuildFile
701 |
702 | 34D5F9CE1984ACD900BE1BBF
703 |
704 | buildSettings
705 |
706 | ALWAYS_SEARCH_USER_PATHS
707 | NO
708 | CLANG_CXX_LANGUAGE_STANDARD
709 | gnu++0x
710 | CLANG_CXX_LIBRARY
711 | libc++
712 | CLANG_ENABLE_MODULES
713 | YES
714 | CLANG_ENABLE_OBJC_ARC
715 | YES
716 | CLANG_WARN_BOOL_CONVERSION
717 | YES
718 | CLANG_WARN_CONSTANT_CONVERSION
719 | YES
720 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE
721 | YES_ERROR
722 | CLANG_WARN_EMPTY_BODY
723 | YES
724 | CLANG_WARN_ENUM_CONVERSION
725 | YES
726 | CLANG_WARN_INT_CONVERSION
727 | YES
728 | CLANG_WARN_OBJC_ROOT_CLASS
729 | YES_ERROR
730 | CLANG_WARN__DUPLICATE_METHOD_MATCH
731 | YES
732 | CODE_SIGN_IDENTITY[sdk=iphoneos*]
733 | iPhone Developer
734 | COPY_PHASE_STRIP
735 | NO
736 | GCC_C_LANGUAGE_STANDARD
737 | gnu99
738 | GCC_DYNAMIC_NO_PIC
739 | NO
740 | GCC_OPTIMIZATION_LEVEL
741 | 0
742 | GCC_PREPROCESSOR_DEFINITIONS
743 |
744 | DEBUG=1
745 | $(inherited)
746 |
747 | GCC_SYMBOLS_PRIVATE_EXTERN
748 | NO
749 | GCC_WARN_64_TO_32_BIT_CONVERSION
750 | YES
751 | GCC_WARN_ABOUT_RETURN_TYPE
752 | YES_ERROR
753 | GCC_WARN_UNDECLARED_SELECTOR
754 | YES
755 | GCC_WARN_UNINITIALIZED_AUTOS
756 | YES_AGGRESSIVE
757 | GCC_WARN_UNUSED_FUNCTION
758 | YES
759 | GCC_WARN_UNUSED_VARIABLE
760 | YES
761 | IPHONEOS_DEPLOYMENT_TARGET
762 | 7.1
763 | ONLY_ACTIVE_ARCH
764 | YES
765 | SDKROOT
766 | iphoneos
767 |
768 | isa
769 | XCBuildConfiguration
770 | name
771 | Debug
772 |
773 | 34D5F9CF1984ACD900BE1BBF
774 |
775 | buildSettings
776 |
777 | ALWAYS_SEARCH_USER_PATHS
778 | NO
779 | CLANG_CXX_LANGUAGE_STANDARD
780 | gnu++0x
781 | CLANG_CXX_LIBRARY
782 | libc++
783 | CLANG_ENABLE_MODULES
784 | YES
785 | CLANG_ENABLE_OBJC_ARC
786 | YES
787 | CLANG_WARN_BOOL_CONVERSION
788 | YES
789 | CLANG_WARN_CONSTANT_CONVERSION
790 | YES
791 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE
792 | YES_ERROR
793 | CLANG_WARN_EMPTY_BODY
794 | YES
795 | CLANG_WARN_ENUM_CONVERSION
796 | YES
797 | CLANG_WARN_INT_CONVERSION
798 | YES
799 | CLANG_WARN_OBJC_ROOT_CLASS
800 | YES_ERROR
801 | CLANG_WARN__DUPLICATE_METHOD_MATCH
802 | YES
803 | CODE_SIGN_IDENTITY[sdk=iphoneos*]
804 | iPhone Developer
805 | COPY_PHASE_STRIP
806 | YES
807 | ENABLE_NS_ASSERTIONS
808 | NO
809 | GCC_C_LANGUAGE_STANDARD
810 | gnu99
811 | GCC_WARN_64_TO_32_BIT_CONVERSION
812 | YES
813 | GCC_WARN_ABOUT_RETURN_TYPE
814 | YES_ERROR
815 | GCC_WARN_UNDECLARED_SELECTOR
816 | YES
817 | GCC_WARN_UNINITIALIZED_AUTOS
818 | YES_AGGRESSIVE
819 | GCC_WARN_UNUSED_FUNCTION
820 | YES
821 | GCC_WARN_UNUSED_VARIABLE
822 | YES
823 | IPHONEOS_DEPLOYMENT_TARGET
824 | 7.1
825 | SDKROOT
826 | iphoneos
827 | VALIDATE_PRODUCT
828 | YES
829 |
830 | isa
831 | XCBuildConfiguration
832 | name
833 | Release
834 |
835 | 34D5F9D01984ACD900BE1BBF
836 |
837 | buildConfigurations
838 |
839 | 34D5F9D11984ACD900BE1BBF
840 | 34D5F9D21984ACD900BE1BBF
841 |
842 | defaultConfigurationIsVisible
843 | 0
844 | defaultConfigurationName
845 | Release
846 | isa
847 | XCConfigurationList
848 |
849 | 34D5F9D11984ACD900BE1BBF
850 |
851 | baseConfigurationReference
852 | 1EF2988E0D4955BC37C2AB0C
853 | buildSettings
854 |
855 | ASSETCATALOG_COMPILER_APPICON_NAME
856 | AppIcon
857 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME
858 | LaunchImage
859 | GCC_PRECOMPILE_PREFIX_HEADER
860 | YES
861 | GCC_PREFIX_HEADER
862 | RealmJSONDemo/RealmJSONDemo-Prefix.pch
863 | INFOPLIST_FILE
864 | RealmJSONDemo/RealmJSONDemo-Info.plist
865 | PRODUCT_NAME
866 | $(TARGET_NAME)
867 | WRAPPER_EXTENSION
868 | app
869 |
870 | isa
871 | XCBuildConfiguration
872 | name
873 | Debug
874 |
875 | 34D5F9D21984ACD900BE1BBF
876 |
877 | baseConfigurationReference
878 | 970782E9E7A985538894C200
879 | buildSettings
880 |
881 | ASSETCATALOG_COMPILER_APPICON_NAME
882 | AppIcon
883 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME
884 | LaunchImage
885 | GCC_PRECOMPILE_PREFIX_HEADER
886 | YES
887 | GCC_PREFIX_HEADER
888 | RealmJSONDemo/RealmJSONDemo-Prefix.pch
889 | INFOPLIST_FILE
890 | RealmJSONDemo/RealmJSONDemo-Info.plist
891 | PRODUCT_NAME
892 | $(TARGET_NAME)
893 | WRAPPER_EXTENSION
894 | app
895 |
896 | isa
897 | XCBuildConfiguration
898 | name
899 | Release
900 |
901 | 34D5F9D31984ACD900BE1BBF
902 |
903 | buildConfigurations
904 |
905 | 34D5F9D41984ACD900BE1BBF
906 | 34D5F9D51984ACD900BE1BBF
907 |
908 | defaultConfigurationIsVisible
909 | 0
910 | defaultConfigurationName
911 | Release
912 | isa
913 | XCConfigurationList
914 |
915 | 34D5F9D41984ACD900BE1BBF
916 |
917 | buildSettings
918 |
919 | BUNDLE_LOADER
920 | $(BUILT_PRODUCTS_DIR)/RealmJSONDemo.app/RealmJSONDemo
921 | FRAMEWORK_SEARCH_PATHS
922 |
923 | $(SDKROOT)/Developer/Library/Frameworks
924 | $(inherited)
925 | $(DEVELOPER_FRAMEWORKS_DIR)
926 |
927 | GCC_PRECOMPILE_PREFIX_HEADER
928 | YES
929 | GCC_PREFIX_HEADER
930 | RealmJSONDemo/RealmJSONDemo-Prefix.pch
931 | GCC_PREPROCESSOR_DEFINITIONS
932 |
933 | DEBUG=1
934 | $(inherited)
935 |
936 | INFOPLIST_FILE
937 | RealmJSONDemoTests/RealmJSONDemoTests-Info.plist
938 | PRODUCT_NAME
939 | $(TARGET_NAME)
940 | TEST_HOST
941 | $(BUNDLE_LOADER)
942 | WRAPPER_EXTENSION
943 | xctest
944 |
945 | isa
946 | XCBuildConfiguration
947 | name
948 | Debug
949 |
950 | 34D5F9D51984ACD900BE1BBF
951 |
952 | buildSettings
953 |
954 | BUNDLE_LOADER
955 | $(BUILT_PRODUCTS_DIR)/RealmJSONDemo.app/RealmJSONDemo
956 | FRAMEWORK_SEARCH_PATHS
957 |
958 | $(SDKROOT)/Developer/Library/Frameworks
959 | $(inherited)
960 | $(DEVELOPER_FRAMEWORKS_DIR)
961 |
962 | GCC_PRECOMPILE_PREFIX_HEADER
963 | YES
964 | GCC_PREFIX_HEADER
965 | RealmJSONDemo/RealmJSONDemo-Prefix.pch
966 | INFOPLIST_FILE
967 | RealmJSONDemoTests/RealmJSONDemoTests-Info.plist
968 | PRODUCT_NAME
969 | $(TARGET_NAME)
970 | TEST_HOST
971 | $(BUNDLE_LOADER)
972 | WRAPPER_EXTENSION
973 | xctest
974 |
975 | isa
976 | XCBuildConfiguration
977 | name
978 | Release
979 |
980 | 34D5F9D61984AEE300BE1BBF
981 |
982 | fileEncoding
983 | 4
984 | isa
985 | PBXFileReference
986 | lastKnownFileType
987 | sourcecode.c.h
988 | path
989 | MCTableViewController.h
990 | sourceTree
991 | <group>
992 |
993 | 34D5F9D71984AEE300BE1BBF
994 |
995 | fileEncoding
996 | 4
997 | isa
998 | PBXFileReference
999 | lastKnownFileType
1000 | sourcecode.c.objc
1001 | path
1002 | MCTableViewController.m
1003 | sourceTree
1004 | <group>
1005 |
1006 | 34D5F9D81984AEE300BE1BBF
1007 |
1008 | fileRef
1009 | 34D5F9D71984AEE300BE1BBF
1010 | isa
1011 | PBXBuildFile
1012 |
1013 | 34D5F9D91984C84700BE1BBF
1014 |
1015 | fileEncoding
1016 | 4
1017 | isa
1018 | PBXFileReference
1019 | lastKnownFileType
1020 | sourcecode.c.h
1021 | path
1022 | MCEpisode.h
1023 | sourceTree
1024 | <group>
1025 |
1026 | 34D5F9DA1984C84700BE1BBF
1027 |
1028 | fileEncoding
1029 | 4
1030 | isa
1031 | PBXFileReference
1032 | lastKnownFileType
1033 | sourcecode.c.objc
1034 | path
1035 | MCEpisode.m
1036 | sourceTree
1037 | <group>
1038 |
1039 | 34D5F9DB1984C84700BE1BBF
1040 |
1041 | fileRef
1042 | 34D5F9DA1984C84700BE1BBF
1043 | isa
1044 | PBXBuildFile
1045 |
1046 | 81665805815743B5997ED31A
1047 |
1048 | fileRef
1049 | CCDF13328EF748B29194D191
1050 | isa
1051 | PBXBuildFile
1052 |
1053 | 90A24D59A82C40FDA4D09950
1054 |
1055 | buildActionMask
1056 | 2147483647
1057 | files
1058 |
1059 | inputPaths
1060 |
1061 | isa
1062 | PBXShellScriptBuildPhase
1063 | name
1064 | Check Pods Manifest.lock
1065 | outputPaths
1066 |
1067 | runOnlyForDeploymentPostprocessing
1068 | 0
1069 | shellPath
1070 | /bin/sh
1071 | shellScript
1072 | diff "${PODS_ROOT}/../Podfile.lock" "${PODS_ROOT}/Manifest.lock" > /dev/null
1073 | if [[ $? != 0 ]] ; then
1074 | cat << EOM
1075 | error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.
1076 | EOM
1077 | exit 1
1078 | fi
1079 |
1080 | showEnvVarsInLog
1081 | 0
1082 |
1083 | 9290BFDD1548386FF432BF83
1084 |
1085 | children
1086 |
1087 | 1EF2988E0D4955BC37C2AB0C
1088 | 970782E9E7A985538894C200
1089 |
1090 | isa
1091 | PBXGroup
1092 | name
1093 | Pods
1094 | sourceTree
1095 | <group>
1096 |
1097 | 970782E9E7A985538894C200
1098 |
1099 | includeInIndex
1100 | 1
1101 | isa
1102 | PBXFileReference
1103 | lastKnownFileType
1104 | text.xcconfig
1105 | name
1106 | Pods.release.xcconfig
1107 | path
1108 | Pods/Target Support Files/Pods/Pods.release.xcconfig
1109 | sourceTree
1110 | <group>
1111 |
1112 | CCDF13328EF748B29194D191
1113 |
1114 | explicitFileType
1115 | archive.ar
1116 | includeInIndex
1117 | 0
1118 | isa
1119 | PBXFileReference
1120 | path
1121 | libPods.a
1122 | sourceTree
1123 | BUILT_PRODUCTS_DIR
1124 |
1125 | F0A39AD6E14A4087B2748160
1126 |
1127 | buildActionMask
1128 | 2147483647
1129 | files
1130 |
1131 | inputPaths
1132 |
1133 | isa
1134 | PBXShellScriptBuildPhase
1135 | name
1136 | Copy Pods Resources
1137 | outputPaths
1138 |
1139 | runOnlyForDeploymentPostprocessing
1140 | 0
1141 | shellPath
1142 | /bin/sh
1143 | shellScript
1144 | "${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh"
1145 |
1146 | showEnvVarsInLog
1147 | 0
1148 |
1149 |
1150 | rootObject
1151 | 34D5F9931984ACD800BE1BBF
1152 |
1153 |
1154 |
--------------------------------------------------------------------------------
/Demo/RealmJSONDemo/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
45 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/Demo/RealmJSONDemo/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "40x40",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "60x60",
16 | "scale" : "2x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/Demo/RealmJSONDemo/Images.xcassets/LaunchImage.launchimage/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "orientation" : "portrait",
5 | "idiom" : "iphone",
6 | "extent" : "full-screen",
7 | "minimum-system-version" : "7.0",
8 | "scale" : "2x"
9 | },
10 | {
11 | "orientation" : "portrait",
12 | "idiom" : "iphone",
13 | "subtype" : "retina4",
14 | "extent" : "full-screen",
15 | "minimum-system-version" : "7.0",
16 | "scale" : "2x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/Demo/RealmJSONDemo/MCAppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // MCAppDelegate.h
3 | // RealmJSONDemo
4 | //
5 | // Created by Matthew Cheok on 27/7/14.
6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface MCAppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/Demo/RealmJSONDemo/MCAppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // MCAppDelegate.m
3 | // RealmJSONDemo
4 | //
5 | // Created by Matthew Cheok on 27/7/14.
6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved.
7 | //
8 |
9 | #import "MCAppDelegate.h"
10 |
11 | @implementation MCAppDelegate
12 |
13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
14 | {
15 | // Override point for customization after application launch.
16 | return YES;
17 | }
18 |
19 | - (void)applicationWillResignActive:(UIApplication *)application
20 | {
21 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
22 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
23 | }
24 |
25 | - (void)applicationDidEnterBackground:(UIApplication *)application
26 | {
27 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
28 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
29 | }
30 |
31 | - (void)applicationWillEnterForeground:(UIApplication *)application
32 | {
33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | - (void)applicationDidBecomeActive:(UIApplication *)application
37 | {
38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
39 | }
40 |
41 | - (void)applicationWillTerminate:(UIApplication *)application
42 | {
43 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
44 | }
45 |
46 | @end
47 |
--------------------------------------------------------------------------------
/Demo/RealmJSONDemo/MCEpisode.h:
--------------------------------------------------------------------------------
1 | //
2 | // MCEpisode.h
3 | // RealmJSONDemo
4 | //
5 | // Created by Matthew Cheok on 27/7/14.
6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | typedef NS_ENUM(NSInteger, MCEpisodeType) {
12 | MCEpisodeTypeFree = 0,
13 | MCEpisodeTypePaid
14 | };
15 |
16 | @interface MCEpisode : RLMObject
17 |
18 | @property NSInteger episodeID;
19 | @property NSInteger episodeNumber;
20 | @property MCEpisodeType episodeType;
21 |
22 | @property NSString *title;
23 | @property NSString *subtitle;
24 | @property NSString *thumbnailURL;
25 |
26 | @property NSDate *publishedDate;
27 |
28 | @end
29 |
30 | // This protocol enables typed collections. i.e.:
31 | // RLMArray
32 | RLM_ARRAY_TYPE(MCEpisode)
33 |
--------------------------------------------------------------------------------
/Demo/RealmJSONDemo/MCEpisode.m:
--------------------------------------------------------------------------------
1 | //
2 | // MCEpisode.m
3 | // RealmJSONDemo
4 | //
5 | // Created by Matthew Cheok on 27/7/14.
6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved.
7 | //
8 |
9 | #import "MCEpisode.h"
10 | #import "RLMObject+JSON.h"
11 |
12 | @implementation MCEpisode
13 |
14 | + (NSDictionary *)JSONInboundMappingDictionary {
15 | return @{
16 | @"title": @"title",
17 | @"description": @"subtitle",
18 | @"id": @"episodeID",
19 | @"episode_number": @"episodeNumber",
20 | @"episode_type": @"episodeType",
21 | @"thumbnail_url": @"thumbnailURL",
22 | @"published_at": @"publishedDate",
23 | };
24 | }
25 |
26 | + (NSDictionary *)JSONOutboundMappingDictionary {
27 | return @{
28 | @"title": @"title",
29 | @"subtitle": @"episode.description",
30 | @"episodeID": @"id",
31 | @"episodeNumber": @"episode.number",
32 | @"publishedDate": @"published_at",
33 | };
34 | }
35 |
36 | + (NSString *)primaryKey {
37 | return @"episodeID";
38 | }
39 |
40 | + (NSValueTransformer *)episodeTypeJSONTransformer {
41 | return [MCJSONValueTransformer valueTransformerWithMappingDictionary:@{
42 | @"free": @(MCEpisodeTypeFree),
43 | @"paid": @(MCEpisodeTypePaid)
44 | }];
45 | }
46 |
47 | // Specify default values for properties
48 |
49 | + (NSDictionary *)defaultPropertyValues {
50 | return @{ @"publishedDate": [NSDate date] };
51 | }
52 |
53 | // Specify properties to ignore (Realm won't persist these)
54 |
55 | //+ (NSArray *)ignoredProperties
56 | //{
57 | // return @[];
58 | //}
59 |
60 | @end
61 |
--------------------------------------------------------------------------------
/Demo/RealmJSONDemo/MCTableViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // MCTableViewController.h
3 | // RealmJSONDemo
4 | //
5 | // Created by Matthew Cheok on 27/7/14.
6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface MCTableViewController : UITableViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Demo/RealmJSONDemo/MCTableViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // MCTableViewController.m
3 | // RealmJSONDemo
4 | //
5 | // Created by Matthew Cheok on 27/7/14.
6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved.
7 | //
8 |
9 | #import "MCTableViewController.h"
10 | #import "MCEpisode.h"
11 |
12 | #import
13 | #import
14 |
15 | #import
16 | #import
17 |
18 | @interface MCTableViewController ()
19 |
20 | @property (nonatomic, strong) RLMResults *results;
21 | @property (nonatomic, strong) RLMNotificationToken *token;
22 |
23 | @end
24 |
25 | @implementation MCTableViewController
26 |
27 | #pragma mark - Methods
28 |
29 | - (IBAction)reloadData {
30 | AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
31 | [manager GET:@"https://www.nsscreencast.com/api/episodes.json" parameters:nil success: ^(AFHTTPRequestOperation *operation, id responseObject) {
32 | NSArray *array = responseObject[@"episodes"];
33 | dispatch_async(dispatch_get_main_queue(), ^{
34 | RLMRealm *realm = [RLMRealm defaultRealm];
35 |
36 | [realm beginWriteTransaction];
37 | NSArray *result = [MCEpisode createOrUpdateInRealm:realm withJSONArray:array];
38 | [realm commitWriteTransaction];
39 |
40 | NSLog(@"result: %@", result);
41 | });
42 | } failure: ^(AFHTTPRequestOperation *operation, NSError *error) {
43 | NSLog(@"Error: %@", error);
44 | }];
45 | }
46 |
47 | - (void)refreshData {
48 | self.results = [[MCEpisode allObjectsInRealm:[RLMRealm defaultRealm]] sortedResultsUsingProperty:@"publishedDate" ascending:NO];
49 | [self.tableView reloadData];
50 | }
51 |
52 | #pragma mark - UIViewController
53 |
54 | - (void)viewDidLoad {
55 | [super viewDidLoad];
56 |
57 | self.token = [[RLMRealm defaultRealm] addNotificationBlock: ^(NSString *notification, RLMRealm *realm) {
58 | [self refreshData];
59 | }];
60 | [self refreshData];
61 | [self reloadData];
62 | }
63 |
64 | - (void)didReceiveMemoryWarning {
65 | [super didReceiveMemoryWarning];
66 | // Dispose of any resources that can be recreated.
67 | }
68 |
69 | #pragma mark - UITableViewDataSource
70 |
71 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
72 | return 1;
73 | }
74 |
75 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
76 | return self.results.count;
77 | }
78 |
79 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
80 | static NSDateFormatter *dateFormatter = nil;
81 | if (!dateFormatter) {
82 | dateFormatter = [[NSDateFormatter alloc] init];
83 | dateFormatter.dateStyle = NSDateFormatterMediumStyle;
84 | dateFormatter.timeStyle = NSDateFormatterShortStyle;
85 | }
86 |
87 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
88 | MCEpisode *episode = self.results[indexPath.row];
89 |
90 | cell.textLabel.text = episode.title;
91 | cell.detailTextLabel.text = [dateFormatter stringFromDate:episode.publishedDate];
92 | cell.imageView.image = nil;
93 | cell.backgroundColor = episode.episodeType == MCEpisodeTypePaid ? [UIColor colorWithRed:0.996 green:0.839 blue:0.843 alpha:1]: nil;
94 |
95 | __weak UITableViewCell *weakCell = cell;
96 | [cell.imageView setImageWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:episode.thumbnailURL]] placeholderImage:nil success: ^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
97 | weakCell.imageView.image = image;
98 | [weakCell setNeedsLayout];
99 | } failure:nil];
100 |
101 | return cell;
102 | }
103 |
104 | @end
105 |
--------------------------------------------------------------------------------
/Demo/RealmJSONDemo/RealmJSONDemo-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | ${PRODUCT_NAME}
9 | CFBundleExecutable
10 | ${EXECUTABLE_NAME}
11 | CFBundleIdentifier
12 | com.matthewcheok.${PRODUCT_NAME:rfc1034identifier}
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | ${PRODUCT_NAME}
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1.0
25 | LSRequiresIPhoneOS
26 |
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UIStatusBarTintParameters
34 |
35 | UINavigationBar
36 |
37 | Style
38 | UIBarStyleDefault
39 | Translucent
40 |
41 |
42 |
43 | UISupportedInterfaceOrientations
44 |
45 | UIInterfaceOrientationPortrait
46 | UIInterfaceOrientationLandscapeLeft
47 | UIInterfaceOrientationLandscapeRight
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/Demo/RealmJSONDemo/RealmJSONDemo-Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix header
3 | //
4 | // The contents of this file are implicitly included at the beginning of every source file.
5 | //
6 |
7 | #import
8 |
9 | #ifndef __IPHONE_5_0
10 | #warning "This project uses features only available in iOS SDK 5.0 and later."
11 | #endif
12 |
13 | #ifdef __OBJC__
14 | #import
15 | #import
16 | #endif
17 |
--------------------------------------------------------------------------------
/Demo/RealmJSONDemo/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/Demo/RealmJSONDemo/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // RealmJSONDemo
4 | //
5 | // Created by Matthew Cheok on 27/7/14.
6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "MCAppDelegate.h"
12 |
13 | int main(int argc, char * argv[])
14 | {
15 | @autoreleasepool {
16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([MCAppDelegate class]));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Demo/RealmJSONDemoTests/RealmJSONDemoTests-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | com.matthewcheok.${PRODUCT_NAME:rfc1034identifier}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundlePackageType
14 | BNDL
15 | CFBundleShortVersionString
16 | 1.0
17 | CFBundleSignature
18 | ????
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Demo/RealmJSONDemoTests/RealmJSONDemoTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // RealmJSONDemoTests.m
3 | // RealmJSONDemoTests
4 | //
5 | // Created by Matthew Cheok on 27/7/14.
6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface RealmJSONDemoTests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation RealmJSONDemoTests
16 |
17 | - (void)setUp
18 | {
19 | [super setUp];
20 | // Put setup code here. This method is called before the invocation of each test method in the class.
21 | }
22 |
23 | - (void)tearDown
24 | {
25 | // Put teardown code here. This method is called after the invocation of each test method in the class.
26 | [super tearDown];
27 | }
28 |
29 | - (void)testExample
30 | {
31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__);
32 | }
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/Demo/RealmJSONDemoTests/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013 Matthew Cheok
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | 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, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Realm+JSON 
2 | ==========
3 |
4 | [](https://github.com/matthewcheok/Realm-JSON)
5 | [](https://github.com/matthewcheok/Realm-JSON)
6 |
7 | A concise [Mantle](https://github.com/Mantle/Mantle)-like way of working with [Realm](https://github.com/realm/realm-cocoa) and JSON.
8 |
9 | ## Breaking Change
10 |
11 | - Method `- deepCopy` replaces the previous functionality of `- shallowCopy`, which no longer maintains an object's primary key
12 | - Updated to use native primary key support in Realm 0.85.0
13 | - Update your code to use methods `-createOrUpdateInRealm:withJSONArray:` or `-createOrUpdateInRealm:withJSONDictionary:`
14 | - You must wrap these methods in a write transaction (between `[realm beginWriteTransaction];` and `[realm commitWriteTransaction];`)
15 | - These methods call `-createOrUpdateInRealm:withObject:` behind the scenes for performance.
16 |
17 | ## Installation
18 |
19 | Add the following to your [CocoaPods](http://cocoapods.org/) Podfile
20 |
21 | pod 'Realm+JSON', '~> 0.2'
22 |
23 | or clone as a git submodule,
24 |
25 | or just copy files in the ```Realm+JSON``` folder into your project.
26 |
27 | ## Using Realm+JSON
28 |
29 | Simply declare your model as normal:
30 |
31 | typedef NS_ENUM(NSInteger, MCEpisodeType) {
32 | MCEpisodeTypeFree = 0,
33 | MCEpisodeTypePaid
34 | };
35 |
36 | @interface MCEpisode : RLMObject
37 |
38 | @property NSInteger episodeID;
39 | @property NSInteger episodeNumber;
40 | @property MCEpisodeType episodeType;
41 |
42 | @property NSString *title;
43 | @property NSString *subtitle;
44 | @property NSString *thumbnailURL;
45 |
46 | @property NSDate *publishedDate;
47 |
48 | @end
49 |
50 | RLM_ARRAY_TYPE(MCEpisode)
51 |
52 | Then pass the result of `NSJSONSerialization` or `AFNetworking` as follows:
53 |
54 | [MCEpisode createOrUpdateInRealm:[RLMRealm defaultRealm] withJSONArray:array];
55 |
56 | or
57 |
58 | [MCEpisode createOrUpdateInRealm:[RLMRealm defaultRealm] withJSONDictionary:dictionary];
59 |
60 | Use the `-JSONDictionary` method to get a JSON-ready dictionary for your network requests.
61 |
62 | ### Configuration
63 |
64 | You should specify the inbound and outbound JSON mapping on your `RLMObject` subclass like this:
65 |
66 | + (NSDictionary *)JSONInboundMappingDictionary {
67 | return @{
68 | @"episode.title": @"title",
69 | @"episode.description": @"subtitle",
70 | @"episode.id": @"episodeID",
71 | @"episode.episode_number": @"episodeNumber",
72 | @"episode.episode_type": @"episodeType",
73 | @"episode.thumbnail_url": @"thumbnailURL",
74 | @"episode.published_at": @"publishedDate",
75 | };
76 | }
77 |
78 | + (NSDictionary *)JSONOutboundMappingDictionary {
79 | return @{
80 | @"title": @"title",
81 | @"subtitle": @"episode.description",
82 | @"episodeID": @"id",
83 | @"episodeNumber": @"episode.number",
84 | @"publishedDate": @"published_at",
85 | };
86 | }
87 |
88 | JSON preprocessing can be done by implementing `jsonPreprocessing:` static method:
89 |
90 | ```ObjC
91 | - (NSDictionary *)jsonPreprocessing:(NSDictionary *)dictionary {
92 | NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithDictionary:dictionary];
93 | dict[@"releaseCount"] = @(0);
94 | return dict.copy;
95 | }
96 | ```
97 |
98 | Leaving out either one of the above will result in a mapping that assumes camelCase for your properties which map to snake_case for the JSON equivalents.
99 |
100 | As you can do with Mantle, you can specify `NSValueTransformers` for your properties:
101 |
102 | + (NSValueTransformer *)episodeTypeJSONTransformer {
103 | return [MCJSONValueTransformer valueTransformerWithMappingDictionary:@{
104 | @"free": @(MCEpisodeTypeFree),
105 | @"paid": @(MCEpisodeTypePaid)
106 | }];
107 | }
108 |
109 | ## Working with background threads
110 |
111 | Realm requires that you use different `RLMRealm` objects when working across different threads. This means you shouldn't access the same `RLMObject` instances from different threads. To make this easier to work with, use `- primaryKeyValue` to retrieve the wrapped primary key value from an instance and query for it later using `+ objectInRealm:withPrimaryKeyValue:`.
112 |
113 | id primaryKeyValue = [episode primaryKeyValue];
114 | dispatch_async(dispatch_get_main_queue(), ^{
115 | MCEpisode *episode = [MCEpisode objectInRealm:[RLMRealm defaultRealm] withPrimaryKeyValue:primaryKeyValue];
116 |
117 | // do something with episode here
118 | });
119 |
120 |
121 | ## Working with (temporary) copies (RLMObject+Copying)
122 |
123 | If you need to display UI that may or may not change an object's properties, it is sometimes useful to work with an object not bound to a realm as a backing model object. When it is time to commit changes, the properties can be copied back to the stored model.
124 |
125 | Methods `- shallowCopy` and `- mergePropertiesFromObject:` are provided. The later of which needs to be performed in a realm transaction.
126 |
127 | #import
128 |
129 | MCEpisode *anotherEpisode = [episode shallowCopy];
130 | anotherEpisode.title = @"New title";
131 |
132 | // ...
133 |
134 | [episode performInTransaction:^{
135 | [episode mergePropertiesFromObject:anotherEpisode];
136 | }];
137 |
138 | Additionally, method `- deepCopy` is provided. Unlike `- shallowCopy`, it maintains the object's primary key.
139 |
140 | ## License
141 |
142 | Realm+JSON is under the MIT license.
143 |
--------------------------------------------------------------------------------
/Realm+JSON.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = 'Realm+JSON'
3 | s.version = '0.2.16'
4 | s.ios.deployment_target = '7.0'
5 | s.osx.deployment_target = '10.9'
6 | s.watchos.deployment_target = '2.0'
7 | s.license = { :type => 'MIT', :file => 'LICENSE' }
8 | s.summary = 'A concise Mantle-like way of working with Realm and JSON.'
9 | s.homepage = 'https://github.com/matthewcheok/Realm-JSON'
10 | s.author = { 'Matthew Cheok' => 'cheok.jz@gmail.com' }
11 | s.requires_arc = true
12 | s.source = {
13 | :git => 'https://github.com/matthewcheok/Realm-JSON.git',
14 | :branch => 'master',
15 | :tag => s.version.to_s
16 | }
17 | s.source_files = 'Realm+JSON/*.{h,m}'
18 | s.public_header_files = 'Realm+JSON/*.h'
19 |
20 | s.dependency 'Realm', '~> 1.0'
21 | end
22 |
--------------------------------------------------------------------------------
/Realm+JSON/MCJSONDateTransformer.h:
--------------------------------------------------------------------------------
1 | //
2 | // MCJSONDateTransformer.h
3 | // RealmJSONDemo
4 | //
5 | // Created by Matthew Cheok on 27/7/14.
6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | extern NSString* const MCJSONDateTimeTransformerName;
12 | extern NSString* const MCJSONDateTimeMillisecondTransformerName;
13 | extern NSString* const MCJSONDateOnlyTransformerName;
14 |
15 | typedef NS_ENUM(NSInteger, MCJSONDateTransformerStyle) {
16 | MCJSONDateTransformerStyleDateTime = 0,
17 | MCJSONDateTransformerStyleDateTimeMillisecond,
18 | MCJSONDateTransformerStyleDateOnly
19 | };
20 |
21 | @interface MCJSONDateTransformer : NSValueTransformer
22 |
23 | + (instancetype)valueTransformerWithDateStyle:(MCJSONDateTransformerStyle)style;
24 | - (instancetype)initWithDateStyle:(MCJSONDateTransformerStyle)style;
25 | + (instancetype)valueTransformerWithDateFormat:(NSString *)dateFormat;
26 | - (instancetype)initWithDateFormat:(NSString *)dateFormat;
27 |
28 | @end
29 |
--------------------------------------------------------------------------------
/Realm+JSON/MCJSONDateTransformer.m:
--------------------------------------------------------------------------------
1 | //
2 | // MCJSONDateTransformer.m
3 | // RealmJSONDemo
4 | //
5 | // Created by Matthew Cheok on 27/7/14.
6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved.
7 | //
8 |
9 | #import "MCJSONDateTransformer.h"
10 |
11 | NSString* const MCJSONDateTimeTransformerName = @"MCJSONDateTimeTransformerName";
12 | NSString* const MCJSONDateTimeMillisecondTransformerName = @"MCJSONDateTimeMillisecondTransformerName";
13 | NSString* const MCJSONDateOnlyTransformerName = @"MCJSONDateOnlyTransformerName";
14 | static NSString *const kDateFormatDateTime = @"yyyy-MM-dd'T'HH:mm:ssZZZZZ";
15 | static NSString *const kDateFormatDateTimeMillisecond = @"yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ";
16 | static NSString *const kDateFormatDateOnly = @"yyyy-MM-dd";
17 |
18 | @interface MCJSONDateTransformer ()
19 |
20 | @property (nonatomic, strong) NSDateFormatter *formatter;
21 |
22 | @end
23 |
24 | @implementation MCJSONDateTransformer
25 |
26 | + (void)load {
27 | [NSValueTransformer setValueTransformer:[[self alloc] initWithDateStyle:MCJSONDateTransformerStyleDateTime] forName:MCJSONDateTimeTransformerName];
28 | [NSValueTransformer setValueTransformer:[[self alloc] initWithDateStyle:MCJSONDateTransformerStyleDateTimeMillisecond] forName:MCJSONDateTimeMillisecondTransformerName];
29 | [NSValueTransformer setValueTransformer:[[self alloc] initWithDateStyle:MCJSONDateTransformerStyleDateOnly] forName:MCJSONDateOnlyTransformerName];
30 | }
31 |
32 | + (instancetype)valueTransformerWithDateStyle:(MCJSONDateTransformerStyle)style {
33 | return [[self alloc] initWithDateStyle:style];
34 | }
35 |
36 | - (instancetype)initWithDateStyle:(MCJSONDateTransformerStyle)style {
37 | switch (style) {
38 | case MCJSONDateTransformerStyleDateOnly:
39 | self = [self initWithDateFormat:kDateFormatDateOnly];
40 | break;
41 | case MCJSONDateTransformerStyleDateTimeMillisecond:
42 | self = [self initWithDateFormat:kDateFormatDateTimeMillisecond];
43 | break;
44 |
45 | default:
46 | self = [self initWithDateFormat:kDateFormatDateTime];
47 | break;
48 | }
49 | return self;
50 | }
51 |
52 | + (instancetype)valueTransformerWithDateFormat:(NSString *)dateFormat {
53 | return [[self alloc] initWithDateFormat:dateFormat];
54 | }
55 |
56 | - (instancetype)initWithDateFormat:(NSString *)dateFormat {
57 | self = [super init];
58 | if (self) {
59 | self.formatter = [[NSDateFormatter alloc] init];
60 | self.formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
61 | self.formatter.dateFormat = dateFormat;
62 | }
63 | return self;
64 | }
65 |
66 | + (Class)transformedValueClass {
67 | return [NSDate class];
68 | }
69 |
70 | + (BOOL)allowsReverseTransformation {
71 | return YES;
72 | }
73 |
74 | - (id)transformedValue:(id)value {
75 | if([value isKindOfClass:[NSNull class]])return nil;
76 | return [self.formatter dateFromString:value];
77 | }
78 |
79 | - (id)reverseTransformedValue:(id)value {
80 | return [self.formatter stringFromDate:value];
81 | }
82 |
83 | @end
84 |
--------------------------------------------------------------------------------
/Realm+JSON/MCJSONNonNullStringTransformer.h:
--------------------------------------------------------------------------------
1 | //
2 | // MCJSONNonNullStringTransformer.h
3 | // Pods
4 | //
5 | // Created by Matthew Cheok on 23/5/15.
6 | //
7 | //
8 |
9 | #import
10 |
11 | @interface MCJSONNonNullStringTransformer : NSValueTransformer
12 |
13 | + (instancetype)valueTransformer;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/Realm+JSON/MCJSONNonNullStringTransformer.m:
--------------------------------------------------------------------------------
1 | //
2 | // MCJSONNonNullStringTransformer.m
3 | // Pods
4 | //
5 | // Created by Matthew Cheok on 23/5/15.
6 | //
7 | //
8 |
9 | #import "MCJSONNonNullStringTransformer.h"
10 |
11 | @implementation MCJSONNonNullStringTransformer
12 |
13 | + (instancetype)valueTransformer {
14 | return [[self alloc] init];
15 | }
16 |
17 | + (Class)transformedValueClass {
18 | return [NSString class];
19 | }
20 |
21 | + (BOOL)allowsReverseTransformation {
22 | return YES;
23 | }
24 |
25 | - (id)transformedValue:(id)value {
26 | if (value && ![value isKindOfClass:[NSNull class]]) {
27 | return value;
28 | }
29 | else {
30 | return @"";
31 | }
32 | }
33 |
34 | - (id)reverseTransformedValue:(id)value {
35 | return value;
36 | }
37 |
38 | @end
39 |
--------------------------------------------------------------------------------
/Realm+JSON/MCJSONPrimaryKeyTransformer.h:
--------------------------------------------------------------------------------
1 | //
2 | // MCJSONPrimaryKeyTransformer.h
3 | // RealmJSON
4 | //
5 | // Created by Anton Gaenko on 14.12.14.
6 | // Copyright (c) 2014 Anton Gaenko. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @interface MCJSONPrimaryKeyTransformer : NSValueTransformer
13 |
14 | // it should be RLMObject subclass
15 | + (instancetype)valueTransformerWithRealmClass:(Class)realmClass;
16 | - (instancetype)initWithRealmClass:(Class)realmClass;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/Realm+JSON/MCJSONPrimaryKeyTransformer.m:
--------------------------------------------------------------------------------
1 | //
2 | // MCJSONPrimaryKeyTransformer.m
3 | // RealmJSON
4 | //
5 | // Created by Anton Gaenko on 14.12.14.
6 | // Copyright (c) 2014 Anton Gaenko. All rights reserved.
7 | //
8 |
9 | #import "MCJSONPrimaryKeyTransformer.h"
10 |
11 | @interface MCJSONPrimaryKeyTransformer ()
12 |
13 | @property (nonatomic, assign) Class realmClassToMap;
14 |
15 | @end
16 |
17 | @implementation MCJSONPrimaryKeyTransformer
18 |
19 | + (instancetype)valueTransformerWithRealmClass:(Class)realmClass {
20 | return [[self alloc] initWithRealmClass:realmClass];
21 | }
22 |
23 | - (instancetype)initWithRealmClass:(Class)realmClass {
24 | self = [super init];
25 | if (self) {
26 | // it should be RLMObject subclass
27 | BOOL isRlmObjectSubclass = [realmClass respondsToSelector:@selector(isSubclassOfClass:)] &&
28 | [realmClass isSubclassOfClass:[RLMObject class]];
29 |
30 | if (isRlmObjectSubclass) {
31 | self.realmClassToMap = realmClass;
32 | }
33 |
34 | }
35 | return self;
36 | }
37 |
38 | - (id)transformedValue:(NSString*)value {
39 | if (value && self.realmClassToMap) {
40 | return [self.realmClassToMap performSelector:@selector(objectForPrimaryKey:) withObject:value];
41 | }
42 |
43 | return nil;
44 | }
45 |
46 | @end
47 |
--------------------------------------------------------------------------------
/Realm+JSON/MCJSONValueTransformer.h:
--------------------------------------------------------------------------------
1 | //
2 | // MCJSONValueTransformer.h
3 | // RealmJSONDemo
4 | //
5 | // Created by Matthew Cheok on 27/7/14.
6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface MCJSONValueTransformer : NSValueTransformer
12 |
13 | + (instancetype)valueTransformerWithMappingDictionary:(NSDictionary *)dictionary;
14 | - (instancetype)initWithMappingDictionary:(NSDictionary *)dictionary;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/Realm+JSON/MCJSONValueTransformer.m:
--------------------------------------------------------------------------------
1 | //
2 | // MCJSONValueTransformer.m
3 | // RealmJSONDemo
4 | //
5 | // Created by Matthew Cheok on 27/7/14.
6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved.
7 | //
8 |
9 | #import "MCJSONValueTransformer.h"
10 |
11 | @interface MCJSONValueTransformer ()
12 |
13 | @property (nonatomic, strong) NSDictionary *mappingDictionary;
14 |
15 | @end
16 |
17 | @implementation MCJSONValueTransformer
18 |
19 | + (instancetype)valueTransformerWithMappingDictionary:(NSDictionary *)dictionary {
20 | return [[self alloc] initWithMappingDictionary:dictionary];
21 | }
22 |
23 | - (instancetype)initWithMappingDictionary:(NSDictionary *)dictionary {
24 | self = [super init];
25 | if (self) {
26 | _mappingDictionary = dictionary;
27 | }
28 | return self;
29 | }
30 |
31 | + (BOOL)allowsReverseTransformation {
32 | return YES;
33 | }
34 |
35 | - (id)transformedValue:(id)value {
36 | return self.mappingDictionary[value];
37 | }
38 |
39 | - (id)reverseTransformedValue:(id)value {
40 | return [[self.mappingDictionary allKeysForObject:value] firstObject];
41 | }
42 |
43 | @end
44 |
--------------------------------------------------------------------------------
/Realm+JSON/RLMObject+Copying.h:
--------------------------------------------------------------------------------
1 | //
2 | // RLMObject+Copying.h
3 | // RealmJSONDemo
4 | //
5 | // Created by Matthew Cheok on 26/8/14.
6 | // Copyright (c) 2014 Getting Real. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface RLMObject (Copying)
12 |
13 | - (instancetype)shallowCopy;
14 | - (instancetype)deepCopy;
15 | - (void)mergePropertiesFromObject:(id)object;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/Realm+JSON/RLMObject+Copying.m:
--------------------------------------------------------------------------------
1 | //
2 | // RLMObject+Copying.m
3 | // RealmJSONDemo
4 | //
5 | // Created by Matthew Cheok on 26/8/14.
6 | // Copyright (c) 2014 Getting Real. All rights reserved.
7 | //
8 |
9 | #import "RLMObject+Copying.h"
10 |
11 | #import
12 | #import
13 |
14 | @interface RLMProperty (Copying_Internal)
15 |
16 | @property (nonatomic, assign) BOOL isPrimary;
17 |
18 | @end
19 |
20 | @implementation RLMObject (Copying)
21 |
22 | - (instancetype)shallowCopy {
23 | id object = [[NSClassFromString(self.objectSchema.className) alloc] init];
24 | [object mergePropertiesFromObject:self];
25 |
26 | return object;
27 | }
28 |
29 | - (void)mergePropertiesFromObject:(id)object {
30 |
31 | BOOL primaryKeyIsEmpty;
32 | id value;
33 | id selfValue;
34 |
35 | BOOL (^valuesAreEqual)(id, id) = ^BOOL(id value1, id value2) {
36 | return ([[NSString stringWithFormat:@"%@", value1]
37 | isEqualToString:[NSString stringWithFormat:@"%@", value2]]);
38 | };
39 |
40 | for (RLMProperty *property in self.objectSchema.properties) {
41 |
42 | if (property.type != RLMPropertyTypeArray) {
43 |
44 | // asume data
45 | value = [object valueForKeyPath:property.name];
46 | selfValue = [self valueForKeyPath:property.name];
47 |
48 | primaryKeyIsEmpty = (property.isPrimary &&
49 | !valuesAreEqual(value, selfValue)
50 | );
51 |
52 | if (primaryKeyIsEmpty || !property.isPrimary) {
53 | [self setValue:value forKeyPath:property.name];
54 | }
55 |
56 | } else {
57 | // asume array
58 | RLMArray *thisArray = [self valueForKeyPath:property.name];
59 | RLMArray *thatArray = [object valueForKeyPath:property.name];
60 | [thisArray addObjects:thatArray];
61 | }
62 | }
63 | }
64 |
65 |
66 | - (instancetype)deepCopy {
67 | RLMObject *object = [[NSClassFromString(self.objectSchema.className) alloc] init];
68 |
69 | for (RLMProperty *property in self.objectSchema.properties) {
70 |
71 | if (property.type == RLMPropertyTypeArray) {
72 | RLMArray *thisArray = [self valueForKeyPath:property.name];
73 | RLMArray *newArray = [object valueForKeyPath:property.name];
74 |
75 | for (RLMObject *currentObject in thisArray) {
76 | [newArray addObject:[currentObject deepCopy]];
77 | }
78 |
79 | }
80 | else if (property.type == RLMPropertyTypeObject) {
81 | RLMObject *value = [self valueForKeyPath:property.name];
82 | [object setValue:[value deepCopy] forKeyPath:property.name];
83 | }
84 | else {
85 | id value = [self valueForKeyPath:property.name];
86 | [object setValue:value forKeyPath:property.name];
87 | }
88 | }
89 |
90 | return object;
91 | }
92 |
93 |
94 |
95 | @end
96 |
--------------------------------------------------------------------------------
/Realm+JSON/RLMObject+JSON.h:
--------------------------------------------------------------------------------
1 | //
2 | // RLMObject+JSON.h
3 | // RealmJSONDemo
4 | //
5 | // Created by Matthew Cheok on 27/7/14.
6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "MCJSONDateTransformer.h"
11 | #import "MCJSONValueTransformer.h"
12 |
13 | @interface RLMObject (JSON)
14 |
15 | + (NSArray *)createOrUpdateInRealm:(RLMRealm *)realm withJSONArray:(NSArray *)array;
16 | + (instancetype)createOrUpdateInRealm:(RLMRealm *)realm withJSONDictionary:(NSDictionary *)dictionary;
17 | + (instancetype)objectInRealm:(RLMRealm *)realm withPrimaryKeyValue:(id)primaryKeyValue;
18 |
19 | - (instancetype)initWithJSONDictionary:(NSDictionary *)dictionary;
20 | - (NSDictionary *)JSONDictionary;
21 |
22 | - (id)primaryKeyValue;
23 | + (id)primaryKeyValueFromJSONDictionary:(NSDictionary *)dictionary;
24 |
25 | - (void)performInTransaction:(void (^)())transaction;
26 | - (void)removeFromRealm;
27 |
28 | @end
29 |
30 | @interface RLMArray (JSON)
31 |
32 | - (NSArray *)NSArray;
33 | - (NSArray *)JSONArray;
34 |
35 | @end
--------------------------------------------------------------------------------
/Realm+JSON/RLMObject+JSON.m:
--------------------------------------------------------------------------------
1 | //
2 | // RLMObject+JSON.m
3 | // RealmJSONDemo
4 | //
5 | // Created by Matthew Cheok on 27/7/14.
6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved.
7 | //
8 |
9 | #import "RLMObject+JSON.h"
10 |
11 | #import
12 | #import
13 |
14 | // RLMSchema private interface
15 | @interface RLMSchema ()
16 | // class for string
17 | + (Class)classForString:(NSString *)className;
18 | @end
19 |
20 | #import
21 |
22 | static id MCValueFromInvocation(id object, SEL selector) {
23 | NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[object methodSignatureForSelector:selector]];
24 | invocation.target = object;
25 | invocation.selector = selector;
26 | [invocation invoke];
27 |
28 | __unsafe_unretained id result = nil;
29 | [invocation getReturnValue:&result];
30 |
31 | return result;
32 | }
33 |
34 | static NSString *MCTypeStringFromPropertyKey(Class class, NSString *key) {
35 | const objc_property_t property = class_getProperty(class, [key UTF8String]);
36 | if (!property) {
37 | [NSException raise:NSInternalInconsistencyException format:@"Class %@ does not have property %@", class, key];
38 | }
39 | const char *type = property_getAttributes(property);
40 | return [NSString stringWithUTF8String:type];
41 | }
42 |
43 | @interface NSString (MCJSON)
44 |
45 | - (NSString *)snakeToCamelCase;
46 | - (NSString *)camelToSnakeCase;
47 |
48 | @end
49 |
50 | @interface RLMObject (JSON_Internal)
51 |
52 | // RLMObject private methods
53 | + (RLMObjectSchema *)sharedSchema;
54 |
55 | @end
56 |
57 | @implementation RLMObject (JSON)
58 |
59 | static NSInteger const kCreateBatchSize = 100;
60 |
61 | + (NSArray *)createOrUpdateInRealm:(RLMRealm *)realm withJSONArray:(NSArray *)array {
62 | NSInteger count = array.count;
63 | NSMutableArray *result = [NSMutableArray array];
64 |
65 | for (NSInteger index=0; index*kCreateBatchSize 0) {
98 | return results.firstObject;
99 | }
100 | else {
101 | return nil;
102 | }
103 | }
104 |
105 | - (instancetype)initWithJSONDictionary:(NSDictionary *)dictionary {
106 | self = [self initWithValue:[[self class] mc_createObjectFromJSONDictionary:dictionary]];
107 | if (self) {
108 | }
109 | return self;
110 | }
111 |
112 | - (NSDictionary *)JSONDictionary {
113 | return [self mc_createJSONDictionary];
114 | }
115 |
116 | - (id)primaryKeyValue {
117 | NSString *primaryKey = [[self class] primaryKey];
118 | NSAssert(primaryKey, @"No primary key on class %@", [self description]);
119 |
120 | return [self valueForKeyPath:primaryKey];
121 | }
122 |
123 | + (id)primaryKeyValueFromJSONDictionary:(NSDictionary *)dictionary {
124 | NSString *primaryKey = [[self class] primaryKey];
125 | if (!primaryKey) {
126 | return nil;
127 | }
128 |
129 | NSDictionary *inboundMapping = [self mc_inboundMapping];
130 | NSString *primaryKeyPath = [[inboundMapping allKeysForObject:primaryKey] firstObject];
131 | id primaryKeyValue = [dictionary valueForKeyPath:primaryKeyPath];
132 |
133 | NSValueTransformer *transformer = [self mc_transformerForPropertyKey:primaryKey];
134 | if (primaryKeyValue && transformer) {
135 | primaryKeyValue = [transformer transformedValue:primaryKeyValue];
136 | }
137 |
138 | return primaryKeyValue;
139 | }
140 |
141 | - (void)performInTransaction:(void (^)())transaction {
142 | NSAssert(transaction != nil, @"No transaction block provided");
143 | if (self.realm) {
144 | [self.realm transactionWithBlock:transaction];
145 | }
146 | else {
147 | transaction();
148 | }
149 | }
150 |
151 | - (void)removeFromRealm {
152 | [self performInTransaction: ^{
153 | [self.realm deleteObject:self];
154 | }];
155 | }
156 |
157 | #pragma mark - Private
158 |
159 | + (id)mc_createObjectFromJSONDictionary:(NSDictionary *)origDict {
160 | NSMutableDictionary *result = [NSMutableDictionary dictionary];
161 | NSDictionary *mapping = [[self class] mc_inboundMapping];
162 |
163 | NSDictionary *dictionary;
164 | SEL preprocessingSel = NSSelectorFromString(@"preprocessedJSON:");
165 | if ([self respondsToSelector:preprocessingSel]) {
166 | dictionary = [self performSelector:preprocessingSel withObject:origDict];
167 | } else {
168 | dictionary = origDict;
169 | }
170 |
171 | for (NSString *dictionaryKeyPath in mapping) {
172 | NSString *objectKeyPath = mapping[dictionaryKeyPath];
173 |
174 | id value = [dictionary valueForKeyPath:dictionaryKeyPath];
175 |
176 | if (value) {
177 | Class propertyClass = [[self class] mc_classForPropertyKey:objectKeyPath];
178 |
179 | NSValueTransformer *transformer = [[self class] mc_transformerForPropertyKey:objectKeyPath];
180 | if (transformer) {
181 | value = [transformer transformedValue:value];
182 | }
183 | else if ([propertyClass isSubclassOfClass:[RLMObject class]]) {
184 | if (!value || [value isEqual:[NSNull null]]) {
185 | continue;
186 | }
187 |
188 | if ([value isKindOfClass:[NSDictionary class]]) {
189 | value = [propertyClass mc_createObjectFromJSONDictionary:value];
190 | }
191 | }
192 | else if ([propertyClass isSubclassOfClass:[RLMArray class]]) {
193 | RLMProperty *property = [self mc_propertyForPropertyKey:objectKeyPath];
194 | Class elementClass = [RLMSchema classForString: property.objectClassName];
195 |
196 | NSMutableArray *array = [NSMutableArray array];
197 | for (id item in(NSArray*) value) {
198 | [array addObject:[elementClass mc_createObjectFromJSONDictionary:item]];
199 | }
200 | value = [array copy];
201 | }
202 |
203 | if ([objectKeyPath isEqualToString:@"self"]) {
204 | return value;
205 | }
206 |
207 | NSArray *keyPathComponents = [objectKeyPath componentsSeparatedByString:@"."];
208 | id currentDictionary = result;
209 | for (NSString *component in keyPathComponents) {
210 | if ([currentDictionary valueForKey:component] == nil) {
211 | [currentDictionary setValue:[NSMutableDictionary dictionary] forKey:component];
212 | }
213 | currentDictionary = [currentDictionary valueForKey:component];
214 | }
215 |
216 | value = value ?: [NSNull null];
217 | [result setValue:value forKeyPath:objectKeyPath];
218 | }
219 | }
220 |
221 | return [result copy];
222 | }
223 |
224 | - (id)mc_createJSONDictionary {
225 | NSMutableDictionary *result = [NSMutableDictionary dictionary];
226 | NSDictionary *mapping = [[self class] mc_outboundMapping];
227 |
228 | for (NSString *objectKeyPath in mapping) {
229 | NSString *dictionaryKeyPath = mapping[objectKeyPath];
230 |
231 | id value = [self valueForKeyPath:objectKeyPath];
232 | if (value) {
233 | Class propertyClass = [[self class] mc_classForPropertyKey:objectKeyPath];
234 |
235 | NSValueTransformer *transformer = [[self class] mc_transformerForPropertyKey:objectKeyPath];
236 | if (transformer) {
237 | value = [transformer reverseTransformedValue:value];
238 | }
239 | else if ([propertyClass isSubclassOfClass:[RLMObject class]]) {
240 | value = [value mc_createJSONDictionary];
241 | }
242 | else if ([propertyClass isSubclassOfClass:[RLMArray class]]) {
243 | NSMutableArray *array = [NSMutableArray array];
244 | for (id item in(RLMArray *) value) {
245 | [array addObject:[item mc_createJSONDictionary]];
246 | }
247 | value = [array copy];
248 | }
249 |
250 | if ([dictionaryKeyPath isEqualToString:@"self"]) {
251 | return value;
252 | }
253 |
254 | NSArray *keyPathComponents = [dictionaryKeyPath componentsSeparatedByString:@"."];
255 | id currentDictionary = result;
256 | for (NSString *component in keyPathComponents) {
257 | if ([currentDictionary valueForKey:component] == nil) {
258 | [currentDictionary setValue:[NSMutableDictionary dictionary] forKey:component];
259 | }
260 | currentDictionary = [currentDictionary valueForKey:component];
261 | }
262 |
263 | [result setValue:value forKeyPath:dictionaryKeyPath];
264 | } else {
265 | [result setValue:[NSNull null] forKeyPath:dictionaryKeyPath];
266 | }
267 | }
268 |
269 | return [result copy];
270 | }
271 |
272 | #pragma mark - Properties
273 |
274 | + (NSDictionary *)mc_defaultInboundMapping {
275 | RLMObjectSchema *schema = [self sharedSchema];
276 |
277 | NSMutableDictionary *result = [NSMutableDictionary dictionary];
278 | for (RLMProperty *property in schema.properties) {
279 | result[[property.name camelToSnakeCase]] = property.name;
280 |
281 | }
282 |
283 | return [result copy];
284 | }
285 |
286 | + (NSDictionary *)mc_defaultOutboundMapping {
287 | RLMObjectSchema *schema = [self sharedSchema];
288 |
289 | NSMutableDictionary *result = [NSMutableDictionary dictionary];
290 | for (RLMProperty *property in schema.properties) {
291 | result[property.name] = [property.name camelToSnakeCase];
292 |
293 | }
294 |
295 | return [result copy];
296 | }
297 |
298 | #pragma mark - Convenience Methods
299 |
300 | + (NSDictionary *)mc_inboundMapping {
301 | static NSMutableDictionary *mappingForClassName = nil;
302 | static dispatch_once_t onceToken;
303 | dispatch_once(&onceToken, ^{
304 | mappingForClassName = [NSMutableDictionary dictionary];
305 | });
306 | @synchronized(mappingForClassName) {
307 | NSDictionary *mapping = mappingForClassName[[self className]];
308 | if (!mapping) {
309 | SEL selector = NSSelectorFromString(@"JSONInboundMappingDictionary");
310 | if ([self respondsToSelector:selector]) {
311 | mapping = MCValueFromInvocation(self, selector);
312 | }
313 | else {
314 | mapping = [self mc_defaultInboundMapping];
315 | }
316 | mappingForClassName[[self className]] = mapping;
317 | }
318 | return mapping;
319 | }
320 | }
321 |
322 | + (NSDictionary *)mc_outboundMapping {
323 | static NSMutableDictionary *mappingForClassName = nil;
324 | static dispatch_once_t onceToken;
325 | dispatch_once(&onceToken, ^{
326 | mappingForClassName = [NSMutableDictionary dictionary];
327 | });
328 |
329 | @synchronized(mappingForClassName) {
330 | NSDictionary *mapping = mappingForClassName[[self className]];
331 | if (!mapping) {
332 | SEL selector = NSSelectorFromString(@"JSONOutboundMappingDictionary");
333 | if ([self respondsToSelector:selector]) {
334 | mapping = MCValueFromInvocation(self, selector);
335 | }
336 | else {
337 | mapping = [self mc_defaultOutboundMapping];
338 | }
339 | mappingForClassName[[self className]] = mapping;
340 | }
341 | return mapping;
342 | }
343 | }
344 |
345 | + (RLMProperty *)mc_propertyForPropertyKey:(NSString *)key {
346 | RLMObjectSchema *schema = [self sharedSchema];
347 | for (RLMProperty *property in schema.properties) {
348 | if ([property.name isEqualToString:key]) {
349 | return property;
350 | }
351 | }
352 | return nil;
353 | }
354 |
355 | + (Class)mc_classForPropertyKey:(NSString *)key {
356 | NSString *attributes = MCTypeStringFromPropertyKey(self, key);
357 | if ([attributes hasPrefix:@"T@"]) {
358 | static NSCharacterSet *set = nil;
359 | static dispatch_once_t onceToken;
360 | dispatch_once(&onceToken, ^{
361 | set = [NSCharacterSet characterSetWithCharactersInString:@"\"<"];
362 | });
363 |
364 | @synchronized(set) {
365 | NSString *string;
366 | NSScanner *scanner = [NSScanner scannerWithString:attributes];
367 | scanner.charactersToBeSkipped = set;
368 | [scanner scanUpToCharactersFromSet:set intoString:NULL];
369 | [scanner scanUpToCharactersFromSet:set intoString:&string];
370 | return NSClassFromString(string);
371 | }
372 | }
373 | return nil;
374 | }
375 |
376 | + (NSValueTransformer *)mc_transformerForPropertyKey:(NSString *)key {
377 | Class propertyClass = [self mc_classForPropertyKey:key];
378 | SEL selector = NSSelectorFromString([key stringByAppendingString:@"JSONTransformer"]);
379 |
380 | NSValueTransformer *transformer = nil;
381 | if ([self respondsToSelector:selector]) {
382 | transformer = MCValueFromInvocation(self, selector);
383 | }
384 | else if ([propertyClass isSubclassOfClass:[NSDate class]]) {
385 | transformer = [NSValueTransformer valueTransformerForName:MCJSONDateTimeTransformerName];
386 | }
387 |
388 | return transformer;
389 | }
390 |
391 | @end
392 |
393 | @implementation NSString (MCJSON)
394 |
395 | - (NSString *)snakeToCamelCase {
396 | NSScanner *scanner = [NSScanner scannerWithString:self];
397 | NSCharacterSet *underscoreSet = [NSCharacterSet characterSetWithCharactersInString:@"_"];
398 | scanner.charactersToBeSkipped = underscoreSet;
399 |
400 | NSMutableString *result = [NSMutableString string];
401 | NSString *buffer = nil;
402 |
403 | while (![scanner isAtEnd]) {
404 | BOOL atStartPosition = scanner.scanLocation == 0;
405 | [scanner scanUpToCharactersFromSet:underscoreSet intoString:&buffer];
406 | [result appendString:atStartPosition ? buffer:[buffer capitalizedString]];
407 | }
408 |
409 | return result;
410 | }
411 |
412 | - (NSString *)camelToSnakeCase {
413 | NSScanner *scanner = [NSScanner scannerWithString:self];
414 | NSCharacterSet *uppercaseSet = [NSCharacterSet uppercaseLetterCharacterSet];
415 | scanner.charactersToBeSkipped = uppercaseSet;
416 |
417 | NSMutableString *result = [NSMutableString string];
418 | NSString *buffer = nil;
419 |
420 | while (![scanner isAtEnd]) {
421 | [scanner scanUpToCharactersFromSet:uppercaseSet intoString:&buffer];
422 | [result appendString:[buffer lowercaseString]];
423 |
424 | if (![scanner isAtEnd]) {
425 | [result appendString:@"_"];
426 | [result appendString:[[self substringWithRange:NSMakeRange(scanner.scanLocation, 1)] lowercaseString]];
427 | }
428 | }
429 |
430 | return result;
431 | }
432 |
433 | @end
434 |
435 | @implementation RLMArray (JSON)
436 |
437 | - (NSArray *)NSArray {
438 | NSMutableArray *array = [NSMutableArray arrayWithCapacity:self.count];
439 | for (id object in self) {
440 | [array addObject:object];
441 | }
442 | return [array copy];
443 | }
444 |
445 | - (NSArray *)JSONArray {
446 | NSMutableArray *array = [NSMutableArray array];
447 | for (RLMObject *object in self) {
448 | [array addObject:[object JSONDictionary]];
449 | }
450 | return [array copy];
451 | }
452 |
453 | @end
454 |
--------------------------------------------------------------------------------