views:

46

answers:

3

Currently I have one managedContext, many NSArrayControllers of entities which are all pretty interrelated, and several Windows which each make use of 1 or 2 of the NSArrayControllers. The windows use core data bindings, all set up via cocoa bindings done in IB

I have 1 nib (xib) right now with everything in there. Often when using my application I'll only open one of these windows and I don't want to load everything else. So, as recommended by Apple and common sense, I want to break in to many nibs (one for each Window ideally)

I'm OK as far as how to load separate nib files, but how can I split this all up and still keep them linked to each other? It seems that when I create a new nib I can't connect between that and another. That makes sense for a lot of reasons, but then how do I go about this? Do I simply switch to doing all bindings programmatically and at nib load I set up my bindings then? Maybe it makes sense to put all my NSArrayControllers in a central nib and load them all at once, and then load up each Window's nib when I access that functionality and do the bindings at that point?

A: 

You will have to create the necessary bindings in code. I don't know the architecture of your app but in general I would recommend to share the context among the different windowcontrollers of your nibs. Within each nib you can bind your (array, tree, object, ...)controllers the context.

mmalc samples give a good explanation of how bindings work.

ADC on Bindings

Martin Brugger
Right but as I described in other comment here, where do I keep interrelated array controllers, and can I do any bindings in IB at that point or does it all become a programmatic task?
Nektarios
A: 

You can't connect between nibs but if those nibs share a controller you can connect through that controller. In addition, as you create these new windows you can pass in the NSManagedObjectContext to the new nib and then bind to it.

As an example, if you had the NSManagedObjectContext configured in your AppDelegate (most common) then you could pass that NSManagedObjectContext to the next window as the AppDelegate creates it. In the nib associated with that window, you can then set up a binding to that NSManagedObjectContext property on the window's controller and bind to it.

update

Any object can be referenced across nibs so long as it is in your controllers somewhere. However referencing array controllers across windows is a bad design in general. If you want the selected item passed around then consider passing around just the object using notifications or something. Hard wiring everything is very fragile and an indication that there is something wrong with the design. MVC and dependency injection are the two designs you should be aiming towards in general.

Marcus S. Zarra
Understand MOC; what about NSArrayControllers? I have NSArrayController "Employee" and "Tasks"; in window A I can select employee by name in a NSTableView, in window B I show an NSTableView of tasks based on selected employee in window A. Window C has an NSPopUpButton of Employee names and NSPopUpButton of Tasks, these both sync w/the values shown on window A and B. Can NSArrayController objects be defined using IB, or should they all be created programatically in AppDelegate ? Must I programatically do my bindings between views and these NSArrayController objects when I load a nib?
Nektarios
A: 

It's a design mistake to connect view controllers (VC) together to tightly. Passing a chunk of data one-way is usually okay for small apps but ideally you don't want to even do that.

Ideally, the data model and only the data model remembers data between views/VCs. Each VC communicates only with the data model and its view. The design goal is to make have each VC controller encapsulated such that it could work standalone without reference to any other view.

The key to accomplishing this is to realize that the data model is the actual core of the application. That is where the critical logic of the app resides. A well designed data model should be UI agnostic and be able to support any kind of interface. For example, the same data model should support a views UI, a web page UI, a command line UI or a scripting interface.

For example, suppose you had an app with a core function to capture two numbers, save them, add them together and return the result. It would be tempting to just do the addition in the VC and immediately display the result. However, since this is a core function, the data model should do the adding. That way, any view or any interface can easily add the numbers just by referring to the function in the data model. If you want to add additional views, each new VC just needs to know about the data model, not any of the other VC.

This also has the practical virtue of making it easy to break the app up into multiple nibs. Each VC gets it own self-contained nib. Since each VC communicates only with the data model, you can load the nibs only when needed and in any order (as long as the data for the VC is in the data model.)

You probably need to back out and reconsider your overall app design. Move the logic and data that connects the VC together into the data model. Then it will be simple to break the VC up into modular nibs.

TechZen
So you're saying not to use bindings like "selection" between 2 NSArrayControllers - instead get the selection of NS*View1 via Controller1, bring that to my model, then from the model I'd send data out to Controller2 to say "Employee X selected" and based on that NS*View2 would display relevant data. Do I understand you?So instead of tightly integrating VC's and having Controllers 'talk', focus on M/C side? I dont see how it's good design for the Model to know what's selected or tell Controllers about what other Controllers have selected or not; it's UI, my model doesn't care
Nektarios
If the selection of one controller alters the logic of the application then it should be in the model. A model is not a passive store. It should contain logic. A good way to think of this is how you would script the data model from external code. If the data model doesn't track which object the script is interested in how could it perform operations on it? You don't have to put this logic/memory in Core Data. If its application state data you can put it in the user defaults. The goal is to decouple VC from each other. If you don't, then your app becomes a spaghetti snarl of interdependency.
TechZen
But the selection of a controller does not change the logic of an application, it just changes the context of what appears in another view. Selecting Employee entity name attribute "TechZen" in a view means that the NSArrayController2 showing Tasks will show TechZen's tasks. That's the only dependency. The model has knowledge of all employees and all tasks. My design as explained in OP, controllers dictate what shows up in views, when actual data is entered it goes back to Model which processes the dataMaybe I am not being clear
Nektarios
Are you (1) attempting to create separate nibs for each window or are you (2) trying to create separate nibs for each view such that each window loads several nibs? If (2), then you really have no option but move the logic to the model if you use binding because you can't bind across nibs. Each nib/view will require its own controller. Don't be afraid to duplicate controllers if if improve modularity. That is what controllers are for.
TechZen
I'm doing #1, again with the current question being what nib should be NSArrayController instances live in, and how/when should I set cocoa bindings between them and the NSTableViews etc. I'm confused about "Don't be afraid to duplicate controllers" - can I have 2 NSArrayControllers that both handle Entity: EmployeeCoreDataEntity, one in each NIB, hook it up properly within that NIB, and bind it to the MOC and that will be ok?
Nektarios
`"Selecting Employee entity name attribute "TechZen" in a view means that the NSArrayController2 showing Tasks will show TechZen's tasks. That's the only dependency."` If this all happens in the same window loaded from the same nib then its not a problem. You just bind one controller to the other. If you want it to happen in different windows then you have to pass the selected data. It is more modular to either mark the data in the model or store a reference in user defaults. That way, you don't have to worry track all the connections between controllers.
TechZen
Yes, you can and should have a separate controllers for each nib. The purpose of the controllers is to bind each UI element to the model. You create as many of them as you need, where you need them, to match the interface. They are not unique objects. Normally, each nib has it own set of controllers even if the UI of the nib duplicates the function of another nib.
TechZen