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 think your problem stems from requiring authentication with your server.
I recommend the popular AFNetworking library for help with making HTTP calls. You'd subclass AFHTTPClient
in order to provide your authentication details, as in this answer.
Then in your case, you can use AFXMLRequestOperation to download your XML directly. You may then write it to disk. Note you will need to read over the iOS Data Storage Guidelines to see if the Documents folder is appropriate for your use (which I don't think it is; Caches would probably be better).
Now, the reason your ExampleDelegate
code (which looks like it came from here) doesn't work is that ExampleDelegateSuccess
and ExampleDelegateFailure
are block types, so you can't pass your NSData
and NSError *
pointers. You need to provide block objects that conform to the signature of the respective types.
For example:
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]}
];
The blocks will provide you with the NSData
and NSError
instances as required, so you don't need to declare your own. You can learn more about blocks here.
Hope that helps :D
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).
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!
We have large databases that we regularly update. I'm not sure how "large" is large, but we are updating megabytes of data. We Update ours as JSON data. JSON is a little less overhead than XML, and there are lots of readily available libraries (like JSONKit). Some of our users have poor data connections, and sometimes difficulties ensue.
We have been testing different ways of updating. One method breaks the data into multiple JSON files. Each of the files are downloaded separately, and they are then stored separately. One advantage over using multiple files, is that if one fails, you only need to resend that particular file.
Also, we use multiple threads to process up to 5 requests/downloads at a time. This requires much more management, but helps us give a better experience to the user. AFHTTPClient is really good at dealing with this stuff. I'd hate to not use it.
Is it a completely new / distinct database each time, or is an updated version of the same database?
If the latter, have you considered sending only the changes (either via an explicit list of adds/updates/deletes, or using something like Zumero to automate the updates)?