Swift • 如何从视图的初始化程序启动后台任务?
Posted
技术标签:
【中文标题】Swift • 如何从视图的初始化程序启动后台任务?【英文标题】:Swift • How can I initiate a Background Task from a View's Initializer? 【发布时间】:2021-08-06 15:47:29 【问题描述】:我正在处理SwiftUI App
并遇到了问题。
我有一个观点(
File Icon
)。一个Data
对象被传递给这个视图。要创建File Icon
,必须将数据转换为 PDFDocument,并且必须从第一个文档页面呈现图像。
想法:由于这是一项繁重的任务,并且有显示多个文件图标的视图(例如同时创建 20 个文件图标),因此计划是使用某种占位符创建File Icon
,在后台队列中渲染图像,完成后更改显示的图像。
代码:
struct FileIcon: View
let data: Data
@State private var image: UIImage?
init(for data: Data)
self.data = data
renderImage() // Initiate the Background Task
var body: some View
Group
if let safeImage = image
// Some Placeholder View
else
Image(uiImage: safeImage)
private func renderImage()
DispatchQueue.global(qos: .userInitiated).async
// Heavy Logic
DispatchQueue.main.async
image = renderedImage
问题:
如您所见,我在View's Initializer
中启动Background Task
。 Xcode 没有给出任何错误。但是,在运行此代码时,占位符视图会一直显示,并且没有切换到实际渲染的图像。
在.onAppear()
中调用renderImage()
时,占位符会在一段时间后被渲染图像替换。
问题:如何从View's Initializer
发起Background Task
?
【问题讨论】:
从 init() 调用时,如果调用甚至进入“main.async”内部,您是否使用断点测试过? 你最好不要那样做,因为 View init 可以被调用很多次。改为在您可以控制的工作流的某些视图模型或管理器中执行此操作。 @Asperi 谢谢你的回答。但是,我可以在View Model
的Initializer
中发起Background Task
吗?在我看来,我会遇到同样的问题吗?
【参考方案1】:
这是一个简单的演示(正如你想在init
中做的那样,但是,由于我不知道你的场景,可能最好将它移到单独的方法中并显式调用)
使用 Xcode 12.5 / ios 14.5 测试
struct DemoBackgroundTaskView: View
class ViewModel: ObservableObject
@Published var finished = false
init()
print("Init") // test called once
// set up once performed background task
DispatchQueue.global(qos: .background).async
sleep(10) // do your long task here
DispatchQueue.main.async [weak self] in
self?.finished = true
@StateObject private var vm = ViewModel()
var body: some View
Text(vm.finished ? "Done" : "Loading...")
【讨论】:
以上是关于Swift • 如何从视图的初始化程序启动后台任务?的主要内容,如果未能解决你的问题,请参考以下文章