iOS Sqlite 資料庫的使用
總體內容
1、sqlite基本操作封裝
2、動態建表-基本建立
3、動態建表-忽略欄位
4、動態更新表-遷移資料
5、儲存/更新模型
6、刪除模型
7、查詢模型
8、模型中-字典/陣列屬性處理
9、存在問題的優化方案
10、上面所有步驟組合起來的 JKSqliteKit
的使用
一、sqlite基本操作封裝
-
1.1、建立專案,匯入
libsqlite3.0.tbd
建立專案,匯入 `libsqlite3.0.tbd`
-
1.2、開啟資料庫
-
<1>、獲取資料庫的名字
NSString *sqliteName = @"jk_common.sqlite"; if (sqliteName.length != 0) { sqliteName = [NSString stringWithFormat:@"jk_%@.sqlite",uid]; }
提示:資料庫的名字我們採取 使用者機制,操作資料庫 ,共同的資料庫,也就是未登入狀態,統一使用
jk_common.sqlite
資料庫,登陸後,根據使用者的id建立對應的資料庫:jk_(使用者id).sqlite
-
<2>、對應的路徑(我們把對一個的資料庫放到了
/Library/Caches
下)NSString *sqlitePath = [JKSqliteCachePath stringByAppendingPathComponent:sqliteName];
提示: JKSqliteCachePath 是一個巨集:
#define JKSqliteCachePath [NSHomeDirectory() stringByAppendingPathComponent:@"/Library/Caches"]
-
<3>、開啟資料庫,不存在的情況下自動建立
sqlite3 *ppDb = nil; if (sqlite3_open(sqlitePath.UTF8String, &ppDb) != SQLITE_OK) { // 開啟資料庫失敗 return NO; }
-
-
1.3、關閉資料庫
// 關閉資料庫 sqlite3_close(ppDb);
-
1.4、執行語句( DDL
(增、刪、改)
、 DDL (表格操作):返回執行結果)// 執行sql語句 /** 第1個引數:資料庫物件 第2個引數:sql語句 第3個引數:查詢時候用到的一個結果集閉包 第4個引數:用不到 第5個引數:用不到 */ BOOL result = sqlite3_exec(ppDb, sql.UTF8String, nil, nil, nil) == SQLITE_OK;
-
1.5、查詢語句( DQL :返回結果集),核心程式碼如下
/** 查詢資料 @param sql sql 語句 @param uid 使用者的id @return 字典組成的陣列,每一個字典都是一行記錄 */ +(NSMutableArray <NSMutableDictionary *>*)querySql:(NSString *)sql witUid:(NSString *)uid{ // 1.開啟資料庫 If (![self openDB:uid]) { NSLog(@"開啟失敗"); return nil; } // 準備語句,預處理語句 // 2.建立準備語句 /** 第1個引數:一個已經開啟的資料庫物件 第2個引數:sql語句 第3個引數:引數2中取出多少位元組的長度,-1 自動計算,\0停止取出 第4個引數:準備語句 第5個引數:通過引數3,取出引數2的長度位元組之後,剩下的字串 */ sqlite3_stmt *ppStmt = nil; if (sqlite3_prepare_v2(ppDb, sql.UTF8String, -1, &ppStmt, nil) != SQLITE_OK) { NSLog(@"準備語句編譯失敗"); return nil; } // 2.繫結資料(可以有 ? 的省略) // 3.執行 // 大陣列 : SQLITE_ROW代表資料的不斷的向下查詢 NSMutableArray *rowDicArray = [NSMutableArray array]; while (sqlite3_step(ppStmt) == SQLITE_ROW) { // 一行記錄 -> 字典 // 記錄值的字典 NSMutableDictionary *rowDictionary = [NSMutableDictionary dictionary]; // 3.1、獲取所有列的個數 int columnCount = sqlite3_column_count(ppStmt); // 3.2、遍歷所有的列 for (int i=0; i<columnCount; i++) { // 3.2.1、獲取所有列的名字,也就是表中欄位的名字 // C語言的字串 const char *columnNameC = sqlite3_column_name(ppStmt, i); // 把 C 語言字串轉為 OC NSString *columnName = [NSString stringWithUTF8String:columnNameC]; // 3.2.2、獲取列值 // 不同列的型別,使用不同的函式,進行獲取值 // 3.2.2.1、獲取列的型別 int type = sqlite3_column_type(ppStmt, i); /** 我們使用的是 SQLite3,所以是:SQLITE3_TEXT SQLite version 2 and SQLite version 3 should use SQLITE3_TEXT, not SQLITE_INTEGER1 SQLITE_FLOAT2 SQLITE3_TEXT3 SQLITE_BLOB4 SQLITE_NULL5 */ // 3.2.2.2、根據列的型別,使用不同的函式,獲取列的值 id value = nil; switch (type) { case SQLITE_INTEGER: value = @(sqlite3_column_int(ppStmt,i)); break; case SQLITE_FLOAT: value = @(sqlite3_column_double(ppStmt, i)); break; case SQLITE3_TEXT: value = [NSString stringWithUTF8String:(const char *)sqlite3_column_text(ppStmt, i)]; break; case SQLITE_BLOB: value = CFBridgingRelease(sqlite3_column_blob(ppStmt, i)); break; case SQLITE_NULL: value = @""; break; default: break; } // 字典填值 [rowDictionary setValue:value forKey:columnName]; } // 每一個新增到陣列中 [rowDicArray addObject:rowDictionary]; } // 4.重置(省略) // 5.釋放資源 sqlite3_finalize(ppStmt); // 6.關閉資料庫 [self closeDB]; return rowDicArray; }
二、sqlite 資料庫動態建表-基本建立
-
2.1、當我們建立一個model模型的時候,一類名為表名,以成員變數的名字為欄位名,成員變數的型別為 sqlite 的型別,從而動態的建立表,如下的模型
Student模型
-
2.2、建立表的 sql 語句合成
目標sql語句:
create table if not exists 表名(欄位1 欄位1型別(約束),欄位2 欄位2型別(約束),欄位3 欄位3型別(約束),.....,primary(欄位))
-
<1>、獲取表名
+(NSString *)tableName:(Class)cls{ // 把類轉化為類名的字串 return NSStringFromClass(cls); }
-
<2>、判斷模型裡面是否有主鍵(定義一個協議,讓使用者設定主鍵),協議是:
JKSqliteProtocol.h
裡面if (![cls respondsToSelector:@selector(primaryKey)]) { NSLog(@"請設定模型裡面的主鍵,遵守協議,實現+(NSString *)primaryKey;,d從而得到主鍵資訊"); return NO; }
-
<3>、拼接欄位與對應型別的字串(如:
欄位1 欄位1型別(約束),欄位2 欄位2型別(約束),欄位3 欄位3型別(約束),.....,
),可以參考demo裡面的JKSqliteModelTool
類提示:技術點是:利用runtime獲取一個類的成員變數,根據成員變數不同的型別轉換成sqlite裡面的型別,再把它們合成sql語句類裡面欄位的 語句
獲取一個模型裡面所有的欄位名字,以及型別
+(NSDictionary *)classIvarNameTypeDictionary:(Class)cls{ NSMutableDictionary *nameTypeDictionary = [NSMutableDictionary dictionary]; // 獲取所有的成員變數 unsigned intoutCount = 0; Ivar *varList = class_copyIvarList(cls, &outCount); for (int i = 0; i<outCount; ++i) { Ivar ivar = varList[I]; // 1.獲取成員變數名字 NSString *ivarName = [NSString stringWithUTF8String:ivar_getName(ivar)]; if ([ivarName hasPrefix:@"_"]) { // 把 _ 去掉,讀取後面的 ivarName = [ivarName substringFromIndex:1]; } // 2.獲取成員變數型別 NSString *ivarType = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)]; // 把包含 @\" 的去掉,如 "@\"NSString\"";-> NSString ivarType = [ivarType stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"@\""]]; NSLog(@"ivarType=%@",ivarType); // 3.成員變數的型別可能重複,成員變數的名字不會重複,所以以成員變數的名字為key [nameTypeDictionary setValue:ivarType forKey:ivarName]; } return nameTypeDictionary; }
獲取一個模型裡面所有的欄位名字,以及型別(型別轉換為sqlite裡面的型別)
+(NSDictionary *)classIvarNameSqliteTypeDictionary:(Class)cls{ NSMutableDictionary *dict = [[self classIvarNameTypeDictionary:cls] mutableCopy]; NSDictionary *typeDict = [self switchOCTypeToSqliteTypeDict]; [dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL * _Nonnull stop) { // 字典 dict[key] = typeDict[obj]; }]; return dict; }
把上面兩個方法合成的欄位組合成sql語句裡面的 欄位
+(NSString *)columnNamesAndTypesStr:(Class)cls{ NSDictionary *dict = [self classIvarNameSqliteTypeDictionary:cls]; NSMutableArray *result = [NSMutableArray array]; [dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL * _Nonnull stop) { [result addObject:[NSString stringWithFormat:@"%@ %@",key,obj]]; }]; return [result componentsJoinedByString:@","]; }
-
三、動態建表-忽略欄位
-
3.1、在定義的協議裡面設定,必須實現的方法和可以不用實現的方法,如下:
#import <Foundation/Foundation.h> NS_ASSUME_NONNULL_BEGIN @protocol JKSqliteProtocol <NSObject> // 主鍵 @required // 必須實現的方法 +(NSString *)primaryKey; @optional // 可以不用實現的方法 +(NSArray *)ignoreColumnNames; @end NS_ASSUME_NONNULL_END
-
3.2、模型類裡面實現協議方法,以demo裡面的
Student
類為例#import "Student.h" @implementation Student +(NSString *)primaryKey{ return @"studentNumber"; } // 實現要在動態建立表的時候要忽略的欄位 +(NSArray *)ignoreColumnNames{ return @[@"testName"]; } @end
-
3.3、在動態建立表建立表的方法裡面實現過濾忽略欄位
在
JKSqliteModel
裡面的+(NSDictionary *)classIvarNameTypeDictionary:(Class)cls
方法類裡面-
先判斷模型有沒有實現忽略方法,有的話取出來
NSArray *ignoreNamesArray = nil; if ([cls respondsToSelector:@selector(ignoreColumnNames)]) { ignoreNamesArray = [cls ignoreColumnNames]; }
-
判斷遍歷的成員變數是否包含在數組裡面,在裡面就
continue
過濾// 1.1、檢視有沒有忽略欄位,如果有就不去建立(根據自己模型裡面是否設定了忽略欄位) if ([ignoreNamesArray containsObject:ivarName]) { continue; }
-
四、動態更新表-遷移資料
-
4.1、檢測表格是否需要更新(在類
JKSqliteTableTool
裡面)判斷是否更新表格的依據:獲取
model
(模型)所有的成員變數名陣列與表格裡面所有的欄位組成的資料進行對比,前提是二者的陣列都進行過排序,利用陣列isEqualToArray
判斷,核心程式碼如下+(BOOL)isUpdateTable:(Class)cls uid:(NSString *)uid{ // 1.獲取模型裡面的所有成員變數的名字 NSArray *modelNames = [JKSqliteModel allTableSortedIvarNames:cls]; // 2.獲取uid對應資料庫裡面對應表的欄位陣列 NSArray *tableNames = [JKSqliteTableTool tableColumnNames:cls uid:uid]; // 3.判斷兩個陣列是否相等,返回響應的結果,取反:相等不需要更新,不相等才需要去更新 return ![modelNames isEqualToArray:tableNames]; }
提示:上面兩個陣列的獲取都很有學習意義,建議看著demo讀這篇部落格
-
4.2、動態遷移資料
思路:由於sqlite 是閹割版的,雖然sql語句有刪除欄位的操作,但是在xcode中不奏效,只有採用如下的方法來解決表更新欄位的問題,程式碼在
JKSqliteModelTool
的+(BOOL)updateTable:(Class)cls uid:(NSString *)uid
裡面- <1>、根據新模型建立臨時表
- <2>、把就表中的主鍵資料插入臨時表
- <3>、臨時表中的欄位有在舊錶中的,根據兩表主鍵相等把舊錶資料匯入臨時表
- <4>、刪除舊錶,並把臨時表名改為舊錶名
提示:上面的方法其實就是在使用者無察覺的情況下完成了偷樑換柱
-
4.3、欄位改名
-
通過協議獲取改名的對映字典
@optional // 更新欄位: 新欄位名字 到 舊欄位名字 的對映表(字典的key是新欄位,字典的value是舊欄位) +(NSDictionary *)updateFieldNewNameReplaceOldName;
-
在模型裡面實現方法(用
studentAge1
欄位替換studentAge
欄位)+(NSDictionary *)updateFieldNewNameReplaceOldName{ return @{@"studentAge1":@"studentAge"}; }
-
遷移資料時, 進行過濾
// 獲取更名字典 NSDictionary *newNameReplaceOldNameDict = @{}; if ([cls respondsToSelector:@selector(updateFieldNewNameReplaceOldName)]) { newNameReplaceOldNameDict = [cls updateFieldNewNameReplaceOldName]; }
提示:在執行 動態遷移資料 這塊會有很多的 sql 語句,為了保證都執行成功才是成功,我們可以用 事務 來解決,具體的程式碼可以看
JKSqliteDatabase
類,對資料庫的操作 -
五、儲存/更新模型
-
5.1、思路分析
要儲存一個模型的資料:1、要先判斷這個模型對應的表是否存在;2、不存在的話建立表,存在就判斷是否需要更表是否需要更新;3、按照模型主鍵檢視當前主鍵下的資料是否存在,存在的話就根據主鍵值更新資料,不存在的話就插入資料
-
5.2、具體的步驟程式碼如下,具體的可以參考JKSqliteModelTool裡面的
+(BOOL)saveOrUpdateModel:(id)model uid:(NSString *)uid;
方法,核心程式碼如下+(BOOL)saveOrUpdateModel:(id)model uid:(NSString *)uid{ // 使用者在使用的過程中直接呼叫這個方法,來儲存模型 Class cls = [model class]; // 1、判斷表格是否存在,不存在就去建立 if (![JKSqliteTableTool isTableExists:cls uid:uid]) { // 建立表格 if (![self createTable:cls uid:uid]) { // 建立失敗 return NO; } } // 2、檢測表格是否需要更新,需要則更新,不需要則不更新 if ([self isUpdateTable:cls uid:uid]) { // 更新表格 [self updateTable:cls uid:uid]; } // 3、判斷記錄是否存在,按照主鍵的值查詢,如果能查詢到,那麼久更新資料,如果查詢不到,就把這條資料插入 // 獲取表名 NSString *tableName = [JKSqliteModel tableName:cls]; // 判斷模型裡面是否有主鍵 if (![cls respondsToSelector:@selector(primaryKey)]) { NSLog(@"請設定模型裡面的主鍵,遵守協議,實現+(NSString *)primaryKey;,d從而得到主鍵資訊"); return NO; } // 拿到主鍵 NSString *primaryKey = [cls primaryKey]; // 模型裡面主鍵的值 id primaryKeyValue = [model valueForKeyPath:primaryKey]; // 建立sql語句 NSString *checkPrimaryKeySql = [NSString stringWithFormat:@"select * from %@ where %@ = %@",tableName,primaryKey,primaryKeyValue]; // 進行查詢 // 獲取表中所有的欄位(下面的方法獲取的是字典,我們取其鍵) NSArray *columnNames = [JKSqliteModel classIvarNameTypeDictionary:cls].allKeys; // 獲取模型裡面所有的值陣列 NSMutableArray *columnNameValues = [NSMutableArray array]; for (NSString *columnName in columnNames) { id columnNameValue = [model valueForKeyPath:columnName]; [columnNameValues addObject:columnNameValue]; } // 把欄位和值拼接生成欄位 = 值字元的陣列 NSInteger count = columnNames.count; NSMutableArray *setValueArray = [NSMutableArray array]; for (int i = 0; i<count; i++) { NSString *name = columnNames[I]; id value = columnNameValues[I]; NSString *setStr = [NSString stringWithFormat:@"%@ = '%@'",name,value]; [setValueArray addObject:setStr]; } NSString *execSql = @""; if ([JKSqliteDatabase querySql:checkPrimaryKeySql witUid:uid].count > 0) { // update 表名 set 欄位1=值 欄位2=值.... where 主鍵名 = 對應的主鍵值;" // 查詢的結果大於0說明表中有這條資料,進行資料更新 // 獲取 更新的 sql 語句 execSql = [NSString stringWithFormat:@"update %@ set %@ where %@ = %@;",tableName,[setValueArray componentsJoinedByString:@","],primaryKey,primaryKeyValue]; }else{ // 不存在資料,進行記錄的插入操作 // 提示這裡 insert into %@(%@) values('%@');,其中的value 要是: 'value1','value2','value2'這樣的格式 execSql = [NSString stringWithFormat:@"insert into %@(%@) values('%@');",tableName,[columnNames componentsJoinedByString:@","],[columnNameValues componentsJoinedByString:@"','"]]; } return [JKSqliteDatabase deal:execSql witUid:uid]; }
六、刪除模型
-
6.1、刪除整個模型,也是刪除對應使用者資料庫中的一個表
/** 刪除模型,也是刪除模型中的全部資料,可以說是刪除整個表 */ +(BOOL)deleteModel:(id)model uid:(NSString *)uid{ Class cls = [model class]; // 獲取表名 NSString *tableName = [JKSqliteModel tableName:cls]; if (![JKSqliteTableTool isTableExists:cls uid:uid]) { // 表不存在預設刪除成功 return YES; } // 組建刪除表的語句 NSString *deleteSql = [NSString stringWithFormat:@"drop table %@;",tableName]; return [JKSqliteDatabase deal:deleteSql witUid:uid]; }
-
6.2、根據主鍵刪除模型中的某一條資料
/** 刪除模型裡面的一條記錄 */ +(BOOL)deleteRecordingModel:(id)model uid:(NSString *)uid{ Class cls = [model class]; // 判斷模型裡面是否有主鍵 if (![cls respondsToSelector:@selector(primaryKey)]) { NSLog(@"請設定模型裡面的主鍵,遵守協議,實現+(NSString *)primaryKey;,d從而得到主鍵資訊"); return NO; } // 拿到主鍵 NSString *primaryKey = [cls primaryKey]; // 模型裡面主鍵的值 id primaryKeyValue = [model valueForKeyPath:primaryKey]; // 獲取表名 NSString *tableName = [JKSqliteModel tableName:cls]; NSString *deleteSql = [NSString stringWithFormat:@"delete from %@ where %@ = %@;",tableName,primaryKey,primaryKeyValue]; return [JKSqliteDatabase deal:deleteSql witUid:uid]; }
-
6.3、根據使用者的條件刪除表中的記錄(根據條件刪除)
+(BOOL)deleteModel:(id)model whereStr:(NSString *)condition uid:(NSString *)uid{ Class cls = [model class]; // 獲取表名 NSString *tableName = [JKSqliteModel tableName:cls]; // 條件小於0直接返回 if (!(condition.length > 0)) { return NO; } // 組建刪除表的語句 NSString *deleteSql = [NSString stringWithFormat:@"delete from %@ where %@;",tableName,condition]; return [JKSqliteDatabase deal:deleteSql witUid:uid]; }
提示:在使用這個條件的方法,要求開發者會 sql 語句,要求高一些
七、查詢模型
-
7.1、查詢模型中所有的資料
/** 查詢模型中所有的資料 */ +(NSArray *)queryAllDataModel:(Class)cls uid:(NSString *)uid{ // 1.查詢前序 // 獲取表名 NSString *tableName = [JKSqliteModel tableName:cls]; // 組合查詢語句 NSString *querySql = [NSString stringWithFormat:@"select * from %@",tableName]; // 2.執行查詢 key value // 模型的屬性名稱 和 屬性值 NSArray <NSDictionary *>*results = [JKSqliteDatabase querySql:querySql witUid:uid]; // 3.處理查詢結果集 -> 模型陣列 return [self parseResults:results withClass:cls]; }
-
7.2、 根據條件來查詢模型裡面的部分資料
+(BOOL)queryDataModel:(Class)cls whereStr:(NSString *)condition uid:(NSString *)uid{ // 1.查詢前序 // 獲取表名 NSString *tableName = [JKSqliteModel tableName:cls]; // 組合查詢語句 NSString *querySql = [NSString stringWithFormat:@"select * from %@ where %@;",tableName,condition]; // 2.執行查詢 key value // 模型的屬性名稱 和 屬性值 NSArray <NSDictionary *>*results = [JKSqliteDatabase querySql:querySql witUid:uid]; // 3.處理查詢結果集 -> 模型陣列 return [self parseResults:results withClass:cls]; }
八、模型中-字典/陣列屬性處理
-
8.1、分析:對於字典和陣列儲存資料庫,我們組要把它們先轉為 NSData,再轉為NSStrinig;在取值的時候,我們進行反序列化,根據模型裡面欄位的型別,把資料庫中的陣列或者字典的字串值轉化為NSData,再反序列化為對應的型別,從而使用 KVC 賦值給對應的key
-
8.2、字典和陣列儲存資料庫的核心程式碼(完整程式碼在
JKSqliteModelTool
裡面的+(BOOL)saveOrUpdateModel:(id)model uid:(NSString *)uid
方法中)// 獲取表中所有的欄位(下面的方法獲取的是字典,我們取其鍵) NSArray *columnNames = [JKSqliteModel classIvarNameTypeDictionary:cls].allKeys; // 獲取模型裡面所有的值陣列 NSMutableArray *columnNameValues = [NSMutableArray array]; for (NSString *columnName in columnNames) { id columnNameValue = [model valueForKeyPath:columnName]; // 判斷型別是不是陣列或者字典 if ([columnNameValue isKindOfClass:[NSArray class]] || [columnNameValue isKindOfClass:[NSDictionary class]]) { // 在這裡我們把陣列或者字典處理成一個字串,才能正確的儲存到資料庫裡面去 // 字典/陣列 -> NSData ->NSString NSData *data = [NSJSONSerialization dataWithJSONObject:columnNameValue options:NSJSONWritingPrettyPrinted error:nil]; columnNameValue = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]; } [columnNameValues addObject:columnNameValue]; }
注意:上面在可變與不可變的處理,可變的陣列或者字典是繼承於不可變的
-
8.3、字典和陣列從資料庫讀取的核心程式碼(具體的程式碼請看
JKSqliteModelTool
裡面的+ (NSArray *)parseResults:(NSArray <NSDictionary *>*)results withClass:(Class)cls
方法)NSString *type = nameTypeDic[key]; // id resultValue = obj; if ([type isEqualToString:@"NSArray"] || [type isEqualToString:@"NSDictionary"]) { // 字串 -> NSData -> 相應的型別 NSData *data = [obj dataUsingEncoding:NSUTF8StringEncoding]; /** NSJSONReadingMutableContainers = (1UL << 0), 可變的 NSJSONReadingMutableLeaves = (1UL << 1), 可變的的型別裡面還有可變的 NSJSONReadingAllowFragments = kNilOptions 不可變 */ resultValue = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]; }else if ([type isEqualToString:@"NSMutableArray"] || [type isEqualToString:@"NSMutableDictionary"]){ // 字串 -> NSData -> 相應的型別 NSData *data = [obj dataUsingEncoding:NSUTF8StringEncoding]; resultValue = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil]; } [model setValue:resultValue forKey:key];
注意:上面在可變與不可變的處理上
9、存在問題-優化方案
-
9.1、存在的問題一:無法建立複雜的表格, 比如新增約束等行為,如下的建立表,很多的欄位,後面都是有一定的約束以及一些預設的值
create table students( id int unsigned primary key auto_increment not null, name varchar(20) default '', age tinyint unsigned default 0, height decimal(5,2), gender enum('男','女','人妖','保密') default "保密", cls_id int unsigned default 0 );
解決辦法:用協議解決,告訴我們每個欄位需要加什麼約束,我們在建立表或者更新欄位的時候 拼接在相應的欄位後面
-
9.2、存在的問題二:無法進行復雜的查詢, 比如多表聯查
解決辦法:暴漏完整的sql語句來執行
10、上面所有步驟組合起來的 JKSqliteKit
的使用
-
10.1、建立專案,匯入
libsqlite3.0.tbd
,步驟和1.1
一樣 -
10.2、主要的類
- JKSqliteDatabase : 資料庫的操作
- JKSqliteModel :模型的操作
- JKSqliteModelTool : 操作模型的類
- JKSqliteTableTool : 有關表的操作
- JKSqliteProtocol :存放協議的內容
-
10.3、具體使用
-
<1>、建立一個
Person
類繼承於NSObject
,設定如下四個屬性#import <Foundation/Foundation.h> NS_ASSUME_NONNULL_BEGIN @interface Person : NSObject /** 人的ID */ @property(nonatomic,assign) int personID; /** 人的名字 */ @property(nonatomic,strong) NSString *personName; /** 人的年齡 */ @property(nonatomic,strong) NSString *personAge; /** 人的身高 */ @property(nonatomic,strong) NSString *personHeight; /** 人的愛好 */ @property(nonatomic,strong) NSArray *personLikes; @end NS_ASSUME_NONNULL_END
-
<2>、匯入協議:
#import "JKSqliteProtocol.h"
,設定personID
(人的ID)為主鍵,主鍵是必須設定的,在協議裡面我們設定了@required
// 匯入協議 #import "JKSqliteProtocol.h" // 設定主鍵 +(NSString *)primaryKey{ return @"personID"; }
-
<3>、找個控制器,建立一個
Person
模型,模型屬性賦值,存入資料庫,我們採用的 使用者機制 ,不同的使用者登入app,對應不同的資料庫,格式是:jk_使用者的ID.sqlite
,未登入是:jk_common.sqlite
,存在於 沙盒的/Library/Caches
下Person *person = [[Person alloc]init]; person.personID = 2; person.personName = @"王小二"; person.personAge = 29; person.personHeight = 178; person. personLikes =@["籃球",@"足球"]; BOOL result = [JKSqliteModelTool saveOrUpdateModel:person uid:@"1"]; if(result){ // 儲存成功 }else{ // 儲存失敗 }
儲存成功的效果圖
-
<4>、取出模型使用
NSArray *resultArray = [JKSqliteModelTool queryAllDataModel:NSClassFromString(@"Person") uid:@"1"]; NSLog(@"resultArray=%@",resultArray); for (Person *person in resultArray) { NSLog(@"personID =%d",person.personID); NSLog(@"personName=%@",person.personName); NSLog(@"personAge=%d",person.personAge); NSLog(@"personHeight=%lf",person.personHeight); NSLog(@"personLikes=%@",person.personLikes); }
-
<5>、把Person模型中表中欄位
personName
改為name
-
在
Peson.h
修改personName
為name
/** 人的名字 */ // @property(nonatomic,strong) NSString *personName; // 改後的名字 @property(nonatomic,strong) NSString *name;
-
在
Peson.m
裡面實現改表中名字的協議+(NSDictionary *)updateFieldNewNameReplaceOldName{ return @{@"name":@"personName"}; }
提示:字典的key是新欄位名,value是舊的欄位名
-
執行替換欄位的方法
BOOL result = [JKSqliteModelTool updateTable:[Person class] uid:@"1"]; if(result){ NSLog(@"修改成功"); }else{ NSLog(@"修改失敗"); }
替換的結果:name 替換 personName
-
-
<6>、刪除Person模型(也可以說是刪除這個Person模型的表)
Person *person = [[Person alloc]init]; BOOL result = [JKSqliteModelTool deleteModel:person uid:@"1"]; if(result){ NSLog(@"刪除模型成功"); }else{ NSLog(@"刪除模型失敗"); }
-
最後,建議看著 demo 讀這篇部落格,裡面有很多的知識可以去學習,這篇部落格僅僅是引出 Realm 做鋪墊,下篇部落格我們再聊