Skip to content

Commit 345bcdf

Browse files
Update LoginView.swift
1 parent aa8434b commit 345bcdf

1 file changed

Lines changed: 30 additions & 23 deletions

File tree

SwiftUIExamples/SwiftUIExamples/Combine/LoginView.swift

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
//
77

88
import SwiftUI
9-
import Combine
9+
@preconcurrency import Combine
1010

1111
// MARK: - Model
1212
struct User: Sendable {
@@ -16,7 +16,7 @@ struct User: Sendable {
1616
enum LoginError: Error, LocalizedError, Sendable {
1717
case invalidCredentials
1818
case networkError
19-
19+
2020
var errorDescription: String? {
2121
switch self {
2222
case .invalidCredentials:
@@ -28,36 +28,39 @@ enum LoginError: Error, LocalizedError, Sendable {
2828
}
2929

3030
// MARK: - Login Service with Combine
31-
@MainActor
31+
3232
final class LoginService: Sendable {
3333
// Subject that never completes, just emits success or failure results
3434
let loginStatus = PassthroughSubject<Result<User, LoginError>, Never>()
35-
36-
nonisolated func login(username: String, password: String) {
37-
Task { @MainActor in
35+
36+
func login(username: String, password: String) async {
37+
do {
3838
try await Task.sleep(nanoseconds: 1_000_000_000) // 1 second delay
39-
40-
if username == "admin" && password == "1234" {
41-
loginStatus.send(.success(User(username: username)))
42-
} else {
43-
loginStatus.send(.failure(.invalidCredentials))
44-
}
39+
} catch {
40+
print("manage error here")
41+
}
42+
43+
if username == "admin" && password == "1234" {
44+
loginStatus.send(.success(User(username: username)))
45+
} else {
46+
loginStatus.send(.failure(.invalidCredentials))
4547
}
4648
}
4749
}
4850

4951
// MARK: - ViewModel
5052
@MainActor
53+
5154
final class LoginViewModel: ObservableObject {
5255
@Published var username: String = ""
5356
@Published var password: String = ""
5457
@Published var errorMessage: String?
5558
@Published var isLoggedIn: Bool = false
5659
@Published var isLoading: Bool = false
57-
60+
5861
private var cancellables = Set<AnyCancellable>()
5962
private let loginService = LoginService()
60-
63+
6164
init() {
6265
loginService.loginStatus
6366
.receive(on: DispatchQueue.main)
@@ -74,44 +77,48 @@ final class LoginViewModel: ObservableObject {
7477
}
7578
.store(in: &cancellables)
7679
}
77-
78-
func login() {
80+
81+
func login() async {
7982
errorMessage = nil
8083
isLoading = true
81-
loginService.login(username: username, password: password)
84+
Task.detached { [self] in
85+
await self.loginService.login(username: username, password: password)
86+
}
8287
}
8388
}
8489

8590
// MARK: - View
8691
struct LoginView: View {
8792
@StateObject private var viewModel = LoginViewModel()
88-
93+
8994
var body: some View {
9095
NavigationStack {
9196
VStack(spacing: 16) {
9297
TextField("Username", text: $viewModel.username)
9398
.textFieldStyle(.roundedBorder)
9499
.autocapitalization(.none)
95-
100+
96101
SecureField("Password", text: $viewModel.password)
97102
.textFieldStyle(.roundedBorder)
98-
103+
99104
if let errorMessage = viewModel.errorMessage {
100105
Text(errorMessage)
101106
.foregroundColor(.red)
102107
.font(.footnote)
103108
.padding(.top, 4)
104109
}
105-
110+
106111
if viewModel.isLoading {
107112
ProgressView("Logging in...")
108113
} else {
109114
Button("Login") {
110-
viewModel.login()
115+
Task {
116+
await viewModel.login()
117+
}
111118
}
112119
.padding(.top)
113120
}
114-
121+
115122
Spacer()
116123
}
117124
.padding()

0 commit comments

Comments
 (0)