Architecture MVVM dans SwiftUI

Salut a tous !

J’essaie d’implementer Directus dans mon projet en utilisant une architecture MVVM.

J’ai un problème avec mon EnvironmentObject qui n’est pas accessible dans mes ViewModel mais seulement dans les Vues.

Je crée mon UserManager que je veux disponible dans toutes mes vues, donc que je passe dans mon environmentObject :

@main
struct MyApp: App {
    
    @StateObject private var userManager = UserManager(webservice: RemoteDataManager)

    var body: some Scene {
        WindowGroup {
            VStack {
                if authentication.isValidated {
                    HomeView()
                        .environmentObject(userManager)
                } else {
                    LoginScreen()
                        .environmentObject(userManager)
                }
            }
        }
    }
}

Version simplifiee de UserManager :

@MainActor
class UserManager: ObservableObject {

    @Published var currentUser: User?
    @Published var token: Token?
}

Lors du lancement, l’utilisateur n’est pas connecte et LoginScreen est presente :

struct LoginScreen: View {
    
    @EnvironmentObject var userManager: UserManagerImpl
    @StateObject private var viewModel = LoginViewModel()

    var body: some View {
        VStack {
                Text("Email")
                TextField("", text: $viewModel.typedEmail)
                Text("Password")
                SecureField("", text: $viewModel.typedPassword)
                Button("Login") {
                    Task {
                        await viewModel.submitCredentials()
                    }
                }
        }
    }
}

LoginViewModel ressemble a ceci:

@MainActor
final class LoginViewModel: ObservableObject {

    @Published var typedEmail: String = ""
    @Published var typedPassword: String = ""
        
    var loginDisabled: Bool {
        typedEmail.isEmpty || typedPassword.isEmpty
    }
    
    @EnvironmentObject var userManager: UserManager
    
    private let service: LoginService
    
    init(service: LoginService = LoginService()) {
        self.service = service
    }

    func submitCredentials() async -> Bool {
        guard typedEmail.isEmpty == false && typedPassword.isEmpty == false else {
            return false
        }
        do {
            let credentials = Credentials(email: typedEmail, password: typedPassword)
            self.userManager.token = try await service.getTokenFromCredentials(credentials)
            return true
        } catch {
            return false
        }
    }
}

Auriez-vous une piste pour me débloquer ?

Merci d’avance !

Salut @cedric06nice !
disclaimer : je n’utilise pas le EnvironmentObject donc je me trompe peut-être mais je ne vois pas le moment où tu transfère le userManager depuis ta vue vers ton view model.
Je vois bien le moment où tu l’envoies de ton app vers ta vue, mais ensuite tu crées le view model sans aucun paramètre et tu n’appelles pas de fonction à lui à part le submitCredentials

Pourquoi ne pas utiliser tes paramètres de constructeur classiques plutôt que ce mécanisme de EnvironmentObject ?