Search code examples
iosobjective-cgrand-central-dispatchnsdata

Prevent loop from looping until inner loop writes to disk


I have a nested for loop in where I call a getSnapShotData method many times and write this data to disk. I've noticed I get too much memory build up doing this and I run out of memory, so I thought this would be a good use case for using dispatch semaphore.

I'm still running out of memory, so I'm not sure if I'm using the semaphore properly. Essentially I want the next loop to wait until the prior loop's data is written to disk, as I think that will free the memory. But I could be wrong. Thank you for your help.

Code:

dispatch_semaphore_t sema = dispatch_semaphore_create(0);

for (NSDictionary *sub in self.array)
{
    NSArray *lastArray = [sub objectForKey:@"LastArray"];

    for (NSDictionary *dict in lastArray)
    {
        currentIndex ++;

        NSData *frame = [NSData dataWithData:[self getSnapshotData]];

        savePath = [NSString stringWithFormat:@"%@/%lu.png",frameSourcePath,(unsigned long)currentIndex];

        BOOL nextLoop = [frame writeToFile:savePath options:0 error:nil];

        frame = nil;

        if (nextLoop)
        {
            dispatch_semaphore_signal(sema);
        }

        dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
    }
}

- (NSData *)getSnapshotData
{
    UIGraphicsBeginImageContextWithOptions(self.containerView.bounds.size, NO, 0.0);
    [self.containerView.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *snapShot = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return [NSData dataWithData:UIImagePNGRepresentation(snapShot)];
}

Solution

  • You have too many autoreleased objects. Add an autorelease pool to improve the situation instead of using the semaphore.

    for (NSDictionary *sub in self.array)
    {
        NSArray *lastArray = [sub objectForKey:@"LastArray"];
    
        for (NSDictionary *dict in lastArray)
        {
            @autoreleasepool {
                currentIndex ++;
    
                NSData *frame = [NSData dataWithData:[self getSnapshotData]];
    
                savePath = [NSString stringWithFormat:@"%@/%lu.png",frameSourcePath,(unsigned long)currentIndex];
    
                BOOL nextLoop = [frame writeToFile:savePath options:0 error:nil];
            }
        }
    }