I have a CoreDataHelper static class that consists of 2 static methods. I ran my project through Clang and didn't find any leaks, however running through Instruments shows a leak that looks like it's related to CoreData. I have basic knowledge of memory management in objective-c and I believe I'm following the rules. However, I also think it's more likely there's something wrong with my code rather than a bug in Apple's CoreData stack. I'm running on the latest, Snow Leopard, iPhone SDK 3.1, XCode 3.2.
stack trace:
17 UIKit 528 Bytes -[UIApplication _run]
16 UIKit 64 Bytes -[UIApplication sendEvent:]
15 UIKit 64 Bytes -[UIApplication handleEvent:withNewEvent:]
14 UIKit 64 Bytes -[UIApplication _runWithURL:sourceBundleID:]
13 UIKit 16 Bytes -[UIApplication _performInitializationWithURL:sourceBundleID:]
12 helm 16 Bytes -[helmAppDelegate applicationDidFinishLaunching:] Classes/helmAppDelegate.m:113
11 helm 16 Bytes +[CoreDataHelper entityWithUIDexists:::] Classes/CoreDataHelper.m:50
10 helm 16 Bytes +[CoreDataHelper searchObjectsInContextCopy:::::] Classes/CoreDataHelper.m:39
9 CoreData 16 Bytes -[NSManagedObjectContext executeFetchRequest:error:]
8 CoreData 16 Bytes -[NSPersistentStoreCoordinator(_NSInternalMethods) executeRequest:withContext:]
7 CoreData 16 Bytes -[NSSQLCore executeRequest:withContext:]
6 CoreData 16 Bytes -[NSSQLiteConnection connect]
5 CoreData 16 Bytes -[NSSQLConnection createSchema]
4 CoreData 16 Bytes -[NSSQLConnection createTablesForEntities:]
3 CoreData 16 Bytes -[NSSQLConnection createTableForEntity:]
2 CoreData 16 Bytes -[NSSQLAdapter newCreateTableStatementForEntity:]
1 Foundation 16 Bytes -[NSCFString appendFormat:]
0 CoreFoundation 16 Bytes -[NSObject respondsToSelector:]
appdelegate:
BOOL b=[CoreDataHelper entityWithUIDexists:#"AddressBook" :context :[NSNumber numberWithInt:1]];
CoreDataHelper:
+(NSMutableArray *) searchObjectsInContextCopy: (NSString*) entityName : (NSManagedObjectContext *) managedObjectContext : (NSPredicate *) predicate : (NSString*) sortKey : (BOOL) sortAscending
{
NSLog(#"searchObjectsInContext");
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
// If a predicate was passed, pass it to the query
if(predicate != nil)
{
[request setPredicate:predicate];
}
// If a sort key was passed, use it for sorting.
if(sortKey != nil)
{
//NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:sortKey ascending:sortAscending selector: #selector(caseInsensitiveCompare:)];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:sortKey ascending:sortAscending selector: #selector(caseInsensitiveCompare:)];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptors release];
[sortDescriptor release];
}
NSError *error;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
[request release];
return mutableFetchResults;
}
+(BOOL) entityWithUIDexists: (NSString *) entityName : (NSManagedObjectContext *) managedObjectContext : (NSNumber *) uid {
BOOL b;
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(uid == %#)", uid];
NSMutableArray *ary=[self searchObjectsInContextCopy: entityName : managedObjectContext : predicate : nil : YES];
if(ary==nil) {
b=NO;
} else {
b=[ary count] >0 ? YES :NO;
}
[ary release];
return b;
}
Looking at your source code, I noticed two things. First, it is wrong to initialize a fetch request without sort descriptors. Quoting from the SDK 3.1 release notes:
"NSFetchedResultsController no longer crashes when fetch request has no sort descriptors. It’s still invalid to initialize an NSFetchedResultsController without sort descriptors, but a proper exception is now raised"
Therefore, you should always initialize your NSFetchedResultsController with sort descriptors.
The second thing is related to your leak. The executeFetchRequest: method return an autoreleased NSArray. You are using the mutableCopy method and you therefore are returning an object which has been retained by mutableCopy. That basically means that you are responsible for releasing the returned object. Again, quoting the mutableCopy method documentation:
"If you are using managed memory (not garbage collection), this method retains the new object before returning it. The invoker of the method, however, is responsible for releasing the returned object."
Ok, I found out something interesting. The nil sort descriptor wasn't causing the leak, it was still there but maybe I was stopping the leak detector too early. Here is the method with the leak. When I comment out the pragma mark, the 16 byte leak doesn't show in Instruments. Why would having a pragma mark in the method cause a 16 byte leak?
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator != nil) {
return persistentStoreCoordinator;
}
NSString *databaseFilePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent: #"Locations.sqlite"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if([fileManager fileExistsAtPath:databaseFilePath])
{
# pragma mark - flag to delete file
NSError *fMerror;
if (![fileManager removeItemAtPath:databaseFilePath error:&fMerror]) {
NSLog(#"persistentStoreCoordinator error %#, %#", fMerror, [fMerror userInfo]);
}
}
NSURL *storeUrl = [NSURL fileURLWithPath: databaseFilePath];
NSError *error;
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error]) {
NSLog(#"persistentStoreCoordinator error %#, %#", error, [error userInfo]); }
return persistentStoreCoordinator;
}
Related
I'm occasionally getting this crash, which is very hard to reproduce:
0 CoreFoundation 0x39ff73e2 __exceptionPreprocess + 158
1 libobjc.A.dylib 0x3905095e objc_exception_throw + 26
2 CoreFoundation 0x39ffaf2c -[NSObject(NSObject) doesNotRecognizeSelector:] + 180
3 CoreFoundation 0x39ff9648 ___forwarding___ + 388
4 CoreFoundation 0x39f51204 _CF_forwarding_prep_0 + 20
5 Foundation 0x32914bec -[NSDictionary(NSKeyValueCoding) valueForKey:] + 28
6 MyAppName 0x00032112 -[myViewController stopPlayersWithVolume:] (myViewController.m:151)
From this code:
- (void)stopPlayersWithVolume:(double)volume
{
for (NSString *file in players)
{
AVAudioPlayer *player = [players valueForKey:file];
if (player.volume == volume || volume == 0)
[player stop];
}
}
players is an NSMutableDictionary property, accessed without self. because I don't believe it's needed with ARC. The keys are filenames (e.g. "mysound.mp3") and the values are AVAudioPlayer objects.
Is the stack trace saying that the parameter file I'm passing to [NSMutableDictionary valueForKey] is not actually an NSString, and hence the unrecognised selector? It is always an NSString in the debugger, as you'd expect as it comes from a fast enumeration through the dictionary, but the crash never occurs in the debugger.
My only thought is that there's a threading issue corrupting the dictionary. The code above is being fired by an NSTimer but that's just a message via the run loop, not a separate thread, so I believe there should be no need to worry about cross-thread access?
Any suggestions appreciated. Sorry to just dump this out but I'm stuck.
Edit:
The players dictionary is allocated in viewDidLoad thus:
players = [[NSMutableDictionary alloc] init];
And declared as follows:
#property (retain, nonatomic) NSMutableDictionary *players;
And synthesised as follows:
#synthesize players;
It's likely that your players dictionary or its contents are being deallocated while you're iterating through them. Can you turn on NSZombies and try to reproduce the crash in the debugger? It will give you more information about what object is being deallocated.
The code to allocate the dictionary (and set up the audio stuff) looked like this:
NSError *error = [[NSError alloc] init];
NSArray *names = [fm contentsOfDirectoryAtPath:resourcePath error:&error];
players = [[NSMutableDictionary alloc] init];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:&error];
[[AVAudioSession sharedInstance] setActive:YES error:&error];
I must have copied and pasted it from somewhere, because that use of NSError is wrong, as far as I know, though hardly likely to cause a problem. I changed the code to this:
NSArray *names = [fm contentsOfDirectoryAtPath:resourcePath error:nil];
players = [[NSMutableDictionary alloc] init];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];
And the problem goes away, it appears. Can't be 100% sure but I can reproduce the crash within 10 attempts with the former code and never with the latter. No idea why.
I want to insert 200 5Mb records in my Core Database. But when I save the NSManagedObject, the memory wasn't released (autoreleased pool didn't help), and after inserting 30 records I got the memory warning and the application crashed. Here is my code
- (void)SaveItem
{
NSString *entityName = kEntityName;
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = appDelegate.managedObjectContext;
NSEntityDescription *entityDesctiption = [NSEntityDescription
entityForName: entityName
inManagedObjectContext:context];
// check if town exists
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"id == %d", self.imageID];
NSFetchRequest *requestToCheckExistense = [[NSFetchRequest alloc] init];
[requestToCheckExistense setEntity:entityDesctiption];
[requestToCheckExistense setPredicate:predicate];
NSArray *objects = [context executeFetchRequest:requestToCheckExistense error:nil];
[requestToCheckExistense release];
if (objects == nil)
{
NSLog(#"there was an error");
}
NSManagedObject *object;
if ([objects count] > 0)
{
// edit item
object = [objects objectAtIndex:0];
}
else
{
// if object doesn't exist, find max id to imlement autoincrement
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesctiption];
request.propertiesToFetch = [NSArray arrayWithObjects: #"id", nil];
NSArray *allobjects = [context executeFetchRequest:request error:nil];
[request release];
NSInteger newID = 1;
if ([allobjects count] > 0)
{
NSNumber *maxID = [allobjects valueForKeyPath:#"#max.id"];
newID = [maxID intValue] + 1;
}
// write item
object = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:context];
[object setValue:[NSNumber numberWithInt:newID] forKey:#"id"];
self.imageID = newID;
}
// fill NSManagedObject
// size of objNSData is about 5MB
NSMutableData *objNSData = [[DatabaseManager sharedDatabaseManager] encryptedDataFromImage:bigImage];
[object setValue:objNSData forKey:#"big"];
[context save:nil];
}
When I commented
[object setValue:objNSData forKey:#"big"];
everything was OK.
I tried to add the code into #autoreleasepool , but that didn't help.
I know, that now, when I save data to database, it's still in iPhone RAM. How to release it from this memory? When I get a set of Managed Objects from the database, they are not in the RAM (I can easyly get 100 object, each of them has 5Mb fields)
object =(tblEntity *) [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:context];
try to type cast the object,this may solve the problem
I've solved the issue.
after call of [self SaveItem];
I used
[context save];
[context reset];
[context save];
all the NSManagedObjects from the context will be released.
After that operation I can add as many big objects as I want
Because you don't own an NSManagedObject when you create it, it may be retained by the core data stack even after releasing it (when using an autoreleasepool contained inside the loop).
This may help:
Set the undo manager of your managedobjectContext to nil:
[context setUndoManager:nil];
Be sure that no properties of that object are retained anywhere, because then the managed object will not be released on time inside your loop.
Be sure to add an autorelease pool inside every loop execution, not wrapping all the loop itself, similar to:
for(i;i<n;i++) {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
[obj saveItem];
[pool drain];
}
If that object belongs to a hierarchy of NSManagedObjects, then you need to release the owner of this object too, for this one to be deallocated from memory.
You can check apple's documentation about memory management in CoreData.
Warning: big objects (> 1MB) are not recommended by Apple to be stored inside CoreData (Check this other question/answer.)
I am experiencing a most weird error trying to update values on entities. I a new to core data, so might be something stupid...
here is my update code:
-(BOOL)trataTarefa:(TarefaMap*) mapa{
NSFetchRequest *request =[[NSFetchRequest alloc] init];
NSManagedObjectContext *context = [[DataSource sharedManager]managedObjectContext];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Tarefa" inManagedObjectContext:context];
[request setEntity:entity];
NSPredicate *predicate;
predicate = [NSPredicate predicateWithFormat:#"cd_tarefa == %# AND cd_instalacao contains[cd] %# ", mapa.cd_tarefa, mapa.cd_instalacao];
[request setPredicate:predicate];
NSError *error=nil;
NSArray *result = [context executeFetchRequest:request error:&error];
[request release];
NSLog(#"result=%d",[result count]);
if([result count]==1){
if (mapa.tp_operacao ==3){
Tarefa* tarefa = [result objectAtIndex:0];
[tarefa setTp_operacao:[NSNumber numberWithInt:3]];
NSLog(#"Tarefa=%#", tarefa);
NSError* saveError=nil;
if (![context save:&saveError]) {
NSLog(#"Saving changes to book book two failed: %#", saveError);
} else {
NSLog(#"Teoricamente gravou...") ;
}
}
}
return YES;
}
the code works, it saves the entries, but it returns a * -[CFNumber release]: message sent to deallocated instance #####
tracing it with shell malloc_history, I get:
Date/Time: 2011-03-24 14:12:01.988 -0300
OS Version: Mac OS X 10.6.6 (10J567)
Report Version: 7
ALLOC 0x6603f60-0x6603f6f [size=16]: thread_a052f540 |start | main | UIApplicationMain |
-[UIApplication _run] | CFRunLoopRunInMode | CFRunLoopRunSpecific | __CFRunLoopRun |
__CFRunLoopDoSource1 | __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ |
PurpleEventCallback | _UIApplicationHandleEvent | -[UIApplication sendEvent:]
| - [UIApplication handleEvent:withNewEvent:] | -[UIApplication
_runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] | -
[UIApplication _createStatusBarWithRequestedStyle:orientation:hidden:] | -[UIStatusBar
requestStyle:animated:] | -[UIStatusBar requestStyle:animationParameters:] | -
[UIStatusBarWindow setCornerStyle:] | -[UIImageView initWithImage:] | -[UIImageView
setImage:] | -[UIImageView(UIImageViewInternal) _updateState] | -
[UIImageView(UIImageViewInternal) _canDrawContent] | -[UIView(Rendering) contentMode] |
+[NSNumber numberWithInt:] | -[NSPlaceholderNumber initWithInt:] | CFNumberCreate |
_CFRuntimeCreateInstance | malloc_zone_malloc
Binary Images:
0x1000 - 0x5cff3 +Nonononono (??? - ???) <C4B33680-F374-3E37-9C91-6DEDE06C4701>
/Users/marsson/Library/Application Support/iPhone Simulator/4.1/Applications/B13321A3-
1E73-4DC0-8E37-E2E56116ECEA/Nonononoo.app/Nnonononononono
What I can take from that log, is that the object is not really deallocated...
I already tried to update the object with setValue:forKey with the same result... if I comment the line on the update, the code runs, but of course the object is not updated.
Anyone had a similar problem??
Thanks in advance!
Actually, it was a stupid thread problem... I was trying to update the ManagedContext from an background thread, and it was sometimes crashing the application. Once I used a different managed context, and used notification center to sync the context, everything went smooth. Thanks everyone for the suggestions...
Looks like a problem with [tarefa setTp_operacao:]. Can you post the code to the Tarefa class? The NSNumber you create is autoreleased, so if Tarefa is not retaining it when setTP_operacao is run, you will be accessing a deallocated object after the autorelease pool releases (probably at the end of the current UI event).
I desperately need help with a memory leak in my iPhone app. The app is ready to submit to the app store, is stable, has no memory leaks at all in iPhone simulator or Clang ... but seems riddled with them on my iPod Touch.
They all seem to stem from managedObjectModel when I'm trying to retrieve data from Core Data.
The Core Data code in my app was automatically created by Xcode a while back, I've noticed that the code has since changed when you get xcode to generate it ... I've tried with the old and new but it makes no difference.
If I comment out the following code, the problem goes away ... can anyway see what's wrong with it? I've spent 9 hours on this so far and just can't figure it out!
NSString *entityForName = [[NSString alloc] initWithString:#"OfflineSettings"];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityForName inManagedObjectContext:[self managedObjectContext]];
[request setEntity:entity];
[entityForName release];
NSSortDescriptor *sortById = [[NSSortDescriptor alloc] initWithKey:#"Id" ascending:YES];
[request setSortDescriptors:[NSArray arrayWithObject:sortById]];
[sortById release];
NSError *error;
NSMutableArray *mutableFetchResults = [[[self managedObjectContext] executeFetchRequest:request error:&error] mutableCopy];
if (mutableFetchResults == nil) {
// Handle the error.
NSLog(#"Error fetching");
}
int intId = -1;
if ([mutableFetchResults count] == 0) {
TTDERROR(#"No id has been saved to offline settings");
} else {
OfflineSettings *offlineSettings = (OfflineSettings *)[mutableFetchResults objectAtIndex:0];
intId = [offlineSettings.Id intValue];
}
[mutableFetchResults release];
[request release];
The leak specifically seems to be on this line:
NSMutableArray *mutableFetchResults = [[[self managedObjectContext] executeFetchRequest:request error:&error] mutableCopy];
.. and the code for [self managedObjectContext] is as follows in case it helps ..
- (NSManagedObjectContext *)managedObjectContext {
if (managedObjectContext_ != nil) {
return managedObjectContext_;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext_ = [[NSManagedObjectContext alloc] init];
[managedObjectContext_ setPersistentStoreCoordinator:coordinator];
}
return managedObjectContext_;
}
I'm really at a loss, so I would be so grateful for some help!
Steven
You don't need the mutable copy. executeFetchRequest: returns an autoreleased static array and you're not mutating the array. (I keep seeing this. Must be in an example somewhere.) Likewise, creating the entityForName NSString is pointless. Just put the string literal in the entityForName: to eliminate another possible source of error.
Niether of these are the likely source of the leak but you should remove them anyway.
As a rule of thumb, if you have troubles on device but not simulator or on one hardware but not others, then the problem is in a library/framework that is not properly compiled for the hardware where the error occurs. There really isn't any type of coder error that leaks in one environment but not others. When we make a mistake, it's universal.
It's also possible for resources such as images and sounds to behave differently because different devices use different graphics and audio hardware. That, however, is rather rare.
If you run the code through Instruments it should tell you exactly what object is leaking.
In my app, I am trying to save and retrieval of an image in core data. I am able to save an image successfully after convention of UIimage into NSData, But when I am trying to get an image as NSData it shows output as given below,
case 1: When trying to display as a string from DB.
<Event: 0x5b5d610> (entity: Event; id: 0x5b5ce30 <x-coredata://F51BBF1D-6484-4EB6-8583-147E23D9FF7B/Event/p1> ; data: <fault>)
case 2: When trying to display as Data
[Event length]: unrecognized selector sent to instance 0x5b3a9c0
2010-07-28 19:11:59.610 IMG_REF[10787:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Event length]: unrecognized selector sent to instance 0x5b3a9c0'
My code,
to save:
NSManagedObjectContext *context = [self managedObjectContext];
newsObj = [NSEntityDescription insertNewObjectForEntityForName:#"Event" inManagedObjectContext:context];
NSURL *url = [NSURL URLWithString:#"http://www.cimgf.com/images/photo.PNG"];
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
uiImage = [UIImage imageWithData:data];
NSData * imageData = UIImagePNGRepresentation(uiImage);
[newsObj setValue:imageData forKey:#"imgPng"];
NSError *error;
#try{
if (managedObjectContext != nil) {
if (![managedObjectContext save:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
NSString * infoString = [NSString stringWithFormat:#"Please check your connection and try again."];
UIAlertView * infoAlert = [[UIAlertView alloc] initWithTitle:#"Database Connection Error" message:infoString delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[infoAlert show];
[infoAlert release];
}
}
}#catch (NSException *exception) {
NSLog(#"inside exception");
}
to retrieve,
NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest * fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity1 = [NSEntityDescription entityForName:#"Event" inManagedObjectContext:context];
[fetchRequest setEntity:entity1];
NSError *error;
NSArray * array = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (array == nil) {
NSLog(#"Testing: No results found");
}else {
NSLog(#"Testing: %d Results found.", [array count]);
}
NSData * dataBytes = [[array objectAtIndex:0] data];
image = [UIImage imageWithData:dataBytes];
[fetchRequest release];
}
#catch (NSException *exception) {
NSLog(#"inside exception");
}
Error:
Testing: 3 Results found.
2010-07-28 23:27:51.343 IMG_REF[11657:207] -[Event data]: unrecognized selector sent to instance 0x5e22ce0
2010-07-28 23:27:51.344 IMG_REF[11657:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Event data]: unrecognized selector sent to instance 0x5e22ce0'
*** Call stack at first throw:
(
0 CoreFoundation 0x02566919 __exceptionPreprocess + 185
1 libobjc.A.dylib 0x026b45de objc_exception_throw + 47
2 CoreFoundation 0x0256842b -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
3 CoreFoundation 0x024d8116 ___forwarding___ + 966
4 CoreFoundation 0x024d7cd2 _CF_forwarding_prep_0 + 50
5 IMG_REF 0x00003b06 -[IMG_REFViewController showAction] + 353
6 UIKit 0x002bae14 -[UIApplication sendAction:to:from:forEvent:] + 119
7 UIKit 0x004c214b -[UIBarButtonItem(UIInternal) _sendAction:withEvent:] + 156
8 UIKit 0x002bae14 -[UIApplication sendAction:to:from:forEvent:] + 119
9 UIKit 0x003446c8 -[UIControl sendAction:to:forEvent:] + 67
10 UIKit 0x00346b4a -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 527
11 UIKit 0x003456f7 -[UIControl touchesEnded:withEvent:] + 458
12 UIKit 0x002de2ff -[UIWindow _sendTouchesForEvent:] + 567
13 UIKit 0x002c01ec -[UIApplication sendEvent:] + 447
14 UIKit 0x002c4ac4 _UIApplicationHandleEvent + 7495
15 GraphicsServices 0x02dccafa PurpleEventCallback + 1578
16 CoreFoundation 0x02547dc4 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 52
17 CoreFoundation 0x024a8737 __CFRunLoopDoSource1 + 215
18 CoreFoundation 0x024a59c3 __CFRunLoopRun + 979
19 CoreFoundation 0x024a5280 CFRunLoopRunSpecific + 208
20 CoreFoundation 0x024a51a1 CFRunLoopRunInMode + 97
21 GraphicsServices 0x02dcb2c8 GSEventRunModal + 217
22 GraphicsServices 0x02dcb38d GSEventRun + 115
23 UIKit 0x002c8b58 UIApplicationMain + 1160
24 IMG_REF 0x00002aac main + 102
25 IMG_REF 0x00002a3d start + 53
)
terminate called after throwing an instance of 'NSException'
Note: Above error is coming when going to execute NSData * dataBytes = [[array objectAtIndex:0] data]; line.
Data Model http://www.freeimagehosting.net/uploads/7c286931cc.png
I spent a lot of time with this. Please help me out!
Not sure if you've gotten this straightened out yet, but I am able to save/retrieve UIImage objects in Core Data as follows:
To save:
NSData *imageData = UIImagePNGRepresentation(yourUIImage);
[newManagedObject setValue:imageData forKey:#"image"];
and to load:
NSManagedObject *selectedObject = [[self fetchedResultsController] objectAtIndexPath:indexPath];
UIImage *image = [UIImage imageWithData:[selectedObject valueForKey:#"image"]];
[[newCustomer yourImageView] setImage:image];
Hope this helps. I am using a UITableView with Core Data and pulling the image from the database in my tableView:didSelectRowAtIndexPath: method.
Here's the proper solution that works very well.
1) Storing UIImage with Core Data:
NSData* coreDataImage = [NSData dataWithData:UIImagePNGRepresentation(delegate.dancePhoto)];
Make sure that "coreDataImage" is of type NSData. You have to set type to "Binary data" for "coreDataImage" in your model.
2) Retrieving UIImage from Core Data:
UIImage* image = [UIImage imageWithData:selectedDance.danceImage];
That's all there's to it, works great.
When you retrieve the image, you're performing the fetch request and storing the results in the variable array, meaning array holds an NSArray of Event objects. Then, later, you assign:
dataBytes = [array objectAtIndex:0];
This means that dataBytes, which you declared as NSData, is now actually an instance of Event. Then when you go to initialize the image, part of the implementation of imageWithData: calls length on what it expects to be your NSData object, but is actually an Event object, hence the error message.
You should adjust your code to read:
dataBytes = [[array objectAtIndex:0] imgPng];
That way, you're getting the first Event object out of the array, then fetching its imgPng property (an instance of NSData, which is what you want).
As a side note, your declaration of dataBytes using the alloc-init on the line above may be extraneous, since you change dataBytes to be the data from your Event immediately afterwards.
The Solution I used was to create the category bellow. You just need it in your project for it to work. Using this storing images works just like you where storing an NSData
UIImage+NSCoding.h
#interface UIImage (UIImage_NSCoding) <NSCoding>
- (void)encodeWithCoder:(NSCoder *)aCoder;
- (id)initWithCoder:(NSCoder *)aDecoder;
#end
UIImage+NSCoding.m
#import "UIImage+NSCoding.h"
#implementation UIImage (UIImage_NSCoding)
- (void)encodeWithCoder:(NSCoder *)aCoder
{
NSData *imageData = UIImagePNGRepresentation(self);
[aCoder encodeDataObject:imageData];
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
[self autorelease];
NSData* imageData = [aDecoder decodeDataObject];
self = [[UIImage alloc] initWithData:imageData];
return self;
}
#end
This sample code has example how to store UIImage in Core Data:
https://developer.apple.com/library/ios/#samplecode/PhotoLocations/Introduction/Intro.html