nsjsonserialization.jsonobjectwithdata 截断接收到的数据

Posted

技术标签:

【中文标题】nsjsonserialization.jsonobjectwithdata 截断接收到的数据【英文标题】:nsjsonserialization.jsonobjectwithdata truncating data received 【发布时间】:2016-04-03 23:11:56 【问题描述】:

我正在使用 NSURLSession 委托方式发出 http get 请求以从服务器获取 json 数据。我最终将在我的 NSURLSessionDataDelegate 中收到的 NSData 传递给模型对象以更新数组,如下所示:

func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) 
    networkDelegate?.updateGameList(data)
    dataTask.resume()

一旦数据进入 updateGameList 函数,如果我尝试使用 NSJSONSerialization.JSONObjectWithData,就会发生奇怪的事情。如果我不尝试使用 NSJSONSerialization,而只是将 NSData 转换为字符串,它看起来就像我期望的正确响应,如下所示:

Optional(["id":"a19610e4-675e-40b3-8335-085b61bfb0e3","name":"tttt","status":"PLAYING",
"id":"3be2e411-0086-46fd-8fc9-38d11831d0fb","name":"LWP TEST","status":"PLAYING",
"id":"b5d97d73-1ce2-4e5b-8b38-805835e2a21d","name":"asd","status":"PLAYING",
"id":"8a15575c-4c2c-4b46-ad5b-51b4b2680416","name":"MsGame","status":"WAITING",
"id":"b54531b8-5323-4630-929c-6eb2cfebde63","name":"423","status":"PLAYING",
"id":"5a7cfaa0-e2a4-41f6-bda2-a854a2d00a57","name":"4234","status":"PLAYING"])

但是,一旦我尝试将 NSData 与 NSJSONSerialization.JSONObjectWithData 一起使用来创建 NSArray,它就会开始抛出错误,因为数据似乎在开头或结尾被截断,如下所示:

Optional(["id":"a19610e4-675e-40b3-8335-085b61bfb0e3","name":"tttt","status":"PLAYING","id":"3be2e411-0086-46fd-8fc9-38d11831d0fb","name":"LWP TEST","status":"PLAYING",      
"id":"6d4e9731-61be-4191-bb9a-a30b6395a4a2","name":"RANDOMBOT","status":"PLAYING","id":"c31b363c-f565-4f4a-a6f1-1ac219425f40","name":"Testament ","status":"PLAYING",
"id":"af14d8bc-37a0-4ec3-88de-ee364344d720","name":"Testament ","status":"PLAYING",
"id":"29439dd9-357d-445b-856c-39862e19c2fc","name":"Testament ","status":"PLAYING","id":"cc29046f-4e80-422d-a103-5be175e799c9","name":"matt7","status":"PLAYING",
"id":"ff75c546-0e9b-4560-8efb-d0fa5be61cde","name":"u","status":"DONE","id":"3d88df55-6f84-469c-a18e-27e463dc30eb","name":"test","status":"PLAYING","id":"40eb1b13-21c3-4c8d-a379-e6b85329374b","name":"test","status":"PLAYING", 
"id":"4e7519dd-79d3-4229-8d0e-47ca112dc08f","name":"test","status":"PLAYING","id":"32ce49cc-17aa-47ca-8b9f-1c35dbdb78e6","name":"test","status":"PLAYING",
"id":"f5d5c961-17eb-421d-86b1-fbbadfb795da","name":"test","status":"PLAYING")

update game list error Error Domain=NSCocoaErrorDomain Code=3840 
"Unexpected end of file while parsing object." 
UserInfo=NSDebugDescription=Unexpected end of file while parsing object. 

这里是 updateGameList 函数,当我注释掉带有 JSONSerialization 代码的 do-catch 块时,dataString 打印出正确的响应,当我取消注释它时,它运行多次,几乎就像它在尝试处理数据一次一个块,而不是一次全部。如果我取出 .AllowFragments 选项,它会告诉我把它放进去,当我把它放进去时,它会得到真正的错误,即 json 数据没有正确开始或结束。

func updateGameList(gameListData:NSData) 
    let dataString = NSString(data: gameListData, encoding: NSUTF8StringEncoding)
    print(dataString)

    do 
        let gameList:NSArray = try NSJSONSerialization.JSONObjectWithData(gameListData, options: [.AllowFragments]) as! NSArray
    
    catch 
        print("update game list error \(error)")
    


【问题讨论】:

我刚刚意识到它实际上是将 NSData 以某些字符限制切割成碎片。所以打印出的第一个数据是开头和结尾不正确,然后打印出的第二个数据从那里继续并开始不正确。所以它试图分块处理它,但我不知道为什么。 请不要在 cmets 中发布内容或代码。请改用edit 按钮来编辑您的问题。谢谢! :) 【参考方案1】:

引用文档:

这个委托方法可能会被多次调用,每次调用 仅提供自上次调用以来收到的数据。该应用程序是 如果需要,负责积累这些数据。

所以你观察到的是一个特性:数据是以块的形式接收的(很可能是因为原始服务器使用Transfer-Encoding: chunked),因此你不能期望能够单独解析每个块 - 你会有将所有块累积到一个响应中,然后您可以尝试对其进行解析。

【讨论】:

以上是关于nsjsonserialization.jsonobjectwithdata 截断接收到的数据的主要内容,如果未能解决你的问题,请参考以下文章