【问题标题】:SwiftUI MVVM pass variable from ViewModel to API ServiceSwiftUI MVVM 将变量从 ViewModel 传递到 API 服务
【发布时间】:2021-01-24 09:21:06
【问题描述】:

我对 Swift 和 XCode 非常陌生,在学习了几个教程之后,我已经创建了一个带有 API 服务的 MVVM 架构,但是我无法将我的变量从 ViewModel 传递到我的 API 服务。我想传递 var 用户并从 LoginViewModel 传递到 APIEndpoint

登录视图模型

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)
    }
}

API端点

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
        }
        
    }
}

请求生成器

protocol RequestBuilder {
    var urlRequest: URLRequest {get}
}

登录服务

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()
    }
}

API服务

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()
    }
}

提前谢谢大家。

【问题讨论】:

    标签: ios swift mvvm swiftui


    【解决方案1】:

    您应该以这种形式更改您的枚举:

    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 作为参数传递

    【讨论】:

    • 感谢您的回答,但是我仍然无法从viewmodel中获取要传递给APIEndpoint的值,我需要在LoginViewModel和LoginService中做什么?对不起,我对此很陌生,已经尝试调整代码,但它只是不断弹出错误
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 2023-03-12
    • 1970-01-01
    • 1970-01-01
    • 2013-09-07
    • 1970-01-01
    相关资源
    最近更新 更多