objective-c sqlite3数据库更改不持久

时间:2013-09-24 11:42:41

标签: ios objective-c sqlite persistent

我的应用程序有一个SQLite数据库。要从db中检索实体,我使用以下方法:

- (sqlite3*) openDatabaseNamed:(NSString*)databaseName
{
    if(![databaseName isEqualToString:kTopInternationalDatabaseName] &&
       ![databaseName isEqualToString:kTop500RODatabaseName]){
        NSAssert(nil, @"Database does not exist!");
    }
    sqlite3 * dataBase;
    NSString * path;
    path =  [[NSBundle mainBundle] pathForResource:databaseName ofType:@"sqlite3"];
    if (sqlite3_open([path UTF8String], &dataBase) != SQLITE_OK) {
        NSString * errorString = [NSString stringWithFormat:@"[SQLITE] Unable to open database <%@> ",databaseName];
        NSAssert(nil,errorString);
    }
    return dataBase;
}

- (NSArray *) getAllEntitiesForDatabaseNamed:(NSString*)databaseName
{
  (...)
    sqlite3 * database  = [self openDatabaseNamed:databaseName];

    NSMutableArray *retval = [[NSMutableArray alloc] init];
    NSString *query = [NSString stringWithFormat:@"SELECT * FROM %@",databaseName];

    NSArray *properties = [entityClass classProperties];

    if (sqlite3_prepare_v2(database, [query UTF8String], -1, &statement, nil)
        == SQLITE_OK) {
        while (sqlite3_step(statement) == SQLITE_ROW) {


            for (int i=2; i<countLimit; i++){

                chars = (char *) sqlite3_column_text(statement,i+1);
                if(chars != NULL)
                {
                    containerString = [NSString stringWithUTF8String:chars];
                    if(containerString && containerString.length>0){
                        [entityModel setValue:containerString forKey:properties[i]];
                    }
                }
            }
            [retval addObject:entityModel];
        }
        sqlite3_finalize(statement);
    }
    sqlite3_close(database);
    return retval.copy;
}

一切都按预期工作。要将实体的自定义字段设置为数据库中的特定值,请使用以下方法:

- (void)setEntity:(EntityModel *)entity favorite:(BOOL)favorite
{
    NSString *query = [NSString stringWithFormat:@"UPDATE %@ SET favorite = %i WHERE position = '%i';",kDatabaseName,favorite?1:0,entity.positionInTop];

    sqlite3_stmt *statement;
    sqlite3 * database = [self openDatabaseNamed:kTop500RODatabaseName];

    if (sqlite3_prepare_v2(database, [query UTF8String], -1, &statement, nil)
        == SQLITE_OK) {
        sqlite3_step(statement);
        sqlite3_finalize(statement);
    }
    sqlite3_close(database);
}

发生的事情有点奇怪。如果我使用更新方法并在使用getAllEntitiesForDatabaseNamed的所有实体的应用查询的同一生命周期中,我对setEntity:Favorite:所做的更改仍然存在。另一方面,如果我使用更新方法,然后关闭应用程序并重新启动它,我使用setEntity:Favorite:所做的更改将丢失。知道为什么会这样吗?

PS:我也尝试使用sqlite3_exec但结果仍然相同:

if (sqlite3_exec(database, [query UTF8String], NULL, NULL, NULL) != SQLITE_OK) {
    // deal with error...
    NSLog(@" -- ERROR!");
}

1 个答案:

答案 0 :(得分:4)

问题在于您打开捆绑包中的数据库,该数据库是只读的(至少在设备上)。相反,您应该检查数据库是否存在于Documents文件夹中,如果没有,请从包中复制它,然后从Documents文件夹中打开数据库。

因此,您可以执行以下操作:

NSString *bundlePath = [[NSBundle mainBundle] pathForResource:databaseName ofType:@"sqlite"];

NSString *documentsFolder = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *documentsPath   = [[documentsFolder stringByAppendingPathComponent:databaseName] stringByAppendingPathExtension:@"sqlite"];

NSFileManager *fileManager = [NSFileManager defaultManager];

if (![fileManager fileExistsAtPath:documentsPath]) {
    NSError *error = nil;
    BOOL success = [fileManager copyItemAtPath:bundlePath toPath:documentsPath error:&error];
    NSAssert(success, @"%s: copyItemAtPath failed: %@", __FUNCTION__, error);
}

完成后,您现在可以继续在documentsPath打开数据库。