面試之家只是為了學(xué)習(xí)和交流使用Weex蒸健,題庫(kù)等內(nèi)容不可用于商業(yè)項(xiàng)目
一開(kāi)始面試之家題庫(kù)是在服務(wù)端,后來(lái)由于后端開(kāi)發(fā)效率和界面加載時(shí)間太長(zhǎng)等原因窗慎,所以我決定將題庫(kù)移植到客戶端铺坞,未來(lái)打算做成動(dòng)態(tài)插入本地?cái)?shù)據(jù)庫(kù)的方式,實(shí)現(xiàn)數(shù)據(jù)庫(kù)題目的更新职车。事實(shí)證明數(shù)據(jù)庫(kù)移植到本地瘫俊,能大大提高加載效率,比如Java科目列表有四百多道題悴灵,從讀取到頁(yè)面渲染完成只用了0.3秒
數(shù)據(jù)庫(kù)整理
注意在將數(shù)據(jù)庫(kù)打包到工程中時(shí)扛芽,讀沒(méi)問(wèn)題,但是寫(xiě)偶爾會(huì)失敗积瞒,所以正確的做法是在程序啟動(dòng)時(shí)將數(shù)據(jù)庫(kù)移到沙盒中
- (void)moveDB{
NSString * docPath = [[NSBundle mainBundle] pathForResource:@"WX" ofType:@"db"];
NSString * appDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *filePath = [appDir stringByAppendingPathComponent:@"WX.db"];
if(![fileManager fileExistsAtPath:filePath]) {
BOOL filesPresent = [self copyMissingFile:docPath toPath:appDir];
if (filesPresent) {
NSLog(@"Copy Success");
}
else
{
NSLog(@"Copy Fail");
}
}
else
{
NSLog(@"文件已存在");
}
}
- (BOOL)copyMissingFile:(NSString *)sourcePath toPath:(NSString *)toPath
{
BOOL retVal = YES; // If the file already exists, we'll return success…
NSString * finalLocation = [toPath stringByAppendingPathComponent:[sourcePath lastPathComponent]];
if (![[NSFileManager defaultManager] fileExistsAtPath:finalLocation]){
retVal = [[NSFileManager defaultManager] copyItemAtPath:sourcePath toPath:finalLocation error:NULL];
}
return retVal;
}
在InterviewHome
項(xiàng)目的原生模塊中川尖,我單獨(dú)準(zhǔn)備了一個(gè)StorageViewController
來(lái)負(fù)責(zé)整理數(shù)據(jù)庫(kù),這個(gè)類里有以下兩個(gè)功能
-
創(chuàng)建數(shù)據(jù)庫(kù)
- (void)createAllSubjectTable { NSString *table = @"CREATE TABLE IF NOT EXISTS Subjects_Table (s_id integer PRIMARY KEY AUTOINCREMENT NOT NULL,_id varchar(128),content varchar(128),groupId varchar(128), totalNum integer, unlockTotal integer)"; if ([_db open]) { BOOL sucess = [_db executeStatements:table]; if (sucess) { NSLog(@"sucess %@",DB_SANDBOX_TABLE); } else { NSLog(@"faile %@",DB_SANDBOX_TABLE); } [_db close]; } - (void)createAllClassTable { NSString *table = @"CREATE TABLE IF NOT EXISTS Class_Table (c_id integer PRIMARY KEY AUTOINCREMENT NOT NULL,s_id integer(20) NOT NULL,pageID varchar(128),showContent varchar(128),integral integer(20),title varchar(128), questcount integer(128))"; if ([_db open]) { BOOL sucess = [_db executeStatements:table]; if (sucess) { NSLog(@"sucess %@",DB_SANDBOX_TABLE); } else { NSLog(@"faile %@",DB_SANDBOX_TABLE); } [_db close]; } } - (void)createQuestionsTable { NSString *table = @"CREATE TABLE IF NOT EXISTS Questions_Table (q_id integer PRIMARY KEY AUTOINCREMENT NOT NULL,_id varchar(128),questionTitle varchar(128),classId varchar(128),isCollection integer,answer varchar(128),author varchar(128),createTime varchar(128), number integer)"; if ([_db open]) { BOOL sucess = [_db executeStatements:table]; if (sucess) { NSLog(@"sucess %@",DB_SANDBOX_TABLE); } else { NSLog(@"faile %@",DB_SANDBOX_TABLE); } [_db close]; }
這里分別創(chuàng)建了三張表茫孔,Subjects_Table
科目表叮喳、 Class_Table
每個(gè)科目下有多少套題 、Questions_Table
題庫(kù)表 三張表的關(guān)系是
Subjects_Table
>Class_Table
>Questions_Table
-
插入數(shù)據(jù)庫(kù)
這里有一個(gè)比較難處理的地方缰贝,因?yàn)榻涌谝淮涡园阉械念}目給返回了馍悟,并且是無(wú)序的,怎么把每道題根據(jù)題目所屬的科目排列起來(lái)呢剩晴,這里我引入了一個(gè)字典類型的額外空間
- (void)insertAllQuestions:(NSArray *)questions { if (!questions.count) { return; } if ([_db open]) { NSInteger num = 1; NSMutableDictionary *recodDic = [NSMutableDictionary dictionary]; for (NSInteger i = 0; i < questions.count; i ++) { @autoreleasepool { [_db beginTransaction]; BOOL isRollBack = NO; @try { NSDictionary *obj = questions[i]; NSString *_id = obj[@"_id"]; NSString *questionTitle = obj[@"questionTitle"]; NSString *classId = obj[@"classId"]; NSInteger isCollection = [obj[@"isCollection"] integerValue]; NSString *answer = obj[@"answer"]; NSString *author = obj[@"author"]; NSString *createTime = obj[@"createTime"]; if (recodDic[classId]) { num = [recodDic[classId] integerValue]; num++; } else { num = 1; } [recodDic setObject:@(num) forKey:classId]; [_db executeUpdate:@"insert into Questions_Table(_id, questionTitle, classId, isCollection, answer, author, createTime, number) values (?, ?, ?, ?, ?, ?, ?, ?)", _id, questionTitle, classId, @(isCollection), answer, author, createTime, @(num)]; } @catch (NSException *exception) { isRollBack = true; [self->_db rollback]; } @finally { if (!isRollBack) { [self->_db commit]; } } } } } }
因?yàn)閿?shù)據(jù)類型中只給了 classID
锣咒,并沒(méi)有給 classID
下的題目編號(hào),所以在做題目詳情的時(shí)候李破,沒(méi)法讀取上一題下一題宠哄,所以要在本地給每個(gè)classID
下的題目創(chuàng)建一個(gè)序號(hào) 這里就用recodDic
記錄classID
下的序號(hào),如果沒(méi)有classID
嗤攻,則新加入一個(gè)同時(shí)num
為1毛嫉,如果有classID
就取出num
+1,并重新存入字典,這樣就整理出了每個(gè)classID
下有多少道題妇菱,同時(shí)為每道題加入一個(gè)編號(hào)
這里題量很大承粤,加入事物暴区,能保證插入的效率
Weex和FMDB交互
Weex
和FMDB
交互的方式就是通過(guò)自定義Module
- 第一步 本地寫(xiě)好增刪改查的語(yǔ)句
- (void)insertSubjects:(NSArray *)subjects;
- (void)insertAllQuestions:(NSArray *)questions;
- (NSArray *)seletAllSubjects;
- (NSArray *)selectQuestionsWithClassID:(NSString *)classID;
- (NSDictionary *)selectQuestionDetail:(NSString *)questionID classID:(NSString *)classID;
- (NSInteger)updateCollection:(NSString *)questionID classID:(NSString *)classID status:(NSInteger)status;
- (NSArray *)selectAllCollertion;
-
第二步 自定義Module類
自定義
Module
類,需要繼承WXModuleProtocol
協(xié)議,使用WX_EXPORT_METHOD
將方法暴露給JavaScript
調(diào)用辛臊, 使用@synthesize weexInstance
可對(duì)Weex
頁(yè)面做一個(gè)弱引用,拿到這個(gè)頁(yè)面上的信息
WX_EXPORT_METHOD(@selector(selectAllSubjects:))
WX_EXPORT_METHOD(@selector(selectQuestionsWithClassID:callBack:))
WX_EXPORT_METHOD(@selector(selectQuestionDetailWithClassID:index:callBack:))
WX_EXPORT_METHOD(@selector(updateCollectionStatus:classID:status:callBack:))
WX_EXPORT_METHOD(@selector(selectAllCollertionWithcallBack:))
- (void)selectAllSubjects:(WXKeepAliveCallback)callbak {
NSArray *array = [[WXDBManger database]seletAllSubjects];
if (callbak) {
callbak(array, false);
}
}
- (void)selectQuestionsWithClassID:(NSString *)classID callBack:(WXKeepAliveCallback)callback {
NSArray *array = [[WXDBManger database] selectQuestionsWithClassID:classID];
if (callback) {
callback(array, false);
}
}
- (void)selectQuestionDetailWithClassID:(NSString *)classID index:(NSString *)number callBack:(WXKeepAliveCallback)callback {
if (callback) {
callback([[WXDBManger database]selectQuestionDetail:number classID:classID], false);
}
}
- (void)updateCollectionStatus:(NSString *)questionID classID:(NSString *)classID status:(NSInteger)status callBack:(WXKeepAliveCallback)callback {
if (callback) {
callback([NSString stringWithFormat:@"%zi",[[WXDBManger database]updateCollection:questionID classID:classID status:status]], false);
}
}
- (void)selectAllCollertionWithcallBack:(WXKeepAliveCallback)callback {
if (callback) {
callback([[WXDBManger database]selectAllCollertion], false);
}
}
-
第三步 將自定義Module注冊(cè)到 WeexSDK
[WXSDKEngine registerModule:@"GL_DatabaseModule" withClass:NSClassFromString(@"WXDatabaseModule")];
第四部 JS調(diào)用
首先定義Module
變量
var db = weex.requireModule('GL_DatabaseModule');
然后就可以調(diào)用本地拋出的函數(shù)了, JS調(diào)用OC函數(shù)仙粱,只需寫(xiě)第一個(gè)參數(shù)前的方法名,多參數(shù)的話直接傳參數(shù)就行彻舰,回調(diào)值用一個(gè)匿名函數(shù)來(lái)接受
db.selectQuestionsWithClassID(this.pageID,function(data){
self.dataArray = data;
})
這樣一個(gè)完整的Module注冊(cè)流程就完成了
END
面試之家是一款用Weex
寫(xiě)的多頁(yè)面應(yīng)用伐割,目前還在與蘋(píng)果審核斗爭(zhēng)中,對(duì)Weex
感興趣的小伙們可以去關(guān)注一下刃唤,謝謝隔心!