如何在 iPhone 上使用带有线程的 sqlite + fdbm 库

2024-06-20

相关这个问题 https://stackoverflow.com/questions/1082554/,我想把数据加载放在后台。

但是,我收到“库例程调用不按顺序”错误。

In 这个所以线程 https://stackoverflow.com/questions/745565/how-to-properly-call-sqlite-functions-from-background-thread-on-iphone说这种方法是使用 NSOperation,但是查看网络上的示例我不知道如何解决该问题。

我与单例模式共享一个 sqlite 连接:

@interface Db : NSObject {
    NSString *path;
    FMDatabase* theDb;
    BOOL isOpen;
}

@property (retain, nonatomic) FMDatabase *theDb;
@property (retain, nonatomic) NSString *path;
@property (nonatomic) BOOL isOpen;
--------
static Db *currentDbSingleton = nil;
#pragma mark Global access

+(id)currentDb {
    @synchronized(self) {
        if (!currentDbSingleton) {
            NSString *reason = NSLocalizedString(@"The database is not set globally",
                                                 @"Error Db: database is not set");
            NSException *e = [NSException exceptionWithName:@"DBError"                        
                                                     reason:reason;
                                                   userInfo:nil];
            @throw e;
        }
    }
    return currentDbSingleton;  
}

所以打开两次相同的数据库更难......

有任何想法吗?

EDIT:

我确认错误是在调用 sqlite.我使用 FDBM 作为调用它的薄包装器。

我正在运行 2 个线程:主线程和用于加载数据的后台任务。我这样运行:

- (void) fillCache:(NSString *)theTable {
    [NSThread detachNewThreadSelector:@selector(fillCacheBackground:)
                             toTarget:self
                           withObject:theTable];
}

- (void)loadComplete {
    [self.table reloadData];
}

- (void) fillCacheBackground:(NSString *)theTable {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    Db *db= [Db currentDb];
    [db beginTransaction];
        ..... STUFF HERE
    [db commitTransaction];
    //Tell our callback what we've done
    [self performSelectorOnMainThread:@selector(loadComplete) 
                           withObject:nil 
                        waitUntilDone:YES];
    [pool drain];
}

数据库接口的代码位于http://code.google.com/p/chibiorm/source/browse/#svn/trunk/src http://code.google.com/p/chibiorm/source/browse/#svn/trunk/src— 特别是 Db.h/m,它是唯一与 fdbm/sqlite 接口的单元。

尝试从 FDBM 调用 sqlite 函数时发生错误。

例如发生在这里:

-(void) checkError {
    if ([self.theDb hadError]) { // <====ERROR HERE
        NSLog(@"Err %d: %@", [self.theDb lastErrorCode], [self.theDb]);
    }
}

这调用了FDBM代码:

- (BOOL) hadError {
    int lastErrCode = sqlite3_errcode(db);
    return (lastErrCode > SQLITE_OK && lastErrCode < SQLITE_ROW);
}

单例方法是一个好主意,尽管它看起来不像您实际上正在初始化currentDbSingleton任何地方...假设您修复了该问题并返回了有效的数据库连接,我认为这不是您的问题。

The “库例程调用不按顺序”您提到的错误提示我您正在使用的库(SQLite 或 FMDB)期望以特定顺序进行方法/函数调用。您可能遇到的并发问题是两个或多个线程正在调用同一个库,虽然每个线程可能使用正确的顺序,但如果它们“同时通话”,可以这么说,库可能会收到调用顺序不符合预期。您想要的是将一组调用视为一个原子单元,以便它们不能重叠或混合。

这是哪里NS操作 http://developer.apple.com/documentation/Cocoa/Reference/NSOperation_class/子类化它允许您将一堆代码视为“单个封装任务”——您可能需要针对非并发操作进行设计。类文档包含解释如何在 NSOperation 中实现逻辑的详细信息。


Edit:(提问者通过补充上下文澄清问题后)

由于问题发生在checkError,并且该方法是从链接的 .m 文件中的多个位置调用的,因此您很有可能正在调用hadError在不正确的时间。 (是在一个事务关闭后调用吗?如果在下一个事务开始后调用怎么办?)

例如,如果fillCache当上一个调用仍在访问数据库时被调用?在这方面,您的事务管理方法看起来非常可疑。例如,如果有人打电话beginTransaction and inTransaction is YES,该方法返回而不执行任何操作(即,它根本不调用 FMDatabase ivar)。您可能希望第二个调用者等待第一个调用者完成其事务。 (除非 FMDatabase 支持并发事务,在这种情况下您需要调用beginTransaction无论如何。)

如果您还没有阅读过这篇关于 Objective-C 线程同步的 Apple 文章 http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocThreading.html。接下来,查阅文档NSLock http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSLock_Class/(特别lockBeforeDate: http://developer.apple.com/DOCUMENTATION/Cocoa/Reference/Foundation/Classes/NSLock_Class/Reference/Reference.html#//apple_ref/occ/instm/NSLock/lockBeforeDate:) and 相关示例代码。在你的里面-[Db beginTransaction]方法,您可能希望阻止获取锁。

您还有几个特殊的类方法,例如 +allocWithZone: — 如果可以的话,选择使用 +inizialize(首次引用该类时,运行时会自动调用该方法),这样该类就可以自行初始化,而无需进行初始化。用于手动呼叫。 (我猜你先调用 +alloc,然后调用 -initWithName:,然后将其反馈给 +setCurrentDb。像 +initializeWithPath: 这样的便捷方法可以处理所有这些事情,这样会更干净。)

还有许多其他问题,例如 +setCurrentDb: 可以交换单例对象,无论事务是否正在进行(并且旧的单例未释放),+currentDb 引发异常,它可能应该只创建单例实例等。但是,您面临的最大问题是如何正确实现并发。我认为实现锁来保护 FMDatabase 引用是朝着正确方向迈出的一步,但仅仅将方法 X 包装在 NSOperation 中并不能满足您的需要。代码中引用的每个点theDb如果不能保证没有其他人这样做,就会面临崩溃的风险。如果这看起来很难,请不要感到难过,因为事实确实如此。

最后随机建议:改变你的方法TypeForField:Type: and ValueForField:Name:Type: to typeForFieldName:typeName: and valueForResultSet:fieldName:typeName:分别。力求准确性、可读性和匹配约定。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 iPhone 上使用带有线程的 sqlite + fdbm 库 的相关文章

  • 外围 BLE 设备的唯一标识符

    所以我有外围设备BLE设备 我需要一些标识符以便稍后与另一部 iPhone 共享 我连接的示例iPhone A 为外围设备 iPhone A 将外围设备的标识符保存到数据库中 稍后我可以轻松获取iPhone B 并连接到通过该标识符找到的外
  • SplitViewController 与 TabbarController

    我在我的应用程序中使用分割视图功能 我必须将选项卡栏放在 rootViewController 中 但是 当我在选项卡栏中添加控制器并将它们添加到分割视图中时 它不会分割 它只显示detailViewController 这是应用程序中完成
  • 如何阻止我的应用程序设置“隔离”位?

    从 OS X 10 7 3 开始 我的文本编辑器就在它接触的任何文件上设置 隔离 位 我的文本编辑器设计用于处理 shell 脚本 如果设置了隔离位 则无法从命令行执行 shell 脚本 直到您在 Finder 中双击它并浏览 此应用程序是
  • 创建宏来执行默认初始化

    我有很多重复这个简单样板的方法 id myObject if myObject self myObject myObject class new return myObject 所以我想用一个简单的宏来替换它 define default
  • 更新到 Xcode 7.0.1,项目现在有问题

    因此 我将 Xcode 6 1 版本上传到 iTunes Connect 并且该应用程序获得了批准 现在我正在尝试更新应用程序 我更新到 Xcode 7 0 1 Xcode 给我带来了问题 指出 对于应用程序 我使用了故事板和 Object
  • 解析后 UITableView 委托和数据源在单独的类中

    我需要从一个单独的类设置 UITableView 委托和数据源 方法调用解析后数据准备就绪 但每次我的表都是空的 我正在使用 ARC 这是简化的代码 HomeViewController h import
  • 选择时的 sqlite3_bind_text,准备好的 SQL 语句与字符串 SQL 语句的结果不同

    当我尝试使用 sqlite3 bind text 函数进行选择时 我遇到了问题 目的是获取数据 10 分钟时间段内的最新值 如果我使用准备好的语句并绑定我的值 则结果与具有 SQL 语法的普通字符串不同 两个测试的 SQL 语法 应该 相同
  • 使用捏合手势;如何放大用户手指实际“捏”的位置?

    我已经在我的应用程序中的 UIImageView 上实现了 UIPinchGestureRecognizer 但是无论我在图像的哪个位置捏合 它似乎都会放大到同一个位置 有谁知道我如何让它放大到用户实际 捏 的地方 请参阅下面的代码 视图控
  • 我可以使用 NSDateFormatter 将此日期字符串转换为 NSDate 吗?

    我有这个字符串 2010 08 24T16 00 00 05 00 我想从中提取时间部分 即 16 00 并将其转换为 12 小时等效值 即下午 04 00 我正在尝试使用 NSDateFormatter 来完成此任务 但它不起作用 NSD
  • Windows 64 位的 SQLite3 下载文件夹中没有 sqlite3.exe

    我正在尝试在 Windows 10 64 位上安装 SQLite 3SQLite下载页面 https www sqlite org download html我尝试了sqlite dll win64 x64 3170000 zip来自页面上
  • 处理 NSPropertyListSerialization 中的 CFNull 对象

    在我的应用程序中 我尝试序列化服务器响应字典并将其写入文件系统 但对于某些响应 我收到错误 属性列表格式无效 原因是服务器响应中的 CFNull 对象 现在 服务器响应将不断变化 因此我没有明确的方法来删除 CFNull 对象 下面是我的代
  • Apple 推送通知徽章编号

    我开发了服务器端应用程序 以在收到新通知后将徽章编号维护为递增或递减 并在看到通知后删除它工作正常 但是显示徽章时存在一些问题 实际情况是 在设备上收到新通知后 我单击取消按钮 然后徽章编号正确显示 但之后我将打开应用程序并关闭应用程序徽章
  • 为什么下面代码的输出是Thread[main,5,main]

    public class test1 public static void main String args TODO Auto generated method stub Thread t Thread currentThread Sys
  • XamlReader.Load 在后台线程中。是否可以?

    WPF 应用程序具有从单独的文件加载用户控件的操作 使用XamlReader Load method StreamReader mysr new StreamReader pathToFile DependencyObject rootOb
  • iPhone PhoneGap 电子邮件编辑器 SECURITY_ERR:DOM 异常 18 [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我正在使用phonegap 中的 i
  • insertObject:atIndex 的复杂性:

    复杂度是多少 NSArray insertObject atIndex N 或常数 另外 如何找出各种 Objective C 语句的复杂度 有一个在这里讨论 http www cocoadev com index pl NSMutable
  • PyCharm - 如何挂起所有线程

    我们使用 PyCharm 5 0 1 进行多线程调试 当它在断点处停止时 只有特定线程停止 而所有其他线程继续 这使得 冻结时刻 和检查参数值以及其他线程的当前状态变得困难 当其中一个线程在断点处停止时 是否可以挂起所有线程 这在最新的 P
  • iOS:addConstraints:应用程序崩溃

    Problem 我似乎无法在现有项目中采用自动布局 Details 我之前也遇到过与此问题相同的问题presentViewController 在 iOS 但所提供的答案都不是我的解决方案 我正在使用所有没有 xib 的故事板视图 我的 使
  • extern NSString *const 在类中。

    你好 我有这个头文件 import
  • 线程和 fork()。我该如何处理呢? [复制]

    这个问题在这里已经有答案了 可能的重复 多线程程序中的fork https stackoverflow com questions 1235516 fork in multi threaded program 如果我有一个使用 fork 的

随机推荐