我一直认为使用
Task
会自动在后台线程上运行耗时的任务,保持 UI 响应。
但是,在下面的代码中,我注意到我的
fetchNotes
函数(非常耗时)仍然在主 UI 线程上运行,因为 UIViewController
被标记为 @MainActor
。
这是需要担心的事情吗?如果耗时的任务在 UI 主线程上运行,会影响 UI 的响应能力吗?
有趣的是,在我的测试过程中,尽管
fetchNotes
需要几秒钟才能完成,但我的 UI 并没有冻结。为什么主 UI 线程处理耗时操作时 UI 不会冻结?
我是否应该考虑使用
Task.detached
?
这是我的代码片段。
class MainViewController: UIViewController {
private func fetchNotesAsync() {
print(">>>> fetchNotesAsync \(Thread.isMainThread)") // true
Task {
print(">>>> Task \(Thread.isMainThread)") // true
let noteWrappers = await fetchNotes()
...
}
}
private func fetchNotes() async -> [NoteWrapper] {
// Executing firebase query.getDocuments() to retrieve remote documents.
// query.getDocuments() is a firebase library async function
let querySnapshot = try await query.getDocuments()
}
Task { ... }
和fetchNotes
中的非异步代码确实在主要参与者上运行,但query.getDocuments
不是,假设它是Query.getDocuments
。
getDocuments
没有声明为与任何参与者隔离,也没有在参与者隔离类型中声明。因此,getDocuments
是非隔离。非隔离的异步方法始终在协作线程池中的某个线程上运行。
如果使用
Task.detached
,Task
中的同步代码将在协作线程池中的线程上运行,而不是
fetchNotes
中的同步代码,因为fetchNotes
是在与以下对象隔离的类中声明的:主要演员。您需要另外将fetchNotes
声明为nonisolated
,以便其主体中的同步代码从主要参与者运行。