【发布时间】:2013-04-15 12:53:27
【问题描述】:
我的应用需要来自 sqlite 数据库的数据。它将附带该数据库的一个版本,但我需要定期更新它(很可能每月一次)。通常,我一直在通过我设置的一堆 Web 服务将我的应用程序的其他部分作为 XML 发送更新,但是我现在正在处理的这个特定数据库非常大(大约 20-30 MB),而且我当我尝试以这种方式发送时出现超时错误。
我尝试将数据库放在我的公司服务器上,然后将其下载到 NSData 对象中。然后我将该数据对象保存到我的应用程序的 Documents 目录中。当我重新启动我的应用程序时,我收到一条错误消息“路径中的文件似乎不是 SQLite 数据库”。代码如下。
// Download data
NSURL *url = [NSURL URLWithString:@"http://www.mysite.net/download/myDatabase.sqlite"];
NSData *fileData = [[NSData alloc] initWithContentsOfURL:url];
NSLog(@"%@",fileData); // Writes a bunch of 8 character (hex?) strings
// Delete old database
NSError *error;
NSURL *destination = [app applicationDocumentsDirectory];
destination = [destination URLByAppendingPathComponent:@"myDatabase"];
destination = [destination URLByAppendingPathExtension:@"sqlite"];
NSLog(@"destination = %@",destination);
[[NSFileManager defaultManager] removeItemAtPath:[destination path] error:&error];
// Save into correct location
[fileData writeToURL:destination atomically:YES];
//[NSFileManager defaultManager] createFileAtPath:[destination path] contents:fileData attributes:nil]; // I also tried this, it doesn't work either.
是否有更新应用程序将使用的大型数据库的标准程序?我感觉我正在尝试做的事情是不正确的,并且有一种完全不同的方法可以做到这一点,但我不知道是什么。
更新: 我已经尝试了几件事来试图找出问题所在,但没有什么能让我更接近。我将尝试从服务器下载的数据库放到 USB 驱动器上,然后放到我正在开发的 mac 上,然后放到模拟器中我的应用程序的 Documents 文件夹中。当我通过这种方式传输数据库来运行我的应用程序时,它运行没有任何问题,我可以看到我的所有数据。
相反,我从模拟器中完全删除了我的应用程序并重新运行它,因此它将从头开始创建我的数据库。我用 USB 驱动器将这个新制作的数据库从我的 mac 转移到了我的服务器上。一旦文件在我的服务器上,我尝试在上面的代码块中运行我的“下载更新”,但是下次我启动我的应用程序时它仍然崩溃,并出现“路径上的文件似乎不是 SQLite 数据库”错误消息。
通过这些测试,我确信问题不在于我尝试下载的数据库。我的“下载更新”代码中的某些内容损坏了数据库,但我仍然无法找出原因,也没有找到可接受的替代方法来在我的应用启动后将更新发送给我的用户。
更新 2:
我一直在进行更多搜索,并且了解到用户需要输入用户名和密码才能访问我服务器上的任何文件。我现在相信我从上面的代码中返回的NSData 实际上是一个身份验证挑战,或者与此相关的东西,这就是为什么当我用NSFileManager 保存它时它不会被识别为sqlite DB。
我发现通过身份验证的最简单解决方案是here。当我尝试执行NSData *fileData = [NSData dataWithContentsOfURL:url options:NSDataReadingMapped error:&error];(当然,按照链接中的建议更改我的url 之后)时,我收到一个错误NSCocoaErrorDomain Code=256,这只是未知错误。这样做之后,我的fileData 是nil。我注意到这个帖子很老了,所以我不知道它是否仍然支持。
我还使用NSURLConnection 而不是dataWithContentsOfURL 找到了身份验证问题here 的不同解决方案。这是较新的,但在该示例中使用了一些我以前从未真正见过的更高级的语法。我几乎可以从示例中复制粘贴,并且我的项目将毫无错误地构建,但我不知道使用UIViewController 中的fetchURL:withCompletion:failure: 例程的正确语法。我试过了
NSError *error;
NSData *fileData;
ExampleDelegate *download = [[ExampleDelegate alloc] init];
[download fetchURL:url withCompletion:fileData failure:&error];
但是发送不兼容的指针会导致构建错误。我想我不能将NSData 和NSError 分别作为ExampleDelegateSuccess 和ExampleDelegateFailure 对象传递,即使它们来自typedef。我可能必须对fileData 和error 做一些事情来转换它们,但是typedefing 是我上面提到的“高级外观语法”之一,我真的不知道该怎么做。
它没有包含在他的示例中,但我发现了另一个名为 connection:didReceiveAuthenticationChallenge: here 的 NSURLConnectionDelegate 方法,我想我可以将其添加到示例中的代码中,这应该可以解决我的身份验证问题。我觉得如果我只知道如何打电话给fetchURL 我会被设置。有人对我需要做些什么来让fileData 和error 参与该电话有任何建议吗?
【问题讨论】:
标签: ios objective-c sqlite updates