Objective c 使用NSURLSessionDataTask处理线程

Objective c 使用NSURLSessionDataTask处理线程,objective-c,ios9,nsurlsession,ios13,xcode11,Objective C,Ios9,Nsurlsession,Ios13,Xcode11,简而言之,我试图显示来自WEB上公开可用的JSON文件的数据。过程如下: 我使用一个NSURLSessionDataTask启动下载,然后解析并显示JSON或处理出现的错误。这是我的相关代码: - (void) initiateDownload { NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; sessionConfig.

简而言之,我试图显示来自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
    一次,并使它在类中的任何地方都可用;所以每次调用刷新时,我都可以调用resume。但是,我找不到重新执行下载过程的命令。一旦我调用了
    [downloadWeatherTask resume]
    ,我就无法从头开始任务

    因此,我将该任务添加到一个单独的函数(您在上面看到的那个)中,并在每次调用该函数时对其进行初始化。这很好,但我不确定这是最好的方式。例如,它是内存安全的还是每次用户启动刷新调用时我都会创建一个新任务,最终会耗尽内存

  • 谢谢你的回答


    更多信息:我使用最新的XCode 11和目标iOS 9及更高版本。

    默认情况下,NSURLSession将使用专用的后台串行队列来完成块(以及委托方法,如果您这样做的话)。但您确实希望确保从主队列触发UI更新(通过
    dispatch\u get\u main\u queue()
    检索)。通常,您希望避免从多个线程更新属性和IVAR(除非它们内置了一些线程安全性,这是不寻常的),因此将这些属性/IVAR的更新发送回主队列是实现线程安全的一种简单方法

    所以,底线是,你在这里做的很好

    但是,我找不到重新执行下载过程的命令


    您只需执行一次给定任务(
    恢复
    )。如果要再次执行类似的请求,请实例化一个新的
    NSURLSessionDataTask

    ,前提是您原谅了不相关的观察,但您正在创建一个
    NSURLSessionConfiguration
    ,但未使用它。应在实例化
    NSURLSession
    期间创建并使用配置。您不希望每次执行此请求时都这样做,因此请将此
    NSURLSessionConfiguration
    代码从该例程中取出,并将其放在实例化
    urlSession
    的任何位置。另外,一个非常小的观察,但您使用的术语是“下载任务”请参阅您的
    NSURLSessionDataTask
    。实际上有一个名为
    NSURLSessionDownloadTask
    的对象类型,用于下载到文件中。你可以考虑使用“数据任务”这一术语来避免未来的混乱。“如果你原谅无关的观察,但是你正在创建一个非结构的配置,但是你没有使用它。”谢谢你指出。我的印象是,它是全球性的,并普遍适用于所有url会话。那么,我如何使它在这种情况下正常工作呢?如果我只是将它移动到我的init(那是我初始化url会话的地方),会发生什么呢。您可以在任何地方定义
    urlSession
    ,例如,
    urlSession=[NSURLSession sessionWithConfiguration:sessionConfig]。但是请确保在
    init
    中执行此操作,以便只创建一次会话。每个
    NSURLSession
    都有开销。谢谢Rob,这很有意义。