SwiftyJSON - 无法从 JSON 字符串获取 transactionId

Posted

技术标签:

【中文标题】SwiftyJSON - 无法从 JSON 字符串获取 transactionId【英文标题】:SwiftyJSON - Unable to get transactionId from JSON String 【发布时间】:2019-08-28 19:27:47 【问题描述】:

我正在使用 CocoaAsyncSocket 从使用 JSON 的服务器 API 检索消息。我能够获取数据并将其转换为可打印的字符串,但我无法使用 SwiftyJSON 从尝试解析我已经拥有的 JSON 字符串中检索一个值 (transactionId)。我知道还有其他类似的帖子,但都没有解决我的问题。

在 ViewController 中:

func socket(_ sock: GCDAsyncSocket, didRead data: Data, withTag tag: Int) 

    guard let msg = String(data: data, encoding: .utf8) else  return 

    var response = " "
    if msg.contains("Reset") 
        transactionID = ParseJSON().parse(message: msg)

        response = String(format: "\"Response\":\"transactionId\":\"%@%\",\"content\":\"Reset\":", transactionID)
        socket.write((response.data(using: .utf8))!, withTimeout: -1, tag: 0)
    

    socket?.readData(withTimeout: -1, tag: 0)

ParseJSON 类:

func parse (message: String) -> String 
    var parsedMessage = " "

    let json = JSON(parseJSON: message)
    let transactionId = json["Request"]["transactionId"].stringValue
    parsedMessage = transactionId

    print(parsedMessage)

    return parsedMessage

显示的结果是一个空的 transactionId 值。没有打印或任何东西。 如果您在我的代码中发现任何错误或有更好的方法,请告诉我!

编辑:

这是我要解析的字符串:

“请求”:“内容”:“重置”:,“transactionId”:“f7c4d630-552b-46d9-a37d-44450537b48d”

这是我的输出:

\"Response\":\"transactionId\":\"\",\"content\":\"Reset\":

【问题讨论】:

可能不相关,但 transactionId 占位符中的尾随 % 是有意的吗? 那是无意的,它并没有解决我的问题,但我肯定会删除它,以防它导致进一步的问题。 肯定有其他事情发生,因为上面的工作正常:gist.github.com/robertmryan/3f181810c17bba9eb982073f4983d815 当然,你可以简化一下parse,你可以去掉那个无关紧要的%,我不会建议手动构建 JSON 等,但最重要的是,以上工作正常。还有一些其他问题(例如,msg 不能与您描述的完全一样,等等)。\ 所以这是我从你提供的内容中发现的,如果我像你一样使用与 msg 相同的字符串创建一个变量,那么它就可以工作。没有意义的是为什么我可以从打印的 msg 中复制并从中创建一个有效的变量,但是如果我使用变量 msg 本身,则什么都不会被解析。 【参考方案1】:

问题不在于代码。考虑:

func parse(message: String) -> String 
    let json = JSON(parseJSON: message)
    return json["Request"]["transactionId"].stringValue


let input = """
    "Request": "content": "Reset": , "transactionId": "f7c4d630-552b-46d9-a37d-44450537b48d"
    """

let transactionID = parse(message: input)

print("transactionId:", transactionID)

let response = String(format: "\"Response\":\"transactionId\":\"%@\",\"content\":\"Reset\":", transactionID)

print("response:", response)

如您所料,上述结果是:

transactionId:f7c4d630-552b-46d9-a37d-44450537b48d

响应:"Response":"transactionId":"f7c4d630-552b-46d9-a37d-44450537b48d","content":"Reset":

所以我怀疑输入 message 与您的预期不太一样。所以我可能会建议添加一些错误处理,以便您可以准确诊断出问题所在:

func parse(message: String) -> String 
    let json = JSON(parseJSON: message)
    if let error = json.error 
        fatalError("JSON parsing error: \(error)")
    

    let request = json["Request"]
    if let error = request.error 
        fatalError("request error: \(error)")
    

    let transactionId = request["transactionId"]
    if let error = transactionId.error 
        fatalError("transactionId error: \(error)")
    

    return transactionId.stringValue

现在,在实践中,您可能不会使用fatalError,而是会进行一些优雅的错误处理(例如,将parse 更改为throws,然后throw 遇到的错误,如果有的话,然后catch 调用parse 的错误并优雅地处理任何运行时问题)。但在此诊断过程中,fatalError 很有用,因为它会在有问题的行停止调试器,从而简化诊断过程。

归根结底,请求不能完全符合您的期望。请注意,它将对大小写、格式错误的 JSON 等非常敏感。因此,通过查看 SwiftyJSON 提供的错误,您应该能够很快缩小问题范围。


下面,你告诉我们Data是:

<7b225265 71756573 74223a20 7b22636f 6e74656e 74223a20 7b225265 73657422
 3a207b7d 7d2c2022 7472616e 73616374 696f6e49 64223a20 22643937 36303036
 622d3130 38302d34 3864652d 39323232 2d623139 63363663 35303164 31227d7d
 00>

问题在于最后一个字节0x00。如果你删除它,它会起作用。

FWIW,当我将该十六进制字符串转换回 Data 并通过 JSONSerialization 运行时,它确认了诊断:

错误域=NSCocoaErrorDomain Code=3840 "最后的垃圾。" UserInfo=NSDebugDescription=垃圾结束。

您需要弄清楚为什么 0x00 包含在有效负载的末尾并将其删除。

【讨论】:

使用您提供的错误处理,我收到了这个致命错误:Thread 1: Fatal error: Request error: wrongType。这个 wrongType 错误意味着 JSON 在顶层的类型不同 ,我不确定这是什么意思。 您在哪一行收到该错误?无论如何,它证实了 JSON 与您描述的不同的假设。最有可能的是,它只是格式不正确。也许您在某处遗漏了引号。也许"。可能有些牙套不平衡。很难说。我们需要查看实际的 JSON,这显然不是您在问题中提供的。它可能看起来相似,但并不完全相同。 (顺便说一句,这就是为什么我们不像您的 String(format:) 示例那样手动构建 JSON 字符串的原因,正是为了避免此类问题。) 我现在正在临时手动构建 JSON 字符串,但这不是我要解析的内容。我提供的 JSON 是从中继服务器读取的,我没有手动构建或格式化它。我打印了中继服务器发送的内容并将其从日志中复制到此处。中继服务器目前正在读取我的格式化字符串,但我最终尝试从中继服务器读取并没有按预期进行。我提供的内容是直接从guard let msg = String(data: data, encoding: .utf8) else return 打印的日志中复制的 既然它不是那么大,你为什么不print(data as NSData) 和我们分享那个完整的十六进制字符串...... &lt;7b225265 71756573 74223a20 7b22636f 6e74656e 74223a20 7b225265 73657422 3a207b7d 7d2c2022 7472616e 73616374 696f6e49 64223a20 22643937 36303036 622d3130 38302d34 3864652d 39323232 2d623139 63363663 35303164 31227d7d 00&gt; 每个字符串唯一不同的是transactionId 不同,此外这应该与我之前提供的准确无误。

以上是关于SwiftyJSON - 无法从 JSON 字符串获取 transactionId的主要内容,如果未能解决你的问题,请参考以下文章

swiftyjson 从 json 数组中获取字符串

如何使用 SwiftyJSON 从深度嵌套的 JSON 字典中获取字符串 [重复]

Swift - 使用 SwiftyJSON 从 JSON 中获取字符串数组

尝试使用 swiftyJSON 快速解析 JSON

从推送通知解析时出现 SwiftyJson 解析问题

使用 SwiftyJSON 选择字符串数组