简而言之,我试图显示来自Web上公开可用的JSON文件的数据。该过程如下:
我以NSURLSessionDataTask
启动下载,然后解析并显示JSON或处理错误(如果发生的话)。这是我的相关代码:
- (void) initiateDownload {
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfig.timeoutIntervalForRequest = 5.0f;
sessionConfig.timeoutIntervalForResource = 20.0f;
NSURLSessionDataTask *downloadWeatherTask = [urlSession dataTaskWithRequest:urlRequest
completionHandler:^(NSData *data, NSURLResponse *response, NSError *downloadError) {
if (downloadError) {
dispatch_sync(dispatch_get_main_queue(), ^{
[self errorReceived:downloadError];
});
} else if (data) {
dispatch_sync(dispatch_get_main_queue(), ^{
[self parseWeatherJSON:data];
});
}
}];
[downloadWeatherTask resume];
}
我对此有两个问题:
我对线程处理不是很熟悉。虽然我添加了
dispatch_sync(dispatch_get_main_queue(), ...)
对于两个完成块,似乎都可以正常工作,我不确定这是否是确保线程安全的最佳方法(之前,我收到各种错误消息,并且在下载完成后的10秒内显示数据) 。有没有更好的方法来处理下载,线程或我的是可接受的解决方案?
我希望用户在他/她想刷新显示的数据时能够手动启动下载过程。首先,我初始化了一次NSURLSessionDataTask
并将其在类中的任何位置都可用;这样我每次调用刷新时都可以调用简历。但是,我找不到重新执行下载过程的命令。呼叫[downloadWeatherTask resume]
后,便无法从头开始任务。
因此,我将任务添加到一个单独的函数(如上所示)中,并在每次调用该函数时在那里对其进行初始化。这很好,但是我不确定这是最好的方法。例如,它是内存安全的还是我每次用户发起刷新调用并最终将耗尽内存时创建一个新任务?
谢谢您的回答!
更多信息:我使用最新的XCode 11,目标是iOS 9及更高版本。
NSURLSession
默认情况下,将使用专用的后台串行队列作为完成块(以及委托方法,如果需要的话)。但是,您确实要确保从主队列中触发UI更新(通过dispatch_get_main_queue()
检索)。而且,您通常希望避免从多个线程更新属性和ivars(除非它们内置了一些线程安全性,这是不寻常的),因此将更新这些属性/ ivas的更新分派回主队列非常简单线程安全的方法。
所以,最重要的是,您在这里所做的事情很好。
但是,我找不到重新执行下载过程的命令。
您仅执行(resume
)给定任务一次。如果要再次执行类似的请求,请实例化一个新的NSURLSessionDataTask
。