Кодируемый для запроса API - PullRequest
1 голос
/ 01 июля 2019

как бы я сделал такой же запрос API через codables?В моем приложении эта функция повторяется в каждом представлении, которое выполняет вызовы 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()
        }
    }

Любая помощь очень ценится.

Ответы [ 3 ]

1 голос
/ 01 июля 2019

По сути, вам необходимо соответствовать протоколу Codable в ваших классах моделей, для этого вам нужно реализовать 2 метода, один для кодирования вашей модели и другой для декодирования вашей модели из JSON

func encode(to encoder: Encoder) throws

required convenience init(from decoder: Decoder) throws

После этого вы сможете использовать JSONDecoder класс, предоставленный Apple, для декодирования вашего 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 {
    }
0 голосов
/ 01 июля 2019

Я бы предложил сделать следующее:

  1. Создать базовую службу, как указано ниже

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
    }

}


вышеупомянутым классом, вы можете использовать его в других сценариях, добавив объект запроса вэто и прохождение любого класса, который вы хотите, если вы соответствуете протоколу Coddle

Создание модели, соответствующей протоколу Coddle

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

}

Создание службы для конкретной модели с подклассами констант конечной точки для BaseService, как показано ниже

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

0 голосов
/ 01 июля 2019

Прежде всего, я могу порекомендовать вам использовать это приложение -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()
}
...