不使用XML更新sqlite数据库

Gen*_*ike 6 sqlite objective-c updates ios

我的应用程序需要来自sqlite数据库的数据.它将附带此数据库的一个版本,但我需要定期更新它(很可能每月一次).通常情况下,我一直在通过我设置的一堆网络服务将我的应用程序的其他部分的更新作为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.
Run Code Online (Sandbox Code Playgroud)

是否有更新应用程序将使用的大型数据库的标准过程?我觉得我正在尝试做的是不正确的,并且有一种完全不同的方式来做到这一点,但我无法弄清楚是什么.


更新:我尝试了几件事来试图找到问题,但没有什么能让我更接近.我把我想要从我的服务器上下载的数据库放到USB驱动器上,然后放到我正在开发的mac上,然后放入模拟器中我的应用程序的Documents文件夹中.当我通过这种方式传输数据库来运行我的应用程序时,它运行没有任何问题,我可以看到我的所有数据.

相反,我完全从模拟器中删除了我的应用程序并重新运行它,因此它将从头开始创建我的数据库.我使用USB驱动器将这个新制作的数据库从我的mac传输到我的服务器上.一旦文件在我的服务器上,我试图在上面的代码块中运行我的"下载更新",但是下次我启动我的应用时它仍然会崩溃"路径中的文件似乎不是SQLite数据库"错误信息.

从这些测试中,我确信问题不在于我正在尝试下载的数据库.我的"下载更新"代码中的某些内容正在破坏数据库,但我仍然无法弄清楚原因,也没有找到一种可接受的替代方法,以便在我的应用启动后将更新发送给我的用户.


更新2:我一直在做更多的搜索,我已经了解到用户需要输入用户名和密码来访问我服务器上的任何文件.我现在相信NSData我从上面的代码中回来实际上是一个身份验证挑战,或者与此相关的东西,这就是为什么当我保存它时NSFileManager它不被识别为sqlite DB.

我发现通过身份验证的最简单的解决方案就在这里.当我尝试这样做时NSData *fileData = [NSData dataWithContentsOfURL:url options:NSDataReadingMapped error:&error];(当然在改变我url的链接之后),我得到一个错误NSCocoaErrorDomain Code=256,这只是未知的错误.我fileDatanil这样做了.我注意到这篇文章很老了,所以我不知道它是否仍然受到支持.

我还发现了一个不同的解决身份认证问题在这里使用的NSURLConnection,而不是dataWithContentsOfURL.这是更近期的,但在该示例中使用了一些我以前没有见过的更先进的语法.我能够从示例中复制粘贴,我的项目将构建没有错误,但我不知道使用fetchURL:withCompletion:failure:我的例程的正确语法UIViewController.我试过了

NSError *error;
NSData *fileData;
ExampleDelegate *download = [[ExampleDelegate alloc] init];
[download fetchURL:url withCompletion:fileData failure:&error];
Run Code Online (Sandbox Code Playgroud)

但是这会导致发送不兼容指针的构建错误.我认为我不能分别传递直接NSDataNSErroras ExampleDelegateSuccessExampleDelegateFailure对象,即使它们是typedef由它们编写的.我可能不得不做一些事情fileData,并error把它们转换,但typedefING是"高级语法看"我指的是上面的一个,我真的不知道该怎么办.

它没有包含在他的示例中,但我发现了另一个NSURLConnectionDelegate调用connection:didReceiveAuthenticationChallenge: 此处的方法,我认为我可以添加到示例中的代码中,这应该可以解决我的身份验证问题.我觉得如果我知道如何打电话fetchURL我会被设定.有没有人有什么我需要做的就是任何意见fileData,并error为这一呼吁?

Gen*_*ike 3

正如@silver_belt 的建议,我最终使用AFNetworking来解决我的问题。不过,我能够在不进行子类化的情况下做到这一点AFHTTPClient请参阅我的答案,我将其作为此问题的后续内容发布)。

最后,我只需要#include "AFHTTPRequestOperation.h"在视图控制器的 .h 文件中,然后在我使用的 .m 文件中

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"ftp://myUsername:myPassword@www.mysite.net/myfile.sqlite"]];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
NSURL *path = [[[app applicationDocumentsDirectory] URLByAppendingPathComponent:@"myfile"] URLByAppendingPathExtension:@"sqlite"];
operation.outputStream = [NSOutputStream outputStreamWithURL:path append:NO];

[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
    {
        NSLog(@"Successfully downloaded file to path: %@",path);
    }
                                 failure:^(AFHTTPRequestOperation *operation, NSError *error)
    {
        NSLog(@"Error in AFHTTPRequestOperation in clickedButtonAtIndex on FlightInfoController.m");
        NSLog(@"%@",error.description);
    }];

[operation start];
Run Code Online (Sandbox Code Playgroud)

当我真正想开始下载时。希望这将使将来想要这样做的人变得更容易!