views:

124

answers:

2

I have a reasonably complex Core Data app for the the iPhone. For the most part, it's working well, but I'm running into a sporadic problem that manifests itself within Core Data.

I'm fetching data from a remote service, said service returns data. I parse the data and modify various managed objects. Then I save the managed object context and I get an error. In the course of printing the error I get the following message:
* -[UIImage length]: unrecognized selector sent to instance 0x8cd7aa0

I can isolate the problem down to a single setter in my one of my managed objects. I save the managed object context before using the setting and I save the managed object context right after. Failure happens right after.

This is all being done in the main thread. I have more than one managed object context, but only one persistent store.

Any pointers for debugging this sort of Core Data problem are appreciated.

A: 

This particular problem was caused by a method with the word "get" in it that corresponded to a field name in the managed object. It, in turn, masked the real problem which is database related.

mousebird
A: 

I had the same problem, so I crafted a workaround. Subclass the NSManagedObject and manually transform the UIImage by overriding the accessor methods for the image property.

  • In the setter method, transform the UIImage object into an instance of NSData, and then set the managed object's image property.
  • In the getter method, transform image property's data, and return an instance of UIImage.

Let's get to work:

In the data model, when you click the attribute, "image", delete the Value Transformer Name's text. It defaults to NSKeyedUnarchiveFromData, which is what you now want.

Next, subclass the entity by clicking on it in the data model, click New File. When you have the entity selected, you should see a new class in Cocoa Touch Classes titled "Managed Object Class." Click Next, leave the file's location as is by clicking Next again, and then put a checkmark next to all the entities you want to subclass.

In the implementation file of your subclassed NSManagedObject, override the image property's accessor methods by including the following two:

- (void)setImage:(UIImage *)image {
    [self willChangeValueForKey:@"image"];

    NSData *data = UIImagePNGRepresentation(image);
    [self setPrimitiveValue:data forKey:@"image"];
    [self didChangeValueForKey:@"image"];
}

- (UIImage *)image {
    [self willAccessValueForKey:@"image"];
    UIImage *image = [UIImage imageWithData:[self primitiveValueForKey:@"image"]];
    [self didAccessValueForKey:@"image"];
    return image;
}

Then, whenever you set the image, use:

object.image = [UIImage imageNamed:@"icon.png"];

rather than:

[object setValue:[UIImage imageNamed:@"icon.png"] forKey:@"image"];

Whenever you get the image, use:

UIImage *myImage = object.image;

rather than:

UIImage *myImage = [object valueForKey:@"image"];
Rose Perrone