假设我创建了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)}
我的问题是:
默认情况下URLSessionTask
正在运行哪个线程?主线程或后台线程?
为什么当前线程在线程name
中显示为null?这是否意味着它默认在后台线程中运行? (我看到名字=&#34;主要&#34;主线程上的print
)
一般情况下,是否需要使用GCD运行URLSessionTask
以强制它在后台线程中运行?我问这个是因为我看到一些教程没有使用GCD来运行URLSessionTask
,他们只使用GCD在主线程中运行完成处理程序。
答案 0 :(得分:10)
简短回答:关键的观察结果是URLSessionTask
始终与您启动它的线程异步运行。除非您明确指定,否则完成处理程序和/或委托方法将在后台线程上运行。因此,您在启动请求时不必使用GCD,但在完成处理程序中,我们将使用GCD将更新UI或模型的任何内容分派到主队列。
你问:
- 默认情况下
醇>URLSessionTask
正在运行哪个线程?主线程或后台线程?
其中有两个问题:哪个线程URLSession
在内部用于其自身目的,哪个线程将运行完成处理程序和/或委托方法。
在前一个问题上,这是一个内部实现细节,没有在任何地方记录,但它似乎创建了自己的(后台)线程,带有一个单独的运行循环来处理请求。但是这些实现细节通常并不重要:我们确信请求是异步运行的(不会阻塞当前线程)。
后一个问题,调用完成处理程序和委托方法的线程通常要重要得多。除非我们另行指定,否则URLSession
会在URLSession
为我们创建的串行操作队列上运行完成处理程序和委托方法。这意味着它们在后台线程上运行。
此规则的唯一例外是,如果在实例化OperationQueue.main
时将queue
指定为URLSession
参数,在这种情况下,它显然会使用主线程来完成处理程序和委托方法。但即使在这种情况下,请求也是异步运行的,URLSession
也不会阻塞主线程。
- 为什么当前线程在线程名称中显示为null?这是否意味着它默认在后台线程中运行? (我看到name =&#34; main&#34;用于在主线程上打印)
醇>
它在串行操作队列上运行。操作队列线程使用的线程通常不具有名称。但您可以查看OperationQueue.current?.name
以确认正在使用哪个操作队列。
- 一般情况下,是否有必要使用GCD运行
醇>URLSessionTask
以强制它在后台线程中运行?我问这个是因为我看到一些教程没有使用GCD来运行URLSessionTask
,他们只使用GCD在主线程中运行完成处理程序。
这些教程建议的流程是正确的。启动请求时,您不必使用GCD。它始终与您启动它的队列异步运行。您需要做的唯一事情是将完成处理程序或委托方法中的相关代码分派到适当的队列。
具体来说,由于我们通常让URLSession
在自己的串行队列上运行完成处理程序,因此我们必须将UI更新分派回主队列。有时会被忽略,我们通常也会将模型更新发送回主队列(或使用其他一些同步机制)。