Ios 可编码的API请求

Ios 可编码的API请求,ios,swift,codable,Ios,Swift,Codable,如何通过codables发出相同的API请求? 在我的应用程序中,此函数在进行API调用的每个视图中都会重复 func getOrders() { DispatchQueue.main.async { let spinningHUD = MBProgressHUD.showAdded(to: self.view, animated: true) spinningHUD.isUserInteractionEnabled = fal

如何通过codables发出相同的API请求? 在我的应用程序中,此函数在进行API调用的每个视图中都会重复

func getOrders() {

        DispatchQueue.main.async {

            let spinningHUD = MBProgressHUD.showAdded(to: self.view, animated: true)
            spinningHUD.isUserInteractionEnabled = false

            let returnAccessToken: String? = UserDefaults.standard.object(forKey: "accessToken") as? String

            let access  = returnAccessToken!
            let headers = [
                "postman-token": "dded3e97-77a5-5632-93b7-dec77d26ba99",
                "Authorization": "JWT \(access)"
            ]

            let request = NSMutableURLRequest(url: NSURL(string: "https://somelink.com")! as URL,
                                              cachePolicy: .useProtocolCachePolicy,
                                              timeoutInterval: 10.0)

            request.httpMethod          = "GET"
            request.allHTTPHeaderFields = headers

            let session  = URLSession.shared
            let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
                if (error != nil) {
                    print(error!)

                } else {
                    if let dataNew = data, let responseString = String(data: dataNew, encoding: .utf8) {
                        print("----- Orders -----")
                        print(responseString)
                        print("----------")

                        let dict = self.convertToDictionary(text: responseString)
                        print(dict?["results"] as Any)
                        guard let results = dict?["results"] as? NSArray else { return }
                        self.responseArray = (results) as! [HomeVCDataSource.JSONDictionary]

                        DispatchQueue.main.async {
                            spinningHUD.hide(animated: true)
                            self.tableView.reloadData()
                        }

                    }

                }

            })

            dataTask.resume()
        }
    }

基本上,您需要在模型类中遵循
Codable
协议,为此您需要实现两种方法,一种用于编码您的模型,另一种用于从
JSON
解码您的模型

func encode(to encoder: Encoder) throws

required convenience init(from decoder: Decoder) throws
之后,您将能够使用apple提供的
JSONDecoder
类对JSON进行解码,并返回一个数组(如果是这样的话)或模型类的一个对象

class ExampleModel: Codable {
    var commentId : String?
    var content : String?

    //if your JSON keys are different than your property name
    enum CodingKeys: String, CodingKey {
        case commentId = "CommentId" 
        case content = "Content"
    }

}
然后使用
JSONDecoder
可以得到如下模型数组

do {
    var arrayOfOrders : [ExampleModel] = try JSONDecoder().decode([ExampleModel].self, from: dataNew)                           
    }
    catch {
    }

首先,我建议您使用这个应用程序-quicktype-将json文件转换为类或结构(可编码的),无论您想要什么

之后,您可以创建一个泛型函数来获取任何类型的可编码类,并将其作为响应返回

func taskHandler<T:Codable>(type: T.Type, useCache: Bool, urlRequest: URLRequest, completion: @escaping (Result<T, Error>) -> Void) {
    let task = URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
        if let error = error {
            print("error : \(error)")
        }
        if let data = data {
            do {
                let dataDecoded = try JSONDecoder().decode(T.self, from: data)
                completion(.success(dataDecoded))
                // if says use cache, let's store response data to cache
                if useCache {
                    if let response = response as? HTTPURLResponse {
                        self.storeDataToCache(urlResponse: response, urlRequest: urlRequest, data: data)
                    }
                }
            } catch let error {
                completion(.failure(error))
            }
        } else {
            completion(.failure(SomeError))
        }
    }
    task.resume()
}
func任务处理程序(类型:T.type,useCache:Bool,urlRequest:urlRequest,完成:@escaping(Result)->Void){
让task=URLSession.shared.dataTask(带:urlRequest){(数据、响应、错误)在
如果let error=error{
打印(“错误:\(错误)”)
}
如果let data=data{
做{
让dataDecoded=try JSONDecoder().decode(T.self,from:data)
完成(.success(数据解码))
//如果说使用缓存,让我们将响应数据存储到缓存中
如果使用缓存{
如果let response=response as?HTTPURLResponse{
self.storeDataToCache(urresponse:response,urlRequest:urlRequest,data:data)
}
}
}捕捉错误{
完成(.failure(error))
}
}否则{
完成(.failure(SomeError))
}
}
task.resume()
}

我建议您执行以下操作

  • 创建基本服务,如下所示
  • 创建特定模型的服务,端点常量子类化为BaseService,如下所示

  • 添加要使用
    Codable
    解析的JSON响应。您需要在模型中实现
    func encode(to encoder:encoder)throws
    便利init(from decoder:decoder)throws
    ,然后您可以执行类似
    var arrayOfComments:[CommentModel]=尝试jsondeconder()。解码([CommentModel].self,from:response.result.value!)
    Info:您可以使用后台线程进行网络请求。更新的主线程UI@ReinierMelian请你详细说明一下好吗?将你的JSON响应粘贴到这个站点上,你将得到可编码的数据,基本上你不需要实现协议方法。在默认实现中,这些方法是合成的。并且符合
    Codable
    的对象不需要是类,也不需要从
    NSObject
    继承。为什么属性被声明为可选的?@vadian你是对的,但是如果你想拥有不同于JSON定义的属性名,你需要定义
    CodingKeys
    ,并实现方法协议或者Iam,关于NSObject你完全正确,我将删除它,感谢添加
    编码密钥
    不需要实现协议方法。
    
    import UIKit
    import Foundation
    
    enum MethodType: String {
        case get     = "GET"
        case post    = "POST"
        case put     = "PUT"
        case patch   = "PATCH"
        case delete  = "DELETE"
    }
    
    class BaseService {
    
        var session: URLSession!
    
        // MARK: Rebuilt Methods
        func FireGenericRequest<ResponseModel: Codable>(url: String, methodType: MethodType, headers: [String: String]?, completion: @escaping ((ResponseModel?) -> Void)) {
            UIApplication.shared.isNetworkActivityIndicatorVisible = true
    
            // Request Preparation
            guard let serviceUrl = URL(string: url) else {
                print("Error Building URL Object")
                return
            }
            var request = URLRequest(url: serviceUrl)
            request.httpMethod = methodType.rawValue
    
            // Header Preparation
            if let header = headers {
                for (key, value) in header {
                    request.setValue(value, forHTTPHeaderField: key)
                }
            }
    
            // Firing the request
            session = URLSession(configuration: URLSessionConfiguration.default)
            session.dataTask(with: request) { (data, response, error) in
                DispatchQueue.main.async {
                    UIApplication.shared.isNetworkActivityIndicatorVisible = false
                }
                if let data = data {
                    do {
                        guard let object = try? JSONDecoder().decode(ResponseModel.self , from: data) else {
                            print("Error Decoding Response Model Object")
                            return
                        }
                        DispatchQueue.main.async {
                            completion(object)
                        }
                    }
                }
            }.resume()
        }
    
        private func buildGenericParameterFrom<RequestModel: Codable>(model: RequestModel?) -> [String : AnyObject]? {
            var object: [String : AnyObject] = [String : AnyObject]()
            do {
                if let dataFromObject = try? JSONEncoder().encode(model) {
                    object = try JSONSerialization.jsonObject(with: dataFromObject, options: []) as! [String : AnyObject]
                }
            } catch (let error) {
                print("\nError Encoding Parameter Model Object \n \(error.localizedDescription)\n")
            }
            return object
        }
    
    }
    
    
    
    
    class ExampleModel: Codable {
        var commentId : String?
        var content : String?
    
        //if your JSON keys are different than your property name
        enum CodingKeys: String, CodingKey {
            case commentId = "CommentId" 
            case content = "Content"
        }
    
    }
    
    
    
    class ExampleModelService: BaseService<ExampleModel/* or [ExampleModel]*/> {
    
        func GetExampleModelList(completion: ((ExampleModel?)/* or [ExampleModel]*/ -> Void)?) {
            super.FireRequestWithURLSession(url: /* url here */, methodType: /* method type here */, headers: /* headers here */) { (responseModel) in
                completion?(responseModel)
            }
        }
    
    }
    
    
    
    class MyLocationsController: UIViewController {
    
        // MARK: Properties
        // better to have in base class for the controller
        var exampleModelService: ExampleModelService = ExampleModelService()
    
        // MARK: Life Cycle Methods
        override func viewDidLoad() {
            super.viewDidLoad()
            exampleModelService.GetExampleModelList(completion: { [weak self] (response) in
                // model available here
            })
        }
    }