[英]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.