使用[NSJSONSerialization dataWithJSONObject:]转换为NSData时保持NSDictionary键的顺序

Rod*_*les 15 cocoa-touch objective-c ios

我有以下情况:

NSDictionary *params = @{
    @"Checkout" : @{
        @"conditions" : @{@"Checkout.user_id" : @1},
        @"order" : @{@"Checkout.id" : @"DESC"}
    },
    @"PaymentState" : @[],
    @"Offer" : @[]
};
Run Code Online (Sandbox Code Playgroud)

此字典包含传递带有Web服务URL的JSON字符串的Web服务请求的参数.我使用NSJSONSerialization类获取JSON字符串,如下所示:

NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:nil];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
Run Code Online (Sandbox Code Playgroud)

问题是:jsonString"keys"的顺序与原来的params字典键顺序不同,如下所示:

{
"Offer":[],
"PaymentState":[],
"Checkout":{
    "conditions":{"Checkout.user_id":6},
    "order":{"Checkout.id":"DESC"}
}
Run Code Online (Sandbox Code Playgroud)

}

也就是说,"PaymentState"和"Offer"键首先出现在jsonString中,我需要保持原始顺序.这非常重要,如下:

{
"Checkout":{
    "conditions":{"Checkout.user_id":6},
    "order":{"Checkout.id":"DESC"}
},
"Offer":[],
"PaymentState":[]
Run Code Online (Sandbox Code Playgroud)

}

那么伙计们,我怎么能这样做?

小智 10

每当我需要保持字典键的顺序时,我就使用CocoaWithLove中的OrderedDictionary.

基本上,OrderedDictionary包含一个NSMutableDictionary和一个NSMutableArray用于其中的键,以跟踪键的顺序.它实现了子类化所需的方法NSDictionary/ NSMutableDictionary并且只是将方法调用"传递"到内部NSMutableDictionary.

  • @mattyohe - 每当有一个也是列表的字典时很有用."字典"(例如,按字母顺序列出单词以及每个单词的定义的其中一个)是一个完美的例子.它是键到值的映射,但键对它们有自然的排序.并且有时可以方便地使用可以容纳该数据结构的单个数据结构. (3认同)
  • 你什么时候"需要"保持字典键的顺序? (2认同)
  • 另一种选择似乎是:https://github.com/Marxon13/NSOrderedDictionary (2认同)
  • @neilvillareal - OrderedDictionary 工作得很好,正是我所需要的。谢谢!! (2认同)

Me1*_*000 10

根据JSON规范,JSON对象是特定无序的.每个JSON库都会考虑到这一点.因此,即使你现在解决这个问题,你几乎肯定会在以后遇到问题; 因为你做的假设不成立(按键是有序的).

  • 事实上OP需要生成的东西在技术上并不是JSON,这在很大程度上是无关紧要的.他的任务是生成一个具有特定字段顺序的类似JSON的字符串.告诉他"这不是JSON"并不能帮助他做到这一点. (7认同)
  • 因为我不知道谁编写了API(虽然显然OP可以访问代码,因为他知道底层的实现细节),这有点困难......所以我的建议很简单......对编写糟糕的API的人大喊大叫,或使用更好的结账提供商.我当然不会相信他们. (2认同)

Ene*_*nso 7

虽然NSDictionary并且Dictionary不为其键维护任何特定顺序,但从 iOS 11 和 macOS 10.13 开始,JSONSerialization支持通过指定选项按字母顺序对键进行排序(请参阅 Apple 文档sortedKeys

例子:

let data: [String: Any] = [
    "hello": "world",
    "a": 1,
    "b": 2
]

let output = try JSONSerialization.data(withJSONObject: data, options: [.prettyPrinted, .sortedKeys])
let string = String(data: output, encoding: .utf8)

// {
//  "a" : 1,
//  "b" : 2,
//  "hello" : "world"
// }
Run Code Online (Sandbox Code Playgroud)

  • 这对于可读性非常有用,但是如果您可以传递自己的排序函数以进行自定义排序作为选项,那就太好了……有时直接按字母顺序排列并不是您想要的。或者,可以选择传入数组(已排序)中的键来指定排序顺序。 (2认同)