Core data and bindings. Handle with care.

27 aprile 2006

After quarreling for a while with core data and bindings, I’ve suddenly felt a need to deliver my conquers to a larger public. So here follow some notes I haven’t found in Cocoa documentation.

Core data and modal dialogs

Simply note this: core data doesn’t work correctly in application modal windows, you will rather use document modal windows. (i.e. tables are not continuously updated but need a fetch: button). This means that if you have a sheet window associated to a document window you MUSTN’T USE

[NSApp runModal];

Instead you will have something like this:

….

– (void) openPanelAsSheetFor:(NSWindow*)window
{
NSWindow *mainWindow=[NSApp mainWindow];
if( mainWindow )
{
[NSApp beginSheet: [self window] modalForWindow:mainWindow modalDelegate: self didEndSelector: @selector(didEndSheet:returnCode:contextInfo:) contextInfo: nil];
}
}

– (IBAction)applyAction:(id)sender
{
[NSApp endSheet:[self window]];
}

– (IBAction)cancelAction:(id)sender
{
[NSApp endSheet:[self window]];
id document=[[NSDocumentController sharedDocumentController]currentDocument];
if( [[document undoManager]canUndo] )
[[document undoManager] undo];
}

– (void)didEndSheet:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
{
[sheet orderOut:self];
}
Bindings to selected item in a table

Let’s suppose you have a main table displaying a list of Depatments. A second table displays people employeed in the selected department. The first table will have its own departmentController (NSArrayController), the second one will have a selectedDepartmetController (NSArrayController) with the contentSet binding bound to departmentController; controller key: selection; model key path: employees.

Different kind of entities in a single table with add/remove buttons.

Obviously, provided that all entities have a common ancestor, it’s sufficient to set as NSArrayController, the ancestor entity. If you need to add different kind of entities, you will provide different buttons connected to the add: action of the relative NSArrayController (circleController for circle entities, rectangleController for rectangle entities and so on…). The remove button must be connected to the remove: action of the ancestor entity controller.

Problem: if I add an entity, I haven’t yet found a way to select it in the common entity table.

Another problem is about implementing a master-detail interface. Let’s suppose you have a table showing Rectangle and Circle entities with Shaper as common ancestor. When you operate a selection you want to display width and height attributes for rectangles and radius attribute for circles. First you create a tabView and bind the selectedLabel to Shape NSArrayController, with selection as controller and entity.name as model key path. All you have to do is to rename the tabs as your entities (i.e. Rectangle and Circle).

The second problem arises when you try to bind a derived entity’s attributes. First of all, you MUSTN’T bind UI elements (i.e. edit fields) to the derived entity array controller but to the ancestor’s one. So you will bind radius to Shape NSArrayController. Since it may cause an exception due to the fact that when you select i.e. circle, edit fields inhereting rectangles ask for width and height attributes which the current selected item has not, you MUST deselect in the Value binding the ‘Raises for not applicable keys’ tag.

Go top