簡(jiǎn)書博客已經(jīng)暫停更新,想看更多技術(shù)博客請(qǐng)到:
在移動(dòng)開發(fā)中鹿蜀,有時(shí)不得不在客戶端本地保存一些數(shù)據(jù)箕慧。在iOS端,我們可以使用plist茴恰,屬性列表等技術(shù)來存儲(chǔ)數(shù)據(jù)颠焦,而相比而下更高端一點(diǎn)的,我們也可以使用數(shù)據(jù)庫(kù)來存儲(chǔ)數(shù)據(jù)往枣。
有趣的是伐庭,很多iOS開發(fā)者沒有去選擇使用蘋果自家的Core Data技術(shù)來操作數(shù)據(jù)庫(kù),而是選擇了FMDB這個(gè)第三方框架婉商。
該框架很好地封裝了操作繁瑣的SQLite語(yǔ)句,讓數(shù)據(jù)庫(kù)的操作更加面向?qū)ο笤眩疑鲜挚煺芍龋T檻低,不用學(xué)習(xí)數(shù)據(jù)庫(kù)的相關(guān)知識(shí)就可以使用自如淳衙。如此優(yōu)秀流行的框架是值得學(xué)習(xí)的蘑秽,于是筆者這兩天研究了一下FMDB饺著。研究后,略有所思肠牲,將它封裝了一下幼衰,寫了一個(gè)Manager
類,最后結(jié)合了一個(gè)Demo演示如何使用這個(gè)類缀雳。
該博客分為兩個(gè)部分:第一個(gè)部分講解筆者封裝的這個(gè)Manager
類元潘;第二部分結(jié)合Demo來體現(xiàn)該類的實(shí)用性经柴。
1. 封裝FMDB
1.1 封裝類的功能
首先看一下這個(gè)類的大名:SJUserInfoManager
- SJ:筆者的名字縮寫,作為前綴,都懂得难述。
- UserInfo:說明這個(gè)類用于操作用戶信息。
- Manager:這個(gè)類只具有工廠方法草冈,省內(nèi)存棺蛛,而且方便使用。
這個(gè)類的功能是:它可以創(chuàng)建一個(gè)關(guān)于用戶信息的表(數(shù)據(jù)庫(kù))敷硅,可以保存功咒,修改,讀取绞蹦,刪除用戶信息力奋。
現(xiàn)在幾乎每個(gè)app都有登錄功能,有登錄就意味著有用戶信息坦辟。有的時(shí)候刊侯,我們需要將一些用戶信息存儲(chǔ)到本地,方便今后的讀取和操作锉走。
而對(duì)于用戶信息滨彻,幾乎永遠(yuǎn)不變的一項(xiàng)就是用戶id,因?yàn)橛脩艨梢愿淖约旱拿峙膊洌约旱淖?cè)手機(jī)號(hào)亭饵,用戶簽名等等,然而用戶id是唯一一成不變的梁厉,后端查找用戶信息一般都通過用戶id來查找辜羊,這不難理解。
因此词顾,這個(gè)封裝類基于用戶id(user_id)八秃,讓使用者可以自主添加一項(xiàng)自定義的用戶信息(可以是用戶名,用戶簽名肉盹,用戶性別等等)昔驱,從而形成一個(gè)只具有兩個(gè)縱行的表(第一個(gè)縱行是默認(rèn)的字段:user_id,第二個(gè)縱行是自定義字段,可以是user_name等等)上忍。
這樣一來骤肛,我們就可以生成很多基于用戶id的表:可以是用戶姓名的表纳本,可以是用戶出生日期的表,可以是用戶手機(jī)號(hào)的表等等腋颠。
1.2 API介紹
該封裝類的API一共有五個(gè)繁成,分別是:
- 創(chuàng)建表格
- 更新用戶信息(添加&修改)
- 查詢某個(gè)用戶的信息
- 查詢?nèi)坑脩舻男畔?/li>
- 刪除某個(gè)用戶的信息
下面開始一一講解:
1. 創(chuàng)建表格
/*
********** Create table with tableName and fieldName **********
*
* @param dataBaseName tableNameString (表的名字)
* @param userInfoField fieldNameString(自定義字段名)
*
* @return if the table is successfully created
*
*/
+ (BOOL)createDataBaseWithName:(NSString *)dataBaseName andUserInfoField:(NSString *)userInfoField;
這個(gè)方法的意圖很明顯,只要傳進(jìn)去表的名字和自定義字段的名字就能創(chuàng)造一個(gè)表淑玫。
- 創(chuàng)建成功巾腕,返回YES;
- 創(chuàng)建失敗混移,返回NO祠墅。
而且這個(gè)表有一個(gè)默認(rèn)的字段:user_id。因?yàn)橥ㄟ^這個(gè)類創(chuàng)建用戶信息的表是基于用戶id來操作的歌径,前面已有說明毁嗦。
2. 更新用戶信息(添加&修改)
/*
********** update specific userInfo with specific userID and userInfoField and userInfoValue **********
*
* @param dataBaseName tableNameString (表的名字)
* @param userID userIDString(用戶id的值)
* @param userInfoField fieldNameString(自定義字段名)
* @param userInfoValue userInfoValueString(字段對(duì)應(yīng)的值)
*
* @return the result of updating specific userInfo
*
*/
+ (NSString *)updateUserInfoIntoDataBase:(NSString *)dataBaseName withUserID:(NSString *)userID andUserInfoField:(NSString *)userInfoField andUserInfoValue:(NSString *)userInfoValue;
這個(gè)方法用于更新用戶信息,傳入表的名字回铛,用戶id狗准,自定義字段名,和自定義字段對(duì)應(yīng)的值茵肃。
- 如果輸入的表不存在腔长,則返回相應(yīng)的錯(cuò)誤信息。
- 如果輸入的用戶id已經(jīng)存在验残,就更新對(duì)應(yīng)的用戶信息捞附。
- 如果輸入的用戶id不存在,就添加這個(gè)用戶的信息您没。
3. 查詢某個(gè)用戶的信息
/*
********** Query specific userInfoValue with tableName and userID and userInfoField **********
*
* @param dataBaseName tableNameString (表的名字)
* @param userID userIDString(用戶id的值)
* @param userInfoField fieldNameString(自定義字段名)
*
* @return specific userInfoValue (表內(nèi)某用戶id對(duì)應(yīng)的用戶信息)
*
*/
+ (NSString *)queryUserInfoInDataBase:(NSString *)dataBaseName WithUserID:(NSString *)userId andUserInfoField:(NSString *)userInfoField;
該方法用于查詢某個(gè)用戶的信息鸟召,傳入表的名字,用戶id和自定義字段名氨鹏。
- 如果輸入的表不存在欧募,則返回相應(yīng)的錯(cuò)誤信息。
- 如果輸入的用戶id存在仆抵,則返回對(duì)應(yīng)的信息跟继。
- 如果輸入的用戶id不存在,則返回相應(yīng)的錯(cuò)誤信息镣丑。
4. 查詢?nèi)坑脩舻男畔?/h4>
/*
********** Query all userInfos in this table with userInfoField **********
*
* @param dataBaseName tableNameString (表的名字)
* @param userInfoField fieldNameString(自定義字段名)
*
* @return all the userInfos in this table (表內(nèi)所有的用戶信息)
*
*/
+ (NSDictionary *)queryUserInfosInDataBase:(NSString *)dataBaseName andUserInfoField:(NSString *)userInfoField;
該方法用戶獲取某個(gè)表內(nèi)的所有用戶信息舔糖,傳入表的名字和自定義字段名即可。
返回的字典里包含一個(gè)數(shù)組莺匠,數(shù)組元素為表的每一行的信息金吗。每一行的信息是一個(gè)字典:
- 其中一個(gè)key為默認(rèn)的字段名:user_id,它的值為對(duì)應(yīng)的user_id的值。
- 另一個(gè)key為添加的自定義字段名辽聊,它對(duì)應(yīng)的值為該字段對(duì)應(yīng)的值。
5. 刪除某個(gè)用戶的信息
/*
********** Delete specific userInfo with specific userID **********
*
* @param dataBaseName tableNameString (表的名字)
* @param userId userIDString(用戶id的值)
*
* @return the result of deleting specific userInfo (刪除的結(jié)果)
*
*/
+ (NSString *)deleteUserInfoInDataBase:(NSString *)dataBaseName WithUserID:(NSString *)userId;
該方法用于刪除表里的某個(gè)用戶信息期贫,只要傳入表的名字和用戶id即可跟匆,可以刪除表中對(duì)應(yīng)的一整行信息。同樣地通砍,如果輸入的表不存在玛臂,則返回相應(yīng)的錯(cuò)誤信息。
/*
********** Query all userInfos in this table with userInfoField **********
*
* @param dataBaseName tableNameString (表的名字)
* @param userInfoField fieldNameString(自定義字段名)
*
* @return all the userInfos in this table (表內(nèi)所有的用戶信息)
*
*/
+ (NSDictionary *)queryUserInfosInDataBase:(NSString *)dataBaseName andUserInfoField:(NSString *)userInfoField;
該方法用戶獲取某個(gè)表內(nèi)的所有用戶信息舔糖,傳入表的名字和自定義字段名即可。
返回的字典里包含一個(gè)數(shù)組莺匠,數(shù)組元素為表的每一行的信息金吗。每一行的信息是一個(gè)字典:
/*
********** Delete specific userInfo with specific userID **********
*
* @param dataBaseName tableNameString (表的名字)
* @param userId userIDString(用戶id的值)
*
* @return the result of deleting specific userInfo (刪除的結(jié)果)
*
*/
+ (NSString *)deleteUserInfoInDataBase:(NSString *)dataBaseName WithUserID:(NSString *)userId;
該方法用于刪除表里的某個(gè)用戶信息期贫,只要傳入表的名字和用戶id即可跟匆,可以刪除表中對(duì)應(yīng)的一整行信息。同樣地通砍,如果輸入的表不存在玛臂,則返回相應(yīng)的錯(cuò)誤信息。
如果覺得有點(diǎn)抽象的話封孙,可以看下面這個(gè)Demo迹冤,可以看到該封裝類的具體使用方法。
2. Demo演示
在這個(gè)Demo中虎忌,我們要在表里添加的自定義字段名(fieldNameString)為:“user_name”泡徙。也就是說這個(gè)表將保存用戶id和用戶名信息。
2.1 需求
- 在插入板塊中插入用戶信息(用戶id和用戶名)膜蠢。
- 在查詢板塊中堪藐,根據(jù)輸入的用戶id,可以顯示對(duì)應(yīng)的用戶名挑围。如果沒有對(duì)應(yīng)的用戶id礁竞,則顯示“沒有對(duì)應(yīng)id”。
- 在刪除板塊中杉辙,根據(jù)輸入的用戶id模捂,可以刪除對(duì)應(yīng)的用戶信息(包括用戶id和用戶名,也就是刪除了表的一整行)蜘矢。如果沒有對(duì)應(yīng)的用戶id狂男,則顯示“沒有對(duì)應(yīng)id”。
- 點(diǎn)擊導(dǎo)航欄右側(cè)的按鈕硼端,進(jìn)入“用戶信息列表頁(yè)”并淋。在這一頁(yè)顯示當(dāng)前表里的全部用戶的信息(在cell的textLabel里顯示用戶名;在cell的detailTextLabel里顯示用戶id)珍昨。
2.2 效果圖
2.3 代碼講解
1. 最先導(dǎo)入這個(gè)封裝類和FMDB框架:
#import "SJUserInfoManager.h"
2. 因?yàn)楸淼拿趾妥远x字段是固定的镣典,所以就以宏來定義了:
#define DATABASENAME @"userInfoTable" //表的名字
#define USERINFOFIELD @"user_name" //自定義字段的名字
3. 添加幾個(gè)輸入框的屬性兔毙,獲取輸入框的內(nèi)容;和查詢結(jié)果顯示Label:
@property (strong, nonatomic) IBOutlet UITextField *insertUserIdTextfield; //插入輸入框:輸入用戶id
@property (strong, nonatomic) IBOutlet UITextField *insertUserInfoValueTextfiled;//插入收入框:輸入用戶名
@property (strong, nonatomic) IBOutlet UITextField *queryUserIdTextfield; //查詢輸入框:輸入用戶id
@property (strong, nonatomic) IBOutlet UILabel *queryUserInfoValueLabel; //查詢結(jié)果顯示Label:顯示用戶id對(duì)應(yīng)的用戶名
@property (strong, nonatomic) IBOutlet UITextField *deleteUserIdTextField; //刪除輸入框:輸入用戶id
4. 下面看一下封裝的增改&查&刪的代碼:
//插入用戶信息
- (IBAction)insertAction:(id)sender {
NSString *result = @"";
if (self.insertUserInfoValueTextfiled.text.length == 0) {
result = @"Please Input UserID!";//沒有輸入用戶id就點(diǎn)擊了插入按鈕
}else{
result = [SJUserInfoManager updateUserInfoIntoDataBase:DATABASENAME withUserID:self.insertUserIdTextfield.text andUserInfoField:USERINFOFIELD andUserInfoValue:self.insertUserInfoValueTextfiled.text];
}
[self showAlertWithTitle:result];
}
//查詢用戶信息
- (IBAction)queryUserInfoValue:(UIButton *)sender {
NSString *result = @"";
if (self.queryUserIdTextfield.text.length == 0) {
result = @"Please Input UserID!";//沒有輸入用戶id就點(diǎn)擊了查詢按鈕
self.queryUserInfoValueLabel.text = @"";//重置查詢輸入框
}else{
result = [SJUserInfoManager queryUserInfoInDataBase:DATABASENAME WithUserID:self.queryUserIdTextfield.text andUserInfoField:USERINFOFIELD];
self.queryUserInfoValueLabel.text = result;
[self showAlertWithTitle:result];
}
[self showAlertWithTitle:result];
}
//刪除用戶信息
- (IBAction)deleteUserInfoWithUserID:(UIButton *)sender {
NSString *result = @"";
if (self.deleteUserIdTextField.text.length == 0) {
result = @"Please Input UserID!";
}else{
result = [SJUserInfoManager deleteUserInfoInDataBase:DATABASENAME WithUserID:self.deleteUserIdTextField.text];
}
[self showAlertWithTitle:result];
}
其實(shí)不難看出兄春,除了處理錯(cuò)誤信息的代碼以外澎剥,數(shù)據(jù)庫(kù)的操作代碼是非常簡(jiǎn)潔的:都是一行結(jié)束,而且返回一個(gè)結(jié)果字符串或者布爾值赶舆。
5. 在進(jìn)入第二頁(yè)之前哑姚,需要查詢表內(nèi)所有的用戶信息并傳遞給第二個(gè)頁(yè)面的VC:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.destinationViewController isKindOfClass:[DataListTableViewController class]]) {
if ([segue.identifier isEqualToString:@"userInfosList"]) {
NSDictionary *userInfosDict = [SJUserInfoManager queryUserInfosInDataBase:DATABASENAME andUserInfoField:USERINFOFIELD];
DataListTableViewController *dataListVc = (DataListTableViewController *)segue.destinationViewController;
dataListVc.userInfosDict = userInfosDict;
}
}
}
6. 在第二頁(yè)的viewDidLoad方法里獲取用戶信息列表祭饭,并刷新表格將其顯示出來:
- (void)viewDidLoad {
[super viewDidLoad];
NSString *alertTitle = [self.userInfosDict objectForKey:@"result"];
[self showAlertWithTitle:alertTitle];
NSArray *userInfosArray = [self.userInfosDict objectForKey:@"userInfosArray"];
if ([userInfosArray count] != 0) {
self.userInfosArray = userInfosArray;
[self.tableView reloadData];
}
}
想知道Demo是如何實(shí)現(xiàn)的么?
Demo傳送門:SJUserInfoManager - GitHub
如果可以給星星叙量,或者給筆者提意見倡蝙,那就再好不過啦~
最后的話
說來慚愧,筆者封裝的這個(gè)類的功能還是很有局限性的:
- 操作表格前必須創(chuàng)建一次表格(一次就可以)绞佩。
- 只支持NSString類型的值寺鸥。
- 除user_id字段以外只支持一個(gè)自定義字段。
- 不同的自定義字段必須對(duì)應(yīng)不同的表格名品山,也就是說不同的自定義字段不能對(duì)應(yīng)同一個(gè)表格名胆建。
- 數(shù)據(jù)庫(kù)操作API的返回值還不夠完善,最好以枚舉類型返回肘交,有待改進(jìn)笆载。
- 沒有使用FMDB的隊(duì)列API。
雖然這個(gè)封裝很簡(jiǎn)單涯呻,但是筆者始終贊同學(xué)習(xí)的最終目的在于應(yīng)用和創(chuàng)造這句話宰译。如果只是用眼睛看FMDB框架的API或是復(fù)制粘貼一些別人寫好的FMDB的應(yīng)用代碼,那么其實(shí)是意義不大的魄懂。
如果在學(xué)習(xí)后沿侈,可以融會(huì)貫通,將學(xué)到的知識(shí)可以按照自己的意圖加以改進(jìn)和運(yùn)用的話市栗,那么相對(duì)于“搬運(yùn)工”式學(xué)習(xí)來說缀拭,顯然收獲更大。
這是筆者第一個(gè)開源項(xiàng)目填帽,雖然簡(jiǎn)單蛛淋,算上優(yōu)化和改bug只寫了大概3個(gè)小時(shí),但是畢竟是開源的第一步篡腌,對(duì)自己的鼓勵(lì)還是蠻大的褐荷,以后還會(huì)封裝優(yōu)化更多的庫(kù),加油~
本文已同步到個(gè)人博客:傳送門嘹悼,歡迎常來^^
本文已在版權(quán)印備案叛甫,如需轉(zhuǎn)載請(qǐng)?jiān)L問版權(quán)印。48422928
-------------------------------- 2018年7月16日更新 --------------------------------
注意注意Q罨铩F浼唷!
筆者在近期開通了個(gè)人公眾號(hào)限匣,主要分享編程抖苦,讀書筆記,思考類的文章。
- 編程類文章:包括筆者以前發(fā)布的精選技術(shù)文章锌历,以及后續(xù)發(fā)布的技術(shù)文章(以原創(chuàng)為主)贮庞,并且逐漸脫離 iOS 的內(nèi)容,將側(cè)重點(diǎn)會(huì)轉(zhuǎn)移到提高編程能力的方向上究西。
- 讀書筆記類文章:分享編程類贸伐,思考類,心理類怔揩,職場(chǎng)類書籍的讀書筆記。
- 思考類文章:分享筆者平時(shí)在技術(shù)上脯丝,生活上的思考商膊。
因?yàn)楣娞?hào)每天發(fā)布的消息數(shù)有限制,所以到目前為止還沒有將所有過去的精選文章都發(fā)布在公眾號(hào)上宠进,后續(xù)會(huì)逐步發(fā)布的晕拆。
而且因?yàn)楦鞔蟛┛推脚_(tái)的各種限制,后面還會(huì)在公眾號(hào)上發(fā)布一些短小精干材蹬,以小見大的干貨文章哦~
掃下方的公眾號(hào)二維碼并點(diǎn)擊關(guān)注实幕,期待與您的共同成長(zhǎng)~