0

I'm working on an app that using core data, and everything is working so far. But I haven't used an image in it yet. I would like to do so but I don't know where to start. I would like to have the user click a button that gives them the option of locations of where they can get images. Also, is it possible to have a user just enter the URL of an image and have it save to core data? Thats really it so if someone could point me in the right direction I would appreciate it. Thanks!

My code so far: https://github.com/jackintosh7/Core-Data

Jack
  • 304
  • 6
  • 19

2 Answers2

1

I learnt a lot from Paul Hegarty's excellent iTunes U / Stanford Uni lectures... his latest is called "Developing iOS Apps for iPhone and iPad" A couple of his lectures specifically address the use of images in Core Data. For what you are wanting to do I recommend you watch lectures 10-13, but really it is worth watching the entire series.

Beyond that, spend some time to read through the Apple Documentation on Core Data, starting here. Samir writes a good response to this stack overflow question.

You have a few options in how you implement the code. While Core Data is capable of managing the saving of images into the structure of your persistent data store (e.g. sqlite), it is important to note that large image files will slow down the fetch process.

Core Data can manage how to store the image for you... by clicking on the Allows External Storage option in the Data Model Inspector... see attached image below.

Data Model Inspector for possible attribute pictureData

If however, you are looking to point a user to a URL, it may be worth considering adding (another separate) attribute to your entity Item, for example an attribute named pictureURL.

Use a property in a UIViewController to manage the entity attribute...

@property (nonatomic, retain) NSString * pictureURL;

Then you can add a UITextField to a UIViewController to accept user input for this property pictureURL.

When you have a URL for an image, you can return the image with "getter" code similar to this (where the UIImage is a property of the UIViewController)...

- (UIImage *)image {
    NSURL *imageURL = [NSURL URLWithString:self.pictureURL];
    NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
    return [UIImage imageWithData:imageData];
}

Hope that provides you with some direction.

Community
  • 1
  • 1
andrewbuilder
  • 3,629
  • 2
  • 24
  • 46
1

EDIT - I updated some of the references in the saveImgData:fromURL to match the parameters passed in the method. I used a variation of this method within an NSURL protocol to intercept requests and cache specific ones. Some of the entity parameters may not apply to your question. Just disregard those (such as encoding/lastModified/mimeType/response).

To save an image to CoreData give this a try.

First, download your image. A user can enter the url in a text entry field. (The example listed by andrewbuilder will work just fine)

NSURL *imgURL = [NSURL URLWithString:myImgURL];
NSData *imgData = [NSData dataWithContentsOfURL:imgURL];

//a better way would be to do this asynchronously. Google "Lazy Image Loading" and
//you should find a suitable example app from Apple

Setup your CoreData entity to store the image data. Here is a sample that stores more than just the image binary data.

Entity Screen Shot

Then save your image data directly to CoreData. I have a CoreData manager class but you may have your CoreData stack in AppDelegate which is how Apple sets them up.

-(void)saveImgData:(NSData*)myImgData fromURL:(NSString*)urlStr{

    //If you have a CoreData manager class do something like this
    CoreDataManager *cdm = [CoreDataManager defaultManager];
    //Use private queue concurrency type for background saving
    NSManagedObjectContext *ctx  = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    //Set up the parent context, in this case is the mainMOC
    //If you are using basic CoreData it would be the managedObjectContext on your AppDelegate
    ctx.parentContext = cdm.mainMOC;

    [ctx performBlock:^{
        //performBlock executes on a background thread
        CachedURLResponse *cacheResponse = [NSEntityDescription insertNewObjectForEntityForName:@"CachedURLResponse" inManagedObjectContext:ctx];
        cacheResponse.relativeURLHash = [NSNumber numberWithInteger:[urlStr hash]];
        cacheResponse.data = [myImgData copy];
        cacheResponse.response = [NSKeyedArchiver archivedDataWithRootObject:self.response];
        cacheResponse.url = [urlStr copy];
        cacheResponse.timestamp = [NSDate date];
        cacheResponse.mimeType = [self.response.MIMEType copy];
        cacheResponse.encoding = [self.response.textEncodingName copy];
        if ([self.headers objectForKey:@"Last-Modified"])
            cacheResponse.lastModified = [self.headers objectForKey:@"Last-Modified"];

        NSError *__block error;
        if (![ctx save:&error])
            NSLog(@"Error, Cache not saved: %@", error.userInfo);

        [cdm.mainMOC performBlockAndWait: ^{
            [cdm saveContext];
        }];

    }];
}

My CoreDataManager.h looks like this: CoreDataManager.h

and my CoreDataManager.m file looks like this:

#import "CoreDataManager.h"
#import <CoreData/CoreData.h>
@implementation CoreDataManager

@synthesize mainMOC = _mainMOC,
        managedObjectModel = _mom,
        persistentStoreCoordinator = _psc
;


+(CoreDataManager*)defaultManager
{
    static CoreDataManager *_defaultMgr = nil;

        static dispatch_once_t oncePred;
        dispatch_once(&oncePred, ^{
            _defaultMgr = [[CoreDataManager alloc] init];
        });

    return _defaultMgr;

}



-(id)init
{
    if (self = [super init])
    {
        NSError *error = nil;
        NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"MyDatabase.sqlite"];
        NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"MyDataModelName" withExtension:@"momd"];

        _mom = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
        _psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
        if (![_psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);

        _mainMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
        [_mainMOC setPersistentStoreCoordinator:self.persistentStoreCoordinator];

    }
    return self;
}


- (void)saveContext
{
    NSError *error = nil;
    if (self.mainMOC != nil && ([self.mainMOC hasChanges] && ![self.mainMOC save:&error])) {
        NSLog(@"CoreData save error: %@, %@", error, [error userInfo]);
    }
}


#pragma mark - Core Data Stack

- (NSManagedObjectContext *)mainMOC
{
    return _mainMOC;
}

- (NSManagedObjectModel *)managedObjectModel
{
    return _mom;
}

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    return _psc;
}

- (NSURL *)applicationDocumentsDirectory
{
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}




@end

Hope that gives you a good starting point. Google "CoreData Class Reference" for some really good reading on the topic.

digitalHound
  • 4,384
  • 27
  • 27