Envío de una variedad de dictionarys con alamofire

Tengo que enviar un set de dictionarys a través de la request POST. Por ejemplo:

materials: [[String, String]] = [ [ "material_id": 1, "qty": 10 ], [ "material_id": 2, "qty": 5 ] ] 

Alamofire.request envía los datos siguientes de la publicación:

 materials => array( [0] => array("material_id" => 1), [1] => array("qty" => 10), [2] => array("material_id" => 2), [3] => array("qty" => 5), ) 

Quiero recibir esa representación:

 materials => array( [0] => array( "material_id" => 1, "qty" => 10 ), [1] => array( "material_id" => 2, "qty" => 5 ), ) 

Dice que desea recibir los datos en el server en este formatting:

 materials => array( [0] => array( "material_id" => 1, "qty" => 10 ), [1] => array( "material_id" => 2, "qty" => 5 ), ) 

Entonces, un par de pensamientos:

  1. Eso parece ser un dictionary con una sola key de "materiales", que consiste en una matriz de dos dictionarys. La versión Swift de eso podría verse así:

     let materials = [ "materials": [ [ "material_id": 1, "qty": 10 ], [ "material_id": 2, "qty": 5 ] ] ] 

    Francamente, no estoy muy seguro de qué hacer con tu ejemplo en tu pregunta: dices que era [[String: String]] , pero que no se comstackría porque es [[String: Int]] ; Dice que utilizó con éxito Alamofire para enviarlo, pero AFAIK, Alamofire solo acepta [String: AnyObject] por sus parameters; etc. Independientemente, dado lo que dices que quieres recibir en el server, habría pensado que lo anterior sería la estructura adecuada para lograrlo.

  2. Al enviar una estructura como esa, JSON es la técnica más común. Para hacerlo, especificaría .JSON para el parámetro de encoding en el método de request Alamofire.

  3. En respuesta a la sugerencia de otro para usar JSON, dijiste que no querías hacer eso. Desafortunadamente, Alamofire no tiene un método que codifique eso en una application/x-www-form-urlencoded request con una estructura complicada como esta para ti, por lo que tendrías que escribir la tuya propia:

    Eso podría parecer:

     func encodeParameters(object: AnyObject, prefix: String! = nil) -> String { if let dictionary = object as? [String: AnyObject] { let results = map(dictionary) { (key, value) -> String in return self.encodeParameters(value, prefix: prefix != nil ? "\(prefix)[\(key)]" : key) } return "&".join(results) } else if let array = object as? [AnyObject] { let results = map(enumerate(array)) { (index, value) -> String in return self.encodeParameters(value, prefix: prefix != nil ? "\(prefix)[\(index)]" : "\(index)") } return "&".join(results) } else { let escapedValue = escape("\(object)") return prefix != nil ? "\(prefix)=\(escapedValue)" : "\(escapedValue)" } } // This is Alamofire's private `escape` function; IMHO, this should // be public method, so either make public, or just re-implement it. func escape(string: String) -> String { let legalURLCharactersToBeEscaped: CFStringRef = ":/?&=;+!@#$()',*" return CFURLCreateStringByAddingPercentEscapes(nil, string, nil, legalURLCharactersToBeEscaped, CFStringBuiltInEncodings.UTF8.rawValue) } 

    A continuación, puede crear una request y enviarla usted mismo:

     let request = NSMutableURLRequest(URL: url) request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") request.HTTPMethod = "POST" request.HTTPBody = encodeParameters(materials).dataUsingEncoding(NSUTF8StringEncoding) Alamofire.request(request) .response { request, response, data, error in println(data) } 

    Obviamente, use cualquier método de response apropiado para la naturaleza de la respuesta de su server (por ejemplo, response vs. responseJSON JSON vs. …).

    De todos modos, lo anterior genera un cuerpo de request que se parece a:

     materials[0][material_id]=1&materials[0][qty]=10&materials[1][material_id]=2&materials[1][qty]=5 

    Y esto parece ser analizado por los serveres como solicitó en su pregunta.

Vale la pena señalar que este punto final ilustra la preparación de una application/x-www-form-urlencoded request con estructura de dictionary / matriz anidada, como se contempla aquí . Esto funciona en mi server administrado por un ISP importante, pero debo confesar que no he visto esta convención documentada en RFC formales, así que tendría cuidado de hacerlo. Personalmente me inclino a implementar esto como interfaz JSON.

El problema estaba en el método de anexar. He codificado en PHP 5 años y he olvidado que en Swift los índices no se asignan automáticamente como en PHP. Entonces, mi primer código de error fue:

 func getParameters() -> [[String: AnyObject]] { var result = [[String: AnyObject]]() for mmap in mmaps { let material: [String: AnyObject] = [ "material_id": mmap.material.id, "quantity": mmap.qty ] result.append(material) } return result } 

La respuesta es difícil asignar las keys como necesite:

 func getParameters() -> [String: [String: AnyObject]] { var result = [String: [String: AnyObject]]() let mmaps = self.mmaps.allObjects as [Mmap] for i in 0..<mmaps.count { let mmap = mmaps[i] let material: [String: AnyObject] = [ "material_id": mmap.material.id, "quantity": mmap.qty ] result["\(i)"] = material } return result } 

Puede hacer que su matriz sea JSON y publicarla en el server, luego analizar JSON en el extremo del server y, a partir de ahí, puede get los datos deseados, como esto:

 NSError *error; NSData *jsonData = [NSJSONSerialization dataWithJSONObject: yourArry options:NSJSONWritingPrettyPrinted error:&error]; NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; 

Espero que esto ayude.. 🙂