0
votes

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;

}
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
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
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

1 Answers

1
votes

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.