URLSessionTask如何运行

说我已经创build了一个URLSessionTask的实例:

 let task = URLSession.shared.dataTask(with: url) { (data, response, error) in print (\(Thread.current)) } // I start the task by task.resume() 

我想了解URLSessionTask实例是默认在线程还是在后台线程中运行。 所以,我打印Thread.current

当我运行我的代码时,它打印出来:

 <NSThread: 0x170273980>{number = 4, name = (null)} 

我的问题是:

  1. 哪个线程的URLSessionTask默认运行? 主线程或后台线程?

  2. 为什么当前线程在线程name显示为空? 这是否意味着它默认在后台线程中运行? (我看到名称=“主”在主线上print

  3. 一般来说,是否有必要使用GCD运行URLSessionTask以强制它在后台线程中运行? 我问这是因为我看到一些教程不使用GCD来运行URLSessionTask ,他们只使用GCD在主线程中运行完成处理程序。

简短的回答:关键的观察是, URLSessionTask始终相对于您启动它的线程asynchronous运行。 除非另外明确指定,否则完成处理程序和/或委托方法将在后台线程上运行。 因此,在启动请求时,您不必使用GCD,但在完成处理程序中,我们将使用GCD来分派将UI或模型更新到主队列的任何内容。


你问:

  1. URLSessionTask默认运行哪个线程? 主线程或后台线程?

这里真的有两个问题: URLSession为了自己的目的在内部使用哪个线程,以及将运行完成处理程序和/或委托方法的线程。

在前一个问题中,这是一个内部实现细节,没有logging在任何地方,但它似乎创build自己的(后台)线程与一个单独的运行循环来处理请求。 但是这些实现细节通常并不重要:我们确信请求是asynchronous运行的(不会阻塞当前线程)。

后一个问题,在哪个线程上调用完成处理程序和委托方法通常要重要得多。 除非我们另外指定,否则URLSessionURLSession为我们创build的串行操作队列上运行完成处理程序和委托方法。 这意味着这些在后台线程上运行。

这个规则的唯一例外是,如果在实例化一个URLSession时候指定了OperationQueue.main作为queue参数,在这种情况下,显然它会使用主线程来完成处理程序和委托方法。 但即使在这种情况下,请求asynchronous运行, URLSession不会阻塞主线程。

  1. 为什么当前线程在线程名称中显示为空? 这是否意味着它默认在后台线程中运行? (我看到名称=“主”在主线上打印)

它在串行操作队列上运行。 操作队列线程使用的线程通常不具有名称。 但是您可以查看OperationQueue.current?.name来确认正在使用哪个操作队列。

  1. 一般来说,是否有必要使用GCD运行URLSessionTask以强制它在后台线程中运行? 我问这是因为我看到一些教程不使用GCD来运行URLSessionTask ,他们只使用GCD在主线程中运行完成处理程序。

这些教程build议的stream程是正确的。 发起请求时,您不必使用GCD。 它始终相对于您启动它的队列asynchronous运行。 唯一需要做的是将完成处理程序或委托方法内的相关代码分派到适当的队列中。

具体来说,因为我们通常让URLSession在自己的串行队列上运行完成处理程序,所以我们不得不将UI更新分派回主队列。 有时候被忽视了,我们也一般也把模型更新发送回主队列(或者使用其他一些同步机制)。