在 Swift 和 UIKit 中 X 秒后更新 UILabel 文本值

Update a UILabel text value after X seconds in Swift & UIKit

所以我需要在视图出现在屏幕上 X 秒后更新一个 UILabel 文本值,初始标签文本值来自一个 API 端点,该端点在每次视图时都会刷新出现。

我目前正在做以下事情:

 func updateLabelAfterAPICall(initialValue: String) {
    lastValue = initialValue //this is a local variable so I can use it to set the text once the view dissappears.
    label.text = lastValue
        Task {
            try? await Task.sleep(nanoseconds: 5_500_000_000)
            label.text = "New Value after 5.5 seconds passed"
        }
 }

视图消失后,我需要将标签设置回其初始值,因此我在 viewDidDissappear 中再次重置它(如果我不这样做,每次显示视图时我都会看到“新文本”,直到 API 调用结束,这是不需要的):

override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)
    label.text = lastValue
}

这在大多数情况下似乎工作正常,但我觉得我缺少一些边缘情况,我可能需要取消任务或类似的东西?也许如果我让视图在 5.5 秒过去之前多次出现和消失,是否会创建一堆不同的任务?

我问这个是因为我不能每次都准确地复制它,但是在测试时,我遇到了一些小问题,例如一旦我 return 到视图,文本就不会重置为 lastValue (不过大多数时候它似乎工作正常,这让测试和调试变得很痛苦)。

欢迎任何改进建议。谢谢!

将您正在执行的操作置于睡眠状态可能不安全。您可以在主线程上执行此操作。 试试这个:

func updateLabelAfterAPICall(initialValue: String) {
    lastValue = initialValue //this is a local variable so I can use it to set the text once the view dissappears.
    label.text = lastValue
    
    DispatchQueue.main.asyncAfter(deadline: .now() + 5.5) {
        label.text = "New Value after 5.5 seconds passed"
    }
 }

看来您可能担心如果视图在标签有机会更改之前就消失了会发生什么。在那种情况下,您可能希望取消整个 Task 操作。为此,请将 Task 保留在实例 属性 中,以便在视图过早消失时可以取消它,如下所示:

var task = Task<Void, Never> {}
func updateLabelAfterAPICall(initialValue: String) {
    task.cancel() // just in case
    task = Task { [weak self] in
        do {
            try await Task.sleep(nanoseconds: 5_500_000_000)
            guard let self = self else { return }
            self.label.text = "New Value after 5.5 seconds passed"
        } catch {}
    }
}
override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    task.cancel()
}

任务的大部分是对 Task.sleep 的调用,它是可取消的,因此整个操作将按顺序取消,因为 Task.sleep 调用将在取消时 throw并且整个任务操作将中止。