编码一个可编码的结构体到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
}
}

这不起作用,因为AnyAnyObject在使用AlamofireURLEncodedFormParameterEncoderJSONParameterEncoder时不可编码。

如果我使用这个参数切换:

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."
);
}

My 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
}
}

AlamoFireURLFormEncodedParameterEncoderJSONParameterEncoder可以接受符合Encodable的任何内容,因此您不需要首先使用JSONEncoder;他们会处理的。

你的根本问题是parameters的类型应该是什么,因为你将有一个不同的参数类型,这取决于API调用。

你不能说

var parameters: APIAccountID

因为如果参数是updatePortfolio或者其他的,那就行不通了

你不能简单地说var parameters: Encodable?,因为你需要一个具体的类型。

需要使用类型擦除。这是Swift中使用的一种技术,允许将其他不相关的类型用作参数。有各种各样的方法,但常见的一种是"拳击"。在实际类型作为属性存储的地方,当您引用类型擦除类型时,您将该引用或函数调用重定向到盒装或包装类型。

因此,在这种情况下,您需要的是AnyEncodable-Encodable的A类型擦除实现。幸运的是,这样的事情是可以从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)
}
}

现在,我们的parametersvar有一个固定的类型-AnyEncodable?,它符合Encodable,所以每个人都很高兴。实现需要用实际的Encodable实例化AnyEncodable的实例

最新更新