原因
storeJson["type"] = "retail"
工作方式不同于
storeJson["name"] = name
是因为第一个在代码中遵循不同的路径。具体来说,它在以下扩展(source)中使用了init(stringLiteral value: StringLiteralType) 方法。
extension JSON: Swift.StringLiteralConvertible {
public init(stringLiteral value: StringLiteralType) {
self.init(value)
}
public init(extendedGraphemeClusterLiteral value: StringLiteralType) {
self.init(value)
}
public init(unicodeScalarLiteral value: StringLiteralType) {
self.init(value)
}
}
在我们讨论如何解决您的具体问题后,我会进一步解释。
可能的解决方案#1:
storeJson["name"]?.string = name
输出:
{
"id" : {
"test" : "test"
},
"type" : "retail"
}
原因
storeJson["name"]?.string = name
不像我们想象的那样工作是因为可选链接。现在,如果我们通过调试器运行它,我们将看不到任何有意义的东西。事实上,我们会看到什么都没有。这有点令人担忧,可能意味着storeJson["name"] 是nil,因此该语句不再执行。让我们通过爆炸来验证我们的假设。我们将这一行改为:
storeJson["name"]!.string = name
在这种情况下,使用您当前的代码,您可能会得到
fatal error: unexpectedly found nil while unwrapping an Optional value
你应该这样做,因为storeJson["name"] 实际上是nil。因此,此解决方案不起作用。
可能的解决方案#2:
正如您在回答中正确指出的那样,如果您添加 storeJson["name"] = JSON(name),您将获得所需的行为:
func jsonTest()->String {
var storeJson = [String: JSON]()
var someJson = JSON(["test":"test"])
storeJson["id"] = someJson
storeJson["type"] = "retail" // <-- works fine
var name = "store1"
storeJson["name"] = JSON(name) // <-- works!
var store = JSON(storeJson)
return store.rawString()!
}
输出:
{
"id" : {
"test" : "test"
},
"name" : "store1",
"type" : "retail"
}
太棒了!因此,此解决方案有效!现在,稍后在您的代码中,您可以使用 .string 等随意更改它。
说明
回到字符串字面量的工作原理。你会在init 中注意到,它有
self.init(value)
通过对象init,然后通过case statement
...
case let string as String:
_type = .String
self.rawString = string
...
当您拨打storeJson["name"] = JSON(name) 时,您将跳过StringLiteralType init 而直接进入switch。
因此,你可以互换
storeJson["type"] = "retail"
与
storeJson["type"] = JSON("retail")