[英]Swift: Convert Dictionary into JSON for multipart/Form-Data
我有一个 swift 应用程序,它向服务器发出具有正常值和图像的请求,因此我使用的是多部分/表单数据请求。 我有一个 object,它具有如下所示的所有值:
struct parameters: Codable {
var request : String = "blah"
var arrayData : [String] = ["bleh", "bluh"]
var dictionaryData : [String: String] = ["1": "Blah", "2": "Blah"]
}
但是,我无法将 arrays 的 json 转换版本和字典插入 httpBody。 我试过使用 JSONEncoder(),但它会将整个 object 转换为 JSON,而且我无法插入边界和其他内容。 有什么方法可以将 arrays & 字典转换为 json 格式,然后我可以将其作为值插入到多部分/表单数据请求中。
例如,对于字符串、字典和数组,它将返回
"blah"
["bleh", "bluh"]
{"1": "Blah", "2": "Blah"}
let dictParam = NSMutableDictionary() //字典
var ids = [String]()
let cat = (Constants.app_delegate.dictAddPostInfo.object(forKey: "categoryArr") as! NSArray)
//filter id from dic and add in ids
for dic in cat {
let dic = dic as! NSDictionary
let id = dic["id"] as! Int
ids.append(String(id))
}
//set data to dicParam
for i in 0..<ids.count {
let key = String.init(format: "categories[%d]", i)
dictParam.setValue(ids[i], forKey: key)
}
//For single value
dictParam.setValue(Constants.app_delegate.dictAddPostInfo.object(forKey: "Title") as! String, forKey: "title")
dictParam.setValue(Constants.app_delegate.dictAddPostInfo.object(forKey: "Description") as! String, forKey: "description")
dictParam.setValue(Constants.app_delegate.dictAddPostInfo.object(forKey: "Price") as! String, forKey: "price")
dictParam.setValue(latitude, forKey: "latitude")
dictParam.setValue(longitude, forKey: "longitude")
if let area = Constants.app_delegate.dictAddPostInfo.object(forKey: "area") as? String {
dictParam.setValue(area, forKey: "area")
}
else {
dictParam.setValue("", forKey: "area")
}
if let city = Constants.app_delegate.dictAddPostInfo.object(forKey: "city") as? String {
dictParam.setValue(city, forKey: "city")
}
else {
dictParam.setValue("", forKey: "city")
}
if let state = Constants.app_delegate.dictAddPostInfo.object(forKey: "state") as? String {
dictParam.setValue(state, forKey: "state")
}
else {
dictParam.setValue("", forKey: "state")
}
if let zip = Constants.app_delegate.dictAddPostInfo.object(forKey: "zip") as? String {
dictParam.setValue(zip, forKey: "zip")
}
else {
dictParam.setValue("", forKey: "zip")
}
这里将字典转换为 json 的代码
if let jsonData = try? JSONSerialization.data(withJSONObject: dictParam, options: .prettyPrinted), let theJSONText = String(data: jsonData, encoding: .ascii) {
print(theJSONText)
}
您可以单独对各个组件进行编码,而不是对整个结构进行编码。 使用上面的例子:
let paramters = Parameters()
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let request = try! encoder.encode(paramters.request)
let array = try! encoder.encode(paramters.arrayData)
let dict = try! encoder.encode(paramters.dictionaryData)
这将为您单独提供组件,然后您可以访问它们并按照您的喜好使用它们。 作为一个简单的例子:
print("Request \n", String(data: request, encoding: .utf8)!, "\n\n")
print("Array \n", String(data: array,encoding: .utf8)!, "\n\n")
print("Dict \n", String(data: dict ,encoding: .utf8)!, "\n\n")
正在输出...
要求
“废话”
大批
[“嘘”,“蓝”]
字典
{“2”:“废话”,“1”:“废话”}
这是一个多部分编码器,您可以直接将其转换为多部分表单数据。 我根据这个答案制作的, Custom Swift Encoder/Decoder for the Strings Resource Format
import Foundation
/// An object that encodes instances of a data type
/// as strings following the simple strings file format.
public class MultipartEncoder {
var boundary: String = ""
/// Returns a strings file-encoded representation of the specified value.
public func encode<T: Encodable>(_ value: T) throws -> Data {
let multipartencoding = MultipartEncoding()
try value.encode(to: multipartencoding)
return dataFromFormat(from: multipartencoding.data.strings)
}
private func dataFromFormat(from strings: [String: String]) -> Data {
let lineBreak = "\r\n"
//return dotStrings.joined(separator: "\n")
var fieldData = Data()
for (key, value) in strings{
fieldData.append("--\(boundary + lineBreak)")
fieldData.append("Content-Disposition: form-data; name=\"\(key)\"\(lineBreak + lineBreak)")
fieldData.append(value)
fieldData.append(lineBreak)
}
print("multipartdata \(String(data: fieldData, encoding: .ascii) )")
return fieldData as Data
}
}
fileprivate struct MultipartEncoding: Encoder {
/// Stores the actual strings file data during encoding.
fileprivate final class dictData {
private(set) var strings: [String: String] = [:]
func encode(key codingKey: [CodingKey], value: String) {
let key = codingKey.map { $0.stringValue }.joined(separator: ".")
strings[key] = value
}
}
fileprivate var data: dictData
init(to encodedData: dictData = dictData()) {
self.data = encodedData
}
var codingPath: [CodingKey] = []
let userInfo: [CodingUserInfoKey : Any] = [:]
func container<Key: CodingKey>(keyedBy type: Key.Type) -> KeyedEncodingContainer<Key> {
var container = StringsKeyedEncoding<Key>(to: data)
print("in container keyed")
container.codingPath = codingPath
return KeyedEncodingContainer(container)
}
func unkeyedContainer() -> UnkeyedEncodingContainer {
var container = StringsUnkeyedEncoding(to: data)
container.codingPath = codingPath
return container
}
func singleValueContainer() -> SingleValueEncodingContainer {
var container = StringsSingleValueEncoding(to: data)
container.codingPath = codingPath
return container
}
}
fileprivate struct StringsKeyedEncoding<Key: CodingKey>: KeyedEncodingContainerProtocol {
private let data: MultipartEncoding.dictData
init(to data: MultipartEncoding.dictData) {
self.data = data
}
var codingPath: [CodingKey] = []
mutating func encodeNil(forKey key: Key) throws {
data.encode(key: codingPath + [key], value: "nil")
}
mutating func encode(_ value: Bool, forKey key: Key) throws {
data.encode(key: codingPath + [key], value: value.description)
}
mutating func encode(_ value: String, forKey key: Key) throws {
data.encode(key: codingPath + [key], value: value)
}
mutating func encode(_ value: Date, forKey key: Key) throws {
var formatter = getDayFormatter()
print("value is \(formatter.string(from: value))")
data.encode(key: codingPath + [key], value: formatter.string(from: value))
}
mutating func encode(_ value: Double, forKey key: Key) throws {
data.encode(key: codingPath + [key], value: value.description)
}
mutating func encode(_ value: Float, forKey key: Key) throws {
data.encode(key: codingPath + [key], value: value.description)
}
mutating func encode(_ value: Int, forKey key: Key) throws {
data.encode(key: codingPath + [key], value: value.description)
}
mutating func encode(_ value: Int8, forKey key: Key) throws {
data.encode(key: codingPath + [key], value: value.description)
}
mutating func encode(_ value: Int16, forKey key: Key) throws {
data.encode(key: codingPath + [key], value: value.description)
}
mutating func encode(_ value: Int32, forKey key: Key) throws {
data.encode(key: codingPath + [key], value: value.description)
}
mutating func encode(_ value: Int64, forKey key: Key) throws {
data.encode(key: codingPath + [key], value: value.description)
}
mutating func encode(_ value: UInt, forKey key: Key) throws {
data.encode(key: codingPath + [key], value: value.description)
}
mutating func encode(_ value: UInt8, forKey key: Key) throws {
data.encode(key: codingPath + [key], value: value.description)
}
mutating func encode(_ value: UInt16, forKey key: Key) throws {
data.encode(key: codingPath + [key], value: value.description)
}
mutating func encode(_ value: UInt32, forKey key: Key) throws {
data.encode(key: codingPath + [key], value: value.description)
}
mutating func encode(_ value: UInt64, forKey key: Key) throws {
data.encode(key: codingPath + [key], value: value.description)
}
mutating func encode<T: Encodable>(_ value: T, forKey key: Key) throws {
if T.self == Date.self{
var formatter = getDayFormatter()
print("value is \(formatter.string(from: value as! Date))")
data.encode(key: codingPath + [key], value: formatter.string(from: value as! Date))
}else{
var stringsEncoding = MultipartEncoding(to: data)
stringsEncoding.codingPath.append(key)
try value.encode(to: stringsEncoding)
}
}
mutating func nestedContainer<NestedKey: CodingKey>(
keyedBy keyType: NestedKey.Type,
forKey key: Key) -> KeyedEncodingContainer<NestedKey> {
var container = StringsKeyedEncoding<NestedKey>(to: data)
container.codingPath = codingPath + [key]
return KeyedEncodingContainer(container)
}
mutating func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer {
var container = StringsUnkeyedEncoding(to: data)
container.codingPath = codingPath + [key]
return container
}
mutating func superEncoder() -> Encoder {
let superKey = Key(stringValue: "super")!
return superEncoder(forKey: superKey)
}
mutating func superEncoder(forKey key: Key) -> Encoder {
var stringsEncoding = MultipartEncoding(to: data)
stringsEncoding.codingPath = codingPath + [key]
return stringsEncoding
}
}
fileprivate struct StringsUnkeyedEncoding: UnkeyedEncodingContainer {
private let data: MultipartEncoding.dictData
init(to data: MultipartEncoding.dictData) {
self.data = data
}
var codingPath: [CodingKey] = []
private(set) var count: Int = 0
private mutating func nextIndexedKey() -> CodingKey {
let nextCodingKey = IndexedCodingKey(intValue: count)!
count += 1
return nextCodingKey
}
private struct IndexedCodingKey: CodingKey {
let intValue: Int?
let stringValue: String
init?(intValue: Int) {
self.intValue = intValue
self.stringValue = intValue.description
}
init?(stringValue: String) {
return nil
}
}
mutating func encodeNil() throws {
data.encode(key: codingPath + [nextIndexedKey()], value: "nil")
}
mutating func encode(_ value: Bool) throws {
data.encode(key: codingPath + [nextIndexedKey()], value: value.description)
}
mutating func encode(_ value: Date) throws {
let formatter = getDayFormatter()
print("value2 is \(formatter.string(from: value))")
data.encode(key: codingPath + [nextIndexedKey()], value: formatter.string(from: value))
}
mutating func encode(_ value: String) throws {
data.encode(key: codingPath + [nextIndexedKey()], value: value)
}
mutating func encode(_ value: Double) throws {
data.encode(key: codingPath + [nextIndexedKey()], value: value.description)
}
mutating func encode(_ value: Float) throws {
data.encode(key: codingPath + [nextIndexedKey()], value: value.description)
}
mutating func encode(_ value: Int) throws {
data.encode(key: codingPath + [nextIndexedKey()], value: value.description)
}
mutating func encode(_ value: Int8) throws {
data.encode(key: codingPath + [nextIndexedKey()], value: value.description)
}
mutating func encode(_ value: Int16) throws {
data.encode(key: codingPath + [nextIndexedKey()], value: value.description)
}
mutating func encode(_ value: Int32) throws {
data.encode(key: codingPath + [nextIndexedKey()], value: value.description)
}
mutating func encode(_ value: Int64) throws {
data.encode(key: codingPath + [nextIndexedKey()], value: value.description)
}
mutating func encode(_ value: UInt) throws {
data.encode(key: codingPath + [nextIndexedKey()], value: value.description)
}
mutating func encode(_ value: UInt8) throws {
data.encode(key: codingPath + [nextIndexedKey()], value: value.description)
}
mutating func encode(_ value: UInt16) throws {
data.encode(key: codingPath + [nextIndexedKey()], value: value.description)
}
mutating func encode(_ value: UInt32) throws {
data.encode(key: codingPath + [nextIndexedKey()], value: value.description)
}
mutating func encode(_ value: UInt64) throws {
data.encode(key: codingPath + [nextIndexedKey()], value: value.description)
}
mutating func encode<T: Encodable>(_ value: T) throws {
var stringsEncoding = MultipartEncoding(to: data)
stringsEncoding.codingPath = codingPath + [nextIndexedKey()]
try value.encode(to: stringsEncoding)
}
mutating func nestedContainer<NestedKey: CodingKey>(
keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer<NestedKey> {
var container = StringsKeyedEncoding<NestedKey>(to: data)
container.codingPath = codingPath + [nextIndexedKey()]
return KeyedEncodingContainer(container)
}
mutating func nestedUnkeyedContainer() -> UnkeyedEncodingContainer {
var container = StringsUnkeyedEncoding(to: data)
container.codingPath = codingPath + [nextIndexedKey()]
return container
}
mutating func superEncoder() -> Encoder {
var stringsEncoding = MultipartEncoding(to: data)
stringsEncoding.codingPath.append(nextIndexedKey())
return stringsEncoding
}
}
fileprivate struct StringsSingleValueEncoding: SingleValueEncodingContainer {
private let data: MultipartEncoding.dictData
init(to data: MultipartEncoding.dictData) {
self.data = data
}
var codingPath: [CodingKey] = []
mutating func encodeNil() throws {
data.encode(key: codingPath, value: "nil")
}
mutating func encode(_ value: Bool) throws {
data.encode(key: codingPath, value: value.description)
}
mutating func encode(_ value: String) throws {
data.encode(key: codingPath, value: value)
}
mutating func encode(_ value: Double) throws {
data.encode(key: codingPath, value: value.description)
}
mutating func encode(_ value: Date) throws {
let formatter = getDayFormatter()
print("value3 is \(formatter.string(from: value))")
data.encode(key: codingPath, value: formatter.string(from: value))
}
mutating func encode(_ value: Float) throws {
data.encode(key: codingPath, value: value.description)
}
mutating func encode(_ value: Int) throws {
data.encode(key: codingPath, value: value.description)
}
mutating func encode(_ value: Int8) throws {
data.encode(key: codingPath, value: value.description)
}
mutating func encode(_ value: Int16) throws {
data.encode(key: codingPath, value: value.description)
}
mutating func encode(_ value: Int32) throws {
data.encode(key: codingPath, value: value.description)
}
mutating func encode(_ value: Int64) throws {
data.encode(key: codingPath, value: value.description)
}
mutating func encode(_ value: UInt) throws {
data.encode(key: codingPath, value: value.description)
}
mutating func encode(_ value: UInt8) throws {
data.encode(key: codingPath, value: value.description)
}
mutating func encode(_ value: UInt16) throws {
data.encode(key: codingPath, value: value.description)
}
mutating func encode(_ value: UInt32) throws {
data.encode(key: codingPath, value: value.description)
}
mutating func encode(_ value: UInt64) throws {
data.encode(key: codingPath, value: value.description)
}
mutating func encode<T: Encodable>(_ value: T) throws {
var stringsEncoding = MultipartEncoding(to: data)
stringsEncoding.codingPath = codingPath
try value.encode(to: stringsEncoding)
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.