0

I'm trying to download and save some images (converted from a base64 string to UIImage) to the device and keep getting a Memory warning.

ontracFullScreenImageViewController *etrackDiagrams = ((ontracFullScreenImageViewController*)[viewControllerDictionary objectForKey:@"E-track Diagrams"]);
    NSMutableSet *etrackSet = [[NSMutableSet alloc] init];

    for (UIImage *image in etrackDiagrams.imageArray) {


        NSAutoreleasePool *localPool = [[NSAutoreleasePool alloc] init];
        //convert the image to NSData and store it in the documents directory
        NSData *pngData = UIImagePNGRepresentation(image);
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documentsPath = [paths objectAtIndex:0]; //Get the docs directory
        NSString * timeInMS = [NSString stringWithFormat:@"%lld", [@(floor([[NSDate date] timeIntervalSince1970] * 1000)) longLongValue]];
        NSString *filePath = [documentsPath stringByAppendingPathComponent:[ NSString stringWithFormat:@"%@_%@_etrack_diagram_%i_%i_image.png", delegate.userName, timeInMS, self.dataObject.dataPack.pack_id, [etrackDiagrams.imageViewArray indexOfObject:image]]]; //Add the file name
        [pngData writeToFile:filePath atomically:YES];
        NSLog(@"filepath %@", filePath);
        NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
        if ([currSysVer isEqualToString:@"5.0.1"]) {
            [[NSURL URLWithString:filePath] setResourceValue: [NSNumber numberWithBool: YES] forKey: NSURLIsExcludedFromBackupKey error: &error];
        }
        //Add the file Path to ImageLinks
        [etrackDiagrams.imageLinks addObject:filePath];
        //save the image location in Core Data
        EtrackDiagram *etrackDiagram = [NSEntityDescription
                                        insertNewObjectForEntityForName:@"EtrackDiagram"
                                        inManagedObjectContext:context];
        etrackDiagram.locationString = filePath;
        etrackDiagram.dataObject = dataObject;
        [etrackSet addObject:etrackDiagram];
        [dataObject addEtrackDiagramsObject:etrackDiagram];
        [localPool drain];

    }
    [dataObject addEtrackDiagrams: etrackSet];

The memory warning occurs at NSData *pngData = UIImagePNGRepresentation(image); as the images are quite large.

Unfortunately I can't control the size of the images but need a way to save them to the device to use them in a gallery later on.

I have tried to wrap the code with @autoreleasepool but it made no difference.

jampez77
  • 5,012
  • 7
  • 32
  • 52

3 Answers3

1

The real problem is this line:

for (UIImage *image in etrackDiagrams.imageArray) {

This implies you are holding an array of images in memory. That is always dangerous. You need to have saved all these images on disk and load them into memory one at a time (and in a noncaching way). Your goal should be to have at most one image in memory at a time.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • You have a good point here. What i've done now is tried to save the image as it is retrieved from the URL (individually). Still no joy though :/ – jampez77 Oct 11 '16 at 13:24
  • if the image is saved to disk as it is retrieved, why do you need to convert it to Png data again? It is data. It is saved. It has a path. Done. – matt Oct 11 '16 at 13:29
  • It's a base64 string that i convert to png so it can be used in a gallery. – jampez77 Oct 11 '16 at 13:30
  • No, I don't follow. You are not displaying any gallery _now_. The data you downloaded is the image data. Saying "base64" doesn't add anything to the story, does it? That just means you downloaded it, and we already know that. – matt Oct 11 '16 at 13:37
  • Let me put it another way. The line `for (UIImage *image in etrackDiagrams.imageArray)` proves that you can derive UIImage objects from the downloaded data. But then you can derive UIImage objects from the downloaded data after that data has been saved to disk. You do not need to perform some intermediate transformation to PNG to resave this data. It is ready to rock-and-roll already. – matt Oct 11 '16 at 14:12
  • Also, having saved the downloaded image to disk, if you really _did_ need to recast it as a PNG, you could do that direct from disk to disk, without any memory stress, by using the ImageIO framework. – matt Oct 12 '16 at 01:51
0

here is the code to prove matt's theory was wrong.

for(NSInteger i =0; i < etrackDiagrams.imageArray.count; i ++) {
   UIImage *image = etrackDiagrams.imageArray[i];
   // here is your code to save image in device.
}

if "for(uiimage *image in imagearray)" holding an array of images in memory, then the code above will fix the problem, but in fact, it's basically without any help.

The memory warning occurs at NSData *pngData = UIImagePNGRepresentation(image); as the images are quite large. I think this message is very important!!!

here is someone had the same problem.click here

Community
  • 1
  • 1
Mistrx丶
  • 267
  • 3
  • 10
0

Maybe you can change a mind:

  1. when you download the base64 string, convert it into nsdata, then add to your array;
  2. when you want to save the imagedata, select the nsdata in your array.

unless you want show the image on some views, you don't need to pay attention to the memory warning occurs.

Mistrx丶
  • 267
  • 3
  • 10