ios - 在不使用XML的情况下更新sqlite数据库

标签 ios objective-c sqlite updates

我的应用程序需要来自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文件夹中。当我通过这种方式传输数据库来运行我的应用程序时,它运行起来没有任何问题,我可以看到我的所有数据。

相反,我从模拟器中完全删除了我的应用程序,然后重新运行它,因此它将从头开始创建数据库。我使用Mac驱动器将这个新建的数据库从Mac转移到了服务器上。一旦文件在我的服务器上,我尝试在上面的代码块中运行我的“下载更新”,但是下次我启动我的应用时出现“文件在路径似乎不是SQLite数据库”错误,它仍然崩溃信息。

通过这些测试,我相信问题不在于我尝试下载的数据库。我的“下载更新”代码中的某些内容破坏了数据库,但是我仍然无法弄清原因,也没有找到一种可接受的替代方法,可在我的应用启动后将更新发布给用户。

更新2:
我一直在进行更多搜索,并且了解到用户需要输入用户名和密码才能访问服务器上的任何文件。我现在相信我从上面的代码中获得的NSData实际上是身份验证挑战,或与此相关的某些事物,这就是为什么当我将其与NSFileManager保存在一起时,它并未被识别为sqlite数据库。

我发现通过身份验证获得的最简单解决方案是here。当我尝试执行NSData *fileData = [NSData dataWithContentsOfURL:url options:NSDataReadingMapped error:&error];时(当然,按照链接中的建议更改了url后),我收到一条错误NSCocoaErrorDomain Code=256,这只是未知错误。完成此操作后,我的fileDatanil。我注意到这篇文章已经很老了,所以我不知道它是否仍然受支持。

我还发现了使用NSURLConnection而不是dataWithContentsOfURL来解决身份验证问题here的另一种解决方案。这是最近的事情,但是在该示例中使用了一些更高级的语法,而我之前从未真正看到过。我可以从示例中进行很多复制粘贴,并且我的项目将正确构建,但是我不知道从fetchURL:withCompletion:failure:使用UIViewController例程的正确语法。我试过了
NSError *error;
NSData *fileData;
ExampleDelegate *download = [[ExampleDelegate alloc] init];
[download fetchURL:url withCompletion:fileData failure:&error];

但这会导致发送不兼容指针的构建错误。我想我不能将直接的NSDataNSError分别作为ExampleDelegateSuccessExampleDelegateFailure对象传递,即使它们是typedef的来源。我可能必须对fileDataerror进行一些操作才能将它们转换,但是typedef编码是我上面提到的“高级语法”之一,我真的不知道该怎么做。

它没有包含在他的示例中,但是我发现了另一个称为NSURLConnectionDelegate hereconnection:didReceiveAuthenticationChallenge:方法,我认为我可以将其添加到示例代码中,这应该可以解决我的身份验证问题。我觉得如果我只知道如何调用fetchURL,我就会被设置。有人对我需要做什么以使fileDataerror进入该调用有任何建议吗?

最佳答案

我认为您的问题源于要求对服务器进行身份验证。

我建议使用流行的AFNetworking库来进行HTTP调用。您可以将AFHTTPClient子类化,以便提供您的身份验证详细信息,如this answer一样。

然后,根据您的情况,您可以使用 AFXMLRequestOperation 直接下载XML。然后,您可以将其写入磁盘。请注意,您将需要阅读iOS Data Storage Guidelines,以查看Documents文件夹是否适合您的使用(我认为不适合;缓存可能会更好)。

现在,您的ExampleDelegate代码(看起来好像来自here)不起作用的原因是ExampleDelegateSuccessExampleDelegateFailure是块类型,因此您无法传递NSDataNSError *指针。您需要提供符合各个类型签名的块对象。

例如:

ExampleDelegate *download = [[ExampleDelegate alloc] init];
[download fetchURL:url 
          withCompletion:^(NSData *thedata) {
    NSLog(@"Success! Data length: %d", theData.length);

    // Delete old database
    NSError *error;

    // You need to declare 'app' here so you can use it in the line below.
    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
    BOOL success = [fileData writeToURL:destination atomically:YES];
    NSLog(@"File written successfully? %d", success);
} 
          failure:^(NSError *theError){ 
    NSLog(@"Failure: %@", [theError localizedDescription]}
];

这些块将根据需要为您提供NSDataNSError实例,因此您无需声明自己的实例。您可以了解有关here块的更多信息。

希望对您有帮助:D

关于ios - 在不使用XML的情况下更新sqlite数据库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16150196/

相关文章:

ios - 当我们使用 ARC 或手动内存管理时,iOS 中的内存管理哪个更好?

sqlite - 如何在sqlite3中清除cmd的屏幕?

c++ - 如何在我的 C++ 项目中包含 SQLite DLL?

java - 将 Mysql 转换为 Sqlite 数据库

iOS |如何保持覆盖标签宽度与实际图像相同而不是 XCode 中的 ImageView

ios - ios 的 Icecast 源码客户端

objective-c - 多个图像/按钮相对于可缩放图像上的位置保持不变

ios - 为什么我的 ipa 中有两个 dsym 文件?

ios - cgfloat swift 的二维数组

javascript - 单个 html 页面 - html 图表 -