gpt4 book ai didi

ios - db executeUpdate... 在 FMDB block 中并且没有结束,没有错误

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:58:47 25 4
gpt4 key购买 nike

我在我的应用程序开发中使用了惊人的 FMDB 项目,我有一个像这样的 NSOperation:

- (void)main
{
@autoreleasepool {

FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:[[NSUserDefaults standardUserDefaults] valueForKey:@"pathDB"]];

[queue inDatabase:^(FMDatabase *db) {

FMResultSet *toQuery;

if (self._id == nil) {
toQuery = [db executeQuery:@"SELECT id,language,update_time FROM task"];

while ([toQuery next]) {

[myarray addObject:[toQuery resultDictionary]];

}
}];

for (int i = 0; i<[myarray count]; i++){

...Do Something

[queue inDatabase:^(FMDatabase *db) {

FMResultSet *checkImgQuery = [db executeQuery:@"SELECT img_url,img_path FROM task WHERE id = ? AND language = ?",myTask.id ,myTask.lang];

while ([checkImgQuery next]) {

if (![[checkImgQuery stringForColumn:@"img_url"] isEqualToString:myTask.img]) {
NSData *my_img = [NSData dataWithContentsOfURL:[NSURL URLWithString:myTask.img]];

if (my_img != nil) {

NSError *er;

[my_img writeToFile:[checkImgQuery stringForColumn:@"img_path"] options:NSDataWritingAtomic error:&er];

//In the line under here the code block, the app still running, but this operation doesn't
//go over this task

[db executeUpdate:@"UPDATE task SET img_url = ? WHERE id = ? AND language = ?",myTask.img,[NSNumber numberWithInt:myTask.id],[NSNumber numberWithInt:myTask.language];

NSLog(@"%@",[db lastErrorMessage]);
}
...Do Something
}
}
}
}];
}
}

问题出在 [db executeUpdate:...] 中,有时可以正常工作,有时会卡住并且不会越过那条线,NSLog 我放在那里不打印任何东西,应用程序不会崩溃并继续工作,但线程卡在那里,如果我关闭应用程序的运行,然后再次重新启动它,线程不会停止在同一个任务上,但在另一个上是随机的,没有标准,有时一个有效,有时不...任何人都可以提供帮助吗?

最佳答案

我突然想到了几个问题,其中一个或多个问题可能会导致您的问题:

  1. 我注意到您正在本地创建一个 FMDatabaseQueue 对象。您应该只为整个应用程序共享一个 FMDatabaseQueue 对象(我把它放在一个单例中)。数据库队列的目的是协调数据库交互,如果您到处创建新的 FMDatabaseQueue 对象,它就无法合理地做到这一点。

  2. 我建议不要使用 inDatabase block ,您可以在其中从网络同步下载一堆图像。

    当您提交一个 inDatabase 任务时,任何 inDatabase 调用使用相同 FMDatabaseQueue 的其他线程(它们应该使用相同的队列,否则你首先会破坏排队的目的)将不会继续,直到你的操作中运行的队列完成(反之亦然)。

    当从多个线程进行数据库交互时,由 FMDatabaseQueue 串行队列协调,您确实希望确保尽快“进出”。不要在 inDatabase block 的中间嵌入可能较慢的网络调用,否则所有其他数据库交互将被阻止,直到它完成。

    因此,执行inDatabase 来识别需要下载的图像,仅此而已。然后在 inDatabase 调用之外检索您的图像,如果您需要更新图像路径等,单独的 inDatabase 调用 do 来执行此操作。但不要在 inDatabase block 中包含任何缓慢和同步的内容。

  3. 我还注意到您正在对 task 表执行 SELECT,保持 FMRecordSet 打开,然后尝试更新相同的记录。您想要打开您的记录集,检索您需要的内容,然后关闭该记录集,然后再尝试更新您在记录集中检索到的相同记录。

    在尝试执行更新同一记录的 executeUpdate 之前,请始终关闭 FMResultSet

  4. 有点不相关,但我可能建议您考虑在您的原始 SELECT 语句中包含 img_urlimg_path,这样您字典条目数组将已经包含您需要的所有内容,它使您不必再执行第二个SELECT


如果您想知道 FMDatabaseQueue 单例可能是什么样子,您可能有一个 DatabaseManager 单例,其接口(interface)如下所示:

//  DatabaseManager.h

@import Foundation;
@import SQLite3;

#import "FMDB.h"

NS_ASSUME_NONNULL_BEGIN

@interface DatabaseManager : NSObject

@property (nonatomic, strong, readonly) FMDatabaseQueue *queue;

@property (class, readonly, strong) DatabaseManager *sharedManager;

- (id)init __attribute__((unavailable("Use +[DatabaseManager sharedManager] instead")));
+ (id)new __attribute__((unavailable("Use +[DatabaseManager sharedManager] instead")));

@end

NS_ASSUME_NONNULL_END

实现可能如下所示:

//  DatabaseManager.m

#import "DatabaseManager.h"

@implementation DatabaseManager

+ (DatabaseManager *)sharedManager {
static id sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}

- (id)init {
if ((self = [super init])) {
_queue = [[FMDatabaseQueue alloc] initWithPath:[[NSUserDefaults standardUserDefaults] valueForKey:@"pathDB"]];
}
return self;
}

@end

然后,任何需要与数据库交互的代码都可以像这样检索队列:

FMDatabaseQueue *queue = DatabaseManager.sharedManager.queue;

关于ios - db executeUpdate... 在 FMDB block 中并且没有结束,没有错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18215625/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com