从服务器下载 plist

Posted

技术标签:

【中文标题】从服务器下载 plist【英文标题】:Download plist from server 【发布时间】:2013-09-30 18:27:12 【问题描述】:

今天我有一个读取 plist 站点的应用程序,但它会像这样工作吗:

当您打开应用程序时,它会检查用户是否已经在设备上拥有 plist,以及是否是最新版本。

如果你没有或不是最新版本的服务器捕获

http://lab.vpgroup.com.br/aplicativos/teste-catalogo/lista.plist

我怎么能这样做? 我在 *** 上看到了很多问题,但没有一个可以满足我的需要。

谢谢

【问题讨论】:

您想阅读您的 plist 或将版本与设备中的当前 plist 进行比较? 【参考方案1】:

您永远不想阻止用户界面。下载可能需要很长时间。因此在后台进行。最简单的就是使用NSURLConnection的便捷方法sendAsynchronousRequest:request 顾名思义,它是异步的,下载完成后调用传入的完成块

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);
]; 

示例:

#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];
    

【讨论】:

虽然考虑调用是否应该是异步的是正确的,但正确的答案可能是同步调用。许多应用程序必须在初始屏幕加载(无 UI)期间首先检查服务器。就其本身而言,异步总是正确的答案并不一定是正确的。上下文推动了这一决定。 没有。对于 IO,异步总是正确的。 (您可以将其卸载到后台线程。我将其视为异步)您绝不能阻塞 ui 线程 想象一下这个简单的例子,如果连接超时。应用程序无法启动,并且 ios 的看门狗会因为太慢而杀死您的应用程序 是的,我的意思是等待通话结束后再继续。这可以通过在后台线程或操作等上进行同步调用来实现。 你当然可以假装模态执行......就像使用uialertviews【参考方案2】:

您可以对路径进行 HEAD 调用,并获取将存储在设备上的 Etag,如果保存在设备上的 etag 不等于服务器发送的 etag,则下载文件,存储新的 Etag并覆盖设备文件。您也可以使用 Last-Modified: 标头,但 etag 可能是最好的。您可能需要在您的服务器上启用实体标签。

为澄清起见,HEAD 仅发送文件的标题,因此通常比发送整个文件进行比较要轻得多。

这是浏览器管理静态文件和 url 的本地缓存的方式,在这种情况下,浏览器发送其 Etag 并且浏览器返回 304 未修改,因此您还可以考虑重现此发送存储的 etag 的协议并让浏览器返回文件或 304 标头。

【讨论】:

【参考方案3】:

我只是在回答你可以使用什么策略,而不是你如何实现、同步或异步,这取决于它所使用的上下文。

我的建议是按照上面 Diaj-Djan 的建议向 NSOperationque 添加请求。

回答你是怎么做到的: 有几种方法可以实现:

    选项 1:如果您可以向 plist 文件添加属性,可以说是版本,如果您可以公开向您发送版本号的服务。其他选项 2。 第一次,您显然会下载 plist 文件,并以您希望的方式将版本保存在您的设备上。 在随后的下载中-->首先检查设备中的持久版本,看看服务器中是否有来自暴露服务的新版本-->如果是-->进行服务调用以获取 plist 文件-->否则使用设备中的那个。 这样,您每次下载 plist 时都可以节省大量时间/数据下载(特别是如果它很大)

    选项2:你每次调用服务,获取plist文件,比较属性看看有没有变化。虽然这不是一个好的选择,但它很耗时,需要大量处理。

【讨论】:

如果您已经制定了策略,那么我可以向您建议一个很好的实施方法。【参考方案4】:

我使用了@daij-Djan 在上面创建的基础,完美运行。像这样:

在我的。 H #导入

@interface ViewController : UIViewController
    NSArray *paths;
    NSString *documentsDirectory;
    NSString *myPathDocs;
    NSFileManager *fileManager;
    NSString *filePath;
    NSString *documentsPath;

    NSURL *url;

在我的。米

- (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);


【讨论】:

Olá Claudia, obrigado pela sua resposta que, mesmo depois de muito tempo, me ajudou muito。

以上是关于从服务器下载 plist的主要内容,如果未能解决你的问题,请参考以下文章

从 URL 下载 plist 并将其解析为 NSMutableDictionary?

从下载的 plist 中重新加载 UITableView 数据

从 iPhone 上的表格视图中下载的内容将数组保存到 PList

如何从服务器端 JavaScript 获取值并将它们存储在 Swift 的 plist 中?

使用 ASIHTTPRequest 下载 plist 只能部分工作

从未保存的 plist 中读取