我需要下载并解析 40mb 的 json。现在我正在使用 AFJSONRequestOperation,它在旧设备上会导致内存警告和崩溃。应该怎么做?我认为正确执行此操作的唯一方法是流式传输 json,但我不知道如何执行此操作或哪个库最好。请提供例子。非常感谢!
问问题
2041 次
2 回答
4
对于任何有同样问题的人,我是这样解决的: 1. 使用 AFHTTPRequestOperation 的输出流将 JSON 文件下载到本地存储。2. 使用 YAJLParser 解析小块 NSData。
结果:我在 iPad (1) 上用 50mb json 测试它,没有任何内存警告(内存大约 10mb)。
例子:
NSError *error = nil;
NSData *data = [NSData dataWithContentsOfFile:path
options:NSDataReadingMappedAlways | NSDataReadingUncached
error:&error];
YAJLParser *parser = [[YAJLParser alloc] initWithParserOptions:YAJLParserOptionsAllowComments];
parser.delegate = self;
[parser parse:data];
parser.delegate = nil;
parser = nil;
YAJLParser 代表:
// first declare in header file NSMutableArray *stack and NSString *mapKey
- (void)parserDidStartDictionary:(YAJLParser *)parser
{
NSString *dictName = mapKey;
if (mapKey == nil)
{
dictName = (stack.count == 0) ? @"" : [stack lastObject];
}
[stack addObject:(dictName)];
}
- (void)parserDidEndDictionary:(YAJLParser *)parser
{
mapKey = nil;
[stack removeLastObject];
}
- (void)parserDidStartArray:(YAJLParser *)parser
{
NSString *arrayName = mapKey;
if (mapKey == nil)
{
arrayName = stack.count == 0 ? @"" : [stack lastObject];
}
[stack addObject:(arrayName)];
if([mapKey isEqualToString:@"something"])
{
// do something
}
}
- (void)parserDidEndArray:(YAJLParser *)parser
{
if([mapKey isEqualToString:@"some1"])
{
// do something
}
mapKey = nil;
[stack removeLastObject];
}
- (void)parser:(YAJLParser *)parser didMapKey:(NSString *)key
{
mapKey = key;
}
- (void)parser:(YAJLParser *)parser didAdd:(id)value
{
if([mapKey isEqualToString:@"id"])
{
// do something
}
}
于 2013-09-23T13:37:31.557 回答
2
将数据写入文件,然后使用 NSData 的 dataWithContentsOfFile:options:error: 并指定 NSDataReadingMappedAlways 和 NSDataReadingUncached 标志。这将告诉系统使用 mmap() 来减少内存占用,而不是用内存块给文件系统缓存增加负担(这会使其速度变慢,但对 iOS 的负担要小得多)。
你可以在这里找到答案 iPad - Parsing an extra huge json - File ( between 50 and 100 mb)
于 2013-09-23T07:50:05.680 回答