【发布时间】:2018-09-21 15:43:20
【问题描述】:
我正在做一个练习项目,iOS 应用程序打印来自 jsonplaceholder.typicode.com 的 /posts 列表,当用户选择一个时,会加载详细的视图控制器并显示有关该帖子的更多信息(作者和 cmets 的数量)。
我已经为三个不同的端点发出了三个单独的 GET 请求,因为它们中的每一个都需要不同的返回类型和不同的参数(或者根本不需要)。
我想尽可能多地采用这三者之间的共同代码并将其放入一个新函数中来整理类,但我觉得我可以做更多的事情。
有没有办法让这些结构的返回类型更通用,用一个 Switch 来确定将 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()
}
}
【问题讨论】:
-
您可以只创建一个函数来获取数据和另一个函数来解析 switch case。我认为这会对你有所帮助。
-
@EssamMohamed 谢谢!我会用路径值确定哪个 Switch 案例,还是有更好的方法来使用枚举?
-
您可以使用您的案例创建枚举并将枚举值传递给解析函数。
标签: ios swift api struct codable