Alamofire响应对象映射

时间:2017-06-01 21:30:15

标签: ios swift swift3 alamofire objectmapper

我是一个刚接触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通用对象

有人请帮我解决这个问题,现在已经坚持这个问题了很长一段时间。

4 个答案:

答案 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)
                }
        }

链接:https://github.com/sua8051/AlamofireMapper

答案 1 :(得分:1)

使用Swift 4 Codable的通用响应对象序列化

如果您不想使用像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)
}