带有FMDatabase Wrapper的SQLite数据库

时间:2011-04-25 04:48:55

标签: objective-c sqlite

我在Objective C中使用FMDatabase SQLite包装器,我遇到以下问题:

我正在后台线程中运行XML解析和数据库插入,以获取用户无权访问的某些内容,但是用户可以从他们所在的部分与UI和数据库进行交互。

The FMDatabase <FMDatabase: 0x17b7b0> is currently in use.

随机地,我将获得“FMDatabase已在使用中”通知,数据库将永远不会填充该数组。我的印象是FMDatabase类一旦它被释放就会处理它,但我有一个:

while(contents.count < 1){
     sleep(1);
}

希望一旦数据库释放,就会填充数组。如果数据库忙,但我也尝试重新运行数组填充脚本,但无济于事。

很抱歉,如果这个问题令人困惑,我很乐意澄清。

2 个答案:

答案 0 :(得分:7)

我遇到了同样的问题。

我为每次必须执行的数据库查询/更新切换到FMDatabaseQueue。它就像一个魅力!

使用performSelectorOnMainThread是一个好主意,但是当涉及实际编码时,传递参数并获得结果以供进一步使用可能非常棘手。

编辑:这是一个小例子

-(void) updateTaskStateAsync:(NSNumber *)taskID withNewStatus:(NSNumber *)state andCompletionBlock:(void(^)(BOOL status))completionBlock{

    NSString *errInfo = [NSString stringWithFormat:@"taskID %d - state %d", [taskID intValue], [state intValue]];

    [queue inDatabase:^(FMDatabase *db) {
        BOOL r = [db executeUpdate:@"UPDATE tasks SET state=?, date_job_last_updated=? WHERE identifier=?", state, [NSDate dateWithTimeIntervalSinceNow:0], taskID];
        DB_DISPLAY_ERROR(errInfo); // convenient macro to log errors

        if(completionBlock)
            completionBlock(r);
    }];
}

-(BOOL) updateTaskStateSync:(NSNumber *)taskID withNewStatus:(NSNumber *)state {

    NSString *errInfo = [NSString stringWithFormat:@"taskID %d - state %d", [taskID intValue], [state intValue]];
    __block BOOL r = NO;
    __block BOOL ended = NO;

    [queue inDatabase:^(FMDatabase *db) {
        r = [db executeUpdate:@"UPDATE tasks SET state=?, date_job_last_updated=? WHERE identifier=?", state, [NSDate dateWithTimeIntervalSinceNow:0], taskID];
        DB_DISPLAY_ERROR(errInfo); // convenient macro to log errors

        ended = YES;
    }];

    NSCondition *cond = [[NSCondition alloc] init];
    [cond lock];
    while(!ended)
        [cond wait];

    [cond unlock];

    return r;
}

答案 1 :(得分:4)

您遇到此问题是因为您的应用程序是多线程的,并且您从不同的线程访问相同的FMDatabase。类似的问题,但对于Python,可以找到here

FMDatabase是sqlite API的包装器。默认情况下,sqlite不允许并发,因此FMDatabase使用名为“inUse”的成员变量进行跟踪。要解决您的问题,请尝试在NSObject上定义的这些方法之一,以便对FMDatabase的所有调用都发生在同一个线程上。

  • performSelectorOnMainThread:withObject:waitUntilDone:
  • performSelectorOnMainThread:withObject:waitUntilDone:模式:
  • performSelector:onThread:withObject:waitUntilDone:
  • performSelector:onThread:withObject:waitUntilDone:模式: