我正在尝试将我的AF请求转换为路由器结构,以使项目更清晰。我得到一个错误:
协议类型“Any”的值不能符合“Encodable”;只有struct/enum/class类型可以符合协议。
请帮我修改一下代码。谢谢您的支持!
我的URL将有一个用户名的占位符,密码将在body
中发送。答案是Bool (success), username and bearer token
。
下面是我的AF请求:
let username = usernameTextField.text
let password = passwordTextField.text
let loginParams = ["password":"\(password)"]
AF.request("https://example.com/users/\(username)/login",
method: .post,
parameters: loginParams,
encoder: JSONParameterEncoder.default,
headers: nil, interceptor: nil).response { response in
switch response.result {
case .success:
if let data = response.data {
do {
let userLogin = try JSONDecoder().decode(UsersLogin.self, from: data)
if userLogin.success == true {
defaults.set(username, forKey: "username")
defaults.set(password, forKey: "password")
defaults.set(userLogin.token, forKey: "token")
print("Successfully get token.")
} else {
//show alert
print("Failed to get token with incorrect login info.")
}
} catch {
print("Error: \(error)")
}
}
case .failure(let error):
//show alert
print("Failed to get token.")
print(error.errorDescription as Any)
}
}
到目前为止,我有什么可以转换为AF Router结构:
import Foundation
import Alamofire
enum Router: URLRequestConvertible {
case login(username: String, password: String)
var method: HTTPMethod {
switch self {
case .login:
return .post
}
}
var path: String {
switch self {
case .login(let username):
return "/users/\(username)/login"
}
}
var parameters: Parameters? {
switch self {
case .login(let password):
return ["password": password]
}
}
// MARK: - URLRequestConvertible
func asURLRequest() throws -> URLRequest {
let url = try Constants.ProductionServer.baseURL.asURL()
var request = URLRequest(url: url.appendingPathComponent(path))
// HTTP Method
request.httpMethod = method.rawValue
// Common Headers
request.setValue(ContentType.json.rawValue, forHTTPHeaderField: HTTPHeaderField.acceptType.rawValue)
request.setValue(ContentType.json.rawValue, forHTTPHeaderField: HTTPHeaderField.contentType.rawValue)
// Parameters
switch self {
case .login(let password):
request = try JSONParameterEncoder().encode(parameters, into: request) //where I got the error
}
return request
}
}
class APIClient {
static func login(password: String, username: String, completion: @escaping (Result<UsersLogin, AFError>) -> Void) {
AF.request(Router.login(username: username, password: password)).responseDecodable { (response: DataResponse<UsersLogin, AFError>) in
completion(response.result)
}
}
}
LoginViewController
类(我替换了AF.request代码)
APIClient.login(password: password, username: username) { result in
switch result {
case .success(let user):
print(user)
case .failure(let error):
print(error.localizedDescription)
}
可编码UsersLogin
模型
struct UsersLogin: Codable {
let success: Bool
let username: String
let token: String?
enum CodingKeys: String, CodingKey {
case success = "success"
case username = "username"
case token = "token"
}
}
3条答案
按热度按时间lztngnrs1#
我花了一段时间,但终于修好了。我也整理了一下代码。
使用
hmtdttj42#
我用这种方法解决了一个类似的问题。我创建了一个协议
Routable
我的路由器看起来像这个
解决生成错误
协议“可编码”作为类型不能符合协议本身
我使用了有用的AnyCodable库。
Codable
的类型擦除实现。AnyCodable不再需要Xcode 14.3
ebdffaop3#
你不能将
Parameters
字典与Encodable
类型一起使用,因为[String: Encodable]
的字典不是Encodable
,就像错误所说的那样。我建议将asURLRequest
过程的这一步移到一个单独的函数中,例如:不幸的是,对于有许多路由的路由器来说,这并不能很好地扩展,所以我通常将路由分解成小的枚举,并将参数移动到单独的类型中,这些类型与路由器结合起来产生
URLRequest
。