From bf521c81a15cb4599b9b47fa913d02bdc4ddee3a Mon Sep 17 00:00:00 2001 From: jackleemeta Date: Thu, 2 Mar 2023 18:43:42 +0800 Subject: [PATCH 1/5] fix: on iOS db locked error --- ios/Classes/FlutterDownloaderPlugin.m | 97 ++++++++++++++++++--------- 1 file changed, 67 insertions(+), 30 deletions(-) diff --git a/ios/Classes/FlutterDownloaderPlugin.m b/ios/Classes/FlutterDownloaderPlugin.m index e3385b37..a5e01b25 100644 --- a/ios/Classes/FlutterDownloaderPlugin.m +++ b/ios/Classes/FlutterDownloaderPlugin.m @@ -39,11 +39,6 @@ @interface FlutterDownloaderPlugin() *_runningTaskById = nil; - - -@synthesize databaseQueue; +static NSThread *databaseThread; +static BOOL isDatabaseThreadStarted = NO; - (instancetype)init:(NSObject *)registrar; { @@ -92,7 +86,6 @@ - (instancetype)init:(NSObject *)registrar; if (debug) { NSLog(@"database path: %@", dbPath); } - databaseQueue = dispatch_queue_create("vn.hunghd.flutter_downloader", 0); _dbManager = [[DBManager alloc] initWithDatabaseFilePath:dbPath]; if (_runningTaskById == nil) { @@ -239,7 +232,7 @@ - (void)pauseTaskWithId: (NSString*)taskId [weakSelf sendUpdateProgressForTaskId:taskId inStatus:@(STATUS_PAUSED) andProgress:@(progress)]; - [weakSelf executeInDatabaseQueueForTask:^{ + [weakSelf executeOnDatabaseThreadForTask:^{ [weakSelf updateTask:taskId status:STATUS_PAUSED progress:progress resumable:YES]; }]; return; @@ -261,7 +254,7 @@ - (void)cancelTaskWithId: (NSString*)taskId if ([taskId isEqualToString:taskIdValue] && (state == NSURLSessionTaskStateRunning)) { [download cancel]; [weakSelf sendUpdateProgressForTaskId:taskId inStatus:@(STATUS_CANCELED) andProgress:@(-1)]; - [weakSelf executeInDatabaseQueueForTask:^{ + [weakSelf executeOnDatabaseThreadForTask:^{ [weakSelf updateTask:taskId status:STATUS_CANCELED progress:-1]; }]; return; @@ -279,7 +272,7 @@ - (void)cancelAllTasks { [download cancel]; NSString *taskId = [self identifierForTask:download]; [weakSelf sendUpdateProgressForTaskId:taskId inStatus:@(STATUS_CANCELED) andProgress:@(-1)]; - [weakSelf executeInDatabaseQueueForTask:^{ + [weakSelf executeOnDatabaseThreadForTask:^{ [weakSelf updateTask:taskId status:STATUS_CANCELED progress:-1]; }]; } @@ -297,12 +290,56 @@ - (void)sendUpdateProgressForTaskId: (NSString*)taskId inStatus: (NSNumber*) sta } } -- (void)executeInDatabaseQueueForTask:(void (^)(void))task { - __typeof__(self) __weak weakSelf = self; - dispatch_sync(databaseQueue, ^{ - if (weakSelf.isDatabaseQueueTerminated) return; - if (task) task(); - }); ++ (void)databaseThread:(id)unused { @autoreleasepool { + [[NSThread currentThread] setName:@"vn.hunghd.flutter_downloader"]; + + [NSTimer scheduledTimerWithTimeInterval:[[NSDate distantFuture] timeIntervalSinceNow] + target:self + selector:@selector(ignore:) + userInfo:nil + repeats:YES]; + + NSThread *currentThread = [NSThread currentThread]; + NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop]; + + BOOL isCancelled = [currentThread isCancelled]; + + while (!isCancelled && [currentRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]) { + isCancelled = [currentThread isCancelled]; + } + +} + +} + ++ (void)ignore:(id)_ { } + ++ (void)startDatabaseThreadIfNeeded { + if (isDatabaseThreadStarted) { + return; + } + + isDatabaseThreadStarted = true; + + databaseThread = [[NSThread alloc] initWithTarget:self + selector:@selector(databaseThread:) + object:nil]; + [databaseThread start]; +} + +- (void)executeOnDatabaseThreadForTask:(void (^)(void))task { + [self.class startDatabaseThreadIfNeeded]; + + [self performSelector:@selector(executeOnDatabaseThreadToCallbackForTask:) + onThread:databaseThread + withObject:task + waitUntilDone:YES]; +} + +- (void)executeOnDatabaseThreadToCallbackForTask:(void (^)(void))task { + if (task) { + task(); + } } - (BOOL)openDocumentWithURL:(NSURL*)url { @@ -360,7 +397,7 @@ - (NSURL*)fileUrlOf:(NSString*)taskId taskInfo:(NSDictionary*)taskInfo downloadT // update DB __typeof__(self) __weak weakSelf = self; - [self executeInDatabaseQueueForTask:^{ + [self executeOnDatabaseThreadForTask:^{ [weakSelf updateTask:taskId filename:filename]; }]; @@ -652,7 +689,7 @@ - (void)enqueueMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result __typeof__(self) __weak weakSelf = self; - [self executeInDatabaseQueueForTask:^{ + [self executeOnDatabaseThreadForTask:^{ [weakSelf addNewTask:taskId url:urlString status:STATUS_ENQUEUED progress:0 filename:fileName savedDir:shortSavedDir headers:headers resumable:NO showNotification: [showNotification boolValue] openFileFromNotification: [openFileFromNotification boolValue]]; }]; result(taskId); @@ -661,7 +698,7 @@ - (void)enqueueMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result - (void)loadTasksMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { __typeof__(self) __weak weakSelf = self; - [self executeInDatabaseQueueForTask:^{ + [self executeOnDatabaseThreadForTask:^{ NSArray* tasks = [weakSelf loadAllTasks]; result(tasks); }]; @@ -670,7 +707,7 @@ - (void)loadTasksMethodCall:(FlutterMethodCall*)call result:(FlutterResult)resul - (void)loadTasksWithRawQueryMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { NSString *query = call.arguments[KEY_QUERY]; __typeof__(self) __weak weakSelf = self; - [self executeInDatabaseQueueForTask:^{ + [self executeOnDatabaseThreadForTask:^{ NSArray* tasks = [weakSelf loadTasksWithRawQuery:query]; result(tasks); }]; @@ -723,7 +760,7 @@ - (void)resumeMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { result(newTaskId); __typeof__(self) __weak weakSelf = self; - [self executeInDatabaseQueueForTask:^{ + [self executeOnDatabaseThreadForTask:^{ [weakSelf updateTask:taskId newTaskId:newTaskId status:STATUS_RUNNING resumable:NO]; NSDictionary *task = [weakSelf loadTaskWithId:newTaskId]; NSNumber *progress = task[KEY_PROGRESS]; @@ -767,7 +804,7 @@ - (void)retryMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { [_runningTaskById removeObjectForKey:taskId]; __typeof__(self) __weak weakSelf = self; - [self executeInDatabaseQueueForTask:^{ + [self executeOnDatabaseThreadForTask:^{ [weakSelf updateTask:taskId newTaskId:newTaskId status:STATUS_ENQUEUED resumable:NO]; }]; result(newTaskId); @@ -818,7 +855,7 @@ - (void)removeMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { if ([taskId isEqualToString:taskIdValue] && (state == NSURLSessionTaskStateRunning)) { [download cancel]; [weakSelf sendUpdateProgressForTaskId:taskId inStatus:@(STATUS_CANCELED) andProgress:@(-1)]; - [weakSelf executeInDatabaseQueueForTask:^{ + [weakSelf executeOnDatabaseThreadForTask:^{ [weakSelf deleteTask:taskId]; }]; return; @@ -827,7 +864,7 @@ - (void)removeMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { }]; } - [self executeInDatabaseQueueForTask:^{ + [self executeOnDatabaseThreadForTask:^{ [weakSelf deleteTask:taskId]; }]; @@ -925,7 +962,7 @@ - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTas [self sendUpdateProgressForTaskId:taskId inStatus:status andProgress:@(progress)]; __typeof__(self) __weak weakSelf = self; - [self executeInDatabaseQueueForTask:^{ + [self executeOnDatabaseThreadForTask:^{ [weakSelf updateTask:taskId status:status.intValue progress:progress]; }]; _runningTaskById[taskId][KEY_PROGRESS] = @(progress); @@ -966,7 +1003,7 @@ - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTas __typeof__(self) __weak weakSelf = self; if (success) { [self sendUpdateProgressForTaskId:taskId inStatus:@(STATUS_COMPLETE) andProgress:@100]; - [self executeInDatabaseQueueForTask:^{ + [self executeOnDatabaseThreadForTask:^{ [weakSelf updateTask:taskId status:STATUS_COMPLETE progress:100]; }]; } else { @@ -974,7 +1011,7 @@ - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTas NSLog(@"Unable to copy temp file. Error: %@", [error localizedDescription]); } [self sendUpdateProgressForTaskId:taskId inStatus:@(STATUS_FAILED) andProgress:@(-1)]; - [self executeInDatabaseQueueForTask:^{ + [self executeOnDatabaseThreadForTask:^{ [weakSelf updateTask:taskId status:STATUS_FAILED progress:-1]; }]; } @@ -1010,7 +1047,7 @@ -(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompl [_runningTaskById removeObjectForKey:taskId]; [self sendUpdateProgressForTaskId:taskId inStatus:@(status) andProgress:@(-1)]; __typeof__(self) __weak weakSelf = self; - [self executeInDatabaseQueueForTask:^{ + [self executeOnDatabaseThreadForTask:^{ [weakSelf updateTask:taskId status:status progress:-1]; }]; } From e37faa7103dfcc7362c7fe8aa005749c456455c9 Mon Sep 17 00:00:00 2001 From: jackleemeta Date: Thu, 2 Mar 2023 22:58:27 +0800 Subject: [PATCH 2/5] Revert "fix: on iOS db locked error" This reverts commit bf521c81a15cb4599b9b47fa913d02bdc4ddee3a. --- ios/Classes/FlutterDownloaderPlugin.m | 97 +++++++++------------------ 1 file changed, 30 insertions(+), 67 deletions(-) diff --git a/ios/Classes/FlutterDownloaderPlugin.m b/ios/Classes/FlutterDownloaderPlugin.m index a5e01b25..e3385b37 100644 --- a/ios/Classes/FlutterDownloaderPlugin.m +++ b/ios/Classes/FlutterDownloaderPlugin.m @@ -39,6 +39,11 @@ @interface FlutterDownloaderPlugin() *_runningTaskById = nil; -static NSThread *databaseThread; -static BOOL isDatabaseThreadStarted = NO; + + +@synthesize databaseQueue; - (instancetype)init:(NSObject *)registrar; { @@ -86,6 +92,7 @@ - (instancetype)init:(NSObject *)registrar; if (debug) { NSLog(@"database path: %@", dbPath); } + databaseQueue = dispatch_queue_create("vn.hunghd.flutter_downloader", 0); _dbManager = [[DBManager alloc] initWithDatabaseFilePath:dbPath]; if (_runningTaskById == nil) { @@ -232,7 +239,7 @@ - (void)pauseTaskWithId: (NSString*)taskId [weakSelf sendUpdateProgressForTaskId:taskId inStatus:@(STATUS_PAUSED) andProgress:@(progress)]; - [weakSelf executeOnDatabaseThreadForTask:^{ + [weakSelf executeInDatabaseQueueForTask:^{ [weakSelf updateTask:taskId status:STATUS_PAUSED progress:progress resumable:YES]; }]; return; @@ -254,7 +261,7 @@ - (void)cancelTaskWithId: (NSString*)taskId if ([taskId isEqualToString:taskIdValue] && (state == NSURLSessionTaskStateRunning)) { [download cancel]; [weakSelf sendUpdateProgressForTaskId:taskId inStatus:@(STATUS_CANCELED) andProgress:@(-1)]; - [weakSelf executeOnDatabaseThreadForTask:^{ + [weakSelf executeInDatabaseQueueForTask:^{ [weakSelf updateTask:taskId status:STATUS_CANCELED progress:-1]; }]; return; @@ -272,7 +279,7 @@ - (void)cancelAllTasks { [download cancel]; NSString *taskId = [self identifierForTask:download]; [weakSelf sendUpdateProgressForTaskId:taskId inStatus:@(STATUS_CANCELED) andProgress:@(-1)]; - [weakSelf executeOnDatabaseThreadForTask:^{ + [weakSelf executeInDatabaseQueueForTask:^{ [weakSelf updateTask:taskId status:STATUS_CANCELED progress:-1]; }]; } @@ -290,56 +297,12 @@ - (void)sendUpdateProgressForTaskId: (NSString*)taskId inStatus: (NSNumber*) sta } } -+ (void)databaseThread:(id)unused { @autoreleasepool { - [[NSThread currentThread] setName:@"vn.hunghd.flutter_downloader"]; - - [NSTimer scheduledTimerWithTimeInterval:[[NSDate distantFuture] timeIntervalSinceNow] - target:self - selector:@selector(ignore:) - userInfo:nil - repeats:YES]; - - NSThread *currentThread = [NSThread currentThread]; - NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop]; - - BOOL isCancelled = [currentThread isCancelled]; - - while (!isCancelled && [currentRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]) { - isCancelled = [currentThread isCancelled]; - } - -} - -} - -+ (void)ignore:(id)_ { } - -+ (void)startDatabaseThreadIfNeeded { - if (isDatabaseThreadStarted) { - return; - } - - isDatabaseThreadStarted = true; - - databaseThread = [[NSThread alloc] initWithTarget:self - selector:@selector(databaseThread:) - object:nil]; - [databaseThread start]; -} - -- (void)executeOnDatabaseThreadForTask:(void (^)(void))task { - [self.class startDatabaseThreadIfNeeded]; - - [self performSelector:@selector(executeOnDatabaseThreadToCallbackForTask:) - onThread:databaseThread - withObject:task - waitUntilDone:YES]; -} - -- (void)executeOnDatabaseThreadToCallbackForTask:(void (^)(void))task { - if (task) { - task(); - } +- (void)executeInDatabaseQueueForTask:(void (^)(void))task { + __typeof__(self) __weak weakSelf = self; + dispatch_sync(databaseQueue, ^{ + if (weakSelf.isDatabaseQueueTerminated) return; + if (task) task(); + }); } - (BOOL)openDocumentWithURL:(NSURL*)url { @@ -397,7 +360,7 @@ - (NSURL*)fileUrlOf:(NSString*)taskId taskInfo:(NSDictionary*)taskInfo downloadT // update DB __typeof__(self) __weak weakSelf = self; - [self executeOnDatabaseThreadForTask:^{ + [self executeInDatabaseQueueForTask:^{ [weakSelf updateTask:taskId filename:filename]; }]; @@ -689,7 +652,7 @@ - (void)enqueueMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result __typeof__(self) __weak weakSelf = self; - [self executeOnDatabaseThreadForTask:^{ + [self executeInDatabaseQueueForTask:^{ [weakSelf addNewTask:taskId url:urlString status:STATUS_ENQUEUED progress:0 filename:fileName savedDir:shortSavedDir headers:headers resumable:NO showNotification: [showNotification boolValue] openFileFromNotification: [openFileFromNotification boolValue]]; }]; result(taskId); @@ -698,7 +661,7 @@ - (void)enqueueMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result - (void)loadTasksMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { __typeof__(self) __weak weakSelf = self; - [self executeOnDatabaseThreadForTask:^{ + [self executeInDatabaseQueueForTask:^{ NSArray* tasks = [weakSelf loadAllTasks]; result(tasks); }]; @@ -707,7 +670,7 @@ - (void)loadTasksMethodCall:(FlutterMethodCall*)call result:(FlutterResult)resul - (void)loadTasksWithRawQueryMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { NSString *query = call.arguments[KEY_QUERY]; __typeof__(self) __weak weakSelf = self; - [self executeOnDatabaseThreadForTask:^{ + [self executeInDatabaseQueueForTask:^{ NSArray* tasks = [weakSelf loadTasksWithRawQuery:query]; result(tasks); }]; @@ -760,7 +723,7 @@ - (void)resumeMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { result(newTaskId); __typeof__(self) __weak weakSelf = self; - [self executeOnDatabaseThreadForTask:^{ + [self executeInDatabaseQueueForTask:^{ [weakSelf updateTask:taskId newTaskId:newTaskId status:STATUS_RUNNING resumable:NO]; NSDictionary *task = [weakSelf loadTaskWithId:newTaskId]; NSNumber *progress = task[KEY_PROGRESS]; @@ -804,7 +767,7 @@ - (void)retryMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { [_runningTaskById removeObjectForKey:taskId]; __typeof__(self) __weak weakSelf = self; - [self executeOnDatabaseThreadForTask:^{ + [self executeInDatabaseQueueForTask:^{ [weakSelf updateTask:taskId newTaskId:newTaskId status:STATUS_ENQUEUED resumable:NO]; }]; result(newTaskId); @@ -855,7 +818,7 @@ - (void)removeMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { if ([taskId isEqualToString:taskIdValue] && (state == NSURLSessionTaskStateRunning)) { [download cancel]; [weakSelf sendUpdateProgressForTaskId:taskId inStatus:@(STATUS_CANCELED) andProgress:@(-1)]; - [weakSelf executeOnDatabaseThreadForTask:^{ + [weakSelf executeInDatabaseQueueForTask:^{ [weakSelf deleteTask:taskId]; }]; return; @@ -864,7 +827,7 @@ - (void)removeMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { }]; } - [self executeOnDatabaseThreadForTask:^{ + [self executeInDatabaseQueueForTask:^{ [weakSelf deleteTask:taskId]; }]; @@ -962,7 +925,7 @@ - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTas [self sendUpdateProgressForTaskId:taskId inStatus:status andProgress:@(progress)]; __typeof__(self) __weak weakSelf = self; - [self executeOnDatabaseThreadForTask:^{ + [self executeInDatabaseQueueForTask:^{ [weakSelf updateTask:taskId status:status.intValue progress:progress]; }]; _runningTaskById[taskId][KEY_PROGRESS] = @(progress); @@ -1003,7 +966,7 @@ - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTas __typeof__(self) __weak weakSelf = self; if (success) { [self sendUpdateProgressForTaskId:taskId inStatus:@(STATUS_COMPLETE) andProgress:@100]; - [self executeOnDatabaseThreadForTask:^{ + [self executeInDatabaseQueueForTask:^{ [weakSelf updateTask:taskId status:STATUS_COMPLETE progress:100]; }]; } else { @@ -1011,7 +974,7 @@ - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTas NSLog(@"Unable to copy temp file. Error: %@", [error localizedDescription]); } [self sendUpdateProgressForTaskId:taskId inStatus:@(STATUS_FAILED) andProgress:@(-1)]; - [self executeOnDatabaseThreadForTask:^{ + [self executeInDatabaseQueueForTask:^{ [weakSelf updateTask:taskId status:STATUS_FAILED progress:-1]; }]; } @@ -1047,7 +1010,7 @@ -(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompl [_runningTaskById removeObjectForKey:taskId]; [self sendUpdateProgressForTaskId:taskId inStatus:@(status) andProgress:@(-1)]; __typeof__(self) __weak weakSelf = self; - [self executeOnDatabaseThreadForTask:^{ + [self executeInDatabaseQueueForTask:^{ [weakSelf updateTask:taskId status:status progress:-1]; }]; } From cf6831f4dc804586f598ddbc182acfda8a5b0c89 Mon Sep 17 00:00:00 2001 From: jackleemeta Date: Fri, 3 Mar 2023 00:07:08 +0800 Subject: [PATCH 3/5] fix: 1. db locked error due to two database queues of main plugin and background isolate plugin 2. loadDataFromDB in `loadTaskWithId` safely --- ios/Classes/FlutterDownloaderPlugin.m | 37 +++++++++++++++++---------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/ios/Classes/FlutterDownloaderPlugin.m b/ios/Classes/FlutterDownloaderPlugin.m index e3385b37..e6c8e9ca 100644 --- a/ios/Classes/FlutterDownloaderPlugin.m +++ b/ios/Classes/FlutterDownloaderPlugin.m @@ -39,11 +39,6 @@ @interface FlutterDownloaderPlugin() *_runningTaskById = nil; - - -@synthesize databaseQueue; +static dispatch_queue_t _databaseQueue; +static void *_isOnDatabaseQueueKey; - (instancetype)init:(NSObject *)registrar; { @@ -92,7 +86,15 @@ - (instancetype)init:(NSObject *)registrar; if (debug) { NSLog(@"database path: %@", dbPath); } - databaseQueue = dispatch_queue_create("vn.hunghd.flutter_downloader", 0); + + if (_databaseQueue == nil) { + _databaseQueue = dispatch_queue_create("vn.hunghd.flutter_downloader", 0); + + _isOnDatabaseQueueKey = &_isOnDatabaseQueueKey; + void *nonNullUnusedPointer = (__bridge void *)(self.class); + dispatch_queue_set_specific(_databaseQueue, _isOnDatabaseQueueKey, nonNullUnusedPointer, NULL); + } + _dbManager = [[DBManager alloc] initWithDatabaseFilePath:dbPath]; if (_runningTaskById == nil) { @@ -298,9 +300,7 @@ - (void)sendUpdateProgressForTaskId: (NSString*)taskId inStatus: (NSNumber*) sta } - (void)executeInDatabaseQueueForTask:(void (^)(void))task { - __typeof__(self) __weak weakSelf = self; - dispatch_sync(databaseQueue, ^{ - if (weakSelf.isDatabaseQueueTerminated) return; + dispatch_sync(_databaseQueue, ^{ if (task) task(); }); } @@ -539,7 +539,18 @@ - (NSDictionary*)loadTaskWithId:(NSString*)taskId return [_runningTaskById objectForKey:taskId]; } else { NSString *query = [NSString stringWithFormat:@"SELECT * FROM task WHERE task_id = \"%@\" ORDER BY id DESC LIMIT 1", taskId]; - NSArray *records = [[NSArray alloc] initWithArray:[_dbManager loadDataFromDB:query]]; + + __block NSArray *records; + + if (dispatch_get_specific(_isOnDatabaseQueueKey)) { + records = [[NSArray alloc] initWithArray:[_dbManager loadDataFromDB:query]]; + } else { + __typeof__(_dbManager) __weak _weakDbManager = _dbManager; + [self executeInDatabaseQueueForTask:^{ + records = [[NSArray alloc] initWithArray:[_weakDbManager loadDataFromDB:query]]; + }]; + } + if (debug) { NSLog(@"Load task successfully"); } From 46f00b8bb501646653a5eca2f2a7c4fa4c380a1d Mon Sep 17 00:00:00 2001 From: jackleemeta Date: Fri, 3 Mar 2023 00:13:31 +0800 Subject: [PATCH 4/5] chore: remove redundant judgment `if(openDatabaseResult == SQLITE_OK)`, because the front lines return when `openDatabaseResult != SQLITE_OK` --- ios/Classes/DBManager.m | 130 ++++++++++++++++++++-------------------- 1 file changed, 65 insertions(+), 65 deletions(-) diff --git a/ios/Classes/DBManager.m b/ios/Classes/DBManager.m index 3932d239..92e0ed50 100644 --- a/ios/Classes/DBManager.m +++ b/ios/Classes/DBManager.m @@ -117,86 +117,86 @@ -(void)runQuery:(const char *)query isQueryExecutable:(BOOL)queryExecutable{ } return; } - if(openDatabaseResult == SQLITE_OK) { - if (debug) { - NSLog(@"open DB successfully"); - } - - // Declare a sqlite3_stmt object in which will be stored the query after having been compiled into a SQLite statement. - sqlite3_stmt *compiledStatement; - - // Load all data from database to memory. - int prepareStatementResult = sqlite3_prepare_v2(sqlite3Database, query, -1, &compiledStatement, NULL); - if(prepareStatementResult == SQLITE_OK) { - // Check if the query is non-executable. - if (!queryExecutable){ - // In this case data must be loaded from the database. + + if (debug) { + NSLog(@"open DB successfully"); + } + + // Declare a sqlite3_stmt object in which will be stored the query after having been compiled into a SQLite statement. + sqlite3_stmt *compiledStatement; + + // Load all data from database to memory. + int prepareStatementResult = sqlite3_prepare_v2(sqlite3Database, query, -1, &compiledStatement, NULL); + if(prepareStatementResult == SQLITE_OK) { + // Check if the query is non-executable. + if (!queryExecutable){ + // In this case data must be loaded from the database. + + // Declare an array to keep the data for each fetched row. + NSMutableArray *arrDataRow; + + // Loop through the results and add them to the results array row by row. + while(sqlite3_step(compiledStatement) == SQLITE_ROW) { + // Initialize the mutable array that will contain the data of a fetched row. + arrDataRow = [[NSMutableArray alloc] init]; - // Declare an array to keep the data for each fetched row. - NSMutableArray *arrDataRow; + // Get the total number of columns. + int totalColumns = sqlite3_column_count(compiledStatement); - // Loop through the results and add them to the results array row by row. - while(sqlite3_step(compiledStatement) == SQLITE_ROW) { - // Initialize the mutable array that will contain the data of a fetched row. - arrDataRow = [[NSMutableArray alloc] init]; - - // Get the total number of columns. - int totalColumns = sqlite3_column_count(compiledStatement); + // Go through all columns and fetch each column data. + for (int i=0; i 0) { - [self.arrResults addObject:arrDataRow]; + // Keep the current column name. + if (self.arrColumnNames.count != totalColumns) { + dbDataAsChars = (char *)sqlite3_column_name(compiledStatement, i); + [self.arrColumnNames addObject:[NSString stringWithUTF8String:dbDataAsChars]]; } } - } - else { - // This is the case of an executable query (insert, update, ...). - // Execute the query. - int executeQueryResults = sqlite3_step(compiledStatement); - if (executeQueryResults == SQLITE_DONE) { - // Keep the affected rows. - self.affectedRows = sqlite3_changes(sqlite3Database); - - // Keep the last inserted row ID. - self.lastInsertedRowID = sqlite3_last_insert_rowid(sqlite3Database); - } - else { - // If could not execute the query show the error message on the debugger. - if (debug) { - NSLog(@"DB Error: %s", sqlite3_errmsg(sqlite3Database)); - } + // Store each fetched data row in the results array, but first check if there is actually data. + if (arrDataRow.count > 0) { + [self.arrResults addObject:arrDataRow]; } } } else { - // In the database cannot be opened then show the error message on the debugger. - if (debug) { - NSLog(@"%s", sqlite3_errmsg(sqlite3Database)); + // This is the case of an executable query (insert, update, ...). + + // Execute the query. + int executeQueryResults = sqlite3_step(compiledStatement); + if (executeQueryResults == SQLITE_DONE) { + // Keep the affected rows. + self.affectedRows = sqlite3_changes(sqlite3Database); + + // Keep the last inserted row ID. + self.lastInsertedRowID = sqlite3_last_insert_rowid(sqlite3Database); + } + else { + // If could not execute the query show the error message on the debugger. + if (debug) { + NSLog(@"DB Error: %s", sqlite3_errmsg(sqlite3Database)); + } } } - - // Release the compiled statement from memory. - sqlite3_finalize(compiledStatement); } + else { + // In the database cannot be opened then show the error message on the debugger. + if (debug) { + NSLog(@"%s", sqlite3_errmsg(sqlite3Database)); + } + } + + // Release the compiled statement from memory. + sqlite3_finalize(compiledStatement); + // Close the database. sqlite3_close(sqlite3Database); From 0f920e3af0806e6b41eaf6366e492a1e366abe5c Mon Sep 17 00:00:00 2001 From: jackleemeta Date: Tue, 7 Mar 2023 19:37:31 +0800 Subject: [PATCH 5/5] chore: 1. rename var 2. determine whether on database queue in [executeInDatabaseQueueForTask] --- ios/Classes/FlutterDownloaderPlugin.m | 32 +++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/ios/Classes/FlutterDownloaderPlugin.m b/ios/Classes/FlutterDownloaderPlugin.m index e6c8e9ca..3446c52f 100644 --- a/ios/Classes/FlutterDownloaderPlugin.m +++ b/ios/Classes/FlutterDownloaderPlugin.m @@ -51,8 +51,8 @@ @implementation FlutterDownloaderPlugin static int64_t _callbackHandle = 0; static int _step = 10; static NSMutableDictionary *_runningTaskById = nil; -static dispatch_queue_t _databaseQueue; -static void *_isOnDatabaseQueueKey; +static dispatch_queue_t databaseQueue; +static void *isOnDatabaseQueueKey; - (instancetype)init:(NSObject *)registrar; { @@ -87,12 +87,12 @@ - (instancetype)init:(NSObject *)registrar; NSLog(@"database path: %@", dbPath); } - if (_databaseQueue == nil) { - _databaseQueue = dispatch_queue_create("vn.hunghd.flutter_downloader", 0); + if (databaseQueue == nil) { + databaseQueue = dispatch_queue_create("vn.hunghd.flutter_downloader", 0); - _isOnDatabaseQueueKey = &_isOnDatabaseQueueKey; + isOnDatabaseQueueKey = &isOnDatabaseQueueKey; void *nonNullUnusedPointer = (__bridge void *)(self.class); - dispatch_queue_set_specific(_databaseQueue, _isOnDatabaseQueueKey, nonNullUnusedPointer, NULL); + dispatch_queue_set_specific(databaseQueue, isOnDatabaseQueueKey, nonNullUnusedPointer, NULL); } _dbManager = [[DBManager alloc] initWithDatabaseFilePath:dbPath]; @@ -300,9 +300,13 @@ - (void)sendUpdateProgressForTaskId: (NSString*)taskId inStatus: (NSNumber*) sta } - (void)executeInDatabaseQueueForTask:(void (^)(void))task { - dispatch_sync(_databaseQueue, ^{ + if (dispatch_get_specific(isOnDatabaseQueueKey)) { if (task) task(); - }); + } else { + dispatch_sync(databaseQueue, ^{ + if (task) task(); + }); + } } - (BOOL)openDocumentWithURL:(NSURL*)url { @@ -542,14 +546,10 @@ - (NSDictionary*)loadTaskWithId:(NSString*)taskId __block NSArray *records; - if (dispatch_get_specific(_isOnDatabaseQueueKey)) { - records = [[NSArray alloc] initWithArray:[_dbManager loadDataFromDB:query]]; - } else { - __typeof__(_dbManager) __weak _weakDbManager = _dbManager; - [self executeInDatabaseQueueForTask:^{ - records = [[NSArray alloc] initWithArray:[_weakDbManager loadDataFromDB:query]]; - }]; - } + __typeof__(_dbManager) __weak weakDbManager = _dbManager; + [self executeInDatabaseQueueForTask:^{ + records = [[NSArray alloc] initWithArray:[weakDbManager loadDataFromDB:query]]; + }]; if (debug) { NSLog(@"Load task successfully");