├── sources
├── 687474703a2f2f696.jpg
└── JYDataBase.podspec
├── JYDatabase - OC
├── JYDatabase - OC
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── www.imageset
│ │ │ ├── pano_sphere2.png
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── DataSoure
│ │ ├── Content
│ │ │ ├── JYClassInfo.m
│ │ │ ├── JYGradeInfo.m
│ │ │ ├── JYPersonInfo.m
│ │ │ ├── JYGradeInfo.h
│ │ │ ├── JYClassInfo.h
│ │ │ └── JYPersonInfo.h
│ │ ├── Storage
│ │ │ ├── JYClassTable.h
│ │ │ ├── JYGradeTable.h
│ │ │ ├── JYPersonTable.h
│ │ │ ├── JYPersonDB.h
│ │ │ ├── JYPersonTable.m
│ │ │ ├── JYGradeTable.m
│ │ │ ├── JYClassTable.m
│ │ │ └── JYPersonDB.m
│ │ └── Service
│ │ │ ├── JYDBService.h
│ │ │ └── JYDBService.m
│ ├── ViewController.h
│ ├── JYDatabase
│ │ ├── fmdb
│ │ │ ├── FMDB.h
│ │ │ ├── FMDatabasePool.h
│ │ │ ├── FMDatabaseQueue.h
│ │ │ ├── FMDatabaseQueue.m
│ │ │ ├── FMDatabaseAdditions.m
│ │ │ ├── FMDatabaseAdditions.h
│ │ │ ├── FMDatabasePool.m
│ │ │ ├── FMResultSet.m
│ │ │ └── FMResultSet.h
│ │ ├── NSObject+JYContentTableClass.h
│ │ ├── NSObject+JYContentTableClass.m
│ │ ├── JYDataBaseConfig.h
│ │ ├── JYQueryConditions.h
│ │ ├── JYDataBase.h
│ │ ├── JYDataBaseConfig.m
│ │ ├── JYContentTable.h
│ │ ├── JYDataBase.m
│ │ └── JYQueryConditions.m
│ ├── AppDelegate.h
│ ├── main.m
│ ├── ViewController.m
│ ├── Info.plist
│ ├── Base.lproj
│ │ ├── Main.storyboard
│ │ └── LaunchScreen.storyboard
│ ├── AppDelegate.m
│ └── ViewController.mm
├── JYDatabase - OC.xcodeproj
│ └── project.xcworkspace
│ │ └── contents.xcworkspacedata
├── JYDatabase - OCTests
│ ├── Info.plist
│ └── JYContentTableTest.m
└── JYDatabase - OCUITests
│ ├── Info.plist
│ └── JYDatabase___OCUITests.m
├── JYGenerationCode
├── JYGenerationCode.xcodeproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── project.pbxproj
├── JYGenerationCode
│ ├── ViewController.h
│ ├── main.m
│ ├── AppDelegate.h
│ ├── AppDelegate.m
│ ├── Assets.xcassets
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── Info.plist
│ ├── ViewController.m
│ └── code.bundle
│ │ └── code1.text
├── JYGenerationCodeTests
│ ├── Info.plist
│ └── JYGenerationCodeTests.m
└── JYGenerationCodeUITests
│ ├── Info.plist
│ └── JYGenerationCodeUITests.m
├── .gitignore
├── README.md
└── LICENSE
/sources/687474703a2f2f696.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weijingyunIOS/JYDatabase/HEAD/sources/687474703a2f2f696.jpg
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/Assets.xcassets/www.imageset/pano_sphere2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weijingyunIOS/JYDatabase/HEAD/JYDatabase - OC/JYDatabase - OC/Assets.xcassets/www.imageset/pano_sphere2.png
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/JYGenerationCode/JYGenerationCode.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/DataSoure/Content/JYClassInfo.m:
--------------------------------------------------------------------------------
1 | //
2 | // JYClassInfo.m
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/11/21.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import "JYClassInfo.h"
10 |
11 | @implementation JYClassInfo
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/DataSoure/Content/JYGradeInfo.m:
--------------------------------------------------------------------------------
1 | //
2 | // JYGradeInfo.m
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/11/21.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import "JYGradeInfo.h"
10 |
11 | @implementation JYGradeInfo
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/DataSoure/Content/JYPersonInfo.m:
--------------------------------------------------------------------------------
1 | //
2 | // JYPersonInfo.m
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/5/9.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import "JYPersonInfo.h"
10 |
11 | @implementation JYPersonInfo
12 |
13 |
14 | @end
15 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/DataSoure/Storage/JYClassTable.h:
--------------------------------------------------------------------------------
1 | //
2 | // JYClassTable.h
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/11/21.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import "JYContentTable.h"
10 |
11 | @interface JYClassTable : JYContentTable
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/DataSoure/Storage/JYGradeTable.h:
--------------------------------------------------------------------------------
1 | //
2 | // JYGradeTable.h
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/11/21.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import "JYContentTable.h"
10 |
11 | @interface JYGradeTable : JYContentTable
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/5/9.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/JYGenerationCode/JYGenerationCode/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // JYGenerationCode
4 | //
5 | // Created by weijingyun on 16/5/15.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : NSViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/JYGenerationCode/JYGenerationCode/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // JYGenerationCode
4 | //
5 | // Created by weijingyun on 16/5/15.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | int main(int argc, const char * argv[]) {
12 | return NSApplicationMain(argc, argv);
13 | }
14 |
--------------------------------------------------------------------------------
/JYGenerationCode/JYGenerationCode/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // JYGenerationCode
4 | //
5 | // Created by weijingyun on 16/5/15.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : NSObject
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/JYDatabase/fmdb/FMDB.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | FOUNDATION_EXPORT double FMDBVersionNumber;
4 | FOUNDATION_EXPORT const unsigned char FMDBVersionString[];
5 |
6 | #import "FMDatabase.h"
7 | #import "FMResultSet.h"
8 | #import "FMDatabaseAdditions.h"
9 | #import "FMDatabaseQueue.h"
10 | #import "FMDatabasePool.h"
11 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/DataSoure/Storage/JYPersonTable.h:
--------------------------------------------------------------------------------
1 | //
2 | // JYPersonTable.h
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/5/9.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import "JYContentTable.h"
10 | #import "JYPersonInfo.h"
11 |
12 | @interface JYPersonTable : JYContentTable
13 |
14 | @end
15 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/5/9.
6 | // Copyright © 2016年 weijingyun. 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 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/5/9.
6 | // Copyright © 2016年 weijingyun. 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 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/JYDatabase/NSObject+JYContentTableClass.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+JYContentTableClass.h
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/10/14.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSObject (JYContentTableClass)
12 |
13 | // 最后插入时间
14 | @property (nonatomic, assign) NSTimeInterval lastInsertTime;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/Assets.xcassets/www.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "pano_sphere2.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/5/9.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 | #import "JYDBService.h"
11 |
12 | @interface ViewController ()
13 |
14 |
15 | @end
16 |
17 | @implementation ViewController
18 |
19 | - (void)viewDidLoad{
20 | [super viewDidLoad];
21 | [[JYDBService shared] deleteAllGradeInfo];
22 | NSLog(@"可跑JYContentTableTest测试用例");
23 | }
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/JYGenerationCode/JYGenerationCode/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // JYGenerationCode
4 | //
5 | // Created by weijingyun on 16/5/15.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 |
11 | @interface AppDelegate ()
12 |
13 | @end
14 |
15 | @implementation AppDelegate
16 |
17 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
18 | // Insert code here to initialize your application
19 | }
20 |
21 | - (void)applicationWillTerminate:(NSNotification *)aNotification {
22 | // Insert code here to tear down your application
23 | }
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/DataSoure/Content/JYGradeInfo.h:
--------------------------------------------------------------------------------
1 | //
2 | // JYGradeInfo.h
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/11/21.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "JYClassInfo.h"
11 |
12 | @interface JYGradeInfo : NSObject
13 |
14 | // 年级编号
15 | @property (nonatomic, copy) NSString *gradeID;
16 |
17 | // 年级名称
18 | @property (nonatomic, copy) NSString *gradeName;
19 |
20 | // 超长描述
21 | @property (nonatomic, copy) NSString *longlongText;
22 |
23 | // 年级下的所有班级
24 | @property (nonatomic, strong) NSArray *allClass;
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/DataSoure/Storage/JYPersonDB.h:
--------------------------------------------------------------------------------
1 | //
2 | // JYPersonDB.h
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/5/9.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import "JYDataBase.h"
10 |
11 | @class JYGradeTable,JYPersonTable,JYClassTable;
12 |
13 | @interface JYPersonDB : JYDataBase
14 |
15 | @property (nonatomic, strong, readonly) NSString *documentDirectory ;
16 | @property (nonatomic, strong, readonly) JYGradeTable *gradeTable;
17 | @property (nonatomic, strong, readonly) JYClassTable *classTable;
18 | @property (nonatomic, strong, readonly) JYPersonTable *personTable;
19 |
20 | + (instancetype)storage;
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/DataSoure/Content/JYClassInfo.h:
--------------------------------------------------------------------------------
1 | //
2 | // JYClassInfo.h
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/11/21.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "JYPersonInfo.h"
11 |
12 | @interface JYClassInfo : NSObject
13 |
14 | // 年级ID
15 | @property (nonatomic, copy) NSString *classID;
16 |
17 | // 班级所属的年级表
18 | @property (nonatomic, copy) NSString *gradeID;
19 |
20 | // 班级名
21 | @property (nonatomic, copy) NSString *className;
22 |
23 | // 一个老师
24 | @property (nonatomic, strong) JYPersonInfo *teacher;
25 |
26 | // 一群学生
27 | @property (nonatomic, strong) NSMutableArray *students;
28 |
29 | @end
30 |
--------------------------------------------------------------------------------
/sources/JYDataBase.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 |
3 | s.name = "JYDataBase"
4 | s.version = "1.0.6"
5 | s.summary = "对FMDB的轻量级封装,帮助快速创建管理移动端数据库."
6 |
7 | s.homepage = "https://github.com/weijingyunIOS/JYDatabase"
8 |
9 | s.license = "MIT"
10 |
11 | s.author = { "魏景云" => "wei_jingyun@outlook.com" }
12 | s.platform = :ios
13 | s.ios.deployment_target = "7.0"
14 | s.source = { :git => "https://github.com/weijingyunIOS/JYDatabase.git",:branch => "master", :tag => "1.0.6" }
15 | s.requires_arc = true
16 | s.source_files = "JYDatabase - OC/JYDatabase - OC/JYDatabase/*.{h,m}"
17 | s.public_header_files = "JYDatabase - OC/JYDatabase - OC/JYDatabase/*.h"
18 |
19 | s.framework = "UIKit","Foundation"
20 |
21 | s.dependency 'FMDB', '~> 2.6.2'
22 |
23 | end
24 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/JYDatabase/NSObject+JYContentTableClass.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+JYContentTableClass.m
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/10/14.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import "NSObject+JYContentTableClass.h"
10 | #import
11 |
12 | static char kJy_LastInsertTime;
13 |
14 | @implementation NSObject (JYContentTableClass)
15 |
16 | - (NSTimeInterval)lastInsertTime{
17 | NSNumber* number = objc_getAssociatedObject(self, &kJy_LastInsertTime);
18 | return [number longLongValue];
19 | }
20 |
21 | - (void)setLastInsertTime:(NSTimeInterval)lastInsertTime{
22 | objc_setAssociatedObject(self,&kJy_LastInsertTime,[NSNumber numberWithUnsignedLong:lastInsertTime],OBJC_ASSOCIATION_RETAIN);
23 | }
24 |
25 |
26 |
27 | @end
28 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OCTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OCUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/JYGenerationCode/JYGenerationCodeTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/JYGenerationCode/JYGenerationCodeUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/DataSoure/Storage/JYPersonTable.m:
--------------------------------------------------------------------------------
1 | //
2 | // JYPersonTable.m
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/5/9.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import "JYPersonTable.h"
10 |
11 | @implementation JYPersonTable
12 |
13 | - (void)configTableName{
14 |
15 | self.contentClass = [JYPersonInfo class];
16 | self.tableName = @"JYPersonTable";
17 | }
18 |
19 | - (NSString *)contentId{
20 | return @"personID";
21 | }
22 |
23 | - (NSArray *)getContentField{
24 | return @[@"mutableString1",@"array",@"arrayM",@"dic",@"dicM",@"integer1",
25 | @"uInteger1",@"int1",@"bool1",@"double1",@"float1",@"cgfloat1",
26 | @"data",@"number",
27 | @"teacherClassID",@"studentClassID",@"studentIdx"];
28 | }
29 |
30 | // 为 studentClassID teacherClassID 加上索引
31 | - (void)addOtherOperationForTable:(FMDatabase *)aDB{
32 | [self addDB:aDB uniques:@[@"teacherClassID",@"studentClassID",@"studentIdx"]];
33 | }
34 |
35 | @end
36 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/JYDatabase/JYDataBaseConfig.h:
--------------------------------------------------------------------------------
1 | //
2 | // JYDataBaseConfig.h
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/10/17.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import
10 | /*
11 | 虽然索引的目的在于提高数据库的性能,但这里有几个情况需要避免使用索引。使用索引时,应重新考虑下列准则:
12 | 索引不应该使用在较小的表上。
13 | 索引不应该使用在有频繁的大批量的更新或插入操作的表上。
14 | 索引不应该使用在含有大量的 NULL 值的列上。
15 | 索引不应该使用在频繁操作的列上。
16 | */
17 | typedef NS_ENUM(NSInteger, EJYDataBaseIndex) { //索引类型
18 | EJYDataBaseIndexNonclustered, // 非唯一索引
19 | EJYDataBaseIndexOnlyIndex, // 唯一索引
20 | EJYDataBaseIndexCompositeIndex // 组合索引
21 | };
22 |
23 |
24 | @interface JYDataBaseConfig : NSObject
25 |
26 | + (instancetype)shared;
27 |
28 | // 额外的映射字段 jy_correspondingDic 可能无法全面覆盖,当遇到崩溃时可设置该属性添加映射
29 | @property (nonatomic, strong) NSDictionary *corresponding;
30 |
31 |
32 | #pragma mark - 静态方法
33 | extern NSDictionary * jy_correspondingDic();
34 | extern NSDictionary * jy_defaultDic();
35 |
36 | @end
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/JYGenerationCode/JYGenerationCodeTests/JYGenerationCodeTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // JYGenerationCodeTests.m
3 | // JYGenerationCodeTests
4 | //
5 | // Created by weijingyun on 16/5/15.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface JYGenerationCodeTests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation JYGenerationCodeTests
16 |
17 | - (void)setUp {
18 | [super setUp];
19 | // Put setup code here. This method is called before the invocation of each test method in the class.
20 | }
21 |
22 | - (void)tearDown {
23 | // Put teardown code here. This method is called after the invocation of each test method in the class.
24 | [super tearDown];
25 | }
26 |
27 | - (void)testExample {
28 | // This is an example of a functional test case.
29 | // Use XCTAssert and related functions to verify your tests produce the correct results.
30 | }
31 |
32 | - (void)testPerformanceExample {
33 | // This is an example of a performance test case.
34 | [self measureBlock:^{
35 | // Put the code you want to measure the time of here.
36 | }];
37 | }
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/JYGenerationCode/JYGenerationCode/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "mac",
5 | "size" : "16x16",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "mac",
10 | "size" : "16x16",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "mac",
15 | "size" : "32x32",
16 | "scale" : "1x"
17 | },
18 | {
19 | "idiom" : "mac",
20 | "size" : "32x32",
21 | "scale" : "2x"
22 | },
23 | {
24 | "idiom" : "mac",
25 | "size" : "128x128",
26 | "scale" : "1x"
27 | },
28 | {
29 | "idiom" : "mac",
30 | "size" : "128x128",
31 | "scale" : "2x"
32 | },
33 | {
34 | "idiom" : "mac",
35 | "size" : "256x256",
36 | "scale" : "1x"
37 | },
38 | {
39 | "idiom" : "mac",
40 | "size" : "256x256",
41 | "scale" : "2x"
42 | },
43 | {
44 | "idiom" : "mac",
45 | "size" : "512x512",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "mac",
50 | "size" : "512x512",
51 | "scale" : "2x"
52 | }
53 | ],
54 | "info" : {
55 | "version" : 1,
56 | "author" : "xcode"
57 | }
58 | }
--------------------------------------------------------------------------------
/JYGenerationCode/JYGenerationCode/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1
25 | LSMinimumSystemVersion
26 | $(MACOSX_DEPLOYMENT_TARGET)
27 | NSHumanReadableCopyright
28 | Copyright © 2016年 weijingyun. All rights reserved.
29 | NSMainStoryboardFile
30 | Main
31 | NSPrincipalClass
32 | NSApplication
33 |
34 |
35 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata
19 |
20 | ## Other
21 | *.xccheckout
22 | *.moved-aside
23 | *.xcuserstate
24 | *.xcscmblueprint
25 |
26 | ## Obj-C/Swift specific
27 | *.hmap
28 | *.ipa
29 |
30 | # CocoaPods
31 | #
32 | # We recommend against adding the Pods directory to your .gitignore. However
33 | # you should judge for yourself, the pros and cons are mentioned at:
34 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
35 | #
36 | # Pods/
37 |
38 | # Carthage
39 | #
40 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
41 | # Carthage/Checkouts
42 |
43 | Carthage/Build
44 |
45 | # fastlane
46 | #
47 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
48 | # screenshots whenever they are needed.
49 | # For more information about the recommended setup visit:
50 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md
51 |
52 | fastlane/report.xml
53 | fastlane/screenshots
54 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/JYDatabase/JYQueryConditions.h:
--------------------------------------------------------------------------------
1 | //
2 | // JYQueryConditions.h
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/5/13.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #define kField @"kField"
12 |
13 | @interface JYQueryConditions : NSObject
14 |
15 | @property (nonatomic, strong, readonly) NSMutableArray *conditions;
16 | @property (nonatomic, copy, readonly) NSMutableString *orderStr;
17 | @property (nonatomic, copy) NSMutableString *conditionStr;
18 |
19 | //以该字段结尾,表示 条件是 或 如 userId = 1 或 userId = 2, 否则就是 AND
20 | - (JYQueryConditions * (^)())OR;
21 |
22 | - (JYQueryConditions * (^)(NSString *compare))notEqualTo;
23 | - (JYQueryConditions * (^)(NSString *compare))equalTo;
24 | - (JYQueryConditions * (^)(NSString *compare))greaterThanOrEqualTo;
25 | - (JYQueryConditions * (^)(NSString *compare))lessThanOrEqualTo;
26 | - (JYQueryConditions * (^)(NSString *compare))greaterTo;
27 | - (JYQueryConditions * (^)(NSString *compare))lessTo;
28 |
29 | - (JYQueryConditions * (^)(NSString *field))field;
30 | - (JYQueryConditions * (^)(NSString *field))asc; // 升序
31 | - (JYQueryConditions * (^)(NSString *field))desc; // 降序
32 |
33 | //以该字段结尾,表示 条件是 或 如 userId = 1 或 userId = 2, 否则就是 AND 与sqlStr 配对
34 | - (JYQueryConditions * (^)())sqlOR;
35 | - (JYQueryConditions * (^)(NSString *str))sqlStr;
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OCUITests/JYDatabase___OCUITests.m:
--------------------------------------------------------------------------------
1 | //
2 | // JYDatabase___OCUITests.m
3 | // JYDatabase - OCUITests
4 | //
5 | // Created by weijingyun on 16/5/9.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface JYDatabase___OCUITests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation JYDatabase___OCUITests
16 |
17 | - (void)setUp {
18 | [super setUp];
19 |
20 | // Put setup code here. This method is called before the invocation of each test method in the class.
21 |
22 | // In UI tests it is usually best to stop immediately when a failure occurs.
23 | self.continueAfterFailure = NO;
24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
25 | [[[XCUIApplication alloc] init] launch];
26 |
27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
28 | }
29 |
30 | - (void)tearDown {
31 | // Put teardown code here. This method is called after the invocation of each test method in the class.
32 | [super tearDown];
33 | }
34 |
35 | - (void)testExample {
36 | // Use recording to get started writing UI tests.
37 | // Use XCTAssert and related functions to verify your tests produce the correct results.
38 | }
39 |
40 | @end
41 |
--------------------------------------------------------------------------------
/JYGenerationCode/JYGenerationCodeUITests/JYGenerationCodeUITests.m:
--------------------------------------------------------------------------------
1 | //
2 | // JYGenerationCodeUITests.m
3 | // JYGenerationCodeUITests
4 | //
5 | // Created by weijingyun on 16/5/15.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface JYGenerationCodeUITests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation JYGenerationCodeUITests
16 |
17 | - (void)setUp {
18 | [super setUp];
19 |
20 | // Put setup code here. This method is called before the invocation of each test method in the class.
21 |
22 | // In UI tests it is usually best to stop immediately when a failure occurs.
23 | self.continueAfterFailure = NO;
24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
25 | [[[XCUIApplication alloc] init] launch];
26 |
27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
28 | }
29 |
30 | - (void)tearDown {
31 | // Put teardown code here. This method is called after the invocation of each test method in the class.
32 | [super tearDown];
33 | }
34 |
35 | - (void)testExample {
36 | // Use recording to get started writing UI tests.
37 | // Use XCTAssert and related functions to verify your tests produce the correct results.
38 | }
39 |
40 | @end
41 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/DataSoure/Storage/JYGradeTable.m:
--------------------------------------------------------------------------------
1 | //
2 | // JYGradeTable.m
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/11/21.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import "JYGradeTable.h"
10 | #import "JYGradeInfo.h"
11 | #import "JYClassTable.h"
12 | #import "JYDBService.h"
13 | #import "JYPersonDB.h"
14 |
15 | @implementation JYGradeTable
16 |
17 | - (void)configTableName{
18 |
19 | self.contentClass = [JYGradeInfo class];
20 | self.tableName = @"JYGradeTable";
21 | }
22 |
23 | - (NSString *)contentId{
24 | return @"gradeID";
25 | }
26 |
27 | - (NSArray *)getContentField{
28 | return @[@"gradeName",@"longlongText"];
29 | }
30 |
31 | // 设置关联的表
32 | - (NSDictionary *)associativeTableField{
33 |
34 | JYClassTable *table = [JYDBService shared].personDB.classTable;
35 | return @{
36 | @"allClass" : @{
37 | tableContentObject : table,
38 | tableViceKey : @"gradeID"
39 | }
40 | };
41 | }
42 |
43 | - (NSDictionary*)fieldStorageType{
44 | return @{
45 | @"longlongText" : @"TEXT"
46 | };
47 | }
48 |
49 | - (NSDictionary *)fieldLenght{
50 | return @{
51 | @"longlongText" : @"515"
52 | };
53 | }
54 |
55 | // 为 gradeID 加上索引
56 | - (void)addOtherOperationForTable:(FMDatabase *)aDB{
57 | [self addDB:aDB uniques:@[@"gradeID"]];
58 | }
59 |
60 | @end
61 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/DataSoure/Storage/JYClassTable.m:
--------------------------------------------------------------------------------
1 | //
2 | // JYClassTable.m
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/11/21.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import "JYClassTable.h"
10 | #import "JYClassInfo.h"
11 | #import "JYPersonTable.h"
12 | #import "JYDBService.h"
13 | #import "JYPersonDB.h"
14 |
15 | @implementation JYClassTable
16 |
17 | - (void)configTableName{
18 |
19 | self.contentClass = [JYClassInfo class];
20 | self.tableName = @"JYClassTable";
21 | }
22 |
23 | - (NSString *)contentId{
24 | return @"classID";
25 | }
26 |
27 | - (NSArray *)getContentField{
28 | return @[@"className",@"gradeID"];
29 | }
30 |
31 | // 设置关联的表
32 | - (NSDictionary *)associativeTableField{
33 |
34 | JYPersonTable *table = [JYDBService shared].personDB.personTable;
35 | // tableSortKey 不设置查询时会以主key做升序放入数组
36 | return @{
37 | @"teacher" : @{
38 | tableContentObject : table,
39 | tableViceKey : @"teacherClassID"
40 | },
41 | @"students" : @{
42 | tableContentObject : table,
43 | tableViceKey : @"studentClassID",
44 | tableSortKey : @"studentIdx"
45 | }
46 | };
47 | }
48 |
49 | // 为 gradeID 加上索引
50 | - (void)addOtherOperationForTable:(FMDatabase *)aDB{
51 | [self addDB:aDB uniques:@[@"gradeID"]];
52 | }
53 |
54 | @end
55 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/JYDatabase/JYDataBase.h:
--------------------------------------------------------------------------------
1 | //
2 | // JYDataBase.h
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/5/9.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "JYContentTable.h"
11 | #import "JYQueryConditions.h"
12 |
13 | @class FMDatabase;
14 | @class FMDatabaseQueue;
15 |
16 | typedef NS_ENUM(NSInteger, ArtDatabaseMode)
17 | {
18 | ArtDatabaseModeRead = 0,
19 | ArtDatabaseModeWrite = 1 << 0,
20 | };
21 |
22 | @interface JYDataBase : NSObject
23 |
24 | @property (nonatomic, copy, readonly) NSString* path;
25 | @property (nonatomic, strong, readonly) FMDatabaseQueue *dbQueue;
26 | @property (nonatomic, assign, readonly) ArtDatabaseMode mode;
27 |
28 | - (void)buildWithPath:(NSString *)aPath mode:(ArtDatabaseMode)aMode;
29 | - (void)buildWithPath:(NSString *)aPath mode:(ArtDatabaseMode)aMode registTable:(void(^)())aRegist;
30 |
31 | - (void)checkError:(FMDatabase *)aDb;
32 | - (id)checkEmpty:(id)aObject;
33 | - (void)addUpdateValue:(id)aValue key:(NSString *)aKey inParams:(NSMutableDictionary *)aParams;
34 |
35 | // 获取DB版本号, 默认返回 1
36 | - (NSInteger)getCurrentDBVersion;
37 |
38 | // 创建数据库
39 | - (void)createAllTable:(FMDatabase *)aDB;
40 | // 数据库升级 1-2 2-3 3-4 4-5 的升级
41 | - (void)updateDB:(FMDatabase *)aDB fromVersion:(NSInteger)aFromVersion toVersion:(NSInteger)aToVersion;
42 |
43 | // 一次性升级
44 | - (void)updateDB:(FMDatabase *)aDB;
45 |
46 | #pragma mark - 简化创建的方法
47 | /*
48 | - (void)buildWithPath:(NSString *)aPath mode:(ArtDatabaseMode)aMode registTable:(void(^)())aRegist;
49 | 使用该方法创建,写在aRegist 回调内
50 | */
51 | - (JYContentTable *)registTableClass:(Class)aClass;
52 |
53 | @end
54 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | 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 | UISupportedInterfaceOrientations~ipad
40 |
41 | UIInterfaceOrientationPortrait
42 | UIInterfaceOrientationPortraitUpsideDown
43 | UIInterfaceOrientationLandscapeLeft
44 | UIInterfaceOrientationLandscapeRight
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/JYGenerationCode/JYGenerationCode/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // JYGenerationCode
4 | //
5 | // Created by weijingyun on 16/5/15.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 |
11 | @interface ViewController()
12 | @property (weak) IBOutlet NSTextField *dbName;
13 | @property (weak) IBOutlet NSTextField *tableName;
14 | @property (weak) IBOutlet NSButton *outButton;
15 | @property (weak) IBOutlet NSTextField *tableClass;
16 | @property (weak) IBOutlet NSTextField *dbClass;
17 | @property (weak) IBOutlet NSTextField *hhContent;
18 |
19 | @property (unsafe_unretained) IBOutlet NSTextView *outPutView;
20 |
21 | @end
22 |
23 | @implementation ViewController
24 |
25 | - (void)viewDidLoad {
26 | [super viewDidLoad];
27 |
28 | // Do any additional setup after loading the view.
29 | }
30 |
31 | - (void)setRepresentedObject:(id)representedObject {
32 | [super setRepresentedObject:representedObject];
33 |
34 | // Update the view, if already loaded.
35 | }
36 |
37 | - (IBAction)tapBut:(id)sender {
38 |
39 | NSString *fileName = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"/code.bundle/code1.text"];
40 | NSString *contentCode1String = [NSString stringWithContentsOfFile:fileName encoding:NSUTF8StringEncoding error:nil];
41 | contentCode1String = [contentCode1String stringByReplacingOccurrencesOfString:@"HHContent" withString:self.hhContent.stringValue];
42 | contentCode1String = [contentCode1String stringByReplacingOccurrencesOfString:@"HHClass" withString:self.tableClass.stringValue];
43 | contentCode1String = [contentCode1String stringByReplacingOccurrencesOfString:@"HHTableName" withString:self.tableName.stringValue];
44 | contentCode1String = [contentCode1String stringByReplacingOccurrencesOfString:@"HHDBName" withString:self.dbName.stringValue];
45 | self.outPutView.string = contentCode1String;
46 | }
47 |
48 |
49 | @end
50 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | }
88 | ],
89 | "info" : {
90 | "version" : 1,
91 | "author" : "xcode"
92 | }
93 | }
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/DataSoure/Content/JYPersonInfo.h:
--------------------------------------------------------------------------------
1 | //
2 | // JYPersonInfo.h
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/5/9.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | @interface JYPersonInfo : NSObject
12 |
13 | // 人员编号
14 | @property (nonatomic, copy) NSString *personID;
15 |
16 | /* 主要演示 class 包含老师和学生
17 | * 这里要 两个外键区分,老师设置teacherClassID 学生 studentClassID
18 | * 否则会有问题,开发过程中表的设计应该避免这样。老师和学生用两张表处理
19 | */
20 | @property (nonatomic, copy) NSString *teacherClassID;
21 | @property (nonatomic, copy) NSString *studentClassID;
22 |
23 | /* 学生在 NSMutableArray *students;
24 | * 不设置这些字段,获取时会以personID 做升序
25 | */
26 | @property (nonatomic, assign) NSInteger studentIdx;
27 |
28 | // 类型测试
29 | @property (nonatomic, copy) NSMutableString *mutableString1;
30 | @property (nonatomic, strong) NSArray *array;
31 | @property (nonatomic, strong) NSMutableArray *arrayM;
32 | @property (nonatomic, strong) NSDictionary *dic;
33 | @property (nonatomic, strong) NSMutableDictionary *dicM;
34 | @property (nonatomic, assign) NSInteger integer1;
35 | @property (nonatomic, assign) NSUInteger uInteger1;
36 | @property (nonatomic, assign) int int1;
37 | @property (nonatomic, assign) BOOL bool1;
38 | @property (nonatomic, assign) double double1;
39 | @property (nonatomic, assign) float float1;
40 | @property (nonatomic, assign) CGFloat cgfloat1;
41 | @property (nonatomic, strong) NSData *data;
42 | @property (nonatomic, strong) NSNumber *number;
43 |
44 | @end
45 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/5/9.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 |
11 | @interface AppDelegate ()
12 |
13 | @end
14 |
15 | @implementation AppDelegate
16 |
17 |
18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
19 | // Override point for customization after application launch.
20 | return YES;
21 | }
22 |
23 | - (void)applicationWillResignActive:(UIApplication *)application {
24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
26 | }
27 |
28 | - (void)applicationDidEnterBackground:(UIApplication *)application {
29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
31 | }
32 |
33 | - (void)applicationWillEnterForeground:(UIApplication *)application {
34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
35 | }
36 |
37 | - (void)applicationDidBecomeActive:(UIApplication *)application {
38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
39 | }
40 |
41 | - (void)applicationWillTerminate:(UIApplication *)application {
42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
43 | }
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/DataSoure/Storage/JYPersonDB.m:
--------------------------------------------------------------------------------
1 | //
2 | // JYPersonDB.m
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/5/9.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import "JYPersonDB.h"
10 | #import "JYGradeTable.h"
11 | #import "JYClassTable.h"
12 | #import "JYPersonTable.h"
13 |
14 | #define dataBaseName @"usersDataSource.db"
15 |
16 | @interface JYPersonDB()
17 |
18 | @property (nonatomic, strong) NSString * documentDirectory ;
19 | @property (nonatomic, strong) JYGradeTable *gradeTable;
20 | @property (nonatomic, strong) JYClassTable *classTable;
21 | @property (nonatomic, strong) JYPersonTable *personTable;
22 |
23 | @end
24 |
25 |
26 | @implementation JYPersonDB
27 | + (instancetype)storage{
28 | JYPersonDB *userStorage = [[JYPersonDB alloc] init];
29 | [userStorage construct];
30 | return userStorage;
31 | }
32 |
33 | - (void)construct{
34 | NSLog(@"%@",self.documentDirectory);
35 | [self buildWithPath:self.documentDirectory mode:ArtDatabaseModeWrite registTable:^{
36 | //注册数据表 建议外引出来,用于其它位置调用封装
37 | self.gradeTable = (JYGradeTable *)[self registTableClass:[JYGradeTable class]];
38 | self.classTable = (JYClassTable *)[self registTableClass:[JYClassTable class]];
39 | self.personTable = (JYPersonTable *)[self registTableClass:[JYPersonTable class]];
40 | }];
41 |
42 | }
43 |
44 | #pragma mark - 数据库版本
45 | - (NSInteger)getCurrentDBVersion
46 | {
47 | return 6;
48 | }
49 |
50 | #pragma make - 懒加载
51 | - (NSString *)documentDirectory{
52 | if (!_documentDirectory) {
53 | NSString *path = [[(NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES)) lastObject] stringByAppendingPathComponent:@"usersDataSource"];
54 |
55 | NSFileManager* fm = [NSFileManager defaultManager];
56 | BOOL isDirectory = NO;
57 | if (![fm fileExistsAtPath:path isDirectory:&isDirectory] || !isDirectory) {
58 | [fm createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
59 | }
60 |
61 | _documentDirectory = [path stringByAppendingPathComponent:dataBaseName];
62 |
63 | }
64 | return _documentDirectory;
65 | }
66 |
67 | @end
68 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/JYDatabase/JYDataBaseConfig.m:
--------------------------------------------------------------------------------
1 | //
2 | // JYDataBaseConfig.m
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/10/17.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import "JYDataBaseConfig.h"
10 |
11 | @implementation JYDataBaseConfig
12 |
13 | + (instancetype)shared
14 | {
15 | static dispatch_once_t onceToken;
16 | static JYDataBaseConfig* shared = nil;
17 | dispatch_once(&onceToken, ^{
18 | shared = [[self alloc] init];
19 | });
20 |
21 | return shared;
22 | }
23 |
24 | #pragma mark - 静态方法
25 | NSDictionary * jy_correspondingDic(){
26 | return @{@"Tb":@"BOOL",
27 | @"TB":@"BOOL",
28 | @"Tc":@"BOOL",
29 | @"TC":@"BOOL",
30 | @"Td":@"DOUBLE",
31 | @"TD":@"DOUBLE",
32 | @"Tf":@"FLOAT",
33 | @"TF":@"INTEGER",
34 | @"Ti":@"INTEGER",
35 | @"TI":@"INTEGER",
36 | @"Tq":@"INTEGER",
37 | @"TQ":@"INTEGER",
38 | @"T@\"NSMutableString\"":@"NVARCHAR",
39 | @"T@\"NSString\"":@"NVARCHAR",
40 | @"T@\"NSData\"":@"BLOB",
41 | @"T@\"NSNumber\"":@"BLOB",
42 | @"T@\"NSDictionary\"":@"BLOB",
43 | @"T@\"NSMutableDictionary\"":@"BLOB",
44 | @"T@\"NSMutableArray\"":@"BLOB",
45 | @"T@\"NSArray\"":@"BLOB",};
46 | }
47 |
48 | NSDictionary * jy_defaultDic(){
49 | return @{@"BOOL":@"1",
50 | @"DOUBLE":@"20",
51 | @"FLOAT":@"10",
52 | @"INTEGER":@"10",
53 | @"VARCHAR":@"10",
54 | @"NVARCHAR":@"10",
55 | @"TEXT" :@"512",
56 | @"BLOB":@"512",};
57 | }
58 |
59 | @end
60 |
61 | /*
62 |
63 | 1、CHAR。CHAR存储定长数据很方便,CHAR字段上的索引效率级高,比如定义char(10),那么不论你存储的数据是否达到了10个字节,都要占去10个字节的空间,不足的自动用空格填充。
64 | 2、VARCHAR。存储变长数据,但存储效率没有CHAR高。如果一个字段可能的值是不固定长度的,我们只知道它不可能超过10个字符,把它定义为 VARCHAR(10)是最合算的。VARCHAR类型的实际长度是它的值的实际长度+1。为什么“+1”呢?这一个字节用于保存实际使用了多大的长度。从空间上考虑,用varchar合适;从效率上考虑,用char合适,关键是根据实际情况找到权衡点。
65 | 3、TEXT。text存储可变长度的非Unicode数据,最大长度为2^31-1(2,147,483,647)个字符。
66 | 4、NCHAR、NVARCHAR、NTEXT。这三种从名字上看比前面三种多了个“N”。它表示存储的是Unicode数据类型的字符。我们知道字符中,英文字符只需要一个字节存储就足够了,但汉字众多,需要两个字节存储,英文与汉字同时存在时容易造成混乱,Unicode字符集就是为了解决字符集这种不兼容的问题而产生的,它所有的字符都用两个字节表示,即英文字符也是用两个字节表示。nchar、nvarchar的长度是在1到4000之间。和char、varchar比较起来,nchar、nvarchar则最多存储4000个字符,不论是英文还是汉字;而char、varchar最多能存储8000个英文,4000个汉字。可以看出使用nchar、nvarchar数据类型时不用担心输入的字符是英文还是汉字,较为方便,但在存储英文时数量上有些损失。
67 | 所以一般来说,如果含有中文字符,用nchar/nvarchar,如果纯英文和数字,用char/varchar。
68 | SQLite最大的特点在于其数据类型为无数据类型(typelessness)。这意味着可以保存任何类型的数据到所想要保存的任何表的任何列中,无论这列声明的数据类型是什么。虽然在生成表结构的时候,要声明每个域的数据类型,但SQLite并不做任何检查。开发人员要靠自己的程序来控制输入与读出数据的类型。这里有一个例外,就是当主键为整型值时,如果要插入一个非整型值时会产生异常。
69 |
70 | 虽然,SQLite允许忽略数据类型,但是,仍然建议在Create Table语句中指定数据类型,因为数据类型有利于增强程序的可读性。另外,虽然在插入或读出数据的时候是不区分类型的,但在比较的时候,不同数据类型是有区别的
71 |
72 | */
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/JYGenerationCode/JYGenerationCode/code.bundle/code1.text:
--------------------------------------------------------------------------------
1 | - (void)insertHHContent:(HHClass *)aHHContent;
2 | - (void)insertHHContents:(NSArray *)aHHContents;
3 | - (void)insertIndependentHHContent:(HHClass *)aHHContent;
4 | - (void)insertIndependentHHContents:(NSArray *)aHHContents;
5 |
6 | - (NSArray *)getHHContentByConditions:(void (^)(JYQueryConditions *make))block;
7 | - (HHClass *)getHHContent:(NSString*)aHHContentID;
8 | - (NSArray *)getHHContents:(NSArray *)aHHContentIDs;
9 | - (NSArray *)getAllHHContent;
10 |
11 | - (void)deleteHHContentByConditions:(void (^)(JYQueryConditions *make))block;
12 | - (void)deleteHHContents:(NSArray*)aHHContentIDs;
13 | - (void)deleteHHContent:(NSString *)aHHContentID;
14 | - (void)deleteAllHHContent;
15 | - (void)cleanHHContentBefore:(NSDate*)date;
16 |
17 | - (NSInteger)getHHContentCountByConditions:(void (^)(JYQueryConditions *make))block;
18 | - (NSInteger)getHHContentAllCount;
19 |
20 | # pragma mark HHClass operation
21 | - (void)insertHHContent:(HHClass *)aHHContent{
22 | [self.HHDBName.HHTableName insertContent:aHHContent];
23 | }
24 |
25 | - (void)insertHHContents:(NSArray *)aHHContents{
26 | [self.HHDBName.HHTableName insertContents:aHHContents];
27 | }
28 |
29 | - (void)insertIndependentHHContent:(HHClass *)aHHContent{
30 | [self.HHDBName.HHTableName insertIndependentContent:aHHContent];
31 | }
32 |
33 | - (void)insertIndependentHHContents:(NSArray *)aHHContents{
34 | [self.HHDBName.HHTableName insertIndependentContents:aHHContents];
35 | }
36 |
37 | - (NSArray *)getHHContentByConditions:(void (^)(JYQueryConditions *make))block{
38 | return [self.HHDBName.HHTableName getContentByConditions:block];
39 | }
40 |
41 | - (HHClass *)getHHContent:(NSString*)aHHContentID{
42 | return [self.HHDBName.HHTableName getContentByID:aHHContentID];
43 | }
44 |
45 | - (NSArray *)getHHContents:(NSArray *)aHHContentIDs{
46 | return [self.HHDBName.HHTableName getContentByIDs:aHHContentIDs];
47 | }
48 |
49 | - (NSArray *)getAllHHContent{
50 | return [self.HHDBName.HHTableName getAllContent];
51 | }
52 |
53 | - (void)deleteHHContentByConditions:(void (^)(JYQueryConditions *make))block{
54 | return [self.HHDBName.HHTableName deleteContentByConditions:block];
55 | }
56 |
57 | - (void)deleteHHContents:(NSArray*)aHHContentIDs{
58 | [self.HHDBName.HHTableName deleteContentByIDs:aHHContentIDs];
59 | }
60 |
61 | - (void)deleteHHContent:(NSString *)aHHContentID{
62 | [self.HHDBName.HHTableName deleteContentByID:aHHContentID];
63 | }
64 |
65 | - (void)deleteAllHHContent{
66 | [self.HHDBName.HHTableName deleteAllContent];
67 | }
68 |
69 | - (void)cleanHHContentBefore:(NSDate*)date{
70 | [self.HHDBName.HHTableName cleanContentBefore:date];
71 | }
72 |
73 | - (NSInteger)getHHContentCountByConditions:(void (^)(JYQueryConditions *make))block{
74 | return [self.HHDBName.HHTableName getCountByConditions:block];
75 | }
76 |
77 | - (NSInteger)getHHContentAllCount{
78 | return [self.HHDBName.HHTableName getAllCount];
79 | }
80 |
81 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/DataSoure/Service/JYDBService.h:
--------------------------------------------------------------------------------
1 | //
2 | // JYDBService.h
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/5/9.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class JYPersonDB,JYGradeInfo,JYClassInfo,JYPersonInfo,JYQueryConditions;
12 |
13 | @interface JYDBService : NSObject
14 |
15 | + (instancetype)shared;
16 |
17 | @property (nonatomic, strong, readonly) JYPersonDB *personDB;
18 |
19 | #pragma mark - 以下代码由 DEMO 中 JYGenerationCode 工具生成
20 | # pragma mark JYGradeInfo operation
21 | - (void)insertGradeInfo:(JYGradeInfo *)aGradeInfo;
22 | - (void)insertGradeInfos:(NSArray *)aGradeInfos;
23 | - (void)insertIndependentGradeInfo:(JYGradeInfo *)aGradeInfo;
24 | - (void)insertIndependentGradeInfos:(NSArray *)aGradeInfos;
25 |
26 | - (NSArray *)getGradeInfoByConditions:(void (^)(JYQueryConditions *make))block;
27 | - (JYGradeInfo *)getGradeInfo:(NSString*)aGradeInfoID;
28 | - (NSArray *)getGradeInfos:(NSArray *)aGradeInfoIDs;
29 | - (NSArray *)getAllGradeInfo;
30 |
31 | - (void)deleteGradeInfoByConditions:(void (^)(JYQueryConditions *make))block;
32 | - (void)deleteGradeInfos:(NSArray*)aGradeInfoIDs;
33 | - (void)deleteGradeInfo:(NSString *)aGradeInfoID;
34 | - (void)deleteAllGradeInfo;
35 | - (void)cleanGradeInfoBefore:(NSDate*)date;
36 |
37 | - (NSInteger)getGradeInfoCountByConditions:(void (^)(JYQueryConditions *make))block;
38 | - (NSInteger)getGradeInfoAllCount;
39 |
40 | # pragma mark JYClassInfo operation
41 | - (void)insertClassInfo:(JYClassInfo *)aClassInfo;
42 | - (void)insertClassInfos:(NSArray *)aClassInfos;
43 | - (void)insertIndependentClassInfo:(JYClassInfo *)aClassInfo;
44 | - (void)insertIndependentClassInfos:(NSArray *)aClassInfos;
45 |
46 | - (NSArray *)getClassInfoByConditions:(void (^)(JYQueryConditions *make))block;
47 | - (JYClassInfo *)getClassInfo:(NSString*)aClassInfoID;
48 | - (NSArray *)getClassInfos:(NSArray *)aClassInfoIDs;
49 | - (NSArray *)getAllClassInfo;
50 |
51 | - (void)deleteClassInfoByConditions:(void (^)(JYQueryConditions *make))block;
52 | - (void)deleteClassInfos:(NSArray*)aClassInfoIDs;
53 | - (void)deleteClassInfo:(NSString *)aClassInfoID;
54 | - (void)deleteAllClassInfo;
55 | - (void)cleanClassInfoBefore:(NSDate*)date;
56 |
57 | - (NSInteger)getClassInfoCountByConditions:(void (^)(JYQueryConditions *make))block;
58 | - (NSInteger)getClassInfoAllCount;
59 |
60 | # pragma mark JYPersonInfo operation
61 | - (void)insertPersonInfo:(JYPersonInfo *)aPersonInfo;
62 | - (void)insertPersonInfos:(NSArray *)aPersonInfos;
63 | - (void)insertIndependentPersonInfo:(JYPersonInfo *)aPersonInfo;
64 | - (void)insertIndependentPersonInfos:(NSArray *)aPersonInfos;
65 |
66 | - (NSArray *)getPersonInfoByConditions:(void (^)(JYQueryConditions *make))block;
67 | - (JYPersonInfo *)getPersonInfo:(NSString*)aPersonInfoID;
68 | - (NSArray *)getPersonInfos:(NSArray *)aPersonInfoIDs;
69 | - (NSArray *)getAllPersonInfo;
70 |
71 | - (void)deletePersonInfoByConditions:(void (^)(JYQueryConditions *make))block;
72 | - (void)deletePersonInfos:(NSArray*)aPersonInfoIDs;
73 | - (void)deletePersonInfo:(NSString *)aPersonInfoID;
74 | - (void)deleteAllPersonInfo;
75 | - (void)cleanPersonInfoBefore:(NSDate*)date;
76 |
77 | - (NSInteger)getPersonInfoCountByConditions:(void (^)(JYQueryConditions *make))block;
78 | - (NSInteger)getPersonInfoAllCount;
79 |
80 | @end
81 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/JYDatabase/JYContentTable.h:
--------------------------------------------------------------------------------
1 | //
2 | // JYContentTable.h
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/5/9.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "JYDataBaseConfig.h"
11 | #import "JYQueryConditions.h"
12 | #import "NSObject+JYContentTableClass.h"
13 |
14 | static const NSString *tableContentObject = @"tableContentObject";// 对应的字段 模型的 JYContentTable 对象
15 | static const NSString *tableViceKey = @"tableViceKey"; // 属于本表的 副key
16 | static const NSString *tableSortKey = @"tableSortKey"; // 用于排序字段(映射到数组的顺序) NSString or NSInteger
17 |
18 | @class FMDatabaseQueue , FMDatabase;
19 |
20 | @interface JYContentTable : NSObject
21 |
22 | @property (nonatomic, strong) FMDatabaseQueue *dbQueue;
23 | //数据库表名
24 | @property (nonatomic, copy) NSString *tableName;
25 | //该表对应的模型类
26 | @property (nonatomic, strong) Class contentClass;
27 |
28 | - (void)checkError:(FMDatabase *)aDb;
29 | - (id)checkEmpty:(id)aObject;
30 | - (id)checkVaule:(id)aVaule forKey:(NSString*)aKey; // 查询出来的数据进行处理
31 |
32 | #pragma mark - 创建表
33 | - (void)configTableName; // 进行一些初始化设置
34 | - (NSString *)contentId; // 表的主键
35 | - (NSArray *)getContentField; // 表除主键外其它的列 默认取 @“DB” 结尾的属性
36 | - (NSDictionary*)fieldStorageType; // 创建表 对应列默认类型
37 | - (NSDictionary*)fieldLenght; // 创建表 对应列默认长度 默认取默认值
38 | /*
39 | * 用于关联其它表的属性联系必须是 NSArray* NSMutableArray或者 ContentClass
40 | * JYTest1Table *table = [[JYTest1Table alloc] init];
41 | * table.dbQueue = self.dbQueue;
42 | * @{
43 | * @"field1":@{
44 | * tableContentClass : table,
45 | * tablePrimaryKey : @"primaryKey",
46 | * tableViceKey : @"viceKey"
47 | * },
48 | * }
49 | */
50 | - (NSDictionary *)associativeTableField;
51 |
52 |
53 | // 不重写 该方法会 通过 contentId getContentField fieldLenght associativeTableField 进行表的创建
54 | - (void)createTable:(FMDatabase *)aDB;
55 |
56 | // 重写该方法 在创建和更新表时添加额外的数据 比如为某些字段添加索引
57 | - (void)addOtherOperationForTable:(FMDatabase *)aDB;
58 |
59 | // 重写该方法 在建表时插入默认数据
60 | - (void)insertDefaultData:(FMDatabase *)aDb;
61 |
62 | #pragma mark - 更新表
63 | // 1-2 2-3 3-4 一步步升级 不建议使用 // - (void)updateDB:(FMDatabase *)aDB 已经实现一步到位
64 | - (void)updateDB:(FMDatabase *)aDB fromVersion:(NSInteger)aFromVersion toVersion:(NSInteger)aToVersion;
65 | // 默认通过 getContentField 来进行对比 从而新增 删除对应列
66 | - (void)updateDB:(FMDatabase *)aDB;
67 |
68 | #pragma mark - 索引添加
69 | - (void)addUniques:(NSArray*)indexs; // 默认添加 非唯一索引
70 | - (void)addDB:(FMDatabase *)aDB uniques:(NSArray*)indexs;
71 | - (void)addDB:(FMDatabase *)aDB type:(EJYDataBaseIndex)aType uniques:(NSArray*)indexs;
72 |
73 | #pragma mark - insert 插入
74 | // 以下插入会更新该模型所有相关表
75 | - (void)insertDB:(FMDatabase *)aDB contents:(NSArray *)aContents;
76 | - (void)insertContent:(id)aContent;
77 | - (void)insertContents:(NSArray *)aContents;
78 |
79 | // 以下插入只会更新本表相关数据,不会更新关联表,请根据情况尽量调用以下方法
80 | - (void)insertIndependentDB:(FMDatabase *)aDB contents:(NSArray *)aContents;
81 | - (void)insertIndependentContent:(id)aContent;
82 | - (void)insertIndependentContents:(NSArray *)aContents;
83 |
84 | #pragma mark - get 查询
85 | - (NSArray *)getContentDB:(FMDatabase *)aDB byconditions:(void (^)(JYQueryConditions *make))block;
86 | - (NSArray *)getDB:(FMDatabase *)aDB contentByIDs:(NSArray*)aIDs;
87 | - (NSArray *)getContentByConditions:(void (^)(JYQueryConditions *make))block;
88 | - (NSArray *)getContentByIDs:(NSArray*)aIDs;
89 | - (id)getContentByID:(NSString*)aID;
90 | - (NSArray *)getAllContent;
91 |
92 | #pragma mark - delete 删除
93 | - (void)deleteContentDB:(FMDatabase *)aDB byconditions:(void (^)(JYQueryConditions *make))block;
94 | - (void)deleteDB:(FMDatabase *)aDB contentByIDs:(NSArray*)aIDs;
95 | - (void)deleteContentByConditions:(void (^)(JYQueryConditions *make))block;
96 | - (void)deleteContentByID:(NSString *)aID;
97 | - (void)deleteContentByIDs:(NSArray*)aIDs;
98 | - (void)deleteAllContent;
99 | - (void)cleanContentBefore:(NSDate*)date;
100 |
101 | #pragma mark - getCount
102 | - (NSInteger)getCountContentDB:(FMDatabase *)aDB byconditions:(void (^)(JYQueryConditions *make))block;
103 | - (NSInteger)getCountByConditions:(void (^)(JYQueryConditions *make))block;
104 | - (NSInteger)getAllCount;
105 |
106 | @end
107 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/JYDatabase/JYDataBase.m:
--------------------------------------------------------------------------------
1 | //
2 | // GKDatabase.m
3 | //
4 | //
5 | // Created by weijingyun on 5/26/15.
6 | // Copyright (c) 2015 justone. All rights reserved.
7 | //
8 |
9 | #import "JYDataBase.h"
10 | #import "FMDatabase.h"
11 | #import "FMDatabaseQueue.h"
12 | #if FMDB_SQLITE_STANDALONE
13 | #import
14 | #else
15 | #import
16 | #endif
17 |
18 | @interface JYDataBase ()
19 |
20 | @property (nonatomic, strong) FMDatabaseQueue *dbQueue;
21 | @property (nonatomic, copy) NSString* path;
22 | @property (nonatomic, assign) ArtDatabaseMode mode;
23 | @property (nonatomic, strong) NSMutableArray *tableArray;
24 |
25 | @end
26 |
27 | @implementation JYDataBase
28 |
29 | #pragma mark - Custom Methods
30 |
31 | - (void)checkError:(FMDatabase *)aDb
32 | {
33 | if ([aDb hadError]) {
34 | NSLog(@"DB Err %d: %@", [aDb lastErrorCode], [aDb lastErrorMessage]);
35 | }
36 | }
37 |
38 | - (id)checkEmpty:(id)aObject
39 | {
40 | return aObject == nil ? [NSNull null] : aObject;
41 | }
42 |
43 | - (void)addUpdateValue:(id)aValue key:(NSString *)aKey inParams:(NSMutableDictionary *)aParams
44 | {
45 | if (aValue) {
46 | [aParams setObject:aValue forKey:aKey];
47 | } else {
48 | [aParams setObject:[NSNull null] forKey:aKey];
49 | }
50 | }
51 |
52 | #pragma mark - init
53 | - (void)buildWithPath:(NSString *)aPath mode:(ArtDatabaseMode)aMode{
54 | [self buildWithPath:aPath mode:aMode registTable:nil];
55 | }
56 |
57 | - (void)buildWithPath:(NSString *)aPath mode:(ArtDatabaseMode)aMode registTable:(void(^)())aRegist{
58 |
59 | self.path = aPath;
60 | self.mode = aMode;
61 |
62 | if (aMode == ArtDatabaseModeRead)
63 | {
64 | // 只读
65 | self.dbQueue = [[FMDatabaseQueue alloc] initWithPath:aPath flags:SQLITE_OPEN_READONLY];
66 | }
67 | else
68 | {
69 | // 读写 或 创建
70 | self.dbQueue = [[FMDatabaseQueue alloc] initWithPath:aPath];
71 | }
72 |
73 | if (aRegist) {
74 | aRegist();
75 | }
76 |
77 | [self.dbQueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
78 | NSString *version = [self getVersion:db];
79 | if (version == nil) {
80 | [self createDBVersionTable:db];
81 | [self createAllTable:db];
82 | [self updateVersion:db];
83 | }else if([version integerValue] != [self getCurrentDBVersion]){
84 | [self updateDB:db fromVersion:[version integerValue]];
85 | [self updateDB:db];
86 | [self updateVersion:db];
87 | }
88 | [self checkError:db];
89 | }];
90 | }
91 |
92 | - (void)dealloc
93 | {
94 | [self.dbQueue close];
95 | }
96 |
97 | #pragma mark - version
98 |
99 | - (NSInteger)getCurrentDBVersion
100 | {
101 | return 1;
102 | }
103 |
104 | - (NSString *)getVersion:(FMDatabase *)aDB
105 | {
106 | NSString* version = nil;
107 | FMResultSet *rs = [aDB executeQuery:@"SELECT Version FROM gkdb_version WHERE Name = 'version'"];
108 | while ([rs next]) {
109 | version = [rs stringForColumnIndex:0];
110 | }
111 | [rs close];
112 | return version;
113 | }
114 |
115 | - (void)updateVersion:(FMDatabase *)aDB
116 | {
117 | NSString* version = [self getVersion:aDB];
118 |
119 | if (version)
120 | {
121 | [aDB executeUpdate:@"UPDATE gkdb_version SET Version=? WHERE Name = 'version'", @([self getCurrentDBVersion])];
122 | } else {
123 | [aDB executeUpdate:@"INSERT INTO gkdb_version (Name, Version) VALUES(?,?)" , @"version", @([self getCurrentDBVersion])];
124 | }
125 | }
126 |
127 |
128 | - (void)updateDB:(FMDatabase *)aDB fromVersion:(NSInteger)aFromVersion
129 | {
130 | NSInteger from = aFromVersion;
131 | NSInteger to = [self getCurrentDBVersion];
132 | while (from < to) {
133 | [self updateDB:aDB fromVersion:from toVersion:from + 1];
134 | ++from;
135 | }
136 | }
137 |
138 | - (void)updateDB:(FMDatabase *)aDB fromVersion:(NSInteger)aFromVersion toVersion:(NSInteger)aToVersion
139 | {
140 |
141 | }
142 |
143 | - (void)updateDB:(FMDatabase *)aDB{
144 | [self.tableArray enumerateObjectsUsingBlock:^(JYContentTable * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
145 | [obj updateDB:aDB];
146 | }];
147 | }
148 |
149 | #pragma mark - Create Table
150 |
151 | - (void)createAllTable:(FMDatabase *)aDB
152 | {
153 | [self.tableArray enumerateObjectsUsingBlock:^(JYContentTable * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
154 | [obj createTable:aDB];
155 | }];
156 | }
157 |
158 | - (void)createDBVersionTable:(FMDatabase *)aDB
159 | {
160 | [aDB executeUpdate:@"CREATE TABLE gkdb_version (Version varchar(20), Name varchar(10))"];
161 | }
162 |
163 | #pragma mark - 简化创建的方法
164 | - (JYContentTable *)registTableClass:(Class)aClass{
165 |
166 | JYContentTable *table = [[aClass alloc] init];
167 | NSAssert([table isKindOfClass:[JYContentTable class]], @"必须是继承JYContentTable 的类");
168 | table.dbQueue = self.dbQueue;
169 | [self.tableArray addObject:table];
170 | return table;
171 | }
172 |
173 | #pragma mark - 懒加载
174 | - (NSMutableArray *)tableArray{
175 | if (!_tableArray) {
176 | _tableArray = [[NSMutableArray alloc] init];
177 | }
178 | return _tableArray;
179 | }
180 |
181 | @end
182 |
183 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/JYDatabase/JYQueryConditions.m:
--------------------------------------------------------------------------------
1 | //
2 | // JYQueryConditions.m
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/5/13.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import "JYQueryConditions.h"
10 |
11 | #define kEqual @"kequal"
12 | #define kCompare @"kcompare"
13 | #define kOR @"kOR"
14 | #define kSqlStr @"kSqlStr"
15 |
16 | @interface JYQueryConditions()
17 |
18 | @property (nonatomic, strong) NSMutableArray *conditions;
19 | @property (nonatomic, copy) NSMutableString *orderStr;
20 | @property (nonatomic, strong) NSMutableArray *sqlStrings;
21 |
22 | @end
23 |
24 | @implementation JYQueryConditions
25 |
26 | - (JYQueryConditions * (^)(NSString *field))field{
27 | return ^id(NSString *field) {
28 | NSMutableDictionary *dicM = [[NSMutableDictionary alloc] init];
29 | dicM[kField] = field;
30 | [self.conditions addObject:dicM];
31 | return self;
32 | };
33 | }
34 |
35 | - (JYQueryConditions * (^)(NSString *field))asc{
36 | return ^id(NSString *field) {
37 | [self orderAppendType:@"asc" field:field];
38 | return self;
39 | };
40 | }
41 |
42 | - (JYQueryConditions * (^)(NSString *field))desc{
43 | return ^id(NSString *field) {
44 | [self orderAppendType:@"desc" field:field];
45 | return self;
46 | };
47 | }
48 |
49 | - (void)orderAppendType:(NSString *)aType field:(NSString *)aField{
50 | if (self.orderStr.length <= 0) {
51 | [self.orderStr appendString:@" order by "];
52 | }else{
53 | [self.orderStr appendString:@","];
54 | }
55 | [self.orderStr appendFormat:@" %@ %@ ",aField,aType];
56 | }
57 |
58 |
59 | - (JYQueryConditions * (^)())OR{
60 | return ^id(NSString *compare) {
61 | NSMutableDictionary *dicM = self.conditions.lastObject;
62 | dicM[kOR] = @"OR";
63 | return self;
64 | };
65 | }
66 |
67 | - (JYQueryConditions * (^)(NSString *compare))equalTo{
68 | return ^id(NSString *compare) {
69 | NSMutableDictionary *dicM = self.conditions.lastObject;
70 | dicM[kEqual] = @"=";
71 | dicM[kCompare] = compare;
72 | return self;
73 | };
74 | }
75 |
76 | - (JYQueryConditions * (^)(NSString *compare))notEqualTo{
77 | return ^id(NSString *compare) {
78 | NSMutableDictionary *dicM = self.conditions.lastObject;
79 | dicM[kEqual] = @"!=";
80 | dicM[kCompare] = compare;
81 | return self;
82 | };
83 | }
84 |
85 | - (JYQueryConditions * (^)(NSString *compare))greaterThanOrEqualTo{
86 | return ^id(NSString *compare) {
87 | NSMutableDictionary *dicM = self.conditions.lastObject;
88 | dicM[kEqual] = @">=";
89 | dicM[kCompare] = compare;
90 | return self;
91 | };
92 | }
93 |
94 | - (JYQueryConditions * (^)(NSString *compare))lessThanOrEqualTo{
95 | return ^id(NSString *compare) {
96 | NSMutableDictionary *dicM = self.conditions.lastObject;
97 | dicM[kEqual] = @"<=";
98 | dicM[kCompare] = compare;
99 | return self;
100 | };
101 | }
102 |
103 | - (JYQueryConditions * (^)(NSString *compare))greaterTo{
104 | return ^id(NSString *compare) {
105 | NSMutableDictionary *dicM = self.conditions.lastObject;
106 | dicM[kEqual] = @">";
107 | dicM[kCompare] = compare;
108 | return self;
109 | };
110 | }
111 |
112 | - (JYQueryConditions * (^)(NSString *compare))lessTo{
113 | return ^id(NSString *compare) {
114 | NSMutableDictionary *dicM = self.conditions.lastObject;
115 | dicM[kEqual] = @"<";
116 | dicM[kCompare] = compare;
117 | return self;
118 | };
119 | }
120 |
121 | - (JYQueryConditions * (^)())sqlOR{
122 | return ^id(NSString *compare) {
123 | NSMutableDictionary *dicM = self.sqlStrings.lastObject;
124 | dicM[kOR] = @"OR";
125 | return self;
126 | };
127 | }
128 |
129 | - (JYQueryConditions * (^)(NSString *str))sqlStr{
130 | return ^id(NSString *str) {
131 | NSMutableDictionary *dicM = [[NSMutableDictionary alloc] init];
132 | dicM[kSqlStr] = str;
133 | [self.sqlStrings addObject:dicM];
134 | return self;
135 | };
136 | }
137 |
138 | - (NSMutableString *)conditionStr{
139 | __block NSMutableString *strM = [[NSMutableString alloc] init];
140 | [self.conditions enumerateObjectsUsingBlock:^(NSMutableDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
141 | [strM appendFormat:@"%@ %@ \"%@\"",obj[kField],obj[kEqual],obj[kCompare]];
142 | if (idx < self.conditions.count - 1) {
143 | if (obj[kOR] != nil) {
144 | [strM appendFormat:@" OR "];
145 | }else{
146 | [strM appendFormat:@" AND "];
147 | }
148 | }
149 | }];
150 |
151 | if (self.sqlStrings.count > 0) {
152 |
153 | [self.sqlStrings enumerateObjectsUsingBlock:^(NSMutableDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
154 | if (!(idx == 0 && self.conditions.count <= 0)) {
155 |
156 | if (obj[kOR] != nil) {
157 | [strM appendFormat:@" OR "];
158 | }else{
159 | [strM appendFormat:@" AND "];
160 | }
161 | }
162 | [strM appendString:obj[kSqlStr]];
163 | }];
164 | }
165 | return strM;
166 | }
167 |
168 | #pragma mark - 懒加载
169 | - (NSMutableArray *)conditions{
170 | if (!_conditions) {
171 | _conditions = [[NSMutableArray alloc] init];
172 | }
173 | return _conditions;
174 | }
175 |
176 | - (NSMutableString *)orderStr{
177 | if (!_orderStr) {
178 | _orderStr = [[NSMutableString alloc] init];
179 | }
180 | return _orderStr;
181 | }
182 |
183 | - (NSMutableArray *)sqlStrings{
184 | if (!_sqlStrings) {
185 | _sqlStrings = [[NSMutableArray alloc] init];
186 | }
187 | return _sqlStrings;
188 | }
189 |
190 | @end
191 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/ViewController.mm:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/5/9.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 | #import "JYDBService.h"
11 |
12 | @interface ViewController ()
13 |
14 | @property (nonatomic, strong) UIImageView *imageView;
15 |
16 | @end
17 |
18 | @implementation ViewController
19 |
20 | - (void)viewDidLoad {
21 | [super viewDidLoad];
22 | // Do any additional setup after loading the view, typically from a nib.
23 | NSMutableArray *arrayM1 = [[NSMutableArray alloc] init];
24 | NSMutableArray *arrayM2 = [[NSMutableArray alloc] init];
25 | for (int i = 0; i < 10000; i++) {
26 | JYPersonInfo *info = [[JYPersonInfo alloc] init];
27 | info.personnumber = [NSString stringWithFormat:@"123456%tu",i];
28 | info.float1 = 10.10111;
29 | info.name = @"测试存储 1万条数据的大小测试存储 1万条数据的大小测试存储 1万条数据的大小测试存储 1万条数据的大小测试存储 1万条数据的大小测试存储 1万条数据的大小";
30 | info.desc = @"测试存储 1万条数据的大小测试存储 1万条数据的大小测试存储 1万条数据的大小测试存储 1万条数据的大小测试存储 1万条数据的大小";
31 | info.int1 = i;
32 | info.bool1 = i % 2 == 0;
33 | info.integer1 = -100;
34 | // info.image = [UIImage imageNamed:@"www"];
35 | info.data = nil;
36 | [arrayM1 addObject:info];
37 |
38 | JYTest1Content *test = [[JYTest1Content alloc] init];
39 | test.testID = [NSString stringWithFormat:@"%3tu",i];
40 | test.acgfloatDB = i * 1.5;
41 | test.numberDB = [NSNumber numberWithInteger:i];
42 | [arrayM2 addObject:test];
43 | }
44 | JYPersonInfo *info = [[JYPersonInfo alloc] init];
45 | info.personnumber = @"aaa";
46 | info.image = [UIImage imageNamed:@"www"];
47 | [[JYDBService shared] insertPersonInfo:info];
48 | [[JYDBService shared] insertPersonInfos:arrayM1];
49 |
50 | [[JYDBService shared] insertTest1Contents:arrayM2];
51 | UIButton *button1 = [self addButtonTitle:@"查询单条" action:@selector(getConttent:)];
52 | button1.frame = CGRectMake(0, 64, 80, 50);
53 |
54 | UIButton *button2 = [self addButtonTitle:@"查询所有" action:@selector(getAllConttent:)];
55 | button2.frame = CGRectMake(100, 64, 80, 50);
56 |
57 | UIButton *button3 = [self addButtonTitle:@"查询多条" action:@selector(getConttents:)];
58 | button3.frame = CGRectMake(200, 64, 80, 50);
59 |
60 | UIButton *button4 = [self addButtonTitle:@"删除单条" action:@selector(deleteConttent:)];
61 | button4.frame = CGRectMake(0, 164, 80, 50);
62 |
63 | UIButton *button5 = [self addButtonTitle:@"删除所有" action:@selector(deleteAllConttent:)];
64 | button5.frame = CGRectMake(100, 164, 80, 50);
65 |
66 | UIButton *button6 = [self addButtonTitle:@"删除多条" action:@selector(deleteConttents:)];
67 | button6.frame = CGRectMake(200, 164, 80, 50);
68 |
69 | UIButton *button7 = [self addButtonTitle:@"条件查询" action:@selector(compareConttents:)];
70 | button7.frame = CGRectMake(0, 264, 80, 50);
71 |
72 | UIButton *button8 = [self addButtonTitle:@"条件删除" action:@selector(deleteCompareConttents:)];
73 | button8.frame = CGRectMake(200, 264, 80, 50);
74 |
75 | UIButton *button9 = [self addButtonTitle:@"清除" action:@selector(clearnCompareConttents:)];
76 | button9.frame = CGRectMake(100, 264, 80, 50);
77 |
78 | self.imageView.frame = CGRectMake(0, 350, 200, 100);
79 | }
80 |
81 | - (void)clearnCompareConttents:(UIButton*)but{
82 | [[JYDBService shared] cleanPersonInfoBefore:[NSDate date]];
83 | }
84 |
85 | - (void)deleteCompareConttents:(UIButton*)but{
86 | [[JYDBService shared] deletePersonInfoByConditions:^(JYQueryConditions *make) {
87 | make.field(@"personnumber").greaterThanOrEqualTo(@"12345620");
88 | make.field(@"bool1").equalTo(@"1");
89 | make.field(@"personnumber").lessTo(@"12345630");
90 | }];
91 | }
92 |
93 | - (void)compareConttents:(UIButton*)but{
94 | NSArray*infos = [[JYDBService shared] getPersonInfoByConditions:^(JYQueryConditions *make) {
95 | make.field(@"personnumber").greaterThanOrEqualTo(@"12345620");
96 | make.field(@"bool1").equalTo(@"1");
97 | make.field(@"personnumber").lessTo(@"12345630");
98 | // make.sqlStr(@"personnumber < 12345630");
99 | // make.asc(@"bool1").desc(@"int1");
100 | }];
101 |
102 | NSLog(@"%@",infos);
103 | }
104 |
105 | - (void)deleteConttent:(UIButton*)but{
106 | [[JYDBService shared] deletePersonInfo:@"1234560"];
107 | }
108 |
109 | - (void)deleteConttents:(UIButton*)but{
110 | [[JYDBService shared] deletePersonInfos:@[@"1234560",@"12345610",@"12345611",@"1234562"]];
111 | }
112 |
113 | - (void)deleteAllConttent:(UIButton*)but{
114 | [[JYDBService shared] deleteAllPersonInfo];
115 | }
116 |
117 | - (void)getConttent:(UIButton*)but{
118 | JYPersonInfo* info = [[JYDBService shared] getPersonInfo:@"aaa"];
119 | NSLog(@"%f",info.lastInsertTime);
120 | self.imageView.image = info.image;
121 | NSArray* infos = [[JYDBService shared] getAllTest1Content];
122 | NSLog(@"%@",infos);
123 | }
124 |
125 | - (void)getConttents:(UIButton*)but{
126 | NSArray* infos = [[JYDBService shared] getPersonInfos:@[@"1234560",@"12345610",@"12345611",@"1234562"]];
127 | self.imageView.image = infos.firstObject.image;
128 | NSLog(@"%@",infos);
129 | }
130 |
131 | - (void)getAllConttent:(UIButton*)but{
132 | NSArray* infos = [[JYDBService shared] getAllPersonInfo];
133 | NSLog(@"%@",infos);
134 | }
135 |
136 | - (UIButton *)addButtonTitle:(NSString*)aTitle action:(SEL)aSel{
137 | UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
138 | button.backgroundColor = [UIColor orangeColor];
139 | [button setTitle:aTitle forState:UIControlStateNormal];
140 | [button addTarget:self action:aSel forControlEvents:UIControlEventTouchUpInside];
141 | [self.view addSubview:button];
142 | return button;
143 | }
144 |
145 | - (void)didReceiveMemoryWarning {
146 | [super didReceiveMemoryWarning];
147 | // Dispose of any resources that can be recreated.
148 | }
149 |
150 | #pragma mark - 懒加载
151 | - (UIImageView *)imageView{
152 | if (!_imageView) {
153 | _imageView = [[UIImageView alloc] init];
154 | [self.view addSubview:_imageView];
155 | }
156 | return _imageView;
157 | }
158 |
159 | @end
160 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/JYDatabase/fmdb/FMDatabasePool.h:
--------------------------------------------------------------------------------
1 | //
2 | // FMDatabasePool.h
3 | // fmdb
4 | //
5 | // Created by August Mueller on 6/22/11.
6 | // Copyright 2011 Flying Meat Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class FMDatabase;
12 |
13 | /** Pool of `` objects.
14 |
15 | ### See also
16 |
17 | - ``
18 | - ``
19 |
20 | @warning Before using `FMDatabasePool`, please consider using `` instead.
21 |
22 | If you really really really know what you're doing and `FMDatabasePool` is what
23 | you really really need (ie, you're using a read only database), OK you can use
24 | it. But just be careful not to deadlock!
25 |
26 | For an example on deadlocking, search for:
27 | `ONLY_USE_THE_POOL_IF_YOU_ARE_DOING_READS_OTHERWISE_YOULL_DEADLOCK_USE_FMDATABASEQUEUE_INSTEAD`
28 | in the main.m file.
29 | */
30 |
31 | @interface FMDatabasePool : NSObject {
32 | NSString *_path;
33 |
34 | dispatch_queue_t _lockQueue;
35 |
36 | NSMutableArray *_databaseInPool;
37 | NSMutableArray *_databaseOutPool;
38 |
39 | __unsafe_unretained id _delegate;
40 |
41 | NSUInteger _maximumNumberOfDatabasesToCreate;
42 | int _openFlags;
43 | NSString *_vfsName;
44 | }
45 |
46 | /** Database path */
47 |
48 | @property (atomic, retain) NSString *path;
49 |
50 | /** Delegate object */
51 |
52 | @property (atomic, assign) id delegate;
53 |
54 | /** Maximum number of databases to create */
55 |
56 | @property (atomic, assign) NSUInteger maximumNumberOfDatabasesToCreate;
57 |
58 | /** Open flags */
59 |
60 | @property (atomic, readonly) int openFlags;
61 |
62 | /** Custom virtual file system name */
63 |
64 | @property (atomic, copy) NSString *vfsName;
65 |
66 |
67 | ///---------------------
68 | /// @name Initialization
69 | ///---------------------
70 |
71 | /** Create pool using path.
72 |
73 | @param aPath The file path of the database.
74 |
75 | @return The `FMDatabasePool` object. `nil` on error.
76 | */
77 |
78 | + (instancetype)databasePoolWithPath:(NSString*)aPath;
79 |
80 | /** Create pool using path and specified flags
81 |
82 | @param aPath The file path of the database.
83 | @param openFlags Flags passed to the openWithFlags method of the database
84 |
85 | @return The `FMDatabasePool` object. `nil` on error.
86 | */
87 |
88 | + (instancetype)databasePoolWithPath:(NSString*)aPath flags:(int)openFlags;
89 |
90 | /** Create pool using path.
91 |
92 | @param aPath The file path of the database.
93 |
94 | @return The `FMDatabasePool` object. `nil` on error.
95 | */
96 |
97 | - (instancetype)initWithPath:(NSString*)aPath;
98 |
99 | /** Create pool using path and specified flags.
100 |
101 | @param aPath The file path of the database.
102 | @param openFlags Flags passed to the openWithFlags method of the database
103 |
104 | @return The `FMDatabasePool` object. `nil` on error.
105 | */
106 |
107 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags;
108 |
109 | /** Create pool using path and specified flags.
110 |
111 | @param aPath The file path of the database.
112 | @param openFlags Flags passed to the openWithFlags method of the database
113 | @param vfsName The name of a custom virtual file system
114 |
115 | @return The `FMDatabasePool` object. `nil` on error.
116 | */
117 |
118 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags vfs:(NSString *)vfsName;
119 |
120 | /** Returns the Class of 'FMDatabase' subclass, that will be used to instantiate database object.
121 |
122 | Subclasses can override this method to return specified Class of 'FMDatabase' subclass.
123 |
124 | @return The Class of 'FMDatabase' subclass, that will be used to instantiate database object.
125 | */
126 |
127 | + (Class)databaseClass;
128 |
129 | ///------------------------------------------------
130 | /// @name Keeping track of checked in/out databases
131 | ///------------------------------------------------
132 |
133 | /** Number of checked-in databases in pool
134 |
135 | @returns Number of databases
136 | */
137 |
138 | - (NSUInteger)countOfCheckedInDatabases;
139 |
140 | /** Number of checked-out databases in pool
141 |
142 | @returns Number of databases
143 | */
144 |
145 | - (NSUInteger)countOfCheckedOutDatabases;
146 |
147 | /** Total number of databases in pool
148 |
149 | @returns Number of databases
150 | */
151 |
152 | - (NSUInteger)countOfOpenDatabases;
153 |
154 | /** Release all databases in pool */
155 |
156 | - (void)releaseAllDatabases;
157 |
158 | ///------------------------------------------
159 | /// @name Perform database operations in pool
160 | ///------------------------------------------
161 |
162 | /** Synchronously perform database operations in pool.
163 |
164 | @param block The code to be run on the `FMDatabasePool` pool.
165 | */
166 |
167 | - (void)inDatabase:(void (^)(FMDatabase *db))block;
168 |
169 | /** Synchronously perform database operations in pool using transaction.
170 |
171 | @param block The code to be run on the `FMDatabasePool` pool.
172 | */
173 |
174 | - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block;
175 |
176 | /** Synchronously perform database operations in pool using deferred transaction.
177 |
178 | @param block The code to be run on the `FMDatabasePool` pool.
179 | */
180 |
181 | - (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block;
182 |
183 | /** Synchronously perform database operations in pool using save point.
184 |
185 | @param block The code to be run on the `FMDatabasePool` pool.
186 |
187 | @return `NSError` object if error; `nil` if successful.
188 |
189 | @warning You can not nest these, since calling it will pull another database out of the pool and you'll get a deadlock. If you need to nest, use `<[FMDatabase startSavePointWithName:error:]>` instead.
190 | */
191 |
192 | - (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block;
193 |
194 | @end
195 |
196 |
197 | /** FMDatabasePool delegate category
198 |
199 | This is a category that defines the protocol for the FMDatabasePool delegate
200 | */
201 |
202 | @interface NSObject (FMDatabasePoolDelegate)
203 |
204 | /** Asks the delegate whether database should be added to the pool.
205 |
206 | @param pool The `FMDatabasePool` object.
207 | @param database The `FMDatabase` object.
208 |
209 | @return `YES` if it should add database to pool; `NO` if not.
210 |
211 | */
212 |
213 | - (BOOL)databasePool:(FMDatabasePool*)pool shouldAddDatabaseToPool:(FMDatabase*)database;
214 |
215 | /** Tells the delegate that database was added to the pool.
216 |
217 | @param pool The `FMDatabasePool` object.
218 | @param database The `FMDatabase` object.
219 |
220 | */
221 |
222 | - (void)databasePool:(FMDatabasePool*)pool didAddDatabase:(FMDatabase*)database;
223 |
224 | @end
225 |
226 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/JYDatabase/fmdb/FMDatabaseQueue.h:
--------------------------------------------------------------------------------
1 | //
2 | // FMDatabaseQueue.h
3 | // fmdb
4 | //
5 | // Created by August Mueller on 6/22/11.
6 | // Copyright 2011 Flying Meat Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class FMDatabase;
12 |
13 | /** To perform queries and updates on multiple threads, you'll want to use `FMDatabaseQueue`.
14 |
15 | Using a single instance of `` from multiple threads at once is a bad idea. It has always been OK to make a `` object *per thread*. Just don't share a single instance across threads, and definitely not across multiple threads at the same time.
16 |
17 | Instead, use `FMDatabaseQueue`. Here's how to use it:
18 |
19 | First, make your queue.
20 |
21 | FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath];
22 |
23 | Then use it like so:
24 |
25 | [queue inDatabase:^(FMDatabase *db) {
26 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]];
27 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]];
28 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]];
29 |
30 | FMResultSet *rs = [db executeQuery:@"select * from foo"];
31 | while ([rs next]) {
32 | //…
33 | }
34 | }];
35 |
36 | An easy way to wrap things up in a transaction can be done like this:
37 |
38 | [queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
39 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]];
40 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]];
41 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]];
42 |
43 | if (whoopsSomethingWrongHappened) {
44 | *rollback = YES;
45 | return;
46 | }
47 | // etc…
48 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:4]];
49 | }];
50 |
51 | `FMDatabaseQueue` will run the blocks on a serialized queue (hence the name of the class). So if you call `FMDatabaseQueue`'s methods from multiple threads at the same time, they will be executed in the order they are received. This way queries and updates won't step on each other's toes, and every one is happy.
52 |
53 | ### See also
54 |
55 | - ``
56 |
57 | @warning Do not instantiate a single `` object and use it across multiple threads. Use `FMDatabaseQueue` instead.
58 |
59 | @warning The calls to `FMDatabaseQueue`'s methods are blocking. So even though you are passing along blocks, they will **not** be run on another thread.
60 |
61 | */
62 |
63 | @interface FMDatabaseQueue : NSObject {
64 | NSString *_path;
65 | dispatch_queue_t _queue;
66 | FMDatabase *_db;
67 | int _openFlags;
68 | NSString *_vfsName;
69 | }
70 |
71 | /** Path of database */
72 |
73 | @property (atomic, retain) NSString *path;
74 |
75 | /** Open flags */
76 |
77 | @property (atomic, readonly) int openFlags;
78 |
79 | /** Custom virtual file system name */
80 |
81 | @property (atomic, copy) NSString *vfsName;
82 |
83 | ///----------------------------------------------------
84 | /// @name Initialization, opening, and closing of queue
85 | ///----------------------------------------------------
86 |
87 | /** Create queue using path.
88 |
89 | @param aPath The file path of the database.
90 |
91 | @return The `FMDatabaseQueue` object. `nil` on error.
92 | */
93 |
94 | + (instancetype)databaseQueueWithPath:(NSString*)aPath;
95 |
96 | /** Create queue using path and specified flags.
97 |
98 | @param aPath The file path of the database.
99 | @param openFlags Flags passed to the openWithFlags method of the database
100 |
101 | @return The `FMDatabaseQueue` object. `nil` on error.
102 | */
103 | + (instancetype)databaseQueueWithPath:(NSString*)aPath flags:(int)openFlags;
104 |
105 | /** Create queue using path.
106 |
107 | @param aPath The file path of the database.
108 |
109 | @return The `FMDatabaseQueue` object. `nil` on error.
110 | */
111 |
112 | - (instancetype)initWithPath:(NSString*)aPath;
113 |
114 | /** Create queue using path and specified flags.
115 |
116 | @param aPath The file path of the database.
117 | @param openFlags Flags passed to the openWithFlags method of the database
118 |
119 | @return The `FMDatabaseQueue` object. `nil` on error.
120 | */
121 |
122 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags;
123 |
124 | /** Create queue using path and specified flags.
125 |
126 | @param aPath The file path of the database.
127 | @param openFlags Flags passed to the openWithFlags method of the database
128 | @param vfsName The name of a custom virtual file system
129 |
130 | @return The `FMDatabaseQueue` object. `nil` on error.
131 | */
132 |
133 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags vfs:(NSString *)vfsName;
134 |
135 | /** Returns the Class of 'FMDatabase' subclass, that will be used to instantiate database object.
136 |
137 | Subclasses can override this method to return specified Class of 'FMDatabase' subclass.
138 |
139 | @return The Class of 'FMDatabase' subclass, that will be used to instantiate database object.
140 | */
141 |
142 | + (Class)databaseClass;
143 |
144 | /** Close database used by queue. */
145 |
146 | - (void)close;
147 |
148 | ///-----------------------------------------------
149 | /// @name Dispatching database operations to queue
150 | ///-----------------------------------------------
151 |
152 | /** Synchronously perform database operations on queue.
153 |
154 | @param block The code to be run on the queue of `FMDatabaseQueue`
155 | */
156 |
157 | - (void)inDatabase:(void (^)(FMDatabase *db))block;
158 |
159 | /** Synchronously perform database operations on queue, using transactions.
160 |
161 | @param block The code to be run on the queue of `FMDatabaseQueue`
162 | */
163 |
164 | - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block;
165 |
166 | /** Synchronously perform database operations on queue, using deferred transactions.
167 |
168 | @param block The code to be run on the queue of `FMDatabaseQueue`
169 | */
170 |
171 | - (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block;
172 |
173 | ///-----------------------------------------------
174 | /// @name Dispatching database operations to queue
175 | ///-----------------------------------------------
176 |
177 | /** Synchronously perform database operations using save point.
178 |
179 | @param block The code to be run on the queue of `FMDatabaseQueue`
180 | */
181 |
182 | // NOTE: you can not nest these, since calling it will pull another database out of the pool and you'll get a deadlock.
183 | // If you need to nest, use FMDatabase's startSavePointWithName:error: instead.
184 | - (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block;
185 |
186 | @end
187 |
188 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/DataSoure/Service/JYDBService.m:
--------------------------------------------------------------------------------
1 | //
2 | // JYDBService.m
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/5/9.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import "JYDBService.h"
10 | #import "JYPersonDB.h"
11 | #import "JYGradeTable.h"
12 | #import "JYGradeInfo.h"
13 | #import "JYClassTable.h"
14 | #import "JYClassInfo.h"
15 | #import "JYPersonTable.h"
16 | #import "JYPersonInfo.h"
17 |
18 | @interface JYDBService ()
19 |
20 | @property (nonatomic, strong) JYPersonDB *personDB;
21 |
22 | @end
23 |
24 | @implementation JYDBService
25 |
26 | + (instancetype)shared{
27 | static JYDBService *globalService = nil;
28 | static dispatch_once_t onceToken;
29 | dispatch_once(&onceToken, ^{
30 | globalService = [[JYDBService alloc] init];
31 | globalService.personDB = [JYPersonDB storage];
32 | });
33 | return globalService;
34 | }
35 |
36 | # pragma mark JYGradeInfo operation
37 | - (void)insertGradeInfo:(JYGradeInfo *)aGradeInfo{
38 | [self.personDB.gradeTable insertContent:aGradeInfo];
39 | }
40 |
41 | - (void)insertGradeInfos:(NSArray *)aGradeInfos{
42 | [self.personDB.gradeTable insertContents:aGradeInfos];
43 | }
44 |
45 | - (void)insertIndependentGradeInfo:(JYGradeInfo *)aGradeInfo{
46 | [self.personDB.gradeTable insertIndependentContent:aGradeInfo];
47 | }
48 |
49 | - (void)insertIndependentGradeInfos:(NSArray *)aGradeInfos{
50 | [self.personDB.gradeTable insertIndependentContents:aGradeInfos];
51 | }
52 |
53 | - (NSArray *)getGradeInfoByConditions:(void (^)(JYQueryConditions *make))block{
54 | return [self.personDB.gradeTable getContentByConditions:block];
55 | }
56 |
57 | - (JYGradeInfo *)getGradeInfo:(NSString*)aGradeInfoID{
58 | return [self.personDB.gradeTable getContentByID:aGradeInfoID];
59 | }
60 |
61 | - (NSArray *)getGradeInfos:(NSArray *)aGradeInfoIDs{
62 | return [self.personDB.gradeTable getContentByIDs:aGradeInfoIDs];
63 | }
64 |
65 | - (NSArray *)getAllGradeInfo{
66 | return [self.personDB.gradeTable getAllContent];
67 | }
68 |
69 | - (void)deleteGradeInfoByConditions:(void (^)(JYQueryConditions *make))block{
70 | return [self.personDB.gradeTable deleteContentByConditions:block];
71 | }
72 |
73 | - (void)deleteGradeInfos:(NSArray*)aGradeInfoIDs{
74 | [self.personDB.gradeTable deleteContentByIDs:aGradeInfoIDs];
75 | }
76 |
77 | - (void)deleteGradeInfo:(NSString *)aGradeInfoID{
78 | [self.personDB.gradeTable deleteContentByID:aGradeInfoID];
79 | }
80 |
81 | - (void)deleteAllGradeInfo{
82 | [self.personDB.gradeTable deleteAllContent];
83 | }
84 |
85 | - (void)cleanGradeInfoBefore:(NSDate*)date{
86 | [self.personDB.gradeTable cleanContentBefore:date];
87 | }
88 |
89 | - (NSInteger)getGradeInfoCountByConditions:(void (^)(JYQueryConditions *make))block{
90 | return [self.personDB.gradeTable getCountByConditions:block];
91 | }
92 |
93 | - (NSInteger)getGradeInfoAllCount{
94 | return [self.personDB.gradeTable getAllCount];
95 | }
96 |
97 |
98 | # pragma mark JYClassInfo operation
99 | - (void)insertClassInfo:(JYClassInfo *)aClassInfo{
100 | [self.personDB.classTable insertContent:aClassInfo];
101 | }
102 |
103 | - (void)insertClassInfos:(NSArray *)aClassInfos{
104 | [self.personDB.classTable insertContents:aClassInfos];
105 | }
106 |
107 | - (void)insertIndependentClassInfo:(JYClassInfo *)aClassInfo{
108 | [self.personDB.classTable insertIndependentContent:aClassInfo];
109 | }
110 |
111 | - (void)insertIndependentClassInfos:(NSArray *)aClassInfos{
112 | [self.personDB.classTable insertIndependentContents:aClassInfos];
113 | }
114 |
115 | - (NSArray *)getClassInfoByConditions:(void (^)(JYQueryConditions *make))block{
116 | return [self.personDB.classTable getContentByConditions:block];
117 | }
118 |
119 | - (JYClassInfo *)getClassInfo:(NSString*)aClassInfoID{
120 | return [self.personDB.classTable getContentByID:aClassInfoID];
121 | }
122 |
123 | - (NSArray *)getClassInfos:(NSArray *)aClassInfoIDs{
124 | return [self.personDB.classTable getContentByIDs:aClassInfoIDs];
125 | }
126 |
127 | - (NSArray *)getAllClassInfo{
128 | return [self.personDB.classTable getAllContent];
129 | }
130 |
131 | - (void)deleteClassInfoByConditions:(void (^)(JYQueryConditions *make))block{
132 | return [self.personDB.classTable deleteContentByConditions:block];
133 | }
134 |
135 | - (void)deleteClassInfos:(NSArray*)aClassInfoIDs{
136 | [self.personDB.classTable deleteContentByIDs:aClassInfoIDs];
137 | }
138 |
139 | - (void)deleteClassInfo:(NSString *)aClassInfoID{
140 | [self.personDB.classTable deleteContentByID:aClassInfoID];
141 | }
142 |
143 | - (void)deleteAllClassInfo{
144 | [self.personDB.classTable deleteAllContent];
145 | }
146 |
147 | - (void)cleanClassInfoBefore:(NSDate*)date{
148 | [self.personDB.classTable cleanContentBefore:date];
149 | }
150 |
151 | - (NSInteger)getClassInfoCountByConditions:(void (^)(JYQueryConditions *make))block{
152 | return [self.personDB.classTable getCountByConditions:block];
153 | }
154 |
155 | - (NSInteger)getClassInfoAllCount{
156 | return [self.personDB.classTable getAllCount];
157 | }
158 |
159 | # pragma mark JYPersonInfo operation
160 | - (void)insertPersonInfo:(JYPersonInfo *)aPersonInfo{
161 | [self.personDB.personTable insertContent:aPersonInfo];
162 | }
163 |
164 | - (void)insertPersonInfos:(NSArray *)aPersonInfos{
165 | [self.personDB.personTable insertContents:aPersonInfos];
166 | }
167 |
168 | - (void)insertIndependentPersonInfo:(JYPersonInfo *)aPersonInfo{
169 | [self.personDB.personTable insertIndependentContent:aPersonInfo];
170 | }
171 |
172 | - (void)insertIndependentPersonInfos:(NSArray *)aPersonInfos{
173 | [self.personDB.personTable insertIndependentContents:aPersonInfos];
174 | }
175 |
176 | - (NSArray *)getPersonInfoByConditions:(void (^)(JYQueryConditions *make))block{
177 | return [self.personDB.personTable getContentByConditions:block];
178 | }
179 |
180 | - (JYPersonInfo *)getPersonInfo:(NSString*)aPersonInfoID{
181 | return [self.personDB.personTable getContentByID:aPersonInfoID];
182 | }
183 |
184 | - (NSArray *)getPersonInfos:(NSArray *)aPersonInfoIDs{
185 | return [self.personDB.personTable getContentByIDs:aPersonInfoIDs];
186 | }
187 |
188 | - (NSArray *)getAllPersonInfo{
189 | return [self.personDB.personTable getAllContent];
190 | }
191 |
192 | - (void)deletePersonInfoByConditions:(void (^)(JYQueryConditions *make))block{
193 | return [self.personDB.personTable deleteContentByConditions:block];
194 | }
195 |
196 | - (void)deletePersonInfos:(NSArray*)aPersonInfoIDs{
197 | [self.personDB.personTable deleteContentByIDs:aPersonInfoIDs];
198 | }
199 |
200 | - (void)deletePersonInfo:(NSString *)aPersonInfoID{
201 | [self.personDB.personTable deleteContentByID:aPersonInfoID];
202 | }
203 |
204 | - (void)deleteAllPersonInfo{
205 | [self.personDB.personTable deleteAllContent];
206 | }
207 |
208 | - (void)cleanPersonInfoBefore:(NSDate*)date{
209 | [self.personDB.personTable cleanContentBefore:date];
210 | }
211 |
212 | - (NSInteger)getPersonInfoCountByConditions:(void (^)(JYQueryConditions *make))block{
213 | return [self.personDB.personTable getCountByConditions:block];
214 | }
215 |
216 | - (NSInteger)getPersonInfoAllCount{
217 | return [self.personDB.personTable getAllCount];
218 | }
219 |
220 | @end
221 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/JYDatabase/fmdb/FMDatabaseQueue.m:
--------------------------------------------------------------------------------
1 | //
2 | // FMDatabaseQueue.m
3 | // fmdb
4 | //
5 | // Created by August Mueller on 6/22/11.
6 | // Copyright 2011 Flying Meat Inc. All rights reserved.
7 | //
8 |
9 | #import "FMDatabaseQueue.h"
10 | #import "FMDatabase.h"
11 |
12 | #if FMDB_SQLITE_STANDALONE
13 | #import
14 | #else
15 | #import
16 | #endif
17 |
18 | /*
19 |
20 | Note: we call [self retain]; before using dispatch_sync, just incase
21 | FMDatabaseQueue is released on another thread and we're in the middle of doing
22 | something in dispatch_sync
23 |
24 | */
25 |
26 | /*
27 | * A key used to associate the FMDatabaseQueue object with the dispatch_queue_t it uses.
28 | * This in turn is used for deadlock detection by seeing if inDatabase: is called on
29 | * the queue's dispatch queue, which should not happen and causes a deadlock.
30 | */
31 | static const void * const kDispatchQueueSpecificKey = &kDispatchQueueSpecificKey;
32 |
33 | @implementation FMDatabaseQueue
34 |
35 | @synthesize path = _path;
36 | @synthesize openFlags = _openFlags;
37 | @synthesize vfsName = _vfsName;
38 |
39 | + (instancetype)databaseQueueWithPath:(NSString*)aPath {
40 |
41 | FMDatabaseQueue *q = [[self alloc] initWithPath:aPath];
42 |
43 | FMDBAutorelease(q);
44 |
45 | return q;
46 | }
47 |
48 | + (instancetype)databaseQueueWithPath:(NSString*)aPath flags:(int)openFlags {
49 |
50 | FMDatabaseQueue *q = [[self alloc] initWithPath:aPath flags:openFlags];
51 |
52 | FMDBAutorelease(q);
53 |
54 | return q;
55 | }
56 |
57 | + (Class)databaseClass {
58 | return [FMDatabase class];
59 | }
60 |
61 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags vfs:(NSString *)vfsName {
62 |
63 | self = [super init];
64 |
65 | if (self != nil) {
66 |
67 | _db = [[[self class] databaseClass] databaseWithPath:aPath];
68 | FMDBRetain(_db);
69 |
70 | #if SQLITE_VERSION_NUMBER >= 3005000
71 | BOOL success = [_db openWithFlags:openFlags vfs:vfsName];
72 | #else
73 | BOOL success = [_db open];
74 | #endif
75 | if (!success) {
76 | NSLog(@"Could not create database queue for path %@", aPath);
77 | FMDBRelease(self);
78 | return 0x00;
79 | }
80 |
81 | _path = FMDBReturnRetained(aPath);
82 |
83 | _queue = dispatch_queue_create([[NSString stringWithFormat:@"fmdb.%@", self] UTF8String], NULL);
84 | dispatch_queue_set_specific(_queue, kDispatchQueueSpecificKey, (__bridge void *)self, NULL);
85 | _openFlags = openFlags;
86 | _vfsName = [vfsName copy];
87 | }
88 |
89 | return self;
90 | }
91 |
92 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags {
93 | return [self initWithPath:aPath flags:openFlags vfs:nil];
94 | }
95 |
96 | - (instancetype)initWithPath:(NSString*)aPath {
97 |
98 | // default flags for sqlite3_open
99 | return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE vfs:nil];
100 | }
101 |
102 | - (instancetype)init {
103 | return [self initWithPath:nil];
104 | }
105 |
106 |
107 | - (void)dealloc {
108 |
109 | FMDBRelease(_db);
110 | FMDBRelease(_path);
111 |
112 | if (_queue) {
113 | FMDBDispatchQueueRelease(_queue);
114 | _queue = 0x00;
115 | }
116 | #if ! __has_feature(objc_arc)
117 | [super dealloc];
118 | #endif
119 | }
120 |
121 | - (void)close {
122 | FMDBRetain(self);
123 | dispatch_sync(_queue, ^() {
124 | [self->_db close];
125 | FMDBRelease(_db);
126 | self->_db = 0x00;
127 | });
128 | FMDBRelease(self);
129 | }
130 |
131 | - (FMDatabase*)database {
132 | if (!_db) {
133 | _db = FMDBReturnRetained([[[self class] databaseClass] databaseWithPath:_path]);
134 |
135 | #if SQLITE_VERSION_NUMBER >= 3005000
136 | BOOL success = [_db openWithFlags:_openFlags vfs:_vfsName];
137 | #else
138 | BOOL success = [_db open];
139 | #endif
140 | if (!success) {
141 | NSLog(@"FMDatabaseQueue could not reopen database for path %@", _path);
142 | FMDBRelease(_db);
143 | _db = 0x00;
144 | return 0x00;
145 | }
146 | }
147 |
148 | return _db;
149 | }
150 |
151 | - (void)inDatabase:(void (^)(FMDatabase *db))block {
152 | /* Get the currently executing queue (which should probably be nil, but in theory could be another DB queue
153 | * and then check it against self to make sure we're not about to deadlock. */
154 | FMDatabaseQueue *currentSyncQueue = (__bridge id)dispatch_get_specific(kDispatchQueueSpecificKey);
155 | assert(currentSyncQueue != self && "inDatabase: was called reentrantly on the same queue, which would lead to a deadlock");
156 |
157 | FMDBRetain(self);
158 |
159 | dispatch_sync(_queue, ^() {
160 |
161 | FMDatabase *db = [self database];
162 | block(db);
163 |
164 | if ([db hasOpenResultSets]) {
165 | NSLog(@"Warning: there is at least one open result set around after performing [FMDatabaseQueue inDatabase:]");
166 |
167 | #if defined(DEBUG) && DEBUG
168 | NSSet *openSetCopy = FMDBReturnAutoreleased([[db valueForKey:@"_openResultSets"] copy]);
169 | for (NSValue *rsInWrappedInATastyValueMeal in openSetCopy) {
170 | FMResultSet *rs = (FMResultSet *)[rsInWrappedInATastyValueMeal pointerValue];
171 | NSLog(@"query: '%@'", [rs query]);
172 | }
173 | #endif
174 | }
175 | });
176 |
177 | FMDBRelease(self);
178 | }
179 |
180 |
181 | - (void)beginTransaction:(BOOL)useDeferred withBlock:(void (^)(FMDatabase *db, BOOL *rollback))block {
182 | FMDBRetain(self);
183 | dispatch_sync(_queue, ^() {
184 |
185 | BOOL shouldRollback = NO;
186 |
187 | if (useDeferred) {
188 | [[self database] beginDeferredTransaction];
189 | }
190 | else {
191 | [[self database] beginTransaction];
192 | }
193 |
194 | block([self database], &shouldRollback);
195 |
196 | if (shouldRollback) {
197 | [[self database] rollback];
198 | }
199 | else {
200 | [[self database] commit];
201 | }
202 | });
203 |
204 | FMDBRelease(self);
205 | }
206 |
207 | - (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block {
208 | [self beginTransaction:YES withBlock:block];
209 | }
210 |
211 | - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block {
212 | [self beginTransaction:NO withBlock:block];
213 | }
214 |
215 | - (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block {
216 | #if SQLITE_VERSION_NUMBER >= 3007000
217 | static unsigned long savePointIdx = 0;
218 | __block NSError *err = 0x00;
219 | FMDBRetain(self);
220 | dispatch_sync(_queue, ^() {
221 |
222 | NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++];
223 |
224 | BOOL shouldRollback = NO;
225 |
226 | if ([[self database] startSavePointWithName:name error:&err]) {
227 |
228 | block([self database], &shouldRollback);
229 |
230 | if (shouldRollback) {
231 | // We need to rollback and release this savepoint to remove it
232 | [[self database] rollbackToSavePointWithName:name error:&err];
233 | }
234 | [[self database] releaseSavePointWithName:name error:&err];
235 |
236 | }
237 | });
238 | FMDBRelease(self);
239 | return err;
240 | #else
241 | NSString *errorMessage = NSLocalizedString(@"Save point functions require SQLite 3.7", nil);
242 | if (self.logsErrors) NSLog(@"%@", errorMessage);
243 | return [NSError errorWithDomain:@"FMDatabase" code:0 userInfo:@{NSLocalizedDescriptionKey : errorMessage}];
244 | #endif
245 | }
246 |
247 | @end
248 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OCTests/JYContentTableTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // JYContentTableTest.m
3 | // JYDatabase - OC
4 | //
5 | // Created by weijingyun on 16/11/21.
6 | // Copyright © 2016年 weijingyun. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "JYDBService.h"
11 | #import "JYGradeInfo.h"
12 | #import "JYClassInfo.h"
13 | #import "JYPersonInfo.h"
14 |
15 | @interface JYContentTableTest : XCTestCase
16 |
17 | @end
18 |
19 | @implementation JYContentTableTest
20 |
21 | - (void)testExample {
22 | // This is an example of a functional test case.
23 | // Use XCTAssert and related functions to verify your tests produce the correct results.
24 | JYGradeInfo *gradeInfo = [self getGradeInfo];
25 | // 插入数据
26 | [[JYDBService shared] insertGradeInfo:gradeInfo];
27 |
28 | // 查询数据
29 | JYGradeInfo *queryGradeInfo = [[JYDBService shared] getGradeInfo:gradeInfo.gradeID];
30 | BOOL isEqual = [self gradeInfo:gradeInfo equalTo:queryGradeInfo];
31 | XCTAssert(isEqual);
32 | //修改数据再插入
33 | gradeInfo.gradeName = @"修改后的 gradeName";
34 | [[JYDBService shared] insertGradeInfo:gradeInfo];
35 |
36 | // 查询出全部的
37 | NSArray*queryGradeInfos = [[JYDBService shared] getAllGradeInfo];
38 | NSInteger count = [[JYDBService shared] getGradeInfoAllCount];
39 | XCTAssert(count == queryGradeInfos.count);
40 | [queryGradeInfos enumerateObjectsUsingBlock:^(JYGradeInfo * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
41 | if ([obj.gradeID isEqualToString:gradeInfo.gradeID]) {
42 | XCTAssert([obj.gradeName isEqualToString:@"修改后的 gradeName"]);
43 | *stop = YES;
44 | }
45 | }];
46 |
47 | //删除该条数据
48 | [[JYDBService shared] deleteGradeInfo:gradeInfo.gradeID];
49 |
50 | //最后获取为空
51 | queryGradeInfo = [[JYDBService shared] getGradeInfo:gradeInfo.gradeID];
52 | XCTAssert(queryGradeInfo == nil);
53 |
54 | //清理所有数据
55 | [[JYDBService shared] deleteAllGradeInfo];
56 | queryGradeInfos = [[JYDBService shared] getAllGradeInfo];
57 | XCTAssert(queryGradeInfos.count == 0);
58 | }
59 |
60 | - (JYGradeInfo *)getGradeInfo{
61 |
62 | JYGradeInfo *gradeInfo = [[JYGradeInfo alloc] init];
63 | gradeInfo.gradeID = [NSString stringWithFormat:@"%f",[NSDate date].timeIntervalSince1970];
64 | gradeInfo.gradeName = @"gradeName";
65 | gradeInfo.longlongText = @"安拉说萨达斯大使鲁大师解答索朗多吉阿斯利康多久啊索朗多吉啊索朗多吉撒了肯德基卢萨卡的就阿斯利康大家阿拉山口大家卢萨卡的家啊索朗多吉啊索朗多吉萨里看到卢卡斯家里打扫家里的空间啊算了撒进来看到就撒了肯德基拉萨卡就收到啦升级到了撒娇的拉萨觉得萨鲁大师萨的旅客撒娇的拉萨金德拉克撒大家拉萨大家卢萨卡大家啦可是大家啊索朗多吉啊上课绝对拉升阶段拉萨肯德基卢萨卡就到拉萨肯德基拉萨肯德基拉萨的就撒了点酒洒了肯德基拉萨肯德基拉萨到拉萨的教练萨大家撒了点结束啦大家拉萨大家拉萨短裤收到了撒娇第六十九阿拉丁就撒了点酒撒了点酒洒落到家啦时间的撒了空间的拉萨到了撒娇的理解啊圣诞节啊圣诞节啊时间都撒到家啦圣诞节阿斯利康大家撒了肯德基撒了肯德基啊索朗多吉撒了点酒撒";
66 | NSMutableArray *arrayM = [[NSMutableArray alloc] init];
67 | for (int i = 0 ; i < 10; i ++) {
68 | JYClassInfo *classInfo = [self getClassInfoForGradeID:gradeInfo.gradeID];
69 | [arrayM addObject:classInfo];
70 | }
71 | gradeInfo.allClass = [arrayM copy];
72 | return gradeInfo;
73 | }
74 |
75 | - (JYClassInfo *)getClassInfoForGradeID:(NSString *)gradeID{
76 |
77 | JYClassInfo *classInfo = [[JYClassInfo alloc] init];
78 | classInfo.classID = [NSString stringWithFormat:@"%f",[NSDate date].timeIntervalSince1970];
79 | classInfo.gradeID = gradeID;
80 | classInfo.className = @"className";
81 | classInfo.teacher = [self getPersonInfoForTeacherClassID:classInfo.classID studentClassID:nil studentIdx:0];
82 | classInfo.students = [[NSMutableArray alloc] init];
83 | for (int i = 0; i < 50; i ++) {
84 | JYPersonInfo *student = [self getPersonInfoForTeacherClassID:nil studentClassID:classInfo.classID studentIdx:i];
85 | [classInfo.students addObject:student];
86 | }
87 | return classInfo;
88 | }
89 |
90 | - (JYPersonInfo *)getPersonInfoForTeacherClassID:(NSString *)teacherClassID studentClassID:(NSString *)studentClassID studentIdx:(NSInteger)idx{
91 |
92 | JYPersonInfo *personInfo = [[JYPersonInfo alloc] init];
93 | personInfo.personID = [NSString stringWithFormat:@"%f",[NSDate date].timeIntervalSince1970];
94 | personInfo.teacherClassID = teacherClassID;
95 | personInfo.studentClassID = studentClassID;
96 | personInfo.studentIdx = idx;
97 | personInfo.mutableString1 = [@"mutableString1" mutableCopy];
98 | personInfo.array = @[@"array1",@"array2"];
99 | personInfo.arrayM = [@[@"arrayM1",@"arrayM2"] mutableCopy];
100 | personInfo.dic = @{@"dic11":@"dic12",
101 | @"dic21":@"dic22"
102 | };
103 | personInfo.dicM = [@{@"dicM11":@"dicM12",
104 | @"dicM21":@"dicM22"
105 | } mutableCopy];
106 | personInfo.integer1 = -100;
107 | personInfo.uInteger1 = 100;
108 | personInfo.int1 = 10;
109 | personInfo.bool1 = YES;
110 | personInfo.double1 = 2.5;
111 | personInfo.float1 = 0.33;
112 | personInfo.cgfloat1 = 3.333;
113 | personInfo.number = [NSNumber numberWithDouble:0.55];
114 | return personInfo;
115 | }
116 |
117 | - (BOOL)gradeInfo:(JYGradeInfo *)gradeInfo1 equalTo:(JYGradeInfo *)gradeInfo2{
118 |
119 | __block BOOL isEqual = YES;
120 | NSArray*keys = @[@"gradeID",@"gradeName",@"longlongText"];
121 | isEqual &= [self mode:gradeInfo1 equalTo:gradeInfo2 forKeys:keys];
122 | XCTAssert([gradeInfo2.allClass isKindOfClass:[NSArray class]] && ![gradeInfo2.allClass isKindOfClass:[NSMutableArray class]]);
123 | [gradeInfo1.allClass enumerateObjectsUsingBlock:^(JYClassInfo * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
124 | isEqual &= [self classInfo:obj equalTo:gradeInfo2.allClass[idx]];
125 | }];
126 | return isEqual;
127 |
128 | }
129 |
130 |
131 | - (BOOL)classInfo:(JYClassInfo *)classInfo1 equalTo:(JYClassInfo *)classInfo2{
132 |
133 | __block BOOL isEqual = YES;
134 | NSArray*keys = @[@"classID",@"gradeID",@"className"];
135 | isEqual &= [self mode:classInfo1 equalTo:classInfo2 forKeys:keys];
136 | isEqual &= [self personInfo:classInfo1.teacher equalTo:classInfo2.teacher];
137 | XCTAssert([classInfo2.students isKindOfClass:[NSMutableArray class]]);
138 | [classInfo1.students enumerateObjectsUsingBlock:^(JYPersonInfo * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
139 | isEqual &= [self personInfo:obj equalTo:classInfo2.students[idx]];
140 | }];
141 | return isEqual;
142 | }
143 |
144 | - (BOOL)personInfo:(JYPersonInfo *)personInfo1 equalTo:(JYPersonInfo *)personInfo2 {
145 |
146 | __block BOOL isEqual = YES;
147 | NSArray*keys = @[@"personID",@"teacherClassID",@"studentClassID"];
148 | isEqual &= [self mode:personInfo1 equalTo:personInfo2 forKeys:keys];
149 | [personInfo1.array.firstObject isEqualToString:personInfo2.array.firstObject];
150 | [personInfo1.arrayM.firstObject isEqualToString:personInfo2.arrayM.firstObject];
151 | [personInfo1.dic[@"dic11"] isEqualToString:personInfo2.dic[@"dic11"]];
152 | [personInfo1.dicM[@"dic12"] isEqualToString:personInfo2.dicM[@"dic12"]];
153 | // 浮点数会有些许偏差
154 | isEqual &= personInfo1.integer1 == personInfo2.integer1;
155 | isEqual &= personInfo1.uInteger1 == personInfo2.uInteger1;
156 | isEqual &= labs(personInfo1.int1 - personInfo2.int1) < 0.00001;
157 | isEqual &= personInfo1.bool1 == personInfo2.bool1;
158 | isEqual &= fabs(personInfo1.double1 - personInfo2.double1) < 0.00001;
159 | isEqual &= fabsf(personInfo1.float1 - personInfo2.float1) < 0.00001;
160 | isEqual &= fabs(personInfo1.cgfloat1 - personInfo2.cgfloat1) < 0.00001;
161 | return isEqual;
162 | }
163 |
164 | // 只支持简单的 NSString 检测
165 | - (BOOL)mode:(id)model1 equalTo:(id)model2 forKeys:(NSArray *)keys{
166 | __block BOOL isEqual = YES;
167 | [keys enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
168 | id v1 = [model1 valueForKey:obj];
169 | id v2 = [model2 valueForKey:obj];
170 | if (v1 == nil && v2 == nil) {
171 |
172 | }else if ([v1 isKindOfClass:[NSString class]]) {
173 | isEqual &= [[v1 copy] isEqual:[v2 copy]];
174 | if (!isEqual) {
175 | NSLog(@"%@--%@",v1,v2);
176 | }
177 | }else{
178 | isEqual = NO;
179 | NSLog(@"%@--%@不支持该类型检测",v1,v2);
180 | }
181 | }];
182 | return isEqual;
183 | }
184 |
185 | @end
186 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/JYDatabase/fmdb/FMDatabaseAdditions.m:
--------------------------------------------------------------------------------
1 | //
2 | // FMDatabaseAdditions.m
3 | // fmdb
4 | //
5 | // Created by August Mueller on 10/30/05.
6 | // Copyright 2005 Flying Meat Inc.. All rights reserved.
7 | //
8 |
9 | #import "FMDatabase.h"
10 | #import "FMDatabaseAdditions.h"
11 | #import "TargetConditionals.h"
12 |
13 | #if FMDB_SQLITE_STANDALONE
14 | #import
15 | #else
16 | #import
17 | #endif
18 |
19 | @interface FMDatabase (PrivateStuff)
20 | - (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args;
21 | @end
22 |
23 | @implementation FMDatabase (FMDatabaseAdditions)
24 |
25 | #define RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(type, sel) \
26 | va_list args; \
27 | va_start(args, query); \
28 | FMResultSet *resultSet = [self executeQuery:query withArgumentsInArray:0x00 orDictionary:0x00 orVAList:args]; \
29 | va_end(args); \
30 | if (![resultSet next]) { return (type)0; } \
31 | type ret = [resultSet sel:0]; \
32 | [resultSet close]; \
33 | [resultSet setParentDB:nil]; \
34 | return ret;
35 |
36 |
37 | - (NSString*)stringForQuery:(NSString*)query, ... {
38 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSString *, stringForColumnIndex);
39 | }
40 |
41 | - (int)intForQuery:(NSString*)query, ... {
42 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(int, intForColumnIndex);
43 | }
44 |
45 | - (long)longForQuery:(NSString*)query, ... {
46 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(long, longForColumnIndex);
47 | }
48 |
49 | - (BOOL)boolForQuery:(NSString*)query, ... {
50 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(BOOL, boolForColumnIndex);
51 | }
52 |
53 | - (double)doubleForQuery:(NSString*)query, ... {
54 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(double, doubleForColumnIndex);
55 | }
56 |
57 | - (NSData*)dataForQuery:(NSString*)query, ... {
58 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSData *, dataForColumnIndex);
59 | }
60 |
61 | - (NSDate*)dateForQuery:(NSString*)query, ... {
62 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSDate *, dateForColumnIndex);
63 | }
64 |
65 |
66 | - (BOOL)tableExists:(NSString*)tableName {
67 |
68 | tableName = [tableName lowercaseString];
69 |
70 | FMResultSet *rs = [self executeQuery:@"select [sql] from sqlite_master where [type] = 'table' and lower(name) = ?", tableName];
71 |
72 | //if at least one next exists, table exists
73 | BOOL returnBool = [rs next];
74 |
75 | //close and free object
76 | [rs close];
77 |
78 | return returnBool;
79 | }
80 |
81 | /*
82 | get table with list of tables: result colums: type[STRING], name[STRING],tbl_name[STRING],rootpage[INTEGER],sql[STRING]
83 | check if table exist in database (patch from OZLB)
84 | */
85 | - (FMResultSet*)getSchema {
86 |
87 | //result colums: type[STRING], name[STRING],tbl_name[STRING],rootpage[INTEGER],sql[STRING]
88 | FMResultSet *rs = [self executeQuery:@"SELECT type, name, tbl_name, rootpage, sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type != 'meta' AND name NOT LIKE 'sqlite_%' ORDER BY tbl_name, type DESC, name"];
89 |
90 | return rs;
91 | }
92 |
93 | /*
94 | get table schema: result colums: cid[INTEGER], name,type [STRING], notnull[INTEGER], dflt_value[],pk[INTEGER]
95 | */
96 | - (FMResultSet*)getTableSchema:(NSString*)tableName {
97 |
98 | //result colums: cid[INTEGER], name,type [STRING], notnull[INTEGER], dflt_value[],pk[INTEGER]
99 | FMResultSet *rs = [self executeQuery:[NSString stringWithFormat: @"pragma table_info('%@')", tableName]];
100 |
101 | return rs;
102 | }
103 |
104 | - (BOOL)columnExists:(NSString*)columnName inTableWithName:(NSString*)tableName {
105 |
106 | BOOL returnBool = NO;
107 |
108 | tableName = [tableName lowercaseString];
109 | columnName = [columnName lowercaseString];
110 |
111 | FMResultSet *rs = [self getTableSchema:tableName];
112 |
113 | //check if column is present in table schema
114 | while ([rs next]) {
115 | if ([[[rs stringForColumn:@"name"] lowercaseString] isEqualToString:columnName]) {
116 | returnBool = YES;
117 | break;
118 | }
119 | }
120 |
121 | //If this is not done FMDatabase instance stays out of pool
122 | [rs close];
123 |
124 | return returnBool;
125 | }
126 |
127 |
128 |
129 | - (uint32_t)applicationID {
130 | #if SQLITE_VERSION_NUMBER >= 3007017
131 | uint32_t r = 0;
132 |
133 | FMResultSet *rs = [self executeQuery:@"pragma application_id"];
134 |
135 | if ([rs next]) {
136 | r = (uint32_t)[rs longLongIntForColumnIndex:0];
137 | }
138 |
139 | [rs close];
140 |
141 | return r;
142 | #else
143 | NSString *errorMessage = NSLocalizedString(@"Application ID functions require SQLite 3.7.17", nil);
144 | if (self.logsErrors) NSLog(@"%@", errorMessage);
145 | return 0;
146 | #endif
147 | }
148 |
149 | - (void)setApplicationID:(uint32_t)appID {
150 | #if SQLITE_VERSION_NUMBER >= 3007017
151 | NSString *query = [NSString stringWithFormat:@"pragma application_id=%d", appID];
152 | FMResultSet *rs = [self executeQuery:query];
153 | [rs next];
154 | [rs close];
155 | #else
156 | NSString *errorMessage = NSLocalizedString(@"Application ID functions require SQLite 3.7.17", nil);
157 | if (self.logsErrors) NSLog(@"%@", errorMessage);
158 | #endif
159 | }
160 |
161 |
162 | #if TARGET_OS_MAC && !TARGET_OS_IPHONE
163 |
164 | - (NSString*)applicationIDString {
165 | #if SQLITE_VERSION_NUMBER >= 3007017
166 | NSString *s = NSFileTypeForHFSTypeCode([self applicationID]);
167 |
168 | assert([s length] == 6);
169 |
170 | s = [s substringWithRange:NSMakeRange(1, 4)];
171 |
172 |
173 | return s;
174 | #else
175 | NSString *errorMessage = NSLocalizedString(@"Application ID functions require SQLite 3.7.17", nil);
176 | if (self.logsErrors) NSLog(@"%@", errorMessage);
177 | return nil;
178 | #endif
179 | }
180 |
181 | - (void)setApplicationIDString:(NSString*)s {
182 | #if SQLITE_VERSION_NUMBER >= 3007017
183 | if ([s length] != 4) {
184 | NSLog(@"setApplicationIDString: string passed is not exactly 4 chars long. (was %ld)", [s length]);
185 | }
186 |
187 | [self setApplicationID:NSHFSTypeCodeFromFileType([NSString stringWithFormat:@"'%@'", s])];
188 | #else
189 | NSString *errorMessage = NSLocalizedString(@"Application ID functions require SQLite 3.7.17", nil);
190 | if (self.logsErrors) NSLog(@"%@", errorMessage);
191 | #endif
192 | }
193 |
194 | #endif
195 |
196 | - (uint32_t)userVersion {
197 | uint32_t r = 0;
198 |
199 | FMResultSet *rs = [self executeQuery:@"pragma user_version"];
200 |
201 | if ([rs next]) {
202 | r = (uint32_t)[rs longLongIntForColumnIndex:0];
203 | }
204 |
205 | [rs close];
206 | return r;
207 | }
208 |
209 | - (void)setUserVersion:(uint32_t)version {
210 | NSString *query = [NSString stringWithFormat:@"pragma user_version = %d", version];
211 | FMResultSet *rs = [self executeQuery:query];
212 | [rs next];
213 | [rs close];
214 | }
215 |
216 | #pragma clang diagnostic push
217 | #pragma clang diagnostic ignored "-Wdeprecated-implementations"
218 |
219 | - (BOOL)columnExists:(NSString*)tableName columnName:(NSString*)columnName __attribute__ ((deprecated)) {
220 | return [self columnExists:columnName inTableWithName:tableName];
221 | }
222 |
223 | #pragma clang diagnostic pop
224 |
225 |
226 | - (BOOL)validateSQL:(NSString*)sql error:(NSError**)error {
227 | sqlite3_stmt *pStmt = NULL;
228 | BOOL validationSucceeded = YES;
229 |
230 | int rc = sqlite3_prepare_v2(_db, [sql UTF8String], -1, &pStmt, 0);
231 | if (rc != SQLITE_OK) {
232 | validationSucceeded = NO;
233 | if (error) {
234 | *error = [NSError errorWithDomain:NSCocoaErrorDomain
235 | code:[self lastErrorCode]
236 | userInfo:[NSDictionary dictionaryWithObject:[self lastErrorMessage]
237 | forKey:NSLocalizedDescriptionKey]];
238 | }
239 | }
240 |
241 | sqlite3_finalize(pStmt);
242 |
243 | return validationSucceeded;
244 | }
245 |
246 | @end
247 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/JYDatabase/fmdb/FMDatabaseAdditions.h:
--------------------------------------------------------------------------------
1 | //
2 | // FMDatabaseAdditions.h
3 | // fmdb
4 | //
5 | // Created by August Mueller on 10/30/05.
6 | // Copyright 2005 Flying Meat Inc.. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "FMDatabase.h"
11 |
12 |
13 | /** Category of additions for `` class.
14 |
15 | ### See also
16 |
17 | - ``
18 | */
19 |
20 | @interface FMDatabase (FMDatabaseAdditions)
21 |
22 | ///----------------------------------------
23 | /// @name Return results of SQL to variable
24 | ///----------------------------------------
25 |
26 | /** Return `int` value for query
27 |
28 | @param query The SQL query to be performed.
29 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query.
30 |
31 | @return `int` value.
32 |
33 | @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project.
34 | */
35 |
36 | - (int)intForQuery:(NSString*)query, ...;
37 |
38 | /** Return `long` value for query
39 |
40 | @param query The SQL query to be performed.
41 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query.
42 |
43 | @return `long` value.
44 |
45 | @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project.
46 | */
47 |
48 | - (long)longForQuery:(NSString*)query, ...;
49 |
50 | /** Return `BOOL` value for query
51 |
52 | @param query The SQL query to be performed.
53 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query.
54 |
55 | @return `BOOL` value.
56 |
57 | @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project.
58 | */
59 |
60 | - (BOOL)boolForQuery:(NSString*)query, ...;
61 |
62 | /** Return `double` value for query
63 |
64 | @param query The SQL query to be performed.
65 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query.
66 |
67 | @return `double` value.
68 |
69 | @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project.
70 | */
71 |
72 | - (double)doubleForQuery:(NSString*)query, ...;
73 |
74 | /** Return `NSString` value for query
75 |
76 | @param query The SQL query to be performed.
77 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query.
78 |
79 | @return `NSString` value.
80 |
81 | @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project.
82 | */
83 |
84 | - (NSString*)stringForQuery:(NSString*)query, ...;
85 |
86 | /** Return `NSData` value for query
87 |
88 | @param query The SQL query to be performed.
89 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query.
90 |
91 | @return `NSData` value.
92 |
93 | @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project.
94 | */
95 |
96 | - (NSData*)dataForQuery:(NSString*)query, ...;
97 |
98 | /** Return `NSDate` value for query
99 |
100 | @param query The SQL query to be performed.
101 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query.
102 |
103 | @return `NSDate` value.
104 |
105 | @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project.
106 | */
107 |
108 | - (NSDate*)dateForQuery:(NSString*)query, ...;
109 |
110 |
111 | // Notice that there's no dataNoCopyForQuery:.
112 | // That would be a bad idea, because we close out the result set, and then what
113 | // happens to the data that we just didn't copy? Who knows, not I.
114 |
115 |
116 | ///--------------------------------
117 | /// @name Schema related operations
118 | ///--------------------------------
119 |
120 | /** Does table exist in database?
121 |
122 | @param tableName The name of the table being looked for.
123 |
124 | @return `YES` if table found; `NO` if not found.
125 | */
126 |
127 | - (BOOL)tableExists:(NSString*)tableName;
128 |
129 | /** The schema of the database.
130 |
131 | This will be the schema for the entire database. For each entity, each row of the result set will include the following fields:
132 |
133 | - `type` - The type of entity (e.g. table, index, view, or trigger)
134 | - `name` - The name of the object
135 | - `tbl_name` - The name of the table to which the object references
136 | - `rootpage` - The page number of the root b-tree page for tables and indices
137 | - `sql` - The SQL that created the entity
138 |
139 | @return `FMResultSet` of schema; `nil` on error.
140 |
141 | @see [SQLite File Format](http://www.sqlite.org/fileformat.html)
142 | */
143 |
144 | - (FMResultSet*)getSchema;
145 |
146 | /** The schema of the database.
147 |
148 | This will be the schema for a particular table as report by SQLite `PRAGMA`, for example:
149 |
150 | PRAGMA table_info('employees')
151 |
152 | This will report:
153 |
154 | - `cid` - The column ID number
155 | - `name` - The name of the column
156 | - `type` - The data type specified for the column
157 | - `notnull` - whether the field is defined as NOT NULL (i.e. values required)
158 | - `dflt_value` - The default value for the column
159 | - `pk` - Whether the field is part of the primary key of the table
160 |
161 | @param tableName The name of the table for whom the schema will be returned.
162 |
163 | @return `FMResultSet` of schema; `nil` on error.
164 |
165 | @see [table_info](http://www.sqlite.org/pragma.html#pragma_table_info)
166 | */
167 |
168 | - (FMResultSet*)getTableSchema:(NSString*)tableName;
169 |
170 | /** Test to see if particular column exists for particular table in database
171 |
172 | @param columnName The name of the column.
173 |
174 | @param tableName The name of the table.
175 |
176 | @return `YES` if column exists in table in question; `NO` otherwise.
177 | */
178 |
179 | - (BOOL)columnExists:(NSString*)columnName inTableWithName:(NSString*)tableName;
180 |
181 | /** Test to see if particular column exists for particular table in database
182 |
183 | @param columnName The name of the column.
184 |
185 | @param tableName The name of the table.
186 |
187 | @return `YES` if column exists in table in question; `NO` otherwise.
188 |
189 | @see columnExists:inTableWithName:
190 |
191 | @warning Deprecated - use `` instead.
192 | */
193 |
194 | - (BOOL)columnExists:(NSString*)tableName columnName:(NSString*)columnName __attribute__ ((deprecated));
195 |
196 |
197 | /** Validate SQL statement
198 |
199 | This validates SQL statement by performing `sqlite3_prepare_v2`, but not returning the results, but instead immediately calling `sqlite3_finalize`.
200 |
201 | @param sql The SQL statement being validated.
202 |
203 | @param error This is a pointer to a `NSError` object that will receive the autoreleased `NSError` object if there was any error. If this is `nil`, no `NSError` result will be returned.
204 |
205 | @return `YES` if validation succeeded without incident; `NO` otherwise.
206 |
207 | */
208 |
209 | - (BOOL)validateSQL:(NSString*)sql error:(NSError**)error;
210 |
211 |
212 | ///-----------------------------------
213 | /// @name Application identifier tasks
214 | ///-----------------------------------
215 |
216 | /** Retrieve application ID
217 |
218 | @return The `uint32_t` numeric value of the application ID.
219 |
220 | @see setApplicationID:
221 | */
222 |
223 | - (uint32_t)applicationID;
224 |
225 | /** Set the application ID
226 |
227 | @param appID The `uint32_t` numeric value of the application ID.
228 |
229 | @see applicationID
230 | */
231 |
232 | - (void)setApplicationID:(uint32_t)appID;
233 |
234 | #if TARGET_OS_MAC && !TARGET_OS_IPHONE
235 | /** Retrieve application ID string
236 |
237 | @return The `NSString` value of the application ID.
238 |
239 | @see setApplicationIDString:
240 | */
241 |
242 |
243 | - (NSString*)applicationIDString;
244 |
245 | /** Set the application ID string
246 |
247 | @param string The `NSString` value of the application ID.
248 |
249 | @see applicationIDString
250 | */
251 |
252 | - (void)setApplicationIDString:(NSString*)string;
253 |
254 | #endif
255 |
256 | ///-----------------------------------
257 | /// @name user version identifier tasks
258 | ///-----------------------------------
259 |
260 | /** Retrieve user version
261 |
262 | @return The `uint32_t` numeric value of the user version.
263 |
264 | @see setUserVersion:
265 | */
266 |
267 | - (uint32_t)userVersion;
268 |
269 | /** Set the user-version
270 |
271 | @param version The `uint32_t` numeric value of the user version.
272 |
273 | @see userVersion
274 | */
275 |
276 | - (void)setUserVersion:(uint32_t)version;
277 |
278 | @end
279 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/JYDatabase/fmdb/FMDatabasePool.m:
--------------------------------------------------------------------------------
1 | //
2 | // FMDatabasePool.m
3 | // fmdb
4 | //
5 | // Created by August Mueller on 6/22/11.
6 | // Copyright 2011 Flying Meat Inc. All rights reserved.
7 | //
8 |
9 | #if FMDB_SQLITE_STANDALONE
10 | #import
11 | #else
12 | #import
13 | #endif
14 |
15 | #import "FMDatabasePool.h"
16 | #import "FMDatabase.h"
17 |
18 | @interface FMDatabasePool()
19 |
20 | - (void)pushDatabaseBackInPool:(FMDatabase*)db;
21 | - (FMDatabase*)db;
22 |
23 | @end
24 |
25 |
26 | @implementation FMDatabasePool
27 | @synthesize path=_path;
28 | @synthesize delegate=_delegate;
29 | @synthesize maximumNumberOfDatabasesToCreate=_maximumNumberOfDatabasesToCreate;
30 | @synthesize openFlags=_openFlags;
31 |
32 |
33 | + (instancetype)databasePoolWithPath:(NSString*)aPath {
34 | return FMDBReturnAutoreleased([[self alloc] initWithPath:aPath]);
35 | }
36 |
37 | + (instancetype)databasePoolWithPath:(NSString*)aPath flags:(int)openFlags {
38 | return FMDBReturnAutoreleased([[self alloc] initWithPath:aPath flags:openFlags]);
39 | }
40 |
41 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags vfs:(NSString *)vfsName {
42 |
43 | self = [super init];
44 |
45 | if (self != nil) {
46 | _path = [aPath copy];
47 | _lockQueue = dispatch_queue_create([[NSString stringWithFormat:@"fmdb.%@", self] UTF8String], NULL);
48 | _databaseInPool = FMDBReturnRetained([NSMutableArray array]);
49 | _databaseOutPool = FMDBReturnRetained([NSMutableArray array]);
50 | _openFlags = openFlags;
51 | _vfsName = [vfsName copy];
52 | }
53 |
54 | return self;
55 | }
56 |
57 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags {
58 | return [self initWithPath:aPath flags:openFlags vfs:nil];
59 | }
60 |
61 | - (instancetype)initWithPath:(NSString*)aPath
62 | {
63 | // default flags for sqlite3_open
64 | return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE];
65 | }
66 |
67 | - (instancetype)init {
68 | return [self initWithPath:nil];
69 | }
70 |
71 | + (Class)databaseClass {
72 | return [FMDatabase class];
73 | }
74 |
75 | - (void)dealloc {
76 |
77 | _delegate = 0x00;
78 | FMDBRelease(_path);
79 | FMDBRelease(_databaseInPool);
80 | FMDBRelease(_databaseOutPool);
81 |
82 | if (_lockQueue) {
83 | FMDBDispatchQueueRelease(_lockQueue);
84 | _lockQueue = 0x00;
85 | }
86 | #if ! __has_feature(objc_arc)
87 | [super dealloc];
88 | #endif
89 | }
90 |
91 |
92 | - (void)executeLocked:(void (^)(void))aBlock {
93 | dispatch_sync(_lockQueue, aBlock);
94 | }
95 |
96 | - (void)pushDatabaseBackInPool:(FMDatabase*)db {
97 |
98 | if (!db) { // db can be null if we set an upper bound on the # of databases to create.
99 | return;
100 | }
101 |
102 | [self executeLocked:^() {
103 |
104 | if ([self->_databaseInPool containsObject:db]) {
105 | [[NSException exceptionWithName:@"Database already in pool" reason:@"The FMDatabase being put back into the pool is already present in the pool" userInfo:nil] raise];
106 | }
107 |
108 | [self->_databaseInPool addObject:db];
109 | [self->_databaseOutPool removeObject:db];
110 |
111 | }];
112 | }
113 |
114 | - (FMDatabase*)db {
115 |
116 | __block FMDatabase *db;
117 |
118 |
119 | [self executeLocked:^() {
120 | db = [self->_databaseInPool lastObject];
121 |
122 | BOOL shouldNotifyDelegate = NO;
123 |
124 | if (db) {
125 | [self->_databaseOutPool addObject:db];
126 | [self->_databaseInPool removeLastObject];
127 | }
128 | else {
129 |
130 | if (self->_maximumNumberOfDatabasesToCreate) {
131 | NSUInteger currentCount = [self->_databaseOutPool count] + [self->_databaseInPool count];
132 |
133 | if (currentCount >= self->_maximumNumberOfDatabasesToCreate) {
134 | NSLog(@"Maximum number of databases (%ld) has already been reached!", (long)currentCount);
135 | return;
136 | }
137 | }
138 |
139 | db = [[[self class] databaseClass] databaseWithPath:self->_path];
140 | shouldNotifyDelegate = YES;
141 | }
142 |
143 | //This ensures that the db is opened before returning
144 | #if SQLITE_VERSION_NUMBER >= 3005000
145 | BOOL success = [db openWithFlags:self->_openFlags vfs:self->_vfsName];
146 | #else
147 | BOOL success = [db open];
148 | #endif
149 | if (success) {
150 | if ([self->_delegate respondsToSelector:@selector(databasePool:shouldAddDatabaseToPool:)] && ![self->_delegate databasePool:self shouldAddDatabaseToPool:db]) {
151 | [db close];
152 | db = 0x00;
153 | }
154 | else {
155 | //It should not get added in the pool twice if lastObject was found
156 | if (![self->_databaseOutPool containsObject:db]) {
157 | [self->_databaseOutPool addObject:db];
158 |
159 | if (shouldNotifyDelegate && [self->_delegate respondsToSelector:@selector(databasePool:didAddDatabase:)]) {
160 | [self->_delegate databasePool:self didAddDatabase:db];
161 | }
162 | }
163 | }
164 | }
165 | else {
166 | NSLog(@"Could not open up the database at path %@", self->_path);
167 | db = 0x00;
168 | }
169 | }];
170 |
171 | return db;
172 | }
173 |
174 | - (NSUInteger)countOfCheckedInDatabases {
175 |
176 | __block NSUInteger count;
177 |
178 | [self executeLocked:^() {
179 | count = [self->_databaseInPool count];
180 | }];
181 |
182 | return count;
183 | }
184 |
185 | - (NSUInteger)countOfCheckedOutDatabases {
186 |
187 | __block NSUInteger count;
188 |
189 | [self executeLocked:^() {
190 | count = [self->_databaseOutPool count];
191 | }];
192 |
193 | return count;
194 | }
195 |
196 | - (NSUInteger)countOfOpenDatabases {
197 | __block NSUInteger count;
198 |
199 | [self executeLocked:^() {
200 | count = [self->_databaseOutPool count] + [self->_databaseInPool count];
201 | }];
202 |
203 | return count;
204 | }
205 |
206 | - (void)releaseAllDatabases {
207 | [self executeLocked:^() {
208 | [self->_databaseOutPool removeAllObjects];
209 | [self->_databaseInPool removeAllObjects];
210 | }];
211 | }
212 |
213 | - (void)inDatabase:(void (^)(FMDatabase *db))block {
214 |
215 | FMDatabase *db = [self db];
216 |
217 | block(db);
218 |
219 | [self pushDatabaseBackInPool:db];
220 | }
221 |
222 | - (void)beginTransaction:(BOOL)useDeferred withBlock:(void (^)(FMDatabase *db, BOOL *rollback))block {
223 |
224 | BOOL shouldRollback = NO;
225 |
226 | FMDatabase *db = [self db];
227 |
228 | if (useDeferred) {
229 | [db beginDeferredTransaction];
230 | }
231 | else {
232 | [db beginTransaction];
233 | }
234 |
235 |
236 | block(db, &shouldRollback);
237 |
238 | if (shouldRollback) {
239 | [db rollback];
240 | }
241 | else {
242 | [db commit];
243 | }
244 |
245 | [self pushDatabaseBackInPool:db];
246 | }
247 |
248 | - (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block {
249 | [self beginTransaction:YES withBlock:block];
250 | }
251 |
252 | - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block {
253 | [self beginTransaction:NO withBlock:block];
254 | }
255 |
256 | - (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block {
257 | #if SQLITE_VERSION_NUMBER >= 3007000
258 | static unsigned long savePointIdx = 0;
259 |
260 | NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++];
261 |
262 | BOOL shouldRollback = NO;
263 |
264 | FMDatabase *db = [self db];
265 |
266 | NSError *err = 0x00;
267 |
268 | if (![db startSavePointWithName:name error:&err]) {
269 | [self pushDatabaseBackInPool:db];
270 | return err;
271 | }
272 |
273 | block(db, &shouldRollback);
274 |
275 | if (shouldRollback) {
276 | // We need to rollback and release this savepoint to remove it
277 | [db rollbackToSavePointWithName:name error:&err];
278 | }
279 | [db releaseSavePointWithName:name error:&err];
280 |
281 | [self pushDatabaseBackInPool:db];
282 |
283 | return err;
284 | #else
285 | NSString *errorMessage = NSLocalizedString(@"Save point functions require SQLite 3.7", nil);
286 | if (self.logsErrors) NSLog(@"%@", errorMessage);
287 | return [NSError errorWithDomain:@"FMDatabase" code:0 userInfo:@{NSLocalizedDescriptionKey : errorMessage}];
288 | #endif
289 | }
290 |
291 | @end
292 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # JYDatabase
2 | 对FMDB的轻量级封装,帮助快速创建管理移动端数据库。让SQLite使用更加简单,记得给小星星哦。
3 |
4 | 要实现的目标:
5 |
6 | 1.自动处理数据库升级,让使用者不用考虑数据库升级带来烦劳。
7 | 2.封装简单常用的查询语句,让使用者只用关注特殊的SQL查询,基本查询不用重复写直接使用即可。
8 |
9 | 已支持 CocoaPods
10 |
11 | pod 'JYDataBase'
12 |
13 | # 一、JYDatabase 的使用
14 | 
15 |
16 | 如图:是Demo中创建本地数据库的一个框图。
17 | BS1: JYDBService类 提供了所有对外的查询方法,数据库的增删查改都通过这个单例调用。
18 | BS2: JYPersonDB 是JYDBService 所包含的其中一个数据库,他管理着 该库所有表的创建和升级。
19 | BS3: JYPersonTable 是JYPersonDB库下的其中一张表,它管理了该表的所有 增删查改 操作。
20 | BS4: JYPersonInfo 是映射JYPersonTable表的列的对象。JYPersonTable表查询出来的数据都会转换成JYPersonInfo对象。
21 | 注意:个人建议不要在项目中建多个数据库,建一个数据库,多张表即可。
22 |
23 | ##### 1.1 JYPersonTable建立(数据表)
24 |
25 | 数据表的建立需要继承 JYContentTable(该类实现了工作中用到的大部分SQL查询),只要重写以下几个方法就可以快速创建一张数据表。
26 |
27 | // 必须实现 contentClass 是该表所对应的模型类,tableName 是表的名字
28 | - (void)configTableName{
29 | self.contentClass = [JYPersonInfo class];
30 | self.tableName = @"JYPersonTable";
31 | }
32 |
33 | // 必须实现 contentId 是该表的主键(也是唯一索引)比如用户的userId 必须是 contentClass 的属性
34 | - (NSString *)contentId{
35 | return @"personnumber";
36 | }
37 |
38 | // 数据表的其他字段,必须是 contentClass 的属性,如不实现则默认取 contentClass 以“DB”结尾 的属性
39 | - (NSArray *)getContentField{
40 | return @[@"mutableString1",@"integer1",@"uInteger1",@"int1",@"bool1",@"double1"];
41 | }
42 |
43 | // 表创建时对应字段的默认长度,如不写,取默认。
44 | - (NSDictionary*)fieldLenght{
45 | return @[@"mutableString1":@"512"];
46 | }
47 |
48 | // 查询是否使用NSCache缓存,默认YES。
49 | - (BOOL)enableCache{
50 | return NO;
51 | }
52 |
53 | 注意:数据表映射的属性支持 NSString NSMutableString NSInteger NSUInteger int BOOL double float NSData NSArray NSMutableArray NSDictionary NSMutableDictionary 的数据类型 其中字典 数组 要能序列化。数组是其它数据库表的模型要进行特殊配置,参考下面多表设置。
54 |
55 | ##### 1.2 JYPersonDB管理了数据库的创建和升级 需要继承JYDataBase
56 |
57 | 关键方法:
58 | // 该方法会根据当前版本判断 是创建数据库表还是 数据表升级
59 | - (void)buildWithPath:(NSString *)aPath mode:(ArtDatabaseMode)aMode;
60 |
61 | // 返回当前数据库版本,只要数据表有修改 返回版本号请 +1 默认返回 1
62 | - (NSInteger)getCurrentDBVersion{
63 | return 4;
64 | }
65 |
66 | // 所有数据表的创建请在该方法实现 调用固定方法 - (void)createTable:(FMDatabase *)aDB;
67 | - (void)createAllTable:(FMDatabase *)aDB{
68 | [self.personTable createTable:aDB];
69 | }
70 |
71 | // 所有数据表的升级请在该方法实现 调用固定方法 - (void)insertDefaultData:(FMDatabase *)aDb;
72 | - (void)updateDB:(FMDatabase *)aDB{
73 | [self.personTable updateDB:aDB];
74 | }
75 |
76 | ##### 1.3 JYDBService
77 |
78 | 这是一个单例,向外提供数据库的一切外部接口,具体实现大家可以看Demo。
79 | # 二、内部部分代码的实现讲解
80 |
81 | ##### 2.1 数据库升级的实现 - (void)updateDB:(FMDatabase *)aDB
82 |
83 | 对于每一张表,所谓的修改无非是 添加了一个 新的字段 或减少了几个字段(这种情况很少)。
84 | 2.2.1 字段的对比
85 | PRAGMA table_info([tableName]) 可以获取一张表的所有字段
86 | 再与当前需要的字段做对比即可得到要增加的字段和减少的字段
87 | 2.2.2 字段的添加
88 | sqlite有提供对应的SQL语句实现
89 | ALTER TABLE tableName ADD 字段 type(lenght)
90 | 2.2.3 减少字段
91 | sqlite并未提供对应的SQL语句实现但可通过以下方法实现
92 | a.根据原表新建一个表
93 | sql = [NSString stringWithFormat:@"create table %@ as select %@%@ from %@", tempTableName,[self contentId],tableField,self.tableName];
94 | b.删除原表
95 | sql = [NSString stringWithFormat:@"drop table if exists %@", self.tableName];
96 | c.将表改名
97 | sql = [NSString stringWithFormat:@"alter table %@ rename to %@",tempTableName ,self.tableName];
98 | d.为新表添加唯一索引
99 | sql = [NSString stringWithFormat:@"create unique index '%@_key' on %@(%@)", self.tableName,self.tableName,[self contentId]];
100 |
101 | ##### 2.2 FMDB部分方法说明
102 |
103 | - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block;
104 | - (void)inDatabase:(void (^)(FMDatabase *db))block;
105 | 以上 两个方法都是开启了事务操作的
106 | - (BOOL)rollback {
107 | BOOL b = [self executeUpdate:@"rollback transaction"];
108 |
109 | if (b) {
110 | _inTransaction = NO;
111 | }
112 |
113 | return b;
114 | }
115 |
116 | - (BOOL)commit {
117 | BOOL b = [self executeUpdate:@"commit transaction"];
118 |
119 | if (b) {
120 | _inTransaction = NO;
121 | }
122 |
123 | return b;
124 | }
125 |
126 | - (BOOL)beginDeferredTransaction {
127 |
128 | BOOL b = [self executeUpdate:@"begin deferred transaction"];
129 | if (b) {
130 | _inTransaction = YES;
131 | }
132 |
133 | return b;
134 | }
135 |
136 | - (BOOL)beginTransaction {
137 |
138 | BOOL b = [self executeUpdate:@"begin exclusive transaction"];
139 | if (b) {
140 | _inTransaction = YES;
141 | }
142 |
143 | return b;
144 | }
145 |
146 | - (BOOL)inTransaction {
147 | return _inTransaction;
148 | }
149 | 在数据库的创建 升级 以及 多数据的插入,我都使用了该方法。
150 |
151 | ##### 2.3 条件查询的实现
152 |
153 | 关于复杂查询我提供了一个简单的方法
154 | - (NSArray *)getContentByConditions:(void (^)(JYQueryConditions *make))block;
155 | 可以看下它的使用
156 | NSArray*infos = [[JYDBService shared] getPersonInfoByConditions:^(JYQueryConditions *make) {
157 | make.field(@"personnumber").greaterThanOrEqualTo(@"12345620");
158 | make.field(@"bool1").equalTo(@"1");
159 | make.field(@"personnumber").lessTo(@"12345630");
160 | make.asc(@"bool1").desc(@"int1");
161 | }];
162 | 其实它不过产生了如下一条查询语句:
163 | SELECT * FROM JYPersonTable WHERE personnumber >= 12345620 AND bool1 = 1 AND personnumber < 12345630 order by bool1 asc , int1 desc
164 |
165 | make.field(@"personnumber").greaterThanOrEqualTo(@"12345620"); 就代表了 personnumber >= 12345620
166 |
167 | 实现实际相当简单,先用 JYQueryConditions 记录下所描描述的参数,最后再拼接出完整的sql语句。
168 | 至于通过点语法的链式调用则参考了 Masonry 的声明方式
169 | - (JYQueryConditions * (^)(NSString *compare))equalTo;
170 | - (JYQueryConditions * (^)(NSString *field))field{
171 | return ^id(NSString *field) {
172 | NSMutableDictionary *dicM = [[NSMutableDictionary alloc] init];
173 | dicM[kField] = field;
174 | [self.conditions addObject:dicM];
175 | return self;
176 | };
177 | }
178 |
179 | # 三、提供的查询方法
180 | #### pragma mark - 索引添加
181 |
182 | - (void)insertDB:(FMDatabase *)aDB contents:(NSArray *)aContents;
183 | - (void)insertContent:(id)aContent;
184 | - (void)insertContents:(NSArray *)aContents;
185 | - (void)insertIndependentDB:(FMDatabase *)aDB contents:(NSArray *)aContents;
186 | - (void)insertIndependentContent:(id)aContent;
187 | - (void)insertIndependentContents:(NSArray *)aContents;
188 |
189 | #### pragma mark - insert 插入
190 |
191 | - (void)insertDB:(FMDatabase *)aDB contents:(NSArray *)aContents;
192 | - (void)insertContent:(id)aContent;
193 | - (void)insertContents:(NSArray *)aContents;
194 |
195 | #### pragma mark - get 查询
196 | - (NSArray *)getContentDB:(FMDatabase *)aDB byconditions:(void (^)(JYQueryConditions *make))block;
197 | - (NSArray *)getDB:(FMDatabase *)aDB contentByIDs:(NSArray*)aIDs;
198 | - (NSArray *)getContentByConditions:(void (^)(JYQueryConditions *make))block;
199 | - (NSArray *)getContentByIDs:(NSArray*)aIDs;
200 | - (id)getContentByID:(NSString*)aID;
201 | - (NSArray *)getAllContent;
202 |
203 | #### pragma mark - delete 删除
204 | - (void)deleteContentDB:(FMDatabase *)aDB byconditions:(void (^)(JYQueryConditions *make))block;
205 | - (void)deleteDB:(FMDatabase *)aDB contentByIDs:(NSArray*)aIDs;
206 | - (void)deleteContentByConditions:(void (^)(JYQueryConditions *make))block;
207 | - (void)deleteContentByID:(NSString *)aID;
208 | - (void)deleteContentByIDs:(NSArray*)aIDs;
209 | - (void)deleteAllContent;
210 | - (void)cleanContentBefore:(NSDate*)date;
211 |
212 | #### pragma mark - getCount
213 | - (NSInteger)getCountContentDB:(FMDatabase *)aDB byconditions:(void (^)(JYQueryConditions *make))block;
214 | - (NSInteger)getCountByConditions:(void (^)(JYQueryConditions *make))block;
215 | - (NSInteger)getAllCount;
216 |
217 |
218 | # 四、工具的推荐
219 |
220 | 在移动端使用SqLite,个人建议安装 火狐浏览器 的一个插件 SQLite Manager 多的就不说了。
221 |
222 | # 五、版本记录
223 |
224 | ### tag - 1.0.6
225 | ##### 修改记录
226 |
227 | 1.本修改了查询方法的使用,以及数据建立方法更为简便,不用用户写大量无用代码,具体可见Demo 中JYPersonDB。
228 |
229 | 2.OC属性字段与sqlite属性字段的映射是依赖与 JYDataBaseConfig 里 NSDictionary * jy_correspondingDic()的静态方法,但是在实际使用中可能无法全部覆盖,触发断言,大家遇到后可以自己设置 corresponding 属性添加额外的映射。
230 |
231 | 3.宗旨就是让数据库的使用变的简单,后期会根据我所遇到的一些业务场景进行持续更新。
232 |
233 | ##### 谈下在移动端,数据库关于不同用户的区分问题
234 |
235 |
236 | 移动端缓存有个必须要注意的问题,那就是用户区分,要不把用户A的缓存数据显示到了用户B上
237 | 就比较尴尬了。一般来说有两种方法:
238 | 1.在每张表添加一个字段 userId 用于用户区分。在查询时要添加userId做为查询条件,插入时也要设置当前的userId。
239 | 2.为每个用户创建一个数据库。
240 | 综合比较的话:方案一:优点是,可以为数据库的每一张表定义是否区分用户,缺点是,要多维护一个字段得不尝失。故而选择方案二。
241 |
242 | 方案二的使用:
243 | 通过监听userId的改变重新绑定数据库。self.documentDirectory 使用懒加载生成与userId有关的 地址。
244 | - (void)construct{
245 | NSLog(@"%@",self.documentDirectory);
246 | self.userId = [ArtUserConfig shared].userId;
247 | [self buildWithPath:self.documentDirectory mode:ArtDatabaseModeWrite registTable:^{
248 | //注册数据表 建议外引出来,用于其它位置调用封装
249 | self.personTable = (JYPersonTable *)[self registTableClass:[JYPersonTable class]];
250 | self.test1Table = (JYTest1Table *)[self registTableClass:[JYTest1Table class]];
251 | }];
252 |
253 | @weakify(self)
254 | [RACObserve([ArtUserConfig shared], userId)subscribeNext:^(NSString *x) {
255 | @strongify(self)
256 | if ([self.userId isEqualToString:x]) {
257 | return;
258 | }
259 | self.documentDirectory = nil;
260 | [self construct];
261 | }];
262 | }
263 | 这种使用方式本身是没有问题的,但在实际的业务使用场景可能照成一些问题,比如在使用用户数据存储时,我将用
264 | 户数据存入用户数据库,在程序中只传递userId 在需要使用时才从 数据库中读取。这时如果退出登录,此时访问的
265 | 数据库就不是插入的数据库,那么就取不到数据。
266 | 如何解决上述问题,我的建议是 建立 两种数据库,一种是公用数据库(该库不区分用户),还有一种是 独立数据库
267 | (每个用户都建一个)。对于社交应用,缓存用户信息的表放倒 公用数据库 即可。
268 |
269 | ### tag - 1.1.0 增加多表关联功能
270 |
271 | ##### 修改记录
272 | 1.增加了多表关联功能,ModelA 包含 ModelB 的存入取出也可用简单的配置解决。
273 | 2.删除了UIImage的数据库存储支持。
274 | 3.删除了内存缓存支持,这是一个很鸡肋无用的处理。需要可以自行在外部加上自己的缓存机制。
275 | 4.DEMO做了大的修改,删除毫无意义的稀烂界面。写了一个测试代码 JYContentTableTest.m
276 | 5.对代码生成工具 JYGenerationCode 做了简单修改。
277 | ##### 多表关联使用说明
278 |
279 | DEMO中写了三模型,JYGradeInfo (年级),JYClassInfo (班级),JYPersonInfo(人)
280 | 他们之间的关系是,一个年级有多个班级,一个班级 有一个老师 和 多个学生。对此建立了三张
281 | 表JYGradeTable(年级表),JYClassTable(班级表),JYPersonTable(人表)。
282 |
283 | 多表关联采用主外键形式:JYClassTable中的 gradeID 字段就是对应JYGradeTable的外
284 | 键.JYPersonTable 中的teacherClassID 对应 JYGradeTable的老师外键studentClassID
285 | 对应 JYGradeTable 的学生外键。
286 |
287 | 1.外键功能的实现:我在直接使用SQL的外键功能时遇到了一些问题(有空会再回头看看),这理是
288 | 使用简单粗暴的形势实现的级联删除。在进行条件删除条件查询时会比较耗时。(也不是很糟糕
289 | 哈),有空我会有sql外键形式看看做下对比。
290 | 2.关联表设置参考DEMO 按如下设置即可
291 | - (NSDictionary *)associativeTableField{
292 |
293 | JYPersonTable *table = [JYDBService shared].personDB.personTable;
294 | // tableSortKey 不设置查询时会以主key做升序放入数组
295 | return @{
296 | @"teacher" : @{
297 | tableContentObject : table,
298 | tableViceKey : @"teacherClassID"
299 | },
300 | @"students" : @{
301 | tableContentObject : table,
302 | tableViceKey : @"studentClassID",
303 | tableSortKey : @"studentIdx"
304 | }
305 | };
306 | }
307 | 3.为外键字段加上索引提高查询效率
308 | // 为 gradeID 加上索引
309 | - (void)addOtherOperationForTable:(FMDatabase *)aDB{
310 | [self addDB:aDB uniques:@[@"gradeID"]];
311 | }
312 |
313 |
314 | ## 六、避坑汇总
315 |
316 | ### 1.数据库字段属性,慎用除NSString外的对象存储。
317 |
318 | 框架虽然提供了 NSData,NSNumber,NSDictionary,NSMutableDictionary,
319 | NSMutableArray,NSArray 这些对象的存储(其中数组字典要可反序列化),但是它们
320 | 在数据库中的存储类型都是 BLOB 类型,这导致sql查询查不出来,所以需要查询的字段请
321 | 使用NSString及基本数据类型。
322 |
323 | ### 2.主键无自增功能
324 |
325 | 因为业务需求问题,是未考虑主键自增的,主键不可为空,请自行处理随机生成唯一主键。
326 |
327 |
328 |
329 |
330 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/JYDatabase/fmdb/FMResultSet.m:
--------------------------------------------------------------------------------
1 | #import "FMResultSet.h"
2 | #import "FMDatabase.h"
3 | #import "unistd.h"
4 |
5 | #if FMDB_SQLITE_STANDALONE
6 | #import
7 | #else
8 | #import
9 | #endif
10 |
11 | @interface FMDatabase ()
12 | - (void)resultSetDidClose:(FMResultSet *)resultSet;
13 | @end
14 |
15 |
16 | @implementation FMResultSet
17 | @synthesize query=_query;
18 | @synthesize statement=_statement;
19 |
20 | + (instancetype)resultSetWithStatement:(FMStatement *)statement usingParentDatabase:(FMDatabase*)aDB {
21 |
22 | FMResultSet *rs = [[FMResultSet alloc] init];
23 |
24 | [rs setStatement:statement];
25 | [rs setParentDB:aDB];
26 |
27 | NSParameterAssert(![statement inUse]);
28 | [statement setInUse:YES]; // weak reference
29 |
30 | return FMDBReturnAutoreleased(rs);
31 | }
32 |
33 | - (void)finalize {
34 | [self close];
35 | [super finalize];
36 | }
37 |
38 | - (void)dealloc {
39 | [self close];
40 |
41 | FMDBRelease(_query);
42 | _query = nil;
43 |
44 | FMDBRelease(_columnNameToIndexMap);
45 | _columnNameToIndexMap = nil;
46 |
47 | #if ! __has_feature(objc_arc)
48 | [super dealloc];
49 | #endif
50 | }
51 |
52 | - (void)close {
53 | [_statement reset];
54 | FMDBRelease(_statement);
55 | _statement = nil;
56 |
57 | // we don't need this anymore... (i think)
58 | //[_parentDB setInUse:NO];
59 | [_parentDB resultSetDidClose:self];
60 | _parentDB = nil;
61 | }
62 |
63 | - (int)columnCount {
64 | return sqlite3_column_count([_statement statement]);
65 | }
66 |
67 | - (NSMutableDictionary *)columnNameToIndexMap {
68 | if (!_columnNameToIndexMap) {
69 | int columnCount = sqlite3_column_count([_statement statement]);
70 | _columnNameToIndexMap = [[NSMutableDictionary alloc] initWithCapacity:(NSUInteger)columnCount];
71 | int columnIdx = 0;
72 | for (columnIdx = 0; columnIdx < columnCount; columnIdx++) {
73 | [_columnNameToIndexMap setObject:[NSNumber numberWithInt:columnIdx]
74 | forKey:[[NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)] lowercaseString]];
75 | }
76 | }
77 | return _columnNameToIndexMap;
78 | }
79 |
80 | - (void)kvcMagic:(id)object {
81 |
82 | int columnCount = sqlite3_column_count([_statement statement]);
83 |
84 | int columnIdx = 0;
85 | for (columnIdx = 0; columnIdx < columnCount; columnIdx++) {
86 |
87 | const char *c = (const char *)sqlite3_column_text([_statement statement], columnIdx);
88 |
89 | // check for a null row
90 | if (c) {
91 | NSString *s = [NSString stringWithUTF8String:c];
92 |
93 | [object setValue:s forKey:[NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)]];
94 | }
95 | }
96 | }
97 |
98 | #pragma clang diagnostic push
99 | #pragma clang diagnostic ignored "-Wdeprecated-implementations"
100 |
101 | - (NSDictionary*)resultDict {
102 |
103 | NSUInteger num_cols = (NSUInteger)sqlite3_data_count([_statement statement]);
104 |
105 | if (num_cols > 0) {
106 | NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:num_cols];
107 |
108 | NSEnumerator *columnNames = [[self columnNameToIndexMap] keyEnumerator];
109 | NSString *columnName = nil;
110 | while ((columnName = [columnNames nextObject])) {
111 | id objectValue = [self objectForColumnName:columnName];
112 | [dict setObject:objectValue forKey:columnName];
113 | }
114 |
115 | return FMDBReturnAutoreleased([dict copy]);
116 | }
117 | else {
118 | NSLog(@"Warning: There seem to be no columns in this set.");
119 | }
120 |
121 | return nil;
122 | }
123 |
124 | #pragma clang diagnostic pop
125 |
126 | - (NSDictionary*)resultDictionary {
127 |
128 | NSUInteger num_cols = (NSUInteger)sqlite3_data_count([_statement statement]);
129 |
130 | if (num_cols > 0) {
131 | NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:num_cols];
132 |
133 | int columnCount = sqlite3_column_count([_statement statement]);
134 |
135 | int columnIdx = 0;
136 | for (columnIdx = 0; columnIdx < columnCount; columnIdx++) {
137 |
138 | NSString *columnName = [NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)];
139 | id objectValue = [self objectForColumnIndex:columnIdx];
140 | [dict setObject:objectValue forKey:columnName];
141 | }
142 |
143 | return dict;
144 | }
145 | else {
146 | NSLog(@"Warning: There seem to be no columns in this set.");
147 | }
148 |
149 | return nil;
150 | }
151 |
152 |
153 |
154 |
155 | - (BOOL)next {
156 | return [self nextWithError:nil];
157 | }
158 |
159 | - (BOOL)nextWithError:(NSError **)outErr {
160 |
161 | int rc = sqlite3_step([_statement statement]);
162 |
163 | if (SQLITE_BUSY == rc || SQLITE_LOCKED == rc) {
164 | NSLog(@"%s:%d Database busy (%@)", __FUNCTION__, __LINE__, [_parentDB databasePath]);
165 | NSLog(@"Database busy");
166 | if (outErr) {
167 | *outErr = [_parentDB lastError];
168 | }
169 | }
170 | else if (SQLITE_DONE == rc || SQLITE_ROW == rc) {
171 | // all is well, let's return.
172 | }
173 | else if (SQLITE_ERROR == rc) {
174 | NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle]));
175 | if (outErr) {
176 | *outErr = [_parentDB lastError];
177 | }
178 | }
179 | else if (SQLITE_MISUSE == rc) {
180 | // uh oh.
181 | NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle]));
182 | if (outErr) {
183 | if (_parentDB) {
184 | *outErr = [_parentDB lastError];
185 | }
186 | else {
187 | // If 'next' or 'nextWithError' is called after the result set is closed,
188 | // we need to return the appropriate error.
189 | NSDictionary* errorMessage = [NSDictionary dictionaryWithObject:@"parentDB does not exist" forKey:NSLocalizedDescriptionKey];
190 | *outErr = [NSError errorWithDomain:@"FMDatabase" code:SQLITE_MISUSE userInfo:errorMessage];
191 | }
192 |
193 | }
194 | }
195 | else {
196 | // wtf?
197 | NSLog(@"Unknown error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle]));
198 | if (outErr) {
199 | *outErr = [_parentDB lastError];
200 | }
201 | }
202 |
203 |
204 | if (rc != SQLITE_ROW) {
205 | [self close];
206 | }
207 |
208 | return (rc == SQLITE_ROW);
209 | }
210 |
211 | - (BOOL)hasAnotherRow {
212 | return sqlite3_errcode([_parentDB sqliteHandle]) == SQLITE_ROW;
213 | }
214 |
215 | - (int)columnIndexForName:(NSString*)columnName {
216 | columnName = [columnName lowercaseString];
217 |
218 | NSNumber *n = [[self columnNameToIndexMap] objectForKey:columnName];
219 |
220 | if (n) {
221 | return [n intValue];
222 | }
223 |
224 | NSLog(@"Warning: I could not find the column named '%@'.", columnName);
225 |
226 | return -1;
227 | }
228 |
229 |
230 |
231 | - (int)intForColumn:(NSString*)columnName {
232 | return [self intForColumnIndex:[self columnIndexForName:columnName]];
233 | }
234 |
235 | - (int)intForColumnIndex:(int)columnIdx {
236 | return sqlite3_column_int([_statement statement], columnIdx);
237 | }
238 |
239 | - (long)longForColumn:(NSString*)columnName {
240 | return [self longForColumnIndex:[self columnIndexForName:columnName]];
241 | }
242 |
243 | - (long)longForColumnIndex:(int)columnIdx {
244 | return (long)sqlite3_column_int64([_statement statement], columnIdx);
245 | }
246 |
247 | - (long long int)longLongIntForColumn:(NSString*)columnName {
248 | return [self longLongIntForColumnIndex:[self columnIndexForName:columnName]];
249 | }
250 |
251 | - (long long int)longLongIntForColumnIndex:(int)columnIdx {
252 | return sqlite3_column_int64([_statement statement], columnIdx);
253 | }
254 |
255 | - (unsigned long long int)unsignedLongLongIntForColumn:(NSString*)columnName {
256 | return [self unsignedLongLongIntForColumnIndex:[self columnIndexForName:columnName]];
257 | }
258 |
259 | - (unsigned long long int)unsignedLongLongIntForColumnIndex:(int)columnIdx {
260 | return (unsigned long long int)[self longLongIntForColumnIndex:columnIdx];
261 | }
262 |
263 | - (BOOL)boolForColumn:(NSString*)columnName {
264 | return [self boolForColumnIndex:[self columnIndexForName:columnName]];
265 | }
266 |
267 | - (BOOL)boolForColumnIndex:(int)columnIdx {
268 | return ([self intForColumnIndex:columnIdx] != 0);
269 | }
270 |
271 | - (double)doubleForColumn:(NSString*)columnName {
272 | return [self doubleForColumnIndex:[self columnIndexForName:columnName]];
273 | }
274 |
275 | - (double)doubleForColumnIndex:(int)columnIdx {
276 | return sqlite3_column_double([_statement statement], columnIdx);
277 | }
278 |
279 | - (NSString*)stringForColumnIndex:(int)columnIdx {
280 |
281 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) {
282 | return nil;
283 | }
284 |
285 | const char *c = (const char *)sqlite3_column_text([_statement statement], columnIdx);
286 |
287 | if (!c) {
288 | // null row.
289 | return nil;
290 | }
291 |
292 | return [NSString stringWithUTF8String:c];
293 | }
294 |
295 | - (NSString*)stringForColumn:(NSString*)columnName {
296 | return [self stringForColumnIndex:[self columnIndexForName:columnName]];
297 | }
298 |
299 | - (NSDate*)dateForColumn:(NSString*)columnName {
300 | return [self dateForColumnIndex:[self columnIndexForName:columnName]];
301 | }
302 |
303 | - (NSDate*)dateForColumnIndex:(int)columnIdx {
304 |
305 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) {
306 | return nil;
307 | }
308 |
309 | return [_parentDB hasDateFormatter] ? [_parentDB dateFromString:[self stringForColumnIndex:columnIdx]] : [NSDate dateWithTimeIntervalSince1970:[self doubleForColumnIndex:columnIdx]];
310 | }
311 |
312 |
313 | - (NSData*)dataForColumn:(NSString*)columnName {
314 | return [self dataForColumnIndex:[self columnIndexForName:columnName]];
315 | }
316 |
317 | - (NSData*)dataForColumnIndex:(int)columnIdx {
318 |
319 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) {
320 | return nil;
321 | }
322 |
323 | const char *dataBuffer = sqlite3_column_blob([_statement statement], columnIdx);
324 | int dataSize = sqlite3_column_bytes([_statement statement], columnIdx);
325 |
326 | if (dataBuffer == NULL) {
327 | return nil;
328 | }
329 |
330 | return [NSData dataWithBytes:(const void *)dataBuffer length:(NSUInteger)dataSize];
331 | }
332 |
333 |
334 | - (NSData*)dataNoCopyForColumn:(NSString*)columnName {
335 | return [self dataNoCopyForColumnIndex:[self columnIndexForName:columnName]];
336 | }
337 |
338 | - (NSData*)dataNoCopyForColumnIndex:(int)columnIdx {
339 |
340 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) {
341 | return nil;
342 | }
343 |
344 | const char *dataBuffer = sqlite3_column_blob([_statement statement], columnIdx);
345 | int dataSize = sqlite3_column_bytes([_statement statement], columnIdx);
346 |
347 | NSData *data = [NSData dataWithBytesNoCopy:(void *)dataBuffer length:(NSUInteger)dataSize freeWhenDone:NO];
348 |
349 | return data;
350 | }
351 |
352 |
353 | - (BOOL)columnIndexIsNull:(int)columnIdx {
354 | return sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL;
355 | }
356 |
357 | - (BOOL)columnIsNull:(NSString*)columnName {
358 | return [self columnIndexIsNull:[self columnIndexForName:columnName]];
359 | }
360 |
361 | - (const unsigned char *)UTF8StringForColumnIndex:(int)columnIdx {
362 |
363 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) {
364 | return nil;
365 | }
366 |
367 | return sqlite3_column_text([_statement statement], columnIdx);
368 | }
369 |
370 | - (const unsigned char *)UTF8StringForColumnName:(NSString*)columnName {
371 | return [self UTF8StringForColumnIndex:[self columnIndexForName:columnName]];
372 | }
373 |
374 | - (id)objectForColumnIndex:(int)columnIdx {
375 | int columnType = sqlite3_column_type([_statement statement], columnIdx);
376 |
377 | id returnValue = nil;
378 |
379 | if (columnType == SQLITE_INTEGER) {
380 | returnValue = [NSNumber numberWithLongLong:[self longLongIntForColumnIndex:columnIdx]];
381 | }
382 | else if (columnType == SQLITE_FLOAT) {
383 | returnValue = [NSNumber numberWithDouble:[self doubleForColumnIndex:columnIdx]];
384 | }
385 | else if (columnType == SQLITE_BLOB) {
386 | returnValue = [self dataForColumnIndex:columnIdx];
387 | }
388 | else {
389 | //default to a string for everything else
390 | returnValue = [self stringForColumnIndex:columnIdx];
391 | }
392 |
393 | if (returnValue == nil) {
394 | returnValue = [NSNull null];
395 | }
396 |
397 | return returnValue;
398 | }
399 |
400 | - (id)objectForColumnName:(NSString*)columnName {
401 | return [self objectForColumnIndex:[self columnIndexForName:columnName]];
402 | }
403 |
404 | // returns autoreleased NSString containing the name of the column in the result set
405 | - (NSString*)columnNameForIndex:(int)columnIdx {
406 | return [NSString stringWithUTF8String: sqlite3_column_name([_statement statement], columnIdx)];
407 | }
408 |
409 | - (void)setParentDB:(FMDatabase *)newDb {
410 | _parentDB = newDb;
411 | }
412 |
413 | - (id)objectAtIndexedSubscript:(int)columnIdx {
414 | return [self objectForColumnIndex:columnIdx];
415 | }
416 |
417 | - (id)objectForKeyedSubscript:(NSString *)columnName {
418 | return [self objectForColumnName:columnName];
419 | }
420 |
421 |
422 | @end
423 |
--------------------------------------------------------------------------------
/JYDatabase - OC/JYDatabase - OC/JYDatabase/fmdb/FMResultSet.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | #ifndef __has_feature // Optional.
4 | #define __has_feature(x) 0 // Compatibility with non-clang compilers.
5 | #endif
6 |
7 | #ifndef NS_RETURNS_NOT_RETAINED
8 | #if __has_feature(attribute_ns_returns_not_retained)
9 | #define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))
10 | #else
11 | #define NS_RETURNS_NOT_RETAINED
12 | #endif
13 | #endif
14 |
15 | @class FMDatabase;
16 | @class FMStatement;
17 |
18 | /** Represents the results of executing a query on an ``.
19 |
20 | ### See also
21 |
22 | - ``
23 | */
24 |
25 | @interface FMResultSet : NSObject {
26 | FMDatabase *_parentDB;
27 | FMStatement *_statement;
28 |
29 | NSString *_query;
30 | NSMutableDictionary *_columnNameToIndexMap;
31 | }
32 |
33 | ///-----------------
34 | /// @name Properties
35 | ///-----------------
36 |
37 | /** Executed query */
38 |
39 | @property (atomic, retain) NSString *query;
40 |
41 | /** `NSMutableDictionary` mapping column names to numeric index */
42 |
43 | @property (readonly) NSMutableDictionary *columnNameToIndexMap;
44 |
45 | /** `FMStatement` used by result set. */
46 |
47 | @property (atomic, retain) FMStatement *statement;
48 |
49 | ///------------------------------------
50 | /// @name Creating and closing database
51 | ///------------------------------------
52 |
53 | /** Create result set from ``
54 |
55 | @param statement A `` to be performed
56 |
57 | @param aDB A `` to be used
58 |
59 | @return A `FMResultSet` on success; `nil` on failure
60 | */
61 |
62 | + (instancetype)resultSetWithStatement:(FMStatement *)statement usingParentDatabase:(FMDatabase*)aDB;
63 |
64 | /** Close result set */
65 |
66 | - (void)close;
67 |
68 | - (void)setParentDB:(FMDatabase *)newDb;
69 |
70 | ///---------------------------------------
71 | /// @name Iterating through the result set
72 | ///---------------------------------------
73 |
74 | /** Retrieve next row for result set.
75 |
76 | You must always invoke `next` or `nextWithError` before attempting to access the values returned in a query, even if you're only expecting one.
77 |
78 | @return `YES` if row successfully retrieved; `NO` if end of result set reached
79 |
80 | @see hasAnotherRow
81 | */
82 |
83 | - (BOOL)next;
84 |
85 | /** Retrieve next row for result set.
86 |
87 | You must always invoke `next` or `nextWithError` before attempting to access the values returned in a query, even if you're only expecting one.
88 |
89 | @param outErr A 'NSError' object to receive any error object (if any).
90 |
91 | @return 'YES' if row successfully retrieved; 'NO' if end of result set reached
92 |
93 | @see hasAnotherRow
94 | */
95 |
96 | - (BOOL)nextWithError:(NSError **)outErr;
97 |
98 | /** Did the last call to `` succeed in retrieving another row?
99 |
100 | @return `YES` if the last call to `` succeeded in retrieving another record; `NO` if not.
101 |
102 | @see next
103 |
104 | @warning The `hasAnotherRow` method must follow a call to ``. If the previous database interaction was something other than a call to `next`, then this method may return `NO`, whether there is another row of data or not.
105 | */
106 |
107 | - (BOOL)hasAnotherRow;
108 |
109 | ///---------------------------------------------
110 | /// @name Retrieving information from result set
111 | ///---------------------------------------------
112 |
113 | /** How many columns in result set
114 |
115 | @return Integer value of the number of columns.
116 | */
117 |
118 | - (int)columnCount;
119 |
120 | /** Column index for column name
121 |
122 | @param columnName `NSString` value of the name of the column.
123 |
124 | @return Zero-based index for column.
125 | */
126 |
127 | - (int)columnIndexForName:(NSString*)columnName;
128 |
129 | /** Column name for column index
130 |
131 | @param columnIdx Zero-based index for column.
132 |
133 | @return columnName `NSString` value of the name of the column.
134 | */
135 |
136 | - (NSString*)columnNameForIndex:(int)columnIdx;
137 |
138 | /** Result set integer value for column.
139 |
140 | @param columnName `NSString` value of the name of the column.
141 |
142 | @return `int` value of the result set's column.
143 | */
144 |
145 | - (int)intForColumn:(NSString*)columnName;
146 |
147 | /** Result set integer value for column.
148 |
149 | @param columnIdx Zero-based index for column.
150 |
151 | @return `int` value of the result set's column.
152 | */
153 |
154 | - (int)intForColumnIndex:(int)columnIdx;
155 |
156 | /** Result set `long` value for column.
157 |
158 | @param columnName `NSString` value of the name of the column.
159 |
160 | @return `long` value of the result set's column.
161 | */
162 |
163 | - (long)longForColumn:(NSString*)columnName;
164 |
165 | /** Result set long value for column.
166 |
167 | @param columnIdx Zero-based index for column.
168 |
169 | @return `long` value of the result set's column.
170 | */
171 |
172 | - (long)longForColumnIndex:(int)columnIdx;
173 |
174 | /** Result set `long long int` value for column.
175 |
176 | @param columnName `NSString` value of the name of the column.
177 |
178 | @return `long long int` value of the result set's column.
179 | */
180 |
181 | - (long long int)longLongIntForColumn:(NSString*)columnName;
182 |
183 | /** Result set `long long int` value for column.
184 |
185 | @param columnIdx Zero-based index for column.
186 |
187 | @return `long long int` value of the result set's column.
188 | */
189 |
190 | - (long long int)longLongIntForColumnIndex:(int)columnIdx;
191 |
192 | /** Result set `unsigned long long int` value for column.
193 |
194 | @param columnName `NSString` value of the name of the column.
195 |
196 | @return `unsigned long long int` value of the result set's column.
197 | */
198 |
199 | - (unsigned long long int)unsignedLongLongIntForColumn:(NSString*)columnName;
200 |
201 | /** Result set `unsigned long long int` value for column.
202 |
203 | @param columnIdx Zero-based index for column.
204 |
205 | @return `unsigned long long int` value of the result set's column.
206 | */
207 |
208 | - (unsigned long long int)unsignedLongLongIntForColumnIndex:(int)columnIdx;
209 |
210 | /** Result set `BOOL` value for column.
211 |
212 | @param columnName `NSString` value of the name of the column.
213 |
214 | @return `BOOL` value of the result set's column.
215 | */
216 |
217 | - (BOOL)boolForColumn:(NSString*)columnName;
218 |
219 | /** Result set `BOOL` value for column.
220 |
221 | @param columnIdx Zero-based index for column.
222 |
223 | @return `BOOL` value of the result set's column.
224 | */
225 |
226 | - (BOOL)boolForColumnIndex:(int)columnIdx;
227 |
228 | /** Result set `double` value for column.
229 |
230 | @param columnName `NSString` value of the name of the column.
231 |
232 | @return `double` value of the result set's column.
233 |
234 | */
235 |
236 | - (double)doubleForColumn:(NSString*)columnName;
237 |
238 | /** Result set `double` value for column.
239 |
240 | @param columnIdx Zero-based index for column.
241 |
242 | @return `double` value of the result set's column.
243 |
244 | */
245 |
246 | - (double)doubleForColumnIndex:(int)columnIdx;
247 |
248 | /** Result set `NSString` value for column.
249 |
250 | @param columnName `NSString` value of the name of the column.
251 |
252 | @return `NSString` value of the result set's column.
253 |
254 | */
255 |
256 | - (NSString*)stringForColumn:(NSString*)columnName;
257 |
258 | /** Result set `NSString` value for column.
259 |
260 | @param columnIdx Zero-based index for column.
261 |
262 | @return `NSString` value of the result set's column.
263 | */
264 |
265 | - (NSString*)stringForColumnIndex:(int)columnIdx;
266 |
267 | /** Result set `NSDate` value for column.
268 |
269 | @param columnName `NSString` value of the name of the column.
270 |
271 | @return `NSDate` value of the result set's column.
272 | */
273 |
274 | - (NSDate*)dateForColumn:(NSString*)columnName;
275 |
276 | /** Result set `NSDate` value for column.
277 |
278 | @param columnIdx Zero-based index for column.
279 |
280 | @return `NSDate` value of the result set's column.
281 |
282 | */
283 |
284 | - (NSDate*)dateForColumnIndex:(int)columnIdx;
285 |
286 | /** Result set `NSData` value for column.
287 |
288 | This is useful when storing binary data in table (such as image or the like).
289 |
290 | @param columnName `NSString` value of the name of the column.
291 |
292 | @return `NSData` value of the result set's column.
293 |
294 | */
295 |
296 | - (NSData*)dataForColumn:(NSString*)columnName;
297 |
298 | /** Result set `NSData` value for column.
299 |
300 | @param columnIdx Zero-based index for column.
301 |
302 | @return `NSData` value of the result set's column.
303 | */
304 |
305 | - (NSData*)dataForColumnIndex:(int)columnIdx;
306 |
307 | /** Result set `(const unsigned char *)` value for column.
308 |
309 | @param columnName `NSString` value of the name of the column.
310 |
311 | @return `(const unsigned char *)` value of the result set's column.
312 | */
313 |
314 | - (const unsigned char *)UTF8StringForColumnName:(NSString*)columnName;
315 |
316 | /** Result set `(const unsigned char *)` value for column.
317 |
318 | @param columnIdx Zero-based index for column.
319 |
320 | @return `(const unsigned char *)` value of the result set's column.
321 | */
322 |
323 | - (const unsigned char *)UTF8StringForColumnIndex:(int)columnIdx;
324 |
325 | /** Result set object for column.
326 |
327 | @param columnName `NSString` value of the name of the column.
328 |
329 | @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object.
330 |
331 | @see objectForKeyedSubscript:
332 | */
333 |
334 | - (id)objectForColumnName:(NSString*)columnName;
335 |
336 | /** Result set object for column.
337 |
338 | @param columnIdx Zero-based index for column.
339 |
340 | @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object.
341 |
342 | @see objectAtIndexedSubscript:
343 | */
344 |
345 | - (id)objectForColumnIndex:(int)columnIdx;
346 |
347 | /** Result set object for column.
348 |
349 | This method allows the use of the "boxed" syntax supported in Modern Objective-C. For example, by defining this method, the following syntax is now supported:
350 |
351 | id result = rs[@"employee_name"];
352 |
353 | This simplified syntax is equivalent to calling:
354 |
355 | id result = [rs objectForKeyedSubscript:@"employee_name"];
356 |
357 | which is, it turns out, equivalent to calling:
358 |
359 | id result = [rs objectForColumnName:@"employee_name"];
360 |
361 | @param columnName `NSString` value of the name of the column.
362 |
363 | @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object.
364 | */
365 |
366 | - (id)objectForKeyedSubscript:(NSString *)columnName;
367 |
368 | /** Result set object for column.
369 |
370 | This method allows the use of the "boxed" syntax supported in Modern Objective-C. For example, by defining this method, the following syntax is now supported:
371 |
372 | id result = rs[0];
373 |
374 | This simplified syntax is equivalent to calling:
375 |
376 | id result = [rs objectForKeyedSubscript:0];
377 |
378 | which is, it turns out, equivalent to calling:
379 |
380 | id result = [rs objectForColumnName:0];
381 |
382 | @param columnIdx Zero-based index for column.
383 |
384 | @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object.
385 | */
386 |
387 | - (id)objectAtIndexedSubscript:(int)columnIdx;
388 |
389 | /** Result set `NSData` value for column.
390 |
391 | @param columnName `NSString` value of the name of the column.
392 |
393 | @return `NSData` value of the result set's column.
394 |
395 | @warning If you are going to use this data after you iterate over the next row, or after you close the
396 | result set, make sure to make a copy of the data first (or just use ``/``)
397 | If you don't, you're going to be in a world of hurt when you try and use the data.
398 |
399 | */
400 |
401 | - (NSData*)dataNoCopyForColumn:(NSString*)columnName NS_RETURNS_NOT_RETAINED;
402 |
403 | /** Result set `NSData` value for column.
404 |
405 | @param columnIdx Zero-based index for column.
406 |
407 | @return `NSData` value of the result set's column.
408 |
409 | @warning If you are going to use this data after you iterate over the next row, or after you close the
410 | result set, make sure to make a copy of the data first (or just use ``/``)
411 | If you don't, you're going to be in a world of hurt when you try and use the data.
412 |
413 | */
414 |
415 | - (NSData*)dataNoCopyForColumnIndex:(int)columnIdx NS_RETURNS_NOT_RETAINED;
416 |
417 | /** Is the column `NULL`?
418 |
419 | @param columnIdx Zero-based index for column.
420 |
421 | @return `YES` if column is `NULL`; `NO` if not `NULL`.
422 | */
423 |
424 | - (BOOL)columnIndexIsNull:(int)columnIdx;
425 |
426 | /** Is the column `NULL`?
427 |
428 | @param columnName `NSString` value of the name of the column.
429 |
430 | @return `YES` if column is `NULL`; `NO` if not `NULL`.
431 | */
432 |
433 | - (BOOL)columnIsNull:(NSString*)columnName;
434 |
435 |
436 | /** Returns a dictionary of the row results mapped to case sensitive keys of the column names.
437 |
438 | @returns `NSDictionary` of the row results.
439 |
440 | @warning The keys to the dictionary are case sensitive of the column names.
441 | */
442 |
443 | - (NSDictionary*)resultDictionary;
444 |
445 | /** Returns a dictionary of the row results
446 |
447 | @see resultDictionary
448 |
449 | @warning **Deprecated**: Please use `` instead. Also, beware that `` is case sensitive!
450 | */
451 |
452 | - (NSDictionary*)resultDict __attribute__ ((deprecated));
453 |
454 | ///-----------------------------
455 | /// @name Key value coding magic
456 | ///-----------------------------
457 |
458 | /** Performs `setValue` to yield support for key value observing.
459 |
460 | @param object The object for which the values will be set. This is the key-value-coding compliant object that you might, for example, observe.
461 |
462 | */
463 |
464 | - (void)kvcMagic:(id)object;
465 |
466 |
467 | @end
468 |
469 |
--------------------------------------------------------------------------------
/JYGenerationCode/JYGenerationCode.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 5C4680F91CE8495A0013D24F /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5C4680F81CE8495A0013D24F /* AppDelegate.m */; };
11 | 5C4680FC1CE8495A0013D24F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5C4680FB1CE8495A0013D24F /* main.m */; };
12 | 5C4680FF1CE8495A0013D24F /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5C4680FE1CE8495A0013D24F /* ViewController.m */; };
13 | 5C4681011CE8495A0013D24F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5C4681001CE8495A0013D24F /* Assets.xcassets */; };
14 | 5C4681041CE8495A0013D24F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5C4681021CE8495A0013D24F /* Main.storyboard */; };
15 | 5C46810F1CE8495A0013D24F /* JYGenerationCodeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5C46810E1CE8495A0013D24F /* JYGenerationCodeTests.m */; };
16 | 5C46811A1CE8495A0013D24F /* JYGenerationCodeUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5C4681191CE8495A0013D24F /* JYGenerationCodeUITests.m */; };
17 | 5C46812E1CE85AB40013D24F /* code.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 5C46812D1CE85AB40013D24F /* code.bundle */; };
18 | /* End PBXBuildFile section */
19 |
20 | /* Begin PBXContainerItemProxy section */
21 | 5C46810B1CE8495A0013D24F /* PBXContainerItemProxy */ = {
22 | isa = PBXContainerItemProxy;
23 | containerPortal = 5C4680EC1CE8495A0013D24F /* Project object */;
24 | proxyType = 1;
25 | remoteGlobalIDString = 5C4680F31CE8495A0013D24F;
26 | remoteInfo = JYGenerationCode;
27 | };
28 | 5C4681161CE8495A0013D24F /* PBXContainerItemProxy */ = {
29 | isa = PBXContainerItemProxy;
30 | containerPortal = 5C4680EC1CE8495A0013D24F /* Project object */;
31 | proxyType = 1;
32 | remoteGlobalIDString = 5C4680F31CE8495A0013D24F;
33 | remoteInfo = JYGenerationCode;
34 | };
35 | /* End PBXContainerItemProxy section */
36 |
37 | /* Begin PBXFileReference section */
38 | 5C4680F41CE8495A0013D24F /* JYGenerationCode.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JYGenerationCode.app; sourceTree = BUILT_PRODUCTS_DIR; };
39 | 5C4680F71CE8495A0013D24F /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
40 | 5C4680F81CE8495A0013D24F /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
41 | 5C4680FB1CE8495A0013D24F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
42 | 5C4680FD1CE8495A0013D24F /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; };
43 | 5C4680FE1CE8495A0013D24F /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; };
44 | 5C4681001CE8495A0013D24F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
45 | 5C4681031CE8495A0013D24F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
46 | 5C4681051CE8495A0013D24F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
47 | 5C46810A1CE8495A0013D24F /* JYGenerationCodeTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = JYGenerationCodeTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
48 | 5C46810E1CE8495A0013D24F /* JYGenerationCodeTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JYGenerationCodeTests.m; sourceTree = ""; };
49 | 5C4681101CE8495A0013D24F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
50 | 5C4681151CE8495A0013D24F /* JYGenerationCodeUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = JYGenerationCodeUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
51 | 5C4681191CE8495A0013D24F /* JYGenerationCodeUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JYGenerationCodeUITests.m; sourceTree = ""; };
52 | 5C46811B1CE8495A0013D24F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
53 | 5C46812D1CE85AB40013D24F /* code.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = code.bundle; sourceTree = ""; };
54 | /* End PBXFileReference section */
55 |
56 | /* Begin PBXFrameworksBuildPhase section */
57 | 5C4680F11CE8495A0013D24F /* Frameworks */ = {
58 | isa = PBXFrameworksBuildPhase;
59 | buildActionMask = 2147483647;
60 | files = (
61 | );
62 | runOnlyForDeploymentPostprocessing = 0;
63 | };
64 | 5C4681071CE8495A0013D24F /* Frameworks */ = {
65 | isa = PBXFrameworksBuildPhase;
66 | buildActionMask = 2147483647;
67 | files = (
68 | );
69 | runOnlyForDeploymentPostprocessing = 0;
70 | };
71 | 5C4681121CE8495A0013D24F /* Frameworks */ = {
72 | isa = PBXFrameworksBuildPhase;
73 | buildActionMask = 2147483647;
74 | files = (
75 | );
76 | runOnlyForDeploymentPostprocessing = 0;
77 | };
78 | /* End PBXFrameworksBuildPhase section */
79 |
80 | /* Begin PBXGroup section */
81 | 5C4680EB1CE8495A0013D24F = {
82 | isa = PBXGroup;
83 | children = (
84 | 5C4680F61CE8495A0013D24F /* JYGenerationCode */,
85 | 5C46810D1CE8495A0013D24F /* JYGenerationCodeTests */,
86 | 5C4681181CE8495A0013D24F /* JYGenerationCodeUITests */,
87 | 5C4680F51CE8495A0013D24F /* Products */,
88 | );
89 | sourceTree = "";
90 | };
91 | 5C4680F51CE8495A0013D24F /* Products */ = {
92 | isa = PBXGroup;
93 | children = (
94 | 5C4680F41CE8495A0013D24F /* JYGenerationCode.app */,
95 | 5C46810A1CE8495A0013D24F /* JYGenerationCodeTests.xctest */,
96 | 5C4681151CE8495A0013D24F /* JYGenerationCodeUITests.xctest */,
97 | );
98 | name = Products;
99 | sourceTree = "";
100 | };
101 | 5C4680F61CE8495A0013D24F /* JYGenerationCode */ = {
102 | isa = PBXGroup;
103 | children = (
104 | 5C46812D1CE85AB40013D24F /* code.bundle */,
105 | 5C4680F71CE8495A0013D24F /* AppDelegate.h */,
106 | 5C4680F81CE8495A0013D24F /* AppDelegate.m */,
107 | 5C4680FD1CE8495A0013D24F /* ViewController.h */,
108 | 5C4680FE1CE8495A0013D24F /* ViewController.m */,
109 | 5C4681001CE8495A0013D24F /* Assets.xcassets */,
110 | 5C4681021CE8495A0013D24F /* Main.storyboard */,
111 | 5C4681051CE8495A0013D24F /* Info.plist */,
112 | 5C4680FA1CE8495A0013D24F /* Supporting Files */,
113 | );
114 | path = JYGenerationCode;
115 | sourceTree = "";
116 | };
117 | 5C4680FA1CE8495A0013D24F /* Supporting Files */ = {
118 | isa = PBXGroup;
119 | children = (
120 | 5C4680FB1CE8495A0013D24F /* main.m */,
121 | );
122 | name = "Supporting Files";
123 | sourceTree = "";
124 | };
125 | 5C46810D1CE8495A0013D24F /* JYGenerationCodeTests */ = {
126 | isa = PBXGroup;
127 | children = (
128 | 5C46810E1CE8495A0013D24F /* JYGenerationCodeTests.m */,
129 | 5C4681101CE8495A0013D24F /* Info.plist */,
130 | );
131 | path = JYGenerationCodeTests;
132 | sourceTree = "";
133 | };
134 | 5C4681181CE8495A0013D24F /* JYGenerationCodeUITests */ = {
135 | isa = PBXGroup;
136 | children = (
137 | 5C4681191CE8495A0013D24F /* JYGenerationCodeUITests.m */,
138 | 5C46811B1CE8495A0013D24F /* Info.plist */,
139 | );
140 | path = JYGenerationCodeUITests;
141 | sourceTree = "";
142 | };
143 | /* End PBXGroup section */
144 |
145 | /* Begin PBXNativeTarget section */
146 | 5C4680F31CE8495A0013D24F /* JYGenerationCode */ = {
147 | isa = PBXNativeTarget;
148 | buildConfigurationList = 5C46811E1CE8495A0013D24F /* Build configuration list for PBXNativeTarget "JYGenerationCode" */;
149 | buildPhases = (
150 | 5C4680F01CE8495A0013D24F /* Sources */,
151 | 5C4680F11CE8495A0013D24F /* Frameworks */,
152 | 5C4680F21CE8495A0013D24F /* Resources */,
153 | );
154 | buildRules = (
155 | );
156 | dependencies = (
157 | );
158 | name = JYGenerationCode;
159 | productName = JYGenerationCode;
160 | productReference = 5C4680F41CE8495A0013D24F /* JYGenerationCode.app */;
161 | productType = "com.apple.product-type.application";
162 | };
163 | 5C4681091CE8495A0013D24F /* JYGenerationCodeTests */ = {
164 | isa = PBXNativeTarget;
165 | buildConfigurationList = 5C4681211CE8495A0013D24F /* Build configuration list for PBXNativeTarget "JYGenerationCodeTests" */;
166 | buildPhases = (
167 | 5C4681061CE8495A0013D24F /* Sources */,
168 | 5C4681071CE8495A0013D24F /* Frameworks */,
169 | 5C4681081CE8495A0013D24F /* Resources */,
170 | );
171 | buildRules = (
172 | );
173 | dependencies = (
174 | 5C46810C1CE8495A0013D24F /* PBXTargetDependency */,
175 | );
176 | name = JYGenerationCodeTests;
177 | productName = JYGenerationCodeTests;
178 | productReference = 5C46810A1CE8495A0013D24F /* JYGenerationCodeTests.xctest */;
179 | productType = "com.apple.product-type.bundle.unit-test";
180 | };
181 | 5C4681141CE8495A0013D24F /* JYGenerationCodeUITests */ = {
182 | isa = PBXNativeTarget;
183 | buildConfigurationList = 5C4681241CE8495A0013D24F /* Build configuration list for PBXNativeTarget "JYGenerationCodeUITests" */;
184 | buildPhases = (
185 | 5C4681111CE8495A0013D24F /* Sources */,
186 | 5C4681121CE8495A0013D24F /* Frameworks */,
187 | 5C4681131CE8495A0013D24F /* Resources */,
188 | );
189 | buildRules = (
190 | );
191 | dependencies = (
192 | 5C4681171CE8495A0013D24F /* PBXTargetDependency */,
193 | );
194 | name = JYGenerationCodeUITests;
195 | productName = JYGenerationCodeUITests;
196 | productReference = 5C4681151CE8495A0013D24F /* JYGenerationCodeUITests.xctest */;
197 | productType = "com.apple.product-type.bundle.ui-testing";
198 | };
199 | /* End PBXNativeTarget section */
200 |
201 | /* Begin PBXProject section */
202 | 5C4680EC1CE8495A0013D24F /* Project object */ = {
203 | isa = PBXProject;
204 | attributes = {
205 | LastUpgradeCheck = 0730;
206 | ORGANIZATIONNAME = weijingyun;
207 | TargetAttributes = {
208 | 5C4680F31CE8495A0013D24F = {
209 | CreatedOnToolsVersion = 7.3;
210 | };
211 | 5C4681091CE8495A0013D24F = {
212 | CreatedOnToolsVersion = 7.3;
213 | TestTargetID = 5C4680F31CE8495A0013D24F;
214 | };
215 | 5C4681141CE8495A0013D24F = {
216 | CreatedOnToolsVersion = 7.3;
217 | TestTargetID = 5C4680F31CE8495A0013D24F;
218 | };
219 | };
220 | };
221 | buildConfigurationList = 5C4680EF1CE8495A0013D24F /* Build configuration list for PBXProject "JYGenerationCode" */;
222 | compatibilityVersion = "Xcode 3.2";
223 | developmentRegion = English;
224 | hasScannedForEncodings = 0;
225 | knownRegions = (
226 | en,
227 | Base,
228 | );
229 | mainGroup = 5C4680EB1CE8495A0013D24F;
230 | productRefGroup = 5C4680F51CE8495A0013D24F /* Products */;
231 | projectDirPath = "";
232 | projectRoot = "";
233 | targets = (
234 | 5C4680F31CE8495A0013D24F /* JYGenerationCode */,
235 | 5C4681091CE8495A0013D24F /* JYGenerationCodeTests */,
236 | 5C4681141CE8495A0013D24F /* JYGenerationCodeUITests */,
237 | );
238 | };
239 | /* End PBXProject section */
240 |
241 | /* Begin PBXResourcesBuildPhase section */
242 | 5C4680F21CE8495A0013D24F /* Resources */ = {
243 | isa = PBXResourcesBuildPhase;
244 | buildActionMask = 2147483647;
245 | files = (
246 | 5C46812E1CE85AB40013D24F /* code.bundle in Resources */,
247 | 5C4681011CE8495A0013D24F /* Assets.xcassets in Resources */,
248 | 5C4681041CE8495A0013D24F /* Main.storyboard in Resources */,
249 | );
250 | runOnlyForDeploymentPostprocessing = 0;
251 | };
252 | 5C4681081CE8495A0013D24F /* Resources */ = {
253 | isa = PBXResourcesBuildPhase;
254 | buildActionMask = 2147483647;
255 | files = (
256 | );
257 | runOnlyForDeploymentPostprocessing = 0;
258 | };
259 | 5C4681131CE8495A0013D24F /* Resources */ = {
260 | isa = PBXResourcesBuildPhase;
261 | buildActionMask = 2147483647;
262 | files = (
263 | );
264 | runOnlyForDeploymentPostprocessing = 0;
265 | };
266 | /* End PBXResourcesBuildPhase section */
267 |
268 | /* Begin PBXSourcesBuildPhase section */
269 | 5C4680F01CE8495A0013D24F /* Sources */ = {
270 | isa = PBXSourcesBuildPhase;
271 | buildActionMask = 2147483647;
272 | files = (
273 | 5C4680FF1CE8495A0013D24F /* ViewController.m in Sources */,
274 | 5C4680FC1CE8495A0013D24F /* main.m in Sources */,
275 | 5C4680F91CE8495A0013D24F /* AppDelegate.m in Sources */,
276 | );
277 | runOnlyForDeploymentPostprocessing = 0;
278 | };
279 | 5C4681061CE8495A0013D24F /* Sources */ = {
280 | isa = PBXSourcesBuildPhase;
281 | buildActionMask = 2147483647;
282 | files = (
283 | 5C46810F1CE8495A0013D24F /* JYGenerationCodeTests.m in Sources */,
284 | );
285 | runOnlyForDeploymentPostprocessing = 0;
286 | };
287 | 5C4681111CE8495A0013D24F /* Sources */ = {
288 | isa = PBXSourcesBuildPhase;
289 | buildActionMask = 2147483647;
290 | files = (
291 | 5C46811A1CE8495A0013D24F /* JYGenerationCodeUITests.m in Sources */,
292 | );
293 | runOnlyForDeploymentPostprocessing = 0;
294 | };
295 | /* End PBXSourcesBuildPhase section */
296 |
297 | /* Begin PBXTargetDependency section */
298 | 5C46810C1CE8495A0013D24F /* PBXTargetDependency */ = {
299 | isa = PBXTargetDependency;
300 | target = 5C4680F31CE8495A0013D24F /* JYGenerationCode */;
301 | targetProxy = 5C46810B1CE8495A0013D24F /* PBXContainerItemProxy */;
302 | };
303 | 5C4681171CE8495A0013D24F /* PBXTargetDependency */ = {
304 | isa = PBXTargetDependency;
305 | target = 5C4680F31CE8495A0013D24F /* JYGenerationCode */;
306 | targetProxy = 5C4681161CE8495A0013D24F /* PBXContainerItemProxy */;
307 | };
308 | /* End PBXTargetDependency section */
309 |
310 | /* Begin PBXVariantGroup section */
311 | 5C4681021CE8495A0013D24F /* Main.storyboard */ = {
312 | isa = PBXVariantGroup;
313 | children = (
314 | 5C4681031CE8495A0013D24F /* Base */,
315 | );
316 | name = Main.storyboard;
317 | sourceTree = "";
318 | };
319 | /* End PBXVariantGroup section */
320 |
321 | /* Begin XCBuildConfiguration section */
322 | 5C46811C1CE8495A0013D24F /* Debug */ = {
323 | isa = XCBuildConfiguration;
324 | buildSettings = {
325 | ALWAYS_SEARCH_USER_PATHS = NO;
326 | CLANG_ANALYZER_NONNULL = YES;
327 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
328 | CLANG_CXX_LIBRARY = "libc++";
329 | CLANG_ENABLE_MODULES = YES;
330 | CLANG_ENABLE_OBJC_ARC = YES;
331 | CLANG_WARN_BOOL_CONVERSION = YES;
332 | CLANG_WARN_CONSTANT_CONVERSION = YES;
333 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
334 | CLANG_WARN_EMPTY_BODY = YES;
335 | CLANG_WARN_ENUM_CONVERSION = YES;
336 | CLANG_WARN_INT_CONVERSION = YES;
337 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
338 | CLANG_WARN_UNREACHABLE_CODE = YES;
339 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
340 | CODE_SIGN_IDENTITY = "-";
341 | COPY_PHASE_STRIP = NO;
342 | DEBUG_INFORMATION_FORMAT = dwarf;
343 | ENABLE_STRICT_OBJC_MSGSEND = YES;
344 | ENABLE_TESTABILITY = YES;
345 | GCC_C_LANGUAGE_STANDARD = gnu99;
346 | GCC_DYNAMIC_NO_PIC = NO;
347 | GCC_NO_COMMON_BLOCKS = YES;
348 | GCC_OPTIMIZATION_LEVEL = 0;
349 | GCC_PREPROCESSOR_DEFINITIONS = (
350 | "DEBUG=1",
351 | "$(inherited)",
352 | );
353 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
354 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
355 | GCC_WARN_UNDECLARED_SELECTOR = YES;
356 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
357 | GCC_WARN_UNUSED_FUNCTION = YES;
358 | GCC_WARN_UNUSED_VARIABLE = YES;
359 | MACOSX_DEPLOYMENT_TARGET = 10.11;
360 | MTL_ENABLE_DEBUG_INFO = YES;
361 | ONLY_ACTIVE_ARCH = YES;
362 | SDKROOT = macosx;
363 | };
364 | name = Debug;
365 | };
366 | 5C46811D1CE8495A0013D24F /* Release */ = {
367 | isa = XCBuildConfiguration;
368 | buildSettings = {
369 | ALWAYS_SEARCH_USER_PATHS = NO;
370 | CLANG_ANALYZER_NONNULL = YES;
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 = "-";
385 | COPY_PHASE_STRIP = NO;
386 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
387 | ENABLE_NS_ASSERTIONS = NO;
388 | ENABLE_STRICT_OBJC_MSGSEND = YES;
389 | GCC_C_LANGUAGE_STANDARD = gnu99;
390 | GCC_NO_COMMON_BLOCKS = YES;
391 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
392 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
393 | GCC_WARN_UNDECLARED_SELECTOR = YES;
394 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
395 | GCC_WARN_UNUSED_FUNCTION = YES;
396 | GCC_WARN_UNUSED_VARIABLE = YES;
397 | MACOSX_DEPLOYMENT_TARGET = 10.11;
398 | MTL_ENABLE_DEBUG_INFO = NO;
399 | SDKROOT = macosx;
400 | };
401 | name = Release;
402 | };
403 | 5C46811F1CE8495A0013D24F /* Debug */ = {
404 | isa = XCBuildConfiguration;
405 | buildSettings = {
406 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
407 | COMBINE_HIDPI_IMAGES = YES;
408 | INFOPLIST_FILE = JYGenerationCode/Info.plist;
409 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
410 | PRODUCT_BUNDLE_IDENTIFIER = yunyunxiao.JYGenerationCode;
411 | PRODUCT_NAME = "$(TARGET_NAME)";
412 | };
413 | name = Debug;
414 | };
415 | 5C4681201CE8495A0013D24F /* Release */ = {
416 | isa = XCBuildConfiguration;
417 | buildSettings = {
418 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
419 | COMBINE_HIDPI_IMAGES = YES;
420 | INFOPLIST_FILE = JYGenerationCode/Info.plist;
421 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
422 | PRODUCT_BUNDLE_IDENTIFIER = yunyunxiao.JYGenerationCode;
423 | PRODUCT_NAME = "$(TARGET_NAME)";
424 | };
425 | name = Release;
426 | };
427 | 5C4681221CE8495A0013D24F /* Debug */ = {
428 | isa = XCBuildConfiguration;
429 | buildSettings = {
430 | BUNDLE_LOADER = "$(TEST_HOST)";
431 | COMBINE_HIDPI_IMAGES = YES;
432 | INFOPLIST_FILE = JYGenerationCodeTests/Info.plist;
433 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
434 | PRODUCT_BUNDLE_IDENTIFIER = yunyunxiao.JYGenerationCodeTests;
435 | PRODUCT_NAME = "$(TARGET_NAME)";
436 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/JYGenerationCode.app/Contents/MacOS/JYGenerationCode";
437 | };
438 | name = Debug;
439 | };
440 | 5C4681231CE8495A0013D24F /* Release */ = {
441 | isa = XCBuildConfiguration;
442 | buildSettings = {
443 | BUNDLE_LOADER = "$(TEST_HOST)";
444 | COMBINE_HIDPI_IMAGES = YES;
445 | INFOPLIST_FILE = JYGenerationCodeTests/Info.plist;
446 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
447 | PRODUCT_BUNDLE_IDENTIFIER = yunyunxiao.JYGenerationCodeTests;
448 | PRODUCT_NAME = "$(TARGET_NAME)";
449 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/JYGenerationCode.app/Contents/MacOS/JYGenerationCode";
450 | };
451 | name = Release;
452 | };
453 | 5C4681251CE8495A0013D24F /* Debug */ = {
454 | isa = XCBuildConfiguration;
455 | buildSettings = {
456 | COMBINE_HIDPI_IMAGES = YES;
457 | INFOPLIST_FILE = JYGenerationCodeUITests/Info.plist;
458 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
459 | PRODUCT_BUNDLE_IDENTIFIER = yunyunxiao.JYGenerationCodeUITests;
460 | PRODUCT_NAME = "$(TARGET_NAME)";
461 | TEST_TARGET_NAME = JYGenerationCode;
462 | };
463 | name = Debug;
464 | };
465 | 5C4681261CE8495A0013D24F /* Release */ = {
466 | isa = XCBuildConfiguration;
467 | buildSettings = {
468 | COMBINE_HIDPI_IMAGES = YES;
469 | INFOPLIST_FILE = JYGenerationCodeUITests/Info.plist;
470 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
471 | PRODUCT_BUNDLE_IDENTIFIER = yunyunxiao.JYGenerationCodeUITests;
472 | PRODUCT_NAME = "$(TARGET_NAME)";
473 | TEST_TARGET_NAME = JYGenerationCode;
474 | };
475 | name = Release;
476 | };
477 | /* End XCBuildConfiguration section */
478 |
479 | /* Begin XCConfigurationList section */
480 | 5C4680EF1CE8495A0013D24F /* Build configuration list for PBXProject "JYGenerationCode" */ = {
481 | isa = XCConfigurationList;
482 | buildConfigurations = (
483 | 5C46811C1CE8495A0013D24F /* Debug */,
484 | 5C46811D1CE8495A0013D24F /* Release */,
485 | );
486 | defaultConfigurationIsVisible = 0;
487 | defaultConfigurationName = Release;
488 | };
489 | 5C46811E1CE8495A0013D24F /* Build configuration list for PBXNativeTarget "JYGenerationCode" */ = {
490 | isa = XCConfigurationList;
491 | buildConfigurations = (
492 | 5C46811F1CE8495A0013D24F /* Debug */,
493 | 5C4681201CE8495A0013D24F /* Release */,
494 | );
495 | defaultConfigurationIsVisible = 0;
496 | };
497 | 5C4681211CE8495A0013D24F /* Build configuration list for PBXNativeTarget "JYGenerationCodeTests" */ = {
498 | isa = XCConfigurationList;
499 | buildConfigurations = (
500 | 5C4681221CE8495A0013D24F /* Debug */,
501 | 5C4681231CE8495A0013D24F /* Release */,
502 | );
503 | defaultConfigurationIsVisible = 0;
504 | };
505 | 5C4681241CE8495A0013D24F /* Build configuration list for PBXNativeTarget "JYGenerationCodeUITests" */ = {
506 | isa = XCConfigurationList;
507 | buildConfigurations = (
508 | 5C4681251CE8495A0013D24F /* Debug */,
509 | 5C4681261CE8495A0013D24F /* Release */,
510 | );
511 | defaultConfigurationIsVisible = 0;
512 | };
513 | /* End XCConfigurationList section */
514 | };
515 | rootObject = 5C4680EC1CE8495A0013D24F /* Project object */;
516 | }
517 |
--------------------------------------------------------------------------------