在 iOS 中使用 NSURLConnection 以串行顺序下载文件

Posted

技术标签:

【中文标题】在 iOS 中使用 NSURLConnection 以串行顺序下载文件【英文标题】:Downloading files in serial order using NSURLConnection in iOS 【发布时间】:2015-07-13 13:56:24 【问题描述】:

我想按顺序下载 3 个文件。其中两个是 txt 文件,一个是 .gz 文件。我正在使用 NSURLConnection 下载上述文件。

我对 ios 编程非常陌生。我在 SO 和 google 的其他问题中看到我们可以使用串行调度队列串行执行一些操作。

但我不知道如何使用 NSURLConnection 来做到这一点。我在下面尝试过,但没有成功。

 dispatch_queue_t serialQueue = dispatch_queue_create("com.clc.PropQueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQueue, ^
    [self downloadProp];
);
dispatch_async(serialQueue, ^
    [self downloadDatabase];
);
dispatch_async(serialQueue, ^
    [self downloadTxt];
);

上面的代码没有执行 NSURLCONnection 的 connectionDidFinishLoading。任何人都知道如何实现这一目标?

【问题讨论】:

那么你需要做的就是发出3个独立的同步网络请求。 这篇文章向您展示了如何发出同步请求:***.com/a/7262578/4657588 您好 Anjali,请使用 AFNetworking 框架,该框架使用基于块的请求。我们不再真正使用 NSURLConnection,它已被 NSURLSession 取代,您正在使用遗留库和代码。其他人建议使用同步请求,我个人只是将一些异步请求链接在一起以达到相同的效果而不阻塞主线程。 如果您最终使用了同步请求,请确保不要在主线程上使用它,否则您的 UI 将阻塞并且您的应用程序可能会被系统终止。 @SteveWilford 好点,我猜你可以做 3 个异步请求,并让他们在完成后调用下一个请求。 【参考方案1】:

NSURLSession 提供了一个队列,该队列将按照创建顺序下载每个任务。

罢工>

NSURLSession *session = [NSURLSession sharedSession];

NSURLSessionTask *task1 = [session dataTaskWithURL:[NSURL URLWithString:@"http://yahoo.com"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) 
    NSLog(@"Complete 1");
];
NSURLSessionTask *task2 = [session dataTaskWithURL:[NSURL URLWithString:@"http://msn.com"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) 
    NSLog(@"Complete 2");
];
NSURLSessionTask *task3 = [session dataTaskWithURL:[NSURL URLWithString:@"http://google.com"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) 
    NSLog(@"Complete 3");
];

// Regardless of which order the tasks are "resumed" (aka started) they will execute synchronously in the order added, above.
[task3 resume];
[task1 resume];
[task2 resume];

基于 cmets 和聊天的更新:

为了更加确定任务的排序和执行...

NSURLSession *session = [NSURLSession sharedSession];

__block NSURLSessionTask *task1 = nil;
__block NSURLSessionTask *task2 = nil;
__block NSURLSessionTask *task3 = nil;

task1 = [session dataTaskWithURL:urlToFirstFile completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) 
    // CHECK ERROR
    NSLog(@"First file completed downloading");
    [task2 resume];
];
task2 = [session dataTaskWithURL:urlToSecondFile completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) 
    // CHECK ERROR
    NSLog(@"Second file completed downloading");
    [task3 resume];
];
task3 = [session dataTaskWithURL:[NSURL URLWithString:@"http://google.com"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) 
    // CHECK ERROR
    NSLog(@"Third file completed downloading");
];

[task1 resume];

【讨论】:

Steve...你能帮我实现 NSURLSession 的代表方法吗,或者只是指向我可以参考的任何链接?正如我之前使用 NSURLConnection 一样......而且我有一个 .gz 文件,一旦下载完成,我必须解压缩。 如果您使用我的答案中的代码,则不需要使用委托方法,一旦下载了 URL 的内容,就会调用每个块。 有一个疑问... NSURLSession 总是在后台运行吗?在我的应用程序中,当我在应用程序未运行时打开应用程序而不是在 bakckground 时,我想下载文件。 Spinner 一直运行,直到下载发生。 但是我怎么知道文件已完全下载,因为我还必须解压缩压缩文件。我还有一些其他条件,比如如果第一个文件被下载,那么只有它应该继续进行,否则停止下载。 NSURLSession does not always run 在后台:“数据任务使用 NSData 对象发送和接收数据。数据任务用于从您的应用程序到服务器的简短的、通常是交互式的请求。数据任务可以将数据返回到在接收到每条数据后,您的应用一次一件,或者通过完成处理程序一次性完成。因为数据任务不将数据存储到文件中,所以后台会话不支持它们”。【参考方案2】:

确保串行操作的简单递归解决方案。

func serialisedRequests(session: URLSession, requests: [URLRequest], index: Int = 0) 

    if index >= requests.count 
        return
    

    let task = session.dataTask(with: requests[index]) 
        data, response, error in
        serialisedRequests(session: session, requests: requests, index: index+1)
    
    task.resume()

【讨论】:

【参考方案3】:

只需将您的NSURLSessionHTTPMaximumConnectionsPerHost 属性设置为1,然后按您想要的顺序添加任务。

有关详细信息,请参阅此答案: https://***.com/a/21018964

【讨论】:

这种方法的唯一问题是,如果下载是从不同的主机发生的,它将无法工作。 this more recent answer - 这让我们回到这个问题的公认答案 - 为什么HTTPMaximumConnectionsPerHost 没有帮助。

以上是关于在 iOS 中使用 NSURLConnection 以串行顺序下载文件的主要内容,如果未能解决你的问题,请参考以下文章

iOS学习笔记12-网络NSURLConnection

NSURLConnection IOS 3G 问题

iOS 中的 JSON 请求 - 使用 Grand Central Dispatch 或 NSURLConnection

iOS开发之网络编程--使用NSURLConnection实现大文件下载

iOS5 中的 NSURLConnection

我在 iOS 中收到 NSURLConnection 的错误 -1100?