Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 正在解码一个巨大的NSString,内存不足_Ios_Xml_Memory Management_Base64_Nsdata - Fatal编程技术网

Ios 正在解码一个巨大的NSString,内存不足

Ios 正在解码一个巨大的NSString,内存不足,ios,xml,memory-management,base64,nsdata,Ios,Xml,Memory Management,Base64,Nsdata,我正在寻找如何改进使用base64编码解码40+MB NSString并将其保存到文件中的过程的想法,同时能够将该过程放入iPad1的256MB内存中 我从NSXMLParser获取NSString: id pointerToString; - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{ if ([currentElement isEqualToString:@"myElement"])

我正在寻找如何改进使用base64编码解码40+MB NSString并将其保存到文件中的过程的想法,同时能够将该过程放入iPad1的256MB内存中

我从NSXMLParser获取NSString:

id pointerToString;

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if ([currentElement isEqualToString:@"myElement"]) 
    {
    pointerToString = [string retain];
}
}
然后我在回调中使用pointerToString:

[handler performSelector: action withObject: pointerToString];
在回调函数中(id值是指针列表)。我使用pointerToString初始化NSData,同时使用base64编码对其进行解码

^(id value)
{
    if ( [[value class] isSubclassOfClass:[NSString class]] ) 
    {
    NSData *data = [NSData dataFromBase64String:value];
    [data writeToFile:file.path atomically:YES];
}
}
iPad1设备内存不足,在NSData呼叫后或期间内存分配达到130MB左右时,会被iOS杀死

我已经确定,为了以这种方式处理40+MB的NSString,我需要大约180+MB的RAM(这是iPad2和iPad3上的最大内存分配,因为内存更多,所以这个过程有效)

有什么想法/建议吗

谢谢你的方法

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
可能不会同时接收所有数据。 医生说

“由解析器对象发送,以向其委托提供表示当前元素的全部或部分字符的字符串。”

所以它被称为多次。 看起来您正在尝试一次写入整个字符串(如果我错了,很抱歉)。 因此,您可以通过执行以下操作将接收到的数据附加到文件中:

您可以使用以下选项的组合:

-writeData: 

用于将NSData写入文件末尾的NSFileHandle类中的方法

但在部分数据接收时请小心使用base64编码

编辑

在处理这种大小的文件时,您可能不希望一次在内存中加载整个数兆字节的文件,无论是巨大的输入文件还是几乎同样巨大的输出文件。您应该以流式方式对此进行解析,在执行过程中对
foundCharacters
中的数据进行解码,而不是在内存中保留任何重要部分

但是,传统技术可能会在流程的三个阶段保存整个XML文件内存:

  • 从服务器下载XML文件时

  • 当XML解析器解析该文件时;及

  • 在执行文件的Base64解码时

  • 诀窍是对单个大型XML文件的小块使用流技术,即同时执行这三个过程。总之,在下载整个50mb文件时,抓取几kb,解析XML,如果要解析Base64编码字段,则对这几kb执行Base64解码,然后继续下一个数据块

    有关这方面的示例(至少是流式XML下载和解析,不包括Base64解码),请参阅Apple的。您将看到它将演示两个XML解析器,我们都熟悉的
    NSXMLParser
    ,以及不太熟悉的
    LibXML
    解析器。
    NSXMLParser
    的问题是,在开始解析之前,它会将整个XML文件加载到内存中,即使您使用
    initWithContentsOfURL

    在我之前的回答中,我错误地宣称,通过使用
    initWithContentsOfURL
    NSXMLParser
    可以在下载URL内容时将其解析为漂亮的小数据包。
    NSXMLParserDelegate
    协议的
    foundCharacters
    方法似乎与
    NSURLConnectionDelegate
    方法
    didReceiveData
    非常相似,我确信
    NSXMLParser
    将像
    NSURLConnection
    一样处理流,即在下载过程中返回信息。可悲的是,事实并非如此

    不过,通过使用
    LibXML
    ,就像Apple XMLPerformance示例项目一样,您实际上可以使用流媒体的
    NSURLConnection
    功能,从而动态解析XML

    我已经创建了一点,但我可能建议您详细了解一下Apple的XMLPerformance示例项目。但在我的实验中,一个56mb的XML文件在通过
    NSXMLParser
    解析和转换时消耗的内存远远超过100mb,但在使用
    LibXML2
    时仅消耗2mb


    在您的评论中,您描述了将Base64编码的数据下载到文件中,然后对其进行解码的愿望。这种方法似乎效率要低得多,但肯定能奏效。顺便说一句,在最初的下载中,您有相同的内存问题(我在上面解决了)。我敦促您确保Base64编码数据的初始下载不会像大多数例程一样轻松地加载到RAM中。假设您使用的是
    NSURLConnection
    ,您希望在
    didReceiveData
    中接收数据时,将数据写入
    NSOutputStream
    ,而不是将其保存在RAM中


    请参阅苹果公司AdvancedGetController.m中的
    didReceiveResponse
    ,了解如何在接收文件时编写文件,而不是将其添加到
    NSMutableData
    中的典型模式(因为这些例程中的大多数都假设您正在处理大小合理的文件)。(忽略AdvancedURLConnections示例中有关身份验证等的所有内容,但重点了解它是如何写入
    NSOutputStream
    的。)此技术将解决此答案顶部列出的三个问题中的第一个问题,而不是后两个问题。为此,您必须考虑使用苹果的XMLPerformance示例项目中说明的
    LibXML2
    ,或其他类似技术。

    我不知道,但这是一个很好的问题。但是,我想知道为什么您有这么大的NSString?修改base64编码,以便在您从解析器接收字符时将其解码到文件中。关键字:“流”(整个过程中,还包括删除
    NSData
    的全部内存使用)看起来您实际上正在尝试解码base64字符串。您通常有大约140mb的RAM fre
    -seekToEndOfFile