user1467267
user1467267

Reputation:

Big image download loop keeps leaking inside GCD queue

I'm downloading over 6000 high resolution (about 2.6GB), but can change depending on which customer logs in into our app. Because the sales agents need all the product images to be loaded when they are outside the country they need all to be available in offline-mode.

My code is pretty much ad-hoc and the problem of my code leaking is probably very obvious to the more experienced Objective-C programmers.

At the moment the status is that the code has downloaded 2041 of the 6253 and 580 seconds have passed. Yet the emulator's memory is already at 931MB.

Could I do anything to improve this code to get the memory back after each loop or X-amount of loop cycles?

int total_new_images = total_images_in_db - total_images_locally;

// Fetch the real pictures now
dispatch_queue_t imageQueue = dispatch_queue_create("Image Queue", DISPATCH_QUEUE_CONCURRENT);

dispatch_async(imageQueue, ^{
    NSString *path = [NSString new];
    NSURL *url = [NSURL new];
    NSData *data = [NSData new];
    NSString *savePath = [NSString new];
    NSArray *imgUrlArray = [NSArray new];

    NSDate *starTime = [NSDate new];

    @autoreleasepool {
        int c = 0;

        FMResultSet *rs = [self.efashionDB executeQuery:@"SELECT * FROM app_images"];

        while ([rs next]) {
            imgUrlArray = [[rs stringForColumn:@"full_url"] componentsSeparatedByString:@"/"];

            savePath = [NSString stringWithFormat:@"%@/%@", imgFolder, [imgUrlArray objectAtIndex:[imgUrlArray count]-1]];

            if ([self.fileMgr fileExistsAtPath:savePath]) {
                //NSLog(@"'%@' is already saved locally.", [imgUrlArray objectAtIndex:[imgUrlArray count]-1]);
                continue;
            }

            path = [NSString stringWithString:[rs stringForColumn:@"full_url"]];
            url = [NSURL URLWithString:path];
            data = [NSData dataWithContentsOfURL:url];

            if (![data writeToFile:savePath atomically:YES]) {
                NSLog(@"Saving of \"%@\" failed!", [imgUrlArray objectAtIndex:[imgUrlArray count]-1]);
            } else {
                //NSLog(@"Saving of \"%@\" succeeded!", [imgUrlArray objectAtIndex:[imgUrlArray count]-1]);

                // Escape back to the main thread and give status update
                dispatch_async(dispatch_get_main_queue(), ^{
                    NSString *progress = [[NSString alloc] initWithFormat:@"%d of the %d new images downloaded\nTime passed: %d seconds", c, total_new_images, (int)([starTime timeIntervalSinceNow] * -1)];
                    [_imageConsole setText:progress];
                });

                c++; // Only increment if it succeeded
            }

            if (c == 20) {
                //break;
            }
        }
        [rs close];
    }
});

Upvotes: 0

Views: 56

Answers (1)

iljawascoding
iljawascoding

Reputation: 1110

Try moving the @autoreleasepool inside the while loop. Otherwise your allocated objects won't be released until the while loop has finished.

Upvotes: 2

Related Questions