Retrieving NSImage from CoreData - Mac OS X - macos

I'm trying to add images into core data and load it when needed. I'm currently adding the NSImage to the core data as follows:
Thumbnail *testEntity = (Thumbnail *)[NSEntityDescription insertNewObjectForEntityForName:#"Thumbnail" inManagedObjectContext:self.managedObjectContext];
NSImage *image = rangeImageView.image;
testEntity.fileName = #"test";
testEntity.image = image;
NSError *error;
[self.managedObjectContext save:&error];
Thumbnail is the entity name and I have two attributes under the Thumbnail entity - fileName(NSString) and image (id - transformable).
I'm trying to retreive them as below:
NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest * fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *imageEntity = [NSEntityDescription entityForName:#"Thumbnail" inManagedObjectContext:[context valueForKey:#"image"]];
[fetchRequest setEntity:imageEntity];
NSError *error;
NSArray * array = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (array == nil) {
NSLog(#"Testing: No results found");
}else {
_coreDataImageView.image = [array objectAtIndex:0];
}
I end up with this error:
[<NSManagedObjectContext 0x103979f60> valueForUndefinedKey:]: this class is not key value coding-compliant for the key image.
The image is added but couldn't retrieve.
Any idea on how to go about with this? Am I doing it right ?

The error is in this line
NSEntityDescription *imageEntity = [NSEntityDescription entityForName:#"Thumbnail"
inManagedObjectContext:[context valueForKey:#"image"]];
You cannot apply valueForKey:#"image" to a managed object context. You have to apply it to the fetched objects (or use the image property of the fetched object).
Note also that executeFetchRequest: returns nil only if an error occurs. If no entities are found, it returns an empty array.
NSEntityDescription *imageEntity = [NSEntityDescription entityForName:#"Thumbnail" inManagedObjectContext:context];
[fetchRequest setEntity:imageEntity];
NSError *error;
NSArray * array = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (array == nil) {
NSLog(#"Testing: Fetch error: %#", error);
} else if ([array count] == 0) {
NSLog(#"Testing: No results found");
}else {
Thumbnail *testEntity = [array objectAtIndex:0];
NSImage *image = testEntity.image;
_coreDataImageView.image = image;
}

Related

Having Trouble Sorting CoreData backed NSArrayController

Im trying to retrieve an array of sorted objects from my Core Data backed NSArrayController. Once the ManagedObjectContext is ready I fire a Notification which the object owning the NSArrayController listens for and then sets up the fetch request with sortDescriptors. However the data is NEVER sorted. I've been pounding my head on this for several hours now.
I get the expected data in the array but it's not sorted at all. Anyone have any ideas where I am going wrong?
// Elsewhere in code
...
_charts = [[NSArrayController alloc] init];
_charts.entityName = #"Charts";
...
// When Cored Data and Managed Object Context is ready
-(void)mangagedObjectContextReady
{
NSManagedObjectContext *moc = ((AppDelegate *)[NSApp delegate]).managedObjectContext;
_charts.managedObjectContext = moc;
_charts.usesLazyFetching = NO;
_charts.automaticallyPreparesContent = YES;
_charts.automaticallyRearrangesObjects = YES;
// Create fetch request for data
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
fetchRequest.entity = [NSEntityDescription entityForName:#"Charts" inManagedObjectContext:moc];
// Create the sort descriptors for the Charts entity
// Name and chartType are properties on the entity "Charts"
NSSortDescriptor *nameDescriptor = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES selector:#selector(caseInsensitiveCompare:)];
NSSortDescriptor *chartTypeDescriptor = [[NSSortDescriptor alloc] initWithKey:#"chartType" ascending:YES selector:#selector(caseInsensitiveCompare:)];
fetchRequest.sortDescriptors = #[nameDescriptor, chartTypeDescriptor];
NSError *error = nil;
BOOL success = [_charts fetchWithRequest:fetchRequest merge:NO error:&error];
if(!success)
NSLog(#"Error %#:", [error localizedDescription]);
else {
[_charts rearrangeObjects];
[_tv reloadData];
}
I use this method to get an array or sorted objects.. but data is not sorted as per above sort descriptors?
[_charts.arrangedObjects objectAtIndex:row]
_charts.sortDescriptors = #[nameDescriptor, chartTypeDescriptor];

When sorting a NSMutable array from core data, i get an error

Below is my viewDidLoad method in a tableViewController. When viewDidLoad runs this error comes up
2014-03-03 12:44:54.904 SalesCRM2[30188:70b] -[_PFArray sortUsingDescriptors:]: unrecognized selector sent to instance 0x8c45710
2014-03-03 12:44:54.931 SalesCRM2[30188:70b] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_PFArray sortUsingDescriptors:]: unrecognized selector sent to instance 0x8c45710'
on this line of code
[array sortUsingDescriptors:[NSArray arrayWithObject:sort]];
Here is the whole method
- (void)viewDidLoad
{
[super viewDidLoad];
JCAppDelegate *appDelegate =
[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context =
[appDelegate managedObjectContext];
NSEntityDescription *entityDesc =
[NSEntityDescription entityForName:#"Customers"
inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesc];
NSError *error;
NSArray *objects = [context executeFetchRequest:request
error:&error];
NSMutableArray *array = (NSMutableArray *)objects;
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:#"firstName" ascending:YES];
[array sortUsingDescriptors:[NSArray arrayWithObject:sort]];
if ([objects count] == 0)
{
//_isEmpty = YES;
}
else
{
//_isEmpty = NO;
_resultsArray = (NSMutableArray *)objects;
NSLog(#"resultsArray: %i",[_resultsArray count]);
// matches = objects[0];
// _address.text = [matches valueForKey:#"address"];
// _phone.text = [matches valueForKey:#"phone"];
// _status.text = [NSString stringWithFormat:
// #"%lu matches found", (unsigned long)[objects count]];
}
}
Read the error message. It's telling you the problem. You can say sortUsingDescriptors: to an immutable array. It is immutable.
Now, as for what you are doing wrong, it is much more interesting! You are saying:
NSMutableArray *array = (NSMutableArray *)objects;
Perhaps you believe that this turns an immutable array into a mutable array. It doesn't. You can't turn a silk purse into a sow's ear by typecasting. You may lie to the compiler (and you did, by typecasting to a false class), but you can't lie to the runtime. What an object is, that's what it is, no matter what you call it.
If you want a mutable array, you must make a mutable array (e.g. by calling mutableCopy) - it isn't enough to say a thing is a mutable array when in fact it isn't.

Fetch update in Cocoa

this is the code in my AppDelegate.m:
-(IBAction)fetch:(id)sender{
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Foo" inManagedObjectContext:[self managedObjectContext]];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"title == 'some title'"];
[fetchRequest setPredicate:predicate];
NSError *error = nil;
NSArray *fetchedObjects = [[self managedObjectContext] executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {NSLog(#"Error: %#", error);}
NSMutableArray *fooArray = [[NSMutableArray alloc]init];
for (Foo *f in fetchedObjects) {
//here another fastenum for a to-many relationship
for(Bar *b in f.relationship){
[fooArray addObject:b.title];
}
}
Everytime I perform the fetch action, even if I've changed the app.storedata file via UI and checked the changes in finder, the result is always the same until i quit the application. After a restart, the fetch result is up to date and aligned with the app.storedata file. The fooArray count is always the same, regardless if I add some entries in the entities and coredata save everything.
I've tried with [fetchRequest setIncludesPendingChanges:YES] but it doesn't affect the behaviour.
How to update the fetch result while the app is running?
UPDATE: i've "solved" the problem with this workaround:
-(IBACTION)fetch:(id)sender{
_managedObjectContext = nil;
_persistenStoreCoordinator = nil;
//rest of the code...
Is this workaround a final solution? Is there a more "correct" way to solve this problem?

Xcode - filter an NSFetchRequest and select each object

I am trying to filter a fetchRequest.
I'm at the point where the result is loaded into an NSArray.
However, I need to parse the array to pull out the individual items - right now, they look as if they were one object.
The code I'm using to get to this point is:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSManagedObjectContext *moc = coreDataController.mainThreadContext;
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Category" inManagedObjectContext:moc];
[request setEntity:entity];
// Order the events by name.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES];
[request setSortDescriptors:#[sortDescriptor]];
// Execute the fetch -- create a mutable copy of the result.
NSError *error = nil;
NSArray *categories = [[moc executeFetchRequest:request error:&error] mutableCopy];
if (categories == nil) {
NSLog(#"bugger");
}
NSObject *value = nil;
value = [categories valueForKeyPath:#"name"];
This results as follows:
value = (
)
[DetailViewController loadPickerArray]
[AppDelegate loadPickerArray]
value = (
"Cat Two",
"Cat Three",
"Cat One",
"Cat Four"
)
Also, please note that the first time this ran, there were no results. I get that about 50% of the time.
Thanks for any help.
There are several methods you can filter your data.
The preferred way is to use a predicate for your search. This will give you the best performance.
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSManagedObjectContext *moc = coreDataController.mainThreadContext;
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Category" inManagedObjectContext:moc];
[request setEntity:entity];
// Order the events by name.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name CONTAINS[CD] %#", #"Cat"]; //This will return all objects that contain 'cat' in their name property.
[request setPredicate:predicate];
[request setSortDescriptors:#[sortDescriptor]];
// Execute the fetch -- create a mutable copy of the result.
NSError *error = nil;
NSArray *categories = [moc executeFetchRequest:request error:&error];
if (categories == nil) {
NSLog(#"bugger");
}
//Here you have the objects you want in categories.
for(Category *category in categories)
{
NSLog(#"Category name: %#", category.name);
}
If you wish to filter using an array, the following is possible also:
NSMutableArray *categories = [[moc executeFetchRequest:request error:&error] mutableCopy];
[categories filterUsingPredicate:[NSPredicate predicateWithFormat:[NSPredicate predicateWithFormat:#"name CONTAINS[CD] %#", #"Cat"]]
//Now, the only objects left in categories will be the ones with "cat" in their name property.
I recommend reading the Predicates Programming Guide, as predicates are very powerful, and it is much more efficient to filter your results in the store.

NSDistantObject enumeration

I was make communication for client-server application and have strange problem.
here is a code where i pickup objects.
- (byref NSArray*)objectsOfName:(bycopy NSString*)name
withPredicate:(bycopy NSPredicate*)predicate;
{
NSManagedObjectContext *context = [self managedObjectContext];
NSError *error = nil;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:name
inManagedObjectContext:context]];
[request setPredicate:predicate];
NSArray *results = [context executeFetchRequest:request error:&error];
[request release], request = nil;
if (error) {
NSLog(#"%#:%# Error on fetch %#", [self class], NSStringFromSelector(_cmd), error);
return nil;
}
//NSLog(#"%#:%# Result of fetch is %#", [self class], NSStringFromSelector(_cmd), results);
return results;
}
Here is pickup:
NSArray *destinations;
#ifdef SNOW_CLIENT
destinations = [server objectsOfName:#"DestinationsListWeBuy" withPredicate:predicate];
If i do
NSLog(#"Destination:%#\n",destinations);
i seen all objects in log.
If i try to do
NSLog(#"all:%#\n%#\n%#\n",[[destinations objectAtIndex:0] valueForKey:#"rate"],[[destinations objectAtIndex:0] valueForKey:#"lastUsedACD"],[[destinations objectAtIndex:0] valueForKey:#"lastUsedCallAttempts"]);
i seen attributes also.
But, if i try to do loop around objects:
for (NSManagedObject *dest in destinations)
{
NSLog(#"all:%#\n%#\n%#\n",[dest valueForKey:#"rate"],[dest valueForKey:#"lastUsedACD"],[dest valueForKey:#"lastUsedCallAttempts"]);
i have EXC_BAD_ACCESS in this part of code:
for (NSManagedObject *dest in destinations)
all debug technic, which i know, don't give me possibility to understand, what happened. (NSZombieEnabled = YES)
if i do loop at another manner:
for (NSUInteger count = 0;count < [destinations count]; count++)
NSLog(#"all:%#\n%#\n%#\n",[[destinations objectAtIndex:count] valueForKey:#"rate"],[[destinations objectAtIndex:count] valueForKey:#"lastUsedACD"],[[destinations objectAtIndex:count] valueForKey:#"lastUsedCallAttempts"]);
i seen all keys without exception. All nsmanagedobject's is subclassed.
If i need implement encodeWithCored method for all subclasses, examples is appreciated.
*UPDATE for Marcus *
This is how i receive objects from server side:
- (byref NSArray*)allObjects
{
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (!coordinator) {
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setValue:#"Failed to initialize the store" forKey:NSLocalizedDescriptionKey];
[dict setValue:#"There was an error building up the data file." forKey:NSLocalizedFailureReasonErrorKey];
NSError *error = [NSError errorWithDomain:#"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
[[NSApplication sharedApplication] presentError:error];
return nil;
}
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init];
[moc setPersistentStoreCoordinator:coordinator];
[moc setUndoManager:nil];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self
selector:#selector(mergeChangesForClient:)
name:NSManagedObjectContextDidSaveNotification
object:thirdMOC];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Carrier"
inManagedObjectContext:moc];
[request setEntity:entity];
[request setIncludesSubentities:YES];
NSError *error = nil;
NSArray *objects = [moc executeFetchRequest:request error:&error];
[request release], request = nil;
for (NSManagedObject *carrier in objects) {
NSSet *destinations = [carrier valueForKeyPath:#"destinationsListForSale"];
for (NSManagedObject *destination in destinations) [destination addObserver:self forKeyPath:#"rate" options:NSKeyValueObservingOptionNew context:nil];
}
if (error) {
NSLog(#"%#:%# error: %#", [self class], NSStringFromSelector(_cmd), error);
return nil;
}
return objects;
}
This is what i do with them on client side:
NSArray *allObjects = [server allObjects];
[carrierArrayController setContent:allObjects];
There is no serialization in this case. Any other ways (like send copy of server moc to client side doesn't work, it just generate exceptions on main.c).
p.s. many thanks to Marcus for his Core Data book.
unrecognized selector sent to class 0x1000a2ed8 2011-03-17 02:15:18.566 snowClient[19380:903] +[AppDelegate encodeWithCoder:]: unrecognized selector sent to class 0x1000a2ed8
That is not a core data problem. That is an error in your code where you are trying to call a method on an object that does not respond to that method. You need to track that down as it appears that you are trying to serialize your AppDelegate.
Update
What kind of class is 0x1000a2ed8? Break on the exception and print out the object to see what it is. Again, this is not a core data error directly, it is sending a messages to an object that does not respond to that message. It is possible that Core Data no longer allows you to send Managed objects across as distributed objects. It is possible that this is simply an issue with an over-released object. No way to know without further investigation.
Step one: Find out what object 0x1000a2ed8 is and see if the object changes from one run to the next.

Resources