有效的 JSON,但来自 AFNetworking/NSJSONSerialization 的“Cocoa 错误 3840”

Posted

技术标签:

【中文标题】有效的 JSON,但来自 AFNetworking/NSJSONSerialization 的“Cocoa 错误 3840”【英文标题】:Valid JSON, but 'Cocoa error 3840' from AFNetworking/NSJSONSerialization 【发布时间】:2013-09-06 05:15:30 【问题描述】:

我已经花了好几个小时试图解决这个问题,但无济于事 - 看来我唯一的选择是在这里发帖,看看是否有人可以对这个问题有所了解。这可能是 AFNetworking 的问题,或者(更有可能)是我的代码的问题。

我使用的代码完美适用于我的应用程序中 99% 的操作。我正在开发一个应用程序,它通过构建 JSON 搜索、发送它们并接收来自服务器的响应来利用 Elastic Search。

以下是返回的 JSON 示例:


    "took": 4,
    "timed_out": false,
    "_shards": 
        "total": 5,
        "successful": 5,
        "failed": 0
    ,
    "hits": 
        "total": 1,
        "max_score": null,
        "hits": [
            
                "_index": "asx",
                "_type": "61a88d3848b00655d9aa59db70847318",
                "_id": "b91f9257744fedb4ef1c127e275c127c",
                "_score": null,
                "_source": 
                    "value": "22/06/1998"
                ,
                "sort": [
                    4.439049394553e-312
                ]
            
        ]
    

现在,将其插入 jsonlint.com(并且了解一点 JSON 格式),很容易看出这是有效的 JSON。

我正在使用 AFHTTPClient 子类来发布我的请求并接收数据。这是我用来发布的代码:

[super postPath:path parameters:parameters success:^(AFHTTPRequestOperation *operation, NSDictionary *response) 
    NSData *responseData = [(AFJSONRequestOperation *)operation responseData];
    NSDictionary *responseDictionary;

    if (responseData != nil) 
        responseDictionary = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingAllowFragments error:NULL];
    

    if (success) 
        success(operation, responseDictionary);
    
 failure:^(AFHTTPRequestOperation *operation, NSError *error) 
    NSData *responseData = [(AFJSONRequestOperation *)operation responseData];
    NSDictionary *responseDictionary;

    if (responseData != nil) 
        responseDictionary = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingAllowFragments error:NULL];
    

    if (failure) 
        failure(operation, error, responseDictionary);
    
];

这里没什么特别的,我只是将响应转换为一些 JSON。

但是,问题在于,对于这个特定的请求,AFNetworking 将响应视为失败,因此失败块中的代码是唯一正在执行的代码。我收到以下错误:

(lldb) po error
$1 = 0x0adbc710 Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (Number wound up as NaN around character 279.) UserInfo=0xad968d0 NSDebugDescription=Number wound up as NaN around character 279.

JSON 中包含一个指数数字(具体为 4.439049394553e-312),但这是有效数字,应该能够被解析。当我尝试使用 NSJSONSerialization 解析响应数据时,我得到了相同的 NSError。澄清一下 - AFNetworking 给我的错误信息与 NSJSONSerialization 相同。

我找不到与我有同样问题的其他人,也无法弄清楚为什么我的 JSON 无法解析。它给我的应用程序留下了一个我无法修复的非常大的错误。

如果有人能对这个问题有所了解,那就太好了。如果这不是 AFNetworking 的问题,如果你能指出一个有用的资源,那也很棒。当然,如果您需要更多信息,请询问

谢谢。

【问题讨论】:

【参考方案1】:

NSJSONSerialization 使用NSDecimalNumber 来表示数字,而

[NSDecimalNumber decimalNumberWithString:@"4.439049394553e-312"]

已经返回NaN,因为NSDecimalNumber只能代表数字

mantissa x 10^exponent         where `-128 <= exponent <= 127`.

所以这似乎是NSJSONSerialization 的“限制”(或错误),它仅适用于 一定范围内的数字。

我用“SBJsonParser”做了一个快速测试,它也有同样的问题。

【讨论】:

我认为您在这里有所作为。我们如何被限制在我们可以解码的数据上有点愚蠢。我原以为它们会包含某种 JSON 解析选项,例如,如果它们不能被解析为数字,则将它们解析为字符串。与您可以有损转换为 NSData 的方式相同。 不,NSJSONSerialization 使用带有整数值的 NSNumber 表示小于 10^18 的整数,使用 NSDecimalNumber 表示整数值 >= 10^18,使用双精度值表示任何有小数点或指数的 NSNumber。跨度> @gnasher729:你说得对,有些情况下使用的是 NSNumber,而不是 NSDecimalNumber。 (我在***.com/questions/20198040/… 的冗长讨论中也注意到了这一点)。但似乎你并不完全正确。 1.2e-3 给出(在我的测试中)一个 NSDecimalNumber。 0.0012 给出一个包含双精度的 NSNumber。而4.439049394553e-312 仍然失败。 (在 ios 7 模拟器中完成的测试。) 是的,这里也在寻找一种方法来规避这个问题 这个问题显然在 iOS 11 之后得到了修复。iOS 10 仍然会崩溃。

以上是关于有效的 JSON,但来自 AFNetworking/NSJSONSerialization 的“Cocoa 错误 3840”的主要内容,如果未能解决你的问题,请参考以下文章

AFNetworking 序列化正斜杠使 JSON 有效负载无效

使用 AFNetworking3 目标 c 显示来自 json 数据的图像

AFNetworking 和 Swift - 保存 json 响应

NSURLConnection 有效,但 AFNetworking 无效(在特定 URL 上)

带有 json 反馈的 AFNetworking 发布请求

AFNetworking 2 响应错误(内容类型:文本/html 而非 JSON)