我是一个刚接触swift 3编程的android开发人员,我正在使用Alamofire进行api调用,并避免繁琐的json paring我正在使用AlamofireObjectMapper库。
我有一个ApiController
,其函数可以在下面进行api调用,代码是:
public static func makePostRequest<T: Mappable>(url: String, params: Parameters, networkProtocol: NetworkProtocol, responseClass: T){
let headers = getHeaders()
networkProtocol.showProgress()
Alamofire.request(url, method: .post, parameters: params, encoding: JSONEncoding.default, headers: headers)
.validate()
.responseData{ response in
let json = response.result.value
var jsonString = String(data: json!, encoding: String.Encoding.utf8)
let responseObject = responseClass(JSONString: jsonString!)
switch(response.result){
case .success(_):
networkProtocol.hideProgress()
networkProtocol.onResponse(response: response)
break
case .failure(_):
networkProtocol.hideProgress()
networkProtocol.onErrorResponse(response: response)
break
}
}
我从服务器获取的Json响应模板是:
{
"some_int": 10,
"some_array":[...]
}
以下是我的模特课:
import ObjectMapper
class BaseResponse: Mappable {
var some_int: Int?
var some_array: [Array_of_objects]?
required init?(map: Map) {
some_int <- map["some_int"]
some_array <- map["some_array"]
}
func mapping(map: Map) {
}
}
下面是类进行api调用的函数:
public static func callSomeApi(params: Parameters, networkProtocol: NetworkProtocol){
ApiHelper.makePostRequest(url: AppConstants.URLs.API_NAME, params: params, networkProtocol: networkProtocol, responseClass: BaseResponse)
}
现在错误位于以下行
let responseObject = responseClass(JSONString: jsonString!)
我无法理解如何将jsonString
转换为我从View控制器接受的responseClass
通用对象
有人请帮我解决这个问题,现在已经坚持这个问题了很长一段时间。
答案 0 :(得分:2)
您可以使用AlamofireMapper:
使用json:
{
"page":1,
"per_page":3,
"total":12,
"total_pages":4,
"data":[
{
"id":1,
"first_name":"George",
"last_name":"Bluth",
"avatar":"https://s3.amazonaws.com/uifaces/faces/twitter/calebogden/128.jpg"
},
{
"id":2,
"first_name":"Janet",
"last_name":"Weaver",
"avatar":"https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128.jpg"
},
{
"id":3,
"first_name":"Emma",
"last_name":"Wong",
"avatar":"https://s3.amazonaws.com/uifaces/faces/twitter/olegpogodaev/128.jpg"
}
]
}
快速班:
class UserResponse: Decodable {
var page: Int!
var per_page: Int!
var total: Int!
var total_pages: Int!
var data: [User]?
}
class User: Decodable {
var id: Double!
var first_name: String!
var last_name: String!
var avatar: String!
}
使用alamofire请求
let url1 = "https://raw.githubusercontent.com/sua8051/AlamofireMapper/master/user1.json"
Alamofire.request(url1, method: .get
, parameters: nil, encoding: URLEncoding.default, headers: nil).responseObject { (response: DataResponse<UserResponse>) in
switch response.result {
case let .success(data):
dump(data)
case let .failure(error):
dump(error)
}
}
答案 1 :(得分:1)
如果您不想使用像ObjectMapper这样的其他依赖项,您可以采取以下方式,但您可能需要制作一些chagnes。
以下是一个典型的模型,我们用它来使用Alamofire使用泛型反序列化JSON数据。 Alamofire上有很多例子和优秀的documentation。
struct User: ResponseObjectSerializable, ResponseCollectionSerializable, CustomStringConvertible {
let username: String
let name: String
var description: String {
return "User: { username: \(username), name: \(name) }"
}
init?(response: HTTPURLResponse, representation: Any) {
guard
let username = response.url?.lastPathComponent,
let representation = representation as? [String: Any],
let name = representation["name"] as? String
else { return nil }
self.username = username
self.name = name
}
}
使用Swift 4中引入的Codable协议
typealias Codable = Decodable & Encodable
这方面的第一步是添加辅助函数 将在反序列化JSON数据和处理中完成一半的工作 错误。使用Swift扩展我们添加了解码传入的函数 JSON到我们之后将要编写的模型结构/类中。
let decoder = JSONDecoder()
let responseObject = try? decoder.decode(T.self, from: jsonData)
The decoder (1) is an object that decodes instances of a data type from JSON objects.
助手功能
extension DataRequest{
/// @Returns - DataRequest
/// completionHandler handles JSON Object T
@discardableResult func responseObject<T: Decodable> (
queue: DispatchQueue? = nil ,
completionHandler: @escaping (DataResponse<T>) -> Void ) -> Self{
let responseSerializer = DataResponseSerializer<T> { request, response, data, error in
guard error == nil else {return .failure(BackendError.network(error: error!))}
let result = DataRequest.serializeResponseData(response: response, data: data, error: error)
guard case let .success(jsonData) = result else{
return .failure(BackendError.jsonSerialization(error: result.error!))
}
// (1)- Json Decoder. Decodes the data object into expected type T
// throws error when failes
let decoder = JSONDecoder()
guard let responseObject = try? decoder.decode(T.self, from: jsonData)else{
return .failure(BackendError.objectSerialization(reason: "JSON object could not be serialized \(String(data: jsonData, encoding: .utf8)!)"))
}
return .success(responseObject)
}
return response(queue: queue, responseSerializer: responseSerializer, completionHandler: completionHandler)
}
/// @Returns - DataRequest
/// completionHandler handles JSON Array [T]
@discardableResult func responseCollection<T: Decodable>(
queue: DispatchQueue? = nil, completionHandler: @escaping (DataResponse<[T]>) -> Void
) -> Self{
let responseSerializer = DataResponseSerializer<[T]>{ request, response, data, error in
guard error == nil else {return .failure(BackendError.network(error: error!))}
let result = DataRequest.serializeResponseData(response: response, data: data, error: error)
guard case let .success(jsonData) = result else{
return .failure(BackendError.jsonSerialization(error: result.error!))
}
let decoder = JSONDecoder()
guard let responseArray = try? decoder.decode([T].self, from: jsonData)else{
return .failure(BackendError.objectSerialization(reason: "JSON array could not be serialized \(String(data: jsonData, encoding: .utf8)!)"))
}
return .success(responseArray)
}
return response(responseSerializer: responseSerializer, completionHandler: completionHandler)
}
}
第二次,我之前提到过“使用Swift 4 Codable”但是如果我们所有的话 想要从服务器解码JSON,我们只需要一个模型 符合协议可解码的struct / class。 (如果你有 您要上传的结构相同,您可以使用Codable来处理这两种情况 解码和编码)所以,现在我们的用户模型结构现在看起来像 此
struct User: Decodable, CustomStringConvertible {
let username: String
let name: String
/// This is the key part
/// If parameters and variable name differ
/// you can specify custom key for mapping "eg. 'user_name'"
enum CodingKeys: String, CodingKey {
case username = "user_name"
case name
}
var description: String {
return "User: { username: \(username), name: \(name) }"
}
}
最后,我们对API的函数调用看起来像。
Alamofire.request(Router.readUser("mattt"))).responseObject{ (response: DataResponse<User>) in
// Process userResponse, of type DataResponse<User>:
if let user = response.value {
print("User: { username: \(user.username), name: \(user.name) }")
}
}
对于更复杂(嵌套)的JSON,逻辑保持不变,只有模型struct / class中需要的修改才是所有结构/类必须符合Decodable协议,而Swift会处理其他所有内容。
答案 2 :(得分:0)
您可以使用SwiftyJSON:https://cocoapods.org/pods/SwiftyJSON
以下是一些示例代码可以帮助您:
Alamofire.request(endpointURL, method: .get, parameters: params, encoding: URLEncoding.default, headers: nil).validate().responseJSON()
{
(response) in
if response.result.isFailure
{
print("ERROR! Reverse geocoding failed!")
}
else if let value = response.result.value
{
var country: String? = nil
var county: String? = nil
var city: String? = nil
var town: String? = nil
var village: String? = nil
print("data: \(value)")
let json = JSON(value)
print("json: \(json)")
country = json["address"]["country"].string
county = json["address"]["county"].string
city = json["address"]["city"].string
town = json["address"]["town"].string
village = json["address"]["village"].string
}
else
{
print("Cannot get response result value!")
}
}
请让你知道代码已被简化(很多行已被删除)并从我的实际项目粘贴到这里,所以这段代码没有经过测试,可能包含拼写错误或类似的东西,但逻辑是可见
答案 3 :(得分:0)
对于对象映射,您需要使用 AlamofireObjectMapper 进行此操作。
//Declare this before ViewLoad
var BaseResponse: Array<BaseResponse>?
// After you receive response from API lets say "data"
if let jsonData = data as? String {
self.BaseResponse = Mapper< BaseResponse >().mapArray(JSONString: jsonData)
}