1

I'm on XCode 8.2, Objective-C, OSX (not iOS), ARC enabled.

I'm importing a large CSV file in a custom NSBlockOperation with DaveDelongs CHCSV parser. My problem: The memory is not freed after the operation is done. Even if i do NOT save the parsed NSArray* the same happens.

Here is the essential part of the code:

SHImportDataOperation.m (custom NSBlockOperation)

// CHCSV parser delegate
@interface Delegate : NSObject <CHCSVParserDelegate>

    @property (readonly) NSArray *lines; // <-- parsing result is stored here
    @property (readonly) NSString *errorMessage;
    @property unsigned long long filesize;
    @property SHGlobalAppData* global;

@end

@implementation SHImportDataOperation
    @synthesize finished  = _finished;
    @synthesize executing = _executing;

- (void)main
{
    // ###############################
    // UI stuff
    dispatch_async(dispatch_get_main_queue(), ^{

        // Hide controls
        [_global.dataFile setFileDropped:NO]; // _global.dataFile is an NSObject with relevant fileInformation
    });

    // ###############################
    // Import CSV
        if (![self importCSV:_global.dataFile]) 
        {                
            [self breakImportData]; // Cleanup
            return;
        }
    }

    // ###############################
    // Finishing Import Data

    // UI stuff
    dispatch_async(dispatch_get_main_queue(), ^{

        // Show controls
        [_global.dataFile setFileDropped:YES];

        // Show OK
        [_global.dataFile setImported:YES];

        // Cleanup
        [self finishOperation];
    });
}

// ################################################
// cleanup
- (void)finishOperation
{
    [self willChangeValueForKey:@"isFinished"];
    [self willChangeValueForKey:@"isExecuting"];
    _executing = NO;
    _finished = YES;
    [self didChangeValueForKey:@"isExecuting"];
    [self didChangeValueForKey:@"isFinished"];
}

// ################################################
- (BOOL)importCSV:(SHDataModelData *)dataFile
{
    encoding = NSMacOSRomanStringEncoding;        
    NSString* delimiter = @",";
    unichar delimiterUnichar = [delimiter characterAtIndex:0];


    // ###############################
    NSInputStream* stream = [NSInputStream inputStreamWithFileAtPath:dataFile.filePath];
    CHCSVParser* p = [[CHCSVParser alloc] initWithInputStream:stream usedEncoding:&encoding delimiter:delimiterUnichar];

    Delegate * d = [[Delegate alloc] init];
    [d setGlobal:_global]; // Reference needed for UI progress bar

    [p setDelegate:d];
    [p setFilepath:dataFile.filePath];      
    [p parse];

    //NSLog(@"Result: %@",d.lines);

    // Save imported data
    //[dataFile setImportData:d.lines]; // Even if not saved, memory is not free'd after operation

    // Even if i nil everything, memory is not freed.
    [d setGlobal:nil];
    [p setDelegate:nil];
    d = nil;
    p = nil;

    return true;
}

And this is how the operation is started:

NSOperationQueue* operationImportQueue = [NSOperationQueue new];

SHImportLayoutOperation *importLayoutOperation = [[SHImportLayoutOperation alloc] init];
[importLayoutOperation setGlobal:[self theAppDataObject]];

SHImportDataOperation *importDataOperation = [[SHImportDataOperation alloc] init];
[importDataOperation setGlobal:[self theAppDataObject]];

NSBlockOperation *importDoneCompletionOperation = [NSBlockOperation blockOperationWithBlock:^{
    [self continueWithStuff];                
    }];

[importDoneCompletionOperation addDependency:importDataOperation];
[importDoneCompletionOperation addDependency:importLayoutOperation];

[operationImportQueue addOperation:importDoneCompletionOperation];
[operationImportQueue addOperation:importDataOperation];
[operationImportQueue addOperation:importLayoutOperation];

Edit 1:

After further testing i can confirm the NSBlockOperation is successfully performed and removed from memory.

Pat_Morita
  • 3,355
  • 3
  • 25
  • 36

0 Answers0