Hi everyone. I’m learning a lot of from Combine thanks to this amazing book.
Currently i’m writing an app and following the clean MVVM architecture.
Then I have the following Layers:
- Domain(UseCases and RepositoryProtocols)
- Data(RepositoryImplementations)
- Presentation(ViewController and ViewModels)
So this is what I have by now:
LoginUseCase.swift
import Foundation
import Combine
public enum LoginState {
case idle
case inProgress
case success
case emailValidationPending
case wrongPassword
case invalidEmail
case invalidPassword
case error
}
public protocol LoginUseCase {
func login(email: String, password: String) -> AnyPublisher<LoginState, Never>
}
public class LoginUseCaseImp: LoginUseCase {
let repository: RegistroRepository
public init(repository: RegistroRepository) {
self.repository = repository
}
public func login(email: String, password: String) -> AnyPublisher<LoginState, Never> {
return Future<LoginState, Never> { [weak self] promise in
self?.repository.login(email: email, password: password) { (result: Result<Bool, LoginRepositoryError>) in
switch result {
case .success(_):
return promise(.success(.success))
case .failure(let error):
switch error {
case .wrongPassword:
return promise(.success(.wrongPassword))
case .userNotExist:
return promise(.success(.error))
case .emailValidationPending:
return promise(.success(.emailValidationPending))
}
}
}
}.eraseToAnyPublisher()
}
}
LoginViewModel.swift
import Foundation
import DomainRadarAir
import Combine
public final class LoginViewModel: ObservableObject {
private let loginUseCase: LoginUseCase
public init(loginUseCase: LoginUseCase) {
self.loginUseCase = loginUseCase
}
public func login(email: String?, password: String?) -> AnyPublisher<LoginState, Never> {
guard let email=email, !email.isEmpty else {
return Just<LoginState>(.invalidEmail).eraseToAnyPublisher()
}
guard let password=password, !password.isEmpty else {
return Just<LoginState>(.invalidPassword).eraseToAnyPublisher()
}
return loginUseCase.login(email: email, password: password)
}
}
Then in the LoginViewController.swift
@IBAction func loginClick(_ sender: Any) {
viewModel.login(email: emailTF.text, password: passwordTF.text)
.print("State: ")
.sink { [weak self] state in
guard let self = self else { return }
switch state {
// all cases
}
.store(in: &cancellables)
}
What do you think of this approach, passing AnyPublisher object from UseCase to ViewController through ViewModel?
Thanks in advance for your opinions.