SwiftUI MVVM将变量从ViewModel传递给API Service



我是Swift的新手。XCode,以下几个教程后,我做了一个MVVM架构与API服务,但是我不能传递我的变量从ViewModel到我的API服务。我想传递var user &从LoginViewModel传递到APIEndpoint

LoginViewModel

class LoginViewModel: ObservableObject, LoginService {
// I want to send this 2 variables to APIEndpoint
@Published var user = ""
@Published var pass = ""

var cancellables = Set<AnyCancellable>()

init(apiSession: APIService = APISession()) {
self.apiSession = apiSession
}

func login() {
let cancellable = self.login()
.sink(receiveCompletion: { result in
switch result {
case .failure(let error):
print("Handle error: (error)")
case .finished:
break
}

}) { (detail) in
print(detail)
}
cancellables.insert(cancellable)
}
}

APIEndpoint

enum APIEndpoint {
case userLogin
case menuList
}
extension APIEndpoint: RequestBuilder {
var urlRequest: URLRequest {
switch self {
case .userLogin:
guard let url = URL(string: "https://jcouserapidev.oxxo.co.id/home/app")
else {preconditionFailure("Invalid URL format")}
var request = URLRequest(url: url)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue(Constants.API_TOKEN, forHTTPHeaderField: "Authorization")
request.httpMethod = "POST"

// I want to pass the variables here, how??
let body: [String: Any] = ["user": $user, "pass": $pass]
let rb = try! JSONSerialization.data(withJSONObject: body)
request.httpBody = rb

return request
case .menuList:
guard let url = URL(string: "https://jcouserapidev.oxxo.co.id/home/app")
else {preconditionFailure("Invalid URL format")}
var request = URLRequest(url: url)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue(Constants.API_TOKEN, forHTTPHeaderField: "Authorization")
request.httpMethod = "POST"
return request
}

}
}

RequestBuilder

protocol RequestBuilder {
var urlRequest: URLRequest {get}
}

LoginService

protocol LoginService {
var apiSession: APIService {get}

func login() -> AnyPublisher<LoginAPIResponse, APIError>
}
extension LoginService {

func login() -> AnyPublisher<LoginAPIResponse, APIError> {
return apiSession.request(with: APIEndpoint.userLogin)
.eraseToAnyPublisher()
}
}

APIService

protocol APIService {
func request<T: Decodable>(with builder: RequestBuilder, test: String) -> AnyPublisher<T, APIError>
}

APISession

struct APISession: APIService {
func request<T>(with builder: RequestBuilder) -> AnyPublisher<T, APIError> where T: Decodable {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase

return URLSession.shared
.dataTaskPublisher(for: builder.urlRequest)
.receive(on: DispatchQueue.main)
.mapError { _ in .unknown }
.flatMap { data, response -> AnyPublisher<T, APIError> in
if let response = response as? HTTPURLResponse {

if (200...299).contains(response.statusCode) {
print(String(data: data, encoding: .utf8) ?? "")
return Just(data)
.decode(type: T.self, decoder: decoder)
.mapError {_ in .decodingError}
.eraseToAnyPublisher()
} else {
return Fail(error: APIError.httpError(response.statusCode))
.eraseToAnyPublisher()
}
}
return Fail(error: APIError.unknown)
.eraseToAnyPublisher()
}
.eraseToAnyPublisher()
}
}

提前感谢大家。

你应该这样改变你的enum:

enum APIEndpoint {
case userLogin(user: String, password: String)
case menuList
}

改变你的requestBuilder:

extension APIEndpoint: RequestBuilder {
var urlRequest: URLRequest {
switch self {
case .userLogin(let user, let password):
guard let url = URL(string: "https://jcouserapidev.oxxo.co.id/home/app")
else {preconditionFailure("Invalid URL format")}
var request = URLRequest(url: url)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue(Constants.API_TOKEN, forHTTPHeaderField: "Authorization")
request.httpMethod = "POST"

let body: [String: Any] = ["user": user, "pass": pass]
let rb = try! JSONSerialization.data(withJSONObject: body)
request.httpBody = rb

return request
case .menuList:
guard let url = URL(string: "https://jcouserapidev.oxxo.co.id/home/app")
else {preconditionFailure("Invalid URL format")}
var request = URLRequest(url: url)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue(Constants.API_TOKEN, forHTTPHeaderField: "Authorization")
request.httpMethod = "POST"
return request
}

}
}

之后,在所有的login函数中,你应该传递userpassword作为参数

最新更新