6
votes

I've been using transformable attributes in core data to transform complex objects like images and colors into raw data. I took this...

The idea behind transformable attributes is that you access an attribute as a non-standard type, but behind the scenes Core Data uses an instance of NSValueTransformer to convert the attribute to and from an instance of NSData. Core Data then stores the data instance to the persistent store.

... to mean that you could only convert things to and from data and not one of the other types of attributes such as strings.

It just occurred to me that this might not be the case. The documentation might just be talking about the most common case. IIRC, in Cocoa bindings, the transforms can be largely arbitrary. It is possible to transform, say, a NSURL to a NSString for display and then reverse it.

Before I waste time experimenting and possibly getting a confusing result, I wondered if someone knew for certain if the transform is only to and from data only.

2

2 Answers

4
votes

Correct. You must transform your attribute into an NSData object. You would need to serialize an NSURL to NSData -- and the default NSKeyedUnarchiveFromDataTransformerName transformer will do this for you.

Another approach, and the one that I use for URLs, is to maintain two parallel properties. One transient property of undefined type for the URL, and a second persistent property of string type for the backing store. I lazily construct the URL from the string the first time it's requested, and I update the string property whenever the URL is changed.

There's no way to enforce it, but you really don't want to use the string property from outside your entity's class. I generally make the @property definition for the string attribute private to remind myself not to use it.

0
votes

I don't have enough points to comment, so I have to contribute in the form of an answer. I just tried to do exactly what @Amaud suggested, using an NSValueTransformer to convert NSURL objects to NSString objects for a Transformable attribute. Unfortunately, Core Data still expects an NSData instance from the transformer, regardless of the transformedValueClass. Core Data still creates the SQLite database with a BLOB column for that transformable attribute, and saving entities results in a crash with uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString bytes]: unrecognized selector sent to instance 0x608000075bc0'. Core Data is trying to invoke [NSData bytes] on the NSString instance my transformer provided. This seems like a big hole in Core Data to me, as I'm sure there are countless non-standard types that could be stored and queried as string attributes.

It seems the only option, aside from using NSString, is to do as @Alex describes and use transient properties and derived values. Core Data does not make that very clean, however, because as @Alex stated, there's no way to enforce exclusive use of the transient property accessors.