为什么我的结构不按照我声明的属性和编码键的顺序进行编码?



这是打印print(String(data: encoded, encoding: .utf8) as Any) 时正确编码的主结构结构体打印编码的mainObject,然后打印结构体中的其他变量,但我希望它按顺序打印:mainAccount、mainObject、reference。

struct T: Codable {
    init(){}
     let mainAccount = "IMHOTECHPECOM"
     let mainObject = mainObject()
     let reference = UUID()
     // Enum that allows easy encoding
     enum CodingKeys: CodingKey {
         case mainAccount, mainObject, reference;
     }
     // function to conform to encodable protocol
     func encode(to encoder: Encoder) throws {
         var container = encoder.container(keyedBy: CodingKeys.self)
         try container.encode(mainAccount, forKey: .merchantAccount)
         try container.encode(mainObject.self, forKey: .mainObject)
         try container.encode(reference, forKey: .reference)
       
     }
    
     // conforms with decodable protocol
     required init(from decoder: Decoder) throws {
         let container = try decoder.container(keyedBy: CodingKeys.self)
         _ = try container.decode(String.self, forKey: .mainAccount)
         _ = try container.decode(String.self, forKey: .mainObject)
         _ = try container.decode(String.self, forKey: .reference)
         
     }
 }

这是主对象

struct mainObject:  Codable {
    var type = "kind"
    var identifier: String = ""
    var guide: String = ""
    
    init(){}
   
    enum CodingKeys: CodingKey{
         case type, identifier, guide;
    }
    // function to conform to encodable protocol
    func encode(to encoder: Encoder) throws {
        
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(type, forKey: .type)
        try container.encode(identifier, forKey: .identifier)
        try container.encode(guide, forKey: .guide)
        }
    // conforms with decodable protocol
   required init(from decoder: Decoder) throws {
       let container = try decoder.container(keyedBy: CodingKeys.self)
       type = try container.decode(String.self, forKey: .type)
       identifier = try container.decode(String.self, forKey: .identifier)
       guide = try container.decode(String.self, forKey: .identifier) 
     
    }
}

这是实际视图中的功能,编码来自按钮按压的数据

func getBalance() async {
        let encoder = JSONEncoder()
        encoder.outputFormatting = [.sortedKeys]
        encoder.outputFormatting = [.withoutEscapingSlashes]
        encoder.outputFormatting = [.prettyPrinted]
        
        guard let encoded = try? encoder.encode(mainobject) else {
            print("Failed to encode")
            return
        }
        
        let url = URL(string: "https://testurl.com")!
        var request = URLRequest(url: url)
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.httpMethod = "POST"
        
        do {
            let (response, _) = try await URLSession.shared.upload(for: request, from: encoded)
            print(String(data: encoded, encoding: .utf8) as Any)
            print(String(data: response, encoding: .utf8) as Any)
            } catch {
            print("Encoding failed")
        }
  
        let _ = try? JSONDecoder().decode(mainObject.self, from: encoded)
     

在这种特殊情况下,您要求的顺序恰好符合字母顺序。因此,如果你将.sortedKeys添加到编码器的outputFormatting属性中,你就会得到你想要的订单:

let encoder = JSONEncoder() 
encoder.outputFormatting = [.sortedKeys]
let data = try encoder.encode(myT)

这将影响JSON中所有对象中键的顺序。因此,T的密钥将按mainAccount, mainObject, reference的顺序输出,而mainObject的密钥将按照guide, identifier, type的顺序输出。

一般的答案是JSONEncoder不记得向带键容器添加键的顺序。在内部,它使用标准Swift Dictionary来存储键和值。Swift Dictionary不保证对其密钥进行任何排序,每次启动程序时,顺序都可能发生变化。

如果要保证密钥的顺序得到保留,就必须编写自己的Encoder实现,这不是一项简单的任务。

相关内容

  • 没有找到相关文章

最新更新