├── .DS_Store ├── FLFMDBManager.podspec ├── FLFMDBManager ├── .DS_Store ├── DataBase_safe │ ├── .DS_Store │ ├── FLFMDBQueueManager.h │ └── FLFMDBQueueManager.m └── DataBase_unsafe │ ├── .DS_Store │ ├── FLFMDBManager.h │ └── FLFMDBManager.m ├── FLFMDBManagerDemo ├── .DS_Store ├── FLFMDBManager.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcuserdata │ │ │ └── clarence.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcuserdata │ │ ├── clarence.xcuserdatad │ │ └── xcschemes │ │ │ ├── FLFMDBManager.xcscheme │ │ │ └── xcschememanagement.plist │ │ └── kongfanlie.xcuserdatad │ │ └── xcschemes │ │ ├── FLFMDBManager.xcscheme │ │ └── xcschememanagement.plist ├── FLFMDBManager.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ ├── clarence.xcuserdatad │ │ ├── UserInterfaceState.xcuserstate │ │ └── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ └── kongfanlie.xcuserdatad │ │ ├── UserInterfaceState.xcuserstate │ │ └── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist ├── FLFMDBManager │ ├── .DS_Store │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── FLBookModel.h │ ├── FLBookModel.m │ ├── FLFMDBManager.h │ ├── FLFMDBManager.m │ ├── FLFMDBQueueManager.h │ ├── FLFMDBQueueManager.m │ ├── FLPenModel.h │ ├── FLPenModel.m │ ├── FLStudentModel.h │ ├── FLStudentModel.m │ ├── FLStudentTableViewCell.h │ ├── FLStudentTableViewCell.m │ ├── FLStudentTableViewCell.xib │ ├── Info.plist │ ├── TestViewController.h │ ├── TestViewController.m │ ├── ViewController.h │ ├── ViewController.m │ └── main.m ├── Podfile ├── Podfile.lock └── Pods │ ├── FMDB │ ├── LICENSE.txt │ ├── README.markdown │ └── src │ │ └── fmdb │ │ ├── FMDB.h │ │ ├── FMDatabase.h │ │ ├── FMDatabase.m │ │ ├── FMDatabaseAdditions.h │ │ ├── FMDatabaseAdditions.m │ │ ├── FMDatabasePool.h │ │ ├── FMDatabasePool.m │ │ ├── FMDatabaseQueue.h │ │ ├── FMDatabaseQueue.m │ │ ├── FMResultSet.h │ │ └── FMResultSet.m │ ├── Manifest.lock │ ├── Pods.xcodeproj │ ├── project.pbxproj │ └── xcuserdata │ │ ├── clarence.xcuserdatad │ │ └── xcschemes │ │ │ ├── FMDB.xcscheme │ │ │ ├── Pods-FLFMDBManager.xcscheme │ │ │ └── xcschememanagement.plist │ │ └── kongfanlie.xcuserdatad │ │ └── xcschemes │ │ ├── FMDB.xcscheme │ │ ├── Pods-FLFMDBManager.xcscheme │ │ └── xcschememanagement.plist │ └── Target Support Files │ ├── FMDB │ ├── FMDB-dummy.m │ ├── FMDB-prefix.pch │ ├── FMDB-umbrella.h │ ├── FMDB.modulemap │ ├── FMDB.xcconfig │ └── Info.plist │ └── Pods-FLFMDBManager │ ├── Info.plist │ ├── Pods-FLFMDBManager-acknowledgements.markdown │ ├── Pods-FLFMDBManager-acknowledgements.plist │ ├── Pods-FLFMDBManager-dummy.m │ ├── Pods-FLFMDBManager-frameworks.sh │ ├── Pods-FLFMDBManager-resources.sh │ ├── Pods-FLFMDBManager-umbrella.h │ ├── Pods-FLFMDBManager.debug.xcconfig │ ├── Pods-FLFMDBManager.modulemap │ └── Pods-FLFMDBManager.release.xcconfig └── README.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitkong/FLFMDBManager/01d4bbae0fa8ede6fa7a04303b424b23084c928b/.DS_Store -------------------------------------------------------------------------------- /FLFMDBManager.podspec: -------------------------------------------------------------------------------- 1 | 2 | Pod::Spec.new do |s| 3 | 4 | # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 5 | 6 | s.name = "FLFMDBManager" 7 | s.version = "0.0.1" 8 | s.summary = "FMDB 再封装,面向模型" 9 | s.description = <<-DESC 10 | FMDB 再封装,面向模型,只需要传入模型或模型数组 11 | DESC 12 | s.homepage = "https://github.com/gitkong/FLFMDBManager" 13 | 14 | 15 | # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 16 | s.license = "MIT (example)" 17 | s.license = { :type => "MIT", :file => "FILE_LICENSE" } 18 | 19 | 20 | # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 21 | s.author = { "gitKong" => "13751855378@163.com" } 22 | 23 | 24 | # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 25 | s.platform = :ios 26 | s.source = { :git => "https://github.com/gitkong/FLFMDBManager.git", :tag => "#{s.version}" } 27 | 28 | 29 | # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 30 | s.source_files = "FLFMDBManagerDemo/FLFMDBManager/*.{h,m}" 31 | #s.exclude_files = "Classes/Exclude" 32 | #s.public_header_files = "FLFMDBManager/FLFMDBManager.h" 33 | 34 | 35 | # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 36 | s.requires_arc = true 37 | 38 | 39 | end 40 | -------------------------------------------------------------------------------- /FLFMDBManager/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitkong/FLFMDBManager/01d4bbae0fa8ede6fa7a04303b424b23084c928b/FLFMDBManager/.DS_Store -------------------------------------------------------------------------------- /FLFMDBManager/DataBase_safe/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitkong/FLFMDBManager/01d4bbae0fa8ede6fa7a04303b424b23084c928b/FLFMDBManager/DataBase_safe/.DS_Store -------------------------------------------------------------------------------- /FLFMDBManager/DataBase_safe/FLFMDBQueueManager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * author gitKong 3 | * 4 | * 个人博客 https://gitKong.github.io 5 | * gitHub https://github.com/gitkong 6 | * cocoaChina http://code.cocoachina.com/user/ 7 | * 简书 http://www.jianshu.com/users/fe5700cfb223/latest_articles 8 | * QQ 279761135 9 | * 微信公众号 原创技术分享 10 | * 喜欢就给个like 和 star 喔~ 11 | */ 12 | 13 | #import 14 | #import 15 | 16 | #define FLDB_DEFAULT_NAME @"gitkong" 17 | 18 | #define FLFMDBQUEUEMANAGER [FLFMDBQueueManager shareManager:FLDB_DEFAULT_NAME] 19 | /** 20 | * @author gitKong 21 | * 22 | * 多数据库操作暂时不开放,有问题需要解决,敬请期待 23 | */ 24 | //#define FLFMDBQUEUEMANAGERX(DB_NAME) [FLFMDBQueueManager shareManager:DB_NAME] 25 | 26 | @interface FLFMDBQueueManager : NSObject 27 | /** 28 | * @author gitKong 29 | * 30 | * 单例创建,项目唯一 31 | */ 32 | + (instancetype)shareManager:(NSString *)fl_dbName; 33 | 34 | #pragma mark -- 创表 35 | 36 | /** 37 | * @author gitKong 38 | * 39 | * 根据类名创建表,如果有则跳过,没有才创建 40 | 41 | * flag:YES表示创建表格操作执行成功 或者 表格已经存在,NO则失败 42 | 43 | * 注意:此方法创建表格后不会自动关闭数据库,当开发者执行其他操作(删除数据库除外)后会自动关闭数据库 44 | 45 | * 建议使用insert创建表格并添加数据 46 | */ 47 | - (void)fl_createTable:(Class)modelClass complete:(void(^)(FLFMDBQueueManager *manager, BOOL flag))complete; 48 | 49 | 50 | #pragma mark -- 插入 51 | 52 | /** 53 | * @author gitKong 54 | * 55 | * @param model 插入单个模型或者模型数组,如果此时传入的模型对应的FLDBID在表中已经存在,则替换更新旧的 56 | 57 | * flag:YES表示插入数据操作执行成功,NO则失败 58 | 59 | * 注意:如果此时没创建表就自动先创建,表名为模型类名,数据插入完毕后会自动关闭数据库 60 | 61 | * 建议直接使用insert创建表格并添加数据,因为create方法执行完不会自动关闭数据库 62 | */ 63 | - (void)fl_insertModel:(id)model complete:(void(^)(FLFMDBQueueManager *manager, BOOL flag))complete; 64 | 65 | #pragma mark -- 查询 66 | 67 | /** 68 | * @author gitKong 69 | * 70 | * 查询指定表是否存在 71 | 72 | * flag:YES表示操作执行成功并且 modelClass 表格存在,NO则操作失败或者 modelClass 表格不存在 73 | 74 | * 注意:操作执行完毕会自动关闭数据库 75 | */ 76 | - (void)fl_isExitTable:(Class)modelClass complete:(void(^)(FLFMDBQueueManager *manager, BOOL flag))complete; 77 | /** 78 | * @author gitKong 79 | * 80 | * 查找指定表中指定DBID的模型 81 | 82 | * model:不等于nil,表示查询数据操作执行成功并有数据,返回查询成功的模型数据,nil则表示查询操作失败 或者 查询成功但数据为空 或者 对应的表格不存在 83 | 84 | * 注意:操作执行完毕会自动关闭数据库 85 | */ 86 | - (void)fl_searchModel:(Class)modelClass byID:(NSString *)FLDBID complete:(void(^)(FLFMDBQueueManager *manager,id model))complete; 87 | /** 88 | * @author gitKong 89 | * 90 | * 查找指定表中模型数组(所有的) 91 | 92 | * modelArr:不等于nil,表示查询数据操作执行成功并有数据,返回查询成功的模型数据,nil则表示查询操作失败 或者 查询成功但数据为空 或者 对应的表格不存在 93 | 94 | * 注意:操作执行完毕会自动关闭数据库 95 | */ 96 | - (void)fl_searchModelArr:(Class)modelClass complete:(void(^)(FLFMDBQueueManager *manager,NSArray *modelArr))complete; 97 | 98 | #pragma mark -- 修改 99 | 100 | /** 101 | * @author gitKong 102 | * 103 | * 修改指定DBID的模型 104 | 105 | * flag:YES表示更新操作执行成功,NO则操作失败 或者 对应的表格不存在 106 | 107 | * 注意:操作执行完毕会自动关闭数据库 108 | */ 109 | 110 | - (void)fl_modifyModel:(id)model byID:(NSString *)FLDBID complete:(void(^)(FLFMDBQueueManager *manager, BOOL flag))complete; 111 | 112 | 113 | #pragma mark -- 删除 114 | /** 115 | * @author gitKong 116 | * 117 | * 删除指定表 118 | 119 | * flag:YES表示删除操作执行成功,NO则操作失败 或者 对应的表格不存在 120 | 121 | * 注意:操作执行完毕会自动关闭数据库 122 | */ 123 | - (void)fl_dropTable:(Class)modelClass complete:(void(^)(FLFMDBQueueManager *manager, BOOL flag))complete; 124 | /** 125 | * @author gitKong 126 | * 127 | * 删除数据库 128 | 129 | * 注意:操作不涉及到数据库操作,如果你通过create创建后执行此操作,不会关闭数据库 130 | 131 | * @return YES 表示删除成功,NO则删除失败 132 | */ 133 | - (BOOL)fl_dropDB; 134 | /** 135 | * @author gitKong 136 | * 137 | * 删除指定表格的所有数据 138 | 139 | * flag:YES表示删除操作执行成功,NO则操作失败 或者 对应的表格不存在 或者 没有对应数据可以删除 140 | 141 | * 注意:操作执行完毕会自动关闭数据库 142 | */ 143 | - (void)fl_deleteAllModel:(Class)modelClass complete:(void(^)(FLFMDBQueueManager *manager, BOOL flag))complete; 144 | 145 | /** 146 | * @author gitKong 147 | * 148 | * 删除指定表中指定DBID的模型 149 | 150 | * flag:YES表示删除操作执行成功,NO则操作失败 或者 对应的表格不存在 或者 没有对应数据可以删除 151 | 152 | * 注意:操作执行完毕会自动关闭数据库 153 | */ 154 | - (void)fl_deleteModel:(Class)modelClass byId:(NSString *)FLDBID complete:(void(^)(FLFMDBQueueManager *manager, BOOL flag))complete; 155 | @end 156 | -------------------------------------------------------------------------------- /FLFMDBManager/DataBase_unsafe/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitkong/FLFMDBManager/01d4bbae0fa8ede6fa7a04303b424b23084c928b/FLFMDBManager/DataBase_unsafe/.DS_Store -------------------------------------------------------------------------------- /FLFMDBManager/DataBase_unsafe/FLFMDBManager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * author gitKong 3 | * 4 | * 个人博客 https://gitKong.github.io 5 | * gitHub https://github.com/gitkong 6 | * cocoaChina http://code.cocoachina.com/user/ 7 | * 简书 http://www.jianshu.com/users/fe5700cfb223/latest_articles 8 | * QQ 279761135 9 | * 微信公众号 原创技术分享 10 | * 喜欢就给个like 和 star 喔~ 11 | */ 12 | 13 | 14 | #import 15 | 16 | #define FLDB_DEFAULT_NAME @"gitkong" 17 | #define FLFMDBMANAGER [FLFMDBManager shareManager:FLDB_DEFAULT_NAME] 18 | #define FLFMDBMANAGERX(DB_NAME) [FLFMDBManager shareManager:DB_NAME] 19 | 20 | @interface FLFMDBManager : NSObject 21 | 22 | /** 23 | * @author Clarence 24 | * 25 | * 单例创建,项目唯一 26 | */ 27 | + (instancetype)shareManager:(NSString *)fl_dbName; 28 | 29 | #pragma mark -- 创表 30 | 31 | /** 32 | * @author Clarence 33 | * 34 | * 根据类名创建表,如果有则跳过,没有才创建,执行完毕后自动关闭数据库 35 | 36 | * @return YES表示创建表格操作执行成功 或者 表格已经存在,NO则失败 37 | */ 38 | - (BOOL)fl_createTable:(Class)modelClass; 39 | 40 | #pragma mark -- 插入 41 | 42 | /** 43 | * @author Clarence 44 | * 45 | * @param model 插入单个模型或者模型数组,如果此时传入的模型对应的FLDBID在表中已经存在,则替换更新旧的 46 | * 如果没创建表就自动先创建,表名为模型类名 47 | * 此时执行完毕后自动关闭数据库 48 | 49 | * @return YES表示创建表格操作执行成功 或者 表格已经存在,NO则失败 50 | */ 51 | - (BOOL)fl_insertModel:(id)model; 52 | 53 | 54 | 55 | #pragma mark -- 查询 56 | /** 57 | * @author Clarence 58 | * 59 | * 查询指定表是否存在,执行完毕后自动关闭数据库 60 | 61 | * @return YES表示操作执行成功并且 modelClass 表格存在,NO则操作失败或者 modelClass 表格不存在 62 | */ 63 | - (BOOL)fl_isExitTable:(Class)modelClass; 64 | 65 | /** 66 | * @author Clarence 67 | * 68 | * 查找指定表中指定DBID的模型,执行完毕后自动关闭数据库 69 | 70 | * @return 不等于nil,表示查询数据操作执行成功并有数据,返回查询成功的模型数据,nil则表示查询操作失败 或者 查询成功但数据为空 或者 对应的表格不存在 71 | */ 72 | - (id)fl_searchModel:(Class)modelClass byID:(NSString *)FLDBID; 73 | /** 74 | * @author Clarence 75 | * 76 | * 查找指定表中模型数组(所有的),执行完毕后自动关闭数据库 77 | 78 | * @return 不等于nil,表示查询数据操作执行成功并有数据,返回查询成功的模型数据,nil则表示查询操作失败 或者 查询成功但数据为空 或者 对应的表格不存在 79 | */ 80 | - (NSArray *)fl_searchModelArr:(Class)modelClass; 81 | 82 | 83 | #pragma mark -- 修改 84 | 85 | /** 86 | * @author Clarence 87 | * 88 | * 修改指定DBID的模型,执行完毕后自动关闭数据库 89 | 90 | * @return YES表示更新操作执行成功,NO则操作失败 或者 对应的表格不存在 91 | */ 92 | 93 | - (BOOL)fl_modifyModel:(id)model byID:(NSString *)FLDBID; 94 | 95 | 96 | #pragma mark -- 删除 97 | /** 98 | * @author Clarence 99 | * 100 | * 删除指定表,执行完毕后自动关闭数据库 101 | 102 | * @return YES表示删除操作执行成功,NO则操作失败 或者 对应的表格不存在 103 | */ 104 | - (BOOL)fl_dropTable:(Class)modelClass; 105 | /** 106 | * @author gitKong 107 | * 108 | * 删除数据库 109 | 110 | * @return 操作不涉及到数据库操作 YES 表示删除成功,NO则删除失败 111 | */ 112 | - (BOOL)fl_dropDB; 113 | /** 114 | * @author Clarence 115 | * 116 | * 删除指定表格的所有数据,执行完毕后自动关闭数据库 117 | 118 | * @return YES表示删除操作执行成功,NO则操作失败 或者 对应的表格不存在 或者 没有对应数据可以删除 119 | */ 120 | - (BOOL)fl_deleteAllModel:(Class)modelClass; 121 | 122 | /** 123 | * @author Clarence 124 | * 125 | * 删除指定表中指定DBID的模型,执行完毕后自动关闭数据库 126 | 127 | * @return YES表示删除操作执行成功,NO则操作失败 或者 对应的表格不存在 或者 没有对应数据可以删除 128 | */ 129 | - (BOOL)fl_deleteModel:(Class)modelClass byId:(NSString *)FLDBID; 130 | 131 | @end 132 | -------------------------------------------------------------------------------- /FLFMDBManager/DataBase_unsafe/FLFMDBManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // FLFMDBManager.m 3 | // FLFMDBManager 4 | // 5 | // Created by clarence on 16/11/17. 6 | // Copyright © 2016年 clarence. All rights reserved. 7 | // 8 | 9 | #import "FLFMDBManager.h" 10 | #import "FMDB.h" 11 | #import 12 | #import 13 | 14 | #define FLCURRENTDB (FMDatabase *)self.dataBaseDictM[self.dbName] 15 | 16 | @interface FLFMDBManager () 17 | @property (nonatomic,copy)NSString *dbName; 18 | @property (nonatomic,strong)NSMutableDictionary *dataBaseDictM; 19 | @end 20 | 21 | @implementation FLFMDBManager 22 | 23 | + (instancetype)shareManager:(NSString *)fl_dbName{ 24 | 25 | // 1、获取沙盒中数据库的路径 26 | NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject; 27 | NSString *tempDBName = nil; 28 | if (fl_dbName && ![fl_dbName isEqualToString:@""]) { 29 | tempDBName = fl_dbName; 30 | } 31 | else{ 32 | tempDBName = FLDB_DEFAULT_NAME; 33 | } 34 | 35 | NSString *sqlFilePath = [path stringByAppendingPathComponent:[tempDBName stringByAppendingString:@".sqlite"]]; 36 | 37 | // 2、判断 caches 文件夹是否存在.不存在则创建 38 | NSFileManager *manager = [NSFileManager defaultManager]; 39 | BOOL isDirectory = YES; 40 | BOOL tag = [manager fileExistsAtPath:sqlFilePath isDirectory:&isDirectory]; 41 | 42 | 43 | static FLFMDBManager *instance; 44 | static dispatch_once_t onceToken; 45 | dispatch_once(&onceToken, ^{ 46 | instance = [[self alloc] init]; 47 | instance.dataBaseDictM = [NSMutableDictionary dictionary]; 48 | if (tag) { 49 | FMDatabase *dataBase = [FMDatabase databaseWithPath:sqlFilePath]; 50 | [instance.dataBaseDictM setValue:dataBase forKey:tempDBName]; 51 | } 52 | }); 53 | 54 | if (!tag) { 55 | [manager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:NULL]; 56 | // 通过路径创建数据库 57 | FMDatabase *dataBase = [FMDatabase databaseWithPath:sqlFilePath]; 58 | [instance.dataBaseDictM setValue:dataBase forKey:tempDBName]; 59 | } 60 | 61 | instance.dbName = tempDBName; 62 | 63 | return instance; 64 | } 65 | 66 | - (BOOL)fl_createTable:(Class)modelClass{ 67 | 68 | return [self fl_createTable:modelClass autoCloseDB:YES]; 69 | } 70 | 71 | 72 | - (BOOL)fl_insertModel:(id)model{ 73 | if ([model isKindOfClass:[NSArray class]] || [model isKindOfClass:[NSMutableArray class]]) { 74 | NSArray *modelArr = (NSArray *)model; 75 | return [self fl_insertModelArr:modelArr]; 76 | } 77 | else{ 78 | return [self fl_insertModel:model autoCloseDB:YES]; 79 | } 80 | } 81 | 82 | 83 | - (id)fl_searchModel:(Class)modelClass byID:(NSString *)FLDBID{ 84 | return [self fl_searchModel:modelClass byID:FLDBID autoCloseDB:YES]; 85 | } 86 | 87 | - (NSArray *)fl_searchModelArr:(Class)modelClass{ 88 | return [self fl_searchModelArr:modelClass autoCloseDB:YES]; 89 | } 90 | 91 | 92 | 93 | 94 | - (BOOL)fl_modifyModel:(id)model byID:(NSString *)FLDBID{ 95 | return [self fl_modifyModel:model byID:FLDBID autoCloseDB:YES]; 96 | } 97 | 98 | - (BOOL)fl_dropTable:(Class)modelClass{ 99 | if ([FLCURRENTDB open]) { 100 | // FL_ISEXITTABLE(modelClass); 101 | if(![self isExitTable:modelClass autoCloseDB:NO])return NO; 102 | // 删除数据 103 | NSMutableString *sql = [NSMutableString stringWithFormat:@"DROP TABLE %@;",modelClass]; 104 | BOOL success = [FLCURRENTDB executeUpdate:sql]; 105 | [FLCURRENTDB close]; 106 | return success; 107 | } 108 | else{ 109 | return NO; 110 | } 111 | } 112 | 113 | - (BOOL)fl_dropDB{ 114 | NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject; 115 | NSString *sqlFilePath = [path stringByAppendingPathComponent:[self.dbName stringByAppendingString:@".sqlite"]]; 116 | NSFileManager *fileManager = [NSFileManager defaultManager]; 117 | return [fileManager removeItemAtPath:sqlFilePath error:NULL]; 118 | } 119 | 120 | - (BOOL)fl_deleteAllModel:(Class)modelClass{ 121 | if ([FLCURRENTDB open]) { 122 | // FL_ISEXITTABLE(modelClass); 123 | if(![self isExitTable:modelClass autoCloseDB:NO])return NO; 124 | NSArray *modelArr = [self fl_searchModelArr:modelClass autoCloseDB:NO]; 125 | if (modelArr && modelArr.count) { 126 | // 删除数据 127 | NSMutableString *sql = [NSMutableString stringWithFormat:@"DELETE FROM %@;",modelClass]; 128 | BOOL success = [FLCURRENTDB executeUpdate:sql]; 129 | [FLCURRENTDB close]; 130 | return success; 131 | } 132 | return NO; 133 | } 134 | else{ 135 | return NO; 136 | } 137 | } 138 | 139 | - (BOOL)fl_deleteModel:(Class)modelClass byId:(NSString *)FLDBID{ 140 | if ([FLCURRENTDB open]) { 141 | // FL_ISEXITTABLE(modelClass); 142 | if(![self isExitTable:modelClass autoCloseDB:NO])return NO; 143 | if ([self fl_searchModel:modelClass byID:FLDBID autoCloseDB:NO]) { 144 | // 删除数据 145 | NSMutableString *sql = [NSMutableString stringWithFormat:@"DELETE FROM %@ WHERE FLDBID = '%@';",modelClass,FLDBID]; 146 | BOOL success = [FLCURRENTDB executeUpdate:sql]; 147 | [FLCURRENTDB close]; 148 | return success; 149 | } 150 | return NO; 151 | } 152 | else{ 153 | return NO; 154 | } 155 | } 156 | 157 | - (BOOL)fl_isExitTable:(Class)modelClass{ 158 | return [self isExitTable:modelClass autoCloseDB:YES]; 159 | } 160 | 161 | 162 | #pragma mark -- private method 163 | /** 164 | * @author Clarence 165 | * 166 | * 创建表的SQL语句 167 | */ 168 | - (NSString *)createTableSQL:(Class)modelClass{ 169 | NSMutableString *sqlPropertyM = [NSMutableString stringWithFormat:@"CREATE TABLE IF NOT EXISTS %@ (id INTEGER PRIMARY KEY AUTOINCREMENT ",modelClass]; 170 | 171 | unsigned int outCount; 172 | Ivar * ivars = class_copyIvarList(modelClass, &outCount); 173 | for (int i = 0; i < outCount; i ++) { 174 | Ivar ivar = ivars[i]; 175 | NSString * key = [NSString stringWithUTF8String:ivar_getName(ivar)] ; 176 | if([[key substringToIndex:1] isEqualToString:@"_"]){ 177 | key = [key stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:@""]; 178 | } 179 | [sqlPropertyM appendFormat:@", %@",key]; 180 | } 181 | [sqlPropertyM appendString:@")"]; 182 | 183 | return sqlPropertyM; 184 | } 185 | 186 | /** 187 | * @author Clarence 188 | * 189 | * 创建插入表的SQL语句 190 | */ 191 | - (NSString *)createInsertSQL:(id)model{ 192 | NSMutableString *sqlValueM = [NSMutableString stringWithFormat:@"INSERT OR REPLACE INTO %@ (",[model class]]; 193 | unsigned int outCount; 194 | Ivar * ivars = class_copyIvarList([model class], &outCount); 195 | for (int i = 0; i < outCount; i ++) { 196 | Ivar ivar = ivars[i]; 197 | NSString * key = [NSString stringWithUTF8String:ivar_getName(ivar)] ; 198 | if([[key substringToIndex:1] isEqualToString:@"_"]){ 199 | key = [key stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:@""]; 200 | } 201 | 202 | if (i == 0) { 203 | [sqlValueM appendString:key]; 204 | } 205 | else{ 206 | [sqlValueM appendFormat:@", %@",key]; 207 | } 208 | } 209 | [sqlValueM appendString:@") VALUES ("]; 210 | 211 | for (int i = 0; i < outCount; i ++) { 212 | Ivar ivar = ivars[i]; 213 | NSString * key = [NSString stringWithUTF8String:ivar_getName(ivar)] ; 214 | if([[key substringToIndex:1] isEqualToString:@"_"]){ 215 | key = [key stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:@""]; 216 | } 217 | 218 | id value = [model valueForKey:key]; 219 | if ([value isKindOfClass:[NSDictionary class]] || [value isKindOfClass:[NSMutableDictionary class]] || [value isKindOfClass:[NSArray class]] || [value isKindOfClass:[NSMutableArray class]]) { 220 | value = [NSString stringWithFormat:@"%@",value]; 221 | } 222 | if (i == 0) { 223 | // sql 语句中字符串需要单引号或者双引号括起来 224 | [sqlValueM appendFormat:@"%@",[value isKindOfClass:[NSString class]] ? [NSString stringWithFormat:@"'%@'",value] : value]; 225 | } 226 | else{ 227 | [sqlValueM appendFormat:@", %@",[value isKindOfClass:[NSString class]] ? [NSString stringWithFormat:@"'%@'",value] : value]; 228 | } 229 | } 230 | // [sqlValueM appendFormat:@" WHERE FLDBID = '%@'",[model valueForKey:@"FLDBID"]]; 231 | [sqlValueM appendString:@");"]; 232 | 233 | return sqlValueM; 234 | } 235 | 236 | /** 237 | * @author Clarence 238 | * 239 | * 指定的表是否存在 240 | */ 241 | - (BOOL)isExitTable:(Class)modelClass autoCloseDB:(BOOL)autoCloseDB{ 242 | if ([FLCURRENTDB open]){ 243 | // BOOL success = [FLCURRENTDB executeQuery:[NSString stringWithFormat:@"SELECT * FROM %@",modelClass]]; 244 | // // 操作完毕是否需要关闭 245 | // if (autoCloseDB) { 246 | // [FLCURRENTDB close]; 247 | // } 248 | // return success; 249 | FMResultSet *rs = [FLCURRENTDB executeQuery:@"select count(*) as 'count' from sqlite_master where type ='table' and name = ?", modelClass]; 250 | while ([rs next]){ 251 | NSInteger count = [rs intForColumn:@"count"]; 252 | 253 | if (0 == count){ 254 | // 操作完毕是否需要关闭 255 | if (autoCloseDB) { 256 | [FLCURRENTDB close]; 257 | } 258 | return NO; 259 | } 260 | else{ 261 | // 操作完毕是否需要关闭 262 | if (autoCloseDB) { 263 | [FLCURRENTDB close]; 264 | } 265 | return YES; 266 | } 267 | } 268 | // 操作完毕是否需要关闭 269 | if (autoCloseDB) { 270 | [FLCURRENTDB close]; 271 | } 272 | return NO; 273 | } 274 | else{ 275 | return NO; 276 | } 277 | } 278 | 279 | - (BOOL)fl_createTable:(Class)modelClass autoCloseDB:(BOOL)autoCloseDB{ 280 | if ([FLCURRENTDB open]) { 281 | // 创表,判断是否已经存在 282 | if ([self isExitTable:modelClass autoCloseDB:NO]) { 283 | if (autoCloseDB) { 284 | [FLCURRENTDB close]; 285 | } 286 | return YES; 287 | } 288 | else{ 289 | BOOL success = [FLCURRENTDB executeUpdate:[self createTableSQL:modelClass]]; 290 | // 关闭数据库 291 | if (autoCloseDB) { 292 | [FLCURRENTDB close]; 293 | } 294 | return success; 295 | } 296 | } 297 | else{ 298 | return NO; 299 | } 300 | } 301 | 302 | - (BOOL)fl_insertModel:(id)model autoCloseDB:(BOOL)autoCloseDB{ 303 | NSAssert(![model isKindOfClass:[UIResponder class]], @"必须保证模型是NSObject或者NSObject的子类,同时不响应事件"); 304 | if ([FLCURRENTDB open]) { 305 | // 没有表的时候,先创建再插入 306 | 307 | // 此时有三步操作,第一步处理完不关闭数据库 308 | if (![self isExitTable:[model class] autoCloseDB:NO]) { 309 | // 第二步处理完不关闭数据库 310 | BOOL success = [self fl_createTable:[model class] autoCloseDB:NO]; 311 | if (success) { 312 | NSString *fl_dbid = [model valueForKey:@"FLDBID"]; 313 | id judgeModle = [self fl_searchModel:[model class] byID:fl_dbid autoCloseDB:NO]; 314 | 315 | if ([[judgeModle valueForKey:@"FLDBID"] isEqualToString:fl_dbid]) { 316 | BOOL updataSuccess = [self fl_modifyModel:model byID:fl_dbid autoCloseDB:NO]; 317 | if (autoCloseDB) { 318 | [FLCURRENTDB close]; 319 | } 320 | return updataSuccess; 321 | } 322 | else{ 323 | BOOL insertSuccess = [FLCURRENTDB executeUpdate:[self createInsertSQL:model]]; 324 | // 最后一步操作完毕,询问是否需要关闭 325 | if (autoCloseDB) { 326 | [FLCURRENTDB close]; 327 | } 328 | return insertSuccess; 329 | } 330 | 331 | } 332 | else { 333 | // 第二步操作失败,询问是否需要关闭,可能是创表失败,或者是已经有表 334 | if (autoCloseDB) { 335 | [FLCURRENTDB close]; 336 | } 337 | return NO; 338 | } 339 | } 340 | // 已经创建有对应的表,直接插入 341 | else{ 342 | NSString *fl_dbid = [model valueForKey:@"FLDBID"]; 343 | id judgeModle = [self fl_searchModel:[model class] byID:fl_dbid autoCloseDB:NO]; 344 | 345 | if ([[judgeModle valueForKey:@"FLDBID"] isEqualToString:fl_dbid]) { 346 | BOOL updataSuccess = [self fl_modifyModel:model byID:fl_dbid autoCloseDB:NO]; 347 | if (autoCloseDB) { 348 | [FLCURRENTDB close]; 349 | } 350 | return updataSuccess; 351 | } 352 | else{ 353 | BOOL insertSuccess = [FLCURRENTDB executeUpdate:[self createInsertSQL:model]]; 354 | // 最后一步操作完毕,询问是否需要关闭 355 | if (autoCloseDB) { 356 | [FLCURRENTDB close]; 357 | } 358 | return insertSuccess; 359 | } 360 | } 361 | } 362 | else{ 363 | return NO; 364 | } 365 | } 366 | 367 | - (BOOL)fl_insertModelArr:(NSArray *)modelArr{ 368 | BOOL flag = YES; 369 | for (id model in modelArr) { 370 | // 处理过程中不关闭数据库 371 | if (![self fl_insertModel:model autoCloseDB:NO]) { 372 | flag = NO; 373 | } 374 | } 375 | // 处理完毕关闭数据库 376 | [FLCURRENTDB close]; 377 | // 全部插入成功才返回YES 378 | return flag; 379 | } 380 | 381 | - (NSArray *)fl_searchModelArr:(Class)modelClass autoCloseDB:(BOOL)autoCloseDB{ 382 | if ([FLCURRENTDB open]) { 383 | // FL_ISEXITTABLE(modelClass); 384 | if(![self isExitTable:modelClass autoCloseDB:NO])return nil; 385 | // 查询数据 386 | FMResultSet *rs = [FLCURRENTDB executeQuery:[NSString stringWithFormat:@"SELECT * FROM %@",modelClass]]; 387 | NSMutableArray *modelArrM = [NSMutableArray array]; 388 | // 遍历结果集 389 | while ([rs next]) { 390 | 391 | // 创建对象 392 | id object = [[modelClass class] new]; 393 | 394 | unsigned int outCount; 395 | Ivar * ivars = class_copyIvarList(modelClass, &outCount); 396 | for (int i = 0; i < outCount; i ++) { 397 | Ivar ivar = ivars[i]; 398 | NSString * key = [NSString stringWithUTF8String:ivar_getName(ivar)] ; 399 | if([[key substringToIndex:1] isEqualToString:@"_"]){ 400 | key = [key stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:@""]; 401 | } 402 | 403 | id value = [rs objectForColumnName:key]; 404 | if ([value isKindOfClass:[NSString class]]) { 405 | NSData *data = [value dataUsingEncoding:NSUTF8StringEncoding]; 406 | id result = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; 407 | if ([result isKindOfClass:[NSDictionary class]] || [result isKindOfClass:[NSMutableDictionary class]] || [result isKindOfClass:[NSArray class]] || [result isKindOfClass:[NSMutableArray class]]) { 408 | [object setValue:result forKey:key]; 409 | } 410 | else{ 411 | [object setValue:value forKey:key]; 412 | } 413 | } 414 | else{ 415 | [object setValue:value forKey:key]; 416 | } 417 | } 418 | 419 | // 添加 420 | [modelArrM addObject:object]; 421 | } 422 | if (autoCloseDB) { 423 | [FLCURRENTDB close]; 424 | } 425 | return modelArrM; 426 | } 427 | else{ 428 | return nil; 429 | } 430 | } 431 | 432 | - (id)fl_searchModel:(Class)modelClass byID:(NSString *)FLDBID autoCloseDB:(BOOL)autoCloseDB{ 433 | if ([FLCURRENTDB open]) { 434 | // FL_ISEXITTABLE(modelClass); 435 | if(![self isExitTable:modelClass autoCloseDB:NO]){ 436 | if (autoCloseDB) { 437 | [FLCURRENTDB close]; 438 | } 439 | return nil; 440 | } 441 | // 查询数据 442 | FMResultSet *rs = [FLCURRENTDB executeQuery:[NSString stringWithFormat:@"SELECT * FROM %@ WHERE FLDBID = '%@';",modelClass,FLDBID]]; 443 | // 创建对象 444 | id object = nil; 445 | // 遍历结果集 446 | while ([rs next]) { 447 | object = [[modelClass class] new]; 448 | unsigned int outCount; 449 | Ivar * ivars = class_copyIvarList(modelClass, &outCount); 450 | for (int i = 0; i < outCount; i ++) { 451 | Ivar ivar = ivars[i]; 452 | NSString * key = [NSString stringWithUTF8String:ivar_getName(ivar)] ; 453 | if([[key substringToIndex:1] isEqualToString:@"_"]){ 454 | key = [key stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:@""]; 455 | } 456 | 457 | id value = [rs objectForColumnName:key]; 458 | if ([value isKindOfClass:[NSString class]]) { 459 | NSData *data = [value dataUsingEncoding:NSUTF8StringEncoding]; 460 | id result = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; 461 | if ([result isKindOfClass:[NSDictionary class]] || [result isKindOfClass:[NSMutableDictionary class]] || [result isKindOfClass:[NSArray class]] || [result isKindOfClass:[NSMutableArray class]]) { 462 | [object setValue:result forKey:key]; 463 | } 464 | else{ 465 | [object setValue:value forKey:key]; 466 | } 467 | } 468 | else{ 469 | [object setValue:value forKey:key]; 470 | } 471 | } 472 | 473 | } 474 | if (autoCloseDB) { 475 | [FLCURRENTDB close]; 476 | } 477 | return object; 478 | } 479 | else{ 480 | if (autoCloseDB) { 481 | [FLCURRENTDB close]; 482 | } 483 | return nil; 484 | } 485 | 486 | } 487 | 488 | - (BOOL)fl_modifyModel:(id)model byID:(NSString *)FLDBID autoCloseDB:(BOOL)autoCloseDB{ 489 | if ([FLCURRENTDB open]) { 490 | // FL_ISEXITTABLE([model class]); 491 | if(![self isExitTable:[model class] autoCloseDB:NO]){ 492 | if (autoCloseDB) { 493 | [FLCURRENTDB close]; 494 | } 495 | return NO; 496 | } 497 | // 修改数据@"UPDATE t_student SET name = 'liwx' WHERE age > 12 AND age < 15;" 498 | NSMutableString *sql = [NSMutableString stringWithFormat:@"UPDATE %@ SET ",[model class]]; 499 | unsigned int outCount; 500 | class_copyIvarList([model superclass],&outCount); 501 | Ivar * ivars = class_copyIvarList([model class], &outCount); 502 | for (int i = 0; i < outCount; i ++) { 503 | Ivar ivar = ivars[i]; 504 | NSString * key = [NSString stringWithUTF8String:ivar_getName(ivar)] ; 505 | if([[key substringToIndex:1] isEqualToString:@"_"]){ 506 | key = [key stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:@""]; 507 | } 508 | id value = [model valueForKey:key]; 509 | /** 510 | * @author gitKong 511 | * 512 | * 防止属性没赋值 513 | */ 514 | if (value == [NSNull null]) { 515 | value = @""; 516 | } 517 | if (i == 0) { 518 | [sql appendFormat:@"%@ = %@",key,([value isKindOfClass:[NSString class]] || [value isKindOfClass:[NSDictionary class]] || [value isKindOfClass:[NSMutableDictionary class]] || [value isKindOfClass:[NSArray class]] || [value isKindOfClass:[NSMutableArray class]]) ? [NSString stringWithFormat:@"'%@'",value] : value]; 519 | } 520 | else{ 521 | [sql appendFormat:@",%@ = %@",key,([value isKindOfClass:[NSString class]] || [value isKindOfClass:[NSDictionary class]] || [value isKindOfClass:[NSMutableDictionary class]] || [value isKindOfClass:[NSArray class]] || [value isKindOfClass:[NSMutableArray class]]) ? [NSString stringWithFormat:@"'%@'",value] : value]; 522 | } 523 | } 524 | 525 | [sql appendFormat:@" WHERE FLDBID = '%@';",FLDBID]; 526 | BOOL success = [FLCURRENTDB executeUpdate:sql]; 527 | if (autoCloseDB) { 528 | [FLCURRENTDB close]; 529 | } 530 | return success; 531 | } 532 | else{ 533 | if (autoCloseDB) { 534 | [FLCURRENTDB close]; 535 | } 536 | return NO; 537 | } 538 | } 539 | 540 | @end 541 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitkong/FLFMDBManager/01d4bbae0fa8ede6fa7a04303b424b23084c928b/FLFMDBManagerDemo/.DS_Store -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager.xcodeproj/project.xcworkspace/xcuserdata/clarence.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitkong/FLFMDBManager/01d4bbae0fa8ede6fa7a04303b424b23084c928b/FLFMDBManagerDemo/FLFMDBManager.xcodeproj/project.xcworkspace/xcuserdata/clarence.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager.xcodeproj/xcuserdata/clarence.xcuserdatad/xcschemes/FLFMDBManager.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager.xcodeproj/xcuserdata/clarence.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | FLFMDBManager.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 11FF1BE21DDD9FC200EBCAB8 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager.xcodeproj/xcuserdata/kongfanlie.xcuserdatad/xcschemes/FLFMDBManager.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager.xcodeproj/xcuserdata/kongfanlie.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | FLFMDBManager.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 11FF1BE21DDD9FC200EBCAB8 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager.xcworkspace/xcuserdata/clarence.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitkong/FLFMDBManager/01d4bbae0fa8ede6fa7a04303b424b23084c928b/FLFMDBManagerDemo/FLFMDBManager.xcworkspace/xcuserdata/clarence.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager.xcworkspace/xcuserdata/clarence.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager.xcworkspace/xcuserdata/kongfanlie.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitkong/FLFMDBManager/01d4bbae0fa8ede6fa7a04303b424b23084c928b/FLFMDBManagerDemo/FLFMDBManager.xcworkspace/xcuserdata/kongfanlie.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager.xcworkspace/xcuserdata/kongfanlie.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitkong/FLFMDBManager/01d4bbae0fa8ede6fa7a04303b424b23084c928b/FLFMDBManagerDemo/FLFMDBManager/.DS_Store -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // FLFMDBManager 4 | // 5 | // Created by clarence on 16/11/17. 6 | // Copyright © 2016年 clarence. 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 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // FLFMDBManager 4 | // 5 | // Created by clarence on 16/11/17. 6 | // Copyright © 2016年 clarence. 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 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // 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. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // 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. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // 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. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager/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 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager/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 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager/FLBookModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // FLBookModel.h 3 | // FLFMDBManager 4 | // 5 | // Created by clarence on 17/2/10. 6 | // Copyright © 2017年 clarence. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface FLBookModel : NSObject 12 | /** 13 | * @author Clarence 14 | * 15 | * 数据库中绑定指定模型的DBID(一般对应后台返回模型数据中的唯一id) 16 | * 属性名称必须是FLDBID,适应框架 17 | */ 18 | @property (nonatomic,copy)NSString *FLDBID; 19 | 20 | @property (nonatomic,copy)NSString *name; 21 | @end 22 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager/FLBookModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // FLBookModel.m 3 | // FLFMDBManager 4 | // 5 | // Created by clarence on 17/2/10. 6 | // Copyright © 2017年 clarence. All rights reserved. 7 | // 8 | 9 | #import "FLBookModel.h" 10 | 11 | @implementation FLBookModel 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager/FLFMDBManager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * author gitKong 3 | * 4 | * 个人博客 https://gitKong.github.io 5 | * gitHub https://github.com/gitkong 6 | * cocoaChina http://code.cocoachina.com/user/ 7 | * 简书 http://www.jianshu.com/users/fe5700cfb223/latest_articles 8 | * QQ 279761135 9 | * 微信公众号 原创技术分享 10 | * 喜欢就给个like 和 star 喔~ 11 | */ 12 | 13 | 14 | #import 15 | 16 | #define FLDB_DEFAULT_NAME @"gitkong" 17 | #define FLFMDBMANAGER [FLFMDBManager shareManager:FLDB_DEFAULT_NAME] 18 | #define FLFMDBMANAGERX(DB_NAME) [FLFMDBManager shareManager:DB_NAME] 19 | 20 | @interface FLFMDBManager : NSObject 21 | 22 | /** 23 | * @author Clarence 24 | * 25 | * 单例创建,项目唯一 26 | */ 27 | + (instancetype)shareManager:(NSString *)fl_dbName; 28 | 29 | #pragma mark -- 创表 30 | 31 | /** 32 | * @author Clarence 33 | * 34 | * 根据类名创建表,如果有则跳过,没有才创建,执行完毕后自动关闭数据库 35 | 36 | * @return YES表示创建表格操作执行成功 或者 表格已经存在,NO则失败 37 | */ 38 | - (BOOL)fl_createTable:(Class)modelClass; 39 | 40 | #pragma mark -- 插入 41 | 42 | /** 43 | * @author Clarence 44 | * 45 | * @param model 插入单个模型或者模型数组,如果此时传入的模型对应的FLDBID在表中已经存在,则替换更新旧的 46 | * 如果没创建表就自动先创建,表名为模型类名 47 | * 此时执行完毕后自动关闭数据库 48 | 49 | * @return YES表示创建表格操作执行成功 或者 表格已经存在,NO则失败 50 | */ 51 | - (BOOL)fl_insertModel:(id)model; 52 | 53 | 54 | 55 | #pragma mark -- 查询 56 | /** 57 | * @author Clarence 58 | * 59 | * 查询指定表是否存在,执行完毕后自动关闭数据库 60 | 61 | * @return YES表示操作执行成功并且 modelClass 表格存在,NO则操作失败或者 modelClass 表格不存在 62 | */ 63 | - (BOOL)fl_isExitTable:(Class)modelClass; 64 | 65 | /** 66 | * @author Clarence 67 | * 68 | * 查找指定表中指定DBID的模型,执行完毕后自动关闭数据库 69 | 70 | * @return 不等于nil,表示查询数据操作执行成功并有数据,返回查询成功的模型数据,nil则表示查询操作失败 或者 查询成功但数据为空 或者 对应的表格不存在 71 | */ 72 | - (id)fl_searchModel:(Class)modelClass byID:(NSString *)FLDBID; 73 | /** 74 | * @author Clarence 75 | * 76 | * 查找指定表中模型数组(所有的),执行完毕后自动关闭数据库 77 | 78 | * @return 不等于nil,表示查询数据操作执行成功并有数据,返回查询成功的模型数据,nil则表示查询操作失败 或者 查询成功但数据为空 或者 对应的表格不存在 79 | */ 80 | - (NSArray *)fl_searchModelArr:(Class)modelClass; 81 | 82 | 83 | #pragma mark -- 修改 84 | 85 | /** 86 | * @author Clarence 87 | * 88 | * 修改指定DBID的模型,执行完毕后自动关闭数据库 89 | 90 | * @return YES表示更新操作执行成功,NO则操作失败 或者 对应的表格不存在 91 | */ 92 | 93 | - (BOOL)fl_modifyModel:(id)model byID:(NSString *)FLDBID; 94 | 95 | 96 | #pragma mark -- 删除 97 | /** 98 | * @author Clarence 99 | * 100 | * 删除指定表,执行完毕后自动关闭数据库 101 | 102 | * @return YES表示删除操作执行成功,NO则操作失败 或者 对应的表格不存在 103 | */ 104 | - (BOOL)fl_dropTable:(Class)modelClass; 105 | /** 106 | * @author gitKong 107 | * 108 | * 删除数据库 109 | 110 | * @return 操作不涉及到数据库操作 YES 表示删除成功,NO则删除失败 111 | */ 112 | - (BOOL)fl_dropDB; 113 | /** 114 | * @author Clarence 115 | * 116 | * 删除指定表格的所有数据,执行完毕后自动关闭数据库 117 | 118 | * @return YES表示删除操作执行成功,NO则操作失败 或者 对应的表格不存在 或者 没有对应数据可以删除 119 | */ 120 | - (BOOL)fl_deleteAllModel:(Class)modelClass; 121 | 122 | /** 123 | * @author Clarence 124 | * 125 | * 删除指定表中指定DBID的模型,执行完毕后自动关闭数据库 126 | 127 | * @return YES表示删除操作执行成功,NO则操作失败 或者 对应的表格不存在 或者 没有对应数据可以删除 128 | */ 129 | - (BOOL)fl_deleteModel:(Class)modelClass byId:(NSString *)FLDBID; 130 | 131 | @end 132 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager/FLFMDBQueueManager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * author gitKong 3 | * 4 | * 个人博客 https://gitKong.github.io 5 | * gitHub https://github.com/gitkong 6 | * cocoaChina http://code.cocoachina.com/user/ 7 | * 简书 http://www.jianshu.com/users/fe5700cfb223/latest_articles 8 | * QQ 279761135 9 | * 微信公众号 原创技术分享 10 | * 喜欢就给个like 和 star 喔~ 11 | */ 12 | 13 | #import 14 | #import 15 | 16 | #define FLDB_DEFAULT_NAME @"gitkong" 17 | 18 | #define FLFMDBQUEUEMANAGER [FLFMDBQueueManager shareManager:FLDB_DEFAULT_NAME] 19 | /** 20 | * @author gitKong 21 | * 22 | * 多数据库操作暂时不开放,有问题需要解决,敬请期待 23 | */ 24 | //#define FLFMDBQUEUEMANAGERX(DB_NAME) [FLFMDBQueueManager shareManager:DB_NAME] 25 | 26 | @interface FLFMDBQueueManager : NSObject 27 | /** 28 | * @author gitKong 29 | * 30 | * 单例创建,项目唯一 31 | */ 32 | + (instancetype)shareManager:(NSString *)fl_dbName; 33 | 34 | #pragma mark -- 创表 35 | 36 | /** 37 | * @author gitKong 38 | * 39 | * 根据类名创建表,如果有则跳过,没有才创建 40 | 41 | * flag:YES表示创建表格操作执行成功 或者 表格已经存在,NO则失败 42 | 43 | * 注意:此方法创建表格后不会自动关闭数据库,当开发者执行其他操作(删除数据库除外)后会自动关闭数据库 44 | 45 | * 建议使用insert创建表格并添加数据 46 | */ 47 | - (void)fl_createTable:(Class)modelClass complete:(void(^)(FLFMDBQueueManager *manager, BOOL flag))complete; 48 | 49 | 50 | #pragma mark -- 插入 51 | 52 | /** 53 | * @author gitKong 54 | * 55 | * @param model 插入单个模型或者模型数组,如果此时传入的模型对应的FLDBID在表中已经存在,则替换更新旧的 56 | 57 | * flag:YES表示插入数据操作执行成功,NO则失败 58 | 59 | * 注意:如果此时没创建表就自动先创建,表名为模型类名,数据插入完毕后会自动关闭数据库 60 | 61 | * 建议直接使用insert创建表格并添加数据,因为create方法执行完不会自动关闭数据库 62 | */ 63 | - (void)fl_insertModel:(id)model complete:(void(^)(FLFMDBQueueManager *manager, BOOL flag))complete; 64 | 65 | #pragma mark -- 查询 66 | 67 | /** 68 | * @author gitKong 69 | * 70 | * 查询指定表是否存在 71 | 72 | * flag:YES表示操作执行成功并且 modelClass 表格存在,NO则操作失败或者 modelClass 表格不存在 73 | 74 | * 注意:操作执行完毕会自动关闭数据库 75 | */ 76 | - (void)fl_isExitTable:(Class)modelClass complete:(void(^)(FLFMDBQueueManager *manager, BOOL flag))complete; 77 | /** 78 | * @author gitKong 79 | * 80 | * 查找指定表中指定DBID的模型 81 | 82 | * model:不等于nil,表示查询数据操作执行成功并有数据,返回查询成功的模型数据,nil则表示查询操作失败 或者 查询成功但数据为空 或者 对应的表格不存在 83 | 84 | * 注意:操作执行完毕会自动关闭数据库 85 | */ 86 | - (void)fl_searchModel:(Class)modelClass byID:(NSString *)FLDBID complete:(void(^)(FLFMDBQueueManager *manager,id model))complete; 87 | /** 88 | * @author gitKong 89 | * 90 | * 查找指定表中模型数组(所有的) 91 | 92 | * modelArr:不等于nil,表示查询数据操作执行成功并有数据,返回查询成功的模型数据,nil则表示查询操作失败 或者 查询成功但数据为空 或者 对应的表格不存在 93 | 94 | * 注意:操作执行完毕会自动关闭数据库 95 | */ 96 | - (void)fl_searchModelArr:(Class)modelClass complete:(void(^)(FLFMDBQueueManager *manager,NSArray *modelArr))complete; 97 | 98 | #pragma mark -- 修改 99 | 100 | /** 101 | * @author gitKong 102 | * 103 | * 修改指定DBID的模型 104 | 105 | * flag:YES表示更新操作执行成功,NO则操作失败 或者 对应的表格不存在 106 | 107 | * 注意:操作执行完毕会自动关闭数据库 108 | */ 109 | 110 | - (void)fl_modifyModel:(id)model byID:(NSString *)FLDBID complete:(void(^)(FLFMDBQueueManager *manager, BOOL flag))complete; 111 | 112 | 113 | #pragma mark -- 删除 114 | /** 115 | * @author gitKong 116 | * 117 | * 删除指定表 118 | 119 | * flag:YES表示删除操作执行成功,NO则操作失败 或者 对应的表格不存在 120 | 121 | * 注意:操作执行完毕会自动关闭数据库 122 | */ 123 | - (void)fl_dropTable:(Class)modelClass complete:(void(^)(FLFMDBQueueManager *manager, BOOL flag))complete; 124 | /** 125 | * @author gitKong 126 | * 127 | * 删除数据库 128 | 129 | * 注意:操作不涉及到数据库操作,如果你通过create创建后执行此操作,不会关闭数据库 130 | 131 | * @return YES 表示删除成功,NO则删除失败 132 | */ 133 | - (BOOL)fl_dropDB; 134 | /** 135 | * @author gitKong 136 | * 137 | * 删除指定表格的所有数据 138 | 139 | * flag:YES表示删除操作执行成功,NO则操作失败 或者 对应的表格不存在 或者 没有对应数据可以删除 140 | 141 | * 注意:操作执行完毕会自动关闭数据库 142 | */ 143 | - (void)fl_deleteAllModel:(Class)modelClass complete:(void(^)(FLFMDBQueueManager *manager, BOOL flag))complete; 144 | 145 | /** 146 | * @author gitKong 147 | * 148 | * 删除指定表中指定DBID的模型 149 | 150 | * flag:YES表示删除操作执行成功,NO则操作失败 或者 对应的表格不存在 或者 没有对应数据可以删除 151 | 152 | * 注意:操作执行完毕会自动关闭数据库 153 | */ 154 | - (void)fl_deleteModel:(Class)modelClass byId:(NSString *)FLDBID complete:(void(^)(FLFMDBQueueManager *manager, BOOL flag))complete; 155 | @end 156 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager/FLPenModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // FLPenModel.h 3 | // FLFMDBManager 4 | // 5 | // Created by clarence on 17/2/10. 6 | // Copyright © 2017年 clarence. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface FLPenModel : NSObject 12 | 13 | /** 14 | * @author Clarence 15 | * 16 | * 数据库中绑定指定模型的DBID(一般对应后台返回模型数据中的唯一id) 17 | * 属性名称必须是FLDBID,适应框架 18 | */ 19 | @property (nonatomic,copy)NSString *FLDBID; 20 | 21 | @property (nonatomic,copy)NSString *name; 22 | 23 | @property (nonatomic,strong)NSDictionary *dict; 24 | 25 | @property (nonatomic,strong)NSArray *arr; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager/FLPenModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // FLPenModel.m 3 | // FLFMDBManager 4 | // 5 | // Created by clarence on 17/2/10. 6 | // Copyright © 2017年 clarence. All rights reserved. 7 | // 8 | 9 | #import "FLPenModel.h" 10 | 11 | @implementation FLPenModel 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager/FLStudentModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // FLStudentModel.h 3 | // FLFMDBManager 4 | // 5 | // Created by clarence on 16/11/17. 6 | // Copyright © 2016年 clarence. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "FLPenModel.h" 11 | #import "FLBookModel.h" 12 | @interface FLStudentModel : NSObject 13 | /** 14 | * @author Clarence 15 | * 16 | * 数据库中绑定指定模型的DBID(一般对应后台返回模型数据中的唯一id) 17 | * 属性名称必须是FLDBID,适应框架 18 | */ 19 | @property (nonatomic,copy)NSString *FLDBID; 20 | 21 | 22 | @property (nonatomic,copy)NSString *name_gitKong; 23 | 24 | @property (nonatomic,assign)NSInteger age; 25 | 26 | @property (nonatomic,strong)NSDictionary *msgInfo; 27 | 28 | @property (nonatomic,strong)NSMutableArray *scroceArrM; 29 | 30 | /** 31 | * @author gitKong 32 | * 33 | * 嵌套模型,多表处理 34 | */ 35 | @property (nonatomic,copy)NSString *penModelID;// 标记 FLPenModel 嵌套模型 36 | //@property (nonatomic,strong)FLPenModel *penModel; 37 | // 38 | @property (nonatomic,copy)NSString *bookModelID;// 标记 FLBookModel 嵌套模型 39 | //@property (nonatomic,strong)FLBookModel *bookModel; 40 | 41 | //@property (nonatomic,copy)NSString *id; 42 | 43 | // 嵌套的模型一般创建多一张表,一张表不好处理 44 | //@property (nonatomic,strong)NSArray *otherModelArr; 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager/FLStudentModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // FLStudentModel.m 3 | // FLFMDBManager 4 | // 5 | // Created by clarence on 16/11/17. 6 | // Copyright © 2016年 clarence. All rights reserved. 7 | // 8 | 9 | #import "FLStudentModel.h" 10 | 11 | @implementation FLStudentModel 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager/FLStudentTableViewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // FLStudentTableViewCell.h 3 | // FLFMDBManager 4 | // 5 | // Created by clarence on 16/11/21. 6 | // Copyright © 2016年 clarence. All rights reserved. 7 | // 8 | 9 | #import 10 | @class FLStudentModel; 11 | @interface FLStudentTableViewCell : UITableViewCell 12 | @property (nonatomic,strong)FLStudentModel *model; 13 | @end 14 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager/FLStudentTableViewCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // FLStudentTableViewCell.m 3 | // FLFMDBManager 4 | // 5 | // Created by clarence on 16/11/21. 6 | // Copyright © 2016年 clarence. All rights reserved. 7 | // 8 | 9 | #import "FLStudentTableViewCell.h" 10 | #import "FLStudentModel.h" 11 | @interface FLStudentTableViewCell () 12 | @property (weak, nonatomic) IBOutlet UILabel *nameLabel; 13 | @property (weak, nonatomic) IBOutlet UILabel *ageLabel; 14 | @property (weak, nonatomic) IBOutlet UILabel *DBIDLabel; 15 | @property (weak, nonatomic) IBOutlet UILabel *msgInfoLabel; 16 | @property (weak, nonatomic) IBOutlet UILabel *scroceArrMLabel; 17 | 18 | @end 19 | 20 | @implementation FLStudentTableViewCell 21 | 22 | - (void)awakeFromNib { 23 | [super awakeFromNib]; 24 | // Initialization code 25 | } 26 | 27 | - (void)setModel:(FLStudentModel *)model{ 28 | _model = model; 29 | self.nameLabel.text = [NSString stringWithFormat:@"名字:%@",model.name_gitKong]; 30 | self.ageLabel.text = [NSString stringWithFormat:@"年龄:%zd",model.age]; 31 | self.DBIDLabel.text = [NSString stringWithFormat:@"FLDBID:%@",model.FLDBID]; 32 | self.msgInfoLabel.text = [NSString stringWithFormat:@"msgInfo:%@",model.msgInfo]; 33 | self.scroceArrMLabel.text = [NSString stringWithFormat:@"scroceArrM:%@",model.scroceArrM]; 34 | } 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager/FLStudentTableViewCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 28 | 33 | 38 | 43 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager/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 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager/TestViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TestViewController.h 3 | // FLFMDBManager 4 | // 5 | // Created by 孔凡列 on 2017/1/15. 6 | // Copyright © 2017年 clarence. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TestViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager/TestViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // TestViewController.m 3 | // FLFMDBManager 4 | // 5 | // Created by 孔凡列 on 2017/1/15. 6 | // Copyright © 2017年 clarence. All rights reserved. 7 | // 8 | 9 | #import "TestViewController.h" 10 | #import "FLFMDBQueueManager.h" 11 | #import "FLStudentModel.h" 12 | @interface TestViewController () 13 | @property(nonatomic,copy)NSString *name; 14 | @end 15 | 16 | @implementation TestViewController 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | self.view.backgroundColor = [UIColor whiteColor]; 21 | // [FLFMDBQUEUEMANAGER fl_createTable:[FLStudentModel class] complete:^(FLFMDBQueueManager *manager, BOOL flag) { 22 | // self.name = @"hello world"; 23 | // [self testCircleRef]; 24 | // }]; 25 | } 26 | 27 | - (void)testCircleRef{ 28 | NSLog(@"%@",self.name); 29 | } 30 | 31 | - (void)dealloc { 32 | NSLog(@"%s",__func__); 33 | } 34 | 35 | /* 36 | #pragma mark - Navigation 37 | 38 | // In a storyboard-based application, you will often want to do a little preparation before navigation 39 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 40 | // Get the new view controller using [segue destinationViewController]. 41 | // Pass the selected object to the new view controller. 42 | } 43 | */ 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // FLFMDBManager 4 | // 5 | // Created by clarence on 16/11/17. 6 | // Copyright © 2016年 clarence. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UITableViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/FLFMDBManager/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // FLFMDBManager 4 | // 5 | // Created by clarence on 16/11/17. 6 | // Copyright © 2016年 clarence. 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 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | target 'FLFMDBManager' do 5 | # Uncomment the next line if you're using Swift or would like to use dynamic frameworks 6 | use_frameworks! 7 | pod 'FMDB' 8 | # Pods for FLFMDBManager 9 | 10 | end 11 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - FMDB (2.6.2): 3 | - FMDB/standard (= 2.6.2) 4 | - FMDB/standard (2.6.2) 5 | 6 | DEPENDENCIES: 7 | - FMDB 8 | 9 | SPEC CHECKSUMS: 10 | FMDB: 854a0341b4726e53276f2a8996f06f1b80f9259a 11 | 12 | PODFILE CHECKSUM: 12c5bb3c07e1480129d6eb5af78ce2c849ae2044 13 | 14 | COCOAPODS: 1.1.1 15 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/FMDB/LICENSE.txt: -------------------------------------------------------------------------------- 1 | If you are using FMDB in your project, I'd love to hear about it. Let Gus know 2 | by sending an email to gus@flyingmeat.com. 3 | 4 | And if you happen to come across either Gus Mueller or Rob Ryan in a bar, you 5 | might consider purchasing a drink of their choosing if FMDB has been useful to 6 | you. 7 | 8 | Finally, and shortly, this is the MIT License. 9 | 10 | Copyright (c) 2008-2014 Flying Meat Inc. 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining a copy 13 | of this software and associated documentation files (the "Software"), to deal 14 | in the Software without restriction, including without limitation the rights 15 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | copies of the Software, and to permit persons to whom the Software is 17 | furnished to do so, subject to the following conditions: 18 | 19 | The above copyright notice and this permission notice shall be included in 20 | all copies or substantial portions of the Software. 21 | 22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 | THE SOFTWARE. -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/FMDB/README.markdown: -------------------------------------------------------------------------------- 1 | # FMDB v2.6.2 2 | 3 | This is an Objective-C wrapper around SQLite: http://sqlite.org/ 4 | 5 | ## The FMDB Mailing List: 6 | http://groups.google.com/group/fmdb 7 | 8 | ## Read the SQLite FAQ: 9 | http://www.sqlite.org/faq.html 10 | 11 | Since FMDB is built on top of SQLite, you're going to want to read this page top to bottom at least once. And while you're there, make sure to bookmark the SQLite Documentation page: http://www.sqlite.org/docs.html 12 | 13 | ## Contributing 14 | Do you have an awesome idea that deserves to be in FMDB? You might consider pinging ccgus first to make sure he hasn't already ruled it out for some reason. Otherwise pull requests are great, and make sure you stick to the local coding conventions. However, please be patient and if you haven't heard anything from ccgus for a week or more, you might want to send a note asking what's up. 15 | 16 | ## CocoaPods 17 | 18 | [![Dependency Status](https://www.versioneye.com/objective-c/fmdb/2.3/badge.svg?style=flat)](https://www.versioneye.com/objective-c/fmdb/2.3) 19 | [![Reference Status](https://www.versioneye.com/objective-c/fmdb/reference_badge.svg?style=flat)](https://www.versioneye.com/objective-c/fmdb/references) 20 | 21 | FMDB can be installed using [CocoaPods](https://cocoapods.org/). 22 | 23 | ``` 24 | pod 'FMDB' 25 | # pod 'FMDB/FTS' # FMDB with FTS 26 | # pod 'FMDB/standalone' # FMDB with latest SQLite amalgamation source 27 | # pod 'FMDB/standalone/FTS' # FMDB with latest SQLite amalgamation source and FTS 28 | # pod 'FMDB/SQLCipher' # FMDB with SQLCipher 29 | ``` 30 | 31 | **If using FMDB with [SQLCipher](https://www.zetetic.net/sqlcipher/) you must use the FMDB/SQLCipher subspec. The FMDB/SQLCipher subspec declares SQLCipher as a dependency, allowing FMDB to be compiled with the `-DSQLITE_HAS_CODEC` flag.** 32 | 33 | ## FMDB Class Reference: 34 | http://ccgus.github.io/fmdb/html/index.html 35 | 36 | ## Automatic Reference Counting (ARC) or Manual Memory Management? 37 | You can use either style in your Cocoa project. FMDB will figure out which you are using at compile time and do the right thing. 38 | 39 | ## Usage 40 | There are three main classes in FMDB: 41 | 42 | 1. `FMDatabase` - Represents a single SQLite database. Used for executing SQL statements. 43 | 2. `FMResultSet` - Represents the results of executing a query on an `FMDatabase`. 44 | 3. `FMDatabaseQueue` - If you're wanting to perform queries and updates on multiple threads, you'll want to use this class. It's described in the "Thread Safety" section below. 45 | 46 | ### Database Creation 47 | An `FMDatabase` is created with a path to a SQLite database file. This path can be one of these three: 48 | 49 | 1. A file system path. The file does not have to exist on disk. If it does not exist, it is created for you. 50 | 2. An empty string (`@""`). An empty database is created at a temporary location. This database is deleted with the `FMDatabase` connection is closed. 51 | 3. `NULL`. An in-memory database is created. This database will be destroyed with the `FMDatabase` connection is closed. 52 | 53 | (For more information on temporary and in-memory databases, read the sqlite documentation on the subject: http://www.sqlite.org/inmemorydb.html) 54 | 55 | ```objc 56 | FMDatabase *db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"]; 57 | ``` 58 | 59 | ### Opening 60 | 61 | Before you can interact with the database, it must be opened. Opening fails if there are insufficient resources or permissions to open and/or create the database. 62 | 63 | ```objc 64 | if (![db open]) { 65 | [db release]; 66 | return; 67 | } 68 | ``` 69 | 70 | ### Executing Updates 71 | 72 | Any sort of SQL statement which is not a `SELECT` statement qualifies as an update. This includes `CREATE`, `UPDATE`, `INSERT`, `ALTER`, `COMMIT`, `BEGIN`, `DETACH`, `DELETE`, `DROP`, `END`, `EXPLAIN`, `VACUUM`, and `REPLACE` statements (plus many more). Basically, if your SQL statement does not begin with `SELECT`, it is an update statement. 73 | 74 | Executing updates returns a single value, a `BOOL`. A return value of `YES` means the update was successfully executed, and a return value of `NO` means that some error was encountered. You may invoke the `-lastErrorMessage` and `-lastErrorCode` methods to retrieve more information. 75 | 76 | ### Executing Queries 77 | 78 | A `SELECT` statement is a query and is executed via one of the `-executeQuery...` methods. 79 | 80 | Executing queries returns an `FMResultSet` object if successful, and `nil` upon failure. You should use the `-lastErrorMessage` and `-lastErrorCode` methods to determine why a query failed. 81 | 82 | In order to iterate through the results of your query, you use a `while()` loop. You also need to "step" from one record to the other. With FMDB, the easiest way to do that is like this: 83 | 84 | ```objc 85 | FMResultSet *s = [db executeQuery:@"SELECT * FROM myTable"]; 86 | while ([s next]) { 87 | //retrieve values for each record 88 | } 89 | ``` 90 | 91 | You must always invoke `-[FMResultSet next]` before attempting to access the values returned in a query, even if you're only expecting one: 92 | 93 | ```objc 94 | FMResultSet *s = [db executeQuery:@"SELECT COUNT(*) FROM myTable"]; 95 | if ([s next]) { 96 | int totalCount = [s intForColumnIndex:0]; 97 | } 98 | ``` 99 | 100 | `FMResultSet` has many methods to retrieve data in an appropriate format: 101 | 102 | - `intForColumn:` 103 | - `longForColumn:` 104 | - `longLongIntForColumn:` 105 | - `boolForColumn:` 106 | - `doubleForColumn:` 107 | - `stringForColumn:` 108 | - `dateForColumn:` 109 | - `dataForColumn:` 110 | - `dataNoCopyForColumn:` 111 | - `UTF8StringForColumnName:` 112 | - `objectForColumnName:` 113 | 114 | Each of these methods also has a `{type}ForColumnIndex:` variant that is used to retrieve the data based on the position of the column in the results, as opposed to the column's name. 115 | 116 | Typically, there's no need to `-close` an `FMResultSet` yourself, since that happens when either the result set is deallocated, or the parent database is closed. 117 | 118 | ### Closing 119 | 120 | When you have finished executing queries and updates on the database, you should `-close` the `FMDatabase` connection so that SQLite will relinquish any resources it has acquired during the course of its operation. 121 | 122 | ```objc 123 | [db close]; 124 | ``` 125 | 126 | ### Transactions 127 | 128 | `FMDatabase` can begin and commit a transaction by invoking one of the appropriate methods or executing a begin/end transaction statement. 129 | 130 | ### Multiple Statements and Batch Stuff 131 | 132 | You can use `FMDatabase`'s executeStatements:withResultBlock: to do multiple statements in a string: 133 | 134 | ```objc 135 | NSString *sql = @"create table bulktest1 (id integer primary key autoincrement, x text);" 136 | "create table bulktest2 (id integer primary key autoincrement, y text);" 137 | "create table bulktest3 (id integer primary key autoincrement, z text);" 138 | "insert into bulktest1 (x) values ('XXX');" 139 | "insert into bulktest2 (y) values ('YYY');" 140 | "insert into bulktest3 (z) values ('ZZZ');"; 141 | 142 | success = [db executeStatements:sql]; 143 | 144 | sql = @"select count(*) as count from bulktest1;" 145 | "select count(*) as count from bulktest2;" 146 | "select count(*) as count from bulktest3;"; 147 | 148 | success = [self.db executeStatements:sql withResultBlock:^int(NSDictionary *dictionary) { 149 | NSInteger count = [dictionary[@"count"] integerValue]; 150 | XCTAssertEqual(count, 1, @"expected one record for dictionary %@", dictionary); 151 | return 0; 152 | }]; 153 | ``` 154 | 155 | ### Data Sanitization 156 | 157 | When providing a SQL statement to FMDB, you should not attempt to "sanitize" any values before insertion. Instead, you should use the standard SQLite binding syntax: 158 | 159 | ```sql 160 | INSERT INTO myTable VALUES (?, ?, ?, ?) 161 | ``` 162 | 163 | The `?` character is recognized by SQLite as a placeholder for a value to be inserted. The execution methods all accept a variable number of arguments (or a representation of those arguments, such as an `NSArray`, `NSDictionary`, or a `va_list`), which are properly escaped for you. 164 | 165 | And, to use that SQL with the `?` placeholders from Objective-C: 166 | 167 | ```objc 168 | NSInteger identifier = 42; 169 | NSString *name = @"Liam O'Flaherty (\"the famous Irish author\")"; 170 | NSDate *date = [NSDate date]; 171 | NSString *comment = nil; 172 | 173 | BOOL success = [db executeUpdate:@"INSERT INTO authors (identifier, name, date, comment) VALUES (?, ?, ?, ?)", @(identifier), name, date, comment ?: [NSNull null]]; 174 | if (!success) { 175 | NSLog(@"error = %@", [db lastErrorMessage]); 176 | } 177 | ``` 178 | 179 | > **Note:** Fundamental data types, like the `NSInteger` variable `identifier`, should be as a `NSNumber` objects, achieved by using the `@` syntax, shown above. Or you can use the `[NSNumber numberWithInt:identifier]` syntax, too. 180 | > 181 | > Likewise, SQL `NULL` values should be inserted as `[NSNull null]`. For example, in the case of `comment` which might be `nil` (and is in this example), you can use the `comment ?: [NSNull null]` syntax, which will insert the string if `comment` is not `nil`, but will insert `[NSNull null]` if it is `nil`. 182 | 183 | In Swift, you would use `executeUpdate(values:)`, which not only is a concise Swift syntax, but also `throws` errors for proper Swift 2 error handling: 184 | 185 | ```swift 186 | do { 187 | let identifier = 42 188 | let name = "Liam O'Flaherty (\"the famous Irish author\")" 189 | let date = NSDate() 190 | let comment: String? = nil 191 | 192 | try db.executeUpdate("INSERT INTO authors (identifier, name, date, comment) VALUES (?, ?, ?, ?)", values: [identifier, name, date, comment ?? NSNull()]) 193 | } catch { 194 | print("error = \(error)") 195 | } 196 | ``` 197 | 198 | > **Note:** In Swift, you don't have to wrap fundamental numeric types like you do in Objective-C. But if you are going to insert an optional string, you would probably use the `comment ?? NSNull()` syntax (i.e., if it is `nil`, use `NSNull`, otherwise use the string). 199 | 200 | Alternatively, you may use named parameters syntax: 201 | 202 | ```sql 203 | INSERT INTO authors (identifier, name, date, comment) VALUES (:identifier, :name, :date, :comment) 204 | ``` 205 | 206 | The parameters *must* start with a colon. SQLite itself supports other characters, but internally the dictionary keys are prefixed with a colon, do **not** include the colon in your dictionary keys. 207 | 208 | ```objc 209 | NSDictionary *arguments = @{@"identifier": @(identifier), @"name": name, @"date": date, @"comment": comment ?: [NSNull null]}; 210 | BOOL success = [db executeUpdate:@"INSERT INTO authors (identifier, name, date, comment) VALUES (:identifier, :name, :date, :comment)" withParameterDictionary:arguments]; 211 | if (!success) { 212 | NSLog(@"error = %@", [db lastErrorMessage]); 213 | } 214 | ``` 215 | 216 | The key point is that one should not use `NSString` method `stringWithFormat` to manually insert values into the SQL statement, itself. Nor should one Swift string interpolation to insert values into the SQL. Use `?` placeholders for values to be inserted into the database (or used in `WHERE` clauses in `SELECT` statements). 217 | 218 |

Using FMDatabaseQueue and Thread Safety.

219 | 220 | Using a single instance of `FMDatabase` from multiple threads at once is a bad idea. It has always been OK to make a `FMDatabase` object *per thread*. Just don't share a single instance across threads, and definitely not across multiple threads at the same time. Bad things will eventually happen and you'll eventually get something to crash, or maybe get an exception, or maybe meteorites will fall out of the sky and hit your Mac Pro. *This would suck*. 221 | 222 | **So don't instantiate a single `FMDatabase` object and use it across multiple threads.** 223 | 224 | Instead, use `FMDatabaseQueue`. Instantiate a single `FMDatabaseQueue` and use it across multiple threads. The `FMDatabaseQueue` object will synchronize and coordinate access across the multiple threads. Here's how to use it: 225 | 226 | First, make your queue. 227 | 228 | ```objc 229 | FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath]; 230 | ``` 231 | 232 | Then use it like so: 233 | 234 | 235 | ```objc 236 | [queue inDatabase:^(FMDatabase *db) { 237 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @1]; 238 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @2]; 239 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @3]; 240 | 241 | FMResultSet *rs = [db executeQuery:@"select * from foo"]; 242 | while ([rs next]) { 243 | … 244 | } 245 | }]; 246 | ``` 247 | 248 | An easy way to wrap things up in a transaction can be done like this: 249 | 250 | ```objc 251 | [queue inTransaction:^(FMDatabase *db, BOOL *rollback) { 252 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @1]; 253 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @2]; 254 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @3]; 255 | 256 | if (whoopsSomethingWrongHappened) { 257 | *rollback = YES; 258 | return; 259 | } 260 | // etc… 261 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @4]; 262 | }]; 263 | ``` 264 | 265 | The Swift equivalent would be: 266 | 267 | ```swift 268 | queue.inTransaction { db, rollback in 269 | do { 270 | try db.executeUpdate("INSERT INTO myTable VALUES (?)", values: [1]) 271 | try db.executeUpdate("INSERT INTO myTable VALUES (?)", values: [2]) 272 | try db.executeUpdate("INSERT INTO myTable VALUES (?)", values: [3]) 273 | 274 | if whoopsSomethingWrongHappened { 275 | rollback.memory = true 276 | return 277 | } 278 | 279 | try db.executeUpdate("INSERT INTO myTable VALUES (?)", values: [4]) 280 | } catch { 281 | rollback.memory = true 282 | print(error) 283 | } 284 | } 285 | ``` 286 | 287 | `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. 288 | 289 | **Note:** The calls to `FMDatabaseQueue`'s methods are blocking. So even though you are passing along blocks, they will **not** be run on another thread. 290 | 291 | ## Making custom sqlite functions, based on blocks. 292 | 293 | You can do this! For an example, look for `-makeFunctionNamed:` in main.m 294 | 295 | ## Swift 296 | 297 | You can use FMDB in Swift projects too. 298 | 299 | To do this, you must: 300 | 301 | 1. Copy the relevant `.m` and `.h` files from the FMDB `src` folder into your project. 302 | 303 | You can copy all of them (which is easiest), or only the ones you need. Likely you will need [`FMDatabase`](http://ccgus.github.io/fmdb/html/Classes/FMDatabase.html) and [`FMResultSet`](http://ccgus.github.io/fmdb/html/Classes/FMResultSet.html) at a minimum. [`FMDatabaseAdditions`](http://ccgus.github.io/fmdb/html/Categories/FMDatabase+FMDatabaseAdditions.html) provides some very useful convenience methods, so you will likely want that, too. If you are doing multithreaded access to a database, [`FMDatabaseQueue`](http://ccgus.github.io/fmdb/html/Classes/FMDatabaseQueue.html) is quite useful, too. If you choose to not copy all of the files from the `src` directory, though, you may want to update `FMDB.h` to only reference the files that you included in your project. 304 | 305 | Note, if you're copying all of the files from the `src` folder into to your project (which is recommended), you may want to drag the individual files into your project, not the folder, itself, because if you drag the folder, you won't be prompted to add the bridging header (see next point). 306 | 307 | 2. If prompted to create a "bridging header", you should do so. If not prompted and if you don't already have a bridging header, add one. 308 | 309 | For more information on bridging headers, see [Swift and Objective-C in the Same Project](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html#//apple_ref/doc/uid/TP40014216-CH10-XID_76). 310 | 311 | 3. In your bridging header, add a line that says: 312 | ```objc 313 | #import "FMDB.h" 314 | ``` 315 | 316 | 4. Use the variations of `executeQuery` and `executeUpdate` with the `sql` and `values` parameters with `try` pattern, as shown below. These renditions of `executeQuery` and `executeUpdate` both `throw` errors in true Swift 2 fashion. 317 | 318 | If you do the above, you can then write Swift code that uses `FMDatabase`. For example: 319 | 320 | ```swift 321 | let documents = try! NSFileManager.defaultManager().URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false) 322 | let fileURL = documents.URLByAppendingPathComponent("test.sqlite") 323 | 324 | let database = FMDatabase(path: fileURL.path) 325 | 326 | if !database.open() { 327 | print("Unable to open database") 328 | return 329 | } 330 | 331 | do { 332 | try database.executeUpdate("create table test(x text, y text, z text)", values: nil) 333 | try database.executeUpdate("insert into test (x, y, z) values (?, ?, ?)", values: ["a", "b", "c"]) 334 | try database.executeUpdate("insert into test (x, y, z) values (?, ?, ?)", values: ["e", "f", "g"]) 335 | 336 | let rs = try database.executeQuery("select x, y, z from test", values: nil) 337 | while rs.next() { 338 | let x = rs.stringForColumn("x") 339 | let y = rs.stringForColumn("y") 340 | let z = rs.stringForColumn("z") 341 | print("x = \(x); y = \(y); z = \(z)") 342 | } 343 | } catch let error as NSError { 344 | print("failed: \(error.localizedDescription)") 345 | } 346 | 347 | database.close() 348 | ``` 349 | 350 | ## History 351 | 352 | The history and changes are availbe on its [GitHub page](https://github.com/ccgus/fmdb) and are summarized in the "CHANGES_AND_TODO_LIST.txt" file. 353 | 354 | ## Contributors 355 | 356 | The contributors to FMDB are contained in the "Contributors.txt" file. 357 | 358 | ## Additional projects using FMDB, which might be interesting to the discerning developer. 359 | 360 | * FMDBMigrationManager, A SQLite schema migration management system for FMDB: https://github.com/layerhq/FMDBMigrationManager 361 | * FCModel, An alternative to Core Data for people who like having direct SQL access: https://github.com/marcoarment/FCModel 362 | 363 | ## Quick notes on FMDB's coding style 364 | 365 | Spaces, not tabs. Square brackets, not dot notation. Look at what FMDB already does with curly brackets and such, and stick to that style. 366 | 367 | ## Reporting bugs 368 | 369 | Reduce your bug down to the smallest amount of code possible. You want to make it super easy for the developers to see and reproduce your bug. If it helps, pretend that the person who can fix your bug is active on shipping 3 major products, works on a handful of open source projects, has a newborn baby, and is generally very very busy. 370 | 371 | And we've even added a template function to main.m (FMDBReportABugFunction) in the FMDB distribution to help you out: 372 | 373 | * Open up fmdb project in Xcode. 374 | * Open up main.m and modify the FMDBReportABugFunction to reproduce your bug. 375 | * Setup your table(s) in the code. 376 | * Make your query or update(s). 377 | * Add some assertions which demonstrate the bug. 378 | 379 | Then you can bring it up on the FMDB mailing list by showing your nice and compact FMDBReportABugFunction, or you can report the bug via the github FMDB bug reporter. 380 | 381 | **Optional:** 382 | 383 | Figure out where the bug is, fix it, and send a patch in or bring that up on the mailing list. Make sure all the other tests run after your modifications. 384 | 385 | ## Support 386 | 387 | The support channels for FMDB are the mailing list (see above), filing a bug here, or maybe on Stack Overflow. So that is to say, support is provided by the community and on a voluntary basis. 388 | 389 | FMDB development is overseen by Gus Mueller of Flying Meat. If FMDB been helpful to you, consider purchasing an app from FM or telling all your friends about it. 390 | 391 | ## License 392 | 393 | The license for FMDB is contained in the "License.txt" file. 394 | 395 | If you happen to come across either Gus Mueller or Rob Ryan in a bar, you might consider purchasing a drink of their choosing if FMDB has been useful to you. 396 | 397 | (The drink is for them of course, shame on you for trying to keep it.) 398 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/FMDB/src/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 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/FMDB/src/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 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/FMDB/src/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 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/FMDB/src/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 | } 44 | 45 | /** Database path */ 46 | 47 | @property (atomic, retain) NSString *path; 48 | 49 | /** Delegate object */ 50 | 51 | @property (atomic, assign) id delegate; 52 | 53 | /** Maximum number of databases to create */ 54 | 55 | @property (atomic, assign) NSUInteger maximumNumberOfDatabasesToCreate; 56 | 57 | /** Open flags */ 58 | 59 | @property (atomic, readonly) int openFlags; 60 | 61 | 62 | ///--------------------- 63 | /// @name Initialization 64 | ///--------------------- 65 | 66 | /** Create pool using path. 67 | 68 | @param aPath The file path of the database. 69 | 70 | @return The `FMDatabasePool` object. `nil` on error. 71 | */ 72 | 73 | + (instancetype)databasePoolWithPath:(NSString*)aPath; 74 | 75 | /** Create pool using path and specified flags 76 | 77 | @param aPath The file path of the database. 78 | @param openFlags Flags passed to the openWithFlags method of the database 79 | 80 | @return The `FMDatabasePool` object. `nil` on error. 81 | */ 82 | 83 | + (instancetype)databasePoolWithPath:(NSString*)aPath flags:(int)openFlags; 84 | 85 | /** Create pool using path. 86 | 87 | @param aPath The file path of the database. 88 | 89 | @return The `FMDatabasePool` object. `nil` on error. 90 | */ 91 | 92 | - (instancetype)initWithPath:(NSString*)aPath; 93 | 94 | /** Create pool using path and specified flags. 95 | 96 | @param aPath The file path of the database. 97 | @param openFlags Flags passed to the openWithFlags method of the database 98 | 99 | @return The `FMDatabasePool` object. `nil` on error. 100 | */ 101 | 102 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags; 103 | 104 | ///------------------------------------------------ 105 | /// @name Keeping track of checked in/out databases 106 | ///------------------------------------------------ 107 | 108 | /** Number of checked-in databases in pool 109 | 110 | @returns Number of databases 111 | */ 112 | 113 | - (NSUInteger)countOfCheckedInDatabases; 114 | 115 | /** Number of checked-out databases in pool 116 | 117 | @returns Number of databases 118 | */ 119 | 120 | - (NSUInteger)countOfCheckedOutDatabases; 121 | 122 | /** Total number of databases in pool 123 | 124 | @returns Number of databases 125 | */ 126 | 127 | - (NSUInteger)countOfOpenDatabases; 128 | 129 | /** Release all databases in pool */ 130 | 131 | - (void)releaseAllDatabases; 132 | 133 | ///------------------------------------------ 134 | /// @name Perform database operations in pool 135 | ///------------------------------------------ 136 | 137 | /** Synchronously perform database operations in pool. 138 | 139 | @param block The code to be run on the `FMDatabasePool` pool. 140 | */ 141 | 142 | - (void)inDatabase:(void (^)(FMDatabase *db))block; 143 | 144 | /** Synchronously perform database operations in pool using transaction. 145 | 146 | @param block The code to be run on the `FMDatabasePool` pool. 147 | */ 148 | 149 | - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block; 150 | 151 | /** Synchronously perform database operations in pool using deferred transaction. 152 | 153 | @param block The code to be run on the `FMDatabasePool` pool. 154 | */ 155 | 156 | - (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block; 157 | 158 | /** Synchronously perform database operations in pool using save point. 159 | 160 | @param block The code to be run on the `FMDatabasePool` pool. 161 | 162 | @return `NSError` object if error; `nil` if successful. 163 | 164 | @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. 165 | */ 166 | 167 | - (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block; 168 | 169 | @end 170 | 171 | 172 | /** FMDatabasePool delegate category 173 | 174 | This is a category that defines the protocol for the FMDatabasePool delegate 175 | */ 176 | 177 | @interface NSObject (FMDatabasePoolDelegate) 178 | 179 | /** Asks the delegate whether database should be added to the pool. 180 | 181 | @param pool The `FMDatabasePool` object. 182 | @param database The `FMDatabase` object. 183 | 184 | @return `YES` if it should add database to pool; `NO` if not. 185 | 186 | */ 187 | 188 | - (BOOL)databasePool:(FMDatabasePool*)pool shouldAddDatabaseToPool:(FMDatabase*)database; 189 | 190 | /** Tells the delegate that database was added to the pool. 191 | 192 | @param pool The `FMDatabasePool` object. 193 | @param database The `FMDatabase` object. 194 | 195 | */ 196 | 197 | - (void)databasePool:(FMDatabasePool*)pool didAddDatabase:(FMDatabase*)database; 198 | 199 | @end 200 | 201 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/FMDB/src/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 { 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 | } 52 | 53 | return self; 54 | } 55 | 56 | - (instancetype)initWithPath:(NSString*)aPath 57 | { 58 | // default flags for sqlite3_open 59 | return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE]; 60 | } 61 | 62 | - (instancetype)init { 63 | return [self initWithPath:nil]; 64 | } 65 | 66 | 67 | - (void)dealloc { 68 | 69 | _delegate = 0x00; 70 | FMDBRelease(_path); 71 | FMDBRelease(_databaseInPool); 72 | FMDBRelease(_databaseOutPool); 73 | 74 | if (_lockQueue) { 75 | FMDBDispatchQueueRelease(_lockQueue); 76 | _lockQueue = 0x00; 77 | } 78 | #if ! __has_feature(objc_arc) 79 | [super dealloc]; 80 | #endif 81 | } 82 | 83 | 84 | - (void)executeLocked:(void (^)(void))aBlock { 85 | dispatch_sync(_lockQueue, aBlock); 86 | } 87 | 88 | - (void)pushDatabaseBackInPool:(FMDatabase*)db { 89 | 90 | if (!db) { // db can be null if we set an upper bound on the # of databases to create. 91 | return; 92 | } 93 | 94 | [self executeLocked:^() { 95 | 96 | if ([self->_databaseInPool containsObject:db]) { 97 | [[NSException exceptionWithName:@"Database already in pool" reason:@"The FMDatabase being put back into the pool is already present in the pool" userInfo:nil] raise]; 98 | } 99 | 100 | [self->_databaseInPool addObject:db]; 101 | [self->_databaseOutPool removeObject:db]; 102 | 103 | }]; 104 | } 105 | 106 | - (FMDatabase*)db { 107 | 108 | __block FMDatabase *db; 109 | 110 | 111 | [self executeLocked:^() { 112 | db = [self->_databaseInPool lastObject]; 113 | 114 | BOOL shouldNotifyDelegate = NO; 115 | 116 | if (db) { 117 | [self->_databaseOutPool addObject:db]; 118 | [self->_databaseInPool removeLastObject]; 119 | } 120 | else { 121 | 122 | if (self->_maximumNumberOfDatabasesToCreate) { 123 | NSUInteger currentCount = [self->_databaseOutPool count] + [self->_databaseInPool count]; 124 | 125 | if (currentCount >= self->_maximumNumberOfDatabasesToCreate) { 126 | NSLog(@"Maximum number of databases (%ld) has already been reached!", (long)currentCount); 127 | return; 128 | } 129 | } 130 | 131 | db = [FMDatabase databaseWithPath:self->_path]; 132 | shouldNotifyDelegate = YES; 133 | } 134 | 135 | //This ensures that the db is opened before returning 136 | #if SQLITE_VERSION_NUMBER >= 3005000 137 | BOOL success = [db openWithFlags:self->_openFlags]; 138 | #else 139 | BOOL success = [db open]; 140 | #endif 141 | if (success) { 142 | if ([self->_delegate respondsToSelector:@selector(databasePool:shouldAddDatabaseToPool:)] && ![self->_delegate databasePool:self shouldAddDatabaseToPool:db]) { 143 | [db close]; 144 | db = 0x00; 145 | } 146 | else { 147 | //It should not get added in the pool twice if lastObject was found 148 | if (![self->_databaseOutPool containsObject:db]) { 149 | [self->_databaseOutPool addObject:db]; 150 | 151 | if (shouldNotifyDelegate && [self->_delegate respondsToSelector:@selector(databasePool:didAddDatabase:)]) { 152 | [self->_delegate databasePool:self didAddDatabase:db]; 153 | } 154 | } 155 | } 156 | } 157 | else { 158 | NSLog(@"Could not open up the database at path %@", self->_path); 159 | db = 0x00; 160 | } 161 | }]; 162 | 163 | return db; 164 | } 165 | 166 | - (NSUInteger)countOfCheckedInDatabases { 167 | 168 | __block NSUInteger count; 169 | 170 | [self executeLocked:^() { 171 | count = [self->_databaseInPool count]; 172 | }]; 173 | 174 | return count; 175 | } 176 | 177 | - (NSUInteger)countOfCheckedOutDatabases { 178 | 179 | __block NSUInteger count; 180 | 181 | [self executeLocked:^() { 182 | count = [self->_databaseOutPool count]; 183 | }]; 184 | 185 | return count; 186 | } 187 | 188 | - (NSUInteger)countOfOpenDatabases { 189 | __block NSUInteger count; 190 | 191 | [self executeLocked:^() { 192 | count = [self->_databaseOutPool count] + [self->_databaseInPool count]; 193 | }]; 194 | 195 | return count; 196 | } 197 | 198 | - (void)releaseAllDatabases { 199 | [self executeLocked:^() { 200 | [self->_databaseOutPool removeAllObjects]; 201 | [self->_databaseInPool removeAllObjects]; 202 | }]; 203 | } 204 | 205 | - (void)inDatabase:(void (^)(FMDatabase *db))block { 206 | 207 | FMDatabase *db = [self db]; 208 | 209 | block(db); 210 | 211 | [self pushDatabaseBackInPool:db]; 212 | } 213 | 214 | - (void)beginTransaction:(BOOL)useDeferred withBlock:(void (^)(FMDatabase *db, BOOL *rollback))block { 215 | 216 | BOOL shouldRollback = NO; 217 | 218 | FMDatabase *db = [self db]; 219 | 220 | if (useDeferred) { 221 | [db beginDeferredTransaction]; 222 | } 223 | else { 224 | [db beginTransaction]; 225 | } 226 | 227 | 228 | block(db, &shouldRollback); 229 | 230 | if (shouldRollback) { 231 | [db rollback]; 232 | } 233 | else { 234 | [db commit]; 235 | } 236 | 237 | [self pushDatabaseBackInPool:db]; 238 | } 239 | 240 | - (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block { 241 | [self beginTransaction:YES withBlock:block]; 242 | } 243 | 244 | - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block { 245 | [self beginTransaction:NO withBlock:block]; 246 | } 247 | 248 | - (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block { 249 | #if SQLITE_VERSION_NUMBER >= 3007000 250 | static unsigned long savePointIdx = 0; 251 | 252 | NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++]; 253 | 254 | BOOL shouldRollback = NO; 255 | 256 | FMDatabase *db = [self db]; 257 | 258 | NSError *err = 0x00; 259 | 260 | if (![db startSavePointWithName:name error:&err]) { 261 | [self pushDatabaseBackInPool:db]; 262 | return err; 263 | } 264 | 265 | block(db, &shouldRollback); 266 | 267 | if (shouldRollback) { 268 | // We need to rollback and release this savepoint to remove it 269 | [db rollbackToSavePointWithName:name error:&err]; 270 | } 271 | [db releaseSavePointWithName:name error:&err]; 272 | 273 | [self pushDatabaseBackInPool:db]; 274 | 275 | return err; 276 | #else 277 | NSString *errorMessage = NSLocalizedString(@"Save point functions require SQLite 3.7", nil); 278 | if (self.logsErrors) NSLog(@"%@", errorMessage); 279 | return [NSError errorWithDomain:@"FMDatabase" code:0 userInfo:@{NSLocalizedDescriptionKey : errorMessage}]; 280 | #endif 281 | } 282 | 283 | @end 284 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/FMDB/src/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 | } 69 | 70 | /** Path of database */ 71 | 72 | @property (atomic, retain) NSString *path; 73 | 74 | /** Open flags */ 75 | 76 | @property (atomic, readonly) int openFlags; 77 | 78 | ///---------------------------------------------------- 79 | /// @name Initialization, opening, and closing of queue 80 | ///---------------------------------------------------- 81 | 82 | /** Create queue using path. 83 | 84 | @param aPath The file path of the database. 85 | 86 | @return The `FMDatabaseQueue` object. `nil` on error. 87 | */ 88 | 89 | + (instancetype)databaseQueueWithPath:(NSString*)aPath; 90 | 91 | /** Create queue using path and specified flags. 92 | 93 | @param aPath The file path of the database. 94 | @param openFlags Flags passed to the openWithFlags method of the database 95 | 96 | @return The `FMDatabaseQueue` object. `nil` on error. 97 | */ 98 | + (instancetype)databaseQueueWithPath:(NSString*)aPath flags:(int)openFlags; 99 | 100 | /** Create queue using path. 101 | 102 | @param aPath The file path of the database. 103 | 104 | @return The `FMDatabaseQueue` object. `nil` on error. 105 | */ 106 | 107 | - (instancetype)initWithPath:(NSString*)aPath; 108 | 109 | /** Create queue 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 | 114 | @return The `FMDatabaseQueue` object. `nil` on error. 115 | */ 116 | 117 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags; 118 | 119 | /** Create queue using path and specified flags. 120 | 121 | @param aPath The file path of the database. 122 | @param openFlags Flags passed to the openWithFlags method of the database 123 | @param vfsName The name of a custom virtual file system 124 | 125 | @return The `FMDatabaseQueue` object. `nil` on error. 126 | */ 127 | 128 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags vfs:(NSString *)vfsName; 129 | 130 | /** Returns the Class of 'FMDatabase' subclass, that will be used to instantiate database object. 131 | 132 | Subclasses can override this method to return specified Class of 'FMDatabase' subclass. 133 | 134 | @return The Class of 'FMDatabase' subclass, that will be used to instantiate database object. 135 | */ 136 | 137 | + (Class)databaseClass; 138 | 139 | /** Close database used by queue. */ 140 | 141 | - (void)close; 142 | 143 | ///----------------------------------------------- 144 | /// @name Dispatching database operations to queue 145 | ///----------------------------------------------- 146 | 147 | /** Synchronously perform database operations on queue. 148 | 149 | @param block The code to be run on the queue of `FMDatabaseQueue` 150 | */ 151 | 152 | - (void)inDatabase:(void (^)(FMDatabase *db))block; 153 | 154 | /** Synchronously perform database operations on queue, using transactions. 155 | 156 | @param block The code to be run on the queue of `FMDatabaseQueue` 157 | */ 158 | 159 | - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block; 160 | 161 | /** Synchronously perform database operations on queue, using deferred transactions. 162 | 163 | @param block The code to be run on the queue of `FMDatabaseQueue` 164 | */ 165 | 166 | - (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block; 167 | 168 | ///----------------------------------------------- 169 | /// @name Dispatching database operations to queue 170 | ///----------------------------------------------- 171 | 172 | /** Synchronously perform database operations using save point. 173 | 174 | @param block The code to be run on the queue of `FMDatabaseQueue` 175 | */ 176 | 177 | // NOTE: you can not nest these, since calling it will pull another database out of the pool and you'll get a deadlock. 178 | // If you need to nest, use FMDatabase's startSavePointWithName:error: instead. 179 | - (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block; 180 | 181 | @end 182 | 183 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/FMDB/src/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 | 38 | + (instancetype)databaseQueueWithPath:(NSString*)aPath { 39 | 40 | FMDatabaseQueue *q = [[self alloc] initWithPath:aPath]; 41 | 42 | FMDBAutorelease(q); 43 | 44 | return q; 45 | } 46 | 47 | + (instancetype)databaseQueueWithPath:(NSString*)aPath flags:(int)openFlags { 48 | 49 | FMDatabaseQueue *q = [[self alloc] initWithPath:aPath flags:openFlags]; 50 | 51 | FMDBAutorelease(q); 52 | 53 | return q; 54 | } 55 | 56 | + (Class)databaseClass { 57 | return [FMDatabase class]; 58 | } 59 | 60 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags vfs:(NSString *)vfsName { 61 | 62 | self = [super init]; 63 | 64 | if (self != nil) { 65 | 66 | _db = [[[self class] databaseClass] databaseWithPath:aPath]; 67 | FMDBRetain(_db); 68 | 69 | #if SQLITE_VERSION_NUMBER >= 3005000 70 | BOOL success = [_db openWithFlags:openFlags vfs:vfsName]; 71 | #else 72 | BOOL success = [_db open]; 73 | #endif 74 | if (!success) { 75 | NSLog(@"Could not create database queue for path %@", aPath); 76 | FMDBRelease(self); 77 | return 0x00; 78 | } 79 | 80 | _path = FMDBReturnRetained(aPath); 81 | 82 | _queue = dispatch_queue_create([[NSString stringWithFormat:@"fmdb.%@", self] UTF8String], NULL); 83 | dispatch_queue_set_specific(_queue, kDispatchQueueSpecificKey, (__bridge void *)self, NULL); 84 | _openFlags = openFlags; 85 | } 86 | 87 | return self; 88 | } 89 | 90 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags { 91 | return [self initWithPath:aPath flags:openFlags vfs:nil]; 92 | } 93 | 94 | - (instancetype)initWithPath:(NSString*)aPath { 95 | 96 | // default flags for sqlite3_open 97 | return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE vfs:nil]; 98 | } 99 | 100 | - (instancetype)init { 101 | return [self initWithPath:nil]; 102 | } 103 | 104 | 105 | - (void)dealloc { 106 | 107 | FMDBRelease(_db); 108 | FMDBRelease(_path); 109 | 110 | if (_queue) { 111 | FMDBDispatchQueueRelease(_queue); 112 | _queue = 0x00; 113 | } 114 | #if ! __has_feature(objc_arc) 115 | [super dealloc]; 116 | #endif 117 | } 118 | 119 | - (void)close { 120 | FMDBRetain(self); 121 | dispatch_sync(_queue, ^() { 122 | [self->_db close]; 123 | FMDBRelease(_db); 124 | self->_db = 0x00; 125 | }); 126 | FMDBRelease(self); 127 | } 128 | 129 | - (FMDatabase*)database { 130 | if (!_db) { 131 | _db = FMDBReturnRetained([FMDatabase databaseWithPath:_path]); 132 | 133 | #if SQLITE_VERSION_NUMBER >= 3005000 134 | BOOL success = [_db openWithFlags:_openFlags]; 135 | #else 136 | BOOL success = [_db open]; 137 | #endif 138 | if (!success) { 139 | NSLog(@"FMDatabaseQueue could not reopen database for path %@", _path); 140 | FMDBRelease(_db); 141 | _db = 0x00; 142 | return 0x00; 143 | } 144 | } 145 | 146 | return _db; 147 | } 148 | 149 | - (void)inDatabase:(void (^)(FMDatabase *db))block { 150 | /* Get the currently executing queue (which should probably be nil, but in theory could be another DB queue 151 | * and then check it against self to make sure we're not about to deadlock. */ 152 | FMDatabaseQueue *currentSyncQueue = (__bridge id)dispatch_get_specific(kDispatchQueueSpecificKey); 153 | assert(currentSyncQueue != self && "inDatabase: was called reentrantly on the same queue, which would lead to a deadlock"); 154 | 155 | FMDBRetain(self); 156 | 157 | dispatch_sync(_queue, ^() { 158 | 159 | FMDatabase *db = [self database]; 160 | block(db); 161 | 162 | if ([db hasOpenResultSets]) { 163 | NSLog(@"Warning: there is at least one open result set around after performing [FMDatabaseQueue inDatabase:]"); 164 | 165 | #if defined(DEBUG) && DEBUG 166 | NSSet *openSetCopy = FMDBReturnAutoreleased([[db valueForKey:@"_openResultSets"] copy]); 167 | for (NSValue *rsInWrappedInATastyValueMeal in openSetCopy) { 168 | FMResultSet *rs = (FMResultSet *)[rsInWrappedInATastyValueMeal pointerValue]; 169 | NSLog(@"query: '%@'", [rs query]); 170 | } 171 | #endif 172 | } 173 | }); 174 | 175 | FMDBRelease(self); 176 | } 177 | 178 | 179 | - (void)beginTransaction:(BOOL)useDeferred withBlock:(void (^)(FMDatabase *db, BOOL *rollback))block { 180 | FMDBRetain(self); 181 | dispatch_sync(_queue, ^() { 182 | 183 | BOOL shouldRollback = NO; 184 | 185 | if (useDeferred) { 186 | [[self database] beginDeferredTransaction]; 187 | } 188 | else { 189 | [[self database] beginTransaction]; 190 | } 191 | 192 | block([self database], &shouldRollback); 193 | 194 | if (shouldRollback) { 195 | [[self database] rollback]; 196 | } 197 | else { 198 | [[self database] commit]; 199 | } 200 | }); 201 | 202 | FMDBRelease(self); 203 | } 204 | 205 | - (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block { 206 | [self beginTransaction:YES withBlock:block]; 207 | } 208 | 209 | - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block { 210 | [self beginTransaction:NO withBlock:block]; 211 | } 212 | 213 | - (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block { 214 | #if SQLITE_VERSION_NUMBER >= 3007000 215 | static unsigned long savePointIdx = 0; 216 | __block NSError *err = 0x00; 217 | FMDBRetain(self); 218 | dispatch_sync(_queue, ^() { 219 | 220 | NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++]; 221 | 222 | BOOL shouldRollback = NO; 223 | 224 | if ([[self database] startSavePointWithName:name error:&err]) { 225 | 226 | block([self database], &shouldRollback); 227 | 228 | if (shouldRollback) { 229 | // We need to rollback and release this savepoint to remove it 230 | [[self database] rollbackToSavePointWithName:name error:&err]; 231 | } 232 | [[self database] releaseSavePointWithName:name error:&err]; 233 | 234 | } 235 | }); 236 | FMDBRelease(self); 237 | return err; 238 | #else 239 | NSString *errorMessage = NSLocalizedString(@"Save point functions require SQLite 3.7", nil); 240 | if (self.logsErrors) NSLog(@"%@", errorMessage); 241 | return [NSError errorWithDomain:@"FMDatabase" code:0 userInfo:@{NSLocalizedDescriptionKey : errorMessage}]; 242 | #endif 243 | } 244 | 245 | @end 246 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/FMDB/src/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 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/FMDB/src/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 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - FMDB (2.6.2): 3 | - FMDB/standard (= 2.6.2) 4 | - FMDB/standard (2.6.2) 5 | 6 | DEPENDENCIES: 7 | - FMDB 8 | 9 | SPEC CHECKSUMS: 10 | FMDB: 854a0341b4726e53276f2a8996f06f1b80f9259a 11 | 12 | PODFILE CHECKSUM: 12c5bb3c07e1480129d6eb5af78ce2c849ae2044 13 | 14 | COCOAPODS: 1.1.1 15 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/Pods.xcodeproj/xcuserdata/clarence.xcuserdatad/xcschemes/FMDB.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 45 | 46 | 52 | 53 | 55 | 56 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/Pods.xcodeproj/xcuserdata/clarence.xcuserdatad/xcschemes/Pods-FLFMDBManager.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 66 | 67 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/Pods.xcodeproj/xcuserdata/clarence.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | FMDB.xcscheme 8 | 9 | isShown 10 | 11 | 12 | Pods-FLFMDBManager.xcscheme 13 | 14 | isShown 15 | 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | 07816470782C0FAE0243298354CAE618 21 | 22 | primary 23 | 24 | 25 | 251BAD17812F7EBF6532EACF66F941C3 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/Pods.xcodeproj/xcuserdata/kongfanlie.xcuserdatad/xcschemes/FMDB.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/Pods.xcodeproj/xcuserdata/kongfanlie.xcuserdatad/xcschemes/Pods-FLFMDBManager.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/Pods.xcodeproj/xcuserdata/kongfanlie.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | FMDB.xcscheme 8 | 9 | orderHint 10 | 1 11 | 12 | Pods-FLFMDBManager.xcscheme 13 | 14 | orderHint 15 | 2 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | 07816470782C0FAE0243298354CAE618 21 | 22 | primary 23 | 24 | 25 | 251BAD17812F7EBF6532EACF66F941C3 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/Target Support Files/FMDB/FMDB-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_FMDB : NSObject 3 | @end 4 | @implementation PodsDummy_FMDB 5 | @end 6 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/Target Support Files/FMDB/FMDB-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #endif 4 | 5 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/Target Support Files/FMDB/FMDB-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #endif 4 | 5 | #import "FMDatabase.h" 6 | #import "FMDatabaseAdditions.h" 7 | #import "FMDatabasePool.h" 8 | #import "FMDatabaseQueue.h" 9 | #import "FMDB.h" 10 | #import "FMResultSet.h" 11 | 12 | FOUNDATION_EXPORT double FMDBVersionNumber; 13 | FOUNDATION_EXPORT const unsigned char FMDBVersionString[]; 14 | 15 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/Target Support Files/FMDB/FMDB.modulemap: -------------------------------------------------------------------------------- 1 | framework module FMDB { 2 | umbrella header "FMDB-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/Target Support Files/FMDB/FMDB.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/FMDB 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public" 4 | OTHER_LDFLAGS = -l"sqlite3" 5 | PODS_BUILD_DIR = $BUILD_DIR 6 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_ROOT = ${SRCROOT} 8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 9 | SKIP_INSTALL = YES 10 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/Target Support Files/FMDB/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 | FMWK 17 | CFBundleShortVersionString 18 | 2.6.2 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/Target Support Files/Pods-FLFMDBManager/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 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/Target Support Files/Pods-FLFMDBManager/Pods-FLFMDBManager-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## FMDB 5 | 6 | If you are using FMDB in your project, I'd love to hear about it. Let Gus know 7 | by sending an email to gus@flyingmeat.com. 8 | 9 | And if you happen to come across either Gus Mueller or Rob Ryan in a bar, you 10 | might consider purchasing a drink of their choosing if FMDB has been useful to 11 | you. 12 | 13 | Finally, and shortly, this is the MIT License. 14 | 15 | Copyright (c) 2008-2014 Flying Meat Inc. 16 | 17 | Permission is hereby granted, free of charge, to any person obtaining a copy 18 | of this software and associated documentation files (the "Software"), to deal 19 | in the Software without restriction, including without limitation the rights 20 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 21 | copies of the Software, and to permit persons to whom the Software is 22 | furnished to do so, subject to the following conditions: 23 | 24 | The above copyright notice and this permission notice shall be included in 25 | all copies or substantial portions of the Software. 26 | 27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 30 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 31 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 32 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 33 | THE SOFTWARE. 34 | Generated by CocoaPods - https://cocoapods.org 35 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/Target Support Files/Pods-FLFMDBManager/Pods-FLFMDBManager-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | If you are using FMDB in your project, I'd love to hear about it. Let Gus know 18 | by sending an email to gus@flyingmeat.com. 19 | 20 | And if you happen to come across either Gus Mueller or Rob Ryan in a bar, you 21 | might consider purchasing a drink of their choosing if FMDB has been useful to 22 | you. 23 | 24 | Finally, and shortly, this is the MIT License. 25 | 26 | Copyright (c) 2008-2014 Flying Meat Inc. 27 | 28 | Permission is hereby granted, free of charge, to any person obtaining a copy 29 | of this software and associated documentation files (the "Software"), to deal 30 | in the Software without restriction, including without limitation the rights 31 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 32 | copies of the Software, and to permit persons to whom the Software is 33 | furnished to do so, subject to the following conditions: 34 | 35 | The above copyright notice and this permission notice shall be included in 36 | all copies or substantial portions of the Software. 37 | 38 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 39 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 40 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 41 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 42 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 43 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 44 | THE SOFTWARE. 45 | License 46 | MIT 47 | Title 48 | FMDB 49 | Type 50 | PSGroupSpecifier 51 | 52 | 53 | FooterText 54 | Generated by CocoaPods - https://cocoapods.org 55 | Title 56 | 57 | Type 58 | PSGroupSpecifier 59 | 60 | 61 | StringsTable 62 | Acknowledgements 63 | Title 64 | Acknowledgements 65 | 66 | 67 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/Target Support Files/Pods-FLFMDBManager/Pods-FLFMDBManager-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_FLFMDBManager : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_FLFMDBManager 5 | @end 6 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/Target Support Files/Pods-FLFMDBManager/Pods-FLFMDBManager-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 5 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 6 | 7 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 8 | 9 | install_framework() 10 | { 11 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 12 | local source="${BUILT_PRODUCTS_DIR}/$1" 13 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 14 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 15 | elif [ -r "$1" ]; then 16 | local source="$1" 17 | fi 18 | 19 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 20 | 21 | if [ -L "${source}" ]; then 22 | echo "Symlinked..." 23 | source="$(readlink "${source}")" 24 | fi 25 | 26 | # use filter instead of exclude so missing patterns dont' throw errors 27 | echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 28 | rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 29 | 30 | local basename 31 | basename="$(basename -s .framework "$1")" 32 | binary="${destination}/${basename}.framework/${basename}" 33 | if ! [ -r "$binary" ]; then 34 | binary="${destination}/${basename}" 35 | fi 36 | 37 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 38 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 39 | strip_invalid_archs "$binary" 40 | fi 41 | 42 | # Resign the code if required by the build settings to avoid unstable apps 43 | code_sign_if_enabled "${destination}/$(basename "$1")" 44 | 45 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 46 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 47 | local swift_runtime_libs 48 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) 49 | for lib in $swift_runtime_libs; do 50 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 51 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 52 | code_sign_if_enabled "${destination}/${lib}" 53 | done 54 | fi 55 | } 56 | 57 | # Signs a framework with the provided identity 58 | code_sign_if_enabled() { 59 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 60 | # Use the current code_sign_identitiy 61 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 62 | echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements \"$1\"" 63 | /usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements "$1" 64 | fi 65 | } 66 | 67 | # Strip invalid architectures 68 | strip_invalid_archs() { 69 | binary="$1" 70 | # Get architectures for current file 71 | archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" 72 | stripped="" 73 | for arch in $archs; do 74 | if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then 75 | # Strip non-valid architectures in-place 76 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1 77 | stripped="$stripped $arch" 78 | fi 79 | done 80 | if [[ "$stripped" ]]; then 81 | echo "Stripped $binary of architectures:$stripped" 82 | fi 83 | } 84 | 85 | 86 | if [[ "$CONFIGURATION" == "Debug" ]]; then 87 | install_framework "$BUILT_PRODUCTS_DIR/FMDB/FMDB.framework" 88 | fi 89 | if [[ "$CONFIGURATION" == "Release" ]]; then 90 | install_framework "$BUILT_PRODUCTS_DIR/FMDB/FMDB.framework" 91 | fi 92 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/Target Support Files/Pods-FLFMDBManager/Pods-FLFMDBManager-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 5 | 6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 7 | > "$RESOURCES_TO_COPY" 8 | 9 | XCASSET_FILES=() 10 | 11 | case "${TARGETED_DEVICE_FAMILY}" in 12 | 1,2) 13 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 14 | ;; 15 | 1) 16 | TARGET_DEVICE_ARGS="--target-device iphone" 17 | ;; 18 | 2) 19 | TARGET_DEVICE_ARGS="--target-device ipad" 20 | ;; 21 | *) 22 | TARGET_DEVICE_ARGS="--target-device mac" 23 | ;; 24 | esac 25 | 26 | install_resource() 27 | { 28 | if [[ "$1" = /* ]] ; then 29 | RESOURCE_PATH="$1" 30 | else 31 | RESOURCE_PATH="${PODS_ROOT}/$1" 32 | fi 33 | if [[ ! -e "$RESOURCE_PATH" ]] ; then 34 | cat << EOM 35 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. 36 | EOM 37 | exit 1 38 | fi 39 | case $RESOURCE_PATH in 40 | *.storyboard) 41 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" 42 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 43 | ;; 44 | *.xib) 45 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" 46 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 47 | ;; 48 | *.framework) 49 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 50 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 51 | echo "rsync -av $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 52 | rsync -av "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 53 | ;; 54 | *.xcdatamodel) 55 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" 56 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" 57 | ;; 58 | *.xcdatamodeld) 59 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" 60 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" 61 | ;; 62 | *.xcmappingmodel) 63 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" 64 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" 65 | ;; 66 | *.xcassets) 67 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" 68 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 69 | ;; 70 | *) 71 | echo "$RESOURCE_PATH" 72 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" 73 | ;; 74 | esac 75 | } 76 | 77 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 78 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 79 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then 80 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 81 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 82 | fi 83 | rm -f "$RESOURCES_TO_COPY" 84 | 85 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] 86 | then 87 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 88 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 89 | while read line; do 90 | if [[ $line != "${PODS_ROOT}*" ]]; then 91 | XCASSET_FILES+=("$line") 92 | fi 93 | done <<<"$OTHER_XCASSETS" 94 | 95 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 96 | fi 97 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/Target Support Files/Pods-FLFMDBManager/Pods-FLFMDBManager-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #endif 4 | 5 | 6 | FOUNDATION_EXPORT double Pods_FLFMDBManagerVersionNumber; 7 | FOUNDATION_EXPORT const unsigned char Pods_FLFMDBManagerVersionString[]; 8 | 9 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/Target Support Files/Pods-FLFMDBManager/Pods-FLFMDBManager.debug.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/FMDB" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 5 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/FMDB/FMDB.framework/Headers" 6 | OTHER_LDFLAGS = $(inherited) -framework "FMDB" 7 | PODS_BUILD_DIR = $BUILD_DIR 8 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/Target Support Files/Pods-FLFMDBManager/Pods-FLFMDBManager.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_FLFMDBManager { 2 | umbrella header "Pods-FLFMDBManager-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /FLFMDBManagerDemo/Pods/Target Support Files/Pods-FLFMDBManager/Pods-FLFMDBManager.release.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/FMDB" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 5 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/FMDB/FMDB.framework/Headers" 6 | OTHER_LDFLAGS = $(inherited) -framework "FMDB" 7 | PODS_BUILD_DIR = $BUILD_DIR 8 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #一、FMDB简单介绍 2 | >*FMDB是OC的方式封装了SQLite的C语言API,并且它对于多线程的并发操作进行了处理,所以是线程安全的;相对系统提供的CoreData,轻量好多,使用起来也很方便,除查询以外的所有操作,都称为“更新”,这里就不详细介绍了,不是本文的主题* 3 | - #####[FMDB gitHub地址](https://github.com/ccgus/fmdb) 4 | 5 | #二、为什么要再封装? 6 | - **1、隔离网络第三方框架,方便修改维护** 7 | 8 | - **2、虽然FMDB已经封装了SQLite,但依然需要写SQL语句,对于模型中属性比较多的话,拼接SQL语句将变得十分繁琐;而且对于字符串、字典、数组数据是没办法直接存入数据库,需要特殊处理。** 9 | >因此封装面向模型,只需要传入对应的模型信息就能进行数据库操作,不需要写任何SQL语句,屏蔽内部所有操作,插入什么模型,就取出什么模型,简单易用!同时为了保证传入的都是模型数据,添加了异常提示,对传入的模型做了限制,必须是NSObject或者NSObject的子类,同时不响应事件 10 | 11 | - **3、对数据库操作后需要关闭数据库,此时增加了代码量,而且容易忘记,内存没办法及时释放。** 12 | >因此将关闭数据库操作封装在框架中,此时调用不需要关心数据库的关闭 13 | 14 | - **4、面向模型开发,操作模型,更加面向对象,以前一般用数据库的时候一般都是直接保存后台返回的数据,此时每次取出来都要转一次模型,麻烦** 15 | 16 | #三、API介绍(增删改查) 17 | 18 | [针对FMDatabase的封装介绍](http://www.jianshu.com/p/17defd564844) 19 | 20 | [针对FMDatabaseQueue的封装介绍](http://www.jianshu.com/p/5d48ff77e46e) 21 | 22 | - *喜欢给个star,如果你有什么问题或者建议,尽管留言,欢迎大家去[简书](http://www.jianshu.com/users/fe5700cfb223/latest_articles)关注我,喜欢就给个like 和 star,随时更新!谢谢支持!* 23 | --------------------------------------------------------------------------------