Save and Retrieve of an UIImage on CoreData

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