Core Data, Cocoa Bindings, OSX Programming

So, I took on a hefty task these past few days and decided to do a lot of complicated stuff all at once.  Teach myself CoreData was the original goal, but then it occurred to me there’s not much you can do with CoreData when you don’t HAVE ANY DATA.

So, knowing that I’m going to want to have a rather substantial pre-populated database in the app, and ideally delegate this menial task of populating it away to the other App designer, I thought I should create a database Editor.   This would then involve making a Mac OSX app that would make it straightforward to get data in the database.

But, if you use Mac OSX, you can leverage the extremely powerful technology called Cocoa Bindings, which is designed in a way where you shouldn’t have to write much (boring) glue code, that would be responsible for synchronizing the UI Controls / Elements with the Data they are controlling/being controlled by.

So there.  CoreData, OSX, and Cocoa Bindings, all at the same time.  Here is my qualitative report on my progress so far:

– Once you understand how things work, it is simple and VERY useful.  😀  (Yeah, ONCE you do)
– Learning a lot of things at the same time can be very difficult because one technology depends on another, and if you don’t understand any of them in great depth, it’s hard to find where the source of your problems are.
– OSX Programming is FUN.  Possibly more fun than iOS programming.

Things that tripped me up:

  • NSTextCell is used to edit text or number properties, though with numbers you will want to apply a NSNumberFormatter, and may require a subclass of NSValueTransformer to ‘translate’ the string output of a NSTextCell into a NSNumber value for your data model.
  • If you want to edit an object’s “to one” relationship with another object, don’t use a NSTextCell nor a NSComboBoxCell, but rather a NSPopUpButtonCell and follow instructions given at Apple Developer
  • If you’re using an array controller for NSManagedObjects, you should bind a NSManagedObjectContext, and use it in entity mode (not class mode), because the add: and remove: (and other such) actions of the NSArrayController will instantiate via [[SomeClass alloc] init] instead of [[SomeManagedObjectClass alloc] initWithEntity… ];
  • I still haven’t figured out how custom validation works.  It seems to validate but then reports validation failures although there shouldn’t be… Will figure that out later and in the meantime ‘will be careful’
  • Maintaining Object uniqueness can be tricky.   I added this method to a category for NSManagedObject:
+ (NSManagedObject*)findForEntityName:(NSString*)anEntityName
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
 	[fetchRequest setFetchLimit:1];
 	[fetchRequest setEntity: [NSEntityDescription entityForName: anEntityName inManagedObjectContext: aContext]];
 	[fetchRequest setPredicate: findCriteria];
 	NSArray *results = [aContext executeFetchRequest:fetchRequest error:nil];

 	if ([results count]==0) return nil;  // no matches (existing records with this code) were found

    return results[0];

Then you can quickly check if an object exists based on the entity name and the predicate (which would be filled with the query that would define uniqueness… i.e.  the property that is your “primary key” )

  • In CoreData, if you have an object that has a to-one relationship, i.e. a Recipe has many steps, and with each step there is an ingredient associated with it. However, many recipes can make use of that same ingredient.  So the step has a to-one relationship with an ingredient, and the inverse relationship has a to-many with recipe steps (and therefore indirectly to a Recipe).    Oh yeah, data modelling databases…. the one course I had, the professor was out sick for 2 months of it, and somehow nobody at my Uni seemed to care if we were receiving an education or not.  Being a German University, it’s not in their nature to care about quality, it’s in their nature to check if everyone has the stamp on their piece of paper that *proves* they are capable.
  • If you use a Transformable Attribute on your model, your subclass of NSValueTransformer has to do the following:
    – the transformedValueClass is NSData
    – Therefore the transformedValue: method should be returning NSData
    – the reverseTransformedValue: should return your custom type
    – allowsReverseTransformation should be set to YES

Things that are still a problem (will update this later when I find the solution):

  • When I create an association from a data parser (via awakeFromInsert), these aren’t being displayed in the User Interface.  However, if I create an object via the UserInterface, the associations are created.

The Most Useful Resources so far have been:

  • Ray Wenderlich Tutorials for Mac App programming (first (CoreData), second (a simple Mac OSX app), third (Cocoa Bindings))
  • Editing “to-one” relationships with Cocoa Bindings:  AppleDeveloper
  • Apple Documentation (yes, really.  Maybe I am getting better at this, or my Attention Deficit problems that arise when reading boring technical texts is not as bad as it used to be)
  • The one and only  Where would we be without that?!

But anyway, I plan to update this post a bit later.   It’s strange; now I seem to know a lot more, but am unclear how I got to this point.  There was a lot of time spent that feels like wasted time, but I guess that’s to be expected when you try to tackle a lot at once, with nobody to answer  your questions, and a lot of pre-requisite knowledge is also kind of missing.

In the end I’m thrilled that I’m learning this stuff as it only serves to make me a better developer.  At least with Apple technology, which is still really fun to work with.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s