├── .travis.yml ├── .gitignore ├── SHModelObject ├── en.lproj │ └── InfoPlist.strings ├── SHAnotherModel.m ├── main.m ├── SHModelObject-Prefix.pch ├── SHAnotherModel.h ├── SHModelObject │ ├── SHConstants.h │ ├── SHModelSerialization.h │ ├── SHModelObject.h │ ├── SHRealmObject.h │ ├── SHModelObject.m │ └── SHRealmObject.m ├── Images.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── LaunchImage.launchimage │ │ └── Contents.json ├── SHAppDelegate.h ├── SHTestModal.m ├── SHModelObject-Info.plist ├── SHTestModal.h └── SHAppDelegate.m ├── Podfile ├── SHModelObjectTests ├── en.lproj │ └── InfoPlist.strings ├── SHModelObjectTests-Info.plist └── SHModalObjectTests.m ├── SHModelObject.xcodeproj ├── xcuserdata │ ├── shanulhaq.xcuserdatad │ │ ├── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ │ ├── xcschememanagement.plist │ │ │ └── SHModalObject.xcscheme │ └── shan.haq.xcuserdatad │ │ └── xcschemes │ │ ├── xcschememanagement.plist │ │ └── SHModelObject.xcscheme ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcuserdata │ │ ├── shan.haq.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ │ └── shanulhaq.xcuserdatad │ │ │ ├── UserInterfaceState.xcuserstate │ │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata │ │ ├── SHModalObject.xccheckout │ │ └── SHModelObject.xccheckout └── project.pbxproj ├── SHModelObject.xcworkspace ├── xcuserdata │ ├── shanulhaq.xcuserdatad │ │ ├── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ └── WorkspaceSettings.xcsettings │ └── shan.haq.xcuserdatad │ │ └── UserInterfaceState.xcuserstate ├── contents.xcworkspacedata └── xcshareddata │ └── SHModelObject.xccheckout ├── Podfile.lock ├── CHANGELOG.md ├── LICENSE ├── SHModelObject.podspec └── README.md /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | DerivedData 3 | Build 4 | Pods -------------------------------------------------------------------------------- /SHModelObject/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '7.0' 2 | 3 | target 'SHModelObject' do 4 | pod 'Realm' 5 | end 6 | 7 | -------------------------------------------------------------------------------- /SHModelObjectTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /SHModelObject.xcodeproj/xcuserdata/shanulhaq.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /SHModelObject.xcworkspace/xcuserdata/shanulhaq.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /SHModelObject.xcworkspace/xcuserdata/shan.haq.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grevolution/SHModelObject/HEAD/SHModelObject.xcworkspace/xcuserdata/shan.haq.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /SHModelObject.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SHModelObject.xcodeproj/project.xcworkspace/xcuserdata/shan.haq.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grevolution/SHModelObject/HEAD/SHModelObject.xcodeproj/project.xcworkspace/xcuserdata/shan.haq.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /SHModelObject.xcodeproj/project.xcworkspace/xcuserdata/shanulhaq.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grevolution/SHModelObject/HEAD/SHModelObject.xcodeproj/project.xcworkspace/xcuserdata/shanulhaq.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /SHModelObject/SHAnotherModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // SHAnotherModel.m 3 | // SHModelObject 4 | // 5 | // Created by SHAN UL HAQ on 14/3/15. 6 | // Copyright (c) 2015 grevolution. All rights reserved. 7 | // 8 | 9 | #import "SHAnotherModel.h" 10 | 11 | @implementation SHAnotherModel 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /SHModelObject.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Realm (1.0.1): 3 | - Realm/Headers (= 1.0.1) 4 | - Realm/Headers (1.0.1) 5 | 6 | DEPENDENCIES: 7 | - Realm 8 | 9 | SPEC CHECKSUMS: 10 | Realm: 2e15e39d35b08abb529e212ed5d8af107b5236c8 11 | 12 | PODFILE CHECKSUM: b1143668b7fe2a332a4de82369d518b567cb9515 13 | 14 | COCOAPODS: 1.0.0 15 | -------------------------------------------------------------------------------- /SHModelObject/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // SHModalObject 4 | // 5 | // Created by SHAN UL HAQ on 23/2/14. 6 | // Copyright (c) 2014 grevolution. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "SHAppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([SHAppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /SHModelObject/SHModelObject-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_3_0 10 | #warning "This project uses features only available in iOS SDK 3.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /SHModelObject.xcworkspace/xcuserdata/shanulhaq.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges 6 | 7 | SnapshotAutomaticallyBeforeSignificantChanges 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /SHModelObject/SHAnotherModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // SHAnotherModel.h 3 | // SHModelObject 4 | // 5 | // Created by SHAN UL HAQ on 14/3/15. 6 | // Copyright (c) 2015 grevolution. All rights reserved. 7 | // 8 | 9 | #import "SHModelObject.h" 10 | 11 | @interface SHAnotherModel : SHModelObject 12 | 13 | @property (nonatomic) int modelId; 14 | @property (nonatomic, strong) NSString *modelName; 15 | @property (nonatomic, strong) NSString *modelType; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /SHModelObject.xcodeproj/project.xcworkspace/xcuserdata/shanulhaq.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges 6 | 7 | SnapshotAutomaticallyBeforeSignificantChanges 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # `SHModelObject` Changelog 2 | 3 | ## 1.1.1 4 | 5 | 1. addition of new class `SHRealmObject` which is a subclass of `RLMObject` from [Realm](http://realm.io/). 6 | 7 | ## 1.0.8 8 | 9 | ### New Features 10 | 11 | 1. `SHModelObject` now supports automatic parsing of instance variables which are also of type `SHModelObject` 12 | 2. `SHModelObject` now supports parsing arrays of objects which are of type `SHModelObject` based on the mapping provided 13 | 14 | ### Refactoring 15 | 16 | 1. removed the use of mapping dictionary for date conversion. `SHModelObject` parses the dates based on the instance variable types. -------------------------------------------------------------------------------- /SHModelObject.xcodeproj/xcuserdata/shan.haq.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SHModelObject.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | F2B4092C18BA16F400611B29 16 | 17 | primary 18 | 19 | 20 | F2B4094718BA16F500611B29 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /SHModelObject.xcodeproj/xcuserdata/shanulhaq.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SHModalObject.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | F2B4092C18BA16F400611B29 16 | 17 | primary 18 | 19 | 20 | F2B4094718BA16F500611B29 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /SHModelObjectTests/SHModelObjectTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.grevolution.shmodalobject.${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 | -------------------------------------------------------------------------------- /SHModelObjectTests/SHModalObjectTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // SHModalObjectTests.m 3 | // SHModalObjectTests 4 | // 5 | // Created by SHAN UL HAQ on 23/2/14. 6 | // Copyright (c) 2014 grevolution. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SHModalObjectTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation SHModalObjectTests 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 | -------------------------------------------------------------------------------- /SHModelObject/SHModelObject/SHConstants.h: -------------------------------------------------------------------------------- 1 | // 2 | // SHConstants.h 3 | // SHModelObject 4 | // 5 | // Created by SHAN UL HAQ on 4/4/15. 6 | // Copyright (c) 2015 grevolution. All rights reserved. 7 | // 8 | 9 | #ifndef SHModelObject_SHConstants_h 10 | #define SHModelObject_SHConstants_h 11 | 12 | /** 13 | * Date option conversion enum to be passed to the serializer constructer 14 | */ 15 | typedef enum { 16 | kDateConverstionFromNSStringToNSStringOption = 0, // do not convert, keep NSString as it is. 17 | kDateConverstionFromNSStringToNSDateOption = 1, // convert NSString to NSDate 18 | kDateConverstionFromNSStringToNSTimeIntervalOption = 2 // convert NSString to NSTimeInterval 19 | } kDateConversionOption; 20 | 21 | /** 22 | * enum for identifying the input date type. 23 | */ 24 | typedef NS_ENUM(int, kInputDateFormat) { 25 | kInputDateFormatJSON = 1, 26 | kInputDateFormatDotNetSimple = 2, 27 | kInputDateFormatDotNetWithTimeZone = 3, 28 | kInputDateFormatCustom = -1, 29 | }; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /SHModelObject/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 | "idiom" : "ipad", 20 | "size" : "29x29", 21 | "scale" : "1x" 22 | }, 23 | { 24 | "idiom" : "ipad", 25 | "size" : "29x29", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "ipad", 30 | "size" : "40x40", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "40x40", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "76x76", 41 | "scale" : "1x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "76x76", 46 | "scale" : "2x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Shan Ul Haq (http://grevolution.me) 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. -------------------------------------------------------------------------------- /SHModelObject/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 | "orientation" : "portrait", 20 | "idiom" : "ipad", 21 | "extent" : "full-screen", 22 | "minimum-system-version" : "7.0", 23 | "scale" : "1x" 24 | }, 25 | { 26 | "orientation" : "landscape", 27 | "idiom" : "ipad", 28 | "extent" : "full-screen", 29 | "minimum-system-version" : "7.0", 30 | "scale" : "1x" 31 | }, 32 | { 33 | "orientation" : "portrait", 34 | "idiom" : "ipad", 35 | "extent" : "full-screen", 36 | "minimum-system-version" : "7.0", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "orientation" : "landscape", 41 | "idiom" : "ipad", 42 | "extent" : "full-screen", 43 | "minimum-system-version" : "7.0", 44 | "scale" : "2x" 45 | } 46 | ], 47 | "info" : { 48 | "version" : 1, 49 | "author" : "xcode" 50 | } 51 | } -------------------------------------------------------------------------------- /SHModelObject/SHAppDelegate.h: -------------------------------------------------------------------------------- 1 | // SHAppDelegate.h 2 | // 3 | // Copyright (c) 2014 Shan Ul Haq (http://grevolution.me) 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 | #import 24 | 25 | @interface SHAppDelegate : UIResponder 26 | 27 | @property (strong, nonatomic) UIWindow *window; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /SHModelObject/SHTestModal.m: -------------------------------------------------------------------------------- 1 | // SHTestModal.m 2 | // 3 | // Copyright (c) 2014 Shan Ul Haq (http://grevolution.me) 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 | #import "SHTestModal.h" 24 | 25 | @implementation SHTestModal 26 | 27 | - (void)serializeValue:(id)value withKey:(id)key 28 | { 29 | if([key isEqualToString:@"numberVALUE"]) { 30 | _numberValue = value; 31 | NSLog(@"did it for _numberValue : %@", _numberValue); 32 | } else { 33 | [super serializeValue:value withKey:key]; 34 | } 35 | } 36 | 37 | @end -------------------------------------------------------------------------------- /SHModelObject/SHModelObject-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.grevolution.shmodalobject.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0.8 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0.8 25 | LSRequiresIPhoneOS 26 | 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 | -------------------------------------------------------------------------------- /SHModelObject.xcworkspace/xcshareddata/SHModelObject.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 1D5875E1-22CF-45BC-B76F-5E8523155564 9 | IDESourceControlProjectName 10 | SHModelObject 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | B5D04170A948972EE1EFA3B27A34E674C9EF57CA 14 | github.com:grevolution/SHModelObject.git 15 | 16 | IDESourceControlProjectPath 17 | SHModelObject.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | B5D04170A948972EE1EFA3B27A34E674C9EF57CA 21 | .. 22 | 23 | IDESourceControlProjectURL 24 | github.com:grevolution/SHModelObject.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | B5D04170A948972EE1EFA3B27A34E674C9EF57CA 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | B5D04170A948972EE1EFA3B27A34E674C9EF57CA 36 | IDESourceControlWCCName 37 | SHModelObject 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /SHModelObject.xcodeproj/project.xcworkspace/xcshareddata/SHModalObject.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | FC166833-3A12-4E9C-940B-26BBE2FD9049 9 | IDESourceControlProjectName 10 | SHModalObject 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 6A161B01-FC15-4A74-B068-2C490C0C2C68 14 | https://github.com/grevolution/SHModalObject.git 15 | 16 | IDESourceControlProjectPath 17 | SHModalObject.xcodeproj/project.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 6A161B01-FC15-4A74-B068-2C490C0C2C68 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/grevolution/SHModalObject.git 25 | IDESourceControlProjectVersion 26 | 110 27 | IDESourceControlProjectWCCIdentifier 28 | 6A161B01-FC15-4A74-B068-2C490C0C2C68 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 6A161B01-FC15-4A74-B068-2C490C0C2C68 36 | IDESourceControlWCCName 37 | SHModalObject 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /SHModelObject.xcodeproj/project.xcworkspace/xcshareddata/SHModelObject.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | BBC6A4B8-4768-465C-B90C-4197CE7B15FD 9 | IDESourceControlProjectName 10 | SHModelObject 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | B5D04170A948972EE1EFA3B27A34E674C9EF57CA 14 | https://github.com/grevolution/SHModelObject.git 15 | 16 | IDESourceControlProjectPath 17 | SHModelObject.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | B5D04170A948972EE1EFA3B27A34E674C9EF57CA 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/grevolution/SHModelObject.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | B5D04170A948972EE1EFA3B27A34E674C9EF57CA 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | B5D04170A948972EE1EFA3B27A34E674C9EF57CA 36 | IDESourceControlWCCName 37 | SHModelObject 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /SHModelObject.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "SHModelObject" 3 | s.version = "1.1.9" 4 | 5 | s.summary = "`SHModelObject` a utility class that reads NSDictionary and populates the instance variables and properties automatically." 6 | 7 | s.description = <<-DESC 8 | `SHModelObject` is a utility Modal Base Class that uses objective-c runtime to assign 9 | the values to instance variables and properties of the model class from an `NSDictionary`, 10 | Which is a basic usecase when using webservices that return JSON response. 11 | DESC 12 | 13 | s.homepage = "https://github.com/grevolution/SHModelObject" 14 | s.license = {:type => 'MIT'} 15 | s.author = { "Shan Ul Haq" => "g@grevolution.me" } 16 | 17 | s.platform = :ios, '7.0' 18 | s.source = { :git => "https://github.com/grevolution/SHModelObject.git", :tag => s.version } 19 | 20 | s.requires_arc = true 21 | #s.source_files = 'SHModelObject/SHModelObject/*.{h,m}' 22 | #s.exclude_files = 'Classes/Exclude' 23 | #s.dependency 'Realm' 24 | 25 | s.subspec 'Core' do |core| 26 | core.source_files = 'SHModelObject/SHModelObject/SHModelObject.{h,m}' , 'SHModelObject/SHModelObject/SHConstants.h' , 27 | 'SHModelObject/SHModelObject/SHModelSerialization.h' 28 | core.exclude_files = 'SHModelObject/SHModelObject/SHRealmObject.{h,m}' 29 | core.platform = :ios 30 | end 31 | 32 | s.subspec 'Realm' do |realm| 33 | realm.source_files = 'SHModelObject/SHModelObject/SHRealmObject.{h,m}' , 'SHModelObject/SHModelObject/SHConstants.h' , 'SHModelObject/SHModelObject/SHModelSerialization.h' 34 | realm.platform = :ios, '7.0' 35 | realm.exclude_files = 'SHModelObject/SHModelObject/SHModelObject.{h,m}' 36 | realm.dependency 'Realm' 37 | end 38 | 39 | end 40 | -------------------------------------------------------------------------------- /SHModelObject/SHTestModal.h: -------------------------------------------------------------------------------- 1 | // SHTestModal.h 2 | // 3 | // Copyright (c) 2014 Shan Ul Haq (http://grevolution.me) 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 | #import "SHModelObject.h" 24 | 25 | @class SHAnotherModel; 26 | 27 | @interface SHTestModal : SHModelObject 28 | 29 | { 30 | NSString *_anotherStringValue; 31 | NSNumber *_intValue; 32 | NSInteger _integerValue; 33 | NSNumber *_numberValue; 34 | BOOL _remember; 35 | NSString *_doItMySelf; 36 | 37 | NSMutableArray *_myArray; 38 | NSMutableDictionary *_myDictionary; 39 | NSDate *time1; 40 | } 41 | 42 | @property (nonatomic, strong) NSString *stringValue; 43 | @property (nonatomic) int anotherIntValue; 44 | @property (nonatomic) NSInteger anotherIntegerValue; 45 | @property (nonatomic, strong) NSNumber *anotherNumberValue; 46 | @property (nonatomic, strong) SHAnotherModel *anotherModel; 47 | @property (nonatomic, strong) NSArray *arrayOfAnotherModels; 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /SHModelObject/SHModelObject/SHModelSerialization.h: -------------------------------------------------------------------------------- 1 | // SHModalSerialization.h 2 | // 3 | // Copyright (c) 2014 Shan Ul Haq (http://grevolution.me) 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 | #import 24 | 25 | /** 26 | * The `SHModalSerialization` protocol is adopted by any class that will then implement how to serialize the key/value 27 | * pair passed to the class. 28 | */ 29 | @protocol SHModelSerialization 30 | 31 | /** 32 | * This method will be implemented by the class that adopts this protocol and will define the logic for how to 33 | * serialize the key/value pair passed to the method. the overridden method must call [super serializeValue: withKey:] 34 | * to impelement the default logic for serialization for a specific key/value pair if it choose not to do any specific 35 | * implementation. 36 | * 37 | * @param value The value object from the NSDictionary object passed to the class 38 | * @param key The key object from the NSDictionary object passed to the class 39 | * 40 | */ 41 | - (void) serializeValue:(id)value withKey:(id)key; 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /SHModelObject.xcodeproj/xcuserdata/shan.haq.xcuserdatad/xcschemes/SHModelObject.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /SHModelObject.xcodeproj/xcuserdata/shanulhaq.xcuserdatad/xcschemes/SHModalObject.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 61 | 62 | 68 | 69 | 70 | 71 | 72 | 73 | 79 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /SHModelObject/SHAppDelegate.m: -------------------------------------------------------------------------------- 1 | // SHAppDelegate.m 2 | // 3 | // Copyright (c) 2014 Shan Ul Haq (http://grevolution.me) 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 | #import "SHAppDelegate.h" 24 | #import "SHTestModal.h" 25 | #import "SHRealmObject.h" 26 | #import 27 | #import 28 | 29 | @class Car; 30 | 31 | RLM_ARRAY_TYPE(Car) 32 | 33 | @interface Person : SHRealmObject 34 | @property NSString *name; 35 | @property int age; 36 | @property RLMArray *cars; 37 | @end 38 | 39 | @implementation Person 40 | @end 41 | 42 | @interface Car : SHRealmObject 43 | @property NSString *model; 44 | @end 45 | 46 | @implementation Car 47 | @end 48 | 49 | @implementation SHAppDelegate 50 | 51 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 52 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 53 | // Override point for customization after application launch. 54 | self.window.backgroundColor = [UIColor whiteColor]; 55 | [self.window makeKeyAndVisible]; 56 | NSDictionary *aDictionary = @{ 57 | @"string_value" : @"shan", 58 | @"another_string_value" : @"ul haq", 59 | @"INTVALUE" : @12, 60 | @"AnotherIntValue" : @23, 61 | @"integerValue" : @78, 62 | @"another_integer_value" : @98, 63 | @"numberVALUE" : @YES, 64 | @"another_numberVALUE" : @NO, 65 | @"remember" : @(false), 66 | @"do_it_my_self" : @"Yahooo", 67 | @"myArray" : @[ @"one", @2, @NO, @"four" ], 68 | @"_my_dictionary" : @{@"name" : @"correct name"}, 69 | @"time1" : @"2014-04-11T23:59:00+08:00", 70 | @"time2" : @"2014-04-11T23:59:00+08:00", 71 | @"time3" : @"2014-04-11T23:59:00+08:00", 72 | @"anotherModel" : @{@"modelId" : @1, @"modelName" : @"My Model", @"modelType" : @"My Model Type"}, 73 | @"arrayOfAnotherModels" : @[ 74 | @{@"modelId" : @2, @"modelName" : @"My Model 2", @"modelType" : @"My Model Type 2"}, 75 | @{@"modelId" : @3, @"modelName" : @"My Model 3", @"modelType" : @"My Model Type 3"}, 76 | @{@"modelId" : @4, @"modelName" : @"My Model 4", @"modelType" : @"My Model Type 4"} 77 | ] 78 | }; 79 | 80 | NSDictionary *mapping = @{ @"arrayOfAnotherModels" : @"SHAnotherModel" }; 81 | 82 | SHTestModal *model = [SHTestModal objectWithDictionary:aDictionary 83 | dateConversionOption:kDateConverstionFromNSStringToNSTimeIntervalOption 84 | inputDateType:kInputDateFormatDotNetWithTimeZone 85 | mappings:mapping]; 86 | 87 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 88 | NSString *documentsDirectoryPath = [paths objectAtIndex:0]; 89 | NSString *filePath = [documentsDirectoryPath stringByAppendingPathComponent:@"appData"]; 90 | 91 | BOOL isArchived = [NSKeyedArchiver archiveRootObject:model toFile:filePath]; 92 | SHTestModal *unarchived = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; 93 | 94 | NSLog([model description], nil); 95 | NSLog([unarchived description], nil); 96 | 97 | // realm testing 98 | [[NSFileManager defaultManager] removeItemAtURL:[[[RLMRealm defaultRealm] configuration] fileURL] error:nil]; 99 | RLMRealm *realm = [RLMRealm defaultRealm]; 100 | [realm transactionWithBlock:^{ 101 | NSDictionary *d = @{ 102 | @"nAme" : @"Shan Ul Haq", 103 | @"_AGE" : @26, 104 | @"cars" : @[ @{@"moDEL" : @"Honda"}, @{@"model" : @"Toyota"} ] 105 | }; 106 | Person *p = [Person objectWithDictionary:d mappings:@{ @"cars" : @"Car" }]; 107 | [realm addObject:p]; 108 | }]; 109 | 110 | // Log all dogs and their owners using the "owners" inverse relationship 111 | RLMResults *allPersons = [Person allObjects]; 112 | for (Person *person in allPersons) { 113 | NSLog(@" person name : %@", person.name); 114 | } 115 | 116 | // Log all dogs and their owners using the "owners" inverse relationship 117 | RLMResults *allCars = [Car allObjects]; 118 | for (Car *car in allCars) { 119 | NSLog(@"car model : %@", car.model); 120 | } 121 | 122 | return YES; 123 | } 124 | 125 | - (void)applicationWillResignActive:(UIApplication *)application { 126 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of 127 | // temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application 128 | // and it begins the transition to the background state. 129 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use 130 | // this method to pause the game. 131 | } 132 | 133 | - (void)applicationDidEnterBackground:(UIApplication *)application { 134 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application 135 | // state information to restore your application to its current state in case it is terminated later. 136 | // If your application supports background execution, this method is called instead of applicationWillTerminate: 137 | // when the user quits. 138 | } 139 | 140 | - (void)applicationWillEnterForeground:(UIApplication *)application { 141 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes 142 | // made on entering the background. 143 | } 144 | 145 | - (void)applicationDidBecomeActive:(UIApplication *)application { 146 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application 147 | // was previously in the background, optionally refresh the user interface. 148 | } 149 | 150 | - (void)applicationWillTerminate:(UIApplication *)application { 151 | // Called when the application is about to terminate. Save data if appropriate. See also 152 | // applicationDidEnterBackground:. 153 | } 154 | 155 | @end 156 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SHModelObject 2 | ============= 3 | 4 | `SHModelObject` is a utility model Base Class that uses objective-c runtime to assign the values to instance variables and properties of the model class from an `NSDictionary`, Which is a basic usecase when using webservices that return JSON response. 5 | 6 | [![Build Status](https://img.shields.io/travis/grevolution/SHModelObject.svg?branch=master)](https://travis-ci.org/grevolution/SHModelObject) [![Pod Version](https://img.shields.io/cocoapods/v/SHModelObject.svg)](https://img.shields.io/cocoapods/v/SHModelObject.svg) [![License](https://img.shields.io/cocoapods/l/SHModelObject.svg)](https://img.shields.io/cocoapods/l/SHModelObject.svg) 7 | 8 | Let say you have a WebService that serves you back the following Response: 9 | 10 | ```json 11 | { 12 | "user_name" : "Shan Ul Haq", 13 | "user_id" : 34567, 14 | "user_role" : "Author", 15 | "user_x_values" : [ 16 | "abcd", 777, "efgh" , true, false 17 | ] 18 | } 19 | ``` 20 | 21 | You parse this response using a JSON library and convert this response into a NSDictionary. Now another task is to populate following User model Object 22 | 23 | ```objective-c 24 | @interface User : NSObject { 25 | NSString *_userName; 26 | NSInteger _userId; 27 | NSString *userRole; 28 | } 29 | 30 | @property(nonatomic, strong) NSArray *userXValues; 31 | 32 | @end 33 | ``` 34 | 35 | To populate an Object of User, you will have to write some initializer that will take a NSDictionary and will populate the `ivars` and `properties` of your model class one by one. and you will have to do this 36 | for all the model classes that you have in your project. you will be adding something like below to your class and implement the method. 37 | 38 | - (User *)initWithDictionary:(NSDictionary *)responseDictionary; 39 | 40 | Thats where `SHModelObject` comes in, its a Single class with basic purpose to reduce this effort and do the work for you. all you have to do is `subclass` your model class with `SHModelObject`, so the above class becomes: 41 | 42 | 43 | ```objective-c 44 | @interface User : SHModelObject { 45 | NSString *_userName; 46 | NSInteger _userId; 47 | NSString *userRole; 48 | } 49 | 50 | @property(nonatomic, strong) NSArray *userXValues; 51 | 52 | @end 53 | ``` 54 | 55 | and thats it. `SHModelObject` has a basic initializer that will take the NSDictionary and will populate all the `ivars` and `properties` for you. 56 | 57 | just initialize the model with provided initializers and off you go. 58 | 59 | User *u = [[User alloc] initWithDictionary:responseDictionary]; 60 | 61 | ##How `SHModelObject` knows which value to assing to which instance variable? 62 | 63 | SHModelObject compares the keys of NSDictionary with the `ivar` or `property` names in an efficient way. while comparing the names of keys with ivars it doesnt take `_`, `-` or ` ` into account (also the case doesnt matter). so 64 | 65 | `user_name` OR `USER_NAME` OR `USERNAME` OR `UserName` will match with `_userName` OR `userName` OR `UserName` 66 | 67 | you can override `- (void)serializeValue:(id)value withKey:(id)key` method if you want to a custom logic to parse a specific key/value pair. make sure to call [super serializeValue] for the values you want to parse by default. 68 | 69 | ```objective-c 70 | - (void)serializeValue:(id)value withKey:(id)key 71 | { 72 | if([key isEqualToString:@"numberVALUE"]) { 73 | _numberValue = value; 74 | } else { 75 | [super serializeValue:value withKey:key]; 76 | } 77 | } 78 | ``` 79 | 80 | ##Parsing .NET JSON Dates to NSDate or NSTimeInterval 81 | 82 | you can use `kDateConversionOption` to convert the .NET JSON Date Strings to either `NSDate` or `NSTimeInterval` or keep it as `NSString` and parse yourself and also you can define `kInputDateFormat` to specify your input date format (JSON format, .NET Simple or .NET with timezone) 83 | 84 | 85 | ##Parsing instance variables which are also a subclass of `SHModelObject` 86 | 87 | you dont have to do anything :). `SHModelObject` automatically handles it. checkout the sample code. 88 | 89 | for example, following JSON 90 | 91 | ```json 92 | 93 | { 94 | "name" : "Shan Ul Haq", 95 | "person_id" : 123, 96 | "image" : { 97 | "image_id" : 234, 98 | "image_url" : "http://image_url", 99 | "orientation" : "portrait" 100 | } 101 | } 102 | 103 | ``` 104 | will be automatically parsed into following object: 105 | 106 | ```objective-c 107 | @interface Person : SHModelObject 108 | 109 | @property(nonatomic, strong) NSString *name; 110 | @property(nonatomic) int personId; 111 | @property(nonatomic, strong) Image *image; 112 | 113 | @end 114 | ``` 115 | where Image object is also a `SHModelObject` 116 | 117 | ```objective-c 118 | @interface Image : SHModelObject 119 | 120 | @property(nonatomic) int imageId; 121 | @property(nonatomic, strong) NSString *imageUrl; 122 | @property(nonatomic, strong) NSString *orientation; 123 | 124 | @end 125 | ``` 126 | 127 | ###Parsing arrays of objects which are a subclass of `SHModelObject` 128 | 129 | similar to parsing `SHModelObject` instance variables, arrays can be handled too. you need to specify the mapping which will define that the JSON array consist of which object type. 130 | 131 | for example, if you have following JSON 132 | 133 | ```json 134 | { 135 | "aKey" : "aValue", 136 | "arrayOfModels" : [ 137 | { 138 | "modelId" : 2, 139 | "modelName" : "My Model 2", 140 | "modelType" : "My Model Type 2" 141 | },{ 142 | "modelId" : 3, 143 | "modelName" : "My Model 3", 144 | "modelType" : "My Model Type 3" 145 | },{ 146 | "modelId" : 4, 147 | "modelName" : "My Model 4", 148 | "modelType" : "My Model Type 4" 149 | } 150 | ] 151 | } 152 | } 153 | ``` 154 | 155 | which translates to following objects. 156 | 157 | ```objective-c 158 | @interface MyObject : SHModelObject 159 | 160 | @property(nonatomic, strong) NSString *aKey; 161 | @property(nonatomic, strong) NSArray *arrayOfModels; 162 | 163 | @end 164 | 165 | @interface AModel : SHModelObject 166 | 167 | @property(nonatomic) int modelId; 168 | @property(nonatomic, strong) NSString *modelName; 169 | @property(nonatomic, strong) NSString *modelType; 170 | 171 | @end 172 | ``` 173 | 174 | you can convert json like this: 175 | 176 | ```objective-c 177 | // key is the variable name and value is the class name. 178 | NSDictionary *mappingDictionary = @{@"arrayOfModels" : "AModel"}; 179 | 180 | MyObject *myObject = [MyObject objectWithDictionary:dictionary mapping:mappingDictionary]; 181 | 182 | ``` 183 | 184 | ##SHRealmObject 185 | 186 | [Realm](http://realm.io/) support out of the box. `SHRealmObject` is a sublclass of `RLMObject` from Realm. If you want to use both SHModelObject to parse your JSON responses and have RLMObject to be used with Realm database. `SHRealmObject` is they class you need. 187 | 188 | `SHRealmObject` is identical in functionality as `SHModelObject` but also confirms with `RLMObject`. that means the it also confirms with the restriction that `RLMObject` class has. (e.g. you cannot use `NSDictionary` objects. and instead of using `NSArrays` you will use `RLMArray` objects). 189 | 190 | `RLMArray` objects will also be parsed automatically for you based on the mapping dictionary provided. (check out parsing arrays section above) 191 | 192 | Following is a simple example. 193 | 194 | 195 | ```objective-c 196 | @interface Person : SHRealmObject 197 | 198 | @property NSString *name; 199 | @property int age; 200 | @property RLMArray *cars; 201 | 202 | @end 203 | 204 | @implementation Person 205 | @end 206 | 207 | //// 208 | 209 | @interface Car : SHRealmObject 210 | @property NSString *model; 211 | @end 212 | 213 | @implementation Car 214 | @end 215 | ``` 216 | 217 | and to add an object in Realm database. 218 | 219 | ```objective-c 220 | RLMRealm *realm = [RLMRealm defaultRealm]; 221 | [realm transactionWithBlock:^{ 222 | NSDictionary *d = @{ 223 | @"nAme" : @"Shan Ul Haq", 224 | @"_AGE" : @26, 225 | @"cars" : @[ @{@"moDEL" : @"Honda"}, @{@"model" : @"Toyota"} ] 226 | }; 227 | Person *p = [Person objectWithDictionary:d mappings:@{ @"cars" : @"Car" }]; 228 | [realm addObject:p]; 229 | }]; 230 | ``` 231 | 232 | 233 | ##How to Use it. 234 | 235 | 1- add the files 236 | 237 | **Using Cocoapods** 238 | 239 | - add `pod 'SHModelObject/Core'` in your Podfile if you just want to use `SHModelObject` 240 | - add `pod 'SHModelObject/Realm'` in your Podfile if you want to use `SHRealmObject` with Realm. 241 | - add `pod 'SHModelObject'` in your Podfile if you want to use both `SHModelObject` and `SHRealmObject`. 242 | 243 | **Manual** 244 | 245 | - Just add the classes into your project. 246 | 247 | 2- sublcass your models with `SHModelObject` or `SHRealmObject` 248 | 249 | 3- initialize using the povided initializers and pass the response NSDictionary ( initWithDictionary: and other variants ) 250 | 251 | 4- override `serializeValue` if you want to parse a specific key/value your way. 252 | 253 | 5- thats it. off you go. 254 | 255 | ##Tasks Pending 256 | 257 | - [X] adding to cocoapods. 258 | - [X] adding support for custom instance variable types that are also subclasses of `SHModelObject` 259 | - [X] implementing `NSCoding` for archiving/unarchiving the model objects. 260 | - [X] adding support for handling arrays of custom `SHModelObject` objects. 261 | - [ ] implementing a deserializer for converting the object to NSDictionary. 262 | 263 | ##Contact Me 264 | 265 | Shan Ul Haq (http://grevolution.me) 266 | 267 | - g@grevolution.me 268 | 269 | - http://twitter.com/gfg5tek 270 | 271 | - http://sg.linkedin.com/in/grevolution/ 272 | 273 | ##License 274 | 275 | `SHModelObject` is available under the MIT license. See the LICENSE file for more info. 276 | -------------------------------------------------------------------------------- /SHModelObject/SHModelObject/SHModelObject.h: -------------------------------------------------------------------------------- 1 | // SHModelObject.h 2 | // 3 | // Copyright (c) 2014 Shan Ul Haq (http://grevolution.me) 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 | #import 24 | #import "SHModelSerialization.h" 25 | #import "SHConstants.h" 26 | 27 | /** 28 | * The `SHModelObject` is a base class that uses objective-c runtime to populate a modal class instance variables 29 | * by passing a NSDictionary to it. The NSDictionary key is compared with the instance variable name and the value is 30 | * populated to the variable. 31 | */ 32 | @interface SHModelObject : NSObject 33 | 34 | /** 35 | * class initializer 36 | * 37 | * @param dictionary dictionary containing key/value pairs for the object 38 | * 39 | * @return object of type instancetype populated with the values from `dictionary` 40 | */ 41 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary; 42 | 43 | /** 44 | * class initializer 45 | * 46 | * @param dictionary dictionary containing key/value pairs for the object 47 | * @param option `kDateConverstionOption` to determine what to do when the value from dictionary is a DOT.NET Date 48 | *type. 49 | * @param inputDateType `kInputDateFormat` to determine what what is the input format of the date. 50 | * 51 | * @return object of type instancetype populated with the values from `dictionary` 52 | */ 53 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary 54 | dateConversionOption:(kDateConversionOption)option 55 | inputDateType:(kInputDateFormat)inputDateType 56 | mappings:(NSDictionary *)mapping; 57 | 58 | /** 59 | * class initializer 60 | * 61 | * @param dictionary dictionary containing key/value pairs for the object 62 | * @param option `kDateConverstionOption` to determine what to do when the value from dictionary is a DOT.NET Date 63 | *type. 64 | * @param inputDateFormat NSDateFormatter format specifier which will be used to format the input date. this will use 65 | *the systemTimeZone to create the formatter 66 | * @param mapping dictionary to define the mappings for date conversion and array <-> object. 67 | * 68 | * @return object of type instancetype populated with the values from `dictionary` 69 | */ 70 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary 71 | dateConversionOption:(kDateConversionOption)option 72 | inputDateFormat:(NSString *)inputDateFormat 73 | mappings:(NSDictionary *)mapping; 74 | 75 | /** 76 | * class initializer 77 | * 78 | * @param dictionary dictionary containing key/value pairs for the object 79 | * @param option `kDateConverstionOption` to determine what to do when the value from dictionary is a DOT.NET Date 80 | *type. 81 | * @param inputDateFormatter NSDateFormatter object which will be used to format the input date. 82 | * @param mapping dictionary to define the mappings for date conversion and array <-> object. 83 | * 84 | * @return object of type instancetype populated with the values from `dictionary` 85 | */ 86 | 87 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary 88 | dateConversionOption:(kDateConversionOption)option 89 | inputDateFormatter:(NSDateFormatter *)inputDateFormatter 90 | mappings:(NSDictionary *)mapping; 91 | 92 | /** 93 | * static variant of class initializer with nil check for the dictionary passed 94 | * 95 | * @param dictionary dictionary containing key/value pairs for the object 96 | * 97 | * @return object of type instancetype populated with the values from `dictionary` 98 | */ 99 | + (instancetype)objectWithDictionary:(NSDictionary *)dictionary; 100 | 101 | /** 102 | * static variant of class initializer with nil check for the dictionary passed and mapping dictionary 103 | * this will use the default date conversion options (kDateConverstionFromNSStringToNSStringOption and 104 | * kInputDateFormatJSON) 105 | * 106 | * @param dictionary dictionary containing key/value pairs for the object 107 | * @param mapping dictionary to define the mappings for date conversion and array <-> object. 108 | * 109 | * @return object of type instancetype populated with the values from `dictionary` 110 | */ 111 | + (instancetype)objectWithDictionary:(NSDictionary *)dictionary mappings:(NSDictionary *)mapping; 112 | 113 | /** 114 | * static variant of class initializer with nil check for the dictionary passed 115 | * 116 | * @param dictionary dictionary containing key/value pairs for the object 117 | * @param option `kDateConverstionOption` to determine what to do when the value from dictionary is a DOT.NET Date 118 | *type. 119 | * @param inputDateType `kInputDateFormat` to determine what what is the input format of the date. 120 | * @param mapping dictionary to define the mappings for date conversion and array <-> object. 121 | * 122 | * @return object of type instancetype populated with the values from `dictionary` 123 | */ 124 | + (instancetype)objectWithDictionary:(NSDictionary *)dictionary 125 | dateConversionOption:(kDateConversionOption)option 126 | inputDateType:(kInputDateFormat)inputDateType 127 | mappings:(NSDictionary *)mapping; 128 | 129 | /** 130 | * static variant of class initializer with nil check for the dictionary passed 131 | * 132 | * @param dictionary dictionary containing key/value pairs for the object 133 | * @param option `kDateConverstionOption` to determine what to do when the value from dictionary is a DOT.NET Date 134 | *type. 135 | * @param inputDateFormat NSDateFormatter format specifier which will be used to format the input date. this will use 136 | *the systemTimeZone to create the formatter 137 | * @param mapping dictionary to define the mappings for date conversion and array <-> object. 138 | * 139 | * @return object of type instancetype populated with the values from `dictionary` 140 | */ 141 | + (instancetype)objectWithDictionary:(NSDictionary *)dictionary 142 | dateConversionOption:(kDateConversionOption)option 143 | inputDateFormat:(NSString *)inputDateFormat 144 | mappings:(NSDictionary *)mapping; 145 | 146 | /** 147 | * static variant of class initializer with nil check for the dictionary passed 148 | * 149 | * @param dictionary dictionary containing key/value pairs for the object 150 | * @param option `kDateConverstionOption` to determine what to do when the value from dictionary is a DOT.NET Date 151 | *type. 152 | * @param inputDateFormatter NSDateFormatter object which will be used to format the input date. 153 | * @param mapping dictionary to define the mappings for date conversion and array <-> object. 154 | * 155 | * @return object of type instancetype populated with the values from `dictionary` 156 | */ 157 | + (instancetype)objectWithDictionary:(NSDictionary *)dictionary 158 | dateConversionOption:(kDateConversionOption)option 159 | inputDateFormatter:(NSDateFormatter *)inputDateFormatter 160 | mappings:(NSDictionary *)mapping; 161 | 162 | /** 163 | * update the instance with new dictionary values 164 | * 165 | * @param dictionary dictionary containing key/value pairs for the object 166 | * 167 | * @return object of type instancetype populated with the values from `dictionary` 168 | */ 169 | - (instancetype)updateWithDictionary:(NSDictionary *)dictionary; 170 | 171 | /** 172 | * update the instance with new dictionary values 173 | * 174 | * @param dictionary dictionary containing key/value pairs for the object 175 | * @param option `kDateConverstionOption` to determine what to do when the value from dictionary is a DOT.NET Date 176 | *type. 177 | * @param inputDateType `kInputDateFormat` to determine what what is the input format of the date. 178 | * @param mapping dictionary to define the mappings for date conversion and array <-> object. 179 | * 180 | * @return object of type instancetype populated with the values from `dictionary` 181 | */ 182 | - (instancetype)updateWithDictionary:(NSDictionary *)dictionary 183 | dateConversionOption:(kDateConversionOption)option 184 | inputDateType:(kInputDateFormat)inputDateType 185 | mappings:(NSDictionary *)mapping; 186 | 187 | /** 188 | * update the instance with new dictionary values 189 | * 190 | * @param dictionary dictionary containing key/value pairs for the object 191 | * @param option `kDateConverstionOption` to determine what to do when the value from dictionary is a DOT.NET Date 192 | *type. 193 | * @param inputDateFormat NSDateFormatter format specifier which will be used to format the input date. this will use 194 | *the systemTimeZone to create the formatter 195 | * @param mapping dictionary to define the mappings for date conversion and array <-> object. 196 | * 197 | * @return object of type instancetype populated with the values from `dictionary` 198 | */ 199 | - (instancetype)updateWithDictionary:(NSDictionary *)dictionary 200 | dateConversionOption:(kDateConversionOption)option 201 | inputDateFormat:(NSString *)inputDateFormat 202 | mappings:(NSDictionary *)mapping; 203 | 204 | /** 205 | * update the instance with new dictionary values 206 | * 207 | * @param dictionary dictionary containing key/value pairs for the object 208 | * @param option `kDateConverstionOption` to determine what to do when the value from dictionary is a DOT.NET Date 209 | *type. 210 | * @param inputDateFormatter NSDateFormatter object which will be used to format the input date. 211 | * @param mapping dictionary to define the mappings for date conversion and array <-> object. 212 | * 213 | * @return object of type instancetype populated with the values from `dictionary` 214 | */ 215 | - (instancetype)updateWithDictionary:(NSDictionary *)dictionary 216 | dateConversionOption:(kDateConversionOption)option 217 | inputDateFormatter:(NSDateFormatter *)inputDateFormatter 218 | mappings:(NSDictionary *)mapping; 219 | 220 | @end 221 | 222 | @interface NSString (Additions) 223 | 224 | - (BOOL)contains:(NSString *)needle; 225 | 226 | @end -------------------------------------------------------------------------------- /SHModelObject/SHModelObject/SHRealmObject.h: -------------------------------------------------------------------------------- 1 | // SHRealmObject.h 2 | // 3 | // Copyright (c) 2014 Shan Ul Haq (http://grevolution.me) 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 | #import 24 | #import "SHModelSerialization.h" 25 | #import 26 | #import "SHConstants.h" 27 | 28 | /** 29 | * The `SHRealmObject` is a base class that uses objective-c runtime to populate a modal class instance variables 30 | * by passing a NSDictionary to it. The NSDictionary key is compared with the instance variable name and the value is 31 | * populated to the variable. 32 | */ 33 | @interface SHRealmObject : RLMObject 34 | 35 | /** 36 | * class initializer 37 | * 38 | * @param dictionary dictionary containing key/value pairs for the object 39 | * 40 | * @return object of type instancetype populated with the values from `dictionary` 41 | */ 42 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary; 43 | 44 | /** 45 | * class initializer 46 | * 47 | * @param dictionary dictionary containing key/value pairs for the object 48 | * @param option `kDateConverstionOption` to determine what to do when the value from dictionary is a DOT.NET Date 49 | *type. 50 | * @param inputDateType `kInputDateFormat` to determine what what is the input format of the date. 51 | * 52 | * @return object of type instancetype populated with the values from `dictionary` 53 | */ 54 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary 55 | dateConversionOption:(kDateConversionOption)option 56 | inputDateType:(kInputDateFormat)inputDateType 57 | mappings:(NSDictionary *)mapping; 58 | 59 | /** 60 | * class initializer 61 | * 62 | * @param dictionary dictionary containing key/value pairs for the object 63 | * @param option `kDateConverstionOption` to determine what to do when the value from dictionary is a DOT.NET Date 64 | *type. 65 | * @param inputDateFormat NSDateFormatter format specifier which will be used to format the input date. this will use 66 | *the systemTimeZone to create the formatter 67 | * @param mapping dictionary to define the mappings for date conversion and array <-> object. 68 | * 69 | * @return object of type instancetype populated with the values from `dictionary` 70 | */ 71 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary 72 | dateConversionOption:(kDateConversionOption)option 73 | inputDateFormat:(NSString *)inputDateFormat 74 | mappings:(NSDictionary *)mapping; 75 | 76 | /** 77 | * class initializer 78 | * 79 | * @param dictionary dictionary containing key/value pairs for the object 80 | * @param option `kDateConverstionOption` to determine what to do when the value from dictionary is a DOT.NET Date 81 | *type. 82 | * @param inputDateFormatter NSDateFormatter object which will be used to format the input date. 83 | * @param mapping dictionary to define the mappings for date conversion and array <-> object. 84 | * 85 | * @return object of type instancetype populated with the values from `dictionary` 86 | */ 87 | 88 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary 89 | dateConversionOption:(kDateConversionOption)option 90 | inputDateFormatter:(NSDateFormatter *)inputDateFormatter 91 | mappings:(NSDictionary *)mapping; 92 | 93 | 94 | /** 95 | * static variant of class initializer with nil check for the dictionary passed 96 | * 97 | * @param dictionary dictionary containing key/value pairs for the object 98 | * 99 | * @return object of type instancetype populated with the values from `dictionary` 100 | */ 101 | + (instancetype)objectWithDictionary:(NSDictionary *)dictionary; 102 | 103 | /** 104 | * static variant of class initializer with nil check for the dictionary passed and mapping dictionary 105 | * this will use the default date conversion options (kDateConverstionFromNSStringToNSStringOption and 106 | * kInputDateFormatJSON) 107 | * 108 | * @param dictionary dictionary containing key/value pairs for the object 109 | * @param mapping dictionary to define the mappings for date conversion and array <-> object. 110 | * 111 | * @return object of type instancetype populated with the values from `dictionary` 112 | */ 113 | + (instancetype)objectWithDictionary:(NSDictionary *)dictionary mappings:(NSDictionary *)mapping; 114 | 115 | /** 116 | * static variant of class initializer with nil check for the dictionary passed 117 | * 118 | * @param dictionary dictionary containing key/value pairs for the object 119 | * @param option `kDateConverstionOption` to determine what to do when the value from dictionary is a DOT.NET Date 120 | *type. 121 | * @param inputDateType `kInputDateFormat` to determine what what is the input format of the date. 122 | * @param mapping dictionary to define the mappings for date conversion and array <-> object. 123 | * 124 | * @return object of type instancetype populated with the values from `dictionary` 125 | */ 126 | + (instancetype)objectWithDictionary:(NSDictionary *)dictionary 127 | dateConversionOption:(kDateConversionOption)option 128 | inputDateType:(kInputDateFormat)inputDateType 129 | mappings:(NSDictionary *)mapping; 130 | 131 | /** 132 | * static variant of class initializer with nil check for the dictionary passed 133 | * 134 | * @param dictionary dictionary containing key/value pairs for the object 135 | * @param option `kDateConverstionOption` to determine what to do when the value from dictionary is a DOT.NET Date 136 | *type. 137 | * @param inputDateFormat NSDateFormatter format specifier which will be used to format the input date. this will use 138 | *the systemTimeZone to create the formatter 139 | * @param mapping dictionary to define the mappings for date conversion and array <-> object. 140 | * 141 | * @return object of type instancetype populated with the values from `dictionary` 142 | */ 143 | + (instancetype)objectWithDictionary:(NSDictionary *)dictionary 144 | dateConversionOption:(kDateConversionOption)option 145 | inputDateFormat:(NSString *)inputDateFormat 146 | mappings:(NSDictionary *)mapping; 147 | 148 | /** 149 | * static variant of class initializer with nil check for the dictionary passed 150 | * 151 | * @param dictionary dictionary containing key/value pairs for the object 152 | * @param option `kDateConverstionOption` to determine what to do when the value from dictionary is a DOT.NET Date 153 | *type. 154 | * @param inputDateFormatter NSDateFormatter object which will be used to format the input date. 155 | * @param mapping dictionary to define the mappings for date conversion and array <-> object. 156 | * 157 | * @return object of type instancetype populated with the values from `dictionary` 158 | */ 159 | + (instancetype)objectWithDictionary:(NSDictionary *)dictionary 160 | dateConversionOption:(kDateConversionOption)option 161 | inputDateFormatter:(NSDateFormatter *)inputDateFormatter 162 | mappings:(NSDictionary *)mapping; 163 | 164 | 165 | /** 166 | * update the instance with new dictionary values 167 | * 168 | * @param dictionary dictionary containing key/value pairs for the object 169 | * 170 | * @return object of type instancetype populated with the values from `dictionary` 171 | */ 172 | - (instancetype)updateWithDictionary:(NSDictionary *)dictionary; 173 | 174 | /** 175 | * update the instance with new dictionary values 176 | * 177 | * @param dictionary dictionary containing key/value pairs for the object 178 | * @param option `kDateConverstionOption` to determine what to do when the value from dictionary is a DOT.NET Date 179 | *type. 180 | * @param inputDateType `kInputDateFormat` to determine what what is the input format of the date. 181 | * @param mapping dictionary to define the mappings for date conversion and array <-> object. 182 | * 183 | * @return object of type instancetype populated with the values from `dictionary` 184 | */ 185 | - (instancetype)updateWithDictionary:(NSDictionary *)dictionary 186 | dateConversionOption:(kDateConversionOption)option 187 | inputDateType:(kInputDateFormat)inputDateType 188 | mappings:(NSDictionary *)mapping; 189 | 190 | /** 191 | * update the instance with new dictionary values 192 | * 193 | * @param dictionary dictionary containing key/value pairs for the object 194 | * @param option `kDateConverstionOption` to determine what to do when the value from dictionary is a DOT.NET Date 195 | *type. 196 | * @param inputDateFormat NSDateFormatter format specifier which will be used to format the input date. this will use 197 | *the systemTimeZone to create the formatter 198 | * @param mapping dictionary to define the mappings for date conversion and array <-> object. 199 | * 200 | * @return object of type instancetype populated with the values from `dictionary` 201 | */ 202 | - (instancetype)updateWithDictionary:(NSDictionary *)dictionary 203 | dateConversionOption:(kDateConversionOption)option 204 | inputDateFormat:(NSString *)inputDateFormat 205 | mappings:(NSDictionary *)mapping; 206 | 207 | /** 208 | * update the instance with new dictionary values 209 | * 210 | * @param dictionary dictionary containing key/value pairs for the object 211 | * @param option `kDateConverstionOption` to determine what to do when the value from dictionary is a DOT.NET Date 212 | *type. 213 | * @param inputDateFormatter NSDateFormatter object which will be used to format the input date. 214 | * @param mapping dictionary to define the mappings for date conversion and array <-> object. 215 | * 216 | * @return object of type instancetype populated with the values from `dictionary` 217 | */ 218 | - (instancetype)updateWithDictionary:(NSDictionary *)dictionary 219 | dateConversionOption:(kDateConversionOption)option 220 | inputDateFormatter:(NSDateFormatter *)inputDateFormatter 221 | mappings:(NSDictionary *)mapping; 222 | 223 | @end 224 | 225 | @interface NSString (Additions) 226 | 227 | - (BOOL)contains:(NSString *)needle; 228 | 229 | @end -------------------------------------------------------------------------------- /SHModelObject/SHModelObject/SHModelObject.m: -------------------------------------------------------------------------------- 1 | // SHModelObject.m 2 | // 3 | // Copyright (c) 2014 Shan Ul Haq (http://grevolution.me) 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 | #import "SHModelObject.h" 24 | #import 25 | 26 | /** 27 | * trims a given NSString 28 | * 29 | * @param val the NSString to be trimmed 30 | * 31 | * @return trimmed NSString 32 | */ 33 | #define TRIM_STRING(val) [val stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] 34 | 35 | /** 36 | * checks if a NSString is valid 37 | * 38 | * @param val a NSString to be checked 39 | * 40 | * @return `YES` or `NO` based on the validity of the NSString 41 | */ 42 | #define IS_VALID_STRING(val) \ 43 | (val != nil) && [val length] != 0 && ([TRIM_STRING(val) length] != 0) && ![val isEqualToString:@"(null)"] 44 | 45 | // pattern to strip from the dictionary key and ivarname for comparision 46 | #define PATTERN_TO_STRIP @"-_ " 47 | 48 | static NSDateFormatter *_simpleDateFormatter; 49 | static NSDateFormatter *_timezoneDateFormatter; 50 | static NSDateFormatter *_customFormatter; 51 | 52 | @implementation SHModelObject { 53 | Ivar *_ivars; 54 | unsigned int _outCount; 55 | kDateConversionOption _converstionOption; 56 | kInputDateFormat _inputDateFormat; 57 | NSDictionary *_mappings; 58 | NSString *_customInputDateFormatString; 59 | } 60 | 61 | #pragma mark - Factory methods for object creation 62 | // 63 | + (instancetype)objectWithDictionary:(NSDictionary *)dictionary { 64 | if (nil == dictionary || ![dictionary isKindOfClass:[NSDictionary class]]) { 65 | return nil; 66 | } 67 | 68 | if ([dictionary isKindOfClass:[NSNull class]]) { 69 | return nil; 70 | } 71 | return [[[self class] alloc] initWithDictionary:dictionary]; 72 | } 73 | 74 | + (instancetype)objectWithDictionary:(NSDictionary *)dictionary mappings:(NSDictionary *)mapping { 75 | if (nil == dictionary || ![dictionary isKindOfClass:[NSDictionary class]]) { 76 | return nil; 77 | } 78 | 79 | if ([dictionary isKindOfClass:[NSNull class]]) { 80 | return nil; 81 | } 82 | return [self objectWithDictionary:dictionary 83 | dateConversionOption:kDateConverstionFromNSStringToNSDateOption 84 | inputDateType:kInputDateFormatJSON 85 | mappings:mapping]; 86 | } 87 | 88 | + (instancetype)objectWithDictionary:(NSDictionary *)dictionary 89 | dateConversionOption:(kDateConversionOption)option 90 | inputDateType:(kInputDateFormat)inputDateType 91 | mappings:(NSDictionary *)mapping { 92 | if (nil == dictionary || ![dictionary isKindOfClass:[NSDictionary class]]) { 93 | return nil; 94 | } 95 | 96 | if ([dictionary isKindOfClass:[NSNull class]]) { 97 | return nil; 98 | } 99 | return [[[self class] alloc] initWithDictionary:dictionary 100 | dateConversionOption:option 101 | inputDateType:inputDateType 102 | mappings:mapping]; 103 | } 104 | 105 | + (instancetype)objectWithDictionary:(NSDictionary *)dictionary 106 | dateConversionOption:(kDateConversionOption)option 107 | inputDateFormat:(NSString *)inputDateFormat 108 | mappings:(NSDictionary *)mapping { 109 | if (nil == dictionary || ![dictionary isKindOfClass:[NSDictionary class]]) { 110 | return nil; 111 | } 112 | 113 | if ([dictionary isKindOfClass:[NSNull class]]) { 114 | return nil; 115 | } 116 | return [[[self class] alloc] initWithDictionary:dictionary 117 | dateConversionOption:option 118 | inputDateFormat:inputDateFormat 119 | mappings:mapping]; 120 | } 121 | 122 | + (instancetype)objectWithDictionary:(NSDictionary *)dictionary 123 | dateConversionOption:(kDateConversionOption)option 124 | inputDateFormatter:(NSDateFormatter *)inputDateFormatter 125 | mappings:(NSDictionary *)mapping { 126 | if (nil == dictionary || ![dictionary isKindOfClass:[NSDictionary class]]) { 127 | return nil; 128 | } 129 | 130 | if ([dictionary isKindOfClass:[NSNull class]]) { 131 | return nil; 132 | } 133 | return [[[self class] alloc] initWithDictionary:dictionary 134 | dateConversionOption:option 135 | inputDateFormatter:inputDateFormatter 136 | mappings:mapping]; 137 | } 138 | 139 | // 140 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary; 141 | { 142 | if ((self = [super init])) { 143 | return [self updateWithDictionary:dictionary 144 | dateConversionOption:kDateConverstionFromNSStringToNSStringOption 145 | inputDateType:kInputDateFormatJSON 146 | mappings:nil]; 147 | } 148 | return self; 149 | } 150 | 151 | // 152 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary 153 | dateConversionOption:(kDateConversionOption)option 154 | inputDateType:(kInputDateFormat)inputDateType 155 | mappings:(NSDictionary *)mapping { 156 | if ((self = [super init])) { 157 | return [self updateWithDictionary:dictionary 158 | dateConversionOption:option 159 | inputDateType:inputDateType 160 | mappings:mapping]; 161 | } 162 | return self; 163 | } 164 | 165 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary 166 | dateConversionOption:(kDateConversionOption)option 167 | inputDateFormat:(NSString *)inputDateFormat 168 | mappings:(NSDictionary *)mapping { 169 | if ((self = [super init])) { 170 | return [self updateWithDictionary:dictionary 171 | dateConversionOption:option 172 | inputDateFormat:inputDateFormat 173 | mappings:mapping]; 174 | } 175 | return self; 176 | } 177 | 178 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary 179 | dateConversionOption:(kDateConversionOption)option 180 | inputDateFormatter:(NSDateFormatter *)inputDateFormatter 181 | mappings:(NSDictionary *)mapping { 182 | if ((self = [super init])) { 183 | return [self updateWithDictionary:dictionary 184 | dateConversionOption:option 185 | inputDateFormatter:inputDateFormatter 186 | mappings:mapping]; 187 | } 188 | return self; 189 | } 190 | 191 | // NSCoding 192 | - (NSArray *)propertyNames { 193 | NSMutableArray *array = [NSMutableArray array]; 194 | 195 | // List of ivars 196 | id class = objc_getClass([NSStringFromClass([self class]) UTF8String]); 197 | _ivars = class_copyIvarList(class, &_outCount); 198 | 199 | // If it match our ivar name, then set it 200 | for (unsigned int i = 0; i < _outCount; i++) { 201 | Ivar ivar = _ivars[i]; 202 | NSString *ivarName = [NSString stringWithCString:ivar_getName(ivar) encoding:NSUTF8StringEncoding]; 203 | [array addObject:ivarName]; 204 | } 205 | 206 | free(_ivars); 207 | _ivars = NULL; 208 | return array; 209 | } 210 | 211 | - (id)initWithCoder:(NSCoder *)aDecoder { 212 | if ((self = [self init])) { 213 | // Loop through the properties 214 | for (NSString *key in [self propertyNames]) { 215 | // Decode the property, and use the KVC setValueForKey: method to set it 216 | id value = [aDecoder decodeObjectForKey:key]; 217 | [self setValue:value forKey:key]; 218 | } 219 | } 220 | return self; 221 | } 222 | 223 | - (void)encodeWithCoder:(NSCoder *)aCoder { 224 | // Loop through the properties 225 | for (NSString *key in [self propertyNames]) { 226 | // Use the KVC valueForKey: method to get the property and then encode it 227 | id value = [self valueForKey:key]; 228 | [aCoder encodeObject:value forKey:key]; 229 | } 230 | } 231 | 232 | // 233 | - (instancetype)updateWithDictionary:(NSDictionary *)dictionary { 234 | // List of ivars 235 | id class = objc_getClass([NSStringFromClass([self class]) UTF8String]); 236 | _ivars = class_copyIvarList(class, &_outCount); 237 | 238 | // For each top-level property in the dictionary 239 | NSEnumerator *enumerator = [dictionary keyEnumerator]; 240 | id key; 241 | while ((key = [enumerator nextObject])) { 242 | id value = [dictionary objectForKey:key]; 243 | [self serializeValue:value withKey:key]; 244 | } 245 | 246 | free(_ivars); 247 | _ivars = NULL; 248 | 249 | return self; 250 | } 251 | 252 | // 253 | - (instancetype)updateWithDictionary:(NSDictionary *)dictionary 254 | dateConversionOption:(kDateConversionOption)option 255 | inputDateType:(kInputDateFormat)inputDateType 256 | mappings:(NSDictionary *)mapping { 257 | _converstionOption = option; 258 | _inputDateFormat = inputDateType; 259 | _mappings = mapping; 260 | 261 | if (nil == _simpleDateFormatter) { 262 | _simpleDateFormatter = [[NSDateFormatter alloc] init]; 263 | [_simpleDateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss"]; 264 | } 265 | 266 | if (nil == _timezoneDateFormatter) { 267 | _timezoneDateFormatter = [[NSDateFormatter alloc] init]; 268 | [_timezoneDateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZZZZZ"]; 269 | } 270 | 271 | return [self updateWithDictionary:dictionary]; 272 | } 273 | 274 | - (instancetype)updateWithDictionary:(NSDictionary *)dictionary 275 | dateConversionOption:(kDateConversionOption)option 276 | inputDateFormat:(NSString *)inputDateFormat 277 | mappings:(NSDictionary *)mapping { 278 | _converstionOption = option; 279 | _inputDateFormat = kInputDateFormatCustom; 280 | _customInputDateFormatString = inputDateFormat; 281 | if (_customInputDateFormatString && !_customFormatter) { 282 | _customFormatter = [[NSDateFormatter alloc] init]; 283 | [_customFormatter setDateFormat:_customInputDateFormatString]; 284 | } 285 | _mappings = mapping; 286 | 287 | return [self updateWithDictionary:dictionary]; 288 | } 289 | 290 | - (instancetype)updateWithDictionary:(NSDictionary *)dictionary 291 | dateConversionOption:(kDateConversionOption)option 292 | inputDateFormatter:(NSDateFormatter *)inputDateFormatter 293 | mappings:(NSDictionary *)mapping { 294 | _converstionOption = option; 295 | _inputDateFormat = kInputDateFormatCustom; 296 | _customFormatter = inputDateFormatter; 297 | _mappings = mapping; 298 | 299 | return [self updateWithDictionary:dictionary]; 300 | } 301 | 302 | #pragma mark - SHModalSerialization protocol methods 303 | 304 | - (void)serializeValue:(id)value withKey:(id)key { 305 | // check for NSNull or nil for key 306 | if ([key isKindOfClass:[NSNull class]] || nil == key) { 307 | return; 308 | } 309 | 310 | // check for NSNull or nil for value 311 | if ([value isKindOfClass:[NSNull class]] || nil == value) { 312 | return; 313 | } 314 | 315 | // If it match our ivar name, then set it 316 | for (unsigned int i = 0; i < _outCount; i++) { 317 | Ivar ivar = _ivars[i]; 318 | NSString *ivarName = [NSString stringWithCString:ivar_getName(ivar) encoding:NSUTF8StringEncoding]; 319 | NSString *ivarType = [NSString stringWithCString:ivar_getTypeEncoding(ivar) encoding:NSUTF8StringEncoding]; 320 | 321 | if ([self matchesPattern:key ivar:ivarName] == NO) { 322 | continue; 323 | } 324 | 325 | // it will be NSString, NSNumber, NSArray, NSDictionary or NSNull 326 | if ([value isKindOfClass:[NSString class]]) { 327 | 328 | /* 329 | converting the .NET JSON Date representation to either NSDate, NSTimeInterval or keeping it as 330 | NSString. if somebody wants a different conversion, please simplye override the method and parse the 331 | value and set for yourself and make sure you call [super serializeValue: key:] for all other values so 332 | that they are parsed correctly. 333 | */ 334 | switch (_converstionOption) { 335 | case kDateConverstionFromNSStringToNSDateOption: { 336 | if ([ivarType contains:@"NSDate"]) { 337 | switch (_inputDateFormat) { 338 | case kInputDateFormatJSON: { 339 | value = (NSDate *)[self dateFromDotNetJSONString:value]; 340 | } break; 341 | case kInputDateFormatDotNetSimple: { 342 | value = (NSDate *)[_simpleDateFormatter dateFromString:value]; 343 | } break; 344 | case kInputDateFormatDotNetWithTimeZone: { 345 | value = (NSDate *)[_timezoneDateFormatter dateFromString:value]; 346 | } break; 347 | case kInputDateFormatCustom: { 348 | value = (NSDate *)[_customFormatter dateFromString:value]; 349 | } break; 350 | default: { value = (NSDate *)[self dateFromDotNetJSONString:value]; } break; 351 | } 352 | } 353 | } break; 354 | case kDateConverstionFromNSStringToNSTimeIntervalOption: { 355 | if (![ivarType contains:@"@"]) { 356 | switch (_inputDateFormat) { 357 | case kInputDateFormatJSON: { 358 | value = @([[self dateFromDotNetJSONString:value] timeIntervalSince1970]); 359 | } break; 360 | case kInputDateFormatDotNetSimple: { 361 | value = @([[_simpleDateFormatter dateFromString:value] timeIntervalSince1970]); 362 | } break; 363 | case kInputDateFormatDotNetWithTimeZone: { 364 | value = @([[_timezoneDateFormatter dateFromString:value] timeIntervalSince1970]); 365 | } break; 366 | case kInputDateFormatCustom: { 367 | value = @([[_customFormatter dateFromString:value] timeIntervalSince1970]); 368 | } break; 369 | default: { 370 | value = @([[self dateFromDotNetJSONString:value] timeIntervalSince1970]); 371 | } break; 372 | } 373 | } 374 | } break; 375 | case kDateConverstionFromNSStringToNSStringOption: { 376 | if (![ivarType contains:NSStringFromClass([NSString class])]) { 377 | NSAssert(false, @"the types do not match : %@ vs %@", ivarType, @"NSString"); 378 | } 379 | } 380 | } 381 | } else if ([value isKindOfClass:[NSNumber class]] && ![ivarType contains:@"NSNumber"]) { 382 | // special case, where NSNumber can be stored into the primitive types. just need to chceck that iVar is not 383 | // an object. 384 | if ([ivarType contains:@"@"]) { 385 | NSAssert(false, @"the types do not match : %@ vs %@", ivarType, @"NSNumber"); 386 | } 387 | } else if ([value isKindOfClass:[NSDictionary class]]) { 388 | NSString *typeName = [ivarType stringByReplacingOccurrencesOfString:@"@" withString:@""]; 389 | typeName = [typeName stringByReplacingOccurrencesOfString:@"\"" withString:@""]; 390 | Class objectClass = NSClassFromString(typeName); 391 | BOOL isSHModelObject = [self isSHModelObject:objectClass]; 392 | if (isSHModelObject) { 393 | value = [objectClass objectWithDictionary:value]; 394 | } else if (![ivarType contains:@"Dictionary"]) { 395 | NSAssert(false, @"the types do not match : %@ vs %@", ivarType, @"NSDictionary or NSMutableDictionary"); 396 | } 397 | } else if ([value isKindOfClass:[NSArray class]]) { 398 | if (![ivarType contains:@"Array"]) { 399 | NSAssert(false, @"the types do not match : %@ vs %@", ivarType, @"NSArray or NSMutableArray"); 400 | } 401 | 402 | id availableMappingClass = _mappings[key]; 403 | if (availableMappingClass && [availableMappingClass isKindOfClass:[NSString class]]) { 404 | // mapping string available. 405 | Class objectClass = NSClassFromString(availableMappingClass); 406 | BOOL isSHModelObject = [self isSHModelObject:objectClass]; 407 | if (isSHModelObject) { 408 | NSMutableArray *valueArray = [NSMutableArray arrayWithCapacity:[value count]]; 409 | for (id item in value) { 410 | // item should be a dictionary 411 | if ([item isKindOfClass:[NSDictionary class]]) { 412 | id itemObject = [objectClass objectWithDictionary:item mappings:_mappings]; 413 | if (itemObject) { 414 | [valueArray addObject:itemObject]; 415 | } 416 | } else { 417 | NSLog(@"object %@ is not a NSDictionary object, skipping.", [item description]); 418 | } 419 | } 420 | value = valueArray; 421 | } 422 | } 423 | } 424 | 425 | [self setValue:value forKey:ivarName]; 426 | } 427 | } 428 | 429 | - (BOOL)isSHModelObject:(Class) class { 430 | if (class == nil) 431 | return NO; 432 | if (class == [SHModelObject class]) { 433 | return YES; 434 | } 435 | return [self isSHModelObject:[class superclass]]; 436 | } 437 | 438 | #pragma mark - NSObject overriden methods 439 | 440 | // 441 | - 442 | (NSString *)description { 443 | return [NSString stringWithFormat:@"<%@ %p>", NSStringFromClass([self class]), self]; 444 | } 445 | 446 | #pragma mark - SHModalSerializer helper functions 447 | 448 | - (BOOL)matchesPattern:(NSString *)key ivar:(NSString *)ivarName { 449 | if (nil == key || nil == ivarName) { 450 | return NO; 451 | } 452 | 453 | if ((!IS_VALID_STRING(key)) || (!IS_VALID_STRING(ivarName))) { 454 | return NO; 455 | } 456 | 457 | NSMutableString *prettyKey = [NSMutableString stringWithCapacity:key.length]; 458 | NSMutableString *prettyIvar = [NSMutableString stringWithCapacity:ivarName.length]; 459 | 460 | NSScanner *scannerForKey = [NSScanner scannerWithString:key]; 461 | NSScanner *scannerForIvar = [NSScanner scannerWithString:ivarName]; 462 | 463 | scannerForKey.caseSensitive = NO; 464 | scannerForIvar.caseSensitive = NO; 465 | 466 | NSCharacterSet *stripChars = [[NSCharacterSet characterSetWithCharactersInString:PATTERN_TO_STRIP] invertedSet]; 467 | while ([scannerForKey isAtEnd] == NO) { 468 | NSString *buffer; 469 | if ([scannerForKey scanCharactersFromSet:stripChars intoString:&buffer]) { 470 | [prettyKey appendString:buffer]; 471 | 472 | } else { 473 | [scannerForKey setScanLocation:([scannerForKey scanLocation] + 1)]; 474 | } 475 | } 476 | 477 | while ([scannerForIvar isAtEnd] == NO) { 478 | NSString *buffer; 479 | if ([scannerForIvar scanCharactersFromSet:stripChars intoString:&buffer]) { 480 | [prettyIvar appendString:buffer]; 481 | } else { 482 | [scannerForIvar setScanLocation:([scannerForIvar scanLocation] + 1)]; 483 | } 484 | } 485 | 486 | return ([[prettyKey lowercaseString] isEqualToString:[prettyIvar lowercaseString]]); 487 | } 488 | 489 | - (NSDate *)dateFromDotNetJSONString:(NSString *)string { 490 | if (!string) { 491 | return nil; 492 | } 493 | static NSRegularExpression *dateRegEx = nil; 494 | static dispatch_once_t onceToken; 495 | dispatch_once(&onceToken, ^{ 496 | dateRegEx = [[NSRegularExpression alloc] initWithPattern:@"^\\/date\\((-?\\d++)(?:([+-])(\\d{2})(\\d{2}))?\\)\\/$" 497 | options:NSRegularExpressionCaseInsensitive 498 | error:nil]; 499 | }); 500 | NSTextCheckingResult *regexResult = 501 | [dateRegEx firstMatchInString:string options:0 range:NSMakeRange(0, [string length])]; 502 | 503 | if (regexResult) { 504 | // milliseconds 505 | NSTimeInterval seconds = [[string substringWithRange:[regexResult rangeAtIndex:1]] doubleValue] / 1000.0; 506 | // timezone offset 507 | if ([regexResult rangeAtIndex:2].location != NSNotFound) { 508 | NSString *sign = [string substringWithRange:[regexResult rangeAtIndex:2]]; 509 | // hours 510 | seconds += [[NSString stringWithFormat:@"%@%@", sign, [string substringWithRange:[regexResult rangeAtIndex:3]]] doubleValue] * 60.0 * 60.0; 511 | // minutes 512 | seconds += [[NSString stringWithFormat:@"%@%@", sign, [string substringWithRange:[regexResult rangeAtIndex:4]]] doubleValue] * 60.0; 513 | } 514 | 515 | return [NSDate dateWithTimeIntervalSince1970:seconds]; 516 | } 517 | return nil; 518 | } 519 | 520 | @end 521 | 522 | #pragma mark - NSString+Additions 523 | 524 | @implementation NSString (Additions) 525 | 526 | - (BOOL)contains:(NSString *)needle; 527 | { 528 | NSRange range = [self rangeOfString:needle options:NSCaseInsensitiveSearch]; 529 | return (range.length == needle.length && range.location != NSNotFound); 530 | } 531 | 532 | @end 533 | -------------------------------------------------------------------------------- /SHModelObject/SHModelObject/SHRealmObject.m: -------------------------------------------------------------------------------- 1 | // SHRealmObject.m 2 | // 3 | // Copyright (c) 2014 Shan Ul Haq (http://grevolution.me) 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 | #import "SHRealmObject.h" 24 | #import 25 | #import 26 | 27 | /** 28 | * trims a given NSString 29 | * 30 | * @param val the NSString to be trimmed 31 | * 32 | * @return trimmed NSString 33 | */ 34 | #define TRIM_STRING(val) [val stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] 35 | 36 | /** 37 | * checks if a NSString is valid 38 | * 39 | * @param val a NSString to be checked 40 | * 41 | * @return `YES` or `NO` based on the validity of the NSString 42 | */ 43 | #define IS_VALID_STRING(val) \ 44 | (val != nil) && [val length] != 0 && ([TRIM_STRING(val) length] != 0) && ![val isEqualToString:@"(null)"] 45 | 46 | // pattern to strip from the dictionary key and ivarname for comparision 47 | #define PATTERN_TO_STRIP @"-_ " 48 | 49 | static NSDateFormatter *_simpleDateFormatter; 50 | static NSDateFormatter *_timezoneDateFormatter; 51 | static NSDateFormatter *_customFormatter; 52 | 53 | @implementation SHRealmObject { 54 | Ivar *_ivars; 55 | unsigned int _outCount; 56 | kDateConversionOption _converstionOption; 57 | kInputDateFormat _inputDateFormat; 58 | NSDictionary *_mappings; 59 | NSString *_customInputDateFormatString; 60 | } 61 | 62 | #pragma mark - Factory methods for object creation 63 | // 64 | + (instancetype)objectWithDictionary:(NSDictionary *)dictionary { 65 | if (nil == dictionary || ![dictionary isKindOfClass:[NSDictionary class]]) { 66 | return nil; 67 | } 68 | 69 | if ([dictionary isKindOfClass:[NSNull class]]) { 70 | return nil; 71 | } 72 | return [[[self class] alloc] initWithDictionary:dictionary]; 73 | } 74 | 75 | + (instancetype)objectWithDictionary:(NSDictionary *)dictionary mappings:(NSDictionary *)mapping { 76 | if (nil == dictionary || ![dictionary isKindOfClass:[NSDictionary class]]) { 77 | return nil; 78 | } 79 | 80 | if ([dictionary isKindOfClass:[NSNull class]]) { 81 | return nil; 82 | } 83 | return [self objectWithDictionary:dictionary 84 | dateConversionOption:kDateConverstionFromNSStringToNSDateOption 85 | inputDateType:kInputDateFormatJSON 86 | mappings:mapping]; 87 | } 88 | 89 | + (instancetype)objectWithDictionary:(NSDictionary *)dictionary 90 | dateConversionOption:(kDateConversionOption)option 91 | inputDateType:(kInputDateFormat)inputDateType 92 | mappings:(NSDictionary *)mapping { 93 | if (nil == dictionary || ![dictionary isKindOfClass:[NSDictionary class]]) { 94 | return nil; 95 | } 96 | 97 | if ([dictionary isKindOfClass:[NSNull class]]) { 98 | return nil; 99 | } 100 | return [[[self class] alloc] initWithDictionary:dictionary 101 | dateConversionOption:option 102 | inputDateType:inputDateType 103 | mappings:mapping]; 104 | } 105 | 106 | + (instancetype)objectWithDictionary:(NSDictionary *)dictionary 107 | dateConversionOption:(kDateConversionOption)option 108 | inputDateFormat:(NSString *)inputDateFormat 109 | mappings:(NSDictionary *)mapping { 110 | if (nil == dictionary || ![dictionary isKindOfClass:[NSDictionary class]]) { 111 | return nil; 112 | } 113 | 114 | if ([dictionary isKindOfClass:[NSNull class]]) { 115 | return nil; 116 | } 117 | return [[[self class] alloc] initWithDictionary:dictionary 118 | dateConversionOption:option 119 | inputDateFormat:inputDateFormat 120 | mappings:mapping]; 121 | } 122 | 123 | + (instancetype)objectWithDictionary:(NSDictionary *)dictionary 124 | dateConversionOption:(kDateConversionOption)option 125 | inputDateFormatter:(NSDateFormatter *)inputDateFormatter 126 | mappings:(NSDictionary *)mapping { 127 | if (nil == dictionary || ![dictionary isKindOfClass:[NSDictionary class]]) { 128 | return nil; 129 | } 130 | 131 | if ([dictionary isKindOfClass:[NSNull class]]) { 132 | return nil; 133 | } 134 | return [[[self class] alloc] initWithDictionary:dictionary 135 | dateConversionOption:option 136 | inputDateFormatter:inputDateFormatter 137 | mappings:mapping]; 138 | } 139 | 140 | // 141 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary; 142 | { 143 | if ((self = [super init])) { 144 | return [self updateWithDictionary:dictionary 145 | dateConversionOption:kDateConverstionFromNSStringToNSStringOption 146 | inputDateType:kInputDateFormatJSON 147 | mappings:nil]; 148 | } 149 | return self; 150 | } 151 | 152 | // 153 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary 154 | dateConversionOption:(kDateConversionOption)option 155 | inputDateType:(kInputDateFormat)inputDateType 156 | mappings:(NSDictionary *)mapping { 157 | if ((self = [super init])) { 158 | return [self updateWithDictionary:dictionary 159 | dateConversionOption:option 160 | inputDateType:inputDateType 161 | mappings:mapping]; 162 | } 163 | return self; 164 | } 165 | 166 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary 167 | dateConversionOption:(kDateConversionOption)option 168 | inputDateFormat:(NSString *)inputDateFormat 169 | mappings:(NSDictionary *)mapping { 170 | if ((self = [super init])) { 171 | return [self updateWithDictionary:dictionary 172 | dateConversionOption:option 173 | inputDateFormat:inputDateFormat 174 | mappings:mapping]; 175 | } 176 | return self; 177 | } 178 | 179 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary 180 | dateConversionOption:(kDateConversionOption)option 181 | inputDateFormatter:(NSDateFormatter *)inputDateFormatter 182 | mappings:(NSDictionary *)mapping { 183 | if ((self = [super init])) { 184 | return [self updateWithDictionary:dictionary 185 | dateConversionOption:option 186 | inputDateFormatter:inputDateFormatter 187 | mappings:mapping]; 188 | } 189 | return self; 190 | } 191 | 192 | // NSCoding 193 | - (NSArray *)propertyNames { 194 | NSMutableArray *array = [NSMutableArray array]; 195 | 196 | // List of ivars 197 | NSString *selfClassName = NSStringFromClass([self class]); 198 | NSString *actualClassName = [[selfClassName componentsSeparatedByString:@"_"] lastObject]; 199 | id class = objc_getClass([actualClassName UTF8String]); 200 | _ivars = class_copyIvarList(class, &_outCount); 201 | 202 | // If it match our ivar name, then set it 203 | for (unsigned int i = 0; i < _outCount; i++) { 204 | Ivar ivar = _ivars[i]; 205 | NSString *ivarName = [NSString stringWithCString:ivar_getName(ivar) encoding:NSUTF8StringEncoding]; 206 | [array addObject:ivarName]; 207 | } 208 | 209 | free(_ivars); 210 | _ivars = NULL; 211 | return array; 212 | } 213 | 214 | - (id)initWithCoder:(NSCoder *)aDecoder { 215 | if ((self = [self init])) { 216 | // Loop through the properties 217 | for (NSString *key in [self propertyNames]) { 218 | // Decode the property, and use the KVC setValueForKey: method to set it 219 | id value = [aDecoder decodeObjectForKey:key]; 220 | [self setValue:value forKey:key]; 221 | } 222 | } 223 | return self; 224 | } 225 | 226 | - (void)encodeWithCoder:(NSCoder *)aCoder { 227 | // Loop through the properties 228 | for (NSString *key in [self propertyNames]) { 229 | // Use the KVC valueForKey: method to get the property and then encode it 230 | id value = [self valueForKey:key]; 231 | [aCoder encodeObject:value forKey:key]; 232 | } 233 | } 234 | 235 | // 236 | - (instancetype)updateWithDictionary:(NSDictionary *)dictionary { 237 | // List of ivars 238 | NSString *selfClassName = NSStringFromClass([self class]); 239 | NSString *actualClassName = [[selfClassName componentsSeparatedByString:@"_"] lastObject]; 240 | id class = objc_getClass([actualClassName UTF8String]); 241 | _ivars = class_copyIvarList(class, &_outCount); 242 | 243 | // For each top-level property in the dictionary 244 | NSEnumerator *enumerator = [dictionary keyEnumerator]; 245 | id key; 246 | while ((key = [enumerator nextObject])) { 247 | id value = [dictionary objectForKey:key]; 248 | [self serializeValue:value withKey:key]; 249 | } 250 | 251 | free(_ivars); 252 | _ivars = NULL; 253 | 254 | return self; 255 | } 256 | 257 | // 258 | - (instancetype)updateWithDictionary:(NSDictionary *)dictionary 259 | dateConversionOption:(kDateConversionOption)option 260 | inputDateType:(kInputDateFormat)inputDateType 261 | mappings:(NSDictionary *)mapping { 262 | _converstionOption = option; 263 | _inputDateFormat = inputDateType; 264 | _mappings = mapping; 265 | 266 | if (nil == _simpleDateFormatter) { 267 | _simpleDateFormatter = [[NSDateFormatter alloc] init]; 268 | [_simpleDateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss"]; 269 | } 270 | 271 | if (nil == _timezoneDateFormatter) { 272 | _timezoneDateFormatter = [[NSDateFormatter alloc] init]; 273 | [_timezoneDateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZZZZZ"]; 274 | } 275 | 276 | return [self updateWithDictionary:dictionary]; 277 | } 278 | 279 | - (instancetype)updateWithDictionary:(NSDictionary *)dictionary 280 | dateConversionOption:(kDateConversionOption)option 281 | inputDateFormat:(NSString *)inputDateFormat 282 | mappings:(NSDictionary *)mapping { 283 | _converstionOption = option; 284 | _inputDateFormat = kInputDateFormatCustom; 285 | _customInputDateFormatString = inputDateFormat; 286 | if (_customInputDateFormatString && !_customFormatter) { 287 | _customFormatter = [[NSDateFormatter alloc] init]; 288 | [_customFormatter setDateFormat:_customInputDateFormatString]; 289 | } 290 | _mappings = mapping; 291 | 292 | return [self updateWithDictionary:dictionary]; 293 | } 294 | 295 | - (instancetype)updateWithDictionary:(NSDictionary *)dictionary 296 | dateConversionOption:(kDateConversionOption)option 297 | inputDateFormatter:(NSDateFormatter *)inputDateFormatter 298 | mappings:(NSDictionary *)mapping { 299 | _converstionOption = option; 300 | _inputDateFormat = kInputDateFormatCustom; 301 | _customFormatter = inputDateFormatter; 302 | _mappings = mapping; 303 | 304 | return [self updateWithDictionary:dictionary]; 305 | } 306 | 307 | #pragma mark - SHModalSerialization protocol methods 308 | 309 | - (void)serializeValue:(id)value withKey:(id)key { 310 | // check for NSNull or nil for key 311 | if ([key isKindOfClass:[NSNull class]] || nil == key) { 312 | return; 313 | } 314 | 315 | // check for NSNull or nil for value 316 | if ([value isKindOfClass:[NSNull class]] || nil == value) { 317 | return; 318 | } 319 | 320 | // If it match our ivar name, then set it 321 | for (unsigned int i = 0; i < _outCount; i++) { 322 | Ivar ivar = _ivars[i]; 323 | NSString *ivarName = [NSString stringWithCString:ivar_getName(ivar) encoding:NSUTF8StringEncoding]; 324 | NSString *ivarType = [NSString stringWithCString:ivar_getTypeEncoding(ivar) encoding:NSUTF8StringEncoding]; 325 | 326 | if ([self matchesPattern:key ivar:ivarName] == NO) { 327 | continue; 328 | } 329 | 330 | // it will be NSString, NSNumber, NSArray, NSDictionary or NSNull 331 | if ([value isKindOfClass:[NSString class]]) { 332 | 333 | /* 334 | converting the .NET JSON Date representation to either NSDate, NSTimeInterval or keeping it as 335 | NSString. if somebody wants a different conversion, please simplye override the method and parse the 336 | value and set for yourself and make sure you call [super serializeValue: key:] for all other values so 337 | that they are parsed correctly. 338 | */ 339 | switch (_converstionOption) { 340 | case kDateConverstionFromNSStringToNSDateOption: { 341 | if ([ivarType contains:@"NSDate"]) { 342 | switch (_inputDateFormat) { 343 | case kInputDateFormatJSON: { 344 | value = (NSDate *)[self dateFromDotNetJSONString:value]; 345 | } break; 346 | case kInputDateFormatDotNetSimple: { 347 | value = (NSDate *)[_simpleDateFormatter dateFromString:value]; 348 | } break; 349 | case kInputDateFormatDotNetWithTimeZone: { 350 | value = (NSDate *)[_timezoneDateFormatter dateFromString:value]; 351 | } break; 352 | case kInputDateFormatCustom: { 353 | value = (NSDate *)[_customFormatter dateFromString:value]; 354 | } break; 355 | 356 | default: { value = (NSDate *)[self dateFromDotNetJSONString:value]; } break; 357 | } 358 | } 359 | } break; 360 | case kDateConverstionFromNSStringToNSTimeIntervalOption: { 361 | if (![ivarType contains:@"@"]) { 362 | switch (_inputDateFormat) { 363 | case kInputDateFormatJSON: { 364 | value = @([[self dateFromDotNetJSONString:value] timeIntervalSince1970]); 365 | } break; 366 | case kInputDateFormatDotNetSimple: { 367 | value = @([[_simpleDateFormatter dateFromString:value] timeIntervalSince1970]); 368 | } break; 369 | case kInputDateFormatDotNetWithTimeZone: { 370 | value = @([[_timezoneDateFormatter dateFromString:value] timeIntervalSince1970]); 371 | } break; 372 | case kInputDateFormatCustom: { 373 | value = @([[_customFormatter dateFromString:value] timeIntervalSince1970]); 374 | } break; 375 | default: { 376 | value = @([[self dateFromDotNetJSONString:value] timeIntervalSince1970]); 377 | } break; 378 | } 379 | } 380 | } break; 381 | case kDateConverstionFromNSStringToNSStringOption: { 382 | if (![ivarType contains:NSStringFromClass([NSString class])]) { 383 | NSAssert(false, @"the types do not match : %@ vs %@", ivarType, @"NSString"); 384 | } 385 | } 386 | } 387 | } else if ([value isKindOfClass:[NSNumber class]] && ![ivarType contains:@"NSNumber"]) { 388 | // special case, where NSNumber can be stored into the primitive types. just need to chceck that iVar is not 389 | // an object. 390 | if ([ivarType contains:@"@"]) { 391 | NSAssert(false, @"the types do not match : %@ vs %@", ivarType, @"NSNumber"); 392 | } 393 | } else if ([value isKindOfClass:[NSDictionary class]]) { 394 | NSString *typeName = [ivarType stringByReplacingOccurrencesOfString:@"@" withString:@""]; 395 | typeName = [typeName stringByReplacingOccurrencesOfString:@"\"" withString:@""]; 396 | Class objectClass = NSClassFromString(typeName); 397 | BOOL isSHRealmObject = [self isSHRealmObject:objectClass]; 398 | if (isSHRealmObject) { 399 | value = [objectClass objectWithDictionary:value]; 400 | } else if (![ivarType contains:@"Dictionary"]) { 401 | NSAssert(false, @"the types do not match : %@ vs %@", ivarType, @"NSDictionary or NSMutableDictionary"); 402 | } 403 | } else if ([value isKindOfClass:[NSArray class]]) { 404 | if (![ivarType contains:@"Array"]) { 405 | NSAssert(false, @"the types do not match : %@ vs %@", ivarType, @"NSArray or NSMutableArray"); 406 | } 407 | 408 | id availableMappingClass = _mappings[key]; 409 | if (availableMappingClass && [availableMappingClass isKindOfClass:[NSString class]]) { 410 | // mapping string available. 411 | Class objectClass = NSClassFromString(availableMappingClass); 412 | BOOL isSHRealmObject = [self isSHRealmObject:objectClass]; 413 | if (isSHRealmObject) { 414 | 415 | NSString *propName = [ivarName substringFromIndex:1]; 416 | id realmArray = ((id (*)(id, SEL))objc_msgSend)(self, NSSelectorFromString(propName)); 417 | for (id item in value) { 418 | // item should be a dictionary 419 | if ([item isKindOfClass:[NSDictionary class]]) { 420 | id itemObject = [objectClass objectWithDictionary:item mappings:_mappings]; 421 | if (itemObject) { 422 | if ([realmArray respondsToSelector:@selector(addObject:)]) { 423 | [realmArray addObject:itemObject]; 424 | } 425 | } 426 | } else { 427 | NSLog(@"object %@ is not a NSDictionary object, skipping.", [item description]); 428 | } 429 | } 430 | } 431 | } 432 | return; 433 | } 434 | [self setValue:value forKey:ivarName]; 435 | } 436 | } 437 | 438 | - (BOOL)isSHRealmObject:(Class) class { 439 | if (class == nil) 440 | return NO; 441 | if (class == [SHRealmObject class]) { 442 | return YES; 443 | } 444 | return [self isSHRealmObject:[class superclass]]; 445 | } 446 | 447 | #pragma mark - NSObject overriden methods 448 | 449 | // 450 | - 451 | (NSString *)description { 452 | return [NSString stringWithFormat:@"<%@ %p>", NSStringFromClass([self class]), self]; 453 | } 454 | 455 | #pragma mark - SHModalSerializer helper functions 456 | 457 | - (BOOL)matchesPattern:(NSString *)key ivar:(NSString *)ivarName { 458 | if (nil == key || nil == ivarName) { 459 | return NO; 460 | } 461 | 462 | if ((!IS_VALID_STRING(key)) || (!IS_VALID_STRING(ivarName))) { 463 | return NO; 464 | } 465 | 466 | NSMutableString *prettyKey = [NSMutableString stringWithCapacity:key.length]; 467 | NSMutableString *prettyIvar = [NSMutableString stringWithCapacity:ivarName.length]; 468 | 469 | NSScanner *scannerForKey = [NSScanner scannerWithString:key]; 470 | NSScanner *scannerForIvar = [NSScanner scannerWithString:ivarName]; 471 | 472 | scannerForKey.caseSensitive = NO; 473 | scannerForIvar.caseSensitive = NO; 474 | 475 | NSCharacterSet *stripChars = [[NSCharacterSet characterSetWithCharactersInString:PATTERN_TO_STRIP] invertedSet]; 476 | while ([scannerForKey isAtEnd] == NO) { 477 | NSString *buffer; 478 | if ([scannerForKey scanCharactersFromSet:stripChars intoString:&buffer]) { 479 | [prettyKey appendString:buffer]; 480 | 481 | } else { 482 | [scannerForKey setScanLocation:([scannerForKey scanLocation] + 1)]; 483 | } 484 | } 485 | 486 | while ([scannerForIvar isAtEnd] == NO) { 487 | NSString *buffer; 488 | if ([scannerForIvar scanCharactersFromSet:stripChars intoString:&buffer]) { 489 | [prettyIvar appendString:buffer]; 490 | } else { 491 | [scannerForIvar setScanLocation:([scannerForIvar scanLocation] + 1)]; 492 | } 493 | } 494 | 495 | return ([[prettyKey lowercaseString] isEqualToString:[prettyIvar lowercaseString]]); 496 | } 497 | 498 | - (NSDate *)dateFromDotNetJSONString:(NSString *)string { 499 | if (!string) { 500 | return nil; 501 | } 502 | static NSRegularExpression *dateRegEx = nil; 503 | static dispatch_once_t onceToken; 504 | dispatch_once(&onceToken, ^{ 505 | dateRegEx = 506 | [[NSRegularExpression alloc] initWithPattern:@"^\\/date\\((-?\\d++)(?:([+-])(\\d{2})(\\d{2}))?\\)\\/$" 507 | options:NSRegularExpressionCaseInsensitive 508 | error:nil]; 509 | }); 510 | NSTextCheckingResult *regexResult = 511 | [dateRegEx firstMatchInString:string options:0 range:NSMakeRange(0, [string length])]; 512 | 513 | if (regexResult) { 514 | // milliseconds 515 | NSTimeInterval seconds = [[string substringWithRange:[regexResult rangeAtIndex:1]] doubleValue] / 1000.0; 516 | // timezone offset 517 | if ([regexResult rangeAtIndex:2].location != NSNotFound) { 518 | NSString *sign = [string substringWithRange:[regexResult rangeAtIndex:2]]; 519 | // hours 520 | seconds += [[NSString stringWithFormat:@"%@%@", sign, [string substringWithRange:[regexResult rangeAtIndex:3]]] doubleValue] * 60.0 * 60.0; 521 | // minutes 522 | seconds += [[NSString stringWithFormat:@"%@%@", sign, [string substringWithRange:[regexResult rangeAtIndex:4]]] doubleValue] * 60.0; 523 | } 524 | 525 | return [NSDate dateWithTimeIntervalSince1970:seconds]; 526 | } 527 | return nil; 528 | } 529 | 530 | @end 531 | 532 | #pragma mark - NSString+Additions 533 | 534 | @implementation NSString (Additions) 535 | 536 | - (BOOL)contains:(NSString *)needle; 537 | { 538 | NSRange range = [self rangeOfString:needle options:NSCaseInsensitiveSearch]; 539 | return (range.length == needle.length && range.location != NSNotFound); 540 | } 541 | 542 | @end 543 | -------------------------------------------------------------------------------- /SHModelObject.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 66D76422E11513B26933E1D3 /* libPods-SHModelObject.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F0DD241F9FB35F3F93B212D7 /* libPods-SHModelObject.a */; }; 11 | F23ED34A1ACECF1100DECB41 /* SHModelObject.m in Sources */ = {isa = PBXBuildFile; fileRef = F23ED3491ACECF1100DECB41 /* SHModelObject.m */; }; 12 | F244007518DACD6B0078B6B0 /* SHRealmObject.m in Sources */ = {isa = PBXBuildFile; fileRef = F244006F18DACD6B0078B6B0 /* SHRealmObject.m */; }; 13 | F244007618DACD6B0078B6B0 /* SHAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = F244007118DACD6B0078B6B0 /* SHAppDelegate.m */; }; 14 | F244007718DACD6B0078B6B0 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F244007218DACD6B0078B6B0 /* Images.xcassets */; }; 15 | F2B4093118BA16F400611B29 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F2B4093018BA16F400611B29 /* Foundation.framework */; }; 16 | F2B4093318BA16F400611B29 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F2B4093218BA16F400611B29 /* CoreGraphics.framework */; }; 17 | F2B4093518BA16F400611B29 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F2B4093418BA16F400611B29 /* UIKit.framework */; }; 18 | F2B4093B18BA16F400611B29 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = F2B4093918BA16F400611B29 /* InfoPlist.strings */; }; 19 | F2B4093D18BA16F400611B29 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = F2B4093C18BA16F400611B29 /* main.m */; }; 20 | F2B4094A18BA16F500611B29 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F2B4094918BA16F500611B29 /* XCTest.framework */; }; 21 | F2B4094B18BA16F500611B29 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F2B4093018BA16F400611B29 /* Foundation.framework */; }; 22 | F2B4094C18BA16F500611B29 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F2B4093418BA16F400611B29 /* UIKit.framework */; }; 23 | F2B4095418BA16F500611B29 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = F2B4095218BA16F500611B29 /* InfoPlist.strings */; }; 24 | F2B4095618BA16F500611B29 /* SHModalObjectTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F2B4095518BA16F500611B29 /* SHModalObjectTests.m */; }; 25 | F2FA97791AB40312002B972D /* SHAnotherModel.m in Sources */ = {isa = PBXBuildFile; fileRef = F2FA97781AB40312002B972D /* SHAnotherModel.m */; }; 26 | F2FA977C1AB40377002B972D /* SHTestModal.m in Sources */ = {isa = PBXBuildFile; fileRef = F2FA977B1AB40377002B972D /* SHTestModal.m */; }; 27 | /* End PBXBuildFile section */ 28 | 29 | /* Begin PBXContainerItemProxy section */ 30 | F2B4094D18BA16F500611B29 /* PBXContainerItemProxy */ = { 31 | isa = PBXContainerItemProxy; 32 | containerPortal = F2B4092518BA16F400611B29 /* Project object */; 33 | proxyType = 1; 34 | remoteGlobalIDString = F2B4092C18BA16F400611B29; 35 | remoteInfo = SHModalObject; 36 | }; 37 | /* End PBXContainerItemProxy section */ 38 | 39 | /* Begin PBXFileReference section */ 40 | 2E37114A22AF21385F13CD70 /* Pods-SHModelObject.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SHModelObject.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SHModelObject/Pods-SHModelObject.debug.xcconfig"; sourceTree = ""; }; 41 | A11D18FAC0D2005DF68AFF60 /* Pods-SHModelObject.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SHModelObject.release.xcconfig"; path = "Pods/Target Support Files/Pods-SHModelObject/Pods-SHModelObject.release.xcconfig"; sourceTree = ""; }; 42 | F0DD241F9FB35F3F93B212D7 /* libPods-SHModelObject.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-SHModelObject.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 43 | F23ED3481ACECF1100DECB41 /* SHModelObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHModelObject.h; sourceTree = ""; }; 44 | F23ED3491ACECF1100DECB41 /* SHModelObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHModelObject.m; sourceTree = ""; }; 45 | F23ED34B1ACF64F400DECB41 /* SHConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHConstants.h; sourceTree = ""; }; 46 | F244006E18DACD6B0078B6B0 /* SHRealmObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHRealmObject.h; sourceTree = ""; }; 47 | F244006F18DACD6B0078B6B0 /* SHRealmObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHRealmObject.m; sourceTree = ""; }; 48 | F244007018DACD6B0078B6B0 /* SHModelSerialization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHModelSerialization.h; sourceTree = ""; }; 49 | F244007118DACD6B0078B6B0 /* SHAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHAppDelegate.m; sourceTree = ""; }; 50 | F244007218DACD6B0078B6B0 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 51 | F244007318DACD6B0078B6B0 /* SHAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHAppDelegate.h; sourceTree = ""; }; 52 | F2B4092D18BA16F400611B29 /* SHModelObject.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SHModelObject.app; sourceTree = BUILT_PRODUCTS_DIR; }; 53 | F2B4093018BA16F400611B29 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 54 | F2B4093218BA16F400611B29 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 55 | F2B4093418BA16F400611B29 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 56 | F2B4093818BA16F400611B29 /* SHModelObject-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "SHModelObject-Info.plist"; sourceTree = ""; }; 57 | F2B4093A18BA16F400611B29 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 58 | F2B4093C18BA16F400611B29 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 59 | F2B4093E18BA16F400611B29 /* SHModelObject-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SHModelObject-Prefix.pch"; sourceTree = ""; }; 60 | F2B4094818BA16F500611B29 /* SHModelObjectTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SHModelObjectTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 61 | F2B4094918BA16F500611B29 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 62 | F2B4095118BA16F500611B29 /* SHModelObjectTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "SHModelObjectTests-Info.plist"; sourceTree = ""; }; 63 | F2B4095318BA16F500611B29 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 64 | F2B4095518BA16F500611B29 /* SHModalObjectTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SHModalObjectTests.m; sourceTree = ""; }; 65 | F2FA97771AB40312002B972D /* SHAnotherModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHAnotherModel.h; sourceTree = ""; }; 66 | F2FA97781AB40312002B972D /* SHAnotherModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHAnotherModel.m; sourceTree = ""; }; 67 | F2FA977A1AB40377002B972D /* SHTestModal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHTestModal.h; sourceTree = ""; }; 68 | F2FA977B1AB40377002B972D /* SHTestModal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHTestModal.m; sourceTree = ""; }; 69 | /* End PBXFileReference section */ 70 | 71 | /* Begin PBXFrameworksBuildPhase section */ 72 | F2B4092A18BA16F400611B29 /* Frameworks */ = { 73 | isa = PBXFrameworksBuildPhase; 74 | buildActionMask = 2147483647; 75 | files = ( 76 | F2B4093318BA16F400611B29 /* CoreGraphics.framework in Frameworks */, 77 | F2B4093518BA16F400611B29 /* UIKit.framework in Frameworks */, 78 | F2B4093118BA16F400611B29 /* Foundation.framework in Frameworks */, 79 | 66D76422E11513B26933E1D3 /* libPods-SHModelObject.a in Frameworks */, 80 | ); 81 | runOnlyForDeploymentPostprocessing = 0; 82 | }; 83 | F2B4094518BA16F500611B29 /* Frameworks */ = { 84 | isa = PBXFrameworksBuildPhase; 85 | buildActionMask = 2147483647; 86 | files = ( 87 | F2B4094A18BA16F500611B29 /* XCTest.framework in Frameworks */, 88 | F2B4094C18BA16F500611B29 /* UIKit.framework in Frameworks */, 89 | F2B4094B18BA16F500611B29 /* Foundation.framework in Frameworks */, 90 | ); 91 | runOnlyForDeploymentPostprocessing = 0; 92 | }; 93 | /* End PBXFrameworksBuildPhase section */ 94 | 95 | /* Begin PBXGroup section */ 96 | 9CC53B38E18E241B9ED13283 /* Pods */ = { 97 | isa = PBXGroup; 98 | children = ( 99 | 2E37114A22AF21385F13CD70 /* Pods-SHModelObject.debug.xcconfig */, 100 | A11D18FAC0D2005DF68AFF60 /* Pods-SHModelObject.release.xcconfig */, 101 | ); 102 | name = Pods; 103 | sourceTree = ""; 104 | }; 105 | F244006D18DACD6B0078B6B0 /* SHModelObject */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | F23ED3481ACECF1100DECB41 /* SHModelObject.h */, 109 | F23ED3491ACECF1100DECB41 /* SHModelObject.m */, 110 | F244006E18DACD6B0078B6B0 /* SHRealmObject.h */, 111 | F244006F18DACD6B0078B6B0 /* SHRealmObject.m */, 112 | F244007018DACD6B0078B6B0 /* SHModelSerialization.h */, 113 | F23ED34B1ACF64F400DECB41 /* SHConstants.h */, 114 | ); 115 | path = SHModelObject; 116 | sourceTree = ""; 117 | }; 118 | F2B4092418BA16F400611B29 = { 119 | isa = PBXGroup; 120 | children = ( 121 | F2B4093618BA16F400611B29 /* SHModelObject */, 122 | F2B4094F18BA16F500611B29 /* SHModelObjectTests */, 123 | F2B4092F18BA16F400611B29 /* Frameworks */, 124 | F2B4092E18BA16F400611B29 /* Products */, 125 | 9CC53B38E18E241B9ED13283 /* Pods */, 126 | ); 127 | sourceTree = ""; 128 | }; 129 | F2B4092E18BA16F400611B29 /* Products */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | F2B4092D18BA16F400611B29 /* SHModelObject.app */, 133 | F2B4094818BA16F500611B29 /* SHModelObjectTests.xctest */, 134 | ); 135 | name = Products; 136 | sourceTree = ""; 137 | }; 138 | F2B4092F18BA16F400611B29 /* Frameworks */ = { 139 | isa = PBXGroup; 140 | children = ( 141 | F2B4093018BA16F400611B29 /* Foundation.framework */, 142 | F2B4093218BA16F400611B29 /* CoreGraphics.framework */, 143 | F2B4093418BA16F400611B29 /* UIKit.framework */, 144 | F2B4094918BA16F500611B29 /* XCTest.framework */, 145 | F0DD241F9FB35F3F93B212D7 /* libPods-SHModelObject.a */, 146 | ); 147 | name = Frameworks; 148 | sourceTree = ""; 149 | }; 150 | F2B4093618BA16F400611B29 /* SHModelObject */ = { 151 | isa = PBXGroup; 152 | children = ( 153 | F244006D18DACD6B0078B6B0 /* SHModelObject */, 154 | F244007118DACD6B0078B6B0 /* SHAppDelegate.m */, 155 | F244007318DACD6B0078B6B0 /* SHAppDelegate.h */, 156 | F244007218DACD6B0078B6B0 /* Images.xcassets */, 157 | F2B4093718BA16F400611B29 /* Supporting Files */, 158 | F2FA977A1AB40377002B972D /* SHTestModal.h */, 159 | F2FA977B1AB40377002B972D /* SHTestModal.m */, 160 | F2FA97771AB40312002B972D /* SHAnotherModel.h */, 161 | F2FA97781AB40312002B972D /* SHAnotherModel.m */, 162 | ); 163 | path = SHModelObject; 164 | sourceTree = ""; 165 | }; 166 | F2B4093718BA16F400611B29 /* Supporting Files */ = { 167 | isa = PBXGroup; 168 | children = ( 169 | F2B4093818BA16F400611B29 /* SHModelObject-Info.plist */, 170 | F2B4093918BA16F400611B29 /* InfoPlist.strings */, 171 | F2B4093C18BA16F400611B29 /* main.m */, 172 | F2B4093E18BA16F400611B29 /* SHModelObject-Prefix.pch */, 173 | ); 174 | name = "Supporting Files"; 175 | sourceTree = ""; 176 | }; 177 | F2B4094F18BA16F500611B29 /* SHModelObjectTests */ = { 178 | isa = PBXGroup; 179 | children = ( 180 | F2B4095518BA16F500611B29 /* SHModalObjectTests.m */, 181 | F2B4095018BA16F500611B29 /* Supporting Files */, 182 | ); 183 | path = SHModelObjectTests; 184 | sourceTree = ""; 185 | }; 186 | F2B4095018BA16F500611B29 /* Supporting Files */ = { 187 | isa = PBXGroup; 188 | children = ( 189 | F2B4095118BA16F500611B29 /* SHModelObjectTests-Info.plist */, 190 | F2B4095218BA16F500611B29 /* InfoPlist.strings */, 191 | ); 192 | name = "Supporting Files"; 193 | sourceTree = ""; 194 | }; 195 | /* End PBXGroup section */ 196 | 197 | /* Begin PBXNativeTarget section */ 198 | F2B4092C18BA16F400611B29 /* SHModelObject */ = { 199 | isa = PBXNativeTarget; 200 | buildConfigurationList = F2B4095918BA16F500611B29 /* Build configuration list for PBXNativeTarget "SHModelObject" */; 201 | buildPhases = ( 202 | 76C12C901F41E58794DEA0B3 /* 📦 Check Pods Manifest.lock */, 203 | F2B4092918BA16F400611B29 /* Sources */, 204 | F2B4092A18BA16F400611B29 /* Frameworks */, 205 | F2B4092B18BA16F400611B29 /* Resources */, 206 | D220DA26D629C2FF6DDD81B5 /* 📦 Embed Pods Frameworks */, 207 | B01D7BF1DBBA78C75C6A004B /* 📦 Copy Pods Resources */, 208 | ); 209 | buildRules = ( 210 | ); 211 | dependencies = ( 212 | ); 213 | name = SHModelObject; 214 | productName = SHModalObject; 215 | productReference = F2B4092D18BA16F400611B29 /* SHModelObject.app */; 216 | productType = "com.apple.product-type.application"; 217 | }; 218 | F2B4094718BA16F500611B29 /* SHModelObjectTests */ = { 219 | isa = PBXNativeTarget; 220 | buildConfigurationList = F2B4095C18BA16F500611B29 /* Build configuration list for PBXNativeTarget "SHModelObjectTests" */; 221 | buildPhases = ( 222 | F2B4094418BA16F500611B29 /* Sources */, 223 | F2B4094518BA16F500611B29 /* Frameworks */, 224 | F2B4094618BA16F500611B29 /* Resources */, 225 | ); 226 | buildRules = ( 227 | ); 228 | dependencies = ( 229 | F2B4094E18BA16F500611B29 /* PBXTargetDependency */, 230 | ); 231 | name = SHModelObjectTests; 232 | productName = SHModalObjectTests; 233 | productReference = F2B4094818BA16F500611B29 /* SHModelObjectTests.xctest */; 234 | productType = "com.apple.product-type.bundle.unit-test"; 235 | }; 236 | /* End PBXNativeTarget section */ 237 | 238 | /* Begin PBXProject section */ 239 | F2B4092518BA16F400611B29 /* Project object */ = { 240 | isa = PBXProject; 241 | attributes = { 242 | CLASSPREFIX = SH; 243 | LastUpgradeCheck = 0500; 244 | ORGANIZATIONNAME = grevolution; 245 | }; 246 | buildConfigurationList = F2B4092818BA16F400611B29 /* Build configuration list for PBXProject "SHModelObject" */; 247 | compatibilityVersion = "Xcode 3.2"; 248 | developmentRegion = English; 249 | hasScannedForEncodings = 0; 250 | knownRegions = ( 251 | en, 252 | ); 253 | mainGroup = F2B4092418BA16F400611B29; 254 | productRefGroup = F2B4092E18BA16F400611B29 /* Products */; 255 | projectDirPath = ""; 256 | projectRoot = ""; 257 | targets = ( 258 | F2B4092C18BA16F400611B29 /* SHModelObject */, 259 | F2B4094718BA16F500611B29 /* SHModelObjectTests */, 260 | ); 261 | }; 262 | /* End PBXProject section */ 263 | 264 | /* Begin PBXResourcesBuildPhase section */ 265 | F2B4092B18BA16F400611B29 /* Resources */ = { 266 | isa = PBXResourcesBuildPhase; 267 | buildActionMask = 2147483647; 268 | files = ( 269 | F2B4093B18BA16F400611B29 /* InfoPlist.strings in Resources */, 270 | F244007718DACD6B0078B6B0 /* Images.xcassets in Resources */, 271 | ); 272 | runOnlyForDeploymentPostprocessing = 0; 273 | }; 274 | F2B4094618BA16F500611B29 /* Resources */ = { 275 | isa = PBXResourcesBuildPhase; 276 | buildActionMask = 2147483647; 277 | files = ( 278 | F2B4095418BA16F500611B29 /* InfoPlist.strings in Resources */, 279 | ); 280 | runOnlyForDeploymentPostprocessing = 0; 281 | }; 282 | /* End PBXResourcesBuildPhase section */ 283 | 284 | /* Begin PBXShellScriptBuildPhase section */ 285 | 76C12C901F41E58794DEA0B3 /* 📦 Check Pods Manifest.lock */ = { 286 | isa = PBXShellScriptBuildPhase; 287 | buildActionMask = 2147483647; 288 | files = ( 289 | ); 290 | inputPaths = ( 291 | ); 292 | name = "📦 Check Pods Manifest.lock"; 293 | outputPaths = ( 294 | ); 295 | runOnlyForDeploymentPostprocessing = 0; 296 | shellPath = /bin/sh; 297 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; 298 | showEnvVarsInLog = 0; 299 | }; 300 | B01D7BF1DBBA78C75C6A004B /* 📦 Copy Pods Resources */ = { 301 | isa = PBXShellScriptBuildPhase; 302 | buildActionMask = 2147483647; 303 | files = ( 304 | ); 305 | inputPaths = ( 306 | ); 307 | name = "📦 Copy Pods Resources"; 308 | outputPaths = ( 309 | ); 310 | runOnlyForDeploymentPostprocessing = 0; 311 | shellPath = /bin/sh; 312 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SHModelObject/Pods-SHModelObject-resources.sh\"\n"; 313 | showEnvVarsInLog = 0; 314 | }; 315 | D220DA26D629C2FF6DDD81B5 /* 📦 Embed Pods Frameworks */ = { 316 | isa = PBXShellScriptBuildPhase; 317 | buildActionMask = 2147483647; 318 | files = ( 319 | ); 320 | inputPaths = ( 321 | ); 322 | name = "📦 Embed Pods Frameworks"; 323 | outputPaths = ( 324 | ); 325 | runOnlyForDeploymentPostprocessing = 0; 326 | shellPath = /bin/sh; 327 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SHModelObject/Pods-SHModelObject-frameworks.sh\"\n"; 328 | showEnvVarsInLog = 0; 329 | }; 330 | /* End PBXShellScriptBuildPhase section */ 331 | 332 | /* Begin PBXSourcesBuildPhase section */ 333 | F2B4092918BA16F400611B29 /* Sources */ = { 334 | isa = PBXSourcesBuildPhase; 335 | buildActionMask = 2147483647; 336 | files = ( 337 | F2FA97791AB40312002B972D /* SHAnotherModel.m in Sources */, 338 | F23ED34A1ACECF1100DECB41 /* SHModelObject.m in Sources */, 339 | F2B4093D18BA16F400611B29 /* main.m in Sources */, 340 | F244007518DACD6B0078B6B0 /* SHRealmObject.m in Sources */, 341 | F244007618DACD6B0078B6B0 /* SHAppDelegate.m in Sources */, 342 | F2FA977C1AB40377002B972D /* SHTestModal.m in Sources */, 343 | ); 344 | runOnlyForDeploymentPostprocessing = 0; 345 | }; 346 | F2B4094418BA16F500611B29 /* Sources */ = { 347 | isa = PBXSourcesBuildPhase; 348 | buildActionMask = 2147483647; 349 | files = ( 350 | F2B4095618BA16F500611B29 /* SHModalObjectTests.m in Sources */, 351 | ); 352 | runOnlyForDeploymentPostprocessing = 0; 353 | }; 354 | /* End PBXSourcesBuildPhase section */ 355 | 356 | /* Begin PBXTargetDependency section */ 357 | F2B4094E18BA16F500611B29 /* PBXTargetDependency */ = { 358 | isa = PBXTargetDependency; 359 | target = F2B4092C18BA16F400611B29 /* SHModelObject */; 360 | targetProxy = F2B4094D18BA16F500611B29 /* PBXContainerItemProxy */; 361 | }; 362 | /* End PBXTargetDependency section */ 363 | 364 | /* Begin PBXVariantGroup section */ 365 | F2B4093918BA16F400611B29 /* InfoPlist.strings */ = { 366 | isa = PBXVariantGroup; 367 | children = ( 368 | F2B4093A18BA16F400611B29 /* en */, 369 | ); 370 | name = InfoPlist.strings; 371 | sourceTree = ""; 372 | }; 373 | F2B4095218BA16F500611B29 /* InfoPlist.strings */ = { 374 | isa = PBXVariantGroup; 375 | children = ( 376 | F2B4095318BA16F500611B29 /* en */, 377 | ); 378 | name = InfoPlist.strings; 379 | sourceTree = ""; 380 | }; 381 | /* End PBXVariantGroup section */ 382 | 383 | /* Begin XCBuildConfiguration section */ 384 | F2B4095718BA16F500611B29 /* Debug */ = { 385 | isa = XCBuildConfiguration; 386 | buildSettings = { 387 | ALWAYS_SEARCH_USER_PATHS = NO; 388 | ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; 389 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 390 | CLANG_CXX_LIBRARY = "libc++"; 391 | CLANG_ENABLE_MODULES = YES; 392 | CLANG_ENABLE_OBJC_ARC = YES; 393 | CLANG_WARN_BOOL_CONVERSION = YES; 394 | CLANG_WARN_CONSTANT_CONVERSION = YES; 395 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 396 | CLANG_WARN_EMPTY_BODY = YES; 397 | CLANG_WARN_ENUM_CONVERSION = YES; 398 | CLANG_WARN_INT_CONVERSION = YES; 399 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 400 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 401 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 402 | COPY_PHASE_STRIP = NO; 403 | GCC_C_LANGUAGE_STANDARD = gnu99; 404 | GCC_DYNAMIC_NO_PIC = NO; 405 | GCC_OPTIMIZATION_LEVEL = 0; 406 | GCC_PREPROCESSOR_DEFINITIONS = ( 407 | "DEBUG=1", 408 | "$(inherited)", 409 | ); 410 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 411 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 412 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 413 | GCC_WARN_UNDECLARED_SELECTOR = YES; 414 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 415 | GCC_WARN_UNUSED_FUNCTION = YES; 416 | GCC_WARN_UNUSED_VARIABLE = YES; 417 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 418 | ONLY_ACTIVE_ARCH = YES; 419 | SDKROOT = iphoneos; 420 | TARGETED_DEVICE_FAMILY = "1,2"; 421 | }; 422 | name = Debug; 423 | }; 424 | F2B4095818BA16F500611B29 /* Release */ = { 425 | isa = XCBuildConfiguration; 426 | buildSettings = { 427 | ALWAYS_SEARCH_USER_PATHS = NO; 428 | ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; 429 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 430 | CLANG_CXX_LIBRARY = "libc++"; 431 | CLANG_ENABLE_MODULES = YES; 432 | CLANG_ENABLE_OBJC_ARC = YES; 433 | CLANG_WARN_BOOL_CONVERSION = YES; 434 | CLANG_WARN_CONSTANT_CONVERSION = YES; 435 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 436 | CLANG_WARN_EMPTY_BODY = YES; 437 | CLANG_WARN_ENUM_CONVERSION = YES; 438 | CLANG_WARN_INT_CONVERSION = YES; 439 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 440 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 441 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 442 | COPY_PHASE_STRIP = YES; 443 | ENABLE_NS_ASSERTIONS = NO; 444 | GCC_C_LANGUAGE_STANDARD = gnu99; 445 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 446 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 447 | GCC_WARN_UNDECLARED_SELECTOR = YES; 448 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 449 | GCC_WARN_UNUSED_FUNCTION = YES; 450 | GCC_WARN_UNUSED_VARIABLE = YES; 451 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 452 | SDKROOT = iphoneos; 453 | TARGETED_DEVICE_FAMILY = "1,2"; 454 | VALIDATE_PRODUCT = YES; 455 | }; 456 | name = Release; 457 | }; 458 | F2B4095A18BA16F500611B29 /* Debug */ = { 459 | isa = XCBuildConfiguration; 460 | baseConfigurationReference = 2E37114A22AF21385F13CD70 /* Pods-SHModelObject.debug.xcconfig */; 461 | buildSettings = { 462 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 463 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 464 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 465 | GCC_PREFIX_HEADER = "SHModelObject/SHModelObject-Prefix.pch"; 466 | INFOPLIST_FILE = "SHModelObject/SHModelObject-Info.plist"; 467 | PRODUCT_NAME = SHModelObject; 468 | WRAPPER_EXTENSION = app; 469 | }; 470 | name = Debug; 471 | }; 472 | F2B4095B18BA16F500611B29 /* Release */ = { 473 | isa = XCBuildConfiguration; 474 | baseConfigurationReference = A11D18FAC0D2005DF68AFF60 /* Pods-SHModelObject.release.xcconfig */; 475 | buildSettings = { 476 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 477 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 478 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 479 | GCC_PREFIX_HEADER = "SHModelObject/SHModelObject-Prefix.pch"; 480 | INFOPLIST_FILE = "SHModelObject/SHModelObject-Info.plist"; 481 | PRODUCT_NAME = SHModelObject; 482 | WRAPPER_EXTENSION = app; 483 | }; 484 | name = Release; 485 | }; 486 | F2B4095D18BA16F500611B29 /* Debug */ = { 487 | isa = XCBuildConfiguration; 488 | buildSettings = { 489 | ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; 490 | FRAMEWORK_SEARCH_PATHS = ( 491 | "$(SDKROOT)/Developer/Library/Frameworks", 492 | "$(inherited)", 493 | "$(DEVELOPER_FRAMEWORKS_DIR)", 494 | ); 495 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 496 | GCC_PREFIX_HEADER = "SHModalObject/SHModalObject-Prefix.pch"; 497 | GCC_PREPROCESSOR_DEFINITIONS = ( 498 | "DEBUG=1", 499 | "$(inherited)", 500 | ); 501 | INFOPLIST_FILE = "SHModalObjectTests/SHModelObjectTests-Info.plist"; 502 | PRODUCT_NAME = SHModelObjectTests; 503 | WRAPPER_EXTENSION = xctest; 504 | }; 505 | name = Debug; 506 | }; 507 | F2B4095E18BA16F500611B29 /* Release */ = { 508 | isa = XCBuildConfiguration; 509 | buildSettings = { 510 | ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; 511 | FRAMEWORK_SEARCH_PATHS = ( 512 | "$(SDKROOT)/Developer/Library/Frameworks", 513 | "$(inherited)", 514 | "$(DEVELOPER_FRAMEWORKS_DIR)", 515 | ); 516 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 517 | GCC_PREFIX_HEADER = "SHModalObject/SHModalObject-Prefix.pch"; 518 | INFOPLIST_FILE = "SHModalObjectTests/SHModelObjectTests-Info.plist"; 519 | PRODUCT_NAME = SHModelObjectTests; 520 | WRAPPER_EXTENSION = xctest; 521 | }; 522 | name = Release; 523 | }; 524 | /* End XCBuildConfiguration section */ 525 | 526 | /* Begin XCConfigurationList section */ 527 | F2B4092818BA16F400611B29 /* Build configuration list for PBXProject "SHModelObject" */ = { 528 | isa = XCConfigurationList; 529 | buildConfigurations = ( 530 | F2B4095718BA16F500611B29 /* Debug */, 531 | F2B4095818BA16F500611B29 /* Release */, 532 | ); 533 | defaultConfigurationIsVisible = 0; 534 | defaultConfigurationName = Release; 535 | }; 536 | F2B4095918BA16F500611B29 /* Build configuration list for PBXNativeTarget "SHModelObject" */ = { 537 | isa = XCConfigurationList; 538 | buildConfigurations = ( 539 | F2B4095A18BA16F500611B29 /* Debug */, 540 | F2B4095B18BA16F500611B29 /* Release */, 541 | ); 542 | defaultConfigurationIsVisible = 0; 543 | defaultConfigurationName = Release; 544 | }; 545 | F2B4095C18BA16F500611B29 /* Build configuration list for PBXNativeTarget "SHModelObjectTests" */ = { 546 | isa = XCConfigurationList; 547 | buildConfigurations = ( 548 | F2B4095D18BA16F500611B29 /* Debug */, 549 | F2B4095E18BA16F500611B29 /* Release */, 550 | ); 551 | defaultConfigurationIsVisible = 0; 552 | defaultConfigurationName = Release; 553 | }; 554 | /* End XCConfigurationList section */ 555 | }; 556 | rootObject = F2B4092518BA16F400611B29 /* Project object */; 557 | } 558 | --------------------------------------------------------------------------------