ios - 将可编码结构编码为 Alamofire POST 参数 - Swift
问题描述
我正在尝试将我的前端 iOS 应用程序 (Swift) 连接到我的 Django 后端。
我尝试创建一个APIRouter
处理任何请求的类。这个类需要符合URLRequestConvertible
.
我有这个结构:
struct APIAccountID: Codable {
let username: String
let password: String
}
这是可编码的。
我正在尝试在 Alamofire POST 请求中传递此结构的数据。
所以我试图像这样对对象进行编码:
var parameters: [String: AnyObject]? {
switch self {
case .fetchAccessToken(let accountID):
if let data = try? JSONEncoder().encode(accountID) {
return data
} else {
print("Error: encoding post data")
return nil
}
default: break
}
}
使用AlamofireAny
或. _AnyObject
URLEncodedFormParameterEncoder
JSONParameterEncoder
如果我使用此参数开关:
var parameters: Data? {
switch self {
case .fetchAccessToken(let accountID):
if let data = try? JSONEncoder().encode(accountID) {
return data
} else {
print("[fetchAccessToken] Error: encoding post data")
}
default:
break
}
return nil
}
发送请求时出现此错误:
{
"non_field_errors" = (
"Invalid data. Expected a dictionary, but got str."
);
}
我的 URLRequestConvertible 函数:
// MARK: - URLRequestConvertible
extension APIRouter: URLRequestConvertible {
func asURLRequest() throws -> URLRequest {
let url = try baseURL.asURL().appendingPathComponent(path)
var request = URLRequest(url: url)
request.method = method
if method == .get {
request = try URLEncodedFormParameterEncoder()
.encode(parameters, into: request)
} else if method == .post {
request = try JSONParameterEncoder().encode(parameters, into: request)
request.setValue("application/json", forHTTPHeaderField: "Accept")
}
return request
}
}
解决方案
AlamoFireURLFormEncodedParameterEncoder
和JSONParameterEncoder
可以接受任何符合的Encodable
,所以你不需要先使用JSONEncoder
;他们会处理这些。
您的根本问题是,鉴于您将拥有不同的参数类型,具体类型应该是什么parameters
,具体取决于 API 调用。
你不能说
var parameters: APIAccountID
因为这不适用于参数是 aupdatePortfolio
或其他的情况。
你不能简单地说var parameters: Encodable?
,因为你需要一个具体的类型。
您需要使用类型擦除。这是一种在 Swift 中使用的技术,允许将原本不相关的类型用作参数。有多种方法,但一种常见的方法是“装箱”,其中实际类型存储为属性,当您引用类型擦除类型时,您将该引用或函数调用重定向到装箱或包装类型。
因此,在这种情况下,您需要的是AnyEncodable
-A 类型擦除的Encodable
. 幸运的是,FlightSchool 存储库中提供了这样的东西 - https://github.com/Flight-School/AnyCodable
将该包添加到项目后,您可以修改parameters
为
var parameters: AnyEncodable? {
switch self {
case .fetchAccessToken(let accountID):
return AnyEncodable(accountID)
case .updatePortfolio(let portfolio):
return AnyEncodable(portfolio)
}
}
现在,我们的parameters
var 有一个固定的类型 - AnyEncodable?
,它符合Encodable
所以每个人都很高兴。该实现要求您AnyEncodable
使用您的实际实例来实例化Encodable
推荐阅读
- architecture - 如何为使用 Stripe 支付的订阅服务设计信用系统
- visual-studio-code - “代码”功能不适用于 Git Bash(Windows)
- spring - 包含项目的生成源阶段已损坏
- javascript - Vue 在按钮单击时执行持久的任务
- python - 如何在类中保存变量而不会因类继承而丢失变量
- javascript - 如何设置开始视频的秒数?使用 Re4act-Player 库
- javascript - 如何将新元素添加到列表中?
- raspberry-pi - node-serialport 组合 JSON 块
- javascript - Vue 测试库 - fireEvent.click() 不工作
- python-3.x - 如何在 matplotlib imshow 等高线图上显示数据点?