Thanks a lot for your reply! It does help a lot to see how someone else implemented a similar concept!... I love the multiple controllers (1 per subclass) / Multiple views (again, 1 per subclass) idea... I'll try to implement it for my situation as it seems to be the best way to go...

I'll let you know if I hit a dead end!

Again, thank you!

J-N

On 24-Nov-08, at 5:38 AM, Graham Cox wrote:


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




Jean-Nicolas Jolivet
[EMAIL PROTECTED]
http://www.silverscripting.com

_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to [EMAIL PROTECTED]

Reply via email to