Reputation: 33
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.
Upvotes: 0
Views: 189
Reputation: 30746
Here are a few best practices:
View
struct and property wrappers instead of a legacy view model object, this increases performance and prevents consistency bugs. let
in a View
struct is the simplest feature: body
is called when the let
value changes from the last time the View
was init. It's inefficient to re-implement this basic pattern yourself with @Published
in ObservableObject
from the Combine framework..task
and .task(id: signIn)
instead of Combine's ObservableObject
when using async/await, this gives you cancellation and restart features.EnvironmentKey
for a service, like how AuthorizationController
is implemented.Upvotes: 1