将可编码结构编码为 Alamofire POST 参数 - Swift
Posted
技术标签:
【中文标题】将可编码结构编码为 Alamofire POST 参数 - Swift【英文标题】:Encode an encodable struct to Alamofire POST parameters - Swift 【发布时间】:2021-09-10 22:22:35 【问题描述】:我正在尝试将我的前端 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
这不起作用,因为在使用 Alamofire URLEncodedFormParameterEncoder
或 JSONParameterEncoder
时,Any
或 AnyObject
不可编码。
如果我使用这个参数开关:
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
【问题讨论】:
我没有测试过代码,但很明显错误表明参数应该是字典类型,并且你在参数中传递字符串。您必须创建一个字典,在该字典中映射您的模型并将其作为参数传递 请注意:您不需要显式的CodingKeys
结构。默认情况下,键与属性名称相同。
@George 是的,这只是因为代码是从我的脚本自动生成的。
@AmaisSheikh 问题是我的结构中可以有多种类型,而 Any 或 AnyObject 不可编码...
@PaulBénéteau 如果您手动发送此数据,是否有效? Data(#"["username": "Paul", "password": "Bénéteau"]"#.utf8)
。我不确定它想要什么数据,所以值得一试。如果这不起作用,请尝试从键中删除 "
。如果我们知道正确的输入,我们就可以解决如何从您的结构中获取该输入。
【参考方案1】:
AlamoFire URLFormEncodedParameterEncoder
和JSONParameterEncoder
可以接受任何符合Encodable
的内容,因此您无需先使用JSONEncoder
;他们会处理这些。
您的根本问题是 parameters
的类型应该是什么,因为您将有不同的参数类型,具体取决于 API 调用。
你不能说
var parameters: APIAccountID
因为这不适用于参数是 updatePortfolio
或其他的情况。
你不能简单地说var parameters: Encodable?
,因为你需要一个具体的类型。
您需要使用类型擦除。这是一种在 Swift 中使用的技术,允许将原本不相关的类型用作参数。有多种方法,但常见的一种是“装箱”,其中实际类型存储为属性,当您引用类型擦除类型时,您将该引用或函数调用重定向到装箱或包装类型。
因此,在这种情况下,您需要的是 AnyEncodable
- 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
,所以每个人都很高兴。该实现要求您使用实际的Encodable
实例化AnyEncodable
的实例
【讨论】:
以上是关于将可编码结构编码为 Alamofire POST 参数 - Swift的主要内容,如果未能解决你的问题,请参考以下文章