├── .swift-version ├── 1.gif ├── LICENSE ├── 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 ├── Headers │ ├── Private │ │ └── FMDB │ │ │ ├── FMDB.h │ │ │ ├── FMDatabase.h │ │ │ ├── FMDatabaseAdditions.h │ │ │ ├── FMDatabasePool.h │ │ │ ├── FMDatabaseQueue.h │ │ │ └── FMResultSet.h │ └── Public │ │ └── FMDB │ │ ├── FMDB.h │ │ ├── FMDatabase.h │ │ ├── FMDatabaseAdditions.h │ │ ├── FMDatabasePool.h │ │ ├── FMDatabaseQueue.h │ │ └── FMResultSet.h ├── Manifest.lock ├── Pods.xcodeproj │ ├── project.pbxproj │ └── xcuserdata │ │ └── Tony.xcuserdatad │ │ └── xcschemes │ │ ├── FMDB.xcscheme │ │ ├── Pods-TODBModel.xcscheme │ │ └── xcschememanagement.plist └── Target Support Files │ ├── FMDB │ ├── FMDB-dummy.m │ ├── FMDB-prefix.pch │ └── FMDB.xcconfig │ └── Pods-TODBModel │ ├── Pods-TODBModel-acknowledgements.markdown │ ├── Pods-TODBModel-acknowledgements.plist │ ├── Pods-TODBModel-dummy.m │ ├── Pods-TODBModel-frameworks.sh │ ├── Pods-TODBModel-resources.sh │ ├── Pods-TODBModel.debug.xcconfig │ └── Pods-TODBModel.release.xcconfig ├── README.md ├── TODBModel.podspec ├── TODBModel.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── Tony.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── Tony.xcuserdatad │ └── xcschemes │ ├── TOModelDemo.xcscheme │ └── xcschememanagement.plist ├── TODBModel.xcworkspace ├── contents.xcworkspacedata ├── xcshareddata │ └── IDEWorkspaceChecks.plist └── xcuserdata │ └── Tony.xcuserdatad │ ├── UserInterfaceState.xcuserstate │ └── xcdebugger │ └── Breakpoints_v2.xcbkptlist ├── TODBModel ├── FMResultSet+Release.h ├── FMResultSet+Release.m ├── NSArray+CheckPointer.h ├── NSArray+CheckPointer.m ├── NSObject+Cache.h ├── NSObject+Cache.m ├── NSObject+NSCoding.h ├── NSObject+NSCoding.m ├── NSObject+Property.h ├── NSObject+Property.m ├── NSObject+Search.h ├── NSObject+Search.m ├── NSObject+TODBModel.h ├── NSObject+TODBModel.m ├── TODBAndCondition.h ├── TODBAndCondition.m ├── TODBCondition.h ├── TODBCondition.m ├── TODBModel.h ├── TODBModelConfig.h ├── TODBModelError.h ├── TODBNotCondition.h ├── TODBNotCondition.m ├── TODBOrCondition.h ├── TODBOrCondition.m ├── TODBPointer.h ├── TODBPointer.m ├── TODBPointerChecker.h ├── TODBPointerChecker.m ├── TODBPointerHelper.h ├── TODBPointerHelper.m ├── TODataBase.h ├── TODataTypeHelper.h └── TODataTypeHelper.m └── TODBModelDemo ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets ├── AppIcon.appiconset │ └── Contents.json ├── Contents.json └── user.imageset │ ├── Contents.json │ └── user@3x.png ├── Base.lproj └── LaunchScreen.storyboard ├── CreateAddressHelper.h ├── CreateAddressHelper.m ├── Info.plist ├── addressBook ├── cells │ ├── AddressTableViewCell.h │ ├── AddressTableViewCell.m │ └── AddressTableViewCell.xib ├── controllers │ ├── AddressBookTableViewController.h │ ├── AddressBookTableViewController.m │ ├── AddressSearchViewController.h │ ├── AddressSearchViewController.m │ ├── AddressSearchViewController.xib │ ├── EditAddressViewController.h │ ├── EditAddressViewController.m │ └── EditAddressViewController.xib └── models │ ├── AddressInfo.h │ ├── AddressInfo.m │ ├── AddressModel.h │ ├── AddressModel.m │ ├── Userinfo.h │ └── Userinfo.m ├── demoList ├── DemoListTableViewController.h └── DemoListTableViewController.m ├── main.m └── performance ├── PreformanceViewController.h ├── PreformanceViewController.m └── PreformanceViewController.xib /.swift-version: -------------------------------------------------------------------------------- 1 | 3.0 2 | -------------------------------------------------------------------------------- /1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyJR/TODBModel/8356d2e091d10d172968fe062f2a7a5ce7a04943/1.gif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Tony.JR 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '7.0' 2 | 3 | target 'TODBModel' do 4 | pod 'FMDB' 5 | end 6 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - FMDB (2.7.2): 3 | - FMDB/standard (= 2.7.2) 4 | - FMDB/standard (2.7.2) 5 | 6 | DEPENDENCIES: 7 | - FMDB 8 | 9 | SPEC CHECKSUMS: 10 | FMDB: 6198a90e7b6900cfc046e6bc0ef6ebb7be9236aa 11 | 12 | PODFILE CHECKSUM: 9c16a6a1d4092ed054958aeda0b786149e335341 13 | 14 | COCOAPODS: 1.3.1 15 | -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | /** Category of additions for `` class. 15 | 16 | ### See also 17 | 18 | - `` 19 | */ 20 | 21 | @interface FMDatabase (FMDatabaseAdditions) 22 | 23 | ///---------------------------------------- 24 | /// @name Return results of SQL to variable 25 | ///---------------------------------------- 26 | 27 | /** Return `int` value for query 28 | 29 | @param query The SQL query to be performed. 30 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 31 | 32 | @return `int` value. 33 | 34 | @note This is not available from Swift. 35 | */ 36 | 37 | - (int)intForQuery:(NSString*)query, ...; 38 | 39 | /** Return `long` value for query 40 | 41 | @param query The SQL query to be performed. 42 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 43 | 44 | @return `long` value. 45 | 46 | @note This is not available from Swift. 47 | */ 48 | 49 | - (long)longForQuery:(NSString*)query, ...; 50 | 51 | /** Return `BOOL` value for query 52 | 53 | @param query The SQL query to be performed. 54 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 55 | 56 | @return `BOOL` value. 57 | 58 | @note This is not available from Swift. 59 | */ 60 | 61 | - (BOOL)boolForQuery:(NSString*)query, ...; 62 | 63 | /** Return `double` value for query 64 | 65 | @param query The SQL query to be performed. 66 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 67 | 68 | @return `double` value. 69 | 70 | @note This is not available from Swift. 71 | */ 72 | 73 | - (double)doubleForQuery:(NSString*)query, ...; 74 | 75 | /** Return `NSString` value for query 76 | 77 | @param query The SQL query to be performed. 78 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 79 | 80 | @return `NSString` value. 81 | 82 | @note This is not available from Swift. 83 | */ 84 | 85 | - (NSString * _Nullable)stringForQuery:(NSString*)query, ...; 86 | 87 | /** Return `NSData` value for query 88 | 89 | @param query The SQL query to be performed. 90 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 91 | 92 | @return `NSData` value. 93 | 94 | @note This is not available from Swift. 95 | */ 96 | 97 | - (NSData * _Nullable)dataForQuery:(NSString*)query, ...; 98 | 99 | /** Return `NSDate` value for query 100 | 101 | @param query The SQL query to be performed. 102 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 103 | 104 | @return `NSDate` value. 105 | 106 | @note This is not available from Swift. 107 | */ 108 | 109 | - (NSDate * _Nullable)dateForQuery:(NSString*)query, ...; 110 | 111 | 112 | // Notice that there's no dataNoCopyForQuery:. 113 | // That would be a bad idea, because we close out the result set, and then what 114 | // happens to the data that we just didn't copy? Who knows, not I. 115 | 116 | 117 | ///-------------------------------- 118 | /// @name Schema related operations 119 | ///-------------------------------- 120 | 121 | /** Does table exist in database? 122 | 123 | @param tableName The name of the table being looked for. 124 | 125 | @return `YES` if table found; `NO` if not found. 126 | */ 127 | 128 | - (BOOL)tableExists:(NSString*)tableName; 129 | 130 | /** The schema of the database. 131 | 132 | This will be the schema for the entire database. For each entity, each row of the result set will include the following fields: 133 | 134 | - `type` - The type of entity (e.g. table, index, view, or trigger) 135 | - `name` - The name of the object 136 | - `tbl_name` - The name of the table to which the object references 137 | - `rootpage` - The page number of the root b-tree page for tables and indices 138 | - `sql` - The SQL that created the entity 139 | 140 | @return `FMResultSet` of schema; `nil` on error. 141 | 142 | @see [SQLite File Format](http://www.sqlite.org/fileformat.html) 143 | */ 144 | 145 | - (FMResultSet *)getSchema; 146 | 147 | /** The schema of the database. 148 | 149 | This will be the schema for a particular table as report by SQLite `PRAGMA`, for example: 150 | 151 | PRAGMA table_info('employees') 152 | 153 | This will report: 154 | 155 | - `cid` - The column ID number 156 | - `name` - The name of the column 157 | - `type` - The data type specified for the column 158 | - `notnull` - whether the field is defined as NOT NULL (i.e. values required) 159 | - `dflt_value` - The default value for the column 160 | - `pk` - Whether the field is part of the primary key of the table 161 | 162 | @param tableName The name of the table for whom the schema will be returned. 163 | 164 | @return `FMResultSet` of schema; `nil` on error. 165 | 166 | @see [table_info](http://www.sqlite.org/pragma.html#pragma_table_info) 167 | */ 168 | 169 | - (FMResultSet*)getTableSchema:(NSString*)tableName; 170 | 171 | /** Test to see if particular column exists for particular table in database 172 | 173 | @param columnName The name of the column. 174 | 175 | @param tableName The name of the table. 176 | 177 | @return `YES` if column exists in table in question; `NO` otherwise. 178 | */ 179 | 180 | - (BOOL)columnExists:(NSString*)columnName inTableWithName:(NSString*)tableName; 181 | 182 | /** Test to see if particular column exists for particular table in database 183 | 184 | @param columnName The name of the column. 185 | 186 | @param tableName The name of the table. 187 | 188 | @return `YES` if column exists in table in question; `NO` otherwise. 189 | 190 | @see columnExists:inTableWithName: 191 | 192 | @warning Deprecated - use `` instead. 193 | */ 194 | 195 | - (BOOL)columnExists:(NSString*)tableName columnName:(NSString*)columnName __deprecated_msg("Use columnExists:inTableWithName: instead"); 196 | 197 | 198 | /** Validate SQL statement 199 | 200 | This validates SQL statement by performing `sqlite3_prepare_v2`, but not returning the results, but instead immediately calling `sqlite3_finalize`. 201 | 202 | @param sql The SQL statement being validated. 203 | 204 | @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. 205 | 206 | @return `YES` if validation succeeded without incident; `NO` otherwise. 207 | 208 | */ 209 | 210 | - (BOOL)validateSQL:(NSString*)sql error:(NSError * _Nullable *)error; 211 | 212 | 213 | ///----------------------------------- 214 | /// @name Application identifier tasks 215 | ///----------------------------------- 216 | 217 | /** Retrieve application ID 218 | 219 | @return The `uint32_t` numeric value of the application ID. 220 | 221 | @see setApplicationID: 222 | */ 223 | 224 | @property (nonatomic) uint32_t applicationID; 225 | 226 | #if TARGET_OS_MAC && !TARGET_OS_IPHONE 227 | 228 | /** Retrieve application ID string 229 | 230 | @see setApplicationIDString: 231 | */ 232 | 233 | @property (nonatomic, retain) NSString *applicationIDString; 234 | 235 | #endif 236 | 237 | ///----------------------------------- 238 | /// @name user version identifier tasks 239 | ///----------------------------------- 240 | 241 | /** Retrieve user version 242 | 243 | @see setUserVersion: 244 | */ 245 | 246 | @property (nonatomic) uint32_t userVersion; 247 | 248 | @end 249 | 250 | NS_ASSUME_NONNULL_END 251 | -------------------------------------------------------------------------------- /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 * _Nullable)arrayArgs orDictionary:(NSDictionary * _Nullable)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) TO_MODEL_LOG(@"%@", 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) TO_MODEL_LOG(@"%@", 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) TO_MODEL_LOG(@"%@", 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 | TO_MODEL_LOG(@"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) TO_MODEL_LOG(@"%@", 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 | - (BOOL)validateSQL:(NSString*)sql error:(NSError**)error { 226 | sqlite3_stmt *pStmt = NULL; 227 | BOOL validationSucceeded = YES; 228 | 229 | int rc = sqlite3_prepare_v2([self sqliteHandle], [sql UTF8String], -1, &pStmt, 0); 230 | if (rc != SQLITE_OK) { 231 | validationSucceeded = NO; 232 | if (error) { 233 | *error = [NSError errorWithDomain:NSCocoaErrorDomain 234 | code:[self lastErrorCode] 235 | userInfo:[NSDictionary dictionaryWithObject:[self lastErrorMessage] 236 | forKey:NSLocalizedDescriptionKey]]; 237 | } 238 | } 239 | 240 | sqlite3_finalize(pStmt); 241 | 242 | return validationSucceeded; 243 | } 244 | 245 | @end 246 | -------------------------------------------------------------------------------- /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 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @class FMDatabase; 14 | 15 | /** Pool of `` objects. 16 | 17 | ### See also 18 | 19 | - `` 20 | - `` 21 | 22 | @warning Before using `FMDatabasePool`, please consider using `` instead. 23 | 24 | If you really really really know what you're doing and `FMDatabasePool` is what 25 | you really really need (ie, you're using a read only database), OK you can use 26 | it. But just be careful not to deadlock! 27 | 28 | For an example on deadlocking, search for: 29 | `ONLY_USE_THE_POOL_IF_YOU_ARE_DOING_READS_OTHERWISE_YOULL_DEADLOCK_USE_FMDATABASEQUEUE_INSTEAD` 30 | in the main.m file. 31 | */ 32 | 33 | @interface FMDatabasePool : NSObject 34 | 35 | /** Database path */ 36 | 37 | @property (atomic, copy, nullable) NSString *path; 38 | 39 | /** Delegate object */ 40 | 41 | @property (atomic, assign, nullable) id delegate; 42 | 43 | /** Maximum number of databases to create */ 44 | 45 | @property (atomic, assign) NSUInteger maximumNumberOfDatabasesToCreate; 46 | 47 | /** Open flags */ 48 | 49 | @property (atomic, readonly) int openFlags; 50 | 51 | /** Custom virtual file system name */ 52 | 53 | @property (atomic, copy, nullable) NSString *vfsName; 54 | 55 | 56 | ///--------------------- 57 | /// @name Initialization 58 | ///--------------------- 59 | 60 | /** Create pool using path. 61 | 62 | @param aPath The file path of the database. 63 | 64 | @return The `FMDatabasePool` object. `nil` on error. 65 | */ 66 | 67 | + (instancetype)databasePoolWithPath:(NSString * _Nullable)aPath; 68 | 69 | /** Create pool using file URL. 70 | 71 | @param url The file `NSURL` of the database. 72 | 73 | @return The `FMDatabasePool` object. `nil` on error. 74 | */ 75 | 76 | + (instancetype)databasePoolWithURL:(NSURL * _Nullable)url; 77 | 78 | /** Create pool using path and specified flags 79 | 80 | @param aPath The file path of the database. 81 | @param openFlags Flags passed to the openWithFlags method of the database. 82 | 83 | @return The `FMDatabasePool` object. `nil` on error. 84 | */ 85 | 86 | + (instancetype)databasePoolWithPath:(NSString * _Nullable)aPath flags:(int)openFlags; 87 | 88 | /** Create pool using file URL and specified flags 89 | 90 | @param url The file `NSURL` of the database. 91 | @param openFlags Flags passed to the openWithFlags method of the database. 92 | 93 | @return The `FMDatabasePool` object. `nil` on error. 94 | */ 95 | 96 | + (instancetype)databasePoolWithURL:(NSURL * _Nullable)url flags:(int)openFlags; 97 | 98 | /** Create pool using path. 99 | 100 | @param aPath The file path of the database. 101 | 102 | @return The `FMDatabasePool` object. `nil` on error. 103 | */ 104 | 105 | - (instancetype)initWithPath:(NSString * _Nullable)aPath; 106 | 107 | /** Create pool using file URL. 108 | 109 | @param url The file `NSURL of the database. 110 | 111 | @return The `FMDatabasePool` object. `nil` on error. 112 | */ 113 | 114 | - (instancetype)initWithURL:(NSURL * _Nullable)url; 115 | 116 | /** Create pool using path and specified flags. 117 | 118 | @param aPath The file path of the database. 119 | @param openFlags Flags passed to the openWithFlags method of the database 120 | 121 | @return The `FMDatabasePool` object. `nil` on error. 122 | */ 123 | 124 | - (instancetype)initWithPath:(NSString * _Nullable)aPath flags:(int)openFlags; 125 | 126 | /** Create pool using file URL and specified flags. 127 | 128 | @param url The file `NSURL` of the database. 129 | @param openFlags Flags passed to the openWithFlags method of the database 130 | 131 | @return The `FMDatabasePool` object. `nil` on error. 132 | */ 133 | 134 | - (instancetype)initWithURL:(NSURL * _Nullable)url flags:(int)openFlags; 135 | 136 | /** Create pool using path and specified flags. 137 | 138 | @param aPath The file path of the database. 139 | @param openFlags Flags passed to the openWithFlags method of the database 140 | @param vfsName The name of a custom virtual file system 141 | 142 | @return The `FMDatabasePool` object. `nil` on error. 143 | */ 144 | 145 | - (instancetype)initWithPath:(NSString * _Nullable)aPath flags:(int)openFlags vfs:(NSString * _Nullable)vfsName; 146 | 147 | /** Create pool using file URL and specified flags. 148 | 149 | @param url The file `NSURL` of the database. 150 | @param openFlags Flags passed to the openWithFlags method of the database 151 | @param vfsName The name of a custom virtual file system 152 | 153 | @return The `FMDatabasePool` object. `nil` on error. 154 | */ 155 | 156 | - (instancetype)initWithURL:(NSURL * _Nullable)url flags:(int)openFlags vfs:(NSString * _Nullable)vfsName; 157 | 158 | /** Returns the Class of 'FMDatabase' subclass, that will be used to instantiate database object. 159 | 160 | Subclasses can override this method to return specified Class of 'FMDatabase' subclass. 161 | 162 | @return The Class of 'FMDatabase' subclass, that will be used to instantiate database object. 163 | */ 164 | 165 | + (Class)databaseClass; 166 | 167 | ///------------------------------------------------ 168 | /// @name Keeping track of checked in/out databases 169 | ///------------------------------------------------ 170 | 171 | /** Number of checked-in databases in pool 172 | */ 173 | 174 | @property (nonatomic, readonly) NSUInteger countOfCheckedInDatabases; 175 | 176 | /** Number of checked-out databases in pool 177 | */ 178 | 179 | @property (nonatomic, readonly) NSUInteger countOfCheckedOutDatabases; 180 | 181 | /** Total number of databases in pool 182 | */ 183 | 184 | @property (nonatomic, readonly) NSUInteger countOfOpenDatabases; 185 | 186 | /** Release all databases in pool */ 187 | 188 | - (void)releaseAllDatabases; 189 | 190 | ///------------------------------------------ 191 | /// @name Perform database operations in pool 192 | ///------------------------------------------ 193 | 194 | /** Synchronously perform database operations in pool. 195 | 196 | @param block The code to be run on the `FMDatabasePool` pool. 197 | */ 198 | 199 | - (void)inDatabase:(__attribute__((noescape)) void (^)(FMDatabase *db))block; 200 | 201 | /** Synchronously perform database operations in pool using transaction. 202 | 203 | @param block The code to be run on the `FMDatabasePool` pool. 204 | */ 205 | 206 | - (void)inTransaction:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block; 207 | 208 | /** Synchronously perform database operations in pool using deferred transaction. 209 | 210 | @param block The code to be run on the `FMDatabasePool` pool. 211 | */ 212 | 213 | - (void)inDeferredTransaction:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block; 214 | 215 | /** Synchronously perform database operations in pool using save point. 216 | 217 | @param block The code to be run on the `FMDatabasePool` pool. 218 | 219 | @return `NSError` object if error; `nil` if successful. 220 | 221 | @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. 222 | */ 223 | 224 | - (NSError * _Nullable)inSavePoint:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block; 225 | 226 | @end 227 | 228 | 229 | /** FMDatabasePool delegate category 230 | 231 | This is a category that defines the protocol for the FMDatabasePool delegate 232 | */ 233 | 234 | @interface NSObject (FMDatabasePoolDelegate) 235 | 236 | /** Asks the delegate whether database should be added to the pool. 237 | 238 | @param pool The `FMDatabasePool` object. 239 | @param database The `FMDatabase` object. 240 | 241 | @return `YES` if it should add database to pool; `NO` if not. 242 | 243 | */ 244 | 245 | - (BOOL)databasePool:(FMDatabasePool*)pool shouldAddDatabaseToPool:(FMDatabase*)database; 246 | 247 | /** Tells the delegate that database was added to the pool. 248 | 249 | @param pool The `FMDatabasePool` object. 250 | @param database The `FMDatabase` object. 251 | 252 | */ 253 | 254 | - (void)databasePool:(FMDatabasePool*)pool didAddDatabase:(FMDatabase*)database; 255 | 256 | @end 257 | 258 | NS_ASSUME_NONNULL_END 259 | -------------------------------------------------------------------------------- /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 | dispatch_queue_t _lockQueue; 20 | 21 | NSMutableArray *_databaseInPool; 22 | NSMutableArray *_databaseOutPool; 23 | } 24 | 25 | - (void)pushDatabaseBackInPool:(FMDatabase*)db; 26 | - (FMDatabase*)db; 27 | 28 | @end 29 | 30 | 31 | @implementation FMDatabasePool 32 | @synthesize path=_path; 33 | @synthesize delegate=_delegate; 34 | @synthesize maximumNumberOfDatabasesToCreate=_maximumNumberOfDatabasesToCreate; 35 | @synthesize openFlags=_openFlags; 36 | 37 | 38 | + (instancetype)databasePoolWithPath:(NSString *)aPath { 39 | return FMDBReturnAutoreleased([[self alloc] initWithPath:aPath]); 40 | } 41 | 42 | + (instancetype)databasePoolWithURL:(NSURL *)url { 43 | return FMDBReturnAutoreleased([[self alloc] initWithPath:url.path]); 44 | } 45 | 46 | + (instancetype)databasePoolWithPath:(NSString *)aPath flags:(int)openFlags { 47 | return FMDBReturnAutoreleased([[self alloc] initWithPath:aPath flags:openFlags]); 48 | } 49 | 50 | + (instancetype)databasePoolWithURL:(NSURL *)url flags:(int)openFlags { 51 | return FMDBReturnAutoreleased([[self alloc] initWithPath:url.path flags:openFlags]); 52 | } 53 | 54 | - (instancetype)initWithURL:(NSURL *)url flags:(int)openFlags vfs:(NSString *)vfsName { 55 | return [self initWithPath:url.path flags:openFlags vfs:vfsName]; 56 | } 57 | 58 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags vfs:(NSString *)vfsName { 59 | 60 | self = [super init]; 61 | 62 | if (self != nil) { 63 | _path = [aPath copy]; 64 | _lockQueue = dispatch_queue_create([[NSString stringWithFormat:@"fmdb.%@", self] UTF8String], NULL); 65 | _databaseInPool = FMDBReturnRetained([NSMutableArray array]); 66 | _databaseOutPool = FMDBReturnRetained([NSMutableArray array]); 67 | _openFlags = openFlags; 68 | _vfsName = [vfsName copy]; 69 | } 70 | 71 | return self; 72 | } 73 | 74 | - (instancetype)initWithPath:(NSString *)aPath flags:(int)openFlags { 75 | return [self initWithPath:aPath flags:openFlags vfs:nil]; 76 | } 77 | 78 | - (instancetype)initWithURL:(NSURL *)url flags:(int)openFlags { 79 | return [self initWithPath:url.path flags:openFlags vfs:nil]; 80 | } 81 | 82 | - (instancetype)initWithPath:(NSString*)aPath { 83 | // default flags for sqlite3_open 84 | return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE]; 85 | } 86 | 87 | - (instancetype)initWithURL:(NSURL *)url { 88 | return [self initWithPath:url.path]; 89 | } 90 | 91 | - (instancetype)init { 92 | return [self initWithPath:nil]; 93 | } 94 | 95 | + (Class)databaseClass { 96 | return [FMDatabase class]; 97 | } 98 | 99 | - (void)dealloc { 100 | 101 | _delegate = 0x00; 102 | FMDBRelease(_path); 103 | FMDBRelease(_databaseInPool); 104 | FMDBRelease(_databaseOutPool); 105 | FMDBRelease(_vfsName); 106 | 107 | if (_lockQueue) { 108 | FMDBDispatchQueueRelease(_lockQueue); 109 | _lockQueue = 0x00; 110 | } 111 | #if ! __has_feature(objc_arc) 112 | [super dealloc]; 113 | #endif 114 | } 115 | 116 | 117 | - (void)executeLocked:(void (^)(void))aBlock { 118 | dispatch_sync(_lockQueue, aBlock); 119 | } 120 | 121 | - (void)pushDatabaseBackInPool:(FMDatabase*)db { 122 | 123 | if (!db) { // db can be null if we set an upper bound on the # of databases to create. 124 | return; 125 | } 126 | 127 | [self executeLocked:^() { 128 | 129 | if ([self->_databaseInPool containsObject:db]) { 130 | [[NSException exceptionWithName:@"Database already in pool" reason:@"The FMDatabase being put back into the pool is already present in the pool" userInfo:nil] raise]; 131 | } 132 | 133 | [self->_databaseInPool addObject:db]; 134 | [self->_databaseOutPool removeObject:db]; 135 | 136 | }]; 137 | } 138 | 139 | - (FMDatabase*)db { 140 | 141 | __block FMDatabase *db; 142 | 143 | 144 | [self executeLocked:^() { 145 | db = [self->_databaseInPool lastObject]; 146 | 147 | BOOL shouldNotifyDelegate = NO; 148 | 149 | if (db) { 150 | [self->_databaseOutPool addObject:db]; 151 | [self->_databaseInPool removeLastObject]; 152 | } 153 | else { 154 | 155 | if (self->_maximumNumberOfDatabasesToCreate) { 156 | NSUInteger currentCount = [self->_databaseOutPool count] + [self->_databaseInPool count]; 157 | 158 | if (currentCount >= self->_maximumNumberOfDatabasesToCreate) { 159 | NSLog(@"Maximum number of databases (%ld) has already been reached!", (long)currentCount); 160 | return; 161 | } 162 | } 163 | 164 | db = [[[self class] databaseClass] databaseWithPath:self->_path]; 165 | shouldNotifyDelegate = YES; 166 | } 167 | 168 | //This ensures that the db is opened before returning 169 | #if SQLITE_VERSION_NUMBER >= 3005000 170 | BOOL success = [db openWithFlags:self->_openFlags vfs:self->_vfsName]; 171 | #else 172 | BOOL success = [db open]; 173 | #endif 174 | if (success) { 175 | if ([self->_delegate respondsToSelector:@selector(databasePool:shouldAddDatabaseToPool:)] && ![self->_delegate databasePool:self shouldAddDatabaseToPool:db]) { 176 | [db close]; 177 | db = 0x00; 178 | } 179 | else { 180 | //It should not get added in the pool twice if lastObject was found 181 | if (![self->_databaseOutPool containsObject:db]) { 182 | [self->_databaseOutPool addObject:db]; 183 | 184 | if (shouldNotifyDelegate && [self->_delegate respondsToSelector:@selector(databasePool:didAddDatabase:)]) { 185 | [self->_delegate databasePool:self didAddDatabase:db]; 186 | } 187 | } 188 | } 189 | } 190 | else { 191 | NSLog(@"Could not open up the database at path %@", self->_path); 192 | db = 0x00; 193 | } 194 | }]; 195 | 196 | return db; 197 | } 198 | 199 | - (NSUInteger)countOfCheckedInDatabases { 200 | 201 | __block NSUInteger count; 202 | 203 | [self executeLocked:^() { 204 | count = [self->_databaseInPool count]; 205 | }]; 206 | 207 | return count; 208 | } 209 | 210 | - (NSUInteger)countOfCheckedOutDatabases { 211 | 212 | __block NSUInteger count; 213 | 214 | [self executeLocked:^() { 215 | count = [self->_databaseOutPool count]; 216 | }]; 217 | 218 | return count; 219 | } 220 | 221 | - (NSUInteger)countOfOpenDatabases { 222 | __block NSUInteger count; 223 | 224 | [self executeLocked:^() { 225 | count = [self->_databaseOutPool count] + [self->_databaseInPool count]; 226 | }]; 227 | 228 | return count; 229 | } 230 | 231 | - (void)releaseAllDatabases { 232 | [self executeLocked:^() { 233 | [self->_databaseOutPool removeAllObjects]; 234 | [self->_databaseInPool removeAllObjects]; 235 | }]; 236 | } 237 | 238 | - (void)inDatabase:(void (^)(FMDatabase *db))block { 239 | 240 | FMDatabase *db = [self db]; 241 | 242 | block(db); 243 | 244 | [self pushDatabaseBackInPool:db]; 245 | } 246 | 247 | - (void)beginTransaction:(BOOL)useDeferred withBlock:(void (^)(FMDatabase *db, BOOL *rollback))block { 248 | 249 | BOOL shouldRollback = NO; 250 | 251 | FMDatabase *db = [self db]; 252 | 253 | if (useDeferred) { 254 | [db beginDeferredTransaction]; 255 | } 256 | else { 257 | [db beginTransaction]; 258 | } 259 | 260 | 261 | block(db, &shouldRollback); 262 | 263 | if (shouldRollback) { 264 | [db rollback]; 265 | } 266 | else { 267 | [db commit]; 268 | } 269 | 270 | [self pushDatabaseBackInPool:db]; 271 | } 272 | 273 | - (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block { 274 | [self beginTransaction:YES withBlock:block]; 275 | } 276 | 277 | - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block { 278 | [self beginTransaction:NO withBlock:block]; 279 | } 280 | 281 | - (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block { 282 | #if SQLITE_VERSION_NUMBER >= 3007000 283 | static unsigned long savePointIdx = 0; 284 | 285 | NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++]; 286 | 287 | BOOL shouldRollback = NO; 288 | 289 | FMDatabase *db = [self db]; 290 | 291 | NSError *err = 0x00; 292 | 293 | if (![db startSavePointWithName:name error:&err]) { 294 | [self pushDatabaseBackInPool:db]; 295 | return err; 296 | } 297 | 298 | block(db, &shouldRollback); 299 | 300 | if (shouldRollback) { 301 | // We need to rollback and release this savepoint to remove it 302 | [db rollbackToSavePointWithName:name error:&err]; 303 | } 304 | [db releaseSavePointWithName:name error:&err]; 305 | 306 | [self pushDatabaseBackInPool:db]; 307 | 308 | return err; 309 | #else 310 | NSString *errorMessage = NSLocalizedString(@"Save point functions require SQLite 3.7", nil); 311 | if (self.logsErrors) NSLog(@"%@", errorMessage); 312 | return [NSError errorWithDomain:@"FMDatabase" code:0 userInfo:@{NSLocalizedDescriptionKey : errorMessage}]; 313 | #endif 314 | } 315 | 316 | @end 317 | -------------------------------------------------------------------------------- /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 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @class FMDatabase; 14 | 15 | /** To perform queries and updates on multiple threads, you'll want to use `FMDatabaseQueue`. 16 | 17 | 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. 18 | 19 | Instead, use `FMDatabaseQueue`. Here's how to use it: 20 | 21 | First, make your queue. 22 | 23 | FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath]; 24 | 25 | Then use it like so: 26 | 27 | [queue inDatabase:^(FMDatabase *db) { 28 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]]; 29 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]]; 30 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]]; 31 | 32 | FMResultSet *rs = [db executeQuery:@"select * from foo"]; 33 | while ([rs next]) { 34 | //… 35 | } 36 | }]; 37 | 38 | An easy way to wrap things up in a transaction can be done like this: 39 | 40 | [queue inTransaction:^(FMDatabase *db, BOOL *rollback) { 41 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]]; 42 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]]; 43 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]]; 44 | 45 | if (whoopsSomethingWrongHappened) { 46 | *rollback = YES; 47 | return; 48 | } 49 | // etc… 50 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:4]]; 51 | }]; 52 | 53 | `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. 54 | 55 | ### See also 56 | 57 | - `` 58 | 59 | @warning Do not instantiate a single `` object and use it across multiple threads. Use `FMDatabaseQueue` instead. 60 | 61 | @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. 62 | 63 | */ 64 | 65 | @interface FMDatabaseQueue : NSObject 66 | /** Path of database */ 67 | 68 | @property (atomic, retain, nullable) NSString *path; 69 | 70 | /** Open flags */ 71 | 72 | @property (atomic, readonly) int openFlags; 73 | 74 | /** Custom virtual file system name */ 75 | 76 | @property (atomic, copy, nullable) NSString *vfsName; 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 * _Nullable)aPath; 90 | 91 | /** Create queue using file URL. 92 | 93 | @param url The file `NSURL` of the database. 94 | 95 | @return The `FMDatabaseQueue` object. `nil` on error. 96 | */ 97 | 98 | + (instancetype)databaseQueueWithURL:(NSURL * _Nullable)url; 99 | 100 | /** Create queue using path and specified flags. 101 | 102 | @param aPath The file path of the database. 103 | @param openFlags Flags passed to the openWithFlags method of the database. 104 | 105 | @return The `FMDatabaseQueue` object. `nil` on error. 106 | */ 107 | + (instancetype)databaseQueueWithPath:(NSString * _Nullable)aPath flags:(int)openFlags; 108 | 109 | /** Create queue using file URL and specified flags. 110 | 111 | @param url The file `NSURL` 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 | + (instancetype)databaseQueueWithURL:(NSURL * _Nullable)url flags:(int)openFlags; 117 | 118 | /** Create queue using path. 119 | 120 | @param aPath The file path of the database. 121 | 122 | @return The `FMDatabaseQueue` object. `nil` on error. 123 | */ 124 | 125 | - (instancetype)initWithPath:(NSString * _Nullable)aPath; 126 | 127 | /** Create queue using file URL. 128 | 129 | @param url The file `NSURL of the database. 130 | 131 | @return The `FMDatabaseQueue` object. `nil` on error. 132 | */ 133 | 134 | - (instancetype)initWithURL:(NSURL * _Nullable)url; 135 | 136 | /** Create queue using path and specified flags. 137 | 138 | @param aPath The file path of the database. 139 | @param openFlags Flags passed to the openWithFlags method of the database. 140 | 141 | @return The `FMDatabaseQueue` object. `nil` on error. 142 | */ 143 | 144 | - (instancetype)initWithPath:(NSString * _Nullable)aPath flags:(int)openFlags; 145 | 146 | /** Create queue using file URL and specified flags. 147 | 148 | @param url The file path of the database. 149 | @param openFlags Flags passed to the openWithFlags method of the database. 150 | 151 | @return The `FMDatabaseQueue` object. `nil` on error. 152 | */ 153 | 154 | - (instancetype)initWithURL:(NSURL * _Nullable)url flags:(int)openFlags; 155 | 156 | /** Create queue using path and specified flags. 157 | 158 | @param aPath The file path of the database. 159 | @param openFlags Flags passed to the openWithFlags method of the database 160 | @param vfsName The name of a custom virtual file system 161 | 162 | @return The `FMDatabaseQueue` object. `nil` on error. 163 | */ 164 | 165 | - (instancetype)initWithPath:(NSString * _Nullable)aPath flags:(int)openFlags vfs:(NSString * _Nullable)vfsName; 166 | 167 | /** Create queue using file URL and specified flags. 168 | 169 | @param url The file `NSURL of the database. 170 | @param openFlags Flags passed to the openWithFlags method of the database 171 | @param vfsName The name of a custom virtual file system 172 | 173 | @return The `FMDatabaseQueue` object. `nil` on error. 174 | */ 175 | 176 | - (instancetype)initWithURL:(NSURL * _Nullable)url flags:(int)openFlags vfs:(NSString * _Nullable)vfsName; 177 | 178 | /** Returns the Class of 'FMDatabase' subclass, that will be used to instantiate database object. 179 | 180 | Subclasses can override this method to return specified Class of 'FMDatabase' subclass. 181 | 182 | @return The Class of 'FMDatabase' subclass, that will be used to instantiate database object. 183 | */ 184 | 185 | + (Class)databaseClass; 186 | 187 | /** Close database used by queue. */ 188 | 189 | - (void)close; 190 | 191 | /** Interupt pending database operation. */ 192 | 193 | - (void)interrupt; 194 | 195 | ///----------------------------------------------- 196 | /// @name Dispatching database operations to queue 197 | ///----------------------------------------------- 198 | 199 | /** Synchronously perform database operations on queue. 200 | 201 | @param block The code to be run on the queue of `FMDatabaseQueue` 202 | */ 203 | 204 | - (void)inDatabase:(__attribute__((noescape)) void (^)(FMDatabase *db))block; 205 | 206 | /** Synchronously perform database operations on queue, using transactions. 207 | 208 | @param block The code to be run on the queue of `FMDatabaseQueue` 209 | */ 210 | 211 | - (void)inTransaction:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block; 212 | 213 | /** Synchronously perform database operations on queue, using deferred transactions. 214 | 215 | @param block The code to be run on the queue of `FMDatabaseQueue` 216 | */ 217 | 218 | - (void)inDeferredTransaction:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block; 219 | 220 | ///----------------------------------------------- 221 | /// @name Dispatching database operations to queue 222 | ///----------------------------------------------- 223 | 224 | /** Synchronously perform database operations using save point. 225 | 226 | @param block The code to be run on the queue of `FMDatabaseQueue` 227 | */ 228 | 229 | // NOTE: you can not nest these, since calling it will pull another database out of the pool and you'll get a deadlock. 230 | // If you need to nest, use FMDatabase's startSavePointWithName:error: instead. 231 | - (NSError * _Nullable)inSavePoint:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block; 232 | 233 | @end 234 | 235 | NS_ASSUME_NONNULL_END 236 | -------------------------------------------------------------------------------- /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 | @interface FMDatabaseQueue () { 34 | dispatch_queue_t _queue; 35 | FMDatabase *_db; 36 | } 37 | @end 38 | 39 | @implementation FMDatabaseQueue 40 | 41 | + (instancetype)databaseQueueWithPath:(NSString *)aPath { 42 | FMDatabaseQueue *q = [[self alloc] initWithPath:aPath]; 43 | 44 | FMDBAutorelease(q); 45 | 46 | return q; 47 | } 48 | 49 | + (instancetype)databaseQueueWithURL:(NSURL *)url { 50 | return [self databaseQueueWithPath:url.path]; 51 | } 52 | 53 | + (instancetype)databaseQueueWithPath:(NSString *)aPath flags:(int)openFlags { 54 | FMDatabaseQueue *q = [[self alloc] initWithPath:aPath flags:openFlags]; 55 | 56 | FMDBAutorelease(q); 57 | 58 | return q; 59 | } 60 | 61 | + (instancetype)databaseQueueWithURL:(NSURL *)url flags:(int)openFlags { 62 | return [self databaseQueueWithPath:url.path flags:openFlags]; 63 | } 64 | 65 | + (Class)databaseClass { 66 | return [FMDatabase class]; 67 | } 68 | 69 | - (instancetype)initWithURL:(NSURL *)url flags:(int)openFlags vfs:(NSString *)vfsName { 70 | return [self initWithPath:url.path flags:openFlags vfs:vfsName]; 71 | } 72 | 73 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags vfs:(NSString *)vfsName { 74 | self = [super init]; 75 | 76 | if (self != nil) { 77 | 78 | _db = [[[self class] databaseClass] databaseWithPath:aPath]; 79 | FMDBRetain(_db); 80 | 81 | #if SQLITE_VERSION_NUMBER >= 3005000 82 | BOOL success = [_db openWithFlags:openFlags vfs:vfsName]; 83 | #else 84 | BOOL success = [_db open]; 85 | #endif 86 | if (!success) { 87 | NSLog(@"Could not create database queue for path %@", aPath); 88 | FMDBRelease(self); 89 | return 0x00; 90 | } 91 | 92 | _path = FMDBReturnRetained(aPath); 93 | 94 | _queue = dispatch_queue_create([[NSString stringWithFormat:@"fmdb.%@", self] UTF8String], NULL); 95 | dispatch_queue_set_specific(_queue, kDispatchQueueSpecificKey, (__bridge void *)self, NULL); 96 | _openFlags = openFlags; 97 | _vfsName = [vfsName copy]; 98 | } 99 | 100 | return self; 101 | } 102 | 103 | - (instancetype)initWithPath:(NSString *)aPath flags:(int)openFlags { 104 | return [self initWithPath:aPath flags:openFlags vfs:nil]; 105 | } 106 | 107 | - (instancetype)initWithURL:(NSURL *)url flags:(int)openFlags { 108 | return [self initWithPath:url.path flags:openFlags vfs:nil]; 109 | } 110 | 111 | - (instancetype)initWithURL:(NSURL *)url { 112 | return [self initWithPath:url.path]; 113 | } 114 | 115 | - (instancetype)initWithPath:(NSString *)aPath { 116 | // default flags for sqlite3_open 117 | return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE vfs:nil]; 118 | } 119 | 120 | - (instancetype)init { 121 | return [self initWithPath:nil]; 122 | } 123 | 124 | 125 | - (void)dealloc { 126 | FMDBRelease(_db); 127 | FMDBRelease(_path); 128 | FMDBRelease(_vfsName); 129 | 130 | if (_queue) { 131 | FMDBDispatchQueueRelease(_queue); 132 | _queue = 0x00; 133 | } 134 | #if ! __has_feature(objc_arc) 135 | [super dealloc]; 136 | #endif 137 | } 138 | 139 | - (void)close { 140 | FMDBRetain(self); 141 | dispatch_sync(_queue, ^() { 142 | [self->_db close]; 143 | FMDBRelease(_db); 144 | self->_db = 0x00; 145 | }); 146 | FMDBRelease(self); 147 | } 148 | 149 | - (void)interrupt { 150 | [[self database] interrupt]; 151 | } 152 | 153 | - (FMDatabase*)database { 154 | if (!_db) { 155 | _db = FMDBReturnRetained([[[self class] databaseClass] databaseWithPath:_path]); 156 | 157 | #if SQLITE_VERSION_NUMBER >= 3005000 158 | BOOL success = [_db openWithFlags:_openFlags vfs:_vfsName]; 159 | #else 160 | BOOL success = [_db open]; 161 | #endif 162 | if (!success) { 163 | NSLog(@"FMDatabaseQueue could not reopen database for path %@", _path); 164 | FMDBRelease(_db); 165 | _db = 0x00; 166 | return 0x00; 167 | } 168 | } 169 | 170 | return _db; 171 | } 172 | 173 | - (void)inDatabase:(void (^)(FMDatabase *db))block { 174 | #ifndef NDEBUG 175 | /* Get the currently executing queue (which should probably be nil, but in theory could be another DB queue 176 | * and then check it against self to make sure we're not about to deadlock. */ 177 | FMDatabaseQueue *currentSyncQueue = (__bridge id)dispatch_get_specific(kDispatchQueueSpecificKey); 178 | assert(currentSyncQueue != self && "inDatabase: was called reentrantly on the same queue, which would lead to a deadlock"); 179 | #endif 180 | 181 | FMDBRetain(self); 182 | 183 | dispatch_sync(_queue, ^() { 184 | 185 | FMDatabase *db = [self database]; 186 | block(db); 187 | 188 | if ([db hasOpenResultSets]) { 189 | NSLog(@"Warning: there is at least one open result set around after performing [FMDatabaseQueue inDatabase:]"); 190 | 191 | #if defined(DEBUG) && DEBUG 192 | NSSet *openSetCopy = FMDBReturnAutoreleased([[db valueForKey:@"_openResultSets"] copy]); 193 | for (NSValue *rsInWrappedInATastyValueMeal in openSetCopy) { 194 | FMResultSet *rs = (FMResultSet *)[rsInWrappedInATastyValueMeal pointerValue]; 195 | NSLog(@"query: '%@'", [rs query]); 196 | } 197 | #endif 198 | } 199 | }); 200 | 201 | FMDBRelease(self); 202 | } 203 | 204 | - (void)beginTransaction:(BOOL)useDeferred withBlock:(void (^)(FMDatabase *db, BOOL *rollback))block { 205 | FMDBRetain(self); 206 | dispatch_sync(_queue, ^() { 207 | 208 | BOOL shouldRollback = NO; 209 | 210 | if (useDeferred) { 211 | [[self database] beginDeferredTransaction]; 212 | } 213 | else { 214 | [[self database] beginTransaction]; 215 | } 216 | 217 | block([self database], &shouldRollback); 218 | 219 | if (shouldRollback) { 220 | [[self database] rollback]; 221 | } 222 | else { 223 | [[self database] commit]; 224 | } 225 | }); 226 | 227 | FMDBRelease(self); 228 | } 229 | 230 | - (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block { 231 | [self beginTransaction:YES withBlock:block]; 232 | } 233 | 234 | - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block { 235 | [self beginTransaction:NO withBlock:block]; 236 | } 237 | 238 | - (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block { 239 | #if SQLITE_VERSION_NUMBER >= 3007000 240 | static unsigned long savePointIdx = 0; 241 | __block NSError *err = 0x00; 242 | FMDBRetain(self); 243 | dispatch_sync(_queue, ^() { 244 | 245 | NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++]; 246 | 247 | BOOL shouldRollback = NO; 248 | 249 | if ([[self database] startSavePointWithName:name error:&err]) { 250 | 251 | block([self database], &shouldRollback); 252 | 253 | if (shouldRollback) { 254 | // We need to rollback and release this savepoint to remove it 255 | [[self database] rollbackToSavePointWithName:name error:&err]; 256 | } 257 | [[self database] releaseSavePointWithName:name error:&err]; 258 | 259 | } 260 | }); 261 | FMDBRelease(self); 262 | return err; 263 | #else 264 | NSString *errorMessage = NSLocalizedString(@"Save point functions require SQLite 3.7", nil); 265 | if (self.logsErrors) NSLog(@"%@", errorMessage); 266 | return [NSError errorWithDomain:@"FMDatabase" code:0 userInfo:@{NSLocalizedDescriptionKey : errorMessage}]; 267 | #endif 268 | } 269 | 270 | @end 271 | -------------------------------------------------------------------------------- /Pods/FMDB/src/fmdb/FMResultSet.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | NS_ASSUME_NONNULL_BEGIN 4 | 5 | #ifndef __has_feature // Optional. 6 | #define __has_feature(x) 0 // Compatibility with non-clang compilers. 7 | #endif 8 | 9 | #ifndef NS_RETURNS_NOT_RETAINED 10 | #if __has_feature(attribute_ns_returns_not_retained) 11 | #define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained)) 12 | #else 13 | #define NS_RETURNS_NOT_RETAINED 14 | #endif 15 | #endif 16 | 17 | @class FMDatabase; 18 | @class FMStatement; 19 | 20 | /** Represents the results of executing a query on an ``. 21 | 22 | ### See also 23 | 24 | - `` 25 | */ 26 | 27 | @interface FMResultSet : NSObject 28 | 29 | @property (nonatomic, retain, nullable) FMDatabase *parentDB; 30 | 31 | ///----------------- 32 | /// @name Properties 33 | ///----------------- 34 | 35 | /** Executed query */ 36 | 37 | @property (atomic, retain, nullable) NSString *query; 38 | 39 | /** `NSMutableDictionary` mapping column names to numeric index */ 40 | 41 | @property (readonly) NSMutableDictionary *columnNameToIndexMap; 42 | 43 | /** `FMStatement` used by result set. */ 44 | 45 | @property (atomic, retain, nullable) FMStatement *statement; 46 | 47 | ///------------------------------------ 48 | /// @name Creating and closing database 49 | ///------------------------------------ 50 | 51 | /** Create result set from `` 52 | 53 | @param statement A `` to be performed 54 | 55 | @param aDB A `` to be used 56 | 57 | @return A `FMResultSet` on success; `nil` on failure 58 | */ 59 | 60 | + (instancetype)resultSetWithStatement:(FMStatement *)statement usingParentDatabase:(FMDatabase*)aDB; 61 | 62 | /** Close result set */ 63 | 64 | - (void)close; 65 | 66 | ///--------------------------------------- 67 | /// @name Iterating through the result set 68 | ///--------------------------------------- 69 | 70 | /** Retrieve next row for result set. 71 | 72 | You must always invoke `next` or `nextWithError` before attempting to access the values returned in a query, even if you're only expecting one. 73 | 74 | @return `YES` if row successfully retrieved; `NO` if end of result set reached 75 | 76 | @see hasAnotherRow 77 | */ 78 | 79 | - (BOOL)next; 80 | 81 | /** Retrieve next row for result set. 82 | 83 | You must always invoke `next` or `nextWithError` before attempting to access the values returned in a query, even if you're only expecting one. 84 | 85 | @param outErr A 'NSError' object to receive any error object (if any). 86 | 87 | @return 'YES' if row successfully retrieved; 'NO' if end of result set reached 88 | 89 | @see hasAnotherRow 90 | */ 91 | 92 | - (BOOL)nextWithError:(NSError * _Nullable *)outErr; 93 | 94 | /** Did the last call to `` succeed in retrieving another row? 95 | 96 | @return `YES` if the last call to `` succeeded in retrieving another record; `NO` if not. 97 | 98 | @see next 99 | 100 | @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. 101 | */ 102 | 103 | - (BOOL)hasAnotherRow; 104 | 105 | ///--------------------------------------------- 106 | /// @name Retrieving information from result set 107 | ///--------------------------------------------- 108 | 109 | /** How many columns in result set 110 | 111 | @return Integer value of the number of columns. 112 | */ 113 | 114 | @property (nonatomic, readonly) int columnCount; 115 | 116 | /** Column index for column name 117 | 118 | @param columnName `NSString` value of the name of the column. 119 | 120 | @return Zero-based index for column. 121 | */ 122 | 123 | - (int)columnIndexForName:(NSString*)columnName; 124 | 125 | /** Column name for column index 126 | 127 | @param columnIdx Zero-based index for column. 128 | 129 | @return columnName `NSString` value of the name of the column. 130 | */ 131 | 132 | - (NSString * _Nullable)columnNameForIndex:(int)columnIdx; 133 | 134 | /** Result set integer value for column. 135 | 136 | @param columnName `NSString` value of the name of the column. 137 | 138 | @return `int` value of the result set's column. 139 | */ 140 | 141 | - (int)intForColumn:(NSString*)columnName; 142 | 143 | /** Result set integer value for column. 144 | 145 | @param columnIdx Zero-based index for column. 146 | 147 | @return `int` value of the result set's column. 148 | */ 149 | 150 | - (int)intForColumnIndex:(int)columnIdx; 151 | 152 | /** Result set `long` value for column. 153 | 154 | @param columnName `NSString` value of the name of the column. 155 | 156 | @return `long` value of the result set's column. 157 | */ 158 | 159 | - (long)longForColumn:(NSString*)columnName; 160 | 161 | /** Result set long value for column. 162 | 163 | @param columnIdx Zero-based index for column. 164 | 165 | @return `long` value of the result set's column. 166 | */ 167 | 168 | - (long)longForColumnIndex:(int)columnIdx; 169 | 170 | /** Result set `long long int` value for column. 171 | 172 | @param columnName `NSString` value of the name of the column. 173 | 174 | @return `long long int` value of the result set's column. 175 | */ 176 | 177 | - (long long int)longLongIntForColumn:(NSString*)columnName; 178 | 179 | /** Result set `long long int` value for column. 180 | 181 | @param columnIdx Zero-based index for column. 182 | 183 | @return `long long int` value of the result set's column. 184 | */ 185 | 186 | - (long long int)longLongIntForColumnIndex:(int)columnIdx; 187 | 188 | /** Result set `unsigned long long int` value for column. 189 | 190 | @param columnName `NSString` value of the name of the column. 191 | 192 | @return `unsigned long long int` value of the result set's column. 193 | */ 194 | 195 | - (unsigned long long int)unsignedLongLongIntForColumn:(NSString*)columnName; 196 | 197 | /** Result set `unsigned long long int` value for column. 198 | 199 | @param columnIdx Zero-based index for column. 200 | 201 | @return `unsigned long long int` value of the result set's column. 202 | */ 203 | 204 | - (unsigned long long int)unsignedLongLongIntForColumnIndex:(int)columnIdx; 205 | 206 | /** Result set `BOOL` value for column. 207 | 208 | @param columnName `NSString` value of the name of the column. 209 | 210 | @return `BOOL` value of the result set's column. 211 | */ 212 | 213 | - (BOOL)boolForColumn:(NSString*)columnName; 214 | 215 | /** Result set `BOOL` value for column. 216 | 217 | @param columnIdx Zero-based index for column. 218 | 219 | @return `BOOL` value of the result set's column. 220 | */ 221 | 222 | - (BOOL)boolForColumnIndex:(int)columnIdx; 223 | 224 | /** Result set `double` value for column. 225 | 226 | @param columnName `NSString` value of the name of the column. 227 | 228 | @return `double` value of the result set's column. 229 | 230 | */ 231 | 232 | - (double)doubleForColumn:(NSString*)columnName; 233 | 234 | /** Result set `double` value for column. 235 | 236 | @param columnIdx Zero-based index for column. 237 | 238 | @return `double` value of the result set's column. 239 | 240 | */ 241 | 242 | - (double)doubleForColumnIndex:(int)columnIdx; 243 | 244 | /** Result set `NSString` value for column. 245 | 246 | @param columnName `NSString` value of the name of the column. 247 | 248 | @return String value of the result set's column. 249 | 250 | */ 251 | 252 | - (NSString * _Nullable)stringForColumn:(NSString*)columnName; 253 | 254 | /** Result set `NSString` value for column. 255 | 256 | @param columnIdx Zero-based index for column. 257 | 258 | @return String value of the result set's column. 259 | */ 260 | 261 | - (NSString * _Nullable)stringForColumnIndex:(int)columnIdx; 262 | 263 | /** Result set `NSDate` value for column. 264 | 265 | @param columnName `NSString` value of the name of the column. 266 | 267 | @return Date value of the result set's column. 268 | */ 269 | 270 | - (NSDate * _Nullable)dateForColumn:(NSString*)columnName; 271 | 272 | /** Result set `NSDate` value for column. 273 | 274 | @param columnIdx Zero-based index for column. 275 | 276 | @return Date value of the result set's column. 277 | 278 | */ 279 | 280 | - (NSDate * _Nullable)dateForColumnIndex:(int)columnIdx; 281 | 282 | /** Result set `NSData` value for column. 283 | 284 | This is useful when storing binary data in table (such as image or the like). 285 | 286 | @param columnName `NSString` value of the name of the column. 287 | 288 | @return Data value of the result set's column. 289 | 290 | */ 291 | 292 | - (NSData * _Nullable)dataForColumn:(NSString*)columnName; 293 | 294 | /** Result set `NSData` value for column. 295 | 296 | @param columnIdx Zero-based index for column. 297 | 298 | @return Data value of the result set's column. 299 | */ 300 | 301 | - (NSData * _Nullable)dataForColumnIndex:(int)columnIdx; 302 | 303 | /** Result set `(const unsigned char *)` value for column. 304 | 305 | @param columnName `NSString` value of the name of the column. 306 | 307 | @return `(const unsigned char *)` value of the result set's column. 308 | */ 309 | 310 | - (const unsigned char * _Nullable)UTF8StringForColumn:(NSString*)columnName; 311 | 312 | - (const unsigned char * _Nullable)UTF8StringForColumnName:(NSString*)columnName __deprecated_msg("Use UTF8StringForColumn instead"); 313 | 314 | /** Result set `(const unsigned char *)` value for column. 315 | 316 | @param columnIdx Zero-based index for column. 317 | 318 | @return `(const unsigned char *)` value of the result set's column. 319 | */ 320 | 321 | - (const unsigned char * _Nullable)UTF8StringForColumnIndex:(int)columnIdx; 322 | 323 | /** Result set object for column. 324 | 325 | @param columnName Name of the column. 326 | 327 | @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object. 328 | 329 | @see objectForKeyedSubscript: 330 | */ 331 | 332 | - (id _Nullable)objectForColumn:(NSString*)columnName; 333 | 334 | - (id _Nullable)objectForColumnName:(NSString*)columnName __deprecated_msg("Use objectForColumn instead"); 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 _Nullable)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 _Nullable)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 _Nullable)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 Data 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 * _Nullable)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 Data 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 * _Nullable)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 | @warning The keys to the dictionary are case sensitive of the column names. 439 | */ 440 | 441 | @property (nonatomic, readonly, nullable) NSDictionary *resultDictionary; 442 | 443 | /** Returns a dictionary of the row results 444 | 445 | @see resultDictionary 446 | 447 | @warning **Deprecated**: Please use `` instead. Also, beware that `` is case sensitive! 448 | */ 449 | 450 | - (NSDictionary * _Nullable)resultDict __deprecated_msg("Use resultDictionary instead"); 451 | 452 | ///----------------------------- 453 | /// @name Key value coding magic 454 | ///----------------------------- 455 | 456 | /** Performs `setValue` to yield support for key value observing. 457 | 458 | @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. 459 | 460 | */ 461 | 462 | - (void)kvcMagic:(id)object; 463 | 464 | 465 | @end 466 | 467 | NS_ASSUME_NONNULL_END 468 | -------------------------------------------------------------------------------- /Pods/Headers/Private/FMDB/FMDB.h: -------------------------------------------------------------------------------- 1 | ../../../FMDB/src/fmdb/FMDB.h -------------------------------------------------------------------------------- /Pods/Headers/Private/FMDB/FMDatabase.h: -------------------------------------------------------------------------------- 1 | ../../../FMDB/src/fmdb/FMDatabase.h -------------------------------------------------------------------------------- /Pods/Headers/Private/FMDB/FMDatabaseAdditions.h: -------------------------------------------------------------------------------- 1 | ../../../FMDB/src/fmdb/FMDatabaseAdditions.h -------------------------------------------------------------------------------- /Pods/Headers/Private/FMDB/FMDatabasePool.h: -------------------------------------------------------------------------------- 1 | ../../../FMDB/src/fmdb/FMDatabasePool.h -------------------------------------------------------------------------------- /Pods/Headers/Private/FMDB/FMDatabaseQueue.h: -------------------------------------------------------------------------------- 1 | ../../../FMDB/src/fmdb/FMDatabaseQueue.h -------------------------------------------------------------------------------- /Pods/Headers/Private/FMDB/FMResultSet.h: -------------------------------------------------------------------------------- 1 | ../../../FMDB/src/fmdb/FMResultSet.h -------------------------------------------------------------------------------- /Pods/Headers/Public/FMDB/FMDB.h: -------------------------------------------------------------------------------- 1 | ../../../FMDB/src/fmdb/FMDB.h -------------------------------------------------------------------------------- /Pods/Headers/Public/FMDB/FMDatabase.h: -------------------------------------------------------------------------------- 1 | ../../../FMDB/src/fmdb/FMDatabase.h -------------------------------------------------------------------------------- /Pods/Headers/Public/FMDB/FMDatabaseAdditions.h: -------------------------------------------------------------------------------- 1 | ../../../FMDB/src/fmdb/FMDatabaseAdditions.h -------------------------------------------------------------------------------- /Pods/Headers/Public/FMDB/FMDatabasePool.h: -------------------------------------------------------------------------------- 1 | ../../../FMDB/src/fmdb/FMDatabasePool.h -------------------------------------------------------------------------------- /Pods/Headers/Public/FMDB/FMDatabaseQueue.h: -------------------------------------------------------------------------------- 1 | ../../../FMDB/src/fmdb/FMDatabaseQueue.h -------------------------------------------------------------------------------- /Pods/Headers/Public/FMDB/FMResultSet.h: -------------------------------------------------------------------------------- 1 | ../../../FMDB/src/fmdb/FMResultSet.h -------------------------------------------------------------------------------- /Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - FMDB (2.7.2): 3 | - FMDB/standard (= 2.7.2) 4 | - FMDB/standard (2.7.2) 5 | 6 | DEPENDENCIES: 7 | - FMDB 8 | 9 | SPEC CHECKSUMS: 10 | FMDB: 6198a90e7b6900cfc046e6bc0ef6ebb7be9236aa 11 | 12 | PODFILE CHECKSUM: 9c16a6a1d4092ed054958aeda0b786149e335341 13 | 14 | COCOAPODS: 1.3.1 15 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/Tony.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 | 66 | 67 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/Tony.xcuserdatad/xcschemes/Pods-TODBModel.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 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/Tony.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | FMDB.xcscheme 8 | 9 | isShown 10 | 11 | 12 | Pods-TODBModel.xcscheme 13 | 14 | isShown 15 | 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Pods/Target Support Files/FMDB/FMDB-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_FMDB : NSObject 3 | @end 4 | @implementation PodsDummy_FMDB 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/FMDB/FMDB-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /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/Private/FMDB" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/FMDB" 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 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/FMDB 9 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 10 | SKIP_INSTALL = YES 11 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-TODBModel/Pods-TODBModel-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 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-TODBModel/Pods-TODBModel-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 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-TODBModel/Pods-TODBModel-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_TODBModel : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_TODBModel 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-TODBModel/Pods-TODBModel-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 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 10 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 11 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 12 | 13 | install_framework() 14 | { 15 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 16 | local source="${BUILT_PRODUCTS_DIR}/$1" 17 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 18 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 19 | elif [ -r "$1" ]; then 20 | local source="$1" 21 | fi 22 | 23 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 24 | 25 | if [ -L "${source}" ]; then 26 | echo "Symlinked..." 27 | source="$(readlink "${source}")" 28 | fi 29 | 30 | # Use filter instead of exclude so missing patterns don't throw errors. 31 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 32 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 33 | 34 | local basename 35 | basename="$(basename -s .framework "$1")" 36 | binary="${destination}/${basename}.framework/${basename}" 37 | if ! [ -r "$binary" ]; then 38 | binary="${destination}/${basename}" 39 | fi 40 | 41 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 42 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 43 | strip_invalid_archs "$binary" 44 | fi 45 | 46 | # Resign the code if required by the build settings to avoid unstable apps 47 | code_sign_if_enabled "${destination}/$(basename "$1")" 48 | 49 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 50 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 51 | local swift_runtime_libs 52 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) 53 | for lib in $swift_runtime_libs; do 54 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 55 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 56 | code_sign_if_enabled "${destination}/${lib}" 57 | done 58 | fi 59 | } 60 | 61 | # Copies the dSYM of a vendored framework 62 | install_dsym() { 63 | local source="$1" 64 | if [ -r "$source" ]; then 65 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DWARF_DSYM_FOLDER_PATH}\"" 66 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DWARF_DSYM_FOLDER_PATH}" 67 | fi 68 | } 69 | 70 | # Signs a framework with the provided identity 71 | code_sign_if_enabled() { 72 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 73 | # Use the current code_sign_identitiy 74 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 75 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements '$1'" 76 | 77 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 78 | code_sign_cmd="$code_sign_cmd &" 79 | fi 80 | echo "$code_sign_cmd" 81 | eval "$code_sign_cmd" 82 | fi 83 | } 84 | 85 | # Strip invalid architectures 86 | strip_invalid_archs() { 87 | binary="$1" 88 | # Get architectures for current file 89 | archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" 90 | stripped="" 91 | for arch in $archs; do 92 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then 93 | # Strip non-valid architectures in-place 94 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1 95 | stripped="$stripped $arch" 96 | fi 97 | done 98 | if [[ "$stripped" ]]; then 99 | echo "Stripped $binary of architectures:$stripped" 100 | fi 101 | } 102 | 103 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 104 | wait 105 | fi 106 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-TODBModel/Pods-TODBModel-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 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 12 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 13 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 14 | 15 | case "${TARGETED_DEVICE_FAMILY}" in 16 | 1,2) 17 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 18 | ;; 19 | 1) 20 | TARGET_DEVICE_ARGS="--target-device iphone" 21 | ;; 22 | 2) 23 | TARGET_DEVICE_ARGS="--target-device ipad" 24 | ;; 25 | 3) 26 | TARGET_DEVICE_ARGS="--target-device tv" 27 | ;; 28 | 4) 29 | TARGET_DEVICE_ARGS="--target-device watch" 30 | ;; 31 | *) 32 | TARGET_DEVICE_ARGS="--target-device mac" 33 | ;; 34 | esac 35 | 36 | install_resource() 37 | { 38 | if [[ "$1" = /* ]] ; then 39 | RESOURCE_PATH="$1" 40 | else 41 | RESOURCE_PATH="${PODS_ROOT}/$1" 42 | fi 43 | if [[ ! -e "$RESOURCE_PATH" ]] ; then 44 | cat << EOM 45 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. 46 | EOM 47 | exit 1 48 | fi 49 | case $RESOURCE_PATH in 50 | *.storyboard) 51 | 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}" || true 52 | 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} 53 | ;; 54 | *.xib) 55 | 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}" || true 56 | 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} 57 | ;; 58 | *.framework) 59 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 60 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 61 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 62 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 63 | ;; 64 | *.xcdatamodel) 65 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true 66 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" 67 | ;; 68 | *.xcdatamodeld) 69 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true 70 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" 71 | ;; 72 | *.xcmappingmodel) 73 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true 74 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" 75 | ;; 76 | *.xcassets) 77 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" 78 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 79 | ;; 80 | *) 81 | echo "$RESOURCE_PATH" || true 82 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" 83 | ;; 84 | esac 85 | } 86 | 87 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 88 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 89 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then 90 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 91 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 92 | fi 93 | rm -f "$RESOURCES_TO_COPY" 94 | 95 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] 96 | then 97 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 98 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 99 | while read line; do 100 | if [[ $line != "${PODS_ROOT}*" ]]; then 101 | XCASSET_FILES+=("$line") 102 | fi 103 | done <<<"$OTHER_XCASSETS" 104 | 105 | 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}" 106 | fi 107 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-TODBModel/Pods-TODBModel.debug.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/FMDB" 3 | LIBRARY_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/FMDB" 4 | OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/FMDB" 5 | OTHER_LDFLAGS = $(inherited) -ObjC -l"FMDB" -l"sqlite3" 6 | PODS_BUILD_DIR = $BUILD_DIR 7 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-TODBModel/Pods-TODBModel.release.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/FMDB" 3 | LIBRARY_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/FMDB" 4 | OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/FMDB" 5 | OTHER_LDFLAGS = $(inherited) -ObjC -l"FMDB" -l"sqlite3" 6 | PODS_BUILD_DIR = $BUILD_DIR 7 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TODBModel 2 | 3 | [![CocoaPods](https://img.shields.io/cocoapods/v/TODBModel.svg?style=flat)](http://cocoapods.org/?q=name%3ATODBModel) 4 | [![CocoaPods](https://img.shields.io/cocoapods/p/TODBModel.svg?style=flat)](https://github.com/TonyJR/TODBModel) 5 | [![CocoaPods](https://img.shields.io/cocoapods/at/TODBModel.svg?style=flat)](http://cocoapods.org/?q=name%3ATODBModel) 6 | [![CocoaPods](https://img.shields.io/cocoapods/dt/TODBModel.svg?style=flat)](https://github.com/TonyJR/TODBModel) 7 | [![CocoaPods](https://img.shields.io/cocoapods/l/TODBModel.svg?style=flat)](https://github.com/TonyJR/TODBModel/blob/master/LICENSE) 8 | 9 | ============== 10 | 11 | 12 | TODBModel是基于FMDB开发的数据库模型系统,它把数据库操作完全融入模型中。该类的任何子类将自动创建并维护数据库,无需懂得任何SQL语法及概念即可进行数据库操作。支持字符串、整型、浮点型、NSData、NSDate、UIImage、NSArray、NSDictionary存储。 13 | 14 | 模型缓存+数据库异步读写,创建1000条数据仅需0.02秒。 15 | 16 | 关于对“事物”的支持问题,我考虑了很久,最终还是放弃了。并不是技术上无法实现。TODBModel并不是数据库的延伸,而是一种数据存储方案,这种方案是提供给那些希望简单的存储数据的场景的,我会尽量屏蔽数据库的概念简化操作流程,让使用者感觉在操作面向对象的model,而不是更加抽象的数据表。 17 | 18 | 在使用TODBModel时,大多数情况下用户都是在操作内存模型。模型的增删改功能也是同步操作内存模型的动作,数据库操作是在模型操作完成后异步完成的(将操作动作转换为SQL语句,等待队列执行),因此用户并不需要担心因为多线程操作导致的数据错误或者执行顺序与预期不符的情况。 19 | 20 | ![image](https://github.com/TonyJR/TODBModel/blob/master/1.gif) 21 | 22 | 快速集成 23 | ------------ 24 | 推荐使用cocoapod安装 25 | ```ruby 26 | pod 'TODBModel' 27 | ``` 28 | 如何使用 29 | ------------ 30 | 1、创建一个对象,继承TODBModel。 31 | 32 | 33 | 2、为对象添加属性 34 | ```objc 35 | // AddressModel.h 36 | 37 | #import "TODBModel.h" 38 | 39 | @interface AddressModel : NSObject 40 | 41 | @property (nonatomic,strong) NSString *name; 42 | @property (nonatomic,assign) int addressID; 43 | @property (nonatomic,strong) NSDate *editDate; 44 | @property (nonatomic,strong) NSString *mobile; 45 | @property (nonatomic,strong) NSString *address; 46 | 47 | @end 48 | ``` 49 | 50 | 3、覆盖+ (NSString *)db_pk方法,并返回主键对应的属性。 51 | ```objc 52 | // AddressModel.m 53 | 54 | #import "AddressModel.h" 55 | 56 | @implementation AddressModel 57 | 58 | + (void)initialize{ 59 |   //在数据库中注册数据表 60 | [self regiestDB]; 61 | } 62 | 63 | + (NSString *)db_pk{ 64 | return @"addressID"; 65 | } 66 | 67 | @end 68 | ``` 69 | 4、增删改 70 | ```objc 71 | //创建 72 | AddressModel *model = [AddressModel crateModel]; 73 | //保存 74 | [model save:^(TODBModel *model) { 75 | //保存成功 76 | }] 77 | //删除 78 | [model del:^(TODBModel *model) { 79 | //删除成功 80 | }] 81 | ``` 82 | 5、查询 83 | ```objc 84 | //查询全部 85 | [AddressModel allModels:^(NSArray *models) { 86 | //获取成功 87 | }]; 88 | //搜索name中或者mobile中包含“123”的数据 89 | TODBCondition *condition1 = [TODBCondition condition:@"name" like:@"%123%"]; 90 | TODBCondition *condition2 = [TODBCondition condition:@"mobile" like:@"%123%"]; 91 | [AddressModel search:[TODBOrCondition conditionWith:condition1 or:condition2] callBack:^(NSArray *models) { 92 | //搜索完成 93 | }]; 94 | ``` 95 | 6、内存索引 96 | ``` 97 | + (nonnull instancetype)modelByKey:(nonnull id)modelKey; 98 | + (nullable instancetype)modelByKey:(nonnull id)modelKey allowNull:(BOOL)allowNull; 99 | ``` 100 | 上面两个方法会现在内存中搜索以key为主键的model,如果内存中不存在,则在数据库中搜索,如果数据库中也不存在则根据allowNull参数决定是否创建空model 101 | [TestModel modelByKey:@"key"] 等价于 [TestModel modelByKey:@"key" allowNull:NO] 102 | 103 | 由于使用了内存索引,所以不建议通过new或alloc方法来创建model,创建model的方法有三种。 104 | 105 | + 前面介绍的 106 | ``` 107 | [TestModel modelByKey:@"key" allowNull:YES]; 108 | ``` 109 | 可以在检查搜索后创建指定主键的model 110 | + 使用自增长主键,创建单个模型。当需要创建多个模型时,crateModel效率并不高,建议使用crateModels 111 | 112 | ``` 113 | TestModel *model = [TestModel crateModel]; 114 | ``` 115 | + 使用自增长主键,批量创建模型。 116 | ``` 117 | NSArray *models = [TestModel crateModels:100]; 118 | ``` 119 | 120 | 121 | Swift 122 | ------------ 123 | 在Swift中,非指针对象(Int,Float,Double,Boolean等)请不要使用“?”、“!”修饰属性。否则可能导致该字段无法插入数据库 124 | ```swift 125 | // AddressModel.swift 126 | 127 | import UIKit 128 | import TODBModel 129 | 130 | class AddressModel: TODBModel { 131 | var name: String = ""; 132 | var addressID: Int = 0; 133 | var age: Float = 0; 134 | 135 | var editDate: NSDate!; 136 | var mobile: String!; 137 | var address: String!; 138 | 139 | public static override func db_pk() -> String{ 140 | return "addressID"; 141 | } 142 | } 143 | ``` 144 | 特别说明 145 | ------------ 146 | TOBDModel的设计基于内存+外存两部分,id相同的model在内存中只会存在一个。您可以在多个controller中持有同一个model,使用KVO或者RAC方便的同步数据。 147 | + 详见内存索引部分 148 | 149 | 更新日志 150 | ------------ 151 | version 1.3.1 152 | ``` 153 | 0、修复iOS 12的一个崩溃问题 154 | ``` 155 | 156 | version 1.3.0 157 | ``` 158 | 0、增加分页功能 159 | ``` 160 | 161 | version 1.2.2 162 | ``` 163 | 0、当模型属性中包含未创建数据表的自定义对象时,直接把对象序列化存储为BLOB列中。该对象会检测是否支持NSCoding协议,如果未支持则会自动实现协议。 164 | 1、修复了一个FMDB中的一个bug——释放FMResultSet对象时使用的线程与查询时不同,导致插入操作如果过于频繁可能导致崩溃。 165 | ``` 166 | 167 | version 1.2.1 168 | ``` 169 | 0、修复了一个模型嵌套时无法保存的问题。 170 | ``` 171 | 172 | version 1.2.0 173 | ``` 174 | 0、当N个模型分别update时,现在会自动合并sql处理,大幅提高了写入速度。 175 | 1、分离了数据表读取和生成模型的线程,提高了并发处理时的读取速度。 176 | 2、对模型属性进行缓存,现在每1万条记录读取速度小于1秒(iphone6测试0.83秒) 177 | ``` 178 | 179 | version 1.0.0 180 | ``` 181 | 0、移除了TODBModel类,现在任何NSObject的子类都可以直接存入数据库 182 | 1、新增了更新表结构的方法,现在不再自动更新表结构了,而是需要手动更新 183 | ``` 184 | 185 | version 0.3 186 | ``` 187 | 0、兼容swift 188 | 1、修复了使用runtime时的内存回收问题 189 | ``` 190 | version 0.2 191 | ``` 192 | 0、完善了DEMO 193 | 1、新增删除 194 | 2、新增查询功能,包括模糊查询、复合条件查询 195 | 3、新增批量添加功能 196 | 4、添加对部分有较高延迟的指令的异步执行方法 197 | 5、优化了性能,修复了已知bug 198 | ``` 199 | version 0.1.1 200 | ``` 201 | 0、增加数据删除功能 202 | 1、修复一个初始化阶段导致死循环的bug 203 | ``` 204 | version 0.1 205 | ``` 206 | 0、自动创建、维护模型对应的数据库。启动时检测模型变化,如属性发生变更则自动更新数据表。 207 | 1、支持NSString、NSDate、NSData、CGFloat、NSInteger、float、double等基本类型。 208 | 2、支持任何实现了NSCoding接口的对象。 209 | 3、特别优化了TODBModel的子类作为属性的支持。 210 | ``` 211 | -------------------------------------------------------------------------------- /TODBModel.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod spec lint TODBModel.podspec' to ensure this is a 3 | # valid spec and to remove all comments including this before submitting the spec. 4 | # 5 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html 6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/ 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | 11 | s.name = "TODBModel" 12 | s.version = "1.3.1" 13 | s.summary = "A thread-safe ORM, base on sqlite and FMDB." 14 | 15 | s.description = <<-DESC 16 | TODBModel是基于FMDB开发的数据库模型系统,它把数据库操作完全融入模型中。该类的任何子类将自动创建并维护数据库,无需懂得任何SQL语法及概念即可进行数据库操作。 17 | DESC 18 | 19 | s.homepage = "https://github.com/TonyJR/TODBModel.git" 20 | # s.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif" 21 | s.license = { :type => 'MIT', :file => 'LICENSE' } 22 | s.author = { "Tony.JR" => "show_3@163.com" } 23 | s.platform = :ios, "7.0" 24 | s.source = { :git => "https://github.com/TonyJR/TODBModel.git", :tag => "#{s.version}" } 25 | s.requires_arc = true 26 | s.source_files = 'TODBModel/*.{h,m}' 27 | s.frameworks = 'Foundation' 28 | s.dependency 'FMDB' 29 | 30 | 31 | end 32 | 33 | 34 | -------------------------------------------------------------------------------- /TODBModel.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /TODBModel.xcodeproj/project.xcworkspace/xcuserdata/Tony.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyJR/TODBModel/8356d2e091d10d172968fe062f2a7a5ce7a04943/TODBModel.xcodeproj/project.xcworkspace/xcuserdata/Tony.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /TODBModel.xcodeproj/xcuserdata/Tony.xcuserdatad/xcschemes/TOModelDemo.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 | -------------------------------------------------------------------------------- /TODBModel.xcodeproj/xcuserdata/Tony.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | TOModelDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | EAC1FEA11DE4353B00555898 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /TODBModel.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /TODBModel.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /TODBModel.xcworkspace/xcuserdata/Tony.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyJR/TODBModel/8356d2e091d10d172968fe062f2a7a5ce7a04943/TODBModel.xcworkspace/xcuserdata/Tony.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /TODBModel.xcworkspace/xcuserdata/Tony.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /TODBModel/FMResultSet+Release.h: -------------------------------------------------------------------------------- 1 | // 2 | // FMResultSet+Release.h 3 | // TODBModel 4 | // 5 | // Created by TonyJR on 2018/10/10. 6 | // Copyright © 2018年 Tony. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface FMResultSet (release) 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /TODBModel/FMResultSet+Release.m: -------------------------------------------------------------------------------- 1 | // 2 | // FMResultSet+Release.m 3 | // TODBModel 4 | // 5 | // Created by TonyJR on 2018/10/10. 6 | // Copyright © 2018年 Tony. All rights reserved. 7 | // 8 | 9 | #import "FMResultSet+Release.h" 10 | 11 | 12 | -------------------------------------------------------------------------------- /TODBModel/NSArray+CheckPointer.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+CheckPointer.h 3 | // TODBModel 4 | // 5 | // Created by TonyJR on 2018/10/13. 6 | // Copyright © 2018年 Tony. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface NSArray (checkPointer) 14 | 15 | - (void)checkPointer; 16 | 17 | @end 18 | 19 | NS_ASSUME_NONNULL_END 20 | -------------------------------------------------------------------------------- /TODBModel/NSArray+CheckPointer.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+CheckPointer.m 3 | // TODBModel 4 | // 5 | // Created by TonyJR on 2018/10/13. 6 | // Copyright © 2018年 Tony. All rights reserved. 7 | // 8 | 9 | #import "NSArray+CheckPointer.h" 10 | #import "NSObject+TODBModel.h" 11 | #import "NSObject+Cache.h" 12 | #import "TODBPointer.h" 13 | #import "TODBPointerChecker.h" 14 | #import "TODBPointerHelper.h" 15 | 16 | #define sql_check_point_label "to_db_model.check_point" 17 | 18 | @interface NSObject () 19 | 20 | - (void)db_checkPointer:(void(^)(TODBPointerChecker *checker))block; 21 | 22 | @end 23 | 24 | 25 | 26 | 27 | @implementation NSArray (checkPointer) 28 | 29 | - (void)checkPointer{ 30 | 31 | 32 | __block NSMutableDictionary *pointerDic = [NSMutableDictionary dictionary]; 33 | for (NSObject *obj in self) { 34 | [obj db_checkPointer:^(TODBPointerChecker *checker) { 35 | [TODBPointerHelper addChecker:checker data:pointerDic]; 36 | }]; 37 | } 38 | if (pointerDic.allKeys.count == 0) { 39 | return; 40 | } 41 | 42 | for (NSString *className in pointerDic.allKeys) { 43 | NSDictionary *> *dic = [TODBPointerHelper groupByID:[pointerDic objectForKey:className]]; 44 | Class class = NSClassFromString(className); 45 | NSDictionary *keyValues = [class modelsByKeys:[dic allKeys]]; 46 | for (NSString *key in dic.allKeys) { 47 | NSSet *checkers = [dic objectForKey:key]; 48 | id value = [keyValues objectForKey:key]; 49 | 50 | for (TODBPointerChecker *checker in checkers) { 51 | [checker.target db_setValue:value forKey:checker.key]; 52 | } 53 | } 54 | } 55 | } 56 | 57 | 58 | 59 | 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /TODBModel/NSObject+Cache.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+Cache.h 3 | // TODBModel 4 | // 5 | // Created by Tony on 2017/8/30. 6 | // Copyright © 2017年 Tony. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** 12 | This category will help you to search model from memory or database. 13 | */ 14 | @interface NSObject (Cache) 15 | 16 | 17 | /** 18 | You can find/create a model with this method. 19 | 1.If a model with same Primary Key in memory. The method will update and return it. 20 | 2.If a model with same Primary Key in database. The method will create a model form database. Update the model and return it. 21 | 3.Otherwise, the method will create a empty model. Update the model and return it. 22 | 23 | @param dic rarams which will update to model 24 | @return result of TODBModel 25 | */ 26 | + (nonnull instancetype)modelByDic:(nonnull NSDictionary *)dic; 27 | 28 | 29 | /** 30 | Search your memory, find a model with Primary Key. 31 | 32 | @param modelKey Primary Key 33 | @return result 34 | */ 35 | + (nullable instancetype)memoryByKey:(nonnull id)modelKey; 36 | 37 | + (NSDictionary *)modelsByKeys:(NSArray *)modelKeys; 38 | 39 | /** 40 | Search memory/database and return the model with same Primary Key. 41 | If find any model, return create a model with Primary Key in memory and return it. 42 | 43 | @param modelKey Primary Key 44 | @return result 45 | */ 46 | + (nonnull instancetype)modelByKey:(nonnull id)modelKey; 47 | 48 | 49 | /** 50 | Refer to -modelByKey: . If allowNull is NO, same to -modelByKey:. 51 | Otherwise may return nil. 52 | 53 | @param modelKey Primary Key 54 | @param allowNull allows nil return 55 | @return result 56 | */ 57 | + (nullable instancetype)modelByKey:(nonnull id)modelKey allowNull:(BOOL)allowNull; 58 | 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /TODBModel/NSObject+Cache.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+Cache.m 3 | // TODBModel 4 | // 5 | // Created by Tony on 2017/8/30. 6 | // Copyright © 2017年 Tony. All rights reserved. 7 | // 8 | 9 | #import "NSObject+Cache.h" 10 | #import "NSObject+TODBModel.h" 11 | #import "NSArray+CheckPointer.h" 12 | 13 | @implementation NSObject (Cache) 14 | 15 | static NSMapTable * cache; 16 | 17 | + (void)load{ 18 | static dispatch_once_t onceToken; 19 | dispatch_once(&onceToken, ^{ 20 | cache = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsCopyIn valueOptions:NSPointerFunctionsWeakMemory]; 21 | }); 22 | } 23 | 24 | #pragma mark - Public 25 | + (id)modelByDic:(NSDictionary *)dic{ 26 | NSString *pkValue = dic[[self db_pk]]; 27 | 28 | NSObject *model = [cache objectForKey:[NSString stringWithFormat:@"%@_%@",NSStringFromClass(self),pkValue]]; 29 | 30 | if (!model) { 31 | model = [[self alloc] init]; 32 | } 33 | 34 | 35 | for (NSString *key in dic.allKeys) { 36 | [model db_setValue:dic[key] forKey:key]; 37 | } 38 | return model; 39 | } 40 | 41 | 42 | + (instancetype)memoryByKey:(id)modelKey{ 43 | id result = [cache objectForKey:[NSString stringWithFormat:@"%@_%@",NSStringFromClass(self),modelKey]]; 44 | return result; 45 | } 46 | //获取模型 47 | + (instancetype)modelByKey:(id)modelKey{ 48 | return [self modelByKey:modelKey allowNull:NO]; 49 | } 50 | 51 | //获取模型 52 | + (instancetype)modelByKey:(id)modelKey allowNull:(BOOL)allowNull{ 53 | if (!modelKey) { 54 | if (allowNull) { 55 | return nil; 56 | }else{ 57 | return [[self alloc] init]; 58 | } 59 | } 60 | 61 | id result = [cache objectForKey:[NSString stringWithFormat:@"%@_%@",NSStringFromClass(self),modelKey]]; 62 | if (!result) { 63 | result = [[self db_search:modelKey forKey:[self db_pk]] lastObject]; 64 | } 65 | if ((!allowNull) && (!result)) { 66 | result = [[self alloc] init]; 67 | 68 | [result db_setValue:modelKey forKey:[self db_pk]]; 69 | } 70 | 71 | return result; 72 | } 73 | 74 | + (NSDictionary *)modelsByKeys:(NSArray *)modelKeys{ 75 | if (!modelKeys || [modelKeys count] == 0) { 76 | return @{}; 77 | } 78 | NSMutableDictionary *result = [NSMutableDictionary dictionary]; 79 | NSMutableArray *searchKeys = [NSMutableArray array]; 80 | for (NSString *modelKey in modelKeys) { 81 | id cachedModel = [cache objectForKey:[NSString stringWithFormat:@"%@_%@",NSStringFromClass(self),modelKey]]; 82 | if (cachedModel) { 83 | [result setObject:cachedModel forKey:modelKey]; 84 | }else{ 85 | [searchKeys addObject:modelKey]; 86 | } 87 | } 88 | 89 | NSDictionary *searchedModel = [self db_searchValues:searchKeys forKey:[self db_pk]]; 90 | NSMutableArray *modesNeedCheck = [NSMutableArray array]; 91 | for (NSString *key in searchedModel.allKeys) { 92 | NSArray *values = [searchedModel objectForKey:key]; 93 | id obj = [values lastObject]; 94 | if (obj) { 95 | [result setObject:obj forKey:key]; 96 | [modesNeedCheck addObject:obj]; 97 | } 98 | } 99 | [modesNeedCheck checkPointer]; 100 | return [result copy]; 101 | } 102 | 103 | + (void)saveModelByKey:(id)modelKey model:(NSObject *)model{ 104 | if (modelKey) { 105 | [cache setObject:model forKey:[NSString stringWithFormat:@"%@_%@",NSStringFromClass(self),modelKey]]; 106 | } 107 | } 108 | 109 | @end 110 | -------------------------------------------------------------------------------- /TODBModel/NSObject+NSCoding.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+NSCoding.h 3 | // TODBModel 4 | // 5 | // Created by TonyJR on 2018/10/10. 6 | // Copyright © 2018年 Tony. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface NSObject (NSCoding) 14 | 15 | + (void)db_registNSCoding; 16 | 17 | 18 | 19 | @end 20 | 21 | NS_ASSUME_NONNULL_END 22 | -------------------------------------------------------------------------------- /TODBModel/NSObject+NSCoding.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+NSCoding.m 3 | // TODBModel 4 | // 5 | // Created by TonyJR on 2018/10/10. 6 | // Copyright © 2018年 Tony. All rights reserved. 7 | // 8 | 9 | #import "NSObject+NSCoding.h" 10 | #import 11 | #import "NSObject+TODBModel.h" 12 | 13 | @interface NSObject() 14 | 15 | + (NSDictionary *)classPropertys; 16 | 17 | @end 18 | 19 | @implementation NSObject (NSCoding) 20 | 21 | + (void)db_registNSCoding{ 22 | Class currentClass = [self class]; 23 | 24 | if (currentClass != [NSObject class]) { 25 | if (!class_getInstanceMethod(currentClass, @selector(initWithCoder:))){ 26 | //创建 initWithCoder: 27 | [self addMethod:@selector(initWithCoder:) from:@selector(db_initWithCoder:)]; 28 | //创建 encodeWithCoder: 29 | [self addMethod:@selector(encodeWithCoder:) from:@selector(db_encodeWithCoder:)]; 30 | 31 | //对子属性实现 NSCoding 32 | NSDictionary *classPropertys = [self classPropertys]; 33 | for (NSString *value in classPropertys.allValues) { 34 | NSString *regex = @"^@\"[a-zA-Z_0-9]+\"$"; 35 | NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex]; 36 | 37 | if ([predicate evaluateWithObject:value]) { 38 | NSString *className = [value substringWithRange:NSMakeRange(2, value.length - 3)]; 39 | Class typeClass = NSClassFromString(className); 40 | if (typeClass) { 41 | [typeClass db_registNSCoding]; 42 | } 43 | } 44 | } 45 | } 46 | } 47 | } 48 | 49 | + (void)addMethod:(SEL)selector from:(SEL)source{ 50 | Class currentClass = [self class]; 51 | 52 | Method m = class_getInstanceMethod(currentClass, source); 53 | const char *type = method_getTypeEncoding(m); 54 | IMP imp = method_getImplementation(m); 55 | class_addMethod(currentClass, selector, imp, type); 56 | } 57 | 58 | - (instancetype)db_initWithCoder:(NSCoder *)coder 59 | { 60 | id result = [self init]; 61 | if (result) { 62 | for (NSString *key in [[self class] classPropertys].allKeys) { 63 | id value = [coder decodeObjectForKey:key]; 64 | [self db_setValue:value forKey:key]; 65 | } 66 | } 67 | return result; 68 | } 69 | 70 | - (void)db_encodeWithCoder:(NSCoder *)aCoder{ 71 | for (NSString *key in [[self class] classPropertys].allKeys) { 72 | id value = [self valueForKey:key]; 73 | if (value) { 74 | [aCoder encodeObject:value forKey:key]; 75 | } 76 | } 77 | } 78 | 79 | @end 80 | -------------------------------------------------------------------------------- /TODBModel/NSObject+Property.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+Property.h 3 | // TODBModel 4 | // 5 | // Created by TonyJR on 2018/10/11. 6 | // Copyright © 2018年 Tony. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | #define TODBSearchCallback void(^)(NSArray *result) 14 | #define TODBSearchCallback_(v) void(^v)(NSArray *result) 15 | 16 | @interface NSObject (Property) 17 | 18 | @property (nonatomic,assign) NSUInteger pk; 19 | 20 | + (NSMutableString *)db_sqlUpdateStr; 21 | + (NSMutableArray *)db_sqlUpdateObjs; 22 | 23 | + (void)addSearch:(NSString *)value forKey:(NSString *)key callback:(TODBSearchCallback)callback; 24 | + (void)searchKey:(NSString *)key make:(nonnull NSDictionary *(^)(NSArray *))block; 25 | 26 | @end 27 | 28 | NS_ASSUME_NONNULL_END 29 | -------------------------------------------------------------------------------- /TODBModel/NSObject+Property.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+Property.m 3 | // TODBModel 4 | // 5 | // Created by TonyJR on 2018/10/11. 6 | // Copyright © 2018年 Tony. All rights reserved. 7 | // 8 | 9 | #import "NSObject+Property.h" 10 | #import 11 | 12 | 13 | 14 | @interface NSObject () 15 | 16 | + (NSMutableDictionary *> *> *)db_sqlSearchObjs; 17 | 18 | @end 19 | 20 | @implementation NSObject (Property) 21 | 22 | 23 | - (NSUInteger)pk{ 24 | return [objc_getAssociatedObject(self, @"NSObject_pk") unsignedIntegerValue]; 25 | } 26 | 27 | - (void)setPk:(NSUInteger)pk{ 28 | objc_setAssociatedObject(self, @"NSObject_pk", [NSNumber numberWithUnsignedInteger:pk], OBJC_ASSOCIATION_RETAIN); 29 | } 30 | 31 | + (NSMutableString *)db_sqlUpdateStr{ 32 | static NSMutableDictionary *sqlClassDic; 33 | static NSLock *lock; 34 | static dispatch_once_t onceToken; 35 | dispatch_once(&onceToken, ^{ 36 | sqlClassDic = [NSMutableDictionary dictionary]; 37 | lock = [NSLock new]; 38 | }); 39 | 40 | [lock lock]; 41 | NSMutableString *sqlStr = [sqlClassDic objectForKey:NSStringFromClass(self)]; 42 | if (!sqlStr) { 43 | sqlStr = [NSMutableString string]; 44 | [sqlClassDic setObject:sqlStr forKey:NSStringFromClass(self)]; 45 | } 46 | [lock unlock]; 47 | return sqlStr; 48 | } 49 | 50 | + (NSMutableArray *)db_sqlUpdateObjs{ 51 | static NSMutableDictionary *sqlClassDic; 52 | static dispatch_once_t onceToken; 53 | dispatch_once(&onceToken, ^{ 54 | sqlClassDic = [NSMutableDictionary dictionary]; 55 | }); 56 | 57 | NSMutableArray *sqlObjs = [sqlClassDic objectForKey:NSStringFromClass(self)]; 58 | if (!sqlObjs) { 59 | sqlObjs = [NSMutableArray array]; 60 | [sqlClassDic setObject:sqlObjs forKey:NSStringFromClass(self)]; 61 | } 62 | return sqlObjs; 63 | } 64 | 65 | + (NSMutableDictionary *> *)db_sqlSearchObjs{ 66 | static NSMutableDictionary *sqlClassDic; 67 | static dispatch_once_t onceToken; 68 | dispatch_once(&onceToken, ^{ 69 | sqlClassDic = [NSMutableDictionary dictionary]; 70 | }); 71 | 72 | NSMutableDictionary *sqlObjs = [sqlClassDic objectForKey:NSStringFromClass(self)]; 73 | if (!sqlObjs) { 74 | sqlObjs = [NSMutableDictionary dictionary]; 75 | [sqlClassDic setObject:sqlObjs forKey:NSStringFromClass(self)]; 76 | } 77 | return sqlObjs; 78 | } 79 | 80 | + (NSMutableDictionary *)db_sqlSearchValueForKey:(NSString *)key{ 81 | NSMutableDictionary *result = [[self db_sqlSearchObjs] objectForKey:key]; 82 | if (!result) { 83 | result = [NSMutableDictionary dictionary]; 84 | [[self db_sqlSearchObjs] setObject:result forKey:key]; 85 | } 86 | return result; 87 | } 88 | 89 | + (NSMutableSet *)db_sqlSearchCallbacksForKey:(NSString *)key value:(NSString *)value{ 90 | NSMutableDictionary *dic = [self db_sqlSearchValueForKey:key]; 91 | NSMutableSet *callbacks = [dic objectForKey:value]; 92 | if (!callbacks) { 93 | callbacks = [NSMutableSet new]; 94 | [dic setObject:callbacks forKey:value]; 95 | } 96 | return callbacks; 97 | } 98 | 99 | + (NSLock *)searchLock{ 100 | static NSLock *_searchLock; 101 | static dispatch_once_t onceToken; 102 | dispatch_once(&onceToken, ^{ 103 | _searchLock = [NSLock new]; 104 | }); 105 | return _searchLock; 106 | } 107 | 108 | + (void)clearSearchForKey:(NSString *)key{ 109 | [[self db_sqlSearchObjs] removeObjectForKey:key]; 110 | } 111 | 112 | + (void)addSearch:(NSString *)value forKey:(NSString *)key callback:(TODBSearchCallback)callback{ 113 | // [[self searchLock] lock]; 114 | NSMutableSet *callbacks = [self db_sqlSearchCallbacksForKey:key value:value]; 115 | [callbacks addObject:callback]; 116 | // [[self searchLock] unlock]; 117 | } 118 | 119 | + (void)searchKey:(NSString *)key make:(nonnull NSDictionary *(^)(NSArray *))block{ 120 | // [[self searchLock] lock]; 121 | NSMutableDictionary *> *searchObj = [[self db_sqlSearchObjs] objectForKey:key]; 122 | 123 | NSArray *values; 124 | if (searchObj) { 125 | [[self db_sqlSearchObjs] removeObjectForKey:key]; 126 | values = [searchObj allKeys]; 127 | } 128 | 129 | // [[self searchLock] unlock]; 130 | if (block && values) { 131 | NSDictionary *searchResults = block(values); 132 | for (NSString *value in values) { 133 | for (TODBSearchCallback_(callback) in [searchObj objectForKey:value]) { 134 | callback([searchResults objectForKey:value]); 135 | } 136 | } 137 | } 138 | } 139 | 140 | @end 141 | -------------------------------------------------------------------------------- /TODBModel/NSObject+Search.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+Search.h 3 | // TODBModel 4 | // 5 | // Created by Tony on 2017/8/30. 6 | // Copyright © 2017年 Tony. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "TODBCondition.h" 11 | 12 | @interface NSObject (Search) 13 | 14 | /** 15 | Find all models in database synchronously. 16 | 17 | @return all models. 18 | */ 19 | + (NSArray *)allModels; 20 | 21 | 22 | /** 23 | Find all models in database asynchronously. 24 | 25 | @param block finish callback. 26 | */ 27 | + (void)allModels:(void(^)(NSArray *models))block; 28 | 29 | + (void)removeAll:(void(^)(void))block; 30 | 31 | /** 32 | Search models in database by condition synchronously. 33 | 34 | @param condition search condition 35 | @return search result 36 | */ 37 | + (NSArray *)search:(id)condition; 38 | 39 | /** 40 | Search models in database by condition asynchronously. 41 | 42 | @param condition search condition 43 | @param block finish callback. 44 | */ 45 | + (void)search:(id)condition callBack:(void(^)(NSArray *models))block; 46 | 47 | /** 48 | Search models in database by SQL synchronously. 49 | 50 | @param sqlString search SQL 51 | @return search result 52 | */ 53 | + (NSArray *)searchSQL:(NSString *)sqlString; 54 | 55 | /** 56 | Search models in database by SQL asynchronously. 57 | 58 | @param sqlString search SQL 59 | @param block finish callback. 60 | */ 61 | + (void)searchSQL:(NSString *)sqlString callBack:(void(^)(NSArray *models))block; 62 | + (void)getNumberOfModels:(NSInteger)count callback:(void(^)(NSArray *models))block; 63 | 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /TODBModel/NSObject+Search.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+Search.m 3 | // TODBModel 4 | // 5 | // Created by Tony on 2017/8/30. 6 | // Copyright © 2017年 Tony. All rights reserved. 7 | // 8 | 9 | #import "NSObject+Search.h" 10 | #import "NSObject+TODBModel.h" 11 | #import 12 | 13 | 14 | 15 | @implementation NSObject (Search) 16 | 17 | + (NSLock *)searchLock{ 18 | static NSLock *lock; 19 | if (!lock) { 20 | lock = [[NSLock alloc] init]; 21 | } 22 | 23 | return lock; 24 | } 25 | 26 | + (NSArray *)allModels{ 27 | [[self searchLock] lock]; 28 | NSArray *result = [self db_search:[NSString stringWithFormat:@"SELECT * FROM %@" ,[self db_name]]]; 29 | [[self searchLock] unlock]; 30 | 31 | return result; 32 | } 33 | + (void)allModels:(void(^)(NSArray *models))block{ 34 | 35 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 36 | [[self searchLock] lock]; 37 | 38 | __block NSArray *result = [self db_search:[NSString stringWithFormat:@"SELECT * FROM %@" ,[self db_name]]]; 39 | 40 | 41 | [[self searchLock] unlock]; 42 | 43 | if (block) { 44 | dispatch_async(dispatch_get_main_queue(), ^{ 45 | block(result); 46 | }); 47 | } 48 | }); 49 | } 50 | 51 | + (void)getNumberOfModels:(NSInteger)count callback:(void(^)(NSArray *models))block{ 52 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 53 | [[self searchLock] lock]; 54 | 55 | __block NSArray *result = [self db_search:[NSString stringWithFormat:@"SELECT * FROM %@ LIMIT %ld" ,[self db_name],(long)count]]; 56 | 57 | 58 | [[self searchLock] unlock]; 59 | 60 | if (block) { 61 | dispatch_async(dispatch_get_main_queue(), ^{ 62 | block(result); 63 | }); 64 | } 65 | }); 66 | } 67 | 68 | + (void)modelsForRange:(NSRange)range callback:(void(^)(NSArray *models))block{ 69 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 70 | [[self searchLock] lock]; 71 | 72 | __block NSArray *result = [self db_search:[NSString stringWithFormat:@"SELECT * FROM %@ LIMIT %ld OFFSET %ld" ,[self db_name],(long)range.length,(long)range.location]]; 73 | 74 | 75 | [[self searchLock] unlock]; 76 | 77 | if (block) { 78 | dispatch_async(dispatch_get_main_queue(), ^{ 79 | block(result); 80 | }); 81 | } 82 | }); 83 | } 84 | 85 | 86 | + (void)removeAll:(void(^)(void))block{ 87 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 88 | [self db_dropTable]; 89 | [self regiestDB]; 90 | if (block) { 91 | dispatch_async(dispatch_get_main_queue(), ^{ 92 | block(); 93 | }); 94 | } 95 | }); 96 | } 97 | 98 | + (NSArray *)search:(id)condition{ 99 | [[self searchLock] lock]; 100 | 101 | NSArray *result = [self db_condition_search:condition]; 102 | 103 | [[self searchLock] unlock]; 104 | return result; 105 | } 106 | 107 | + (void)search:(id)condition callBack:(void(^)(NSArray *models))block{ 108 | 109 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 110 | [[self searchLock] lock]; 111 | 112 | __block NSArray *result = [self db_condition_search:condition]; 113 | [[self searchLock] unlock]; 114 | 115 | if (block) { 116 | dispatch_async(dispatch_get_main_queue(), ^{ 117 | block(result); 118 | }); 119 | } 120 | 121 | 122 | }); 123 | } 124 | 125 | + (NSArray *)searchSQL:(NSString *)sqlString{ 126 | [[self searchLock] lock]; 127 | 128 | NSArray *result = [self db_search:sqlString]; 129 | [[self searchLock] unlock]; 130 | return result; 131 | } 132 | 133 | + (void)searchSQL:(NSString *)sqlString callBack:(void(^)(NSArray *models))block{ 134 | 135 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 136 | [[self searchLock] lock]; 137 | 138 | __block NSArray *result = [self db_search:sqlString]; 139 | 140 | [[self searchLock] unlock]; 141 | 142 | if (block) { 143 | dispatch_async(dispatch_get_main_queue(), ^{ 144 | block(result); 145 | }); 146 | } 147 | }); 148 | } 149 | 150 | @end 151 | -------------------------------------------------------------------------------- /TODBModel/NSObject+TODBModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+TODBModel.h 3 | // TODBModel 4 | // 5 | // Created by Tony on 2017/8/30. 6 | // Copyright © 2017年 Tony. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "TODataBase.h" 11 | 12 | @interface NSObject (RegiestDB) 13 | 14 | @property (nonatomic,assign) NSUInteger pk; 15 | 16 | 17 | /** 18 | Did existed table in database 19 | */ 20 | + (BOOL)existDB; 21 | 22 | /** 23 | Create or update table for this class. 24 | */ 25 | + (void)regiestDB; 26 | 27 | /** 28 | Create a new model. 29 | */ 30 | + (id)crateModel; 31 | 32 | /** 33 | Create a number of models synchronously. 34 | 35 | @param count create number. 36 | @return created models. 37 | */ 38 | + (NSArray *)crateModels:(NSUInteger)count; 39 | 40 | /** 41 | Create a number of models asynchronously. 42 | 43 | @param count create number. 44 | @return created models. 45 | */ 46 | + (void)crateModels:(NSUInteger)count callback:(void(^)(NSArray *models,NSError *error))block; 47 | 48 | /** 49 | Save a model to database synchronously. 50 | */ 51 | - (void)save; 52 | 53 | /** 54 | Save a model to database asynchronously. 55 | 56 | @param block finish callback. 57 | */ 58 | - (void)save:(void(^)(NSObject *model))block; 59 | 60 | /** 61 | Delete a model from database synchronously. 62 | */ 63 | - (void)del; 64 | 65 | /** 66 | Delete a model from database synchronously. 67 | 68 | @param block finish callback. 69 | */ 70 | - (void)del:(void(^)(NSObject *model))block; 71 | 72 | - (void)db_setValue:(id)value forKey:(NSString *)key; 73 | 74 | 75 | @end 76 | -------------------------------------------------------------------------------- /TODBModel/TODBAndCondition.h: -------------------------------------------------------------------------------- 1 | // 2 | // TODBAndCondition.h 3 | // TODBModel 4 | // 5 | // Created by Tony on 17/2/6. 6 | // Copyright © 2017年 Tony. All rights reserved. 7 | // 8 | 9 | #import "TODBCondition.h" 10 | 11 | @interface TODBAndCondition: NSObject 12 | 13 | @property (nonatomic,strong) id condition1; 14 | @property (nonatomic,strong) id condition2; 15 | 16 | - (instancetype)initConditionWith:(id)condition1 and:(id)condition2; 17 | 18 | + (instancetype)conditionWith:(id)condition1 and:(id)condition2; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /TODBModel/TODBAndCondition.m: -------------------------------------------------------------------------------- 1 | // 2 | // TODBAndCondition.m 3 | // TODBModel 4 | // 5 | // Created by Tony on 17/2/6. 6 | // Copyright © 2017年 Tony. All rights reserved. 7 | // 8 | 9 | #import "TODBAndCondition.h" 10 | 11 | @implementation TODBAndCondition 12 | 13 | - (instancetype)initConditionWith:(id)condition1 and:(id)condition2 14 | { 15 | self = [self init]; 16 | if (self) { 17 | self.condition1 = condition1; 18 | self.condition2 = condition2; 19 | } 20 | return self; 21 | } 22 | 23 | + (instancetype)conditionWith:(id)condition1 and:(id)condition2 24 | { 25 | return [[self alloc] initConditionWith:condition1 and:condition2]; 26 | } 27 | 28 | - (NSString *)conditionWithPropertys:(NSDictionary *)propertys 29 | { 30 | return [NSString stringWithFormat:@"(%@) AND (%@)",[self.condition1 conditionWithPropertys:propertys],[self.condition2 conditionWithPropertys:propertys]]; 31 | } 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /TODBModel/TODBCondition.h: -------------------------------------------------------------------------------- 1 | // 2 | // TODBCondition.h 3 | // TODBModel 4 | // 5 | // Created by Tony on 17/2/3. 6 | // Copyright © 2017年 Tony. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @protocol TODBConditionBase 13 | 14 | @required 15 | - (NSString *)conditionWithPropertys:(NSDictionary *)propertys; 16 | 17 | @end 18 | 19 | 20 | 21 | 22 | @interface TODBCondition: NSObject 23 | 24 | @property (nonatomic,copy) NSString *key; 25 | @property (nonatomic,copy) id value; 26 | @property (nonatomic,copy) NSString *relationship; 27 | 28 | 29 | + (TODBCondition *)condition:(NSString *)key equalTo:(id)value; 30 | + (TODBCondition *)condition:(NSString *)key like:(NSString *)value; 31 | 32 | 33 | + (TODBCondition *)condition:(NSString *)key greaterThan:(id)value; 34 | + (TODBCondition *)condition:(NSString *)key greaterOrEqualThan:(id)value; 35 | + (TODBCondition *)condition:(NSString *)key lessThan:(id)value; 36 | + (TODBCondition *)condition:(NSString *)key lessOrEqualThan:(id)value; 37 | 38 | 39 | 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /TODBModel/TODBCondition.m: -------------------------------------------------------------------------------- 1 | // 2 | // TODBCondition.m 3 | // TODBModel 4 | // 5 | // Created by Tony on 17/2/3. 6 | // Copyright © 2017年 Tony. All rights reserved. 7 | // 8 | 9 | #import "TODBCondition.h" 10 | #import "TODataTypeHelper.h" 11 | 12 | @implementation TODBCondition 13 | 14 | - (id)initWithKey:(NSString *)key value:(id)value relationship:(NSString *)relationship{ 15 | self = [super init]; 16 | if (self) { 17 | self.key = key; 18 | self.value = value; 19 | self.relationship = relationship; 20 | } 21 | return self; 22 | } 23 | 24 | 25 | + (TODBCondition *)condition:(NSString *)key equalTo:(id)value{ 26 | return [[self alloc] initWithKey:key value:value relationship:@"="]; 27 | } 28 | + (TODBCondition *)condition:(NSString *)key like:(NSString *)value{ 29 | return [[self alloc] initWithKey:key value:value relationship:@"like"]; 30 | } 31 | 32 | 33 | + (TODBCondition *)condition:(NSString *)key greaterThan:(id)value{ 34 | return [[self alloc] initWithKey:key value:value relationship:@">"]; 35 | } 36 | + (TODBCondition *)condition:(NSString *)key greaterOrEqualThan:(id)value{ 37 | return [[self alloc] initWithKey:key value:value relationship:@">="]; 38 | } 39 | + (TODBCondition *)condition:(NSString *)key lessThan:(id)value{ 40 | return [[self alloc] initWithKey:key value:value relationship:@"<"]; 41 | } 42 | + (TODBCondition *)condition:(NSString *)key lessOrEqualThan:(id)value{ 43 | return [[self alloc] initWithKey:key value:value relationship:@"<="]; 44 | } 45 | 46 | #pragma mark - 47 | - (NSString *)conditionWithPropertys:(NSDictionary *)propertys{ 48 | NSString *valueStr = [TODataTypeHelper objcObjectToSqlObject:self.value withType:propertys[self.key] arguments:nil]; 49 | return [NSString stringWithFormat:@"%@ %@ %@",self.key,self.relationship,valueStr]; 50 | } 51 | @end 52 | -------------------------------------------------------------------------------- /TODBModel/TODBModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // TODBModel.h 3 | // TODBModel 4 | // 5 | // Created by Tony on 16/11/22. 6 | // Copyright © 2016年 Tony. All rights reserved. 7 | // 8 | 9 | #ifndef TODBModel_h 10 | #define TODBModel_h 11 | #import 12 | 13 | 14 | 15 | #import "TODataBase.h" 16 | #import "TODBCondition.h" 17 | #import "TODBAndCondition.h" 18 | #import "TODBOrCondition.h" 19 | #import "TODBNotCondition.h" 20 | 21 | #import "NSObject+TODBModel.h" 22 | #import "NSObject+Cache.h" 23 | #import "NSObject+Search.h" 24 | #endif /* TODBModel_h */ 25 | -------------------------------------------------------------------------------- /TODBModel/TODBModelConfig.h: -------------------------------------------------------------------------------- 1 | // 2 | // TODBModelConfig.h 3 | // TODBModel 4 | // 5 | // Created by Tony on 16/11/22. 6 | // Copyright © 2016年 Tony. All rights reserved. 7 | // 8 | 9 | #ifndef TODBModelConfig_h 10 | #define TODBModelConfig_h 11 | 12 | #define TO_MODEL_DEBUG 1 13 | 14 | #define TO_MODEL_DATABASE_PATH [[NSString alloc] initWithString:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@"TOModel.db"]] 15 | 16 | #define TO_MODEL_LOG(x...) if(TO_MODEL_DEBUG){NSLog(x);} 17 | 18 | #endif /* TODBModelConfig_h */ 19 | -------------------------------------------------------------------------------- /TODBModel/TODBModelError.h: -------------------------------------------------------------------------------- 1 | // 2 | // TODBModelError.h 3 | // TODBModel 4 | // 5 | // Created by Tony on 2017/12/1. 6 | // Copyright © 2017年 Tony. All rights reserved. 7 | // 8 | 9 | 10 | 11 | #ifndef TODBModelError_h 12 | #define TODBModelError_h 13 | 14 | #import 15 | 16 | 17 | FOUNDATION_EXPORT NSErrorDomain const TODBModelError = @"TODBModelError"; 18 | 19 | typedef enum : NSUInteger { 20 | TODBModelPrivateKeyError, 21 | TODBModelIOError, 22 | } TODBModelErrorType; 23 | 24 | #endif /* TODBModelError_h */ 25 | -------------------------------------------------------------------------------- /TODBModel/TODBNotCondition.h: -------------------------------------------------------------------------------- 1 | // 2 | // TODBNotCondition.h 3 | // TODBModel 4 | // 5 | // Created by Tony on 17/2/6. 6 | // Copyright © 2017年 Tony. All rights reserved. 7 | // 8 | 9 | #import "TODBCondition.h" 10 | 11 | @interface TODBNotCondition: NSObject 12 | 13 | @property (nonatomic,strong) id condition; 14 | 15 | - (instancetype)initConditionWith:(id)condition; 16 | 17 | + (instancetype)conditionWith:(id)condition; 18 | 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /TODBModel/TODBNotCondition.m: -------------------------------------------------------------------------------- 1 | // 2 | // TODBNotCondition.m 3 | // TODBModel 4 | // 5 | // Created by Tony on 17/2/6. 6 | // Copyright © 2017年 Tony. All rights reserved. 7 | // 8 | 9 | #import "TODBNotCondition.h" 10 | 11 | @implementation TODBNotCondition 12 | 13 | - (instancetype)initConditionWith:(id)condition 14 | { 15 | self = [self init]; 16 | if (self) { 17 | self.condition = condition; 18 | } 19 | return self; 20 | } 21 | 22 | + (instancetype)conditionWith:(id)condition 23 | { 24 | return [[self alloc] initConditionWith:condition]; 25 | } 26 | 27 | - (NSString *)conditionWithPropertys:(NSDictionary *)propertys 28 | { 29 | return [NSString stringWithFormat:@"NOT (%@)",[self.condition conditionWithPropertys:propertys]]; 30 | } 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /TODBModel/TODBOrCondition.h: -------------------------------------------------------------------------------- 1 | // 2 | // TODBOrCondition.h 3 | // TODBModel 4 | // 5 | // Created by Tony on 17/2/6. 6 | // Copyright © 2017年 Tony. All rights reserved. 7 | // 8 | 9 | #import "TODBCondition.h" 10 | 11 | @interface TODBOrCondition : NSObject 12 | 13 | @property (nonatomic,strong) id condition1; 14 | @property (nonatomic,strong) id condition2; 15 | 16 | - (instancetype)initConditionWith:(id)condition1 or:(id)condition2; 17 | 18 | + (instancetype)conditionWith:(id)condition1 or:(id)condition2; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /TODBModel/TODBOrCondition.m: -------------------------------------------------------------------------------- 1 | // 2 | // TODBOrCondition.m 3 | // TODBModel 4 | // 5 | // Created by Tony on 17/2/6. 6 | // Copyright © 2017年 Tony. All rights reserved. 7 | // 8 | 9 | #import "TODBOrCondition.h" 10 | 11 | @implementation TODBOrCondition 12 | 13 | - (instancetype)initConditionWith:(id)condition1 or:(id)condition2 14 | { 15 | self = [self init]; 16 | if (self) { 17 | self.condition1 = condition1; 18 | self.condition2 = condition2; 19 | } 20 | return self; 21 | } 22 | 23 | + (instancetype)conditionWith:(id)condition1 or:(id)condition2 24 | { 25 | return [[self alloc] initConditionWith:condition1 or:condition2]; 26 | } 27 | 28 | - (NSString *)conditionWithPropertys:(NSDictionary *)propertys 29 | { 30 | return [NSString stringWithFormat:@"(%@) OR (%@)",[self.condition1 conditionWithPropertys:propertys],[self.condition2 conditionWithPropertys:propertys]]; 31 | } 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /TODBModel/TODBPointer.h: -------------------------------------------------------------------------------- 1 | // 2 | // TODBPointer.h 3 | // TODBModel 4 | // 5 | // Created by Tony on 16/11/30. 6 | // Copyright © 2016年 Tony. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TODBPointer : NSObject 12 | 13 | @property (nonatomic,copy) NSString *pkValue; 14 | @property (nonatomic,copy) NSString *className; 15 | @property (nonatomic,readonly) NSObject *model; 16 | 17 | - (instancetype)initWithModel:(NSObject *)model; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /TODBModel/TODBPointer.m: -------------------------------------------------------------------------------- 1 | // 2 | // TODBPointer.m 3 | // TODBModel 4 | // 5 | // Created by Tony on 16/11/30. 6 | // Copyright © 2016年 Tony. All rights reserved. 7 | // 8 | 9 | #import "TODBPointer.h" 10 | #import "NSObject+TODBModel.h" 11 | #import "NSObject+Cache.h" 12 | 13 | @interface TODBPointer () 14 | 15 | @end 16 | 17 | @implementation TODBPointer 18 | 19 | - (instancetype)initWithCoder:(NSCoder *)aDecoder{ 20 | self = [self init]; 21 | if (self == nil) return nil; 22 | 23 | _className = [aDecoder decodeObjectForKey:@"className"]; 24 | _pkValue = [aDecoder decodeObjectForKey:@"pkValue"]; 25 | 26 | return self; 27 | } 28 | 29 | 30 | - (void)encodeWithCoder:(NSCoder *)aCoder{ 31 | [aCoder encodeObject:_className forKey:@"className"]; 32 | [aCoder encodeObject:_pkValue forKey:@"pkValue"]; 33 | } 34 | 35 | - (instancetype)initWithModel:(NSObject *)model{ 36 | if (!model) { 37 | return nil; 38 | } 39 | 40 | self = [self init]; 41 | if (self == nil) return nil; 42 | 43 | self.className = NSStringFromClass([model class]); 44 | self.pkValue = [model valueForKey:[[model class] db_pk]]; 45 | 46 | return self; 47 | } 48 | 49 | - (NSObject *)model{ 50 | NSObject *result; 51 | 52 | if (self.className && self.className.length > 0) { 53 | Class class = NSClassFromString(self.className); 54 | 55 | result = [class modelByKey:self.pkValue allowNull:YES]; 56 | } 57 | return result; 58 | } 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /TODBModel/TODBPointerChecker.h: -------------------------------------------------------------------------------- 1 | // 2 | // TODBPointerChecker.h 3 | // TODBModel 4 | // 5 | // Created by TonyJR on 2018/10/16. 6 | // Copyright © 2018年 Tony. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "TODBPointer.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface TODBPointerChecker : NSObject 15 | 16 | @property (nonatomic,strong) NSObject *target; 17 | @property (nonatomic,copy) NSString *key; 18 | @property (nonatomic,strong) TODBPointer *pointer; 19 | 20 | + (instancetype)checkerWithPointer:(TODBPointer *)pointer target:(NSObject *)target key:(NSString *)key; 21 | 22 | @end 23 | 24 | NS_ASSUME_NONNULL_END 25 | -------------------------------------------------------------------------------- /TODBModel/TODBPointerChecker.m: -------------------------------------------------------------------------------- 1 | // 2 | // TODBPointerChecker.m 3 | // TODBModel 4 | // 5 | // Created by TonyJR on 2018/10/16. 6 | // Copyright © 2018年 Tony. All rights reserved. 7 | // 8 | 9 | #import "TODBPointerChecker.h" 10 | 11 | @implementation TODBPointerChecker 12 | 13 | + (instancetype)checkerWithPointer:(TODBPointer *)pointer target:(NSObject *)target key:(NSString *)key{ 14 | TODBPointerChecker *result = [[self alloc] init]; 15 | if (result) { 16 | result.target = target; 17 | result.key = key; 18 | result.pointer = pointer; 19 | } 20 | return result; 21 | } 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /TODBModel/TODBPointerHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // TODBPointerHelper.h 3 | // TODBModel 4 | // 5 | // Created by TonyJR on 2018/10/16. 6 | // Copyright © 2018年 Tony. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "TODBPointerChecker.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface TODBPointerHelper : NSObject 15 | 16 | + (void)addChecker:(TODBPointerChecker *)checker data:(NSMutableDictionary *> *)data; 17 | + (NSDictionary *> *)groupByID:(NSSet *)checkers; 18 | 19 | @end 20 | 21 | NS_ASSUME_NONNULL_END 22 | -------------------------------------------------------------------------------- /TODBModel/TODBPointerHelper.m: -------------------------------------------------------------------------------- 1 | // 2 | // TODBPointerHelper.m 3 | // TODBModel 4 | // 5 | // Created by TonyJR on 2018/10/16. 6 | // Copyright © 2018年 Tony. All rights reserved. 7 | // 8 | 9 | #import "TODBPointerHelper.h" 10 | 11 | @implementation TODBPointerHelper 12 | 13 | + (void)addChecker:(TODBPointerChecker *)checker data:(NSMutableDictionary *> *)data{ 14 | NSString *className = checker.pointer.className; 15 | NSMutableSet *set = [data objectForKey:className]; 16 | if (!set) { 17 | set = [NSMutableSet set]; 18 | [data setObject:set forKey:className]; 19 | } 20 | [set addObject:checker]; 21 | } 22 | 23 | + (NSDictionary *> *)groupByID:(NSSet *)checkers{ 24 | NSMutableDictionary *result = [NSMutableDictionary dictionary]; 25 | for (TODBPointerChecker *checker in checkers) { 26 | TODBPointer *pointer = checker.pointer; 27 | NSMutableSet *set = [result objectForKey:pointer.pkValue]; 28 | if (!set) { 29 | set = [NSMutableSet set]; 30 | [result setObject:set forKey:pointer.pkValue]; 31 | } 32 | [set addObject:checker]; 33 | } 34 | return result; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /TODBModel/TODataBase.h: -------------------------------------------------------------------------------- 1 | // 2 | // TODataBase.h 3 | // TODBModel 4 | // 5 | // Created by Tony on 16/11/22. 6 | // Copyright © 2016年 Tony. All rights reserved. 7 | // 8 | 9 | #ifndef TODataBase_h 10 | #define TODataBase_h 11 | 12 | 13 | #import "TODBCondition.h" 14 | 15 | @protocol TODataBase 16 | 17 | @required 18 | //检查并更新数据结构 19 | + (void)db_updateTable; 20 | //删除数据库 21 | + (BOOL)db_dropTable; 22 | 23 | //删除数据库内容 24 | - (void)db_delete; 25 | //内存数据同步到数据库 26 | - (void)db_update; 27 | //放弃内存数据,从数据库重新读取 28 | - (void)db_rollback; 29 | //删除内存与数据库内容 30 | - (void)db_destory; 31 | 32 | + (NSString *)db_pk; 33 | + (NSArray *)db_search:(NSString *)value forKey:(NSString *)key; 34 | + (NSArray *)db_search:(NSString *)sqlStr; 35 | + (NSArray *)db_condition_search:(id)condition; 36 | + (NSDictionary *)db_searchValues:(NSArray *)values forKey:(NSString *)key; 37 | 38 | 39 | @optional 40 | + (NSString *)db_name; 41 | 42 | @end 43 | 44 | #endif /* TODataBase_h */ 45 | -------------------------------------------------------------------------------- /TODBModel/TODataTypeHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // TODataTypeHelper.h 3 | // TODBModel 4 | // 5 | // Created by Tony on 16/11/28. 6 | // Copyright © 2016年 Tony. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | #ifndef objcType2SqlType 13 | 14 | #define objcType2SqlType(type) [TODataTypeHelper objcTypeToSqlType:type] 15 | 16 | #endif 17 | 18 | #define DB_TYPE_INTEGER @"INTEGER" 19 | #define DB_TYPE_REAL @"REAL" 20 | #define DB_TYPE_TEXT @"TEXT" 21 | #define DB_TYPE_BLOB @"BLOB" 22 | 23 | #define DB_NULL @"null" 24 | 25 | 26 | 27 | @interface TODataTypeHelper : NSObject 28 | 29 | /** 30 | Charge a objc-type to sqlite-type 31 | 32 | @param objcType objc-type 33 | @return sqlite-type 34 | */ 35 | + (NSString *)objcTypeToSqlType:(const char *)objcType; 36 | 37 | 38 | /** 39 | Charge a objc-object to sqlite-object 40 | 41 | 42 | @param objcObject objc-object 43 | @param type sqlite-type 44 | @param arguments arguments with bitcode 45 | @return sqlite-object 46 | */ 47 | + (NSString *)objcObjectToSqlObject:(id)objcObject withType:(NSString *)type arguments:(NSMutableArray *)arguments; 48 | 49 | 50 | /** 51 | Read a objc-object from FMResultSet 52 | 53 | @param resultSet source FMResultSet 54 | @param name reading name 55 | @param objcType objc-type 56 | @return objc-object 57 | */ 58 | + (id)readObjcObjectFrom:(FMResultSet *)resultSet name:(NSString *)name type:(NSString *)objcType; 59 | 60 | 61 | /** 62 | Copy a NSArray. Replace TODBPointer with TODBModel 63 | 64 | @param array source array 65 | @return result array 66 | */ 67 | + (NSArray *)copyArray:(NSArray *)array; 68 | 69 | /** 70 | Copy a NSDictionary. Replace TODBPointer with TODBModel 71 | 72 | @param array source dictionary 73 | @return result dictionary 74 | */ 75 | + (NSDictionary *)copyDictionary:(NSDictionary *)array; 76 | 77 | @end 78 | -------------------------------------------------------------------------------- /TODBModel/TODataTypeHelper.m: -------------------------------------------------------------------------------- 1 | // 2 | // TODataTypeHelper.m 3 | // TODBModel 4 | // 5 | // Created by Tony on 16/11/28. 6 | // Copyright © 2016年 Tony. All rights reserved. 7 | // 8 | 9 | #import "TODataTypeHelper.h" 10 | #import "TODBPointer.h" 11 | #import "NSObject+TODBModel.h" 12 | #import "TODBModelConfig.h" 13 | 14 | typedef enum : NSUInteger { 15 | TODataTypeUnknow, 16 | TODataTypeClass, 17 | TODataTypeNSString, 18 | TODataTypeNSDate, 19 | TODataTypeNSData, 20 | } TODataType; 21 | 22 | @implementation TODataTypeHelper 23 | 24 | //将objc类型转化为Sqllite对应的类型 25 | + (NSString *)objcTypeToSqlType:(const char *)objcType{ 26 | NSString *result = nil; 27 | 28 | NSString *type = [NSString stringWithUTF8String:objcType]; 29 | NSString *regex = @"^@\"[a-zA-Z_0-9]+\"$"; 30 | NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex]; 31 | if ([predicate evaluateWithObject:type]) { 32 | if ([type isEqualToString:@"@\"NSString\""]) { 33 | result = DB_TYPE_TEXT; 34 | }else if([type isEqualToString:@"@\"NSDate\""]){ 35 | result = DB_TYPE_INTEGER; 36 | }else{ 37 | result = DB_TYPE_BLOB; 38 | } 39 | }else{ 40 | char t = objcType[0]; 41 | if (t == '^') { 42 | t = objcType[1]; 43 | } 44 | 45 | switch (t) { 46 | case 'i': 47 | case 'I': 48 | result = DB_TYPE_INTEGER; 49 | break; 50 | case 'q': 51 | case 'Q': 52 | case 'd': 53 | case 'D': 54 | result = DB_TYPE_INTEGER; 55 | break; 56 | case 'f': 57 | case 'F': 58 | result = DB_TYPE_REAL; 59 | break; 60 | default: 61 | break; 62 | } 63 | } 64 | 65 | return result; 66 | } 67 | 68 | 69 | + (NSString *)objcObjectToSqlObject:(id)objcObject withType:(NSString *)type arguments:(NSMutableArray *)arguments{ 70 | 71 | NSString *result = nil; 72 | 73 | if ([type isEqualToString:DB_TYPE_BLOB]) { 74 | if ([objcObject isKindOfClass:[NSObject class]]) { 75 | if ([[objcObject class] existDB]) { 76 | objcObject = [[TODBPointer alloc] initWithModel:objcObject]; 77 | } 78 | } 79 | 80 | if (!objcObject || [objcObject isEqual:[NSNull null]]) { 81 | result = DB_NULL; 82 | }else{ 83 | result = @"?"; 84 | if (arguments) { 85 | NSData *dataOnObject = [NSKeyedArchiver archivedDataWithRootObject:objcObject]; 86 | [arguments addObject:dataOnObject]; 87 | } 88 | } 89 | }else{ 90 | if (!objcObject || [objcObject isEqual:[NSNull null]]) { 91 | result = DB_NULL; 92 | }else{ 93 | if ([type isEqualToString:DB_TYPE_TEXT]) { 94 | result = [NSString stringWithFormat:@"\"%@\"",objcObject]; 95 | 96 | }else if([objcObject isKindOfClass:[NSDate class]]){ 97 | result = [NSString stringWithFormat:@"%f",[(NSDate *)objcObject timeIntervalSince1970]]; 98 | }else{ 99 | result = [NSString stringWithFormat:@"%@",objcObject]; 100 | } 101 | } 102 | } 103 | 104 | 105 | return result; 106 | } 107 | 108 | + (void)typeFromString:(NSString *)objcType complete:(void(^)(TODataType type,Class customClass))complete{ 109 | static NSMutableDictionary *typeDic; 110 | static dispatch_once_t onceToken; 111 | dispatch_once(&onceToken, ^{ 112 | typeDic = [NSMutableDictionary dictionary]; 113 | }); 114 | 115 | if (objcType) { 116 | NSDictionary *cachedTypeDic = [typeDic objectForKey:objcType]; 117 | if (!cachedTypeDic) { 118 | NSString *regex = @"^@\"[a-zA-Z_0-9]+\"$"; 119 | NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex]; 120 | if ([predicate evaluateWithObject:objcType]) { 121 | if ([objcType isEqualToString:@"@\"NSString\""]) { 122 | cachedTypeDic = @{@"type":@(TODataTypeNSString)}; 123 | }else if ([objcType isEqualToString:@"@\"NSDate\""]) { 124 | cachedTypeDic = @{@"type":@(TODataTypeNSDate)}; 125 | 126 | }else if([objcType isEqualToString:@"@\"NSData\""]){ 127 | cachedTypeDic = @{@"type":@(TODataTypeNSData)}; 128 | }else{ 129 | NSString *className = [objcType substringWithRange:NSMakeRange(2, objcType.length - 3)]; 130 | Class class = NSClassFromString(className); 131 | cachedTypeDic = @{@"type":@(TODataTypeClass),@"class":class}; 132 | } 133 | }else{ 134 | cachedTypeDic = @{@"type":@(TODataTypeUnknow)}; 135 | } 136 | 137 | [typeDic setObject:cachedTypeDic forKey:objcType]; 138 | } 139 | 140 | 141 | if (complete) { 142 | TODataType type = [cachedTypeDic[@"type"] integerValue]; 143 | if (type == TODataTypeClass) { 144 | complete(type,cachedTypeDic[@"class"]); 145 | }else{ 146 | complete(type,nil); 147 | } 148 | } 149 | } 150 | } 151 | 152 | + (id)readObjcObjectFrom:(FMResultSet *)resultSet name:(NSString *)name type:(NSString *)objcType{ 153 | 154 | __block id result; 155 | 156 | [self typeFromString:objcType complete:^(TODataType type, __unsafe_unretained Class customClass) { 157 | switch (type) { 158 | case TODataTypeNSString: 159 | result = [resultSet stringForColumn:name]; 160 | break; 161 | case TODataTypeNSDate: 162 | { 163 | NSTimeInterval timeInterval = [resultSet doubleForColumn:name]; 164 | result = [NSDate dateWithTimeIntervalSince1970:timeInterval]; 165 | } 166 | break; 167 | case TODataTypeNSData: 168 | result = [result dataForColumn:name]; 169 | break; 170 | case TODataTypeClass: 171 | { 172 | NSData *data = [resultSet dataForColumn:name]; 173 | 174 | if ([customClass isSubclassOfClass:[NSObject class]]) { 175 | 176 | TODBPointer *pointer; 177 | @try { 178 | pointer = [NSKeyedUnarchiver unarchiveObjectWithData:data]; 179 | } 180 | @catch (NSException *exception) { 181 | } 182 | if (pointer && ![pointer isEqual:[NSNull null]]) { 183 | result = pointer; 184 | } 185 | }else{ 186 | @try { 187 | result = [NSKeyedUnarchiver unarchiveObjectWithData:data]; 188 | } 189 | @catch (NSException *exception) { 190 | TO_MODEL_LOG(@"属性解析失败.\n%@",exception); 191 | } 192 | } 193 | } 194 | break; 195 | case TODataTypeUnknow: 196 | result = @([resultSet doubleForColumn:name]); 197 | break; 198 | default: 199 | break; 200 | } 201 | }]; 202 | 203 | return result; 204 | } 205 | 206 | + (NSArray *)copyArray:(NSArray *)array{ 207 | NSMutableArray *result = [NSMutableArray arrayWithArray:array]; 208 | 209 | for (NSUInteger i=0; i 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /TODBModelDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // TODBModel 4 | // 5 | // Created by Tony on 16/11/22. 6 | // Copyright © 2016年 Tony. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "DemoListTableViewController.h" 11 | 12 | @interface AppDelegate () 13 | 14 | @end 15 | 16 | @implementation AppDelegate 17 | 18 | 19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 20 | 21 | // Override point for customization after application launch. 22 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 23 | self.window.backgroundColor = [UIColor whiteColor]; 24 | self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:[[DemoListTableViewController alloc] init]]; 25 | [self.window makeKeyAndVisible]; 26 | 27 | return YES; 28 | } 29 | 30 | - (void)applicationWillResignActive:(UIApplication *)application { 31 | // 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. 32 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 33 | } 34 | 35 | - (void)applicationDidEnterBackground:(UIApplication *)application { 36 | // 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. 37 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 38 | } 39 | 40 | - (void)applicationWillEnterForeground:(UIApplication *)application { 41 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 42 | } 43 | 44 | - (void)applicationDidBecomeActive:(UIApplication *)application { 45 | // 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. 46 | } 47 | 48 | - (void)applicationWillTerminate:(UIApplication *)application { 49 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 50 | } 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /TODBModelDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "size" : "1024x1024", 46 | "scale" : "1x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } -------------------------------------------------------------------------------- /TODBModelDemo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /TODBModelDemo/Assets.xcassets/user.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "user@3x.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /TODBModelDemo/Assets.xcassets/user.imageset/user@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyJR/TODBModel/8356d2e091d10d172968fe062f2a7a5ce7a04943/TODBModelDemo/Assets.xcassets/user.imageset/user@3x.png -------------------------------------------------------------------------------- /TODBModelDemo/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 | -------------------------------------------------------------------------------- /TODBModelDemo/CreateAddressHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // CreateAddressHelper.h 3 | // TODBModel 4 | // 5 | // Created by TonyJR on 2018/10/8. 6 | // Copyright © 2018年 Tony. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AddressModel.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface CreateAddressHelper : NSObject 15 | 16 | + (NSArray *)createAddress:(NSUInteger)count complete:(nullable void(^)(NSTimeInterval costTime))complete; 17 | 18 | @end 19 | 20 | NS_ASSUME_NONNULL_END 21 | -------------------------------------------------------------------------------- /TODBModelDemo/CreateAddressHelper.m: -------------------------------------------------------------------------------- 1 | // 2 | // CreateAddressHelper.m 3 | // TODBModel 4 | // 5 | // Created by TonyJR on 2018/10/8. 6 | // Copyright © 2018年 Tony. All rights reserved. 7 | // 8 | 9 | #import "CreateAddressHelper.h" 10 | 11 | #define MOBILE_HEAD @[@"130",@"131",@"132",@"133",@"134",@"135",@"136",@"137",@"138",@"139"]; 12 | #define SURNAME @[@"赵",@"钱",@"孙",@"李",@"周",@"吴",@"郑",@"王",@"冯",@"陈",@"楮",@"蒋",@"沈",@"韩",@"杨",@"朱",@"秦",@"尤",@"许",@"何",@"吕",@"施",@"张",@"孔",@"曹",@"严",@"华",@"卫"]; 13 | #define CN_NUM @[@"零",@"一",@"二",@"三",@"四",@"五",@"六",@"七",@"八",@"九"]; 14 | 15 | @implementation CreateAddressHelper 16 | 17 | + (NSArray *)createAddress:(NSUInteger)count complete:(void (^)(NSTimeInterval))complete 18 | { 19 | NSDate *startDate = [NSDate date]; 20 | NSDate *date = startDate; 21 | 22 | NSArray *createdModels = [AddressModel crateModels:count]; 23 | NSArray *createdUserinfo = [Userinfo crateModels:count]; 24 | 25 | NSLog(@"创建%ld条记录用时%f",count,[[NSDate date] timeIntervalSinceDate:date]); 26 | date = [NSDate date]; 27 | NSArray *mobileHead = MOBILE_HEAD; 28 | NSArray *surname = SURNAME; 29 | 30 | NSArray *cnNumber = CN_NUM; 31 | date = [NSDate date]; 32 | for (int i=0; i 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | cn 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.2.2 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /TODBModelDemo/addressBook/cells/AddressTableViewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // AddressTableViewCell.h 3 | // TODBModel 4 | // 5 | // Created by Tony on 17/2/5. 6 | // Copyright © 2017年 Tony. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AddressModel.h" 11 | 12 | @interface AddressTableViewCell : UITableViewCell 13 | 14 | @property (nonatomic,strong) AddressModel *addressModel; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /TODBModelDemo/addressBook/cells/AddressTableViewCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // AddressTableViewCell.m 3 | // TODBModel 4 | // 5 | // Created by Tony on 17/2/5. 6 | // Copyright © 2017年 Tony. All rights reserved. 7 | // 8 | 9 | #import "AddressTableViewCell.h" 10 | 11 | @interface AddressTableViewCell() 12 | 13 | @property (nonatomic,strong) IBOutlet UILabel *nameLabel; 14 | @property (nonatomic,strong) IBOutlet UILabel *editDateLabel; 15 | @property (nonatomic,strong) IBOutlet UILabel *mobileLabel; 16 | 17 | @end 18 | 19 | @implementation AddressTableViewCell 20 | 21 | + (NSDateFormatter *)formatter{ 22 | static NSDateFormatter *formatter; 23 | 24 | static dispatch_once_t onceToken; 25 | dispatch_once(&onceToken, ^{ 26 | formatter = [[NSDateFormatter alloc] init]; 27 | formatter.dateFormat = @"修改时间:YYYY-MM-DD HH:mm:ss"; 28 | }); 29 | return formatter; 30 | } 31 | 32 | 33 | - (void)awakeFromNib { 34 | [super awakeFromNib]; 35 | // Initialization code 36 | } 37 | 38 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated { 39 | [super setSelected:selected animated:animated]; 40 | 41 | // Configure the view for the selected state 42 | } 43 | 44 | - (void)setAddressModel:(AddressModel *)addressModel{ 45 | _addressModel = addressModel; 46 | self.nameLabel.text = addressModel.userinfo.name; 47 | self.editDateLabel.text = [[[self class] formatter] stringFromDate:addressModel.editDate]; 48 | self.mobileLabel.text = addressModel.mobile; 49 | } 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /TODBModelDemo/addressBook/cells/AddressTableViewCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 31 | 37 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /TODBModelDemo/addressBook/controllers/AddressBookTableViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // AddressBookTableViewController.h 3 | // TODBModel 4 | // 5 | // Created by Tony on 17/2/5. 6 | // Copyright © 2017年 Tony. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AddressBookTableViewController : UITableViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /TODBModelDemo/addressBook/controllers/AddressBookTableViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // AddressBookTableViewController.m 3 | // TODBModel 4 | // 5 | // Created by Tony on 17/2/5. 6 | // Copyright © 2017年 Tony. All rights reserved. 7 | // 8 | 9 | #import "AddressBookTableViewController.h" 10 | #import "AddressModel.h" 11 | #import "AddressTableViewCell.h" 12 | #import "AddressSearchViewController.h" 13 | #import "TODBOrCondition.h" 14 | #import "EditAddressViewController.h" 15 | 16 | #import "NSObject+TODBModel.h" 17 | #import "NSObject+Cache.h" 18 | #import "NSObject+Search.h" 19 | #import "CreateAddressHelper.h" 20 | 21 | #define kAddressCellTag @"AddressCellTag" 22 | 23 | 24 | @interface AddressBookTableViewController () 25 | { 26 | 27 | } 28 | @property (nonatomic,strong) NSMutableArray *dataList; 29 | 30 | @property (nonatomic,strong) UISearchBar *searchBar; 31 | 32 | @end 33 | 34 | 35 | @implementation AddressBookTableViewController 36 | 37 | #pragma mark - Life Cycle 38 | - (void)viewDidLoad { 39 | [super viewDidLoad]; 40 | 41 | // Uncomment the following line to preserve selection between presentations. 42 | // self.clearsSelectionOnViewWillAppear = NO; 43 | 44 | // Uncomment the following line to display an Edit button in the navigation bar for this view controller. 45 | // self.navigationItem.rightBarButtonItem = self.editButtonItem; 46 | 47 | [self initUI]; 48 | 49 | [self loadModels]; 50 | } 51 | 52 | - (void)initUI{ 53 | self.title = @"通讯录"; 54 | self.navigationItem.rightBarButtonItems = @[ 55 | 56 | [[UIBarButtonItem alloc] initWithTitle:@"编辑" style:UIBarButtonItemStylePlain target:self action:@selector(leftBarButtonClickHandler:)], 57 | [[UIBarButtonItem alloc] initWithTitle:@"添加" style:UIBarButtonItemStylePlain target:self action:@selector(rightBarButtonClickHandler:)], 58 | ]; 59 | 60 | 61 | self.tableView.tableHeaderView = self.searchBar; 62 | self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag; 63 | [self.tableView registerNib:[UINib nibWithNibName:@"AddressTableViewCell" bundle:nil] forCellReuseIdentifier:kAddressCellTag]; 64 | self.tableView.rowHeight = UITableViewAutomaticDimension; 65 | self.tableView.estimatedRowHeight = 60; 66 | } 67 | 68 | - (void)loadModels{ 69 | __weak id self_weak = self; 70 | [AddressModel allModels:^(NSArray *models) { 71 | __strong AddressBookTableViewController *self_strong = self_weak; 72 | 73 | self_strong.dataList = [NSMutableArray arrayWithArray:models]; 74 | if (self_strong.dataList.count == 0) { 75 | self_strong.dataList = [NSMutableArray arrayWithArray:[CreateAddressHelper createAddress:1000 complete:nil]]; 76 | } 77 | [self_strong.tableView reloadData]; 78 | }]; 79 | } 80 | 81 | 82 | 83 | - (void)viewWillAppear:(BOOL)animated{ 84 | [super viewWillAppear:animated]; 85 | [self.tableView reloadData]; 86 | } 87 | 88 | - (void)didReceiveMemoryWarning { 89 | [super didReceiveMemoryWarning]; 90 | // Dispose of any resources that can be recreated. 91 | } 92 | 93 | #pragma mark - Getter 94 | - (UISearchBar *)searchBar{ 95 | if (!_searchBar) { 96 | _searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, [ UIScreen mainScreen ].bounds.size.width, 46)]; 97 | _searchBar.delegate = self; 98 | } 99 | return _searchBar; 100 | } 101 | 102 | #pragma mark - Events 103 | - (void)leftBarButtonClickHandler:(UIBarButtonItem *)sender{ 104 | if (self.tableView.isEditing) { 105 | sender.title = @"编辑"; 106 | [self.tableView setEditing:NO animated:YES]; 107 | }else{ 108 | sender.title = @"完成"; 109 | [self.tableView setEditing:YES animated:YES]; 110 | } 111 | } 112 | 113 | - (void)rightBarButtonClickHandler:(id)sender{ 114 | if (self.tableView.isEditing) { 115 | [self leftBarButtonClickHandler:self.navigationItem.leftBarButtonItem]; 116 | } 117 | 118 | EditAddressViewController *editer = [[EditAddressViewController alloc] init]; 119 | 120 | [self.navigationController pushViewController:editer animated:YES]; 121 | } 122 | 123 | #pragma mark - Table view data source 124 | 125 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 126 | return 1; 127 | } 128 | 129 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 130 | return self.dataList.count; 131 | } 132 | 133 | 134 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 135 | AddressTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kAddressCellTag forIndexPath:indexPath]; 136 | 137 | cell.addressModel = self.dataList[indexPath.row]; 138 | return cell; 139 | } 140 | 141 | 142 | /* 143 | // Override to support conditional editing of the table view. 144 | - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { 145 | // Return NO if you do not want the specified item to be editable. 146 | return YES; 147 | } 148 | */ 149 | 150 | 151 | // Override to support editing the table view. 152 | - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { 153 | if (editingStyle == UITableViewCellEditingStyleDelete) { 154 | // Delete the row from the data source 155 | AddressModel *addressModel = self.dataList[indexPath.row]; 156 | [addressModel del:^(NSObject *model) { 157 | 158 | }]; 159 | [self.dataList removeObjectAtIndex:indexPath.row]; 160 | [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; 161 | 162 | } else if (editingStyle == UITableViewCellEditingStyleInsert) { 163 | // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view 164 | } 165 | } 166 | 167 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 168 | { 169 | EditAddressViewController *editer = [[EditAddressViewController alloc] init]; 170 | editer.model = self.dataList[indexPath.row]; 171 | [self.navigationController pushViewController:editer animated:YES]; 172 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 173 | } 174 | 175 | #pragma mark 176 | - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText 177 | { 178 | 179 | 180 | if (searchText.length > 0) { 181 | __weak id self_weak = self; 182 | 183 | 184 | TODBCondition *condition = [TODBCondition condition:@"mobile" like:[NSString stringWithFormat:@"%%%@%%",searchText]]; 185 | [AddressModel search:condition callBack:^(NSArray *models) { 186 | __strong AddressBookTableViewController *self_strong = self_weak; 187 | self_strong.dataList = [NSMutableArray arrayWithArray:models]; 188 | [self_strong.tableView reloadData]; 189 | 190 | }]; 191 | 192 | }else{ 193 | [self loadModels]; 194 | } 195 | } 196 | 197 | - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar 198 | { 199 | [searchBar endEditing:YES]; 200 | } 201 | 202 | @end 203 | -------------------------------------------------------------------------------- /TODBModelDemo/addressBook/controllers/AddressSearchViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // AddressSearchViewController.h 3 | // TODBModel 4 | // 5 | // Created by Tony on 17/2/6. 6 | // Copyright © 2017年 Tony. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "TODBCondition.h" 11 | 12 | @interface AddressSearchViewController : UIViewController 13 | 14 | @property (nonatomic,strong) void(^searchConditionsBlock)(TODBCondition * conditions); 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /TODBModelDemo/addressBook/controllers/AddressSearchViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // AddressSearchViewController.m 3 | // TODBModel 4 | // 5 | // Created by Tony on 17/2/6. 6 | // Copyright © 2017年 Tony. All rights reserved. 7 | // 8 | 9 | #import "AddressSearchViewController.h" 10 | 11 | @interface AddressSearchViewController () 12 | 13 | @end 14 | 15 | @implementation AddressSearchViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | // Do any additional setup after loading the view from its nib. 20 | } 21 | 22 | - (void)didReceiveMemoryWarning { 23 | [super didReceiveMemoryWarning]; 24 | // Dispose of any resources that can be recreated. 25 | } 26 | 27 | /* 28 | #pragma mark - Navigation 29 | 30 | // In a storyboard-based application, you will often want to do a little preparation before navigation 31 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 32 | // Get the new view controller using [segue destinationViewController]. 33 | // Pass the selected object to the new view controller. 34 | } 35 | */ 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /TODBModelDemo/addressBook/controllers/AddressSearchViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /TODBModelDemo/addressBook/controllers/EditAddressViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // EditAddressViewController.h 3 | // TODBModel 4 | // 5 | // Created by Tony on 17/2/6. 6 | // Copyright © 2017年 Tony. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AddressModel.h" 11 | 12 | @interface EditAddressViewController : UIViewController 13 | 14 | @property (nonatomic,strong) AddressModel *model; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /TODBModelDemo/addressBook/controllers/EditAddressViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // EditAddressViewController.m 3 | // TODBModel 4 | // 5 | // Created by Tony on 17/2/6. 6 | // Copyright © 2017年 Tony. All rights reserved. 7 | // 8 | 9 | #import "EditAddressViewController.h" 10 | 11 | @interface EditAddressViewController () 12 | 13 | @property (nonatomic,strong) IBOutlet UILabel *idLabel; 14 | @property (nonatomic,strong) IBOutlet UITextField *nameTextField; 15 | @property (nonatomic,strong) IBOutlet UITextField *mobileTextField; 16 | @property (nonatomic,strong) IBOutlet UITextView *adddressTextView; 17 | @property (nonatomic,strong) IBOutlet UILabel *editTimeLabel; 18 | 19 | @end 20 | 21 | @implementation EditAddressViewController 22 | 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | // Do any additional setup after loading the view from its nib. 26 | 27 | [self setEdgesForExtendedLayout:UIRectEdgeNone]; 28 | 29 | self.model = self.model; 30 | 31 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"保存" style:UIBarButtonItemStylePlain target:self action:@selector(saveHandler:)]; 32 | } 33 | 34 | 35 | - (void)didReceiveMemoryWarning { 36 | [super didReceiveMemoryWarning]; 37 | // Dispose of any resources that can be recreated. 38 | } 39 | 40 | /* 41 | #pragma mark - Navigation 42 | 43 | // In a storyboard-based application, you will often want to do a little preparation before navigation 44 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 45 | // Get the new view controller using [segue destinationViewController]. 46 | // Pass the selected object to the new view controller. 47 | } 48 | */ 49 | 50 | #pragma mark - Events 51 | - (void)saveHandler:(id)sender{ 52 | if (!_model) { 53 | _model = [AddressModel crateModel]; 54 | } 55 | self.model.userinfo.name = self.nameTextField.text; 56 | self.model.mobile = self.mobileTextField.text; 57 | self.model.editDate = [NSDate date]; 58 | 59 | self.model.addressInfo.address = self.adddressTextView.text; 60 | 61 | 62 | [self.model save:^(NSObject *model) { 63 | 64 | }]; 65 | [self.navigationController popViewControllerAnimated:YES]; 66 | 67 | } 68 | 69 | #pragma mark - Setter 70 | - (void)setModel:(AddressModel *)model{ 71 | _model = model; 72 | if (self.viewLoaded) { 73 | self.nameTextField.text = model.userinfo.name; 74 | self.mobileTextField.text = model.mobile; 75 | self.adddressTextView.text = model.addressInfo.address; 76 | self.idLabel.text = [NSString stringWithFormat:@"ID:%d",model.addressID]; 77 | self.editTimeLabel.text = [[[self class] formatter] stringFromDate:model.editDate]; 78 | } 79 | } 80 | 81 | + (NSDateFormatter *)formatter{ 82 | static NSDateFormatter *formatter; 83 | 84 | static dispatch_once_t onceToken; 85 | dispatch_once(&onceToken, ^{ 86 | formatter = [[NSDateFormatter alloc] init]; 87 | formatter.dateFormat = @"修改时间:YYYY-MM-DD HH:mm:ss"; 88 | }); 89 | return formatter; 90 | } 91 | 92 | @end 93 | -------------------------------------------------------------------------------- /TODBModelDemo/addressBook/controllers/EditAddressViewController.xib: -------------------------------------------------------------------------------- 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 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 57 | 63 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /TODBModelDemo/addressBook/models/AddressInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // AddressInfo.h 3 | // TODBModel 4 | // 5 | // Created by TonyJR on 2018/10/10. 6 | // Copyright © 2018年 Tony. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface AddressInfo : NSObject 14 | 15 | @property (nonatomic,copy) NSString *city; 16 | @property (nonatomic,copy) NSString *area; 17 | @property (nonatomic,copy) NSString *address; 18 | @property (nonatomic,copy) NSString *zipCode; 19 | 20 | @end 21 | 22 | NS_ASSUME_NONNULL_END 23 | -------------------------------------------------------------------------------- /TODBModelDemo/addressBook/models/AddressInfo.m: -------------------------------------------------------------------------------- 1 | // 2 | // AddressInfo.m 3 | // TODBModel 4 | // 5 | // Created by TonyJR on 2018/10/10. 6 | // Copyright © 2018年 Tony. All rights reserved. 7 | // 8 | 9 | #import "AddressInfo.h" 10 | 11 | @implementation AddressInfo 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /TODBModelDemo/addressBook/models/AddressModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // AddressModel.h 3 | // TODBModel 4 | // 5 | // Created by Tony on 17/2/5. 6 | // Copyright © 2017年 Tony. All rights reserved. 7 | // 8 | 9 | #import "NSObject+TODBModel.h" 10 | #import "Userinfo.h" 11 | #import "AddressInfo.h" 12 | 13 | @interface AddressModel : NSObject 14 | 15 | @property (nonatomic,strong) Userinfo *userinfo; 16 | @property (nonatomic,assign) int addressID; 17 | @property (nonatomic,strong) NSDate *editDate; 18 | @property (nonatomic,copy) NSString *mobile; 19 | @property (nonatomic,strong) AddressInfo *addressInfo; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /TODBModelDemo/addressBook/models/AddressModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // AddressModel.m 3 | // TODBModel 4 | // 5 | // Created by Tony on 17/2/5. 6 | // Copyright © 2017年 Tony. All rights reserved. 7 | // 8 | 9 | #import "AddressModel.h" 10 | 11 | @implementation AddressModel 12 | 13 | + (void)load{ 14 | [self regiestDB]; 15 | } 16 | 17 | + (NSString *)db_pk{ 18 | return @"addressID"; 19 | } 20 | 21 | 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /TODBModelDemo/addressBook/models/Userinfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // Userinfo.h 3 | // TODBModel 4 | // 5 | // Created by TonyJR on 2018/10/8. 6 | // Copyright © 2018年 Tony. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | typedef enum : NSUInteger { 14 | UserSexUnknow, 15 | UserSexMale, 16 | UserSexFemale, 17 | } UserSex; 18 | 19 | @interface Userinfo : NSObject 20 | 21 | @property (nonatomic,copy) NSString *name; 22 | @property (nonatomic,assign) UserSex sex; 23 | @property (nonatomic,assign) int infoID; 24 | 25 | 26 | @end 27 | 28 | NS_ASSUME_NONNULL_END 29 | -------------------------------------------------------------------------------- /TODBModelDemo/addressBook/models/Userinfo.m: -------------------------------------------------------------------------------- 1 | // 2 | // Userinfo.m 3 | // TODBModel 4 | // 5 | // Created by TonyJR on 2018/10/8. 6 | // Copyright © 2018年 Tony. All rights reserved. 7 | // 8 | 9 | #import "Userinfo.h" 10 | #import "NSObject+TODBModel.h" 11 | 12 | @implementation Userinfo 13 | 14 | + (void)load{ 15 | [self regiestDB]; 16 | } 17 | 18 | + (NSString *)db_pk{ 19 | return @"infoID"; 20 | } 21 | 22 | 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /TODBModelDemo/demoList/DemoListTableViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // DemoListTableViewController.h 3 | // TODBModel 4 | // 5 | // Created by Tony on 2017/11/29. 6 | // Copyright © 2017年 Tony. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DemoListTableViewController : UITableViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /TODBModelDemo/demoList/DemoListTableViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // DemoListTableViewController.m 3 | // TODBModel 4 | // 5 | // Created by Tony on 2017/11/29. 6 | // Copyright © 2017年 Tony. All rights reserved. 7 | // 8 | 9 | #import "DemoListTableViewController.h" 10 | 11 | #pragma mark - DemoItem 12 | @interface DemoItem : NSObject 13 | 14 | @property (nonatomic,copy) NSString *name; 15 | @property (nonatomic,copy) NSString *className; 16 | 17 | 18 | + (instancetype)itemWithName:(NSString *)name className:(NSString *)className; 19 | 20 | @end 21 | 22 | @implementation DemoItem 23 | 24 | + (instancetype)itemWithName:(NSString *)name className:(NSString *)className{ 25 | DemoItem *item = [[DemoItem alloc] init]; 26 | if (item) { 27 | item.name = name; 28 | item.className = className; 29 | } 30 | return item; 31 | } 32 | @end 33 | 34 | 35 | #pragma mark - DemoListTableViewController 36 | 37 | @interface DemoListTableViewController ()< 38 | UITableViewDelegate> 39 | 40 | @property (nonatomic,strong) NSArray *itemList; 41 | 42 | @end 43 | 44 | @implementation DemoListTableViewController 45 | 46 | - (void)viewDidLoad { 47 | [super viewDidLoad]; 48 | self.title = @"目录"; 49 | // Uncomment the following line to preserve selection between presentations. 50 | // self.clearsSelectionOnViewWillAppear = NO; 51 | 52 | // Uncomment the following line to display an Edit button in the navigation bar for this view controller. 53 | // self.navigationItem.rightBarButtonItem = self.editButtonItem; 54 | [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"reuseIdentifier"]; 55 | self.itemList = @[ 56 | [DemoItem itemWithName:@"通讯录" className:@"AddressBookTableViewController"], 57 | [DemoItem itemWithName:@"性能测试" className:@"PreformanceViewController"], 58 | ]; 59 | } 60 | 61 | - (void)didReceiveMemoryWarning { 62 | [super didReceiveMemoryWarning]; 63 | // Dispose of any resources that can be recreated. 64 | } 65 | 66 | #pragma mark - Table view data source 67 | 68 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 69 | return 1; 70 | } 71 | 72 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 73 | return self.itemList.count; 74 | } 75 | 76 | 77 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 78 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"reuseIdentifier" forIndexPath:indexPath]; 79 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 80 | cell.textLabel.text = self.itemList[indexPath.row].name; 81 | return cell; 82 | } 83 | 84 | #pragma mark - UITableViewDelegate 85 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ 86 | 87 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 88 | 89 | Class class = NSClassFromString(self.itemList[indexPath.row].className); 90 | if (class) { 91 | UIViewController *targetViewController = [[class alloc] init]; 92 | if (targetViewController) { 93 | [self.navigationController pushViewController:targetViewController animated:YES]; 94 | } 95 | } 96 | } 97 | @end 98 | -------------------------------------------------------------------------------- /TODBModelDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // TODBModel 4 | // 5 | // Created by Tony on 16/11/22. 6 | // Copyright © 2016年 Tony. 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 | -------------------------------------------------------------------------------- /TODBModelDemo/performance/PreformanceViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // PreformanceViewController.h 3 | // TODBModel 4 | // 5 | // Created by Tony on 2017/11/29. 6 | // Copyright © 2017年 Tony. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface PreformanceViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /TODBModelDemo/performance/PreformanceViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // PreformanceViewController.m 3 | // TODBModel 4 | // 5 | // Created by Tony on 2017/11/29. 6 | // Copyright © 2017年 Tony. All rights reserved. 7 | // 8 | 9 | #import "PreformanceViewController.h" 10 | #import "AddressModel.h" 11 | #import "NSObject+Search.h" 12 | #import "CreateAddressHelper.h" 13 | 14 | @interface PreformanceViewController () 15 | 16 | @property (nonatomic,strong) IBOutlet UITextField *createCountText; 17 | @property (nonatomic,strong) IBOutlet UIButton *searchKeyButton; 18 | @property (nonatomic,strong) IBOutlet UIButton *searchTypeButton; 19 | @property (nonatomic,strong) IBOutlet UITextField *searchValueText; 20 | 21 | 22 | @property (nonatomic,strong) IBOutlet UITextView *logTextView; 23 | 24 | @end 25 | 26 | @implementation PreformanceViewController 27 | 28 | - (instancetype)init 29 | { 30 | self = [super init]; 31 | if (self) { 32 | self.edgesForExtendedLayout = UIRectEdgeNone; 33 | } 34 | return self; 35 | } 36 | 37 | - (void)viewDidLoad { 38 | [super viewDidLoad]; 39 | // Do any additional setup after loading the view from its nib. 40 | } 41 | 42 | - (void)didReceiveMemoryWarning { 43 | [super didReceiveMemoryWarning]; 44 | // Dispose of any resources that can be recreated. 45 | } 46 | 47 | /* 48 | #pragma mark - Navigation 49 | 50 | // In a storyboard-based application, you will often want to do a little preparation before navigation 51 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 52 | // Get the new view controller using [segue destinationViewController]. 53 | // Pass the selected object to the new view controller. 54 | } 55 | */ 56 | 57 | - (void)log:(NSString *)logStr{ 58 | dispatch_async(dispatch_get_main_queue(), ^{ 59 | self.logTextView.text = [self.logTextView.text stringByAppendingFormat:@"\n%@",logStr]; 60 | CGFloat top = self.logTextView.contentSize.height - self.logTextView.frame.size.height; 61 | top = MAX(top, 0); 62 | [self.logTextView setContentOffset:CGPointMake(0, top)]; 63 | // [self.logTextView scrollRectToVisible:CGRectMake(0, top, 0, 0) animated:YES]; 64 | }); 65 | } 66 | 67 | - (IBAction)endEdit:(id)sender{ 68 | [self.view endEditing:YES]; 69 | } 70 | 71 | - (IBAction)insert:(id)sender{ 72 | NSInteger count = [self.createCountText.text integerValue]; 73 | if (count > 0) { 74 | 75 | [CreateAddressHelper createAddress:count complete:^(NSTimeInterval costTime) { 76 | //addressModel中包含userInfo,因此实际载入时间会较慢,模型包含其他模型的搜索还可以优化 77 | [self log:[NSString stringWithFormat:@"创建%ld条记录用时%f",count * 2,costTime]]; 78 | }]; 79 | 80 | 81 | } 82 | [self endEdit:nil]; 83 | } 84 | 85 | - (IBAction)search:(id)sender{ 86 | 87 | TODBCondition *searchCondition; 88 | 89 | if ([self.searchTypeButton.titleLabel.text isEqualToString: @"=="]) { 90 | searchCondition = [TODBCondition condition:self.searchKeyButton.titleLabel.text equalTo:self.searchValueText.text]; 91 | }else if ([self.searchTypeButton.titleLabel.text isEqualToString: @">"]){ 92 | searchCondition = [TODBCondition condition:self.searchKeyButton.titleLabel.text greaterThan:self.searchValueText.text]; 93 | }else if ([self.searchTypeButton.titleLabel.text isEqualToString: @"<"]){ 94 | searchCondition = [TODBCondition condition:self.searchKeyButton.titleLabel.text lessThan:self.searchValueText.text]; 95 | }else { 96 | return; 97 | } 98 | NSDate *date = [NSDate date]; 99 | [AddressModel search:searchCondition callBack:^(NSArray *models) { 100 | 101 | [self log:[NSString stringWithFormat:@"搜索到%ld条记录用时%f",[models count],[[NSDate date] timeIntervalSinceDate:date]]]; 102 | }]; 103 | } 104 | 105 | - (IBAction)findAll:(id)sender{ 106 | NSDate *date = [NSDate date]; 107 | [AddressModel allModels:^(NSArray *models) { 108 | [self log:[NSString stringWithFormat:@"获取%ld条记录用时%f",[models count],[[NSDate date] timeIntervalSinceDate:date]]]; 109 | }]; 110 | } 111 | 112 | - (IBAction)removeAll:(id)sender{ 113 | [AddressModel removeAll:^{ 114 | [self log:@"删除成功"]; 115 | }]; 116 | } 117 | 118 | - (IBAction)clearLog:(id)sender{ 119 | dispatch_async(dispatch_get_main_queue(), ^{ 120 | self.logTextView.text = @""; 121 | }); 122 | } 123 | 124 | @end 125 | --------------------------------------------------------------------------------