如何在iPhone应用程序更新时更新SQLite数据库?

12

我目前在iTunes应用商店中有一个iPhone应用程序,它使用SQLite数据库作为数据存储。用户可以将应用程序与Web服务同步,返回的数据会被存储在SQLite数据库中。用户还可以将新项目插入到数据库中,并将其更改同步回Web服务。

当连接打开到应用程序的本地数据库时,代码将检查确认数据库文件是否存在于“文档”文件夹中,如果不存在,则通过将其从“资源”文件夹复制到“文档”文件夹中来创建数据库。

我必须发布应用程序的更新版本。更新包含数据库模式更改(新表格、列等)。根据我所读到的,位于“文档”目录中的文件将在应用程序更新时保留,这意味着更新后现有数据库仍将完整保留。

我的问题是,如何用更新的数据库替换现有数据库,并且有没有一种方法可以在不丢失现有数据库中的数据的情况下进行替换?有没有某种“更新后首次运行”事件可用于执行数据库更新,或者我必须对现有数据库进行某种检查(寻找新列或表),并在我的检查失败时手动替换/更新数据库?

谢谢!


请查看此链接,了解一个SQLite包装器,它可以使SQLite操作更加容易-https://github.com/ccgus/fmdb/ - Lalith B
3个回答

18

你应该将应用程序的当前版本号存储在某个持久化的地方,比如数据库或者最好是Defaults数据库中。在启动时,你的应用程序将会将自己的版本号与持久化的版本号进行比较。如果它们不同,那么这就是更新后的第一次运行。如果持久化的版本号不存在,那么显然这也是更新后的第一次运行。

至于更新数据库,如果已经存在,则可以使用通常的SQL ALTER命令来更新模式,并同时进行任何数据库数据迁移。


那么没有内置的“应用程序更新”或“更新后第一次运行”事件/检查或类似的内容吗?听起来像是我需要在每次应用程序加载时检查版本? - Billy
我不知道有没有,但如果有的话,在文档中很容易找到。 - Simon Woodside

4

sqlite3 *数据库; sqlite3_stmt *更新语句 = nil;

if(sqlite3_open([strDatabasePath UTF8String], &database) == SQLITE_OK)
{
   nsstring  *strMQueryupdate="write your query here";

    const char *sql = [strMQueryupdate UTF8String];

    if (sqlite3_prepare_v2(database, sql, -1, &update_statement, NULL) != SQLITE_OK) {
        NSLog(@"update fails");
    }
    else
    {
        sqlite3_bind_text(update_statement, 1, [[arrayname objectAtIndex:0]  UTF8String], -1, SQLITE_TRANSIENT);


        int success = sqlite3_step(update_statement);
        sqlite3_reset(update_statement);
        if (success == SQLITE_ERROR){}
        else {}
    }
    sqlite3_finalize(update_statement);
}
sqlite3_close(database);   

3
我们通过查询服务器上一个plist文件头部的哈希值来检查更新,这个plist文件是通过一个查询服务器数据库的php文件生成的。您可以将该哈希值存储在本地,并将其与应用程序上次运行时的哈希值进行比较,以便手机知道是否版本过期。然后我们在后台下载新的plist文件并更新手机上的数据库。
编辑: 在我们的php文件结尾处,我们获取服务器上生成的plist文件的XML输出的MD5值。
header("MD5-Hash: ". md5($xml_output));
echo $xml_output;

然后,我们可以像这样从userDefaults中获取iPhone上plist的哈希值:
NSUserDefaults* defaults  = [NSUserDefaults standardUserDefaults];
curHash = [defaults stringForKey:kUpdateUserDefault];

而服务器的哈希值从NSURLRequest获取,如下所示:

NSString *hash = [[[res allHeaderFields] objectForKey:kUpdateHeaderField] retain];

然后我们将这两个进行比较,只有在哈希值不匹配的情况下才开始下载:

    if (![curHash isEqualToString:hash]) {
            [self performSelector:@selector(sendUpdateStarted) onThread:[NSThread mainThread] withObject:nil waitUntilDone:NO];
            ... download the file and save it as the new iPhone's plist
    }

这段代码是由我的非常能干的搭档奥利弗·赖斯编写的。


我并不真正理解你的回答。哪个属性列表的哈希值? - Simon Woodside
这似乎还有防止盗版的额外好处。 - Jess
关于防止盗版的问题,除非你在首次加载应用时发送手机的UUID并将其存储起来,否则它无法阻止某人访问你服务器的plist并获取相关信息。如果你想要保护文件,可以在提供数据之前使用这个UUID进行检测。 - Michael Morrison
应该将 [self performSelector:@selector(sendUpdateStarted) onThread:[NSThread mainThread] withObject:nil waitUntilDone:NO]; 改为 [self performSelectorOnMainThread:@selector(sendUpdateStarted) withObject:nil waitUntilDone:NO]; - user102008

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接