8

POSTリクエストを介して辞書の配列を送信する必要があります。例えば:

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

Alamofire.request は次の投稿データを送信します。

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

私はその表現を受け取りたい:

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

3 に答える 3

9

問題は append メソッドにありました。私はPHPで5年間コーディングしましたが、SwiftではPHPのようにインデックスが自動的に割り当てられないことを忘れていました。したがって、私の最初のバグのあるコードは次のとおりです。

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
}

答えは、必要に応じてキーをハード アサインすることです。

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
}
于 2015-01-08T02:21:37.190 に答える
2

いくつかの考え:

  1. 応答を 1 つのキーを持つディクショナリとして送信すると、ディクショナリ内の配列が正しくエンコードされます。

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

    parametersそれをofとして指定するだけでrequest()、Alamofire が適切にエンコードします。

  2. 辞書の配列を送信したい場合は、JSON を受け入れるように Web サービスを変更することもできます。次に、JSON を自分で (JSONSerializationまたはを使用してJSONEncoder) エンコードし、要求の本文を設定して、その要求を送信できます。

  3. application/x-www-form-urlencoded辞書の配列でリクエストを送信したい場合は、それを自分でエンコードする必要があります。Swift 3 以降では、次のようになります。

    func encodeParameters(_ object: Any, prefix: String? = nil) -> String {
        if let dictionary = object as? [String: Any] {
            return dictionary.map { key, value -> String in
                self.encodeParameters(value, prefix: prefix != nil ? "\(prefix!)[\(key)]" : key)
                }.joined(separator: "&")
        } else if let array = object as? [Any] {
            return array.enumerated().map { (index, value) -> String in
                return self.encodeParameters(value, prefix: prefix != nil ? "\(prefix!)[\(index)]" : "\(index)")
            }.joined(separator: "&")
        } else {
            let escapedValue = "\(object)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed)!
            return prefix != nil ? "\(prefix!)=\(escapedValue)" : "\(escapedValue)"
        }
    }
    

    どこ

    extension CharacterSet {
    
        /// Returns the character set for characters allowed in the individual parameters within a query URL component.
        ///
        /// The query component of a URL is the component immediately following a question mark (?).
        /// For example, in the URL `http://www.example.com/index.php?key1=value1#jumpLink`, the query
        /// component is `key1=value1`. The individual parameters of that query would be the key `key1`
        /// and its associated value `value1`.
        ///
        /// According to RFC 3986, the set of unreserved characters includes
        ///
        /// `ALPHA / DIGIT / "-" / "." / "_" / "~"`
        ///
        /// In section 3.4 of the RFC, it further recommends adding `/` and `?` to the list of unescaped characters
        /// for the sake of compatibility with some erroneous implementations, so this routine also allows those
        /// to pass unescaped.
    
        static var urlQueryValueAllowed: CharacterSet = {
            let generalDelimitersToEncode = ":#[]@"    // does not include "?" or "/" due to RFC 3986 - Section 3.4
            let subDelimitersToEncode = "!$&'()*+,;="
    
            var allowed = CharacterSet.urlQueryAllowed
            allowed.remove(charactersIn: generalDelimitersToEncode + subDelimitersToEncode)
            return allowed
        }()
    }
    

    明らかに、responseサーバーの応答の性質に適した方法を使用してください (例: responsevs. responseJSONvs. ...)。

    とにかく、上記は次のようなリクエストボディを生成します:

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

    そして、これは、質問で要求したとおり、サーバーによって解析されているようです。

この最後のポイントは、application/x-www-form-urlencodedネストされたディクショナリ/配列構造を使用したリクエストの準備を示していることに注意してください。これは主要な ISP が運営する私のサーバーでは機能しますが、この規則が正式な RFC で文書化されているのを見たことがないことを告白しなければなりません。個人的には、これを JSON インターフェイスとして実装する傾向があります。

以前のバージョンの Swift については、この回答の以前のリビジョンを参照してください。

于 2015-01-06T17:24:15.810 に答える