Filtering breaks bindings-enabled app
Filtering breaks bindings-enabled app
- Subject: Filtering breaks bindings-enabled app
- From: Dan Stein <email@hidden>
- Date: Mon, 24 Jan 2005 20:13:20 -0800
Apologies if this reads like a dissertation prospectus. I'm not
competent to draw you any object graphs you could use.
This is a straightforward document-based app centered on a table-view,
and implements undo and pasteboard for both rows and cells in the
table. Inspectors/Data Entry Fields are bound to three user-editable
table columns. Values in a fourth column are computed by a process that
takes place when an auxiliary window is opened and operated. The view
is bound to the array controller by specifying the model key path (for
the table columns) following the usual examples pretty much to the
letter. Most of the important controls are implemented in a standard
toolbar, backed up by items in the various menus.
There are two model classes: the first encapsulates the data in a
single table row and the second handles the array and some ancillary
view data specific to a single document. The document class archives
the second model class; the way this is done is to copy over the
current array returned from the array controller's arrangedObjects:
method when the saveDocument: operation is ordered. (Some conditions,
such as filtering, to be described below, disable the Save action and
require the user to use Save As...). Again nothing fancy: this level of
the app allows the user to edit the table and save it. Here, for
example the insert and delete toolbar buttons are targeted in the array
controller, on selectors for insert: and remove:.
FIRST QUESTIONABLE DESIGN DECISION: To support the undo manager and
pasteboard, the document class also declares a separate array that gets
bound to the array controller's content array by setting that in the
controller's bindings pane in IB. I have read the documentation to
indicate that this array should change in lock step with insert: and
remove: messages to the array contrroller. Document methods insert and
remove objects from this array and start and stop observing of them.
This more or less follows the design suggestions in Aaron Hillegass'
introduction to bindings and KVO in the second edition of his book.
(NOTE: By using the word "questionable", above, I do not mean to imply
that Aaron's design suggestions are faulty, only that they might not be
appropriate for my app. But see below.)
I implemented filtering from a search field in the toolbar as sketched
out in mmalcolm Crawford's "Filtering Controller" example, and even the
feature of adding new rows unconditionally during filtering. I assume
the problem of removing rows during filtering has the usual solution
presented in non-Bindings examples of enumerating the content array and
copying the selected records to a buffer array before deleting the
contents of the buffer array from the original, though I have not tried
this yet. I also note that the table view's selectedRowEnumerator
method is now deprecated, and have started to use NSIndexSet in this
app.
SECOND QUESTIONABLE DESIGN DECISION: I implemented a second type of
filtering by creating a support table in the main document view that
contains a list of all the unique strings in one of the table columns.
When an item is selected from this table, the main table is filtered to
display only those rows containing the selected string in the column of
interest. This feature supports selecting multiple strings in the
support table for aggregating rows. It also works seamlessly (for
filtering, at least) with the search field in the toolbar. Looks good,
but something is broken deep inside my app, because when this filter is
active I can no longer force new rows into the table as I can with the
search field, even though the logic that performs the filtering in the
array controller's arrangeObjects: method is pretty much the same as
for the search field, except that an enumerator is required to examine
( for all the rows in the main table; nested: for all selected rows in
the support table: see if the string from that table matches the one in
the appropriate field in the main table.)
If I don't force new entries into the filtered table, I get messages
that new entries could not be inserted at the index after the last
displayed item. If I do force the entries, I get two instances of the
new row, which I can delete, but if I do not, the program crashes on
exit with a SIGBUS. Perhaps I am forcing it to write beyond the bounds
of the filtered array. Some permutations give me error messages about
the old "double free". On attempting to delete objects, some or all are
escaping from the KVO message to stop observing them, evidenced by
error messages to that effect. It is an ugly mess.
I've been staring at this problem off and on for a week and I am
getting more and more despondent. If I have omitted any crucial
details, you might be able to ask for the missing piece, or the above
description may make no sense at all. Needless to say, I am not eager
put the sources out there, particularly in this condition, and probably
no one is eager to see it: it is hundreds of lines already with other
features that have nothing to do with filtering. If anyone can offer
helpful suggestions or questions after reading the above, I will be
eternally grateful. Or should I just trash the last four weeks of work
and begin again. This would not be so bad, as I have notes describing
most details of the development. But I would dearly love to salvage
this work.
Of course the "trivial" solution is to remove this filtering feature;
then I would have a "trivial" application that merely duplicates
snippets from all sorts of table view examples, including pasteboard
and undo. Even with the second filter, it is not going to be anything
astonishing. The bug informs me that I have gone off half-cocked (or
would that be half-clocked?) regarding bindings. This is probably a
good candidate for implementing some manual bindings, but I have no
clue where to begin.
Additional notes: The windowController is the delegate of both table
views. The second (support) table notifies the window controller that
the user changed the selection in that table. When this notification is
received, the array controller is sent a rearrangeObjects: message in
order to update display of the filtered content array. The window
controller sends itself a message to update the ancillary table anytime
it gets a controlTextDidChange from the main table (the rationale is
that the user might have edited the field that the ancillary table is
interested in.) Along with arrangeObjects:, the array controller just
overrides insert: and remove:, but does not do much more than call the
super and try to send notifications to the window controller and update
the support table. These are probably not all necessary.
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden