├── 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 | ![enter image description here](http://images2015.cnblogs.com/blog/737816/201611/737816-20161103101051924-1899693155.jpg) 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 | --------------------------------------------------------------------------------