问题
Today I have an application that reads a plist site, but would it work like this:
when you open the app it checks if the User already has the plist on device and if that is the latest version.
If you have not or not it is the latest version of the server catches
http://lab.vpgroup.com.br/aplicativos/teste-catalogo/lista.plist
How could I do this? I have seen many questions here on stackoverflow, but none worked as I need.
Thanks
回答1:
you never want to block the UI. Downloading can take a long time. Therefore do it in background. Easiest is using NSURLConnection's convenience method sendAsynchronousRequest:request
Like the name says, it is asynchronous and calls the passed completion block when the download finished
NSURL *url = [NSURL URLWithString:@"http://lab.vpgroup.com.br/aplicativos/teste-catalogo/lista.plist"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSDictionary *dict = [NSPropertyListSerialization propertyListFromData:data mutabilityOption:0 format:0 errorDescription:nil];
NSLog(@"%@", dict);
}];
Sample:
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
@autoreleasepool {
NSURL *url = [NSURL URLWithString:@"http://lab.vpgroup.com.br/aplicativos/teste-catalogo/lista.plist"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSDictionary *dict = [NSPropertyListSerialization propertyListFromData:data mutabilityOption:0 format:0 errorDescription:nil];
NSLog(@"%@", dict);
}];
//just for demo
[[NSRunLoop currentRunLoop] run];
}
}
回答2:
You can make a HEAD call to the path, and get the Etag which would be stored on the device, if the etag saved on the device is not equal to the etag the server sends then download the file, store the new Etag and overwrite the device file. You could also get by with the Last-Modified: header, but etag is probably best. You may need to enable Entity Tags on your server.
For clarification HEAD only sends the headers for a file so usually much lighter weight than sending the whole file for comparison.
This is how browsers manage their local cache for static files and urls, in that scenario the browser sends their Etag and the browser returns 304 unmodified, so you could also look into reproducing this protocol of sending your stored etag and have the browser either return the file or a 304 header.
回答3:
I am just replying on what strategy you could use and not how you implement, sync or asyn is something that depends on the context it is being used.
My suggestion would be to add a request to NSOperationque as suggested by Diaj-Djan above.
To Answer how you could do it: There are couple of ways you can achieve that:
Option 1: If you can add a property to the plist file lets say Version and If you can have a service exposed which sends you the version number. Else Option 2. For the first time you will download the plist file obviously and persist the version on your device the way you wish to. On subsequent download--> fist check the persisted version from device and see if there is a new version available in the server from the exposed service --> If Yes --> Make a service call to get the plist file --> else use the one in the device. This way you get to save lot of time/data download every time downloading a plist (specially if its huge)
Option 2: You make a service call every time, get the plist file, compare the properties and see if there are any changes. This is not a good option though, it is time consuming , lot of processing.
回答4:
I used the base that @ daij-Djan went and created above, worked perfectly.Like this:
in my. h #import
@interface ViewController : UIViewController{
NSArray *paths;
NSString *documentsDirectory;
NSString *myPathDocs;
NSFileManager *fileManager;
NSString *filePath;
NSString *documentsPath;
NSURL *url;
}
in my. m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
documentsDirectory = [paths objectAtIndex:0];
//filename that will save in device
filePath = [documentsDirectory stringByAppendingPathComponent:@"lista.plist"];
[self showData];
[self updatingData];
}
- (void) updatingData {
NSLog(@"updating Data");
url = [NSURL URLWithString:@"http://lab.vpgroup.com.br/aplicativos/teste-catalogo/lista.plist"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSDictionary *dict = [NSPropertyListSerialization propertyListFromData:data mutabilityOption:0 format:0 errorDescription:nil];
NSLog(@"%@", dict);
@try {
[dict writeToFile:filePath atomically:YES];
NSLog(@"Saved!! path: %@", filePath);
}
@catch (NSException *exception) {
NSLog(@"Error writing. Erro: %@", [exception description]);
}
[self showData];
}];
}
- (void) showData {
NSString *pathFinal = filePath;
if (![[NSFileManager defaultManager] fileExistsAtPath:filePath])
{
// if failed to get the plist server uses the local built
pathFinal = [[NSBundle mainBundle] pathForResource:@"lista" ofType:@"plist"];
}
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:pathFinal];
NSLog(@"data displayed: %@", dict);
}
来源:https://stackoverflow.com/questions/19101179/download-plist-from-server