I’m fighting with an entity in Core Data and I wish to avoid subclassing it. But maybe I take the wrong way:
The entity has two attributes (you can substitute “Class” to Entity and “Property” to attribute) and I’m trying to concatenate their values into a third one.
Say you have a “personID” attribute and a “personName” attribute. Is it possible to put them into a “personIdandName” attribute (so I could bind this attribute to a pop menu) using a Regular Expression?
If there is no hope, I should consider subclassing the Entity.
I tried to subclass the entity, finally, and got my menu items, but it’s really not worth it-- for a single trick like putting two properties into one menu item, subclassing is a big change.
You have, for instance, to handle the KVO mechanism yourself. Let’s say your integer ID is changed somewhere in the view, your model stays unchanged if you don’t implement “willChangeValueForKey” and “didChangeValueForKey” methods.
One error, and your Core Data structure is ruined. The big advantage with CD is to rely on the context management done by the framework. If you begin to interfere, you are suddenly in charge of it.
So I turned back to the NSValueTransformer, but have no success so far. My idea was to send the Core Data entity to the transformer, and get back a NSString formatted with the ID and name entity’s properties like this:
Curiously enough, this custom transformer is never called. I bound the arranged objects of the controller to the menu “Content values” (with no key path) and set my custom transformer for this binding. The menu item does contain the NSManagedObject (under a hardly readable form.) but the NSValueTransformer is not invoked.
I still think you can do this without subclassing or a value transformer. You just loop through your managedObjects, concatenate the two attributes, and add those strings to a new array. Bind that array to your popup button. I did a test app like so, using an array of dictionaries rather than managed objects, but the principle is the same.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSArray *dictArray = @[@{@"name":@"Bill", @"age":@"24"},@{@"name":@"Tom", @"age":@"23"},@{@"name":@"Alvin", @"age":@"64"},@{@"name":@"Xavier", @"age":@"47"}];
self.theData = [NSMutableArray array];
for (NSDictionary *dict in dictArray) {
NSString *s = [NSString stringWithFormat:@"%@--%@",[dict valueForKey:@"name"],[dict valueForKey:@"age"]];
[self.theData addObject:s];
}
self.theData = _theData; //this array is bound to the array controller's contentArray
}
I don’t have to test your code to see that it will work :). The only difference is that I have to postpone the array update just before the menu is displayed (because the entities may have been modified since the app was launched).
This will work, but has a taste of procedural coding (I did exactly the same thing in the Pascal version, years ago). I was so unsatisfied by this “UpdateMenu” approach that I just put another pop menu just aside the first one: you choose the ID, the name appears on the second. You choose the name, the ID is selected in the first one.
Ugly, non-HIG, almost ridiculous.
The question is now: what’s wrong with my transformer? I have programmed a half-dozen of them, I know that you can convert any object into any other object. I’m sure that you can modify your own code to send a particular dictionary to a transformer and get back the concatenated string, using the keys of the dictionary. A Core Data entity can be compared to a NSDictionary (according to the docs). So what?
I’m quite sure it is a binding problem. You have a lot of fields to set up for a pop menu. This is the model:
Cards is the first entities controller
Objects is the second entities controller
Object.card relationship to the card (inverse: Cards.objects): a card may have many objects; an object belongs to one card.
I’ve tried some little test projects using a value transformer to transform the objects in an array being used to populate a popup button – so far I haven’t gotten it to work. I’ve gotten them to work for table views, but the problem seems to be what values are sent to the value transformer – I’m not sure why this is, but when I log value in the transformedValue method, it gives me an empty array when doing it with a popup button, but it seems to send the values individually (which is what you want) when working with a table view. I’ll have to look into this a little more.
I also have the problem of finding my value transformer in IB. You’re supposed to register a name for your transformer with setValueTransformer:forName:, and that has worked for me in the past (and if I log valueTransformerNames it gives me the complete list including mine that I just registered). However, now if you pull down the menu in IB I see the name of my transformer class rather than the name I registered the instance.
So. For a so simple thing, I finally subclassed the Core Data Entity and overridden the “description” method. This time, Apple, I’m not sure the mistake is on my side.