前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用@MainActor自动在主线程更新UI

使用@MainActor自动在主线程更新UI

作者头像
小刀c
发布2022-09-21 16:17:22
9390
发布2022-09-21 16:17:22
举报
文章被收录于专栏:cc logcc log

Swift 5.5 终于为开发者带来了async,await,actor这些便捷的异步语法,而其中一个小小的@MainActor语法,能带来让我们的开发更加便捷安全。

手动dispath到主线程

在swift 5.5 之前,我们需要手动使用DispatchQueue.main来让代码运行在主线程,特别是UI更新操作。这样没问题,但是略显麻烦,而且容易遗漏。

代码语言:javascript
复制
class ProfileViewController: UIViewController {
    private let userID: User.ID
    private let loader: UserLoader
    private lazy var nameLabel = UILabel()
    private lazy var biographyLabel = UILabel()
    ...

    private func loadUser() {
        loader.loadUser { [weak self] result in
            DispatchQueue.main.async {
                switch result {
                case .success(let user):
                    self?.nameLabel.text = user.name
                    self?.biographyLabel.text = user.biography
                case .failure(let error):
                    self?.showError(error)
                }
            }
        }
    }
}

@MainActor

Swift 5.5 内置了的actor,MainActor被装饰的操作自动运行在主线程。

首先我们需要将我们的异步callback代码,转换成async/await模式。

代码语言:javascript
复制
extension UserLoader {
    func loadUser() async throws -> User {
        try await withCheckedThrowingContinuation { continuation in
            loadUser { result in
                switch result {
                case .success(let user):
                    continuation.resume(returning: user)
                case .failure(let error):
                    continuation.resume(throwing: error)
                }
            }
        }
    }
}

在UIKit中使用@MainActor

代码语言:javascript
复制
class ProfileViewController: UIViewController {
    ...
    
    private func loadUser() {
        async {
            do {
                let user = try await loader.loadUser()
                nameLabel.text = user.name
                biographyLabel.text = user.biography
            } catch {
                showError(error)
            }
        }
    }
}

等等,没有看到@MainAcotr?

那是因为apple已经将UILabelUIViewController 装饰过了。

代码语言:javascript
复制
@MainActor class UILabel: UIView
@MainActor class UIViewController: UIResponder

也就是,在swift 的concurrency 系统中,被@MainActor装饰过的类,及其子类的属性和方法,都会自动在主线程中,get,set,或者call

自定义UI class

假设,我们SwiftUI中的一个实现ObservableObject的类,其中被@Published装饰的属性需要自动运行在主线程。 我们只需要装饰@MainActor即可。

代码语言:javascript
复制
@MainActor class ListViewModel: ObservableObject {
    @Published private(set) var result: Result<[Item], Error>?
    private let loader: ItemLoader
    ...

    func load() {
        async {
            do {
                let items = try await loader.loadItems()
                result = .success(items)
            } catch {
                result = .failure(error)
            }
        }
    }
}

就是这么简单!!!

@MainActor 只能运行在async/await环境中。

代码语言:javascript
复制
@MainActor class ListViewModel: ObservableObject {
    ...

    func load() {
        loader.loadItems { [weak self] result in
    self?.result = result
}
    }
}

👉@MainActor 不会对Callback中的代码生效

@MainActor 必须使用在Swift async/await Concurrency环境中,否则无法生效。因为actor必须通过同步方式来获取。

参考自:

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-07-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 手动dispath到主线程
  • @MainActor
    • 在UIKit中使用@MainActor
      • 自定义UI class
        • @MainActor 只能运行在async/await环境中。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档