Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用协议的Swift通用解码器_Swift_Protocols - Fatal编程技术网

使用协议的Swift通用解码器

使用协议的Swift通用解码器,swift,protocols,Swift,Protocols,我尝试使用protrocol为所有模型使用通用Json解码器 //以下是协议的定义: func fetch<T: Decodable>(with request: URLRequest, decode: @escaping (Decodable) -> T?, completion: @escaping (Result<T, APIError>) -> Void) {.. other Code} func-fetch(带请求:URLRequest,解码:@e

我尝试使用protrocol为所有模型使用通用Json解码器

//以下是协议的定义:

func fetch<T: Decodable>(with request: URLRequest, decode: @escaping (Decodable) -> T?, completion: @escaping (Result<T, APIError>) -> Void) {.. other Code}
func-fetch(带请求:URLRequest,解码:@escaping(Decodable)->T?,完成:@escaping(Result)->Void){..other-code}
//以下是实施情况:

func getData(from endPoint: Endpoint, completion: @escaping (Result<ApiResponseArray<Codable>, APIError>) -> Void) {

        let request = endPoint.request

        fetch(with: request, decode: { json -> Decodable in
           guard let dataResult = json as? modelData else { return  nil }
           return dataResult
        }, completion: completion)
    }
func getData(从端点:端点,完成:@escaping(Result)->Void){
let request=endPoint.request
获取(使用:request,解码:{json->Decodable in)
guard let dataResult=json作为?modelData else{return nil}
返回数据结果
},完成:完成)
}
ApiResponseArray给了我一个错误:协议类型“Codable”(又名“Decodable&Encodable”)不能符合“Decodable”,因为只有具体类型才能符合协议。但是,我如何实现一个通用解码器并将不同的模型传递给它们呢。我想我必须修改我的协议定义,但是如何修改呢?我希望传递模型,然后接收模型的解码数据(在我的示例modelData中)。很明显,当我编写以下代码时,程序会运行: func getData(来自endPoint:endPoint,completion:@escaping(Result,apierro>)我的意思是当我使用具体的模型时,但是我想传递模型,这样我就可以对不同的模型使用该类

谢谢,
Arnold

我可以建议您如何使用
Alamofire
在API调用结构中使用
Decodable

我创建了
RequestManager
类,该类继承自
SessionManager
,并在其中添加了对所有人都通用的请求调用

class RequestManager: SessionManager {

    // Create shared instance
    static let shared = RequestManager()

    // Create http headers
    lazy var httpHeaders : HTTPHeaders = {
        var httpHeader = HTTPHeaders()
        httpHeader["Content-Type"] = "application/json"
        httpHeader["Accept"] = "application/json"
        return httpHeader
    }()


    //------------------------------------------------------------------------------
    // MARK:-
    // MARK:- Request Methods
    //------------------------------------------------------------------------------

    func responseRequest(_ url: String, method: Alamofire.HTTPMethod, parameter: Parameters? = nil, encoding: ParameterEncoding, header: HTTPHeaders? = nil, completionHandler: @escaping (DefaultDataResponse) -> Void) -> Void {

        self.request(url, method: method, parameters: parameter, encoding: encoding, headers: header).response { response in
            completionHandler(response)
        }
    }
} 
然后,在创建了一个以上的类之后,
NetworkManager
类,该类包含所需的get/post方法调用,并通过
JSONDecoder
对json进行解码,如下所示:

class NetworkManager {

    static let shared                   = NetworkManager()
    var progressVC                      : ProgressVC?

    //----------------------------------------------------------------
    // MARK:-
    // MARK:- Get Request Method
    //----------------------------------------------------------------

    func getResponse<T: Decodable>(_ url: String, parameter: Parameters? = nil, encoding: ParameterEncoding = URLEncoding.default, header: HTTPHeaders? = nil, showHUD: HUDFlag = .show, message: String? = "Please wait...", decodingType: T.Type, completion: @escaping (Decodable?, APIError?) -> Void) {

        DispatchQueue.main.async {
            self.showHideHud(showHUD: showHUD, message: "")
        }

        RequestManager.shared.responseRequest(url, method: .get, parameter: parameter, encoding: encoding, header: header) { response in

            DispatchQueue.main.async {
                self.showHideHud(showHUD: .hide, message: "")
            }

            guard let httpResponse = response.response else {
                completion(nil, .requestFailed("Request Failed"))
                return
            }

            if httpResponse.statusCode == 200 {
                if let data = response.data {
                    do {
                        let genericModel = try JSONDecoder().decode(decodingType, from: data)
                        completion(genericModel, nil)
                    } catch {

                        do {

                            let error = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any]

                            if let message = error!["message"] as? String {

                                completion(nil, .errorMessage(message)!)

                            } else if let message = error!["message"] as? Int {

                                completion(nil, .errorMessage(String(describing: "Bad Request = \(message)")))
                            }

                        } catch {
                            completion(nil, .jsonConversionFailure("JSON Conversion Failure"))
                        }
                    }
                } else {
                    completion(nil, .invalidData("Invalid Data"))
                }
            } else {
                completion(nil, .responseUnsuccessful("Response Unsuccessful"))
            }
        }
    }
}
我创建了以下枚举以发送数据或我的完成块中的错误

enum Result<T, U> where U: Error  {
    case success(T)
    case failure(U)
}
之后,我将扩展这个
DataManager
类来调用基于模块的web服务,因此我将创建Swift文件并扩展
DataManager
类并调用相关API

参见下文,在API调用中,我将把相对模型返回到
Result
like
Result


注意:-一些变量、模型和类是我的自定义。您可以将其替换为。

协议不能符合自身,
Codable
必须是具体类型,或者只能用作泛型约束

在你的上下文中,你必须做后一种事情,类似这样的事情

func fetch<T: Decodable>(with request: URLRequest, decode: @escaping (Data) throws -> T, completion: @escaping (Result<T, APIError>) -> Void) {  }

func getData<T: Decodable>(_ : T.Type = T.self, from endPoint: Endpoint, completion: @escaping (Result<T, APIError>) -> Void) {

    let request = endPoint.request

    fetch(with: request, decode: { data -> T  in
        return try JSONDecoder().decode(T.self, from: data)
    }, completion: completion)
}
func fetch(带请求:URLRequest,解码:@escaping(Data)throws->T,完成:@escaping(Result)->Void){
func-getData(uquot.Type=T.self,from-endPoint:endPoint,completion:@escaping(Result)->Void){
let request=endPoint.request
获取(带:请求,解码:{data->T in)
返回try JSONDecoder().decode(T.self,from:data)
},完成:完成)
}

网络请求通常返回
数据
,这更合理,因为
解码
闭包的参数类型

阅读本系列文章:感谢您的提示。但也许您可以给我一个建议,如何编写完成处理程序来处理泛型模型。我刚刚学会的一个技巧使这一点变得更好:make
getData()
的第一个参数是
\uuuu:T.Type=T.self
。这样,您就可以在函数签名中传递类型,而不必将其包含在闭包中(这通常有点难看)。但是,如果很容易推断,您就不必传递它。@RobNapier听起来确实不错。那么如何使用该函数来推断类型?如果您传递的是文本闭包,那么您将调用它
getData(Something.self,from:endpoint){…})
,并且不需要将类型放入闭包中。如果要传递闭包变量(因此类型已知),可以调用
getData(from:endpoint,completion:completion)
enum APIError: Error {
    case errorMessage(String)
    case requestFailed(String)
    case jsonConversionFailure(String)
    case invalidData(String)
    case responseUnsuccessful(String)
    case jsonParsingFailure(String)

    var localizedDescription: String {

        switch self {

        case.errorMessage(let msg):
            return msg

        case .requestFailed(let msg):
            return msg

        case .jsonConversionFailure(let msg):
            return msg

        case .invalidData(let msg):
            return msg

        case .responseUnsuccessful(let msg):
            return msg

        case .jsonParsingFailure(let msg):
            return msg
        }
    }
}
extension DataManager {

    // MARK:- Store List
    func getStoreList(completion: @escaping (Result<StoreListModel, APIError>) -> Void) {

        NetworkManager.shared.getResponse(getURL(.storeList), parameter: nil, encoding: JSONEncoding.default, header: getHeaders("bd_suvlascentralpos"), showHUD: .show, message: "Please wait...", decodingType: StoreListModel.self) { (decodableData, apiError) in

            if apiError != nil {

                completion(.failure(apiError!))

            } else {

                guard let userData = decodableData as? StoreListModel else {
                    completion(.failure(apiError!))
                    return
                }

                completion(.success(userData))
            }
        }
    }
}
DataManager.shared.getStoreList { (result) in

        switch result {

        case .success(let storeListModel):

            if let storeList = storeListModel, storeList.count > 0 {
                self.arrStoreList = storeList

                self.tblStoreList.isHidden = false
                self.labelEmptyData.isHidden = true

                self.tblStoreList.reloadData()
            } else {
                self.tblStoreList.isHidden = true
                self.labelEmptyData.isHidden = false
            }
            break

        case .failure(let error):
            print(error.localizedDescription)
            break
        }
    }
func fetch<T: Decodable>(with request: URLRequest, decode: @escaping (Data) throws -> T, completion: @escaping (Result<T, APIError>) -> Void) {  }

func getData<T: Decodable>(_ : T.Type = T.self, from endPoint: Endpoint, completion: @escaping (Result<T, APIError>) -> Void) {

    let request = endPoint.request

    fetch(with: request, decode: { data -> T  in
        return try JSONDecoder().decode(T.self, from: data)
    }, completion: completion)
}