不使用XML更新sqlite数据库 [英] Updating sqlite database without XML
问题描述
我的应用需要来自sqlite数据库的数据。它将附带此数据库的一个版本,但我需要定期更新它(很可能每月一次)。通常情况下,我一直在通过我设置的一堆网络服务将我的应用程序的其他部分的更新作为XML发送,但我现在正在处理的这个特定数据库相当大(大约20-30 MB),而且我当我尝试以这种方式发送时出现超时错误。
My app requires data from a sqlite database. It will ship with a version of this database, but I need to update it on a regular basis (most likely once a month). Typically I've been sending updates for other parts of my app as XML through a bunch of webservices I've set up, but this particular database I'm working on now is pretty large (about 20-30 MB), and I'm getting timeout errors when I try to send it that way.
我尝试将数据库放在公司服务器上,然后将其下载到 NSData
对象。然后我将该数据对象保存到我的应用程序的Documents目录中。当我重新启动我的应用程序时,我收到一条错误消息路径中的文件似乎不是SQLite数据库。代码如下。
I tried putting the database on my companies server, then downloading it into an NSData
object. I then saved that data object to my app's Documents directory. When I restart my app, I get an error saying "File at path does not appear to be a SQLite database". Code for this is below.
// 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.
是否有更新应用程序将使用的大型数据库的标准程序?我觉得我正在尝试做的是不正确的,并且有一种完全不同的方式来做到这一点,但我无法弄清楚是什么。
Is there a standard procedure for updating a large database that an app will use? I get the feeling that what I'm trying to do is incorrect and that there is a totally different way to do this, but I can't figure out what.
更新:
我尝试了几件事来试图找到问题,但没有什么能让我更接近。我把我想要从我的服务器上下载的数据库放到USB驱动器上然后放到我正在开发的mac上,然后放入模拟器中我的应用程序的Documents文件夹中。当我通过这种方式传输数据库来运行我的应用程序时,它运行没有任何问题,我可以看到我的所有数据。
UPDATE: I've tried a couple things to try to find the problem, but nothing is getting me any closer. I put the database I'm trying to download from my server onto a USB drive and then onto the mac I'm developing on, and into the Documents folder for my app in the Simulator. When I run my app by transferring the database this way, it runs without any problem and I can see all my data.
相反,我完全从模拟器中删除了我的应用程序并重新运行它,因此它将从头开始创建我的数据库。我使用USB驱动器将这个新制作的数据库从我的mac传输到我的服务器上。一旦文件在我的服务器上,我试图在上面的代码块中运行我的下载更新,但是下次我启动我的应用时仍然会崩溃路径中的文件似乎不是SQLite数据库错误消息。
Conversely, I completely removed my app from the simulator and re-ran it, so it would create my database from scratch. I transferred this newly-made database from my mac onto my server with the USB drive. Once the file was on my server, I tried to run my "download update" in the code block above, but it still crashes the next time I start my app with the "File at path does not appear to be a SQLite database" error message.
从这些测试中,我确信问题不在于我正在尝试下载的数据库。我的下载更新代码中的某些内容正在破坏数据库,但我仍然无法弄清楚原因,也没有找到一种可接受的替代方法,以便在我的应用启动后将更新发送给我的用户。
From these tests, I'm confident that the problem is not with the database I'm trying to download. Something in my "download update" code is corrupting the database, but I still haven't been able to figure out why, nor have I found an acceptable alternate method to get my updates out to my users once my app launches.
更新2:
我一直在做更多搜索,我已经了解到用户需要输入用户名和密码来访问我服务器上的任何文件。我现在相信 NSData
我从上面的代码中回来实际上是一个身份验证挑战,或者与之相关的东西,这就是为什么当我用 NSFileManager
它不被识别为sqlite数据库。
UPDATE 2:
I've been doing some more searching, and I've learned that a user will need to put in a username and password to access any file on my server. I now believe that the NSData
I'm getting back from my code above is actually an authentication challenge, or something related to that, and that's why when I save it with the NSFileManager
it's not being recognized as a sqlite DB.
我发现通过身份验证的最简单的解决方案是此处。当我尝试 NSData * fileData = [NSData dataWithContentsOfURL:url options:NSDataReadingMapped error:& error];
(更改我的 url后
正如链接中所建议的那样),我收到错误 NSCocoaErrorDomain Code = 256
,这只是未知错误。执行此操作后,我的 fileData
为 nil
。我注意到这篇文章很老了,所以我不知道它是否仍然受支持。
The simplest solution I've found to get through the authentication is here. When I try to do NSData *fileData = [NSData dataWithContentsOfURL:url options:NSDataReadingMapped error:&error];
(after changing my url
as suggested in the link, of course), I get an error NSCocoaErrorDomain Code=256
, which is just unknown error. My fileData
is nil
after doing this. I've noticed this post is quite old, so I don't know if it is still supported.
我还发现了一个不同的身份验证问题解决方案这里使用 NSURLConnection
而不是 dataWithContentsOfURL
。这是更近期的,但在该示例中使用了一些我以前没有见过的更高级的语法。我能够从示例中复制粘贴,我的项目将构建没有错误,但我不知道使用 fetchURL的正确语法:withCompletion:failed:
来自我的 UIViewController
的例程。我试过
I also found a different solution to the authentication problem here using an NSURLConnection
instead of dataWithContentsOfURL
. This is much more recent, but there is some more advanced looking syntax used in that example that I haven't really seen before. I was able to pretty much copy-paste from the example, and my project will build without errors, but I don't know the proper syntax for using the fetchURL:withCompletion:failure:
routine from my UIViewController
. I tried
NSError *error;
NSData *fileData;
ExampleDelegate *download = [[ExampleDelegate alloc] init];
[download fetchURL:url withCompletion:fileData failure:&error];
但这会导致发送不兼容指针的构建错误。我想我不能直接 NSData
和 NSError
传递 ExampleDelegateSuccess $ c分别是$ c>和
ExampleDelegateFailure
对象,即使它们是 typedef
ed from。我可能需要做一些事情来 fileData
和错误
来转换它们,但那个 typedef
ing是上面提到的高级语法之一,我真的不知道该怎么做。
but that gives a build error for sending an incompatible pointer. I think I can't pass a straight NSData
and NSError
as ExampleDelegateSuccess
and ExampleDelegateFailure
objects respectively, even though that what they are typedef
ed from. I probably have to do something to fileData
and error
to convert them, but that typedef
ing is one of the "advanced looking syntax" I was referring to above, and I don't really know what to do.
它不是包含在他的示例中,但我发现另一个名为的
在其中我认为我可以添加到示例中的代码中,这应该可以解决我的身份验证问题。我觉得如果我只知道如何调用 NSURLConnectionDelegate
方法:didReceiveAuthenticationChallenge: fetchURL
我会被设置。有没有人对我需要做什么建议才能将 fileData
和错误
纳入该电话?
It's not included in his example, but I found another NSURLConnectionDelegate
method called connection:didReceiveAuthenticationChallenge:
here that I think I can just add into the code from the example, and that should solve my authentication issue. I feel if I just knew how to call fetchURL
I'd be set. Does anyone have any advice on what I need to do to get fileData
and error
into that call?
推荐答案
我最终使用 AFNetworking 解决了我的问题。我能够在没有继承 AFHTTPClient
的情况下做到这一点(参见我的回答这里,我发布了这个问题的后续内容)。
I ultimately ended up using AFNetworking to solve my problem, as suggested by @silver_belt. I was able to do it without subclassing AFHTTPClient
though (see my answer here, which I posted as a follow up to this question).
最后,我只需要在我的视图控制器的.h文件中 #includeAFHTTPRequestOperation.h
,然后在我使用的.m中
In the end, I just had to #include "AFHTTPRequestOperation.h"
in my view controller's .h file, then in the .m I used
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];
当我真的想开始下载时。希望这将使任何想要在未来做到这一点的人更容易!
when I actually wanted to start my download. Hope this will make it easier for anyone looking to do this in the future!
这篇关于不使用XML更新sqlite数据库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!