Я работаю над учебным проектом, в котором приложение для iOS печатает список / публикаций с jsonplaceholder.typicode.com, и когда пользователь выбирает один, загружается контроллер подробного представления и отображается дополнительная информация об этом сообщении (автори количество комментариев).
Я сделал три отдельных запроса GET для трех разных конечных точек, поскольку для каждого из них требуются разные типы возврата и разные параметры (или их вообще нет).
Я хотел взять как можно больше кода, общего между тремя, и поместить его в новую функцию, чтобы привести в порядок класс, но я чувствую, что могу сделать гораздо больше.
Есть ли способ сделать тип возвращаемых данных этих структур более универсальным, с помощью переключателя, чтобы определить, к какому из них будет привязан ответ json?Любое руководство будет с благодарностью.
import UIKit
struct Post: Codable {
let userId: Int
let id: Int
let title: String
let body: String
}
struct Author: Codable {
let name: String
}
struct Comment: Codable {
let postId: Int
let id: Int
let name: String
let email: String
let body: String
}
enum Result<Value> {
case success(Value)
case failure(Error)
}
class APIManager {
static let sharedInstance = APIManager()
func getUrl(for path: String) -> URL {
var urlComponents = URLComponents()
urlComponents.scheme = "https"
urlComponents.host = "jsonplaceholder.typicode.com"
urlComponents.path = path
guard let url = urlComponents.url else { fatalError("Could not create URL from components") }
return url
}
func getPosts(completion: ((Result<[Post]>) -> Void)?) {
let url = getUrl(for: "/posts")
var request = URLRequest(url: url)
request.httpMethod = "GET"
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let task = session.dataTask(with: request) { (responseData, response, responseError) in
DispatchQueue.main.async {
if let error = responseError {
completion?(.failure(error))
} else if let jsonData = responseData {
let decoder = JSONDecoder()
do {
let posts = try decoder.decode([Post].self, from: jsonData)
completion?(.success(posts))
} catch {
completion?(.failure(error))
}
} else {
let error = NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey : "Data was not retrieved from request"]) as Error
completion?(.failure(error))
}
}
}
task.resume()
}
func getAuthor(for userId: Int, completion: ((Result<String>) -> Void)?) {
let url = getUrl(for: "/users/\(userId)")
var request = URLRequest(url: url)
request.httpMethod = "GET"
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let task = session.dataTask(with: request) { (responseData, response, responseError) in
DispatchQueue.main.async {
if let error = responseError {
completion?(.failure(error))
} else if let jsonData = responseData {
let decoder = JSONDecoder()
do {
let author = try decoder.decode(Author.self, from: jsonData)
completion?(.success(author.name))
} catch {
completion?(.failure(error))
}
} else {
let error = NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey : "Data was not retrieved from request"]) as Error
completion?(.failure(error))
}
}
}
task.resume()
}
func getComments(for postId: Int, completion: ((Result<[Comment]>) -> Void)?) {
let url = getUrl(for: "/posts/\(postId)/comments")
var request = URLRequest(url: url)
request.httpMethod = "GET"
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let task = session.dataTask(with: request) { (responseData, response, responseError) in
DispatchQueue.main.async {
if let error = responseError {
completion?(.failure(error))
} else if let jsonData = responseData {
let decoder = JSONDecoder()
do {
let comments = try decoder.decode([Comment].self, from: jsonData)
completion?(.success(comments))
} catch {
completion?(.failure(error))
}
} else {
let error = NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey : "Data was not retrieved from request"]) as Error
completion?(.failure(error))
}
}
}
task.resume()
}
}