iOS - 在 swift 中使用 ObjectMapper 映射根 JSON 数组

iOS - Map a root JSON array with ObjectMapper in swift

我使用库 ObjectMapper 将 json 映射到我的对象,但我在映射根 json 数组时遇到了一些问题。

这是收到的 json :

[
   {
       CustomerId = "A000015",
       ...
   },
   {
       CustomerId = "A000016",
       ...
   },
   {
       CustomerId = "A000017",
       ...
   }
]

这是我的对象

class Customer : Mappable
{
    var CustomerId : String? = nil

    class func newInstance(map: Map) -> Mappable? {
        return Customer()
    }

    func mapping(map: Map) {
        CustomerId   <- map["CustomerId"]
    }
}

我将控制器中的 json 映射为

let json = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &error) as! NSArray

if (error != nil) {
    return completionHandler(nil, error)
} else {
    var customers = Mapper<Customer>().map(json)
}

但是不行,我试了Mapper<[Customer]>().map(json)也不行。 最后,我尝试创建一个包含 Customer 数组的新 swift 对象 CustomerList,但它不起作用。

您知道如何映射 json 根数组吗?

谢谢。

我终于解决了我的问题:

控制器中的映射方法应该是

let json : AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &error)

if (error != nil) {
    return completionHandler(nil, error)
} else {
    var customer = Mapper<Customer>().mapArray(json)! //Swift 2
    var customer = Mapper<Customer>().mapArray(JSONArray: json)! //Swift 3
}

如果对某人有帮助。

使用 JSONObjectWithData(::) 和正确的条件向下转换类型

您的 JSON 是 [[String: AnyObject]] 类型。因此,对于 Swift 2,您可以将 JSONObjectWithData(::)[[String: AnyObject]] 类型的条件向下转换一起使用,以防止使用 NSArrayAnyObject!:

do {
    if let jsonArray = try NSJSONSerialization
        .JSONObjectWithData(data, options: []) as? [[String: AnyObject]] {
        /* perform your ObjectMapper's mapping operation here */
    } else {
        /* ... */
    }
}
catch let error as NSError {
    print(error)
}

使用 mapArray(:) 方法映射到 Customer

ObjectMapperMapper class 提供了一个名为 mapArray(:) 的方法,它具有以下声明:

public func mapArray(JSONArray: [[String : AnyObject]]) -> [N]?

ObjectMapper 文档对此进行了说明:

Maps an array of JSON dictionary to an array of Mappable objects

因此,您的最终代码应如下所示:

do {
    if let jsonArray = try NSJSONSerialization
        .JSONObjectWithData(data, options: []) as? [[String: AnyObject]] {
        let customerArray = Mapper<Customer>().mapArray(jsonArray)
        print(customerArray) // customerArray is of type [Customer]?
    } else {
        /* ... */
    }
}
catch let error as NSError {
    print(error)
}

使用 map(:) 方法映射到 Customer

ObjectMapperMapper class 提供了一个名为 map(:) 的方法,它具有以下声明:

func map(JSONDictionary: [String : AnyObject]) -> N?

ObjectMapper 文档对此进行了说明:

Maps a JSON dictionary to an object that conforms to Mappable

作为前面代码的替代方案,以下代码显示了如何使用 map(:) 将 JSON 映射到 Customer:

do {
    if let jsonArray = try NSJSONSerialization
        .JSONObjectWithData(data, options: []) as? [[String: AnyObject]] {
        for element in jsonArray {
            let customer = Mapper<Customer>().map(element)
            print(customer) // customer is of type Customer?
        }
    } else {
        /* ... */
    }
}
catch let error as NSError {
    print(error)
}

解决用泛型对象映射根数组问题的一个好方法是创建一个泛型对象,该对象在 class 实现中创建一个包含该对象的列表。让我们在下面看一个这种实现的例子:

    Alamofire.request(REQ_URL_STRING, 
       method: REQ_METHOD(eg.: .GET), 
       parameters: REQ_PARAMS, 
       encoding: REQ_ENCODING, 
       headers: REQ_HEADERS).responseObject { (response: DataResponse<GenericResponseList<SingleElement>>) in
            //your code after serialization here
    }

在上面的代码中,您将用自己的值填充大写变量。检查闭包中的响应 return 是否是来自 Alamofire 的通用对象 DataResponse,我确实创建了另一个名为 GenericResponseList 的对象。我在“< >”内放置了我将从服务器获取列表的对象类型。在我的例子中,它是一个 SingleElements 列表。

现在,看看下面 GenericResponseList 的实现:

final class GenericResponseList<T: Mappable>: Mappable {

    var result: [T]?

    required convenience init?(map: Map) {
        self.init()
    }

    func mapping(map: Map) {
        result <- map["result"]
    }
}

看一下,我在 class 中有一个变量,它是我发送给此 class.

的通用类型的列表
var result: [T]?

所以现在,当你得到 JSON 时,它会将其转换为 SingleElement 列表。

希望对您有所帮助:)

在我最近遇到的同样情况Swift 3,能够解决以root身份获取Array中存在的对象映射器。

首先使用序列化将 json 字符串转换为对象。

let parsedMapperString = Mapper<Customer>.parseJSONString(JSONString: result) //result is string from json serializer

然后您可以从 JSON 字典的 MapSet 中获取 Customer DTO 到 Mappable 对象数组。

let customerDto = Mapper<Customer>().mapSet(JSONArray: jsonParsed as! [[String : Any]])

希望对您有所帮助。感谢@Nicolas 推动我接近解决方案。

AlamofireObjectMapper 提供了最简单的解决方案。使用 responseArray() 便捷方法:

Alamofire.request(endpoint).responseArray { (response: DataResponse<[MyMappableClass]>) in

            if let result = response.result.value {
                // Customer array is here
            } else if let error = response.result.error {
                // Handle error
            } else {
                // Handle some other not networking error
            }
        }

将数组转换为 json 并返回:

let json = shops.toJSONString()
let shops = Array<Shop>(JSONString: json)