swift 在一个符合observableObject的类中,标记带有/不带有@Published的变量有什么区别?

jyztefdp  于 2023-06-04  发布在  Swift
关注(0)|答案(1)|浏览(252)

所有人
我目前正在做一个SwiftUI项目,遇到了一个关于在视图模型中使用@Published的问题。我在视图模型中有一个带有变量'errorMessage'的登录视图。
我注意到,即使我从变量中删除了@Published,应用程序仍然可以正常运行。我已经使用@EnvironmentObject将视图模型注入SwiftUI环境中,但我没有显式地使用@Published标记变量或在视图模型中使用objectWillChange.send()。
我的问题是:在这种情况下,当需要观察属性并触发视图更新时,我是否仍然应该显式使用@Published?在这个上下文中,使用@Published和不使用它声明变量之间有什么区别?是否有任何我应该注意的最佳实践或潜在影响?
我将非常感谢任何与此主题相关的见解,建议或例子。提前感谢您的帮助!

import SwiftUI

struct LoginView: View {
    @EnvironmentObject var authService: AuthService
    @Environment(\.dismiss) private var dismiss

    var body: some View {
        ZStack {
            Text(authService.errorMessage)
        }
        .onSubmit {
            Task {
                if await authService.signIn(){
                     dismiss()
                }
            }
        }
    }
}

import Foundation
import FirebaseAuth

enum AuthError: Error {
    case emptyPassword
    case emptyEmail
}

extension AuthError: LocalizedError {
    var errorDescription: String? {
        switch self {
        case .emptyPassword:
            return NSLocalizedString("Please enter a password to continue.", comment: "")
        case .emptyEmail:
            return NSLocalizedString("Please enter an email address to continue.", comment: "")
}

@MainActor
final class AuthService: ObservableObject {
    @Published var email = ""
    @Published var password = ""
    
    private(set) var errorMessage = ""

    private func validation() throws {
        if email.isEmpty {
            throw AuthError.emptyEmail
        }
        if password.isEmpty {
            throw AuthError.emptyPassword
        }
    }
    
    func signIn() async -> Bool {
        do {
            try validation()
            let authResult = try await auth.signIn(withEmail: email, password: password)
            return true
        } catch {
            errorMessage = error.localizedDescription
            return false
        }
    }
}

我已经检查了Apple提供的文档中的相关概念(Published,EnvironmentObject,ObservableObject等)。

eqqqjvef

eqqqjvef1#

以下是一些最佳实践:
1.使用View结构体和属性 Package 器而不是遗留的视图模型对象,这可以提高性能并防止一致性错误。View结构中的let是最简单的功能:当let的值从上次初始化View时发生更改时,将调用body。使用合并框架中的ObservableObject中的@Published重新实现这个基本模式的效率很低。
1.在使用async/await时,使用.task.task(id: signIn)而不是合并的ObservableObject,这为您提供了取消和重新启动功能。
1.为服务使用自定义的EnvironmentKey,就像AuthorizationController的实现方式一样。

相关问题