Ios 可编码的API请求
如何通过codables发出相同的API请求? 在我的应用程序中,此函数在进行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
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()
}
我建议您执行以下操作
添加要使用
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
})
}
}