Re: Multiple views in a nib file?
Re: Multiple views in a nib file?
- Subject: Re: Multiple views in a nib file?
- From: Graham Cox <email@hidden>
- Date: Mon, 24 Nov 2008 21:38:50 +1100
On 24 Nov 2008, at 7:56 pm, Jean-Nicolas Jolivet wrote:
mm interesting reading!... I'm trying to see how I could implement
this in my case...I used the "Tool" example as it seemed easier to
explain but basically, what the abstract class represents is an
"Operation" (just a simple operation performed on some text...)..
example of subclass could be "Insert text Operation", "Replace Text
Operation" etc... basically an operation has some parameters
(textToInsert, textToSearchFor etc..) and it takes some text,
performs a transformation on it and returns a string... the custom
views are just used to set those operation's parameters (text to
insert etc..)... I thought of several way of doing it but since an
operation could have boolean, int or string parameters, I figured
having a custom view for each operation would be the way to go...
So to sum it up, each operation has a set of parameters, controlled
by a custom view ... but the user can add as many operations as he
wants (so it's not really like there will be only 1 instance of each
operation... which makes things a little more complex than if it
were just a tool...)
This sounds similar to a couple of things in my app.
In one case, I have a search mechanism that finds objects based on
matching a list of criteria. It's conceptually much the same as
predicate filtering but the code predates the existence of predicates
so it rolls its own. I have an object that represents the query and
it's pure model - it takes an array argument and returns an array
argument which is the subset of the input that matched the query. This
sounds sort of similar to your operation object. Each separate clause
of the query is modelled using another object, of which the query can
have any number, stored in a list.
I also have a UI for editing and creating the query which again has a
modern equivalent in the NSPredicateEditor but which I wrote myself
prior to that being available. It works by having one sub-controller
per 'clause' as well as an overall controller for the whole query.
Each clause has an implicit data type (think of matching a string, in
which case the data type is a string, or matching a value, in which
case the data type is a number) and each data type has an associated
set of controls in a view, so each data type maps to one of several
different views. There are about 6 or 7 data types, so my nib has 6 or
7 views which contain the appropriate controls. When the user adds a
clause to the query, adding a row of controls to the UI, they pick a
property from a menu for what to search on, and this finds the data
type that that property is associated with, makes a controller for it,
and installs the matching type of view (the view is copied from one of
the predefined prototype views), so the UI is correct for the data
type. The overall controller simply has outlets to all the different
"flavours" of view and simply returns the right one, copied, given the
data type for that row.
When I wrote this one I hadn't thought of the naming convention +
valueForKey: idea, so it currently hard-codes the look up of the
outlet in a switch/case statement, which is OK but could be done
slightly more cleverly. If I added new data types I'd have to modify
this code to match.
Given that the query object itself is pure model, it knows nothing
about this UI stuff. The 'clause' object doesn't have or need a view
outlet, but it does have a data type, so the controller uses that to
look up a view. In this case, note that the same view can be installed
many times, which is why I copy it, since the same data type can be
associated with different properties.
In the second case, I have a style object that applies graphical
attributes to objects. Again any number of attributes can be applied
and the overall style object contains these in a list. Though this
does drawing, it's model in that the attributes are graphical
properties of objects in my data model. There are numerous kinds,
about 16 different classes at the moment.
The UI to set the parameters for the attributes is a master/detail
interface, the master being an NSOutlineView (the attributes can be
arranged in hierarchies) and I switch in a view appropriate to the
class of the selected item. This uses the naming convention +
valueForKey: approach. Each class of attribute has its own sub-
controller which uses KVO to observe the attribute model object. Each
sub-controller has an outlet to all of the controls appropriate to the
class it's controlling, as well as an outlet to the custom view that
contains them all (this is used to insert the view in its entirety
into the hosting view in the window). In this case the mapping is from
the class of the attribute to a specific controller so my outlet
naming convention is derived from the class name of the original
attribute object. All I do is when the master selection changes, I get
the attribute model object at that row, do some string manipulation on
its class name (using NSStringFromClass() + stringWithFormat:) to
derive the outlet name, then get the outlet using valueForKey: Once I
have that I can get its view and insert it as a subview into my window.
Again the attribute object itself knows nothing about the UI at all -
it merely has properties that a controller can observe and set. The
overall controller for the editor in this case uses the class name to
map to a given sub-controller and then to its views. The nib for this
UI is quite complex in that it contains 16 different kinds of
controllers, one per class, and in turn 16 different custom views,
each loaded with all the controls for the properties of the associated
attribute class. But so what, it loads quickly and works a treat.
There could be an overhead in that views are loaded into memory even
for classes that may never get edited in a given session, but I doubt
that the memory overhead can be that excessive (if we were talking
>100 classes rather than 16, I might reconsider), and if you do need
to add a new attribute, its editor is presented instantly.
As I mentioned, one advantage I found was that the overall controller
doesn't need to know about all of the different possible class types
it might encounter, it only requires that I stick to my naming
convention - I don't have to modify the code to add new types, I just
add a new outlet for the new sub-controller. In this case each view is
unique to the class of selected object and only one is shown at a
time, so unlike in the first case I don't copy it but instead just
install it directly.
One thing that is common to both of these things is that the
arrangement of controllers and subcontrollers very closely mirrors the
arrangement of the model objects themselves. (Query object + list of
clause objects -> Query controller + list of clause controllers; Style
object + list of graphical attributes -> Style controller + list of
attribute controllers). It seems to me that this is a good rule of
thumb - your controller(s) will probably fall into place if they
follow the design of the model - I've certainly found that to be the
case anyway.
Hope this is helpful, and if anyone reading this thinks I've missed
something really obvious about how to do this stuff, I'd really like
to know!
cheers, Graham
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden