beyond MV and (one) C

  • Chapter 5 section 4 is about the target action paradigm. If you mean
    Chapter 4 (Cocoa Design Patterns) I had read that (and just reread
    it), but I don't see obvious answers to my question. Maybe a clue is
    buried in the discussion of mediating and coordinating controllers.

    "In a well-designed Cocoa MVC application, coordinating controller
    objects often "own" mediating controllers, which are archived in nib
    files."

    While that gives me a vague sense that I should explore the canned
    controller classes (and bindings), it says nothing about how many
    controllers to use for the various model parts. If I understand what
    they're saying (and that's a big if), my case boils down to this:

    model-controller to choose file type (NSWindowController?) => window 0
    model for parsing file type 1 => regular (homemade) controller =>
    window 1
    model for parsing file type 2 => regular (homemade) controller =>
    window 2
    model for parsing file type 3 => regular (homemade) controller =>
    window 3

    I've tried to read all I can about NSWindowController, I don't quite
    understand where they fit in, especially if used outside of the
    document architecture (which I'm not using yet).

    ÔÚ Jan 12, 2008£¬8:40 PM£¬<cocoa-dev-request...> дµÀ£º

    >> In the MVC paradigm, do you typically use a different controller for
    >> each major interface?
    >>
    > This is discussed in  <http://developer.apple.com/documentation/
    > Cocoa/Conceptual/CocoaFundamentals/CocoaDesignPatterns/
    > chapter_5_section_4.html
  • On Jan 13, 2008, at 8:59 AM, Daniel Child wrote:
    >>
    > Chapter 5 section 4 is about the target action paradigm. If you mean
    > Chapter 4 (Cocoa Design Patterns)
    >
    ??
    When I click on the link, it takes me straight to "The Model-View-
    Controller Design Pattern".

    > I had read that (and just reread it), but I don't see obvious
    > answers to my question. Maybe a clue is buried in the discussion of
    > mediating and coordinating controllers.
    >
    The section on mediating and coordinating controllers deals entirely
    with your situation -- I'm not sure why you think there's just a clue
    buried in there?

    > "In a well-designed Cocoa MVC application, coordinating controller
    > objects often "own" mediating controllers, which are archived in nib
    > files."
    > While that gives me a vague sense that I should explore the canned
    > controller classes (and bindings), it says nothing about how many
    > controllers to use for the various model parts.
    >

    The controller is what's mediating between the model and the view
    ("Controller Objects Tie the Model to the View").  The number of model
    parts is largely immaterial -- it's how you want to display them
    that's important.  For example, if you're displaying an array of
    objects in a table view, it doesn't matter how many objects there are
    in the table view, you still have one table view and (in the basic MVC
    case) one controller...
    Additional controllers come into play if you want to devolve
    responsibility for managing a fairly self-contained subset of the UI
    to a separate controller.  NSWindowController is perhaps the "biggest
    granularity" example where rather than an NSDocument instance being
    responsible for multiple windows it can devolve responsibility to
    individual window controllers.  A window controller might then devolve
    responsibility for managing, say, a table view to an NSArray
    controller.  Or for a custom view you might implement your own
    NSViewController. It's all up to you to decide how you want to factor
    out the workload.

    mmalc
  • On Jan 13, 2008, at 10:35 AM, mmalc crawford wrote:

    > The controller is what's mediating between the model and the view
    > ("Controller Objects Tie the Model to the View").  The number of
    > model parts is largely immaterial -- it's how you want to display
    > them that's important.  For example, if you're displaying an array
    > of objects in a table view, it doesn't matter how many objects there
    > are in the table view, you still have one table view and (in the
    > basic MVC case) one controller...
    >

    "it doesn't matter how many objects there are in the table view" ->
    "it doesn't matter how many objects there are in the array"

    > Additional controllers come into play if you want to devolve
    > responsibility for managing a fairly self-contained subset of the UI
    > to a separate controller. [...] It's all up to you to decide how you
    > want to factor out the workload.
    >
    Since the mention of the various NSControllers (in the Design Patterns
    article) seems to be confusing, perhaps it might be worth thinking
    about how you might factor out similar controllers yourself.

    Suppose you have a corpus containing a number of documents, and you
    want a table view that presents to the user the title of each document
    so they can select one.  You'd have a controller managing the corpus,
    and acting as the table view's data source.  Suppose then each
    document is divided into sections, and you want to display in another
    table view the titles of each section of the currently-selected
    document.  Again the original controller can manage this, and serve as
    the data source for this new table view.

    The controller can readily enough provide data for each table view
    because the table data source methods include a reference to the table
    view:
    - (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView

    The problem, though, is that the code for managing the table view
    starts to become messy:

    - (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView

    {
        if (aTableView == documentsTableView)
        {
            return [documentsArray count];
        }
        if (aTableView == sectionsTableView)
        {
            return [sectionsArray count];
        }
        // ...
    }

    So rather than putting all the code into one controller, you could
    implement separate controllers -- DoucumentsTableController and
    SectionsTableController -- to manage just the table views. You tell
    each one which array it's managing, and if the array is mutable you
    provide suitable methods to allow content changes to be communicated.
    They'd implement the relevant table data source methods, but since
    each is only responsible for a single table view you end up with
    simpler code.  When you look at the code for the two, you notice that
    it's very similar -- and if you're able to leverage KVC to get and set
    the document and section attributes, it may well be identical.  So you
    can refactor them into a single generic table controller that you can
    also reuse elsewhere.  And if you abstract this sufficiently, and
    leverage other technologies (KVO, KVB) as well, you end up with
    NSArrayController.

    mmalc
  • On Jan 13, 2008, at 1:35 PM, mmalc crawford wrote:

    > Additional controllers come into play if you want to devolve
    > responsibility for managing a fairly self-contained subset of the
    > UI to a separate controller.  NSWindowController is perhaps the
    > "biggest granularity" example where rather than an NSDocument
    > instance being responsible for multiple windows it can devolve
    > responsibility to individual window controllers.  A window
    > controller might then devolve responsibility for managing, say, a
    > table view to an NSArray controller.  Or for a custom view you
    > might implement your own NSViewController. It's all up to you to
    > decide how you want to factor out the workload.

    I think I understand why you might devolve responsibility to window
    controllers in a doc app. I don't see what they do in a non-doc app,
    however.

    More importantly, how you get the window controllers working in the
    first place? The description of controller objects "owning" mediating
    controllers  (in "MVC Design Patterns") is totally abstract to me
    until I see an example of how this is done.

    To test the idea, I created an app with two nibs:

    MainMenu.nib -- contains WindowA and WindowB
    WindowC.nib  -- contains WindowC

    Each window has a button to reference the other two. (Open Window A,
    Open Window B, etc.)

    MainMenu.nib has an instance of a (typical) Controller (subclass of
    NSObject) that has code for windows A and B.

    WindowC.nib has an instance of a WindowCController that is a subclass
    of NSWindowController, and has code for the actions of Window C
    (openA and openB).

    I can get WindowA to open WindowB, and vice versa, just fine. Both
    windows tie into the CentralController and use the standard target-
    action paradigm. But this design is clearly a mess.

    Using this is forcing me to copy code (openA, openB) into different
    controllers. Not a good idea.

    Also, how will the different nibs know about each other? When I
    instantiate the WindowCController, there seems to be no recognition
    of the fact that I had declared an IBOutlet NSWindow *windowC or
    IBActions (openA, openB). In other words, the instantiated subclass
    of NSWindowController does not behave like a regular controller in
    terms of the target-action paradigm.

    I think my questions may be as much practical as theoretical. How do
    you literally hook up window controllers / open/load separate nibs.
    And do I have to mess around with File's Owner at this point (i.e. in
    WindowC.nib)?
  • On Jan 18, 2008, at 2:09 PM, Daniel Child wrote:

    >
    > On Jan 13, 2008, at 1:35 PM, mmalc crawford wrote:
    >
    >> Additional controllers come into play if you want to devolve
    >> responsibility for managing a fairly self-contained subset of the
    >> UI to a separate controller.  NSWindowController is perhaps the
    >> "biggest granularity" example where rather than an NSDocument
    >> instance being responsible for multiple windows it can devolve
    >> responsibility to individual window controllers.  A window
    >> controller might then devolve responsibility for managing, say, a
    >> table view to an NSArray controller.  Or for a custom view you
    >> might implement your own NSViewController. It's all up to you to
    >> decide how you want to factor out the workload.
    >
    > I think I understand why you might devolve responsibility to window
    > controllers in a doc app. I don't see what they do in a non-doc app,
    > however.
    >
    > More importantly, how you get the window controllers working in the
    > first place? The description of controller objects "owning"
    > mediating controllers  (in "MVC Design Patterns") is totally
    > abstract to me until I see an example of how this is done.
    >
    > To test the idea, I created an app with two nibs:
    >
    > MainMenu.nib -- contains WindowA and WindowB
    > WindowC.nib  -- contains WindowC
    >
    > Each window has a button to reference the other two. (Open Window A,
    > Open Window B, etc.)
    >
    > MainMenu.nib has an instance of a (typical) Controller (subclass of
    > NSObject) that has code for windows A and B.
    >
    > WindowC.nib has an instance of a WindowCController that is a
    > subclass of NSWindowController, and has code for the actions of
    > Window C (openA and openB).

    The nib should not contain an instance of a NSWindowController-derived
    class.  An NSWindowController is intended to be the owner of the nib.
    As such, it's outside of the nib -- "above" it, in a certain sense.
    So, when it comes time to load WindowC.nib, you do:

    WindowCController* myWindowCController = [[WindowCController alloc]
    initWithWindowNibName:@"WindowC"];

    In the nib, you would set the class of File's Owner to
    WindowCController.  You'd also connect its "window" outlet to the
    window in the nib.  Then, anywhere that some other part of the code
    needs to refer to WindowC, you use this expression:

    [myWindowCController window]

    If you want the WindowCController instance to know about the other
    windows, you can add some ivars to it and set them up.  You can do
    that immediately after the alloc-init statement, above, or actually
    define your own custom init... method that takes additional arguments.

    One thing that might be confusing you: you might want a controller
    which manages the window controllers.  Often, there's an application
    controller, which might also be the application delegate.  This
    application controller is what knows about the various nibs and window
    controller classes.  So, it is what would allocate and initialize the
    WindowCController instance, as illustrated above except that
    myWindowCController would not be a local variable, it would be an
    instance variable.  The application controller would also have the
    "global" overview sufficient to connect the various nibs and window
    controllers to each other.

    > Also, how will the different nibs know about each other? When I
    > instantiate the WindowCController, there seems to be no recognition
    > of the fact that I had declared an IBOutlet NSWindow *windowC or
    > IBActions (openA, openB). In other words, the instantiated subclass
    > of NSWindowController does not behave like a regular controller in
    > terms of the target-action paradigm.

    I'm not sure I followed this part.  What does "a regular controller in
    terms of the target-action paradigm" mean?

    Remember that you can target actions to the First Responder, as well
    as a customer controller instance in the nib.  And, if you do that,
    then the application delegate is automatically included in the
    responder chain that will be asked to handle the action.  See <http://developer.apple.com/documentation/Cocoa/Conceptual/EventOverview/Eve
    ntArchitecture/chapter_2_section_6.html#//apple_ref/doc/uid/10000060i-CH3-S
    W9
    >.  So, you can put the openA, openB, and openC methods in the
    application delegate and any of your buttons will be able to invoke
    them.

    It's also perfectly acceptable to target the actions to the File's
    Owner, which would be your custom subclass of NSWindowController.  If
    you're worried about duplicate code appearing in all of your
    controller subclasses, figure out where the responsibility truly
    should live, put it there, and just have the window controllers
    forward the request.  In other words, WindowCController could have an
    openA: action method which just forwards the request to some method of
    the application controller.

    How does a WindowCController get a pointer to the application
    controller?  Well, it could be given one explicitly by the application
    controller when it creates the WindowCController instance.  Or, the
    WindowCController can just use [NSApp delegate].

    -Ken
  • On Jan 20, 2008, at 2:45 AM, Ken Thomases wrote:

    > The nib should not contain an instance of a NSWindowController-
    > derived class.  An NSWindowController is intended to be the owner of
    > the nib.  As such, it's outside of the nib -- "above" it, in a
    > certain sense.
    >
    This is at best misleading.
    It is perfectly reasonable to put an NSWindowController instance in a
    nib file.  An About panel controller or an Inspector controller might,
    for example, be instantiated in the Main Menu nib.

    mmalc
  • On Jan 20, 2008, at 4:58 AM, mmalc crawford wrote:

    > On Jan 20, 2008, at 2:45 AM, Ken Thomases wrote:
    >
    >> The nib should not contain an instance of a NSWindowController-
    >> derived class.  An NSWindowController is intended to be the owner
    >> of the nib.  As such, it's outside of the nib -- "above" it, in a
    >> certain sense.
    >>
    > This is at best misleading.

    In context, it was meant to contrast with what the original poster had
    described -- an NSWindowController instantiated inside of the nib it
    was supposed to be controlling/owning.

    I didn't say _no_ nib should contain an NSWindowController-derived
    class.  I referred to "the nib", meaning the WindowC.nib he gave in
    his example.

    -Ken
  • Ken,

    Your explanation below was super helpful. I tried passing a reference
    to the app controller directly as you suggest at the bottom, and that
    worked.

    Judging from the rest of what you wrote, I see that my next readings
    should be on delegation and the responder chain. I will try those
    approaches next. And as you mention, duplicate code was bothering me,
    so I will try to put the window-opening code all in one place as well.

    Thanks!

    On Jan 20, 2008, at 5:45 AM, Ken Thomases wrote:

    > The nib should not contain an instance of a NSWindowController-
    > derived class.  An NSWindowController is intended to be the owner
    > of the nib.  As such, it's outside of the nib -- "above" it, in a
    > certain sense.  So, when it comes time to load WindowC.nib, you do:
    >
    > WindowCController* myWindowCController = [[WindowCController
    > alloc] initWithWindowNibName:@"WindowC"];
    >
    > In the nib, you would set the class of File's Owner to
    > WindowCController.  You'd also connect its "window" outlet to the
    > window in the nib.  Then, anywhere that some other part of the code
    > needs to refer to WindowC, you use this expression:
    >
    > [myWindowCController window]
    >
    > If you want the WindowCController instance to know about the other
    > windows, you can add some ivars to it and set them up.  You can do
    > that immediately after the alloc-init statement, above, or actually
    > define your own custom init... method that takes additional arguments.
    >
    > One thing that might be confusing you: you might want a controller
    > which manages the window controllers.  Often, there's an
    > application controller, which might also be the application
    > delegate.  This application controller is what knows about the
    > various nibs and window controller classes.  So, it is what would
    > allocate and initialize the WindowCController instance, as
    > illustrated above except that myWindowCController would not be a
    > local variable, it would be an instance variable.  The application
    > controller would also have the "global" overview sufficient to
    > connect the various nibs and window controllers to each other.
    >
    > How does a WindowCController get a pointer to the application
    > controller?  Well, it could be given one explicitly by the
    > application controller when it creates the WindowCController
    > instance.  Or, the WindowCController can just use [NSApp delegate].
    >
    > -Ken
previous month january 2008 next month
MTWTFSS
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      
Go to today