我已经构建了一个后端并正在开发一个前端客户端,目前,我的客户端返回的登录响应是:
{
"user": {
"email": "fdsa@fdsafsdfa.com",
"token": "eyJhbGciOiJIUzI"
}
}
这给我带来了一个问题,我无法简单地解码为用户对象,我必须为所有内容执行以下 2 层:
struct User: Codable {
let email: String
let token: String
}
struct UserResponseData: Codable {
let user: User
}
是否有更有效的方法来直接访问值并限制对象?也许我将 user
json parent 编辑为更通用的东西,比如 data
然后让用户坐在里面?我不确定...
我的客户端如下所示,如果这有助于改进架构:
class APIClient {
static func signup(request: SignupRequestData, completion: @escaping (Result<UserResponseData>) -> Void) {
performRequest(route: APIRouter.signup(request), completion: completion)
}
@discardableResult
private static func performRequest<T:Decodable>(route: APIRouter,
decoder: JSONDecoder = JSONDecoder(),
completion:@escaping (Result<T>)->Void) -> DataRequest {
return AF.request(route).responseDecodable (decoder: decoder){ (response: DataResponse<T>) in
completion(response.result)
}
}
}
感谢在更适合的结构中提供的一些帮助,这样我就不必继续解开父级来获得客户所需的值
最佳答案
一个相当简单的方法是将其包装到一个通用的 Response
类型中,该类型假定第一个键始终是正确的。
struct AnyStringKey: CodingKey {
var stringValue: String
init?(stringValue: String) { self.stringValue = stringValue }
var intValue: Int?
init?(intValue: Int) { return nil }
}
struct Response<Payload: Decodable>: Decodable {
let payload: Payload
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: AnyStringKey.self)
guard let key = container.allKeys.first else {
throw DecodingError.dataCorrupted(.init(codingPath: decoder.codingPath,
debugDescription: "Missing payload key"))
}
self.payload = try container.decode(Payload.self, forKey: key)
}
}
let user = try JSONDecoder().decode(Response<User>.self, from: json).payload
可以使其更高级,并检查 key 是否符合您的预期,但这可能足以满足您的情况。
这种方法将一些工作转移到调用方(调用 .payload
)。您可以通过使用处理提取子 key 的协议(protocol)将一些工作转移到解码类型中来摆脱它。
protocol LayerDecodable: Decodable {
associatedtype CodingKeys: CodingKey
init(from container: KeyedDecodingContainer<CodingKeys>) throws
}
extension LayerDecodable {
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: AnyStringKey.self)
guard let key = container.allKeys.first else {
throw DecodingError.dataCorrupted(.init(codingPath: decoder.codingPath,
debugDescription: "Missing payload key"))
}
try self.init(from: container.nestedContainer(keyedBy: CodingKeys.self, forKey: key))
}
}
但是有了这个,你需要手动实现解码。
struct User: LayerDecodable {
let email: String
let token: String
enum CodingKeys: CodingKey {
case email, token
}
init(from container: KeyedDecodingContainer<CodingKeys>) throws {
self.email = try container.decode(String.self, forKey: .email)
self.token = try container.decode(String.self, forKey: .token)
}
}
好处是调用者现在是干净的:
let user = try JSONDecoder().decode(User.self, from: json)
关于ios - 处理 Response JSON 数据结构的最佳方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55344959/