0

我正在从事 ARC 自动转换的项目。

我有一个巨大的文本文件(14MB)的内容存储在一个NSString *_documentDataString.

现在我有这个循环:

- (void)scanParts
{
    NSString *boundary = [boundaryPrefix stringByAppendingString:_header.boundary];

    NSMutableArray *parts = [NSMutableArray array];

    NSInteger currentLocation = [_documentDataString rangeOfString:boundary].location;

    BOOL reachedTheEnd = NO;
    while(!reachedTheEnd)
    {
        NSInteger nextBoundaryLocation = [[_documentDataString substringFromIndex:currentLocation + 1]
                                          rangeOfString:boundary].location;

        if(nextBoundaryLocation == NSNotFound)
        {
            reachedTheEnd = YES;
        }
        else
        {
            nextBoundaryLocation += currentLocation + 1;

            //[parts addObject:[_documentDataString substringWithRange:
              //                NSMakeRange(currentLocation, nextBoundaryLocation - currentLocation)]];

            currentLocation = nextBoundaryLocation;
        }
    }
}

但是,我开始收到这些错误:

 malloc: *** mmap(size=6496256) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug

出了什么问题?

运行此循环时,我什至开始收到此错误:

while(true)
{
    NSInteger nextBoundaryLocation = [[_documentDataString substringFromIndex:currentLocation + 1]
                                          rangeOfString:boundary].location;
}
4

3 回答 3

5

substringFromIndex:在_

NSInteger nextBoundaryLocation = [[_documentDataString substringFromIndex:currentLocation + 1]
                                      rangeOfString:boundary].location;

创建一个(临时的,自动释放的)子字符串,仅在当前自动释放池被销毁时(例如,当程序控制返回到主事件循环时)才被释放。

您可以将该代码替换为

NSInteger nextBoundaryLocation = [_documentDataString rangeOfString:boundary
             options:0
               range:NSMakeRange(currentLocation + 1, [_documentDataString length] - (currentLocation + 1))].location;

(希望)避免创建临时字符串。请注意,nextBoundaryLocation然后相对于字符串的开头,因此

nextBoundaryLocation += currentLocation + 1;

不再需要了。

或者,您可以简单地将整个循环替换为

NSArray *parts = [_documentDataString componentsSeparatedByString:boundary];
于 2013-05-22T13:40:52.743 回答
0

你也可以NSInputStream,它会减少你的内存使用量。iOS 设备上的 14MB 已经很多了。

于 2013-05-22T13:50:02.670 回答
0

看起来文档太大而无法像通常使用(合理的)常规大小的字符串那样操作它,这是您在字符串对象的内存分配过程中遇到错误的原因。

对于您的特定情况,您可能需要使用NSInputStream, 基本上可以逐字节读取文件的数据,而不是一次全部读取。

看看以下问题Objective-C:Reading a file line by line

简而言之,根据文档,您需要执行以下操作:

首先打开文件

- (void)setUpStreamForFile:(NSString *)path {
    // iStream is NSInputStream instance variable
    iStream = [[NSInputStream alloc] initWithFileAtPath:path];
    [iStream setDelegate:self];
    [iStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
        forMode:NSDefaultRunLoopMode];
    [iStream open];
}

编写代码以处理当流中有更多可用字节时要做什么(虽然它不是文件的结尾)

- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {

    switch(eventCode) {
        case NSStreamEventHasBytesAvailable:
        {
            if(!_data) {
                _data = [[NSMutableData data] retain];
            }
            uint8_t buf[1024];
            unsigned int len = 0;
            len = [(NSInputStream *)stream read:buf maxLength:1024];
            if(len) {
                [_data appendBytes:(const void *)buf length:len];
                // bytesRead is an instance variable of type NSNumber.
                [bytesRead setIntValue:[bytesRead intValue]+len];
            } else {
                NSLog(@"no buffer!");
            }
            break;
        }
于 2013-05-22T13:45:54.307 回答