В проекте есть
- протокол APIManager осуществляет запрос к серверу
- класс APIAppManager тут создается запрос и парсинг ответа от сервера в модель
- класс VC отдает параметры для запроса и принимает модель.
Сейчас модель принимает в Класс APIAppManager вопрос в том как передать эту ответственность в VC
APIManager
import Foundation
typealias JSONTask = URLSessionDataTask
typealias JSONCompletionHandler = (Data?, URLResponse?, Error?) -> Void
protocol JSONDecodable {
init?(JSON: [String: AnyObject])
}
protocol FinalURLPoint {
var baseURL: URL { get }
var path: String { get }
var request: URLRequest { get }
}
enum APIResult<T> {
case Success(T)
case Failure(Error)
}
protocol APIManager {
var sessionConfiguration: URLSessionConfiguration { get }
var session: URLSession { get }
func JSONTaskWith(request: URLRequest, completionHandler: @escaping JSONCompletionHandler) -> JSONTask
func fetch<T: JSONDecodable>(request: URLRequest, parse: @escaping (Data) -> T?, completionHandler: @escaping (APIResult<T>) -> Void)
}
extension APIManager {
func JSONTaskWith(request: URLRequest, completionHandler: @escaping JSONCompletionHandler) -> JSONTask {
let dataTask = session.dataTask(with: request) { (data, response, error) in
guard let HTTPResponse = response as? HTTPURLResponse else {
let userInfo = [
NSLocalizedDescriptionKey: NSLocalizedString("Missing HTTP Response", comment: "")
]
let error = NSError(domain: SWINetworkingErrorDomain, code: 100, userInfo: userInfo)
completionHandler(nil, nil, error)
return
}
if data == nil {
if let error = error {
completionHandler(nil, HTTPResponse, error)
}
} else {
switch HTTPResponse.statusCode {
case 200:
do {
completionHandler(data, HTTPResponse, nil)
} catch let error as NSError {
completionHandler(nil, HTTPResponse, error)
}
default:
print("We have got response status \(HTTPResponse.statusCode)")
}
}
}
return dataTask
}
func fetch<T>(request: URLRequest, parse: @escaping (Data) -> T?, completionHandler: @escaping (APIResult<T>) -> Void) {
let dataTask = JSONTaskWith(request: request) { (json, response, error) in
DispatchQueue.main.async(execute: {
guard let json = json else {
if let error = error {
completionHandler(.Failure(error))
}
return
}
if let value = parse(json) {
completionHandler(.Success(value))
} else {
let error = NSError(domain: SWINetworkingErrorDomain, code: 200, userInfo: nil)
completionHandler(.Failure(error))
}
})
}
dataTask.resume()
}
}
APIAppManager
import Foundation
enum TypeRequest: String {
case GET = "GET"
case POST = "POST"
case PUT = "PUT"
case PATCH = "PATCH"
case DELETE = "DELETE"
}
enum Request: FinalURLPoint {
case Deals(apiKey: String, id: String?)
case Products(apiKey: String, id: String?)
case Users(apiKey: String, id: String?)
var baseURL: URL {
return URL(string: "https://api.forecast.io")!
}
var baseURL_Plum: URL {
return URL(string: "https://plum-app-backend.herokuapp.com")!
}
var path: String {
switch self {
case .Deals(let apiKey, let id):
return "/api/v1/\(apiKey)/\(id ?? "")/"
case .Products(let apiKey, let id):
return "/api/v1/\(apiKey)/\(id ?? "")/"
case .Users(let apiKey, let id):
return "/api/v1/\(apiKey)/\(id ?? "")/"
}
}
var request: URLRequest {
let url = URL(string: path, relativeTo: baseURL_Plum)
return URLRequest(url: url!)
}
}
final class APIAppManager: APIManager {
let token = "176c154b852f250ade2097958cce531ca78f077f"
let sessionConfiguration: URLSessionConfiguration
lazy var session: URLSession = {
return URLSession(configuration: self.sessionConfiguration)
} ()
let apiKey: String
init(sessionConfiguration: URLSessionConfiguration, apiKey: String) {
self.sessionConfiguration = sessionConfiguration
self.apiKey = apiKey
}
convenience init(apiKey: String) {
self.init(sessionConfiguration: URLSessionConfiguration.default, apiKey: apiKey)
}
func fetchCurrentWeatherWith(typeRequest: TypeRequest,
apiKey: String,
id: String?,
body: [String: Any]?,
completionHandler: @escaping (APIResult<User>) -> Void) {
var request = Request.Users(apiKey: apiKey, id: id).request
request.httpMethod = typeRequest.rawValue
request.addValue("application/json", forHTTPHeaderField: "content-type")
request.addValue("Token \(token)", forHTTPHeaderField: "Authorization")
if let body = body {
let theJSONData = try? JSONSerialization.data(withJSONObject: body, options: [])
request.httpBody = theJSONData
}
fetch(request: request, parse: { (data) -> User? in
do {
let user = try JSONDecoder().decode(User.self, from: data)
return user
} catch let error {
print(error)
return nil
}
}, completionHandler: completionHandler)
}
}
VC
import UIKit
extension Encodable {
func jsonData() throws -> Data { let encoder = JSONEncoder() encoder.outputFormatting = .prettyPrinted encoder.dateEncodingStrategy = .iso8601 return try encoder.encode(self) }
}
class ViewController: UIViewController {
lazy var requestManager = APIAppManager(apiKey: "/us__ers/") override func viewDidLoad() { super.viewDidLoad() requestManager.fetchCurrentWeatherWith(typeRequest: .GET, apiKey: "users", id: "me", body: nil) { result in switch result { case .Success(let user): print("success") self.updateUIWith(user: user) case .Failure(let error as NSError): print("failure") let alertController = UIAlertController(title: "Unable to get data ", message: "\(error.localizedDescription)", preferredStyle: .alert) let okAction = UIAlertAction(title: "OK", style: .default, handler: nil) alertController.addAction(okAction) self.present(alertController, animated: true, completion: nil) default: break } } } func updateUIWith(user: User) { print("user in VC ", user) } @IBAction func patch(_ sender: Any) { let locationPatch = LocationPatch(id: "b209f6f0-9471-4b60-900b-9117bc94e67d") let size1 = LocationPatch(id: "845bc99c-c218-4bd2-b3d7-7d5eb7e5a746") let size2 = LocationPatch(id: "503e1059-7e0b-41bf-895d-3549012fbd1d") let userPatch = UserPatch(name: "Gabriella", location: locationPatch, categories: nil, sizes: [size1, size2]) let jsonData = try? userPatch.jsonData() let json = try? JSONSerialization.jsonObject(with: jsonData!, options: []) guard let params = json as? [String : Any] else { return } requestManager.fetchCurrentWeatherWith(typeRequest: .PATCH, apiKey: "users", id: "19", body: params) { result in switch result { case .Success(let user): print("success") self.updateUIWith(user: user) case .Failure(let error as NSError): print("failure") let alertController = UIAlertController(title: "Unable to get data ", message: "\(error.localizedDescription)", preferredStyle: .alert) let okAction = UIAlertAction(title: "OK", style: .default, handler: nil) alertController.addAction(okAction) self.present(alertController, animated: true, completion: nil) default: break } } }
}
Буду рад любым советам.
Благодарю!