ios - jsonserialization - parse json swift 4
iOS: mapee una matriz JSON raíz con ObjectMapper en forma rápida (6)
Uso la biblioteca ObjectMapper para mapear json con mis objetos, pero tengo algunos problemas para mapear una raíz json Array.
Este es el json recibido:
[
{
CustomerId = "A000015",
...
},
{
CustomerId = "A000016",
...
},
{
CustomerId = "A000017",
...
}
]
Este es mi objeto
class Customer : Mappable
{
var CustomerId : String? = nil
class func newInstance(map: Map) -> Mappable? {
return Customer()
}
func mapping(map: Map) {
CustomerId <- map["CustomerId"]
}
}
Asigné el json en mi controlador con
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)
}
Pero no funciona, probé Mapper<[Customer]>().map(json)
pero tampoco funciona. Finalmente, traté de crear un nuevo CustomerList objeto rápido que contiene una matriz de cliente, pero no funciona.
¿Tiene una idea de cómo mapear json de una matriz raíz?
Gracias.
Usando JSONObjectWithData(::)
con el tipo de JSONObjectWithData(::)
condicional correcto
Su JSON es del tipo [[String: AnyObject]]
. Por lo tanto, con Swift 2, puede usar JSONObjectWithData(::)
con un JSONObjectWithData(::)
condicional de tipo [[String: AnyObject]]
para evitar el uso de NSArray
o AnyObject!
:
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)
}
Mapeo al Customer
usando el método mapArray(:)
La clase Mapper
ObjectMapper
proporciona un método llamado mapArray(:)
que tiene la siguiente declaración:
public func mapArray(JSONArray: [[String : AnyObject]]) -> [N]?
La documentación de ObjectMapper
dice al respecto:
Mapas una matriz de diccionario JSON para una matriz de objetos Mappable
Por lo tanto, su código final debería verse más o menos así:
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)
}
Mapeo al Customer
usando el método map(:)
La clase Mapper
ObjectMapper
proporciona un método llamado map(:)
que tiene la siguiente declaración:
func map(JSONDictionary: [String : AnyObject]) -> N?
La documentación de ObjectMapper
dice al respecto:
Asigna un diccionario JSON a un objeto que se ajusta a Mappable
Como alternativa al código anterior, el siguiente código muestra cómo asignar su JSON al Customer
usando el map(:)
:
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)
}
Convierte array a json y viceversa:
let json = shops.toJSONString()
let shops = Array<Shop>(JSONString: json)
En la misma situación en mi reciente Swift 3, soy capaz de resolver para obtener el mapeador de objetos presente en Matriz como raíz.
Primero convierta una cadena json en un objeto usando la serialización.
let parsedMapperString = Mapper<Customer>.parseJSONString(JSONString: result) //result is string from json serializer
Luego puede obtener Customer DTO del MapSet del diccionario JSON en una matriz de objetos Mappable.
let customerDto = Mapper<Customer>().mapSet(JSONArray: jsonParsed as! [[String : Any]])
Espero eso ayude. Gracias a @Nicolas que me presionó para obtener una solución.
Finalmente resuelvo mi problema:
El método de mapeo en el controlador debe ser
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
}
Si puede ayudar a alguien
La solución más fácil es provista por AlamofireObjectMapper . Use el método de conveniencia 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
}
}
Una buena forma de resolver el problema de mapear una matriz raíz con un objeto genérico es crear un objeto genérico que cree una lista con el objeto dentro de la implementación de la clase. Veamos un ejemplo de este tipo de implementación a continuación:
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
}
En el código anterior, rellenará las variables en mayúscula con sus propios valores. Compruebe que el retorno de la respuesta en el cierre es un objeto genérico DataResponse de Alamofire, y creé otro llamado GenericResponseList. Puse en el interior el "<>" el tipo de objeto que obtendré una lista del servidor. En mi caso, era una lista de SingleElements.
Ahora, eche un vistazo a la implementación de GenericResponseList a continuación:
final class GenericResponseList<T: Mappable>: Mappable {
var result: [T]?
required convenience init?(map: Map) {
self.init()
}
func mapping(map: Map) {
result <- map["result"]
}
}
Eche un vistazo, tengo una variable dentro de la clase que es una lista del tipo genérico que envié a esta clase.
var result: [T]?
Entonces, cuando obtenga JSON, lo convertirá en una lista de SingleElement.
Espero que haya ayudado :)