我有一个使用FMDB的应用程序,并在应用程序启动后立即执行更新(仅一次)。更新非常繁重,需要12到20秒才能完成。我正在使用FMDatabaseQueue和基于单例类的事务。
======== DB.h ====================
@interface DB : NSObject{
FMDatabaseQueue *dbqueue;
NSArray *queriesCreateSchema;
NSString *dbFullPath;
}
@property (nonatomic, strong) FMDatabaseQueue *dbqueue;
==================================
======== DB.m ====================
- (id)initWithFullPath: (NSString*)fullPath {
if (self = [super init]) {
dbFullPath = fullPath;
//Opening/Creating the serial queue
dbqueue = [FMDatabaseQueue databaseQueueWithPath:dbFullPath];
if (dbqueue == nil){
return nil;
}
queriesCreateSchema = [NSArray arrayWithObjects:DBQUERY_ENABLE_FOREIGN_KEYS,
DBQUERY_CREATE_DB,
DBQUERY_CREATE_USERS,
DBQUERY_CREATE_BOOKS,
DBQUERY_INDEX_BOOKS,
DBQUERY_CREATE_BOOKUSER,
DBQUERY_CREATE_PAGES,
DBQUERY_CREATE_PAGEUSER,
DBQUERY_CREATE_TAGS,
DBQUERY_CREATE_TAGBOOK,
DBQUERY_CREATE_CATEGORIES,
DBQUERY_CREATE_CATBOOK,
nil];
}
return self;
}
================================== ======== DBManager.h ====================
@interface DBManager : NSObject <CommsManagerDelegate> {
__weak id <DBMDelegate> delegate;
DB *database;
NSString *dbFullPath;
}
@property (nonatomic, weak) id <DBMDelegate> delegate;
@property (nonatomic, strong) DB *database;
@property (nonatomic, strong) NSString *dbFullPath;
=========================================
======== DBManager.m ====================
-(BOOL) parseMetaDataDict: (NSDictionary*) serverDict {
/// Getting the lists of books from the Server's JSON dictionary
NSDictionary *dictAllBooks = [serverDict objectForKey:@"Books"];
int bookNum=0;
int totalBooks = [[dictAllBooks valueForKey:@"Book"] count];
// Updates the UI
[delegate dbmNumberOfBooksProcessedByDB:totalBooks];
/// Browsing it book by book
for (id serverDictBook in [dictAllBooks valueForKey:@"Book"]){
bookNum++;
/// Trimming book from the server and placing it into the local book dictionary
BookDict *bookDict = [[BookDict alloc]initWithServerDict:serverDictBook];
__block BOOL isError = NO;
/// Sending the queries into the serial queue
[database.dbqueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
/// Inserting book into the BOOKS table
if(![db executeUpdate:DBUPDATE_INSERT_BOOK withParameterDictionary:bookDict.dictionary])
{
isError = YES;
DDLogWarn(@"%@", [db lastErrorMessage]);
*rollback = YES;
return; // Carefull - It returns from the transaction, not the function
}
}];
if (isError){
return NO;
}
__block NSString *bookID;
/// Getting the bookID automatically generated by the DB
NSString *query = [NSString stringWithFormat:@"SELECT bookID FROM BOOKS where isbn = '%@'", [bookDict.dictionary valueForKey:@"isbn"]];
[database.dbqueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
FMResultSet *result = [db executeQuery:query];
if([result next])
{
int num = [result intForColumnIndex:0];
bookID = [NSString stringWithFormat:@"%d", num];
}
else{
isError = YES;
DDLogWarn(@"%@", [db lastErrorMessage]);
*rollback = YES;
return; // Carefull - It returns from the transaction, not the function
}
}];
if (isError){
return NO;
}
int numPages = [[serverDictBook objectForKey:@"numberOfPages"] intValue];
/// Browsing the book page by page
///VCC Today probably replace by 0
for (int i=1; i<=numPages; i++)
{
PageDict *pageDict = [[PageDict alloc]initWithPage:i andBookID:bookID ofServerDict:serverDictBook];
__block BOOL isError = NO;
/// Sending the queries into the serial queue
[database.dbqueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
/// Inserting page into the PAGES table
if(![db executeUpdate:DBUPDATE_INSERT_PAGE withParameterDictionary:pageDict.dictionary])
{
isError = YES;
DDLogWarn(@"%@", [db lastErrorMessage]);
*rollback = YES;
return; // Carefull - It returns from the transaction, not the function
}
}];
if (isError)
return NO;
}
__block NSString *catID;
/// Browsing the book categories one by one
for (id serverCatDict in [serverDictBook valueForKey:@"categories"]){
__block BOOL isError = NO;
/// Sending the queries into the serial queue
[database.dbqueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
/// Inserting row into the CATEGORY table
if(![db executeUpdate:DBUPDATE_INSERT_CATEGORY withParameterDictionary:serverCatDict])
{
isError = YES;
DDLogWarn(@"%@", [db lastErrorMessage]);
*rollback = YES;
return; // Carefull - It returns from the transaction, not the function
}
/// Getting the catID automatically generated by the DB
NSString *query = [NSString stringWithFormat:@"SELECT catID FROM CATEGORIES where name = '%@'", [serverCatDict valueForKey:@"name"]];
FMResultSet *result = [db executeQuery:query];
if([result next])
{
catID = [result stringForColumnIndex:0];
}
else{
isError = YES;
DDLogError(@"%@", [db lastErrorMessage]);
*rollback = YES;
return; // Carefull - It returns from the transaction, not the function
}
CatBookDict *catBookDict = [[CatBookDict alloc] initWithCatID:catID andBookID:bookID];
/// Inserting row into the CATBOOK table
if(![db executeUpdate:DBUPDATE_INSERT_CATBOOK withParameterDictionary:catBookDict.dictionary])
{
isError = YES;
DDLogError(@"%@", [db lastErrorMessage]);
*rollback = YES;
return; // Carefull - It returns from the transaction, not the function
}
}];
if (isError)
return NO;
}
// /// Browsing the book categories one by one
// for (id serverCatDict in [serverDictBook valueForKey:@"name"]){
//
// __block BOOL isError = NO;
//
// CatBookDict *catBookDict = [[CatBookDict alloc] initWithCatID:[serverCatDict valueForKey:@"catID"]];
//
// /// Sending the queries into the serial queue
// [database.dbqueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
// andBookID:bookID];
// /// Inserting row into the CATBOOK table
// if(![db executeUpdate:DBUPDATE_INSERT_CATBOOK withParameterDictionary:catBookDict.dictionary])
// {
// isError = YES;
// DDLogVerbose(@"%@", [db lastErrorMessage]);
// *rollback = YES;
// return; // Carefull - It returns from the transaction, not the function
// }
// }];
//
// if (isError)
// return NO;
//
// }
[database.dbqueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
FMResultSet *result = [db executeQuery:query];
if([result next])
{
int num = [result intForColumnIndex:0];
bookID = [NSString stringWithFormat:@"%d", num];
}
else{
isError = YES;
DDLogError(@"%@", [db lastErrorMessage]);
*rollback = YES;
return; // Carefull - It returns from the transaction, not the function
}
}];
if (isError){
return NO;
}
/// Browsing the book tags one by one
for (id serverTagDict in [serverDictBook valueForKey:@"tags"]){
// TagDict *tagDict = [[TagDict alloc] initWithServerDict:serverTagDict[0]];
// TagBookDict *tagBookDict = [[TagBookDict alloc] initWithTagID:[serverTagDict valueForKey:@"tagID"]
// andBookID:bookID];
__block BOOL isError = NO;
/// Sending the queries into the serial queue
[database.dbqueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
/// Inserting tag into the TAGS table
if(![db executeUpdate:DBUPDATE_INSERT_TAG withParameterDictionary:serverTagDict])
{
isError = YES;
DDLogError(@"%@", [db lastErrorMessage]);
*rollback = YES;
return; // Carefull - It returns from the transaction, not the function
}
// /// Inserting the row into the TAGBOOK table
// if(![db executeUpdate:DBUPDATE_INSERT_TAGBOOK withParameterDictionary:tagBookDict.dictionary])
// {
// isError = YES;
// DDLogVerbose(@"%@", [db lastErrorMessage]);
// *rollback = YES;
// return; // Carefull - It returns from the transaction, not the function
// }
}];
if (isError)
return NO;
}
// Updates the UI
[delegate dbmBookProcessedByDB:bookNum];
}
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (![defaults objectForKey:@"firstSynced"]){
[defaults setObject:[NSDate date] forKey:@"firstSynced"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
return TRUE;
我有一个视图控制器,通过调用前面的方法&#34; parseMetaDataDict&#34;来使用DBManager类。对于书籍的每次迭代都会被处理,并且插入会在数据库中进行。我正在使用委托并在循环中更新UI。
============= SplashViewController.h ============================
- (无效)dbmBookProcessedByDB:(INT)bookNum {
dispatch_async(dispatch_get_main_queue(), ^(void){
//Run UI Updates
NSString *strMsg = [NSString stringWithFormat:@"DB Processing Book %d / %d", bookNum, _totalBooksToBeDownloaded];
[self.progressBar setText:strMsg];;
if (bookNum == _totalBooksToBeDownloaded){
[self.progressBar setText:@"Books library has successfully been updated"];
[self.progressBar setNeedsDisplay];
[self performSegueWithIdentifier:@"splashToHome" sender:self];
}
});
}
=========================================
进度条的更新未发生。我相信dispatch_async是不必要的。调试显示它通过dispatch_async并且从不进入内部。
FMDB队列是否阻止整个主线程。每次处理图书时,如何定期更新标签?
答案 0 :(得分:3)
在FMDB中,dispatch_sync
函数用于将事务块放入串行队列。
dispatch_sync
的{{3}}说:
作为优化,此函数调用当前的块 尽可能的线程。
我认为这是为什么调用-inTransaction:
可能会阻止主线程。
尝试从后台线程调用-inTransaction:
。为此,您可以通过CGD将for
周期的正文放入Documentation,如下所示:
-(BOOL) parseMetaDataDict: (NSDictionary*) serverDict {
...
/// Browsing it book by book
for (id serverDictBook in [dictAllBooks valueForKey:@"Book"]){
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(void){
... all -inTransaction: calls are here
dispatch_async(dispatch_get_main_queue(), ^(void){
// Updates the UI
[delegate dbmBookProcessedByDB:bookNum];
});
});
}
注意:最好在一个范围内的线程之间跳转,以使代码看起来清晰,这样您也可以从dispatch_async(dispatch_get_main_queue(), ...)
-dbmBookProcessedByDB
体内for
移动{{1}}如上面的代码所示。