├── RHParrotDataDemo ├── RHParrotDataDemo.xcodeproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── project.pbxproj ├── RHParrotDataDemo │ ├── ViewController.h │ ├── Brand.m │ ├── AppDelegate.h │ ├── ViewController.m │ ├── Person.m │ ├── main.m │ ├── RHParrotData │ │ ├── RHParrotData.h │ │ ├── RHParrotMacro.h │ │ ├── RHQueryResultController.m │ │ ├── RHDataImporter.h │ │ ├── RHQueryResultController.h │ │ ├── RHDataImporter.m │ │ ├── RHDatabaseManager.h │ │ ├── RHDataAgent.h │ │ ├── RHQuery.h │ │ ├── RHDataAgent.m │ │ ├── RHQuery.m │ │ └── RHDatabaseManager.m │ ├── Brand.h │ ├── Person.h │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ ├── Base.lproj │ │ ├── Main.storyboard │ │ └── LaunchScreen.xib │ ├── Model.xcdatamodeld │ │ └── Model.xcdatamodel │ │ │ └── contents │ └── AppDelegate.m └── RHParrotDataDemoTests │ ├── Info.plist │ └── RHParrotDataDemoTests.m ├── RHParrotData ├── RHParrotData.h ├── RHParrotMacro.h ├── RHQueryResultController.m ├── RHDataImporter.h ├── RHQueryResultController.h ├── RHDataImporter.m ├── RHDatabaseManager.h ├── RHDataAgent.h ├── RHQuery.h ├── RHDataAgent.m ├── RHQuery.m └── RHDatabaseManager.m ├── RHParrotData.podspec ├── .gitignore ├── LICENSE └── README.md /RHParrotDataDemo/RHParrotDataDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /RHParrotDataDemo/RHParrotDataDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/17. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /RHParrotDataDemo/RHParrotDataDemo/Brand.m: -------------------------------------------------------------------------------- 1 | // 2 | // Brand.m 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/20. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import "Brand.h" 10 | 11 | 12 | @implementation Brand 13 | 14 | @dynamic brandId; 15 | @dynamic product; 16 | @dynamic country; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /RHParrotDataDemo/RHParrotDataDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/17. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /RHParrotDataDemo/RHParrotDataDemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/17. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | @interface ViewController () 12 | 13 | @end 14 | 15 | @implementation ViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | } 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /RHParrotDataDemo/RHParrotDataDemo/Person.m: -------------------------------------------------------------------------------- 1 | // 2 | // Person.m 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/20. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import "Person.h" 10 | 11 | 12 | @implementation Person 13 | 14 | @dynamic name; 15 | @dynamic age; 16 | @dynamic sex; 17 | @dynamic birthday; 18 | @dynamic updatedAt; 19 | @dynamic createdAt; 20 | @dynamic personId; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /RHParrotDataDemo/RHParrotDataDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/17. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /RHParrotData/RHParrotData.h: -------------------------------------------------------------------------------- 1 | // 2 | // RHParrotData.h 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/19. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #ifndef RHParrotDataDemo_RHParrotData_h 10 | #define RHParrotDataDemo_RHParrotData_h 11 | 12 | #import "RHQuery.h" 13 | #import "RHDataAgent.h" 14 | #import "RHDataImporter.h" 15 | #import "RHDatabaseManager.h" 16 | #import "RHQueryResultController.h" 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /RHParrotDataDemo/RHParrotDataDemo/RHParrotData/RHParrotData.h: -------------------------------------------------------------------------------- 1 | // 2 | // RHParrotData.h 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/19. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #ifndef RHParrotDataDemo_RHParrotData_h 10 | #define RHParrotDataDemo_RHParrotData_h 11 | 12 | #import "RHQuery.h" 13 | #import "RHDataAgent.h" 14 | #import "RHDataImporter.h" 15 | #import "RHDatabaseManager.h" 16 | #import "RHQueryResultController.h" 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /RHParrotDataDemo/RHParrotDataDemo/Brand.h: -------------------------------------------------------------------------------- 1 | // 2 | // Brand.h 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/20. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | 13 | @interface Brand : NSManagedObject 14 | 15 | @property (nonatomic, retain) NSString * brandId; 16 | @property (nonatomic, retain) NSString * product; 17 | @property (nonatomic, retain) NSString * country; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /RHParrotData/RHParrotMacro.h: -------------------------------------------------------------------------------- 1 | // 2 | // RHParrotMacro.h 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/17. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #ifndef RHParrotDataDemo_RHParrotMacro_h 10 | #define RHParrotDataDemo_RHParrotMacro_h 11 | 12 | #import 13 | 14 | #ifdef DEBUG 15 | # define RLog(...) NSLog((@"%s [Line %d] %@"), __PRETTY_FUNCTION__, __LINE__, [NSString stringWithFormat:__VA_ARGS__]) 16 | #else 17 | # define RLog(...) 18 | #endif 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /RHParrotDataDemo/RHParrotDataDemo/RHParrotData/RHParrotMacro.h: -------------------------------------------------------------------------------- 1 | // 2 | // RHParrotMacro.h 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/17. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #ifndef RHParrotDataDemo_RHParrotMacro_h 10 | #define RHParrotDataDemo_RHParrotMacro_h 11 | 12 | #import 13 | 14 | #ifdef DEBUG 15 | # define RLog(...) NSLog((@"%s [Line %d] %@"), __PRETTY_FUNCTION__, __LINE__, [NSString stringWithFormat:__VA_ARGS__]) 16 | #else 17 | # define RLog(...) 18 | #endif 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /RHParrotData.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "RHParrotData" 3 | s.version = "0.1.5" 4 | s.summary = "CoreData stack management and quick query language library." 5 | s.homepage = "https://github.com/Rannie/RHParrotData" 6 | s.license = "MIT" 7 | s.author = "Hanran Liu" 8 | s.platform = :ios, "6.0" 9 | s.source = { :git => "https://github.com/Rannie/RHParrotData.git", :tag => s.version } 10 | s.source_files = "RHParrotData", "RHParrotData/*.{h,m}" 11 | s.framework = "CoreData" 12 | s.requires_arc = true 13 | end 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | # Pods/ 27 | -------------------------------------------------------------------------------- /RHParrotDataDemo/RHParrotDataDemo/Person.h: -------------------------------------------------------------------------------- 1 | // 2 | // Person.h 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/20. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | 13 | @interface Person : NSManagedObject 14 | 15 | @property (nonatomic, retain) NSString * name; 16 | @property (nonatomic, retain) NSNumber * age; 17 | @property (nonatomic, retain) NSString * sex; 18 | @property (nonatomic, retain) NSDate * birthday; 19 | @property (nonatomic, retain) NSDate * updatedAt; 20 | @property (nonatomic, retain) NSDate * createdAt; 21 | @property (nonatomic, retain) NSString * personId; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /RHParrotDataDemo/RHParrotDataDemo/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" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /RHParrotDataDemo/RHParrotDataDemoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.rannie.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /RHParrotDataDemo/RHParrotDataDemoTests/RHParrotDataDemoTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // RHParrotDataDemoTests.m 3 | // RHParrotDataDemoTests 4 | // 5 | // Created by Hanran Liu on 15/1/17. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface RHParrotDataDemoTests : XCTestCase 13 | 14 | @end 15 | 16 | @implementation RHParrotDataDemoTests 17 | 18 | - (void)setUp { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | [super tearDown]; 26 | } 27 | 28 | - (void)testExample { 29 | // This is an example of a functional test case. 30 | XCTAssert(YES, @"Pass"); 31 | } 32 | 33 | - (void)testPerformanceExample { 34 | // This is an example of a performance test case. 35 | [self measureBlock:^{ 36 | // Put the code you want to measure the time of here. 37 | }]; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /RHParrotData/RHQueryResultController.m: -------------------------------------------------------------------------------- 1 | // 2 | // RHQueryResultController.m 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/23. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import "RHQueryResultController.h" 10 | #import "RHDataAgent.h" 11 | #import "RHQuery.h" 12 | 13 | @implementation RHQueryResultController 14 | 15 | + (instancetype)queryResultControllerWithQuery:(RHQuery *)query 16 | sectionNameKeyPath:(NSString *)sectionNameKeyPath 17 | cacheName:(NSString *)name { 18 | NSParameterAssert(query); 19 | NSFetchRequest *fetchRequest = [query generateFetchRequest]; 20 | return [[self alloc] initWithFetchRequest:fetchRequest managedObjectContext:RHMainContext sectionNameKeyPath:sectionNameKeyPath cacheName:name]; 21 | } 22 | 23 | + (instancetype)queryResultControllerWithQuery:(RHQuery *)query { 24 | return [self queryResultControllerWithQuery:query sectionNameKeyPath:nil cacheName:nil]; 25 | } 26 | 27 | - (void)performQuery { 28 | [[RHDataAgent agent] executeQueryWithController:self]; 29 | } 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Hanran Liu 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 | -------------------------------------------------------------------------------- /RHParrotData/RHDataImporter.h: -------------------------------------------------------------------------------- 1 | // 2 | // RHDataImporter.h 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/17. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import "RHParrotMacro.h" 10 | 11 | typedef void (^RHObjectSerializeHandler)(id oriObj, NSManagedObject *dataObj); 12 | 13 | @interface RHDataImporter : NSObject 14 | 15 | /** 16 | * Defines how often save data to store. 17 | */ 18 | @property (nonatomic, assign) NSUInteger batchCount; //default 10 19 | 20 | /** 21 | * Import data method. 22 | * 23 | * @param entity managed object class name, required 24 | * @param primaryKey primary key, can be nil 25 | * @param data data 26 | * @param insertHandler how to insert between data instance and managed object 27 | * @param updateHandler how to update between data instance and managed object 28 | */ 29 | - (void)importEntity:(NSString *)entity 30 | primaryKey:(NSString *)primaryKey 31 | data:(NSArray *)data 32 | insertHandler:(RHObjectSerializeHandler)insertHandler 33 | updateHandler:(RHObjectSerializeHandler)updateHandler; 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /RHParrotDataDemo/RHParrotDataDemo/RHParrotData/RHQueryResultController.m: -------------------------------------------------------------------------------- 1 | // 2 | // RHQueryResultController.m 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/23. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import "RHQueryResultController.h" 10 | #import "RHDataAgent.h" 11 | #import "RHQuery.h" 12 | 13 | @implementation RHQueryResultController 14 | 15 | + (instancetype)queryResultControllerWithQuery:(RHQuery *)query 16 | sectionNameKeyPath:(NSString *)sectionNameKeyPath 17 | cacheName:(NSString *)name { 18 | NSParameterAssert(query); 19 | NSFetchRequest *fetchRequest = [query generateFetchRequest]; 20 | return [[self alloc] initWithFetchRequest:fetchRequest managedObjectContext:RHMainContext sectionNameKeyPath:sectionNameKeyPath cacheName:name]; 21 | } 22 | 23 | + (instancetype)queryResultControllerWithQuery:(RHQuery *)query { 24 | return [self queryResultControllerWithQuery:query sectionNameKeyPath:nil cacheName:nil]; 25 | } 26 | 27 | - (void)performQuery { 28 | [[RHDataAgent agent] executeQueryWithController:self]; 29 | } 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /RHParrotDataDemo/RHParrotDataDemo/RHParrotData/RHDataImporter.h: -------------------------------------------------------------------------------- 1 | // 2 | // RHDataImporter.h 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/17. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import "RHParrotMacro.h" 10 | 11 | typedef void (^RHObjectSerializeHandler)(id oriObj, NSManagedObject *dataObj); 12 | 13 | @interface RHDataImporter : NSObject 14 | 15 | /** 16 | * Defines how often save data to store. 17 | */ 18 | @property (nonatomic, assign) NSUInteger batchCount; //default 10 19 | 20 | /** 21 | * Import data method. 22 | * 23 | * @param entity managed object class name, required 24 | * @param primaryKey primary key, can be nil 25 | * @param data data 26 | * @param insertHandler how to insert between data instance and managed object 27 | * @param updateHandler how to update between data instance and managed object 28 | */ 29 | - (void)importEntity:(NSString *)entity 30 | primaryKey:(NSString *)primaryKey 31 | data:(NSArray *)data 32 | insertHandler:(RHObjectSerializeHandler)insertHandler 33 | updateHandler:(RHObjectSerializeHandler)updateHandler; 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /RHParrotDataDemo/RHParrotDataDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.rannie.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /RHParrotData/RHQueryResultController.h: -------------------------------------------------------------------------------- 1 | // 2 | // RHQueryResultController.h 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/23. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import "RHParrotMacro.h" 10 | 11 | @class RHQuery; 12 | 13 | @interface RHQueryResultController : NSFetchedResultsController 14 | 15 | /** 16 | * Create a RHQueryResultController (NSFetchedResultsController's subclass) instance. 17 | * 18 | * @param query query instance 19 | * @param sectionNameKeyPath keypath on resulting objects that returns the section name. This will be used to pre-compute the section information. 20 | * @param name Section info is cached persistently to a private file under this name. Cached sections are checked to see if the time stamp matches the store, but not if you have illegally mutated the readonly fetch request, predicate, or sort descriptor. 21 | * 22 | * @return controller instance 23 | */ 24 | + (instancetype)queryResultControllerWithQuery:(RHQuery *)query 25 | sectionNameKeyPath:(NSString *)sectionNameKeyPath 26 | cacheName:(NSString *)name; 27 | 28 | /** 29 | * Quick create controller only specify query. 30 | * 31 | * @param query query instance 32 | * 33 | * @return controller instance 34 | */ 35 | + (instancetype)queryResultControllerWithQuery:(RHQuery *)query; 36 | 37 | /** 38 | * Perform fetch, log will collect by agent. Also can use 'performFetch:' method directly. 39 | */ 40 | - (void)performQuery; 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /RHParrotDataDemo/RHParrotDataDemo/RHParrotData/RHQueryResultController.h: -------------------------------------------------------------------------------- 1 | // 2 | // RHQueryResultController.h 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/23. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import "RHParrotMacro.h" 10 | 11 | @class RHQuery; 12 | 13 | @interface RHQueryResultController : NSFetchedResultsController 14 | 15 | /** 16 | * Create a RHQueryResultController (NSFetchedResultsController's subclass) instance. 17 | * 18 | * @param query query instance 19 | * @param sectionNameKeyPath keypath on resulting objects that returns the section name. This will be used to pre-compute the section information. 20 | * @param name Section info is cached persistently to a private file under this name. Cached sections are checked to see if the time stamp matches the store, but not if you have illegally mutated the readonly fetch request, predicate, or sort descriptor. 21 | * 22 | * @return controller instance 23 | */ 24 | + (instancetype)queryResultControllerWithQuery:(RHQuery *)query 25 | sectionNameKeyPath:(NSString *)sectionNameKeyPath 26 | cacheName:(NSString *)name; 27 | 28 | /** 29 | * Quick create controller only specify query. 30 | * 31 | * @param query query instance 32 | * 33 | * @return controller instance 34 | */ 35 | + (instancetype)queryResultControllerWithQuery:(RHQuery *)query; 36 | 37 | /** 38 | * Perform fetch, log will collect by agent. Also can use 'performFetch:' method directly. 39 | */ 40 | - (void)performQuery; 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /RHParrotDataDemo/RHParrotDataDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /RHParrotDataDemo/RHParrotDataDemo/Model.xcdatamodeld/Model.xcdatamodel/contents: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /RHParrotData/RHDataImporter.m: -------------------------------------------------------------------------------- 1 | // 2 | // RHDataImporter.m 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/17. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import "RHDataImporter.h" 10 | #import "RHDataAgent.h" 11 | #import "RHQuery.h" 12 | 13 | @implementation RHDataImporter 14 | 15 | - (instancetype)init { 16 | self = [super init]; 17 | if (self) { 18 | self.batchCount = 10; 19 | } 20 | return self; 21 | } 22 | 23 | - (void)importEntity:(NSString *)entity primaryKey:(NSString *)primaryKey data:(NSArray *)data insertHandler:(RHObjectSerializeHandler)insertHandler updateHandler:(RHObjectSerializeHandler)updateHandler { 24 | NSParameterAssert(entity); 25 | 26 | __block NSUInteger count = 0; 27 | 28 | [RHBackgroundContext performBlock:^{ 29 | for (id obj in data) { 30 | NSManagedObject *managedObj; 31 | if (primaryKey != nil) { 32 | id primaryValue = [obj valueForKey:primaryKey]; 33 | RHQuery *query = [RHQuery queryWithEntity:entity]; 34 | [query queryKey:primaryKey op:RHEqual value:primaryValue]; 35 | managedObj = [[query execute] firstObject]; 36 | } 37 | 38 | if (managedObj) { 39 | if (updateHandler) updateHandler(obj, managedObj); 40 | } else { 41 | managedObj = [NSEntityDescription insertNewObjectForEntityForName:entity inManagedObjectContext:RHBackgroundContext]; 42 | if (insertHandler) insertHandler(obj, managedObj); 43 | } 44 | 45 | count++; 46 | if (count % _batchCount == 0 || count == data.count) { 47 | NSError *error = nil; 48 | [RHBackgroundContext save:&error]; 49 | if (error) { 50 | RLog(@"RHDataImporter: Import data occurs error(%@)!", error.localizedDescription); 51 | } 52 | } 53 | } 54 | }]; 55 | } 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /RHParrotData/RHDatabaseManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // RHDatabaseManager.h 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/19. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import "RHParrotMacro.h" 10 | 11 | typedef void (^DBOperationSuccessBlock)(); 12 | typedef void (^DBQuerySuccessBlock)(id result); 13 | typedef void (^DBOperationFailureBlock)(NSError *error); 14 | 15 | /** 16 | * The CoreData stack class. 17 | * Operate database directly. 18 | */ 19 | @interface RHDatabaseManager : NSObject 20 | 21 | //URL 22 | @property (nonatomic, strong) NSURL *momdURL; 23 | @property (nonatomic, strong) NSURL *storeURL; 24 | 25 | //Stack 26 | @property (nonatomic, strong, readonly) NSManagedObjectContext *managedObjectContext; 27 | @property (nonatomic, strong, readonly) NSManagedObjectContext *backgroundManagedObjectContext; 28 | @property (nonatomic, strong, readonly) NSManagedObjectModel *managedObjectModel; 29 | @property (nonatomic, strong, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator; 30 | 31 | //Initialization 32 | + (instancetype)databaseManagerWithModelURL:(NSURL *)momdURL storeURL:(NSURL *)storeURL; 33 | - (instancetype)initWithModelURL:(NSURL *)momdURL storeURL:(NSURL *)storeURL; 34 | 35 | //C.R.U.D 36 | - (void)commitChangesWithSuccess:(DBOperationSuccessBlock)success failure:(DBOperationFailureBlock)failure; 37 | - (void)deleteManagedObject:(id)object success:(DBOperationSuccessBlock)success failure:(DBOperationFailureBlock)failure; 38 | - (void)deleteObjects:(NSArray *)objects success:(DBOperationSuccessBlock)success failure:(DBOperationFailureBlock)failure; 39 | - (void)queryWithRequest:(NSFetchRequest *)fetchRequest success:(DBQuerySuccessBlock)success failure:(DBOperationFailureBlock)failure; 40 | 41 | //UndoManager 42 | - (void)undo; 43 | - (void)redo; 44 | - (void)rollback; 45 | - (void)reset; 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /RHParrotDataDemo/RHParrotDataDemo/RHParrotData/RHDataImporter.m: -------------------------------------------------------------------------------- 1 | // 2 | // RHDataImporter.m 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/17. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import "RHDataImporter.h" 10 | #import "RHDataAgent.h" 11 | #import "RHQuery.h" 12 | 13 | @implementation RHDataImporter 14 | 15 | - (instancetype)init { 16 | self = [super init]; 17 | if (self) { 18 | self.batchCount = 10; 19 | } 20 | return self; 21 | } 22 | 23 | - (void)importEntity:(NSString *)entity primaryKey:(NSString *)primaryKey data:(NSArray *)data insertHandler:(RHObjectSerializeHandler)insertHandler updateHandler:(RHObjectSerializeHandler)updateHandler { 24 | NSParameterAssert(entity); 25 | 26 | __block NSUInteger count = 0; 27 | 28 | [RHBackgroundContext performBlock:^{ 29 | for (id obj in data) { 30 | NSManagedObject *managedObj; 31 | if (primaryKey != nil) { 32 | id primaryValue = [obj valueForKey:primaryKey]; 33 | RHQuery *query = [RHQuery queryWithEntity:entity]; 34 | [query queryKey:primaryKey op:RHEqual value:primaryValue]; 35 | managedObj = [[query execute] firstObject]; 36 | } 37 | 38 | if (managedObj) { 39 | if (updateHandler) updateHandler(obj, managedObj); 40 | } else { 41 | managedObj = [NSEntityDescription insertNewObjectForEntityForName:entity inManagedObjectContext:RHBackgroundContext]; 42 | if (insertHandler) insertHandler(obj, managedObj); 43 | } 44 | 45 | count++; 46 | if (count % _batchCount == 0 || count == data.count) { 47 | NSError *error = nil; 48 | [RHBackgroundContext save:&error]; 49 | if (error) { 50 | RLog(@"RHDataImporter: Import data occurs error(%@)!", error.localizedDescription); 51 | } 52 | } 53 | } 54 | }]; 55 | } 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /RHParrotDataDemo/RHParrotDataDemo/RHParrotData/RHDatabaseManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // RHDatabaseManager.h 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/19. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import "RHParrotMacro.h" 10 | 11 | typedef void (^DBOperationSuccessBlock)(); 12 | typedef void (^DBQuerySuccessBlock)(id result); 13 | typedef void (^DBOperationFailureBlock)(NSError *error); 14 | 15 | /** 16 | * The CoreData stack class. 17 | * Operate database directly. 18 | */ 19 | @interface RHDatabaseManager : NSObject 20 | 21 | //URL 22 | @property (nonatomic, strong) NSURL *momdURL; 23 | @property (nonatomic, strong) NSURL *storeURL; 24 | 25 | //Stack 26 | @property (nonatomic, strong, readonly) NSManagedObjectContext *managedObjectContext; 27 | @property (nonatomic, strong, readonly) NSManagedObjectContext *backgroundManagedObjectContext; 28 | @property (nonatomic, strong, readonly) NSManagedObjectModel *managedObjectModel; 29 | @property (nonatomic, strong, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator; 30 | 31 | //Initialization 32 | + (instancetype)databaseManagerWithModelURL:(NSURL *)momdURL storeURL:(NSURL *)storeURL; 33 | - (instancetype)initWithModelURL:(NSURL *)momdURL storeURL:(NSURL *)storeURL; 34 | 35 | //C.R.U.D 36 | - (void)commitChangesWithSuccess:(DBOperationSuccessBlock)success failure:(DBOperationFailureBlock)failure; 37 | - (void)deleteManagedObject:(id)object success:(DBOperationSuccessBlock)success failure:(DBOperationFailureBlock)failure; 38 | - (void)deleteObjects:(NSArray *)objects success:(DBOperationSuccessBlock)success failure:(DBOperationFailureBlock)failure; 39 | - (void)queryWithRequest:(NSFetchRequest *)fetchRequest success:(DBQuerySuccessBlock)success failure:(DBOperationFailureBlock)failure; 40 | 41 | //UndoManager 42 | - (void)undo; 43 | - (void)redo; 44 | - (void)rollback; 45 | - (void)reset; 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /RHParrotData/RHDataAgent.h: -------------------------------------------------------------------------------- 1 | // 2 | // RHDataAgent.h 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/17. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import "RHParrotMacro.h" 10 | 11 | @class RHQuery; 12 | @class RHDatabaseManager; 13 | @class RHQueryResultController; 14 | 15 | #define RHMainContext ([RHDataAgent agent].mainManagedObjectContext) 16 | #define RHBackgroundContext ([RHDataAgent agent].backgroundManagedObjectContext) 17 | 18 | @interface RHDataAgent : NSObject 19 | 20 | /** 21 | * Database manageder. see "RHDatabaseManager.h". 22 | */ 23 | @property (nonatomic, readonly) RHDatabaseManager *dbManager; 24 | 25 | /** 26 | * MainQueueConcurrencyType NSManagedObjectContext instance. 27 | */ 28 | @property (nonatomic, readonly) NSManagedObjectContext *mainManagedObjectContext; 29 | 30 | /** 31 | * PrivateQueueConcurrencyType NSManagedObjectContext instance. 32 | */ 33 | @property (nonatomic, readonly) NSManagedObjectContext *backgroundManagedObjectContext; 34 | 35 | /** 36 | * Track logs. Default is NO. 37 | */ 38 | @property (nonatomic, assign) BOOL trackLogging; 39 | 40 | /** 41 | * Create a shared instance with database required info. 42 | * 43 | * @param momdURL xcdatamodeld file path url 44 | * @param storeURL sqlite path url 45 | */ 46 | + (void)setupAgentWithMomdFile:(NSURL *)momdURL andStoreURL:(NSURL *)storeURL; 47 | 48 | /** 49 | * Singleton retrived. 50 | * 51 | * @return the agent instance 52 | */ 53 | + (instancetype)agent; 54 | 55 | /** 56 | * When you insert or update managed objects use this method. 57 | */ 58 | - (void)commit; 59 | 60 | /** 61 | * Delete a managed object. 62 | * 63 | * @param object object to be deleted 64 | */ 65 | - (void)deleteObject:(NSManagedObject *)object; 66 | 67 | /** 68 | * Delete managed objects. 69 | * 70 | * @param objects objects to be deleted 71 | */ 72 | - (void)deleteObjects:(NSArray *)objects; 73 | 74 | /** 75 | * Execute a query. also can use RHQuery method '- execute'. 76 | * 77 | * @param query RHQuery instance 78 | * 79 | * @return query result 80 | */ 81 | - (id)executeQuery:(RHQuery *)query; 82 | 83 | /** 84 | * Drive a subclass of 'NSFetchResultController' instance to perfom fetch. 85 | * 86 | * @param controller query result controller 87 | */ 88 | - (void)executeQueryWithController:(RHQueryResultController *)controller; 89 | 90 | /** 91 | * Cached a query by a string identifier. 92 | * 93 | * @param query query want to be cached 94 | * @param queryKey cache identifier 95 | */ 96 | - (void)cachedQuery:(RHQuery *)query withKey:(NSString *)queryKey; 97 | 98 | /** 99 | * Remove the cached query 100 | * 101 | * @param queryKey cache identifier 102 | */ 103 | - (void)removeCachedQueryForKey:(NSString *)queryKey; 104 | 105 | /** 106 | * Get the cached query. 107 | * 108 | * @param queryKey cache identifier 109 | * 110 | * @return cached query instance 111 | */ 112 | - (RHQuery *)cachedQueryForKey:(NSString *)queryKey; 113 | 114 | /** 115 | * Undo command. 116 | */ 117 | - (void)undo; 118 | 119 | /** 120 | * Redo command. 121 | */ 122 | - (void)redo; 123 | 124 | /** 125 | * Rollback command. 126 | */ 127 | - (void)rollback; 128 | 129 | /** 130 | * Reset command. 131 | */ 132 | - (void)reset; 133 | 134 | /** 135 | * Reduce memory by clear query caches, undo stack and so on. 136 | */ 137 | - (void)reduceMemory; 138 | 139 | @end 140 | -------------------------------------------------------------------------------- /RHParrotDataDemo/RHParrotDataDemo/RHParrotData/RHDataAgent.h: -------------------------------------------------------------------------------- 1 | // 2 | // RHDataAgent.h 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/17. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import "RHParrotMacro.h" 10 | 11 | @class RHQuery; 12 | @class RHDatabaseManager; 13 | @class RHQueryResultController; 14 | 15 | #define RHMainContext ([RHDataAgent agent].mainManagedObjectContext) 16 | #define RHBackgroundContext ([RHDataAgent agent].backgroundManagedObjectContext) 17 | 18 | @interface RHDataAgent : NSObject 19 | 20 | /** 21 | * Database manageder. see "RHDatabaseManager.h". 22 | */ 23 | @property (nonatomic, readonly) RHDatabaseManager *dbManager; 24 | 25 | /** 26 | * MainQueueConcurrencyType NSManagedObjectContext instance. 27 | */ 28 | @property (nonatomic, readonly) NSManagedObjectContext *mainManagedObjectContext; 29 | 30 | /** 31 | * PrivateQueueConcurrencyType NSManagedObjectContext instance. 32 | */ 33 | @property (nonatomic, readonly) NSManagedObjectContext *backgroundManagedObjectContext; 34 | 35 | /** 36 | * Track logs. Default is NO. 37 | */ 38 | @property (nonatomic, assign) BOOL trackLogging; 39 | 40 | /** 41 | * Create a shared instance with database required info. 42 | * 43 | * @param momdURL xcdatamodeld file path url 44 | * @param storeURL sqlite path url 45 | */ 46 | + (void)setupAgentWithMomdFile:(NSURL *)momdURL andStoreURL:(NSURL *)storeURL; 47 | 48 | /** 49 | * Singleton retrived. 50 | * 51 | * @return the agent instance 52 | */ 53 | + (instancetype)agent; 54 | 55 | /** 56 | * When you insert or update managed objects use this method. 57 | */ 58 | - (void)commit; 59 | 60 | /** 61 | * Delete a managed object. 62 | * 63 | * @param object object to be deleted 64 | */ 65 | - (void)deleteObject:(NSManagedObject *)object; 66 | 67 | /** 68 | * Delete managed objects. 69 | * 70 | * @param objects objects to be deleted 71 | */ 72 | - (void)deleteObjects:(NSArray *)objects; 73 | 74 | /** 75 | * Execute a query. also can use RHQuery method '- execute'. 76 | * 77 | * @param query RHQuery instance 78 | * 79 | * @return query result 80 | */ 81 | - (id)executeQuery:(RHQuery *)query; 82 | 83 | /** 84 | * Drive a subclass of 'NSFetchResultController' instance to perfom fetch. 85 | * 86 | * @param controller query result controller 87 | */ 88 | - (void)executeQueryWithController:(RHQueryResultController *)controller; 89 | 90 | /** 91 | * Cached a query by a string identifier. 92 | * 93 | * @param query query want to be cached 94 | * @param queryKey cache identifier 95 | */ 96 | - (void)cachedQuery:(RHQuery *)query withKey:(NSString *)queryKey; 97 | 98 | /** 99 | * Remove the cached query 100 | * 101 | * @param queryKey cache identifier 102 | */ 103 | - (void)removeCachedQueryForKey:(NSString *)queryKey; 104 | 105 | /** 106 | * Get the cached query. 107 | * 108 | * @param queryKey cache identifier 109 | * 110 | * @return cached query instance 111 | */ 112 | - (RHQuery *)cachedQueryForKey:(NSString *)queryKey; 113 | 114 | /** 115 | * Undo command. 116 | */ 117 | - (void)undo; 118 | 119 | /** 120 | * Redo command. 121 | */ 122 | - (void)redo; 123 | 124 | /** 125 | * Rollback command. 126 | */ 127 | - (void)rollback; 128 | 129 | /** 130 | * Reset command. 131 | */ 132 | - (void)reset; 133 | 134 | /** 135 | * Reduce memory by clear query caches, undo stack and so on. 136 | */ 137 | - (void)reduceMemory; 138 | 139 | @end 140 | -------------------------------------------------------------------------------- /RHParrotDataDemo/RHParrotDataDemo/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /RHParrotData/RHQuery.h: -------------------------------------------------------------------------------- 1 | // 2 | // RHQuery.h 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/17. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "RHParrotMacro.h" 11 | 12 | typedef NS_ENUM(NSInteger, RHOperator) { 13 | RHNone = 0, 14 | // == 15 | RHEqual, 16 | // > 17 | RHGreaterThan, 18 | // < 19 | RHLessThan, 20 | // >= 21 | RHGreaterOrEqual, 22 | // <= 23 | RHLessOrEqual, 24 | // != 25 | RHNot, 26 | // < lhs < 27 | RHBetween, 28 | // BEGINSWITH 29 | RHBeginsWith, 30 | // ENDSWITH 31 | RHEndsWith, 32 | // CONTAINS 33 | RHContains, 34 | // LIKE[CD] 35 | RHLike, 36 | // MATCHES 37 | RHMatches, 38 | // IN 39 | RHIn 40 | }; 41 | 42 | typedef NS_ENUM(NSInteger, RHFunction) { 43 | // MAX 44 | RHMax = 0, 45 | // MIN 46 | RHMin, 47 | // AVERAGE 48 | RHAverage, 49 | // SUM 50 | RHSum, 51 | // COUNT 52 | RHCount 53 | }; 54 | 55 | @interface RHQuery : NSObject 56 | 57 | /** 58 | * The managed object class name of query. 59 | */ 60 | @property (nonatomic, strong, readonly) NSString *entity; 61 | 62 | /** 63 | * Query condition. 64 | */ 65 | @property (nonatomic, strong, readonly) NSPredicate *queryPredicate; 66 | 67 | /** 68 | * Sort condition. 69 | */ 70 | @property (nonatomic, strong, readonly) NSArray *sortDescriptors; 71 | 72 | /** 73 | * When call 'queryKey:withFunction:', will generate a expression description. 74 | */ 75 | @property (nonatomic, strong, readonly) NSExpressionDescription *expressionDescription; 76 | 77 | /** 78 | * Query result limit count. Default is 0, means have no limit. 79 | */ 80 | @property (nonatomic, assign) NSUInteger limitCount; 81 | 82 | /** 83 | * Query batch size. Default is 0. 84 | */ 85 | @property (nonatomic, assign) NSUInteger batchSize; 86 | 87 | /** 88 | * Query offset. Default is 0. 89 | */ 90 | @property (nonatomic, assign) NSUInteger queryOffset; 91 | 92 | /** 93 | * Create a RHQuery instance. 94 | * 95 | * @param entityName The class name of the query managed object. 96 | * 97 | * @return query instance 98 | */ 99 | + (RHQuery *)queryWithEntity:(NSString *)entityName; 100 | 101 | /** 102 | * Create a query has same entity name. 103 | * 104 | * @return query instance 105 | */ 106 | - (RHQuery *)same; 107 | 108 | /** 109 | * Simple query with key-operator-value pattern. 110 | * 111 | * @param key managed object's property keypath 112 | * @param op operator see enum 'RHOperator' 113 | * @param value rhs 114 | */ 115 | - (void)queryKey:(NSString *)key op:(RHOperator)op value:(id)value; 116 | 117 | /** 118 | * Query with function. 119 | * 120 | * @param key managed object's property keypath 121 | * @param function function to caculate. functions see enum 'RHFunction' 122 | */ 123 | - (void)queryKey:(NSString *)key function:(RHFunction)function; 124 | 125 | /** 126 | * Query with sort result. 127 | * 128 | * @param key managed object's property keypath 129 | * @param ascending YES means ascending, or descending 130 | */ 131 | - (void)sort:(NSString *)key ascending:(BOOL)ascending; 132 | 133 | /** 134 | * Query with sort result by custom comparator. 135 | * 136 | * @param key managed object's property keypath 137 | * @param ascending YES means ascending, or descending 138 | * @param comparator custom compare method 139 | */ 140 | - (void)sort:(NSString *)key ascending:(BOOL)ascending comparator:(NSComparator)comparator; 141 | 142 | /** 143 | * Create a new query by combining two 'or' relations queries. 144 | * 145 | * @param anoQuery another query instance 146 | * 147 | * @return new query instance 148 | */ 149 | - (RHQuery *)OR:(RHQuery *)anoQuery; 150 | 151 | /** 152 | * Create a new query by combining two 'and' relations queries. 153 | * 154 | * @param anoQuery another query instance 155 | * 156 | * @return new query instance 157 | */ 158 | - (RHQuery *)AND:(RHQuery *)anoQuery; 159 | 160 | /** 161 | * Create a new query that is in contrast with its own query conditions. 162 | * 163 | * @return new query instance 164 | */ 165 | - (RHQuery *)NOT; 166 | 167 | /** 168 | * generate a fetch request contains all condition. 169 | * 170 | * @return the fetch request 171 | */ 172 | - (NSFetchRequest *)generateFetchRequest; 173 | 174 | /** 175 | * Execute the query. 176 | * 177 | * @return query result 178 | */ 179 | - (id)execute; 180 | 181 | @end 182 | -------------------------------------------------------------------------------- /RHParrotDataDemo/RHParrotDataDemo/RHParrotData/RHQuery.h: -------------------------------------------------------------------------------- 1 | // 2 | // RHQuery.h 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/17. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "RHParrotMacro.h" 11 | 12 | typedef NS_ENUM(NSInteger, RHOperator) { 13 | RHNone = 0, 14 | // == 15 | RHEqual, 16 | // > 17 | RHGreaterThan, 18 | // < 19 | RHLessThan, 20 | // >= 21 | RHGreaterOrEqual, 22 | // <= 23 | RHLessOrEqual, 24 | // != 25 | RHNot, 26 | // < lhs < 27 | RHBetween, 28 | // BEGINSWITH 29 | RHBeginsWith, 30 | // ENDSWITH 31 | RHEndsWith, 32 | // CONTAINS 33 | RHContains, 34 | // LIKE[CD] 35 | RHLike, 36 | // MATCHES 37 | RHMatches, 38 | // IN 39 | RHIn 40 | }; 41 | 42 | typedef NS_ENUM(NSInteger, RHFunction) { 43 | // MAX 44 | RHMax = 0, 45 | // MIN 46 | RHMin, 47 | // AVERAGE 48 | RHAverage, 49 | // SUM 50 | RHSum, 51 | // COUNT 52 | RHCount 53 | }; 54 | 55 | @interface RHQuery : NSObject 56 | 57 | /** 58 | * The managed object class name of query. 59 | */ 60 | @property (nonatomic, strong, readonly) NSString *entity; 61 | 62 | /** 63 | * Query condition. 64 | */ 65 | @property (nonatomic, strong, readonly) NSPredicate *queryPredicate; 66 | 67 | /** 68 | * Sort condition. 69 | */ 70 | @property (nonatomic, strong, readonly) NSArray *sortDescriptors; 71 | 72 | /** 73 | * When call 'queryKey:withFunction:', will generate a expression description. 74 | */ 75 | @property (nonatomic, strong, readonly) NSExpressionDescription *expressionDescription; 76 | 77 | /** 78 | * Query result limit count. Default is 0, means have no limit. 79 | */ 80 | @property (nonatomic, assign) NSUInteger limitCount; 81 | 82 | /** 83 | * Query batch size. Default is 0. 84 | */ 85 | @property (nonatomic, assign) NSUInteger batchSize; 86 | 87 | /** 88 | * Query offset. Default is 0. 89 | */ 90 | @property (nonatomic, assign) NSUInteger queryOffset; 91 | 92 | /** 93 | * Create a RHQuery instance. 94 | * 95 | * @param entityName The class name of the query managed object. 96 | * 97 | * @return query instance 98 | */ 99 | + (RHQuery *)queryWithEntity:(NSString *)entityName; 100 | 101 | /** 102 | * Create a query has same entity name. 103 | * 104 | * @return query instance 105 | */ 106 | - (RHQuery *)same; 107 | 108 | /** 109 | * Simple query with key-operator-value pattern. 110 | * 111 | * @param key managed object's property keypath 112 | * @param op operator see enum 'RHOperator' 113 | * @param value rhs 114 | */ 115 | - (void)queryKey:(NSString *)key op:(RHOperator)op value:(id)value; 116 | 117 | /** 118 | * Query with function. 119 | * 120 | * @param key managed object's property keypath 121 | * @param function function to caculate. functions see enum 'RHFunction' 122 | */ 123 | - (void)queryKey:(NSString *)key function:(RHFunction)function; 124 | 125 | /** 126 | * Query with sort result. 127 | * 128 | * @param key managed object's property keypath 129 | * @param ascending YES means ascending, or descending 130 | */ 131 | - (void)sort:(NSString *)key ascending:(BOOL)ascending; 132 | 133 | /** 134 | * Query with sort result by custom comparator. 135 | * 136 | * @param key managed object's property keypath 137 | * @param ascending YES means ascending, or descending 138 | * @param comparator custom compare method 139 | */ 140 | - (void)sort:(NSString *)key ascending:(BOOL)ascending comparator:(NSComparator)comparator; 141 | 142 | /** 143 | * Create a new query by combining two 'or' relations queries. 144 | * 145 | * @param anoQuery another query instance 146 | * 147 | * @return new query instance 148 | */ 149 | - (RHQuery *)OR:(RHQuery *)anoQuery; 150 | 151 | /** 152 | * Create a new query by combining two 'and' relations queries. 153 | * 154 | * @param anoQuery another query instance 155 | * 156 | * @return new query instance 157 | */ 158 | - (RHQuery *)AND:(RHQuery *)anoQuery; 159 | 160 | /** 161 | * Create a new query that is in contrast with its own query conditions. 162 | * 163 | * @return new query instance 164 | */ 165 | - (RHQuery *)NOT; 166 | 167 | /** 168 | * generate a fetch request contains all condition. 169 | * 170 | * @return the fetch request 171 | */ 172 | - (NSFetchRequest *)generateFetchRequest; 173 | 174 | /** 175 | * Execute the query. 176 | * 177 | * @return query result 178 | */ 179 | - (id)execute; 180 | 181 | @end 182 | -------------------------------------------------------------------------------- /RHParrotDataDemo/RHParrotDataDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/17. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "RHParrotData.h" 11 | #import "Person.h" 12 | #import "Brand.h" 13 | 14 | @interface AppDelegate () 15 | @property (nonatomic, strong) RHDataAgent *dataAgent; 16 | @property (nonatomic, strong) RHDataImporter *importer; 17 | @end 18 | 19 | @implementation AppDelegate 20 | 21 | 22 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 23 | NSLog(@"path : %@", [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]); 24 | 25 | [self setupAgent]; 26 | 27 | // [self insertCase]; 28 | // [self deleteCase]; 29 | // [self updateCase]; 30 | // [self queryCase]; 31 | // [self importCase]; 32 | // [self fetchResultControllerCase]; 33 | 34 | return YES; 35 | } 36 | 37 | - (void)setupAgent { 38 | NSURL *momdURL = [[NSBundle mainBundle] URLForResource:@"Model" withExtension:@"momd"]; 39 | NSURL *appDocumentsDirectory = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; 40 | NSURL *storeURL = [appDocumentsDirectory URLByAppendingPathComponent:@"ParrotData.sqlite"]; 41 | [RHDataAgent setupAgentWithMomdFile:momdURL andStoreURL:storeURL]; 42 | self.dataAgent = [RHDataAgent agent]; 43 | } 44 | 45 | - (void)queryCase { 46 | id result; 47 | 48 | RHQuery *query = [RHQuery queryWithEntity:@"Person"]; 49 | [query queryKey:@"name" op:RHEqual value:@"Kobe"]; 50 | result = [query execute]; 51 | 52 | NSLog(@"result : %@", result); 53 | 54 | RHQuery *sortQuery = [RHQuery queryWithEntity:@"Person"]; 55 | [sortQuery sort:@"age" ascending:NO]; 56 | result = [sortQuery execute]; 57 | [result enumerateObjectsUsingBlock:^(Person *obj, NSUInteger idx, BOOL *stop) { 58 | NSLog(@"obj age : %@", obj.age); 59 | }]; 60 | 61 | RHQuery *queryAverageAge = [query same]; 62 | [queryAverageAge queryKey:@"age" function:RHAverage]; 63 | result = [queryAverageAge execute]; 64 | 65 | NSLog(@"result : %@", result); 66 | 67 | RHQuery *queryMin = [query same]; 68 | [queryMin queryKey:@"age" function:RHMin]; 69 | result = [queryMin execute]; 70 | 71 | NSLog(@"result : %@", result); 72 | 73 | RHQuery *queryStart = [query same]; 74 | [queryStart queryKey:@"name" op:RHBeginsWith value:@"H"]; 75 | result = [queryStart execute]; 76 | 77 | NSLog(@"result : %@", result); 78 | 79 | RHQuery *orQuery = [queryStart OR:query]; 80 | result = [orQuery execute]; 81 | 82 | NSLog(@"result : %@", result); 83 | } 84 | 85 | - (void)fetchResultControllerCase { 86 | RHQuery *query = [RHQuery queryWithEntity:@"Person"]; 87 | [query queryKey:@"name" op:RHEqual value:@"Kobe"]; 88 | 89 | RHQueryResultController *qrc = [RHQueryResultController queryResultControllerWithQuery:query]; 90 | [qrc performQuery]; 91 | } 92 | 93 | - (void)importCase { 94 | self.importer = [[RHDataImporter alloc] init]; 95 | 96 | void (^block)(id oriObj, NSManagedObject *managedObj) = ^(id oriObj, NSManagedObject *managedObj) { 97 | if ([oriObj isKindOfClass:NSDictionary.class]) { 98 | NSDictionary *dict = oriObj; 99 | [managedObj setValuesForKeysWithDictionary:dict]; 100 | } 101 | }; 102 | 103 | [self.importer importEntity:@"Brand" 104 | primaryKey:@"brandId" 105 | data:[self unimportData] 106 | insertHandler:block 107 | updateHandler:block]; 108 | } 109 | 110 | - (void)updateCase { 111 | RHQuery *query = [RHQuery queryWithEntity:@"Person"]; 112 | [query queryKey:@"name" op:RHEqual value:@"Kobe"]; 113 | Person *p = [[query execute] firstObject]; 114 | 115 | p.birthday = [NSDate date]; 116 | 117 | [self.dataAgent commit]; 118 | } 119 | 120 | - (void)deleteCase { 121 | RHQuery *query = [RHQuery queryWithEntity:@"Person"]; 122 | [query queryKey:@"name" op:RHEqual value:@"hehe"]; 123 | id result = [[query execute] firstObject]; 124 | 125 | [self.dataAgent deleteObject:result]; 126 | } 127 | 128 | - (void)insertCase { 129 | Person *p = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:self.dataAgent.mainManagedObjectContext]; 130 | p.name = @"Kobe"; 131 | p.age = @38; 132 | p.sex = @"male"; 133 | p.personId = @"103821"; 134 | [self.dataAgent commit]; 135 | } 136 | 137 | - (NSArray *)unimportData { 138 | NSMutableArray *data = [NSMutableArray array]; 139 | for (int i = 0; i < 1000; i++) { 140 | NSDictionary *dict = @{@"brandId": [NSString stringWithFormat:@"%d", i], 141 | @"product": [NSString stringWithFormat:@"product_%d", i]}; 142 | [data addObject:dict]; 143 | } 144 | return [data copy]; 145 | } 146 | 147 | @end 148 | -------------------------------------------------------------------------------- /RHParrotData/RHDataAgent.m: -------------------------------------------------------------------------------- 1 | // 2 | // RHDataAgent.m 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/17. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import "RHDataAgent.h" 10 | #import "RHQuery.h" 11 | #import "RHDatabaseManager.h" 12 | #import "RHQueryResultController.h" 13 | 14 | @interface RHDataAgent () 15 | @property (nonatomic, readwrite) RHDatabaseManager *dbManager; 16 | @property (nonatomic, strong) NSMutableDictionary *queryCache; 17 | @property (nonatomic, strong) NSMutableString *logText; 18 | @end 19 | 20 | @implementation RHDataAgent 21 | 22 | #pragma mark - Initialization 23 | static RHDataAgent *instance = nil; 24 | 25 | + (void)setupAgentWithMomdFile:(NSURL *)momdURL andStoreURL:(NSURL *)storeURL { 26 | static dispatch_once_t onceToken; 27 | dispatch_once(&onceToken, ^{ 28 | instance = [[self alloc] initWithMomdURL:momdURL storeURL:storeURL]; 29 | }); 30 | } 31 | 32 | + (instancetype)agent { 33 | return instance; 34 | } 35 | 36 | - (instancetype)initWithMomdURL:(NSURL *)momdURL storeURL:(NSURL *)storeURL { 37 | NSParameterAssert(momdURL); 38 | NSParameterAssert(storeURL); 39 | 40 | self = [super init]; 41 | if (self) { 42 | self.dbManager = [RHDatabaseManager databaseManagerWithModelURL:momdURL storeURL:storeURL]; 43 | self.queryCache = [NSMutableDictionary dictionary]; 44 | self.logText = [NSMutableString string]; 45 | self.trackLogging = NO; 46 | } 47 | return self; 48 | } 49 | 50 | - (instancetype)init { 51 | RLog(@"RHDataAgent: Warning! This is a singleton class, please use 'agent'"); 52 | return nil; 53 | } 54 | 55 | - (NSManagedObjectContext *)mainManagedObjectContext { 56 | return self.dbManager.managedObjectContext; 57 | } 58 | 59 | - (NSManagedObjectContext *)backgroundManagedObjectContext { 60 | return self.dbManager.backgroundManagedObjectContext; 61 | } 62 | 63 | #pragma mark - Insert, Update, Delete 64 | - (void)commit { 65 | [self.dbManager commitChangesWithSuccess:^{ 66 | [self RHLogging:@"RHDataAgent: Insert or update object success"]; 67 | } failure:^(NSError *error) { 68 | [self RHLogging:[NSString stringWithFormat:@"RHDataAgent: Insert or update object failed. error(%@)", error.localizedDescription]]; 69 | }]; 70 | } 71 | 72 | - (void)deleteObject:(NSManagedObject *)object { 73 | [self.dbManager deleteManagedObject:object success:^{ 74 | [self RHLogging:[NSString stringWithFormat:@"RHDataAgent: Delete obj(%@) success", object]]; 75 | } failure:^(NSError *error) { 76 | [self RHLogging:[NSString stringWithFormat:@"RHDataAgent: Delete obj(%@) failed. error(%@)", object, error.localizedDescription]]; 77 | }]; 78 | } 79 | 80 | - (void)deleteObjects:(NSArray *)objects { 81 | [self.dbManager deleteObjects:objects success:^{ 82 | [self RHLogging:[NSString stringWithFormat:@"RHDataAgent: Delete objs(%@) success", objects]]; 83 | } failure:^(NSError *error) { 84 | [self RHLogging:[NSString stringWithFormat:@"RHDataAgent: Delete objs(%@) failed! error(%@)", objects, error.localizedDescription]]; 85 | }]; 86 | } 87 | 88 | #pragma mark - Excuting 89 | - (id)executeQuery:(RHQuery *)query { 90 | NSParameterAssert(query); 91 | 92 | __block id ret = nil; 93 | 94 | NSFetchRequest *fetchRequest = [query generateFetchRequest]; 95 | 96 | [self.dbManager queryWithRequest:fetchRequest success:^(NSArray *result) { 97 | if (query.expressionDescription == nil) { 98 | ret = result; 99 | } else { 100 | NSDictionary *dict = [result firstObject]; 101 | ret = dict[query.expressionDescription.name]; 102 | } 103 | } failure:^(NSError *error) { 104 | [self RHLogging:[NSString stringWithFormat:@"RHDataAgent: Query(%@) execute failed! error(%@)", query, error.localizedDescription]]; 105 | }]; 106 | 107 | return ret; 108 | } 109 | 110 | - (void)executeQueryWithController:(RHQueryResultController *)controller { 111 | NSError *error = nil; 112 | if (![controller performFetch:&error]) { 113 | [self RHLogging:[NSString stringWithFormat:@"RHDataAgent: QueryResultController query failed! error(%@)", error.localizedDescription]]; 114 | } 115 | } 116 | 117 | #pragma mark - Cache 118 | - (void)cachedQuery:(RHQuery *)query withKey:(NSString *)queryKey { 119 | [self.queryCache setObject:query forKey:queryKey]; 120 | } 121 | 122 | - (void)removeCachedQueryForKey:(NSString *)queryKey { 123 | [self.queryCache removeObjectForKey:queryKey]; 124 | } 125 | 126 | - (RHQuery *)cachedQueryForKey:(NSString *)queryKey { 127 | return self.queryCache[queryKey]; 128 | } 129 | 130 | #pragma mark - Undo Management 131 | - (void)undo { 132 | [self.dbManager undo]; 133 | } 134 | 135 | - (void)redo { 136 | [self.dbManager redo]; 137 | } 138 | 139 | - (void)rollback { 140 | [self.dbManager rollback]; 141 | } 142 | 143 | - (void)reset { 144 | [self.dbManager reset]; 145 | } 146 | 147 | #pragma mark - Memory 148 | - (void)reduceMemory { 149 | //Clear cached queries 150 | [self.queryCache removeAllObjects]; 151 | //Clear undo manager track stack 152 | [self.mainManagedObjectContext.undoManager removeAllActions]; 153 | //Clear log 154 | self.logText = nil; 155 | self.logText = [NSMutableString string]; 156 | } 157 | 158 | #pragma mark - Logging Util 159 | - (void)RHLogging:(NSString *)log { 160 | if (self.trackLogging) { 161 | [self.logText appendFormat:@"%@\n", log]; 162 | } else { 163 | RLog(@"%@", log); 164 | } 165 | } 166 | 167 | @end 168 | -------------------------------------------------------------------------------- /RHParrotDataDemo/RHParrotDataDemo/RHParrotData/RHDataAgent.m: -------------------------------------------------------------------------------- 1 | // 2 | // RHDataAgent.m 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/17. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import "RHDataAgent.h" 10 | #import "RHQuery.h" 11 | #import "RHDatabaseManager.h" 12 | #import "RHQueryResultController.h" 13 | 14 | @interface RHDataAgent () 15 | @property (nonatomic, readwrite) RHDatabaseManager *dbManager; 16 | @property (nonatomic, strong) NSMutableDictionary *queryCache; 17 | @property (nonatomic, strong) NSMutableString *logText; 18 | @end 19 | 20 | @implementation RHDataAgent 21 | 22 | #pragma mark - Initialization 23 | static RHDataAgent *instance = nil; 24 | 25 | + (void)setupAgentWithMomdFile:(NSURL *)momdURL andStoreURL:(NSURL *)storeURL { 26 | static dispatch_once_t onceToken; 27 | dispatch_once(&onceToken, ^{ 28 | instance = [[self alloc] initWithMomdURL:momdURL storeURL:storeURL]; 29 | }); 30 | } 31 | 32 | + (instancetype)agent { 33 | return instance; 34 | } 35 | 36 | - (instancetype)initWithMomdURL:(NSURL *)momdURL storeURL:(NSURL *)storeURL { 37 | NSParameterAssert(momdURL); 38 | NSParameterAssert(storeURL); 39 | 40 | self = [super init]; 41 | if (self) { 42 | self.dbManager = [RHDatabaseManager databaseManagerWithModelURL:momdURL storeURL:storeURL]; 43 | self.queryCache = [NSMutableDictionary dictionary]; 44 | self.logText = [NSMutableString string]; 45 | self.trackLogging = NO; 46 | } 47 | return self; 48 | } 49 | 50 | - (instancetype)init { 51 | RLog(@"RHDataAgent: Warning! This is a singleton class, please use 'agent'"); 52 | return nil; 53 | } 54 | 55 | - (NSManagedObjectContext *)mainManagedObjectContext { 56 | return self.dbManager.managedObjectContext; 57 | } 58 | 59 | - (NSManagedObjectContext *)backgroundManagedObjectContext { 60 | return self.dbManager.backgroundManagedObjectContext; 61 | } 62 | 63 | #pragma mark - Insert, Update, Delete 64 | - (void)commit { 65 | [self.dbManager commitChangesWithSuccess:^{ 66 | [self RHLogging:@"RHDataAgent: Insert or update object success"]; 67 | } failure:^(NSError *error) { 68 | [self RHLogging:[NSString stringWithFormat:@"RHDataAgent: Insert or update object failed. error(%@)", error.localizedDescription]]; 69 | }]; 70 | } 71 | 72 | - (void)deleteObject:(NSManagedObject *)object { 73 | [self.dbManager deleteManagedObject:object success:^{ 74 | [self RHLogging:[NSString stringWithFormat:@"RHDataAgent: Delete obj(%@) success", object]]; 75 | } failure:^(NSError *error) { 76 | [self RHLogging:[NSString stringWithFormat:@"RHDataAgent: Delete obj(%@) failed. error(%@)", object, error.localizedDescription]]; 77 | }]; 78 | } 79 | 80 | - (void)deleteObjects:(NSArray *)objects { 81 | [self.dbManager deleteObjects:objects success:^{ 82 | [self RHLogging:[NSString stringWithFormat:@"RHDataAgent: Delete objs(%@) success", objects]]; 83 | } failure:^(NSError *error) { 84 | [self RHLogging:[NSString stringWithFormat:@"RHDataAgent: Delete objs(%@) failed! error(%@)", objects, error.localizedDescription]]; 85 | }]; 86 | } 87 | 88 | #pragma mark - Excuting 89 | - (id)executeQuery:(RHQuery *)query { 90 | NSParameterAssert(query); 91 | 92 | __block id ret = nil; 93 | 94 | NSFetchRequest *fetchRequest = [query generateFetchRequest]; 95 | 96 | [self.dbManager queryWithRequest:fetchRequest success:^(NSArray *result) { 97 | if (query.expressionDescription == nil) { 98 | ret = result; 99 | } else { 100 | NSDictionary *dict = [result firstObject]; 101 | ret = dict[query.expressionDescription.name]; 102 | } 103 | } failure:^(NSError *error) { 104 | [self RHLogging:[NSString stringWithFormat:@"RHDataAgent: Query(%@) execute failed! error(%@)", query, error.localizedDescription]]; 105 | }]; 106 | 107 | return ret; 108 | } 109 | 110 | - (void)executeQueryWithController:(RHQueryResultController *)controller { 111 | NSError *error = nil; 112 | if (![controller performFetch:&error]) { 113 | [self RHLogging:[NSString stringWithFormat:@"RHDataAgent: QueryResultController query failed! error(%@)", error.localizedDescription]]; 114 | } 115 | } 116 | 117 | #pragma mark - Cache 118 | - (void)cachedQuery:(RHQuery *)query withKey:(NSString *)queryKey { 119 | [self.queryCache setObject:query forKey:queryKey]; 120 | } 121 | 122 | - (void)removeCachedQueryForKey:(NSString *)queryKey { 123 | [self.queryCache removeObjectForKey:queryKey]; 124 | } 125 | 126 | - (RHQuery *)cachedQueryForKey:(NSString *)queryKey { 127 | return self.queryCache[queryKey]; 128 | } 129 | 130 | #pragma mark - Undo Management 131 | - (void)undo { 132 | [self.dbManager undo]; 133 | } 134 | 135 | - (void)redo { 136 | [self.dbManager redo]; 137 | } 138 | 139 | - (void)rollback { 140 | [self.dbManager rollback]; 141 | } 142 | 143 | - (void)reset { 144 | [self.dbManager reset]; 145 | } 146 | 147 | #pragma mark - Memory 148 | - (void)reduceMemory { 149 | //Clear cached queries 150 | [self.queryCache removeAllObjects]; 151 | //Clear undo manager track stack 152 | [self.mainManagedObjectContext.undoManager removeAllActions]; 153 | //Clear log 154 | self.logText = nil; 155 | self.logText = [NSMutableString string]; 156 | } 157 | 158 | #pragma mark - Logging Util 159 | - (void)RHLogging:(NSString *)log { 160 | if (self.trackLogging) { 161 | [self.logText appendFormat:@"%@\n", log]; 162 | } else { 163 | RLog(@"%@", log); 164 | } 165 | } 166 | 167 | @end 168 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RHParrotData 2 | 3 | [![Platform](https://cocoapod-badges.herokuapp.com/p/RHParrotData/badge.png)](http://cocoadocs.org/docsets/RHParrotData) 4 | [![Version](https://cocoapod-badges.herokuapp.com/v/RHParrotData/badge.png)](http://cocoadocs.org/docsets/RHParrotData) 5 | 6 | CoreData stack management and quick query language library. 7 | 8 | [Swift Version](https://github.com/Rannie/CoreDataParrot) 9 | 10 | ### Usage 11 | --- 12 | 13 | #### Install 14 | 15 | Use CocoaPods 16 | 17 | touch a Podfile and add: 18 | 19 | pod 'RHParrotData' 20 | 21 | Or clone this repository 22 | 23 | Drag "RHParrotData" folder into your project, and import "RHParrotData.h". 24 | 25 | #### Setup Database 26 | 27 | ```objc 28 | NSURL *momdURL = [[NSBundle mainBundle] URLForResource:$YOUR_MOMDFILENAME withExtension:@"momd"]; 29 | NSURL *appDocumentsDirectory = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; 30 | NSURL *storeURL = [appDocumentsDirectory URLByAppendingPathComponent:$YOUR_DBNAME]; 31 | [RHDataAgent setupAgentWithMomdFile:momdURL andStoreURL:storeURL]; 32 | ``` 33 | 34 | Then u can retrieve the instance of RHDataAgent by class method '*agent*'. 35 | 36 | 37 | #### Query 38 | 39 | ##### Simple Operator Query: 40 | 41 | ```objc 42 | RHQuery *query = [RHQuery queryWithEntity:@"Person"]; 43 | [query queryKey:@"name" op:RHEqual value:@"Kobe"]; 44 | id result = [query execute]; 45 | ``` 46 | 47 | Result will be a name == "Kobe" person array. 48 | 49 | ##### Query and Sort: 50 | 51 | ```objc 52 | RHQuery *sortQuery = [RHQuery queryWithEntity:@"Person"]; 53 | [sortQuery sort:@"age" ascending:NO]; 54 | id result = [sortQuery execute]; 55 | ``` 56 | 57 | Age will sort descending. 58 | 59 | ##### Query with Function 60 | 61 | ```objc 62 | RHQuery *queryAverageAge = [query same]; 63 | [queryAverageAge queryKey:@"age" function:RHAverage]; 64 | id result = [queryAverageAge execute]; 65 | ``` 66 | 67 | *same* means query same entity. 68 | Result will be the average number about age; 69 | 70 | ##### Compound Query 71 | 72 | **RHQuery** also support compound query. 73 | 74 | ```objc 75 | - (RHQuery *)OR:(RHQuery *)anoQuery; 76 | - (RHQuery *)AND:(RHQuery *)anoQuery; 77 | - (RHQuery *)NOT; 78 | ``` 79 | 80 | Sample: 81 | 82 | ```objc 83 | RHQuery *orQuery = [queryStart OR:query]; //"name == Kobe" query above 84 | id result = [orQuery execute]; 85 | ``` 86 | 87 | Result will be a list contains "$QUERY_START_CONDITION" or "name == Kobe" objects. 88 | 89 | #### Data Import 90 | 91 | Need new a RHDataImportor instance, and use: 92 | 93 | ```objc 94 | - (void)importEntity:(NSString *)entity 95 | primaryKey:(NSString *)primaryKey 96 | data:(NSArray *)data 97 | insertHandler:(RHObjectSerializeHandler)insertHandler 98 | updateHandler:(RHObjectSerializeHandler)updateHandler; 99 | ``` 100 | 101 | It will import data in a background managedObjectContext and merge changes to the main managedObjectContext. 102 | 103 | #### NSFetchedResultController 104 | 105 | The class 'RHQueryResultController' is a subclass of 'NSFetchedResultController'.
106 | Use it with RHQuery: 107 | 108 | ```objc 109 | RHQuery *query = ... 110 | RHQueryResultController *qrc = [RHQueryResultController queryResultControllerWithQuery:query]; 111 | [qrc performQuery]; 112 | ``` 113 | 114 | Or use *queryResultControllerWithQuery:sectionNameKeyPath:cacheName:* method to support section or cache. 115 | 116 | #### Data Agent 117 | 118 | Agent is a singleton. It's Features: 119 | 120 | * commit changes about managed objects 121 | * cache queries 122 | * undo management 123 | * memory management 124 | 125 | Insert and update: 126 | 127 | ```objc 128 | [[RHDataAgent agent] commit]; 129 | ``` 130 | 131 | Delete object or objects: 132 | 133 | ```objc 134 | [[RHDataAgent agent] deleteObject:objToDelete]; 135 | [[RHDataAgent agent] deleteObjects:(NSArray *)objsToDelete]; 136 | ``` 137 | 138 | execute RHQuery: 139 | 140 | ```objc 141 | [[RHDataAgent agent] executeQuery:query]; 142 | ``` 143 | 144 | Undo management: 145 | 146 | ```objc 147 | - (void)undo; 148 | - (void)redo; 149 | - (void)rollback; 150 | - (void)reset; 151 | ``` 152 | 153 | Reduce memory: 154 | 155 | ```objc 156 | - (void)reduceMemory; 157 | ``` 158 | 159 | ### Query Operators 160 | --- 161 | 162 | | **Operator Enum** | **Comparison** | **Example** | 163 | |---------------------|------------------|-------------------------- | 164 | | RHEqual | == | "name == Hanran" | 165 | | RHGreaterThan | > | "age > 20" | 166 | | RHLessThan | < | "age < 40" | 167 | | RHGreaterOrEqual | >= | "price >= 100" | 168 | | RHLessOrEqual | <= | "price <= 1000" | 169 | | RHNot | != | "sex != female" | 170 | | RHBetween | < lhs < | "price IN 100, 1000" | 171 | | RHBeginsWith | lhs start with rhs| "Terry BEGINSWITH T" | 172 | | RHEndsWith | lhs end with rhs | "Terry ENDSWITH y" | 173 | | RHContains | lhs contains rhs | "Terry CONTAINS rr" | 174 | | RHLike | lhs like rhs | "name LIKE[c] next" | 175 | | RHMatches | lhs matches rhs | "name MATCHES ^A.+e$". [Regular Expressions][1] | 176 | | RHIn | lhs in rhs | "name IN Ben, Melissa, Nick"| 177 | 178 | 179 | ### Query Functions 180 | --- 181 | 182 | | **Function Enum** | **Meaning** | 183 | |-------------------|--------------| 184 | | RHMax | max number of the column | 185 | | RHMin | min number of the column | 186 | | RHAverage | average number | 187 | | RHSum | sum number | 188 | | RHCount | row count | 189 | 190 | 191 | ### TODO 192 | --- 193 | ~~Podspec File~~
194 | ~~Document~~
195 | ~~NSFetchResultController~~
196 | Log Util
197 | ~~Swift Version~~ ([CoreDataParrot](https://github.com/Rannie/CoreDataParrot))
198 | Test
199 | Complete Example
200 | FMDB Version
201 | Base ManagedObject (Serialization)
202 | 203 | ### LICENSE 204 | --- 205 | 206 | The MIT License (MIT) 207 | 208 | Copyright (c) 2015-2017 Hanran Liu 209 | 210 | Permission is hereby granted, free of charge, to any person obtaining a copy 211 | of this software and associated documentation files (the "Software"), to deal 212 | in the Software without restriction, including without limitation the rights 213 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 214 | copies of the Software, and to permit persons to whom the Software is 215 | furnished to do so, subject to the following conditions: 216 | 217 | The above copyright notice and this permission notice shall be included in all 218 | copies or substantial portions of the Software. 219 | 220 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 221 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 222 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 223 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 224 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 225 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 226 | SOFTWARE. 227 | 228 | 229 | 230 | [1]:http://userguide.icu-project.org/strings/regexp 231 | -------------------------------------------------------------------------------- /RHParrotData/RHQuery.m: -------------------------------------------------------------------------------- 1 | // 2 | // RHQuery.m 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/17. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import "RHQuery.h" 10 | #import "RHDataAgent.h" 11 | 12 | static NSString * RHOperatorText(RHOperator op) { 13 | switch (op) { 14 | case RHEqual: 15 | return @"="; 16 | case RHGreaterThan: 17 | return @">"; 18 | case RHLessThan: 19 | return @"<"; 20 | case RHGreaterOrEqual: 21 | return @">="; 22 | case RHLessOrEqual: 23 | return @"<="; 24 | case RHNot: 25 | return @"!="; 26 | case RHBetween: 27 | return @"BETWEEN"; 28 | case RHBeginsWith: 29 | return @"BEGINSWITH"; 30 | case RHEndsWith: 31 | return @"ENDSWITH"; 32 | case RHContains: 33 | return @"CONTAINS"; 34 | case RHLike: 35 | return @"LIKE[cd]"; 36 | case RHMatches: 37 | return @"MATCHES"; 38 | case RHIn: 39 | return @"IN"; 40 | default: 41 | RLog(@"RHQuery: Unknown operator!"); 42 | break; 43 | } 44 | return nil; 45 | } 46 | 47 | static NSString * RHFunctionExpression(RHFunction func) { 48 | switch (func) { 49 | case RHMax: 50 | return @"max:"; 51 | case RHMin: 52 | return @"min:"; 53 | case RHCount: 54 | return @"count:"; 55 | case RHSum: 56 | return @"sum:"; 57 | case RHAverage: 58 | return @"average:"; 59 | default: 60 | RLog(@"RHQuery: Unknown function!"); 61 | break; 62 | } 63 | return nil; 64 | } 65 | 66 | @interface RHQuery () 67 | @property (nonatomic, strong, readwrite) NSPredicate *queryPredicate; 68 | @property (nonatomic, strong, readwrite) NSString *entity; 69 | @property (nonatomic, strong, readwrite) NSExpressionDescription *expressionDescription; 70 | 71 | @property (nonatomic, assign, getter=isCompound) BOOL compound; 72 | @property (nonatomic, strong) NSMutableArray *sortConditions; 73 | @end 74 | 75 | @implementation RHQuery 76 | 77 | #pragma mark - Initialization 78 | + (RHQuery *)queryWithEntity:(NSString *)entityName { 79 | return [[self alloc] initWithQueryEntity:entityName]; 80 | } 81 | 82 | - (RHQuery *)initWithQueryEntity:(NSString *)entityName { 83 | NSParameterAssert(entityName); 84 | 85 | self = [self init]; 86 | if (self) { 87 | self.entity = entityName; 88 | self.sortConditions = [NSMutableArray array]; 89 | self.queryOffset = 0; 90 | self.batchSize = 0; 91 | self.limitCount = 0; 92 | } 93 | return self; 94 | } 95 | 96 | - (RHQuery *)same { 97 | return [RHQuery queryWithEntity:self.entity]; 98 | } 99 | 100 | - (id)copyWithZone:(NSZone *)zone { 101 | RHQuery *query = [[RHQuery allocWithZone:zone] init]; 102 | query.entity = self.entity; 103 | query.queryPredicate = self.queryPredicate; 104 | query.expressionDescription = self.expressionDescription; 105 | query.sortConditions = self.sortConditions; 106 | query.limitCount = self.limitCount; 107 | query.batchSize = self.batchSize; 108 | query.queryOffset = self.queryOffset; 109 | return query; 110 | } 111 | 112 | - (NSArray *)sortDescriptors { 113 | return [self.sortConditions copy]; 114 | } 115 | 116 | #pragma mark - Query Condition Methods 117 | - (void)queryKey:(NSString *)key op:(RHOperator)op value:(id)value { 118 | NSParameterAssert(key); 119 | NSParameterAssert(value); 120 | 121 | if (op == RHNone) { return; } 122 | if (op == RHIn) { 123 | if (![value isKindOfClass:NSArray.class]) { 124 | RLog(@"RHQuery: In value should be a list, if only one value, should use 'RHEqual'."); 125 | return; 126 | } 127 | } 128 | 129 | if (self.isCompound) { 130 | RLog(@"RHQuery: Query is compound. If want to add a condition, can use 'AND:' method!"); 131 | return; 132 | } 133 | 134 | NSString *operator = RHOperatorText(op); 135 | NSString *statement = [NSString stringWithFormat:@"%@ %@ \"%@\"", key, operator, value]; 136 | NSPredicate *predicate = [NSPredicate predicateWithFormat:statement]; 137 | self.queryPredicate = predicate; 138 | } 139 | 140 | - (void)queryKey:(NSString *)key function:(RHFunction)function { 141 | NSParameterAssert(key); 142 | 143 | NSExpression *keyPathExpression = [NSExpression expressionForKeyPath:key]; 144 | NSExpression *expression = [NSExpression expressionForFunction:RHFunctionExpression(function) arguments:@[keyPathExpression]]; 145 | 146 | NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init]; 147 | expressionDescription.name = key; 148 | expressionDescription.expression = expression; 149 | expressionDescription.expressionResultType = NSUndefinedAttributeType; 150 | 151 | self.expressionDescription = expressionDescription; 152 | } 153 | 154 | - (RHQuery *)OR:(RHQuery *)anoQuery { 155 | NSParameterAssert(anoQuery); 156 | NSPredicate *comPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:@[self.queryPredicate, anoQuery.queryPredicate]]; 157 | RHQuery *newQuery = [self copy]; 158 | newQuery.queryPredicate = comPredicate; 159 | newQuery.compound = YES; 160 | return newQuery; 161 | } 162 | 163 | - (RHQuery *)AND:(RHQuery *)anoQuery { 164 | NSParameterAssert(anoQuery); 165 | NSPredicate *comPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[self.queryPredicate, anoQuery.queryPredicate]]; 166 | RHQuery *newQuery = [self copy]; 167 | newQuery.queryPredicate = comPredicate; 168 | newQuery.compound = YES; 169 | return newQuery; 170 | } 171 | 172 | - (RHQuery *)NOT { 173 | NSPredicate *comPredicate = [NSCompoundPredicate notPredicateWithSubpredicate:self.queryPredicate]; 174 | RHQuery *newQuery = [self copy]; 175 | newQuery.queryPredicate = comPredicate; 176 | newQuery.compound = YES; 177 | return newQuery; 178 | } 179 | 180 | - (void)sort:(NSString *)key ascending:(BOOL)ascending { 181 | NSParameterAssert(key); 182 | NSSortDescriptor *sortDes = [[NSSortDescriptor alloc] initWithKey:key ascending:ascending]; 183 | [self.sortConditions addObject:sortDes]; 184 | } 185 | 186 | - (void)sort:(NSString *)key ascending:(BOOL)ascending comparator:(NSComparator)comparator { 187 | NSParameterAssert(key); 188 | NSSortDescriptor *sortDes = nil; 189 | sortDes = [[NSSortDescriptor alloc] initWithKey:key ascending:ascending comparator:comparator]; 190 | [self.sortConditions addObject:sortDes]; 191 | } 192 | 193 | - (id)execute { 194 | return [[RHDataAgent agent] executeQuery:self]; 195 | } 196 | 197 | #pragma mark - Other 198 | - (NSFetchRequest *)generateFetchRequest { 199 | NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 200 | 201 | NSEntityDescription *entityDes = [NSEntityDescription entityForName:self.entity inManagedObjectContext:RHMainContext]; 202 | fetchRequest.entity = entityDes; 203 | 204 | fetchRequest.predicate = self.queryPredicate; 205 | fetchRequest.sortDescriptors = self.sortDescriptors; 206 | fetchRequest.fetchBatchSize = self.batchSize; 207 | fetchRequest.fetchOffset = self.queryOffset; 208 | fetchRequest.fetchLimit = self.limitCount; 209 | 210 | if (self.expressionDescription) { 211 | [fetchRequest setPropertiesToFetch:@[self.expressionDescription]]; 212 | [fetchRequest setResultType:NSDictionaryResultType]; 213 | } 214 | 215 | return fetchRequest; 216 | } 217 | 218 | - (NSString *)description { 219 | return [NSString stringWithFormat:@"", self, self.entity, self.queryPredicate.predicateFormat]; 220 | } 221 | 222 | @end 223 | -------------------------------------------------------------------------------- /RHParrotDataDemo/RHParrotDataDemo/RHParrotData/RHQuery.m: -------------------------------------------------------------------------------- 1 | // 2 | // RHQuery.m 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/17. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import "RHQuery.h" 10 | #import "RHDataAgent.h" 11 | 12 | static NSString * RHOperatorText(RHOperator op) { 13 | switch (op) { 14 | case RHEqual: 15 | return @"="; 16 | case RHGreaterThan: 17 | return @">"; 18 | case RHLessThan: 19 | return @"<"; 20 | case RHGreaterOrEqual: 21 | return @">="; 22 | case RHLessOrEqual: 23 | return @"<="; 24 | case RHNot: 25 | return @"!="; 26 | case RHBetween: 27 | return @"BETWEEN"; 28 | case RHBeginsWith: 29 | return @"BEGINSWITH"; 30 | case RHEndsWith: 31 | return @"ENDSWITH"; 32 | case RHContains: 33 | return @"CONTAINS"; 34 | case RHLike: 35 | return @"LIKE[cd]"; 36 | case RHMatches: 37 | return @"MATCHES"; 38 | case RHIn: 39 | return @"IN"; 40 | default: 41 | RLog(@"RHQuery: Unknown operator!"); 42 | break; 43 | } 44 | return nil; 45 | } 46 | 47 | static NSString * RHFunctionExpression(RHFunction func) { 48 | switch (func) { 49 | case RHMax: 50 | return @"max:"; 51 | case RHMin: 52 | return @"min:"; 53 | case RHCount: 54 | return @"count:"; 55 | case RHSum: 56 | return @"sum:"; 57 | case RHAverage: 58 | return @"average:"; 59 | default: 60 | RLog(@"RHQuery: Unknown function!"); 61 | break; 62 | } 63 | return nil; 64 | } 65 | 66 | @interface RHQuery () 67 | @property (nonatomic, strong, readwrite) NSPredicate *queryPredicate; 68 | @property (nonatomic, strong, readwrite) NSString *entity; 69 | @property (nonatomic, strong, readwrite) NSExpressionDescription *expressionDescription; 70 | 71 | @property (nonatomic, assign, getter=isCompound) BOOL compound; 72 | @property (nonatomic, strong) NSMutableArray *sortConditions; 73 | @end 74 | 75 | @implementation RHQuery 76 | 77 | #pragma mark - Initialization 78 | + (RHQuery *)queryWithEntity:(NSString *)entityName { 79 | return [[self alloc] initWithQueryEntity:entityName]; 80 | } 81 | 82 | - (RHQuery *)initWithQueryEntity:(NSString *)entityName { 83 | NSParameterAssert(entityName); 84 | 85 | self = [self init]; 86 | if (self) { 87 | self.entity = entityName; 88 | self.sortConditions = [NSMutableArray array]; 89 | self.queryOffset = 0; 90 | self.batchSize = 0; 91 | self.limitCount = 0; 92 | } 93 | return self; 94 | } 95 | 96 | - (RHQuery *)same { 97 | return [RHQuery queryWithEntity:self.entity]; 98 | } 99 | 100 | - (id)copyWithZone:(NSZone *)zone { 101 | RHQuery *query = [[RHQuery allocWithZone:zone] init]; 102 | query.entity = self.entity; 103 | query.queryPredicate = self.queryPredicate; 104 | query.expressionDescription = self.expressionDescription; 105 | query.sortConditions = self.sortConditions; 106 | query.limitCount = self.limitCount; 107 | query.batchSize = self.batchSize; 108 | query.queryOffset = self.queryOffset; 109 | return query; 110 | } 111 | 112 | - (NSArray *)sortDescriptors { 113 | return [self.sortConditions copy]; 114 | } 115 | 116 | #pragma mark - Query Condition Methods 117 | - (void)queryKey:(NSString *)key op:(RHOperator)op value:(id)value { 118 | NSParameterAssert(key); 119 | NSParameterAssert(value); 120 | 121 | if (op == RHNone) { return; } 122 | if (op == RHIn) { 123 | if (![value isKindOfClass:NSArray.class]) { 124 | RLog(@"RHQuery: In value should be a list, if only one value, should use 'RHEqual'."); 125 | return; 126 | } 127 | } 128 | 129 | if (self.isCompound) { 130 | RLog(@"RHQuery: Query is compound. If want to add a condition, can use 'AND:' method!"); 131 | return; 132 | } 133 | 134 | NSString *operator = RHOperatorText(op); 135 | NSString *statement = [NSString stringWithFormat:@"%@ %@ \"%@\"", key, operator, value]; 136 | NSPredicate *predicate = [NSPredicate predicateWithFormat:statement]; 137 | self.queryPredicate = predicate; 138 | } 139 | 140 | - (void)queryKey:(NSString *)key function:(RHFunction)function { 141 | NSParameterAssert(key); 142 | 143 | NSExpression *keyPathExpression = [NSExpression expressionForKeyPath:key]; 144 | NSExpression *expression = [NSExpression expressionForFunction:RHFunctionExpression(function) arguments:@[keyPathExpression]]; 145 | 146 | NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init]; 147 | expressionDescription.name = key; 148 | expressionDescription.expression = expression; 149 | expressionDescription.expressionResultType = NSUndefinedAttributeType; 150 | 151 | self.expressionDescription = expressionDescription; 152 | } 153 | 154 | - (RHQuery *)OR:(RHQuery *)anoQuery { 155 | NSParameterAssert(anoQuery); 156 | NSPredicate *comPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:@[self.queryPredicate, anoQuery.queryPredicate]]; 157 | RHQuery *newQuery = [self copy]; 158 | newQuery.queryPredicate = comPredicate; 159 | newQuery.compound = YES; 160 | return newQuery; 161 | } 162 | 163 | - (RHQuery *)AND:(RHQuery *)anoQuery { 164 | NSParameterAssert(anoQuery); 165 | NSPredicate *comPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[self.queryPredicate, anoQuery.queryPredicate]]; 166 | RHQuery *newQuery = [self copy]; 167 | newQuery.queryPredicate = comPredicate; 168 | newQuery.compound = YES; 169 | return newQuery; 170 | } 171 | 172 | - (RHQuery *)NOT { 173 | NSPredicate *comPredicate = [NSCompoundPredicate notPredicateWithSubpredicate:self.queryPredicate]; 174 | RHQuery *newQuery = [self copy]; 175 | newQuery.queryPredicate = comPredicate; 176 | newQuery.compound = YES; 177 | return newQuery; 178 | } 179 | 180 | - (void)sort:(NSString *)key ascending:(BOOL)ascending { 181 | NSParameterAssert(key); 182 | NSSortDescriptor *sortDes = [[NSSortDescriptor alloc] initWithKey:key ascending:ascending]; 183 | [self.sortConditions addObject:sortDes]; 184 | } 185 | 186 | - (void)sort:(NSString *)key ascending:(BOOL)ascending comparator:(NSComparator)comparator { 187 | NSParameterAssert(key); 188 | NSSortDescriptor *sortDes = nil; 189 | sortDes = [[NSSortDescriptor alloc] initWithKey:key ascending:ascending comparator:comparator]; 190 | [self.sortConditions addObject:sortDes]; 191 | } 192 | 193 | - (id)execute { 194 | return [[RHDataAgent agent] executeQuery:self]; 195 | } 196 | 197 | #pragma mark - Other 198 | - (NSFetchRequest *)generateFetchRequest { 199 | NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 200 | 201 | NSEntityDescription *entityDes = [NSEntityDescription entityForName:self.entity inManagedObjectContext:RHMainContext]; 202 | fetchRequest.entity = entityDes; 203 | 204 | fetchRequest.predicate = self.queryPredicate; 205 | fetchRequest.sortDescriptors = self.sortDescriptors; 206 | fetchRequest.fetchBatchSize = self.batchSize; 207 | fetchRequest.fetchOffset = self.queryOffset; 208 | fetchRequest.fetchLimit = self.limitCount; 209 | 210 | if (self.expressionDescription) { 211 | [fetchRequest setPropertiesToFetch:@[self.expressionDescription]]; 212 | [fetchRequest setResultType:NSDictionaryResultType]; 213 | } 214 | 215 | return fetchRequest; 216 | } 217 | 218 | - (NSString *)description { 219 | return [NSString stringWithFormat:@"", self, self.entity, self.queryPredicate.predicateFormat]; 220 | } 221 | 222 | @end 223 | -------------------------------------------------------------------------------- /RHParrotData/RHDatabaseManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // RHDatabaseManager.m 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/19. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import "RHDatabaseManager.h" 10 | 11 | static NSString * const RHDatabaseManagerDomain = @"RHDatabaseManagerDomain"; 12 | 13 | @implementation RHDatabaseManager 14 | 15 | @synthesize managedObjectContext = _managedObjectContext; 16 | @synthesize backgroundManagedObjectContext = _backgroundManagedObjectContext; 17 | @synthesize managedObjectModel = _managedObjectModel; 18 | @synthesize persistentStoreCoordinator = _persistentStoreCoordinator; 19 | 20 | #pragma mark - Initilialization 21 | + (instancetype)databaseManagerWithModelURL:(NSURL *)momdURL storeURL:(NSURL *)storeURL { 22 | return [[self alloc] initWithModelURL:momdURL storeURL:storeURL]; 23 | } 24 | 25 | - (instancetype)initWithModelURL:(NSURL *)momdURL storeURL:(NSURL *)storeURL { 26 | self = [self init]; 27 | if (self) { 28 | self.momdURL = momdURL; 29 | self.storeURL = storeURL; 30 | [self observeContextDidSavingNotification]; 31 | } 32 | return self; 33 | } 34 | 35 | #pragma mark - Stack 36 | - (NSManagedObjectModel *)managedObjectModel { 37 | if (_managedObjectModel != nil) { 38 | return _managedObjectModel; 39 | } 40 | 41 | _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:self.momdURL]; 42 | return _managedObjectModel; 43 | } 44 | 45 | - (NSManagedObjectContext *)managedObjectContext { 46 | if (_managedObjectContext != nil) { 47 | return _managedObjectContext; 48 | } 49 | 50 | _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; 51 | _managedObjectContext.undoManager = [[NSUndoManager alloc] init]; 52 | [_managedObjectContext setPersistentStoreCoordinator:self.persistentStoreCoordinator]; 53 | return _managedObjectContext; 54 | } 55 | 56 | - (NSManagedObjectContext *)backgroundManagedObjectContext { 57 | if (_backgroundManagedObjectContext != nil) { 58 | return _backgroundManagedObjectContext; 59 | } 60 | 61 | _backgroundManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 62 | _backgroundManagedObjectContext.undoManager = nil; 63 | [_backgroundManagedObjectContext setPersistentStoreCoordinator:self.persistentStoreCoordinator]; 64 | return _backgroundManagedObjectContext; 65 | } 66 | 67 | - (NSPersistentStoreCoordinator *)persistentStoreCoordinator { 68 | if (_persistentStoreCoordinator != nil) { 69 | return _persistentStoreCoordinator; 70 | } 71 | 72 | NSError *error = nil; 73 | _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel]; 74 | 75 | NSDictionary *options = @{NSMigratePersistentStoresAutomaticallyOption: @YES, 76 | NSInferMappingModelAutomaticallyOption: @YES }; 77 | if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType 78 | configuration:nil 79 | URL:self.storeURL 80 | options:options 81 | error:&error]) 82 | { 83 | RLog(@"DBManager: Unresolved error %@, %@", error, [error userInfo]); 84 | } 85 | return _persistentStoreCoordinator; 86 | } 87 | 88 | 89 | #pragma mark - Observe Concurrency Note 90 | - (void)observeContextDidSavingNotification { 91 | [[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextDidSaveNotification 92 | object:nil 93 | queue:nil 94 | usingBlock:^(NSNotification *note) { 95 | NSManagedObjectContext *moc = self.managedObjectContext; 96 | if (note.object != moc) { 97 | [moc performBlock:^{ 98 | [moc mergeChangesFromContextDidSaveNotification:note]; 99 | }]; 100 | } 101 | }]; 102 | } 103 | 104 | #pragma mark - Insert, Update 105 | - (void)commitChangesWithSuccess:(DBOperationSuccessBlock)success failure:(DBOperationFailureBlock)failure { 106 | [self saveContextWithSuccess:success failure:failure]; 107 | } 108 | 109 | #pragma mark - Delete 110 | - (void)deleteManagedObject:(id)object success:(DBOperationSuccessBlock)success failure:(DBOperationFailureBlock)failure { 111 | NSManagedObject *managedObj = object; 112 | if (managedObj.managedObjectContext == self.managedObjectContext) { 113 | [self.managedObjectContext deleteObject:managedObj]; 114 | [self saveContextWithSuccess:success failure:failure]; 115 | } else { 116 | NSError *error = [NSError errorWithDomain:RHDatabaseManagerDomain code:0 userInfo:@{NSLocalizedDescriptionKey: @"DBManager: WARNING! Object in diffrent context!"}]; 117 | if (failure) failure(error); 118 | } 119 | } 120 | 121 | - (void)deleteObjects:(NSArray *)objects success:(DBOperationSuccessBlock)success failure:(DBOperationFailureBlock)failure { 122 | for (NSManagedObject *modelObj in objects) { 123 | if (modelObj.managedObjectContext == self.managedObjectContext) { 124 | [self.managedObjectContext deleteObject:modelObj]; 125 | } else { 126 | NSError *error = [NSError errorWithDomain:RHDatabaseManagerDomain code:0 userInfo:@{NSLocalizedDescriptionKey: @"DBManager: WARNING! Object in diffrent context!"}]; 127 | if (failure) failure(error); 128 | } 129 | } 130 | 131 | [self saveContextWithSuccess:success failure:failure]; 132 | } 133 | 134 | #pragma mark - Update 135 | - (void)updateManagedObject:(id)object success:(DBOperationSuccessBlock)success failure:(DBOperationFailureBlock)failure { 136 | NSManagedObject *managedObj = object; 137 | 138 | if (managedObj.managedObjectContext != self.managedObjectContext) { 139 | NSError *error = [NSError errorWithDomain:RHDatabaseManagerDomain code:0 userInfo:@{NSLocalizedDescriptionKey: @"DBManager: WARNING! Object in diffrent context!"}]; 140 | if (failure) failure(error); 141 | } 142 | 143 | if ([managedObj hasChanges]) { 144 | [self saveContextWithSuccess:success failure:failure]; 145 | } 146 | } 147 | 148 | - (void)updateObjects:(NSArray *)objects success:(DBOperationSuccessBlock)success failure:(DBOperationFailureBlock)failure { 149 | NSManagedObject *managedObj = [objects firstObject]; 150 | if (managedObj.managedObjectContext != self.managedObjectContext) { 151 | NSError *error = [NSError errorWithDomain:RHDatabaseManagerDomain code:0 userInfo:@{NSLocalizedDescriptionKey: @"DBManager: WARNING! Object in diffrent context!"}]; 152 | if (failure) failure(error); 153 | return; 154 | } 155 | 156 | [self saveContextWithSuccess:success failure:failure]; 157 | } 158 | 159 | #pragma mark - Query 160 | - (void)queryWithRequest:(NSFetchRequest *)fetchRequest success:(DBQuerySuccessBlock)success failure:(DBOperationFailureBlock)failure { 161 | NSError *error = nil; 162 | NSArray *results = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error]; 163 | if (error) { 164 | if (failure) failure(error); 165 | } else { 166 | if (success) success(results); 167 | } 168 | } 169 | 170 | #pragma mark - Save Context 171 | - (void)saveContextWithSuccess:(DBOperationSuccessBlock)success failure:(DBOperationFailureBlock)failure 172 | { 173 | NSError *error = nil; 174 | NSManagedObjectContext *context = self.managedObjectContext; 175 | if ([context hasChanges] && ![context save:&error]) { 176 | if (failure) failure(error); 177 | } else { 178 | if (success) success(); 179 | } 180 | } 181 | 182 | #pragma mark - Undo Management 183 | - (void)undo { 184 | [self.managedObjectContext undo]; 185 | } 186 | 187 | - (void)redo { 188 | [self.managedObjectContext redo]; 189 | } 190 | 191 | - (void)rollback { 192 | [self.managedObjectContext rollback]; 193 | } 194 | 195 | - (void)reset { 196 | [self.managedObjectContext reset]; 197 | } 198 | 199 | @end 200 | -------------------------------------------------------------------------------- /RHParrotDataDemo/RHParrotDataDemo/RHParrotData/RHDatabaseManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // RHDatabaseManager.m 3 | // RHParrotDataDemo 4 | // 5 | // Created by Hanran Liu on 15/1/19. 6 | // Copyright (c) 2015年 ran. All rights reserved. 7 | // 8 | 9 | #import "RHDatabaseManager.h" 10 | 11 | static NSString * const RHDatabaseManagerDomain = @"RHDatabaseManagerDomain"; 12 | 13 | @implementation RHDatabaseManager 14 | 15 | @synthesize managedObjectContext = _managedObjectContext; 16 | @synthesize backgroundManagedObjectContext = _backgroundManagedObjectContext; 17 | @synthesize managedObjectModel = _managedObjectModel; 18 | @synthesize persistentStoreCoordinator = _persistentStoreCoordinator; 19 | 20 | #pragma mark - Initilialization 21 | + (instancetype)databaseManagerWithModelURL:(NSURL *)momdURL storeURL:(NSURL *)storeURL { 22 | return [[self alloc] initWithModelURL:momdURL storeURL:storeURL]; 23 | } 24 | 25 | - (instancetype)initWithModelURL:(NSURL *)momdURL storeURL:(NSURL *)storeURL { 26 | self = [self init]; 27 | if (self) { 28 | self.momdURL = momdURL; 29 | self.storeURL = storeURL; 30 | [self observeContextDidSavingNotification]; 31 | } 32 | return self; 33 | } 34 | 35 | #pragma mark - Stack 36 | - (NSManagedObjectModel *)managedObjectModel { 37 | if (_managedObjectModel != nil) { 38 | return _managedObjectModel; 39 | } 40 | 41 | _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:self.momdURL]; 42 | return _managedObjectModel; 43 | } 44 | 45 | - (NSManagedObjectContext *)managedObjectContext { 46 | if (_managedObjectContext != nil) { 47 | return _managedObjectContext; 48 | } 49 | 50 | _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; 51 | _managedObjectContext.undoManager = [[NSUndoManager alloc] init]; 52 | [_managedObjectContext setPersistentStoreCoordinator:self.persistentStoreCoordinator]; 53 | return _managedObjectContext; 54 | } 55 | 56 | - (NSManagedObjectContext *)backgroundManagedObjectContext { 57 | if (_backgroundManagedObjectContext != nil) { 58 | return _backgroundManagedObjectContext; 59 | } 60 | 61 | _backgroundManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 62 | _backgroundManagedObjectContext.undoManager = nil; 63 | [_backgroundManagedObjectContext setPersistentStoreCoordinator:self.persistentStoreCoordinator]; 64 | return _backgroundManagedObjectContext; 65 | } 66 | 67 | - (NSPersistentStoreCoordinator *)persistentStoreCoordinator { 68 | if (_persistentStoreCoordinator != nil) { 69 | return _persistentStoreCoordinator; 70 | } 71 | 72 | NSError *error = nil; 73 | _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel]; 74 | 75 | NSDictionary *options = @{NSMigratePersistentStoresAutomaticallyOption: @YES, 76 | NSInferMappingModelAutomaticallyOption: @YES }; 77 | if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType 78 | configuration:nil 79 | URL:self.storeURL 80 | options:options 81 | error:&error]) 82 | { 83 | RLog(@"DBManager: Unresolved error %@, %@", error, [error userInfo]); 84 | } 85 | return _persistentStoreCoordinator; 86 | } 87 | 88 | 89 | #pragma mark - Observe Concurrency Note 90 | - (void)observeContextDidSavingNotification { 91 | [[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextDidSaveNotification 92 | object:nil 93 | queue:nil 94 | usingBlock:^(NSNotification *note) { 95 | NSManagedObjectContext *moc = self.managedObjectContext; 96 | if (note.object != moc) { 97 | [moc performBlock:^{ 98 | [moc mergeChangesFromContextDidSaveNotification:note]; 99 | }]; 100 | } 101 | }]; 102 | } 103 | 104 | #pragma mark - Insert, Update 105 | - (void)commitChangesWithSuccess:(DBOperationSuccessBlock)success failure:(DBOperationFailureBlock)failure { 106 | [self saveContextWithSuccess:success failure:failure]; 107 | } 108 | 109 | #pragma mark - Delete 110 | - (void)deleteManagedObject:(id)object success:(DBOperationSuccessBlock)success failure:(DBOperationFailureBlock)failure { 111 | NSManagedObject *managedObj = object; 112 | if (managedObj.managedObjectContext == self.managedObjectContext) { 113 | [self.managedObjectContext deleteObject:managedObj]; 114 | [self saveContextWithSuccess:success failure:failure]; 115 | } else { 116 | NSError *error = [NSError errorWithDomain:RHDatabaseManagerDomain code:0 userInfo:@{NSLocalizedDescriptionKey: @"DBManager: WARNING! Object in diffrent context!"}]; 117 | if (failure) failure(error); 118 | } 119 | } 120 | 121 | - (void)deleteObjects:(NSArray *)objects success:(DBOperationSuccessBlock)success failure:(DBOperationFailureBlock)failure { 122 | for (NSManagedObject *modelObj in objects) { 123 | if (modelObj.managedObjectContext == self.managedObjectContext) { 124 | [self.managedObjectContext deleteObject:modelObj]; 125 | } else { 126 | NSError *error = [NSError errorWithDomain:RHDatabaseManagerDomain code:0 userInfo:@{NSLocalizedDescriptionKey: @"DBManager: WARNING! Object in diffrent context!"}]; 127 | if (failure) failure(error); 128 | } 129 | } 130 | 131 | [self saveContextWithSuccess:success failure:failure]; 132 | } 133 | 134 | #pragma mark - Update 135 | - (void)updateManagedObject:(id)object success:(DBOperationSuccessBlock)success failure:(DBOperationFailureBlock)failure { 136 | NSManagedObject *managedObj = object; 137 | 138 | if (managedObj.managedObjectContext != self.managedObjectContext) { 139 | NSError *error = [NSError errorWithDomain:RHDatabaseManagerDomain code:0 userInfo:@{NSLocalizedDescriptionKey: @"DBManager: WARNING! Object in diffrent context!"}]; 140 | if (failure) failure(error); 141 | } 142 | 143 | if ([managedObj hasChanges]) { 144 | [self saveContextWithSuccess:success failure:failure]; 145 | } 146 | } 147 | 148 | - (void)updateObjects:(NSArray *)objects success:(DBOperationSuccessBlock)success failure:(DBOperationFailureBlock)failure { 149 | NSManagedObject *managedObj = [objects firstObject]; 150 | if (managedObj.managedObjectContext != self.managedObjectContext) { 151 | NSError *error = [NSError errorWithDomain:RHDatabaseManagerDomain code:0 userInfo:@{NSLocalizedDescriptionKey: @"DBManager: WARNING! Object in diffrent context!"}]; 152 | if (failure) failure(error); 153 | return; 154 | } 155 | 156 | [self saveContextWithSuccess:success failure:failure]; 157 | } 158 | 159 | #pragma mark - Query 160 | - (void)queryWithRequest:(NSFetchRequest *)fetchRequest success:(DBQuerySuccessBlock)success failure:(DBOperationFailureBlock)failure { 161 | NSError *error = nil; 162 | NSArray *results = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error]; 163 | if (error) { 164 | if (failure) failure(error); 165 | } else { 166 | if (success) success(results); 167 | } 168 | } 169 | 170 | #pragma mark - Save Context 171 | - (void)saveContextWithSuccess:(DBOperationSuccessBlock)success failure:(DBOperationFailureBlock)failure 172 | { 173 | NSError *error = nil; 174 | NSManagedObjectContext *context = self.managedObjectContext; 175 | if ([context hasChanges] && ![context save:&error]) { 176 | if (failure) failure(error); 177 | } else { 178 | if (success) success(); 179 | } 180 | } 181 | 182 | #pragma mark - Undo Management 183 | - (void)undo { 184 | [self.managedObjectContext undo]; 185 | } 186 | 187 | - (void)redo { 188 | [self.managedObjectContext redo]; 189 | } 190 | 191 | - (void)rollback { 192 | [self.managedObjectContext rollback]; 193 | } 194 | 195 | - (void)reset { 196 | [self.managedObjectContext reset]; 197 | } 198 | 199 | @end 200 | -------------------------------------------------------------------------------- /RHParrotDataDemo/RHParrotDataDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4D25F88E1A6A97E900866345 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D25F88D1A6A97E900866345 /* main.m */; }; 11 | 4D25F8911A6A97E900866345 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D25F8901A6A97E900866345 /* AppDelegate.m */; }; 12 | 4D25F8941A6A97E900866345 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D25F8931A6A97E900866345 /* ViewController.m */; }; 13 | 4D25F8971A6A97E900866345 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4D25F8951A6A97E900866345 /* Main.storyboard */; }; 14 | 4D25F8991A6A97E900866345 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4D25F8981A6A97E900866345 /* Images.xcassets */; }; 15 | 4D25F89C1A6A97E900866345 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4D25F89A1A6A97E900866345 /* LaunchScreen.xib */; }; 16 | 4D25F8A81A6A97E900866345 /* RHParrotDataDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D25F8A71A6A97E900866345 /* RHParrotDataDemoTests.m */; }; 17 | 4D25F8B41A6A982B00866345 /* RHQuery.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D25F8B31A6A982B00866345 /* RHQuery.m */; }; 18 | 4D25F8B71A6A986400866345 /* RHDataAgent.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D25F8B61A6A986400866345 /* RHDataAgent.m */; }; 19 | 4D25F8BA1A6A987700866345 /* RHDataImporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D25F8B91A6A987700866345 /* RHDataImporter.m */; }; 20 | 4D865D161A6D3AFB005FA54C /* RHDatabaseManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D865D151A6D3AFB005FA54C /* RHDatabaseManager.m */; }; 21 | 4D90F6891A6E4B8900471EDE /* Model.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 4D90F6871A6E4B8900471EDE /* Model.xcdatamodeld */; }; 22 | 4D90F68C1A6E4C7F00471EDE /* Brand.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D90F68B1A6E4C7F00471EDE /* Brand.m */; }; 23 | 4D90F68F1A6E4C7F00471EDE /* Person.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D90F68E1A6E4C7F00471EDE /* Person.m */; }; 24 | 4DC8C5701A7287E900783898 /* RHQueryResultController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DC8C56F1A7287E900783898 /* RHQueryResultController.m */; }; 25 | /* End PBXBuildFile section */ 26 | 27 | /* Begin PBXContainerItemProxy section */ 28 | 4D25F8A21A6A97E900866345 /* PBXContainerItemProxy */ = { 29 | isa = PBXContainerItemProxy; 30 | containerPortal = 4D25F8801A6A97E900866345 /* Project object */; 31 | proxyType = 1; 32 | remoteGlobalIDString = 4D25F8871A6A97E900866345; 33 | remoteInfo = RHParrotDataDemo; 34 | }; 35 | /* End PBXContainerItemProxy section */ 36 | 37 | /* Begin PBXFileReference section */ 38 | 4D25F8881A6A97E900866345 /* RHParrotDataDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RHParrotDataDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 39 | 4D25F88C1A6A97E900866345 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 40 | 4D25F88D1A6A97E900866345 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 41 | 4D25F88F1A6A97E900866345 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 42 | 4D25F8901A6A97E900866345 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 43 | 4D25F8921A6A97E900866345 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 44 | 4D25F8931A6A97E900866345 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 45 | 4D25F8961A6A97E900866345 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 46 | 4D25F8981A6A97E900866345 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 47 | 4D25F89B1A6A97E900866345 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 48 | 4D25F8A11A6A97E900866345 /* RHParrotDataDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RHParrotDataDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | 4D25F8A61A6A97E900866345 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 50 | 4D25F8A71A6A97E900866345 /* RHParrotDataDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RHParrotDataDemoTests.m; sourceTree = ""; }; 51 | 4D25F8B21A6A982B00866345 /* RHQuery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RHQuery.h; sourceTree = ""; }; 52 | 4D25F8B31A6A982B00866345 /* RHQuery.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RHQuery.m; sourceTree = ""; }; 53 | 4D25F8B51A6A986400866345 /* RHDataAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RHDataAgent.h; sourceTree = ""; }; 54 | 4D25F8B61A6A986400866345 /* RHDataAgent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RHDataAgent.m; sourceTree = ""; }; 55 | 4D25F8B81A6A987700866345 /* RHDataImporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RHDataImporter.h; sourceTree = ""; }; 56 | 4D25F8B91A6A987700866345 /* RHDataImporter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RHDataImporter.m; sourceTree = ""; }; 57 | 4D25F8BF1A6AA65700866345 /* RHParrotMacro.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RHParrotMacro.h; sourceTree = ""; }; 58 | 4D6AB83E1A6D0C6100EC0174 /* RHParrotData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RHParrotData.h; sourceTree = ""; }; 59 | 4D865D141A6D3AFB005FA54C /* RHDatabaseManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RHDatabaseManager.h; sourceTree = ""; }; 60 | 4D865D151A6D3AFB005FA54C /* RHDatabaseManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RHDatabaseManager.m; sourceTree = ""; }; 61 | 4D90F6881A6E4B8900471EDE /* Model.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Model.xcdatamodel; sourceTree = ""; }; 62 | 4D90F68A1A6E4C7F00471EDE /* Brand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Brand.h; sourceTree = ""; }; 63 | 4D90F68B1A6E4C7F00471EDE /* Brand.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Brand.m; sourceTree = ""; }; 64 | 4D90F68D1A6E4C7F00471EDE /* Person.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Person.h; sourceTree = ""; }; 65 | 4D90F68E1A6E4C7F00471EDE /* Person.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Person.m; sourceTree = ""; }; 66 | 4DC8C56E1A7287E900783898 /* RHQueryResultController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RHQueryResultController.h; sourceTree = ""; }; 67 | 4DC8C56F1A7287E900783898 /* RHQueryResultController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RHQueryResultController.m; sourceTree = ""; }; 68 | /* End PBXFileReference section */ 69 | 70 | /* Begin PBXFrameworksBuildPhase section */ 71 | 4D25F8851A6A97E900866345 /* Frameworks */ = { 72 | isa = PBXFrameworksBuildPhase; 73 | buildActionMask = 2147483647; 74 | files = ( 75 | ); 76 | runOnlyForDeploymentPostprocessing = 0; 77 | }; 78 | 4D25F89E1A6A97E900866345 /* Frameworks */ = { 79 | isa = PBXFrameworksBuildPhase; 80 | buildActionMask = 2147483647; 81 | files = ( 82 | ); 83 | runOnlyForDeploymentPostprocessing = 0; 84 | }; 85 | /* End PBXFrameworksBuildPhase section */ 86 | 87 | /* Begin PBXGroup section */ 88 | 4D25F87F1A6A97E900866345 = { 89 | isa = PBXGroup; 90 | children = ( 91 | 4D25F88A1A6A97E900866345 /* RHParrotDataDemo */, 92 | 4D25F8A41A6A97E900866345 /* RHParrotDataDemoTests */, 93 | 4D25F8891A6A97E900866345 /* Products */, 94 | ); 95 | indentWidth = 2; 96 | sourceTree = ""; 97 | tabWidth = 2; 98 | }; 99 | 4D25F8891A6A97E900866345 /* Products */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | 4D25F8881A6A97E900866345 /* RHParrotDataDemo.app */, 103 | 4D25F8A11A6A97E900866345 /* RHParrotDataDemoTests.xctest */, 104 | ); 105 | name = Products; 106 | sourceTree = ""; 107 | }; 108 | 4D25F88A1A6A97E900866345 /* RHParrotDataDemo */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | 4D25F8B11A6A980300866345 /* RHParrotData */, 112 | 4D25F88F1A6A97E900866345 /* AppDelegate.h */, 113 | 4D25F8901A6A97E900866345 /* AppDelegate.m */, 114 | 4D25F8921A6A97E900866345 /* ViewController.h */, 115 | 4D25F8931A6A97E900866345 /* ViewController.m */, 116 | 4D90F68D1A6E4C7F00471EDE /* Person.h */, 117 | 4D90F68E1A6E4C7F00471EDE /* Person.m */, 118 | 4D90F68A1A6E4C7F00471EDE /* Brand.h */, 119 | 4D90F68B1A6E4C7F00471EDE /* Brand.m */, 120 | 4D90F6871A6E4B8900471EDE /* Model.xcdatamodeld */, 121 | 4D25F8951A6A97E900866345 /* Main.storyboard */, 122 | 4D25F8981A6A97E900866345 /* Images.xcassets */, 123 | 4D25F89A1A6A97E900866345 /* LaunchScreen.xib */, 124 | 4D25F88B1A6A97E900866345 /* Supporting Files */, 125 | ); 126 | path = RHParrotDataDemo; 127 | sourceTree = ""; 128 | }; 129 | 4D25F88B1A6A97E900866345 /* Supporting Files */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | 4D25F88C1A6A97E900866345 /* Info.plist */, 133 | 4D25F88D1A6A97E900866345 /* main.m */, 134 | ); 135 | name = "Supporting Files"; 136 | sourceTree = ""; 137 | }; 138 | 4D25F8A41A6A97E900866345 /* RHParrotDataDemoTests */ = { 139 | isa = PBXGroup; 140 | children = ( 141 | 4D25F8A71A6A97E900866345 /* RHParrotDataDemoTests.m */, 142 | 4D25F8A51A6A97E900866345 /* Supporting Files */, 143 | ); 144 | path = RHParrotDataDemoTests; 145 | sourceTree = ""; 146 | }; 147 | 4D25F8A51A6A97E900866345 /* Supporting Files */ = { 148 | isa = PBXGroup; 149 | children = ( 150 | 4D25F8A61A6A97E900866345 /* Info.plist */, 151 | ); 152 | name = "Supporting Files"; 153 | sourceTree = ""; 154 | }; 155 | 4D25F8B11A6A980300866345 /* RHParrotData */ = { 156 | isa = PBXGroup; 157 | children = ( 158 | 4D6AB83E1A6D0C6100EC0174 /* RHParrotData.h */, 159 | 4D25F8BF1A6AA65700866345 /* RHParrotMacro.h */, 160 | 4D25F8B21A6A982B00866345 /* RHQuery.h */, 161 | 4D25F8B31A6A982B00866345 /* RHQuery.m */, 162 | 4D25F8B51A6A986400866345 /* RHDataAgent.h */, 163 | 4D25F8B61A6A986400866345 /* RHDataAgent.m */, 164 | 4D25F8B81A6A987700866345 /* RHDataImporter.h */, 165 | 4D25F8B91A6A987700866345 /* RHDataImporter.m */, 166 | 4D865D141A6D3AFB005FA54C /* RHDatabaseManager.h */, 167 | 4D865D151A6D3AFB005FA54C /* RHDatabaseManager.m */, 168 | 4DC8C56E1A7287E900783898 /* RHQueryResultController.h */, 169 | 4DC8C56F1A7287E900783898 /* RHQueryResultController.m */, 170 | ); 171 | path = RHParrotData; 172 | sourceTree = ""; 173 | }; 174 | /* End PBXGroup section */ 175 | 176 | /* Begin PBXNativeTarget section */ 177 | 4D25F8871A6A97E900866345 /* RHParrotDataDemo */ = { 178 | isa = PBXNativeTarget; 179 | buildConfigurationList = 4D25F8AB1A6A97E900866345 /* Build configuration list for PBXNativeTarget "RHParrotDataDemo" */; 180 | buildPhases = ( 181 | 4D25F8841A6A97E900866345 /* Sources */, 182 | 4D25F8851A6A97E900866345 /* Frameworks */, 183 | 4D25F8861A6A97E900866345 /* Resources */, 184 | ); 185 | buildRules = ( 186 | ); 187 | dependencies = ( 188 | ); 189 | name = RHParrotDataDemo; 190 | productName = RHParrotDataDemo; 191 | productReference = 4D25F8881A6A97E900866345 /* RHParrotDataDemo.app */; 192 | productType = "com.apple.product-type.application"; 193 | }; 194 | 4D25F8A01A6A97E900866345 /* RHParrotDataDemoTests */ = { 195 | isa = PBXNativeTarget; 196 | buildConfigurationList = 4D25F8AE1A6A97E900866345 /* Build configuration list for PBXNativeTarget "RHParrotDataDemoTests" */; 197 | buildPhases = ( 198 | 4D25F89D1A6A97E900866345 /* Sources */, 199 | 4D25F89E1A6A97E900866345 /* Frameworks */, 200 | 4D25F89F1A6A97E900866345 /* Resources */, 201 | ); 202 | buildRules = ( 203 | ); 204 | dependencies = ( 205 | 4D25F8A31A6A97E900866345 /* PBXTargetDependency */, 206 | ); 207 | name = RHParrotDataDemoTests; 208 | productName = RHParrotDataDemoTests; 209 | productReference = 4D25F8A11A6A97E900866345 /* RHParrotDataDemoTests.xctest */; 210 | productType = "com.apple.product-type.bundle.unit-test"; 211 | }; 212 | /* End PBXNativeTarget section */ 213 | 214 | /* Begin PBXProject section */ 215 | 4D25F8801A6A97E900866345 /* Project object */ = { 216 | isa = PBXProject; 217 | attributes = { 218 | LastUpgradeCheck = 0610; 219 | ORGANIZATIONNAME = ran; 220 | TargetAttributes = { 221 | 4D25F8871A6A97E900866345 = { 222 | CreatedOnToolsVersion = 6.1.1; 223 | }; 224 | 4D25F8A01A6A97E900866345 = { 225 | CreatedOnToolsVersion = 6.1.1; 226 | TestTargetID = 4D25F8871A6A97E900866345; 227 | }; 228 | }; 229 | }; 230 | buildConfigurationList = 4D25F8831A6A97E900866345 /* Build configuration list for PBXProject "RHParrotDataDemo" */; 231 | compatibilityVersion = "Xcode 3.2"; 232 | developmentRegion = English; 233 | hasScannedForEncodings = 0; 234 | knownRegions = ( 235 | en, 236 | Base, 237 | ); 238 | mainGroup = 4D25F87F1A6A97E900866345; 239 | productRefGroup = 4D25F8891A6A97E900866345 /* Products */; 240 | projectDirPath = ""; 241 | projectRoot = ""; 242 | targets = ( 243 | 4D25F8871A6A97E900866345 /* RHParrotDataDemo */, 244 | 4D25F8A01A6A97E900866345 /* RHParrotDataDemoTests */, 245 | ); 246 | }; 247 | /* End PBXProject section */ 248 | 249 | /* Begin PBXResourcesBuildPhase section */ 250 | 4D25F8861A6A97E900866345 /* Resources */ = { 251 | isa = PBXResourcesBuildPhase; 252 | buildActionMask = 2147483647; 253 | files = ( 254 | 4D25F8971A6A97E900866345 /* Main.storyboard in Resources */, 255 | 4D25F89C1A6A97E900866345 /* LaunchScreen.xib in Resources */, 256 | 4D25F8991A6A97E900866345 /* Images.xcassets in Resources */, 257 | ); 258 | runOnlyForDeploymentPostprocessing = 0; 259 | }; 260 | 4D25F89F1A6A97E900866345 /* Resources */ = { 261 | isa = PBXResourcesBuildPhase; 262 | buildActionMask = 2147483647; 263 | files = ( 264 | ); 265 | runOnlyForDeploymentPostprocessing = 0; 266 | }; 267 | /* End PBXResourcesBuildPhase section */ 268 | 269 | /* Begin PBXSourcesBuildPhase section */ 270 | 4D25F8841A6A97E900866345 /* Sources */ = { 271 | isa = PBXSourcesBuildPhase; 272 | buildActionMask = 2147483647; 273 | files = ( 274 | 4D90F68C1A6E4C7F00471EDE /* Brand.m in Sources */, 275 | 4D25F8B41A6A982B00866345 /* RHQuery.m in Sources */, 276 | 4D90F68F1A6E4C7F00471EDE /* Person.m in Sources */, 277 | 4D25F8941A6A97E900866345 /* ViewController.m in Sources */, 278 | 4DC8C5701A7287E900783898 /* RHQueryResultController.m in Sources */, 279 | 4D25F8911A6A97E900866345 /* AppDelegate.m in Sources */, 280 | 4D90F6891A6E4B8900471EDE /* Model.xcdatamodeld in Sources */, 281 | 4D25F8BA1A6A987700866345 /* RHDataImporter.m in Sources */, 282 | 4D25F8B71A6A986400866345 /* RHDataAgent.m in Sources */, 283 | 4D865D161A6D3AFB005FA54C /* RHDatabaseManager.m in Sources */, 284 | 4D25F88E1A6A97E900866345 /* main.m in Sources */, 285 | ); 286 | runOnlyForDeploymentPostprocessing = 0; 287 | }; 288 | 4D25F89D1A6A97E900866345 /* Sources */ = { 289 | isa = PBXSourcesBuildPhase; 290 | buildActionMask = 2147483647; 291 | files = ( 292 | 4D25F8A81A6A97E900866345 /* RHParrotDataDemoTests.m in Sources */, 293 | ); 294 | runOnlyForDeploymentPostprocessing = 0; 295 | }; 296 | /* End PBXSourcesBuildPhase section */ 297 | 298 | /* Begin PBXTargetDependency section */ 299 | 4D25F8A31A6A97E900866345 /* PBXTargetDependency */ = { 300 | isa = PBXTargetDependency; 301 | target = 4D25F8871A6A97E900866345 /* RHParrotDataDemo */; 302 | targetProxy = 4D25F8A21A6A97E900866345 /* PBXContainerItemProxy */; 303 | }; 304 | /* End PBXTargetDependency section */ 305 | 306 | /* Begin PBXVariantGroup section */ 307 | 4D25F8951A6A97E900866345 /* Main.storyboard */ = { 308 | isa = PBXVariantGroup; 309 | children = ( 310 | 4D25F8961A6A97E900866345 /* Base */, 311 | ); 312 | name = Main.storyboard; 313 | sourceTree = ""; 314 | }; 315 | 4D25F89A1A6A97E900866345 /* LaunchScreen.xib */ = { 316 | isa = PBXVariantGroup; 317 | children = ( 318 | 4D25F89B1A6A97E900866345 /* Base */, 319 | ); 320 | name = LaunchScreen.xib; 321 | sourceTree = ""; 322 | }; 323 | /* End PBXVariantGroup section */ 324 | 325 | /* Begin XCBuildConfiguration section */ 326 | 4D25F8A91A6A97E900866345 /* Debug */ = { 327 | isa = XCBuildConfiguration; 328 | buildSettings = { 329 | ALWAYS_SEARCH_USER_PATHS = NO; 330 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 331 | CLANG_CXX_LIBRARY = "libc++"; 332 | CLANG_ENABLE_MODULES = YES; 333 | CLANG_ENABLE_OBJC_ARC = YES; 334 | CLANG_WARN_BOOL_CONVERSION = YES; 335 | CLANG_WARN_CONSTANT_CONVERSION = YES; 336 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 337 | CLANG_WARN_EMPTY_BODY = YES; 338 | CLANG_WARN_ENUM_CONVERSION = YES; 339 | CLANG_WARN_INT_CONVERSION = YES; 340 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 341 | CLANG_WARN_UNREACHABLE_CODE = YES; 342 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 343 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 344 | COPY_PHASE_STRIP = NO; 345 | ENABLE_STRICT_OBJC_MSGSEND = YES; 346 | GCC_C_LANGUAGE_STANDARD = gnu99; 347 | GCC_DYNAMIC_NO_PIC = NO; 348 | GCC_OPTIMIZATION_LEVEL = 0; 349 | GCC_PREPROCESSOR_DEFINITIONS = ( 350 | "DEBUG=1", 351 | "$(inherited)", 352 | ); 353 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 354 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 355 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 356 | GCC_WARN_UNDECLARED_SELECTOR = YES; 357 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 358 | GCC_WARN_UNUSED_FUNCTION = YES; 359 | GCC_WARN_UNUSED_VARIABLE = YES; 360 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 361 | MTL_ENABLE_DEBUG_INFO = YES; 362 | ONLY_ACTIVE_ARCH = YES; 363 | SDKROOT = iphoneos; 364 | }; 365 | name = Debug; 366 | }; 367 | 4D25F8AA1A6A97E900866345 /* Release */ = { 368 | isa = XCBuildConfiguration; 369 | buildSettings = { 370 | ALWAYS_SEARCH_USER_PATHS = NO; 371 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 372 | CLANG_CXX_LIBRARY = "libc++"; 373 | CLANG_ENABLE_MODULES = YES; 374 | CLANG_ENABLE_OBJC_ARC = YES; 375 | CLANG_WARN_BOOL_CONVERSION = YES; 376 | CLANG_WARN_CONSTANT_CONVERSION = YES; 377 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 378 | CLANG_WARN_EMPTY_BODY = YES; 379 | CLANG_WARN_ENUM_CONVERSION = YES; 380 | CLANG_WARN_INT_CONVERSION = YES; 381 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 382 | CLANG_WARN_UNREACHABLE_CODE = YES; 383 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 384 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 385 | COPY_PHASE_STRIP = YES; 386 | ENABLE_NS_ASSERTIONS = NO; 387 | ENABLE_STRICT_OBJC_MSGSEND = YES; 388 | GCC_C_LANGUAGE_STANDARD = gnu99; 389 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 390 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 391 | GCC_WARN_UNDECLARED_SELECTOR = YES; 392 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 393 | GCC_WARN_UNUSED_FUNCTION = YES; 394 | GCC_WARN_UNUSED_VARIABLE = YES; 395 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 396 | MTL_ENABLE_DEBUG_INFO = NO; 397 | SDKROOT = iphoneos; 398 | VALIDATE_PRODUCT = YES; 399 | }; 400 | name = Release; 401 | }; 402 | 4D25F8AC1A6A97E900866345 /* Debug */ = { 403 | isa = XCBuildConfiguration; 404 | buildSettings = { 405 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 406 | INFOPLIST_FILE = RHParrotDataDemo/Info.plist; 407 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 408 | PRODUCT_NAME = "$(TARGET_NAME)"; 409 | }; 410 | name = Debug; 411 | }; 412 | 4D25F8AD1A6A97E900866345 /* Release */ = { 413 | isa = XCBuildConfiguration; 414 | buildSettings = { 415 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 416 | INFOPLIST_FILE = RHParrotDataDemo/Info.plist; 417 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 418 | PRODUCT_NAME = "$(TARGET_NAME)"; 419 | }; 420 | name = Release; 421 | }; 422 | 4D25F8AF1A6A97E900866345 /* Debug */ = { 423 | isa = XCBuildConfiguration; 424 | buildSettings = { 425 | BUNDLE_LOADER = "$(TEST_HOST)"; 426 | FRAMEWORK_SEARCH_PATHS = ( 427 | "$(SDKROOT)/Developer/Library/Frameworks", 428 | "$(inherited)", 429 | ); 430 | GCC_PREPROCESSOR_DEFINITIONS = ( 431 | "DEBUG=1", 432 | "$(inherited)", 433 | ); 434 | INFOPLIST_FILE = RHParrotDataDemoTests/Info.plist; 435 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 436 | PRODUCT_NAME = "$(TARGET_NAME)"; 437 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/RHParrotDataDemo.app/RHParrotDataDemo"; 438 | }; 439 | name = Debug; 440 | }; 441 | 4D25F8B01A6A97E900866345 /* Release */ = { 442 | isa = XCBuildConfiguration; 443 | buildSettings = { 444 | BUNDLE_LOADER = "$(TEST_HOST)"; 445 | FRAMEWORK_SEARCH_PATHS = ( 446 | "$(SDKROOT)/Developer/Library/Frameworks", 447 | "$(inherited)", 448 | ); 449 | INFOPLIST_FILE = RHParrotDataDemoTests/Info.plist; 450 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 451 | PRODUCT_NAME = "$(TARGET_NAME)"; 452 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/RHParrotDataDemo.app/RHParrotDataDemo"; 453 | }; 454 | name = Release; 455 | }; 456 | /* End XCBuildConfiguration section */ 457 | 458 | /* Begin XCConfigurationList section */ 459 | 4D25F8831A6A97E900866345 /* Build configuration list for PBXProject "RHParrotDataDemo" */ = { 460 | isa = XCConfigurationList; 461 | buildConfigurations = ( 462 | 4D25F8A91A6A97E900866345 /* Debug */, 463 | 4D25F8AA1A6A97E900866345 /* Release */, 464 | ); 465 | defaultConfigurationIsVisible = 0; 466 | defaultConfigurationName = Release; 467 | }; 468 | 4D25F8AB1A6A97E900866345 /* Build configuration list for PBXNativeTarget "RHParrotDataDemo" */ = { 469 | isa = XCConfigurationList; 470 | buildConfigurations = ( 471 | 4D25F8AC1A6A97E900866345 /* Debug */, 472 | 4D25F8AD1A6A97E900866345 /* Release */, 473 | ); 474 | defaultConfigurationIsVisible = 0; 475 | defaultConfigurationName = Release; 476 | }; 477 | 4D25F8AE1A6A97E900866345 /* Build configuration list for PBXNativeTarget "RHParrotDataDemoTests" */ = { 478 | isa = XCConfigurationList; 479 | buildConfigurations = ( 480 | 4D25F8AF1A6A97E900866345 /* Debug */, 481 | 4D25F8B01A6A97E900866345 /* Release */, 482 | ); 483 | defaultConfigurationIsVisible = 0; 484 | defaultConfigurationName = Release; 485 | }; 486 | /* End XCConfigurationList section */ 487 | 488 | /* Begin XCVersionGroup section */ 489 | 4D90F6871A6E4B8900471EDE /* Model.xcdatamodeld */ = { 490 | isa = XCVersionGroup; 491 | children = ( 492 | 4D90F6881A6E4B8900471EDE /* Model.xcdatamodel */, 493 | ); 494 | currentVersion = 4D90F6881A6E4B8900471EDE /* Model.xcdatamodel */; 495 | path = Model.xcdatamodeld; 496 | sourceTree = ""; 497 | versionGroupType = wrapper.xcdatamodel; 498 | }; 499 | /* End XCVersionGroup section */ 500 | }; 501 | rootObject = 4D25F8801A6A97E900866345 /* Project object */; 502 | } 503 | --------------------------------------------------------------------------------