0

I realize this question has been asked before but I didn't find any answers that actually resolved it, so...asking again.

I'm using ARC. My app takes photos from an AVCaptureSession at periodic intervals and saves them to core data. I get the NSData object by calling UIImagePNGRepresentation(). As this is happening, memory steadily climbs and the app eventually quits due to memory pressure...but there are no leaks. Instruments shows that for each photo, 500k is being malloced and it never gets released.

The answer I keep coming across is to wrap UIImagePNGRepresentation, or indeed the whole method body, in an autoreleasepool, but this did not help.

I am reasonably certain that the UIImagePNGRepresentation call is the culprit, because when I comment it out, no more memory problems (or images to save).

Would appreciate any help here...is there another way to grab NSData from a UIImage? Is this just another SDK bug we have to live with?

-(void)photoTimerFired:(NSTimer*)timer
{

...

ManagedDataPoint *lastPoint = [_currentSession.dataPoints lastObject];

_lastImage = [_imageCapturer singleImage];


Photo *newPhoto = [NSEntityDescription insertNewObjectForEntityForName:@"Photo"
inManagedObjectContext:self.managedObjectContext];

// Line below is the culprit.
newPhoto.photoData = UIImagePNGRepresentation(_lastImage);
newPhoto.managedDataPoint = lastPoint;

}
Reid
  • 1,109
  • 1
  • 12
  • 27
  • 1
    Note - Core Data is not great for storing binary data like this. You should write the NSData to a file and store a reference (by filename) in the managed object. It isn't clear what you do with the managed object - do you [self.managedObjectContext save:&error] at some point? – Adam Eberbach Mar 20 '14 at 00:16
  • 1
    What happens if you use `[NSManagedContext -refreshObject:newPhoto mergeChanges:NO]` to turn your object back into a fault after you've saved? Are you sure it's not that the Core Data objects are keeping the data alive? – Tommy Mar 20 '14 at 00:18
  • Thanks to you both. I think I had read before that it wasn't ideal to store BLOBs directly in Core Data (but was seeing if I could get away with it--looks as though I can't). I will try what you suggested. – Reid Mar 20 '14 at 01:41

1 Answers1

1

I think this page of the CoreData Programming Guide is worth reading in your case, talking to things you need to take care to minimize overheads when using BLOBs (binary data) like images in CoreData.

Especially the part when they talk about creating a dedicated entity to only hold your binary attribute / image, separating it from other attributes of your primary entity and allowing it to "fault", so that it will only be loaded from the database into memory when the attribute is actually referenced/used.


Another thing to try is to check the "Use External Storage" checkbox on the binary attribute of your entity that holds the image. This way in practice the image won't actually be saved as a BLOB directly in your sqlite database, but will be saved in an external file instead, the attribute holding only a reference (path) to this external file, limiting the growth of your database (and corruption risks as the base grows in size). (Hopefully it will also reduce your memory footprint by avoiding to keep the image in memory when the NSManagedObject is around and not faulting...?)

Note: all of this "External Storage" stuff is working totally transparently for you as for the usage of this attribute in your code: you still access it as if the attribute directly contained the binary data.

AliSoftware
  • 32,623
  • 6
  • 82
  • 77
  • Thanks, I'll try this when I get in tomorrow! Will of course accept if it works out. – Reid Mar 20 '14 at 01:39
  • Thanks for the helpful answer! You pointed me in the right direction. Since my BLOBs are fairly large, what I ended up doing was (as Adam suggested) saving the data itself to disk, and saving the file path in my data model. This works beautifully...no memory issues whatsoever. – Reid Mar 20 '14 at 17:37
  • As explained in my answer, what you are doing manually (saving the file in an external file on disk and saving only the path in the datamodel) is actually quite what the "External Storage" option/checkbox does automatically for you transparently... did you try to activate that option on your attribute first? That would greatly simplify your code then, as CoreData does all the work for you. See also http://stackoverflow.com/questions/7924840/storing-uiimage-in-core-data-with-the-new-external-storage-flag – AliSoftware Mar 20 '14 at 22:20