我是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
函数中,你应该传递user
和password
作为参数