英文:
What is the difference between marking a variable with/without @Published in a class conforming observableObject?
问题
大家好,
我目前正在开发一个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("请提供密码以继续。", comment: "")
case .emptyEmail:
return NSLocalizedString("请提供电子邮件地址以继续。", 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等重要概念。
英文:
everyone,
I'm currently working on a SwiftUI project and have encountered a question regarding the usage of @Published in a view model. I have a login view with a variable 'errorMessage' in the view model.
I noticed that even when I removed @Published from the variable, the app still functions correctly. I have injected the view model into the SwiftUI environment using @EnvironmentObject, but I haven't explicitly marked the variable with @Published or used objectWillChange.send() in the view model.
My question is: Under this scenario, should I still use @Published explicitly when a property needs to be observed and trigger view updates? What could be the difference between declaring a variable with @Published and without it in this context? Are there any best practices or potential implications that I should be aware of?
I would greatly appreciate any insights, suggestions, or examples related to this topic. Thank you in advance for your help!
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
}
}
}
I have examined the pertinent concepts (Published, EnvironmentObject, ObservableObject etc.) within the documentation provided by Apple.
答案1
得分: 1
以下是要翻译的内容:
- 使用
View
结构和属性包装器,而不是传统的视图模型对象,这可以提高性能并防止一致性错误。在View
结构中使用let
是最简单的特性:当let
的值与上次初始化View
时的值不同时,会调用body
。使用Combine框架中的@Published
自行重新实现这个基本模式是低效的。 - 在使用async/await时,使用
.task
和.task(id: signIn)
,而不是Combine的ObservableObject
,这可以提供取消和重启功能。 - 使用自定义的
EnvironmentKey
来提供服务,就像AuthorizationController
的实现方式一样。
英文:
Here are a few best practices:
- Use the
View
struct and property wrappers instead of a legacy view model object, this increases performance and prevents consistency bugs.let
in aView
struct is the simplest feature:body
is called when thelet
value changes from the last time theView
was init. It's inefficient to re-implement this basic pattern yourself with@Published
inObservableObject
from the Combine framework. - Use
.task
and.task(id: signIn)
instead of Combine'sObservableObject
when using async/await, this gives you cancellation and restart features. - Use a custom
EnvironmentKey
for a service, like howAuthorizationController
is implemented.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论