├── 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 | [](http://cocoadocs.org/docsets/RHParrotData)
4 | [](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 |
--------------------------------------------------------------------------------