iOS 解析大型 JSON 消息时遇到问题

Posted

技术标签:

【中文标题】iOS 解析大型 JSON 消息时遇到问题【英文标题】:iOS trouble parsing large JSON message 【发布时间】:2014-04-10 12:13:26 【问题描述】:

我有一个应用程序接收 JSON messages 超过 TCP。这对于较小的消息非常有效,但是有时当消息很大时,它们会在中间被截断,并且应用无法解析它们。

我的 ios 代码:

- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent 

    collectedData = [NSMutableData data];

    switch (streamEvent) 

        case NSStreamEventOpenCompleted:
            NSLog(@"Stream opened");

            break;
        case NSStreamEventHasBytesAvailable:

            if (theStream == inputStream) 


                NSData *nl = [@"\n" dataUsingEncoding:NSUTF8StringEncoding];

                uint8_t bufferz[1024];
                int lenz;
                while ([inputStream hasBytesAvailable]) 
                    lenz = [inputStream read:bufferz maxLength:sizeof(bufferz)];
                    [collectedData appendBytes: (const void *)bufferz length:lenz];
                
                NSRange nlRange =[collectedData rangeOfData:nl options:0 range:NSMakeRange(0, [collectedData length])];
                while (nlRange.location != NSNotFound) 
                    // Extract data from the beginning up to (but not including) the newline character:
                    NSData *jsonData = [collectedData subdataWithRange:NSMakeRange(0, nlRange.location)];
                    // Remove data from the beginning up to and including the newline character:
                    [collectedData replaceBytesInRange:NSMakeRange(0, nlRange.location + nlRange.length) withBytes:NULL length:0];

                    // Process jsonData ...
                    NSError *error;
                    NSMutableDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&error];
                    // ...


                    NSString* type = [jsonDict objectForKey:@"type"];

                    //NSLog(@"NEW NEW NEW --> %@\n", jsonDict);
                    NSString *outputData = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];


                    if(error) 
                        NSLog(@"THE STRING ------------>>>>> %@\n", outputData);
                        NSLog(@"PARSE ERROR ------------->>>>> : %@\n", error);
                    


                    //NSLog(@"TYPEN ----------------------------------------------> %@", type);

                    if([type isEqualToString:@"message"]) 
                        //NSLog(@"New chat message: %@", output);

                        [self messageReceived:outputData];

                     else if([type isEqualToString:@"offlineMessages"]) 
                        NSLog(@"New offline messages: %@", outputData);
                        NSLog(@"NEW OFFLINE MESSAGES!!");
                        [self offlineMessagesReceived:outputData];

                    

                    // Check for another newline character:
                    nlRange =[collectedData rangeOfData:nl options:0 range:NSMakeRange(0, [collectedData length])];
                
            
            break;


        case NSStreamEventErrorOccurred:

            [self closeNetworkCommunication];
            isConnected = 0;

            NSLog(@"STREAM ERROR");
            //theStream = nil;

            break;

        case NSStreamEventEndEncountered:

            [self closeNetworkCommunication];
            isConnected = 0;

            NSLog(@"STREAM END");
            //theStream = nil;

            break;
    

这是服务器发送应用程序的示例字符串:

"id":"1", "type":"offlineMessages", "msg": "\"agentsArray\":[\"id\":281102,\"msgFrom\":\"V281570150514504\",\"msgDate\":\"2014-04-10T11:09:49.000Z\" ,\"msgBody\":\"Pellentesque 居民 morbi tristique senectus et netus et malesuada 名声 ac turpis egestas。 Donec odio Tellus, dictum eu congue id, malesuada non 风险。 Mauris dapibus velit massa,非 laoreet lectus lacinia nec。 Morbi sagittis molestie eros,nec blandit sem accumsan eget。阿里康 eu sem egestas,malesuada urna sat amet,gravida velit。库拉比图尔 拍卖师坐在 amet turpis vitae feugiat。 Nam id velit viverra eros blandit consectetur vel eu 侵权。 Nullam at augue eros。普雷森 dolor libero, venenatis in adipiscing vitae, dignissim nec nisi。在 lobortis sem 一个 neque ultrices,一个前庭 urna ullamcorper。 Pellentesque eu suscipit est, quis dignissim orci。埃涅斯调味品 简历dolor ac cursus。 Aenean eu pulvinar nunc, et mollis erat。 前庭 commodo malesuada nunc et iaculis。在 mattis cursus mi 怀孕简历。 Etiam et iaculis Tellus, 非 iaculis nulla.\",\"channelID\":\"V281570150514504\",\"recipient\":\"test@email.com\"]", “名称”:“281”,“时间”:“12:09”,“频道”:“V281570150514504”\n

有时应用会像这样解析消息:

auctor sat amet turpis vitae feugiat。 Nam id velit viverra eros blandit consectetur vel eu 侵权。 Nullam at augue eros。普雷森 dolor libero, venenatis in adipiscing vitae, dignissim nec nisi。在 lobortis sem 一个 neque ultrices,一个前庭 urna ullamcorper。 Pellentesque eu suscipit est, quis dignissim orci。埃涅斯调味品 简历dolor ac cursus。 Aenean eu pulvinar nunc, et mollis erat。 前庭 commodo malesuada nunc et iaculis。在 mattis cursus mi 怀孕简历。 Etiam et iaculis Tellus, 非 iaculis nulla.\",\"channelID\":\"V281570150514504\",\"recipient\":\"test@email.com\"]", “名称”:“281”,“时间”:“12:09”,“频道”:“V281570150514504”\n

我应该补充一点,这种情况并非一直发生,它的时间大约减少了 50%。

任何想法我做错了什么?

【问题讨论】:

尝试追加数据,直到收到消息的结尾,然后才尝试解析它。 @Jenox 我将如何做到这一点? 你到底想用换行符来完成什么? 我使用换行符分隔消息 你可以试试JSONObjectWithStream:options:error:。不过,我自己从未测试过输入是多个 JSON 文档的情况。 【参考方案1】:

听起来您可能遇到了有关 TCP 数据包大小的问题。因此,当消息很大时,它会被拆分而不是一次全部接收。

从外观上看,在尝试处理 JSON 之前,您需要内置检查以确保您拥有预期的所有字节。

这是某种“类似”的 Apple 文档,https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Streams/Articles/ReadingInputStreams.html#//apple_ref/doc/uid/20002273-BCIJHAGD。

你会看到它可以处理多次运行 handleEvent 并在执行过程中将数据附加到缓冲区中。

希望对您有所帮助。

【讨论】:

【参考方案2】:

使用以下方法从服务器获取 JSON 数据

 NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithURL:myUrl completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) 

    NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
    NSLog(@"%@", json);
];
[dataTask resume];

【讨论】:

不太确定我是否遵循,我应该在我的代码中替换什么? =)

以上是关于iOS 解析大型 JSON 消息时遇到问题的主要内容,如果未能解决你的问题,请参考以下文章

解析大型 M3U 文件时遇到问题

解析 API 响应时遇到意外字符

iOS 下载和解析大型 JSON 响应导致 CFData(存储)泄漏

iOS开发过程中,遇到解析的json数据为<null>,进行赋值时会导致崩溃,使用AFNetworking可以这样解决。

iOS 高效地从 Documents Dir 中解析大型 JSON

JSON解析iOS