If I changed my NSOutlineView from using bindings and an NSTreeController to having a data source and a delegate, how would I automatically update the NSOutlineView, if my model tree changes? Should I observe the childNodes property of every single node in my tree with my controller and trigger a reload when a change occurs? Or is there another way?
That's one way. Another way would be for the model to post notifications when it changes and have your controller observe those.
Also, a model doesn't typically change spontaneously. Usually, the change is initiated outside of the model in response to some event. A controller is usually doing that. So, that controller could also provoke an update to the outline view. (There may be multiple controllers, so maybe the controller that initiates the model change just informs a window or view controller, which would be responsible for updating the outline view.)
I asked a similar question that was marked as duplicate here: Recommended Pattern for Observing Changes in Tree Structure [duplicate]
I wanted to avoid using NSTreeController as it means you lose control of animations when updates occur.
I have an MVVM set up. My model is a graph, my view model is a tree. There is a one-one relationship between any tree nodes and a graph node. As detailed in the question above, there is obviously a many-one relationship between the tree nodes and an outline view.
So, I settled with...
The view-model tree nodes need to know when their children are updated, so I used KVO of the associated graph node to catch when children are added or removed.
For the outline view update I settled on a model-view delegate that I implement on the view-controller. Each tree-node in the view model can call delegate methods on the tree root when children are added or removed. This felt the clearest approach to me, and easily debuggable. I didn't want chains of things happening behind the scenes.
The final outline view update call felt satisfyingly simple:
func itemsInserted(atIndexes indexes: IndexSet, forParent parent: ECViewModelNode) {
outlineView?.insertItems(at: indexes, inParent: parent, withAnimation: .slideDown)
}
At the table-cell-view level I bind directly to the details of the graph model nodes.
Related
I'm a little confused about input processing in regards to Apple's MVC pattern. According to Apple, your objects should be divided into model objects (which handle the data), view objects (which display stuff), and controllers (which bind the two and also process events and input). However, many of Apple's native UIKit views — UIScrollView, UIControl objects, etc. — do all the input processing themselves, possibly letting their controllers know about it via delegates and data sources. This really confuses me. In my mind, the sturdiness of the MVC triad depends on both the model and view being fairly dumb (and thus easily swappable). When all the OS-level event complexity is centralized in the controller, you have a very nice separation of concerns. On the other hand, adding input processing to the view seems to turn it into a sort of controller of its own.
Am I missing something here? What's the correct way to think about this?
User Input is part of the View in the MVC pattern. They directly interact with the user and provide their data, either on request or through delegation, to a Controller, which might then use that input to affect changes to the Model.
"Dumb" and "easily swappable" are not necessarily the same thing.
Buttons contain a lot of functionality that we don't want to rewrite in every single controller: tinting of the image to indicate highlighting, allowing for cancellation if the tap strays a certain distance before touch-up, etc. Scroll views contain a lot of physics.
In other words, "which display stuff" is a mischaracterisation of view objects. UIView -- the base class -- just provides event data, but subclasses provide higher-level data such as "the button was tapped" or "the scroll view decelerated to a stop".
One thing to think about is your perspective.
When most of us code, our Model is a data object (maybe backed by files or databases, etc), our View is a UIView (possibly setup/configured in Interface Builder) and our Controller is the UIViewController.
What if you weren't coding an app though? What if your world was a UITableView? You can still have a basic MVC separation. Your Model is represented by the UITableViewDataSource protocol, your View still a UIView with it's setups and configurations and your Controller is the UITableViewDelegate protocol. All the pieces there and even separated, the separation is just different than when using a UIViewController. You can see a practical example of the separation a data change. When you the data in the data source protocol nothing happens. You have to call a reloadData method on Controller bit for the table to realize data was changed.
The smaller the item, the harder it will be to see the MVC pattern. A "button" would be a lot harder to use if it was broken into 3 different objects, but you can use MVC patterning inside a single object to create well encapsulated. A UIButton has it's Model in the form of a both public and private properties, a View (UIView still) and a Controller which is bunch of code that accepts events and makes modifications to the View and/or Model as appropriate.
I would like to know if there are any apple Xcode APIs for monitoring state changes before I attempt to build my own. The app I work on changes out several View Controllers. Each controller can have a couple smaller custom views plus the usual check boxes, text fields etc.
The main app needs to know if a view controller or anything on it is edited from its previous state when it is pulled up before it is saved again. We only need to know if the state has changed. The caveat is this: if a user checks a checkbox , that is considered a change of state, but if the user also unchecks the check box, then the state is not changed.
I was looking at the NSUndoManager but I'm nor sure if it will work.
Any suggestions appreciated
There are a couple of approaches:
Implement a centralized "model" object. In this scenario, view controllers would just update properties of this main model object and there's little else you have to do. View controllers would then, in viewDidAppear, check the state of this model object and see if anything changed and act accordingly.
Another approach would be to implement a delegate-protocol pattern, by which the various controllers might have some delegate property that would indicate what object must be informed of data changes. This object that would be the data delegate would be defined to conform to some well defined protocol that indicate how to inform it of the changes.
If, though, you (a) have multiple objects that need to be informed of changes; and/or (b) these changes might happen asynchronously while a view is presented, you need some mechanism to do this notification. The two common approaches would be either with key-value-observing of that model object or by posting a custom notification to the NSNotificationCenter.
To advise you better, we'd need a better sense of the nature of your model object, whether updates are happening asynchronously in the background, etc.
Maybe it is a dumb question but I would like to know when we have to or when it is recommanded to create new class. This is not really clear in my mind. For now, I've only one class per Controller and that's it... All my code is in this class.
I think it could be better...
Regards
If you're following the MVC pattern, for the most part your classes should be separated into one of those categories:
Controllers: UIKit/NS view controllers, which are responsible for presenting views and receiving messages from interactive elements on those views.
Views: If the view presented by one of your controllers requires a lot of custom logic in order to present itself, it might be a better idea to separate it into its own class. In essence, this is done when creating views using Interface Builder (.xib files).
Models: Objects that encapsulate logic in your application.
For example, if you are building an RSS viewer according to this design pattern, you'd likely make the following classes:
Models representing an individual RSS item, as well as one that represents an RSS feed. If you roll your own RSS feed parser, you would want to isolate the logic required to fetch entries within another class.
Controllers to handle displaying the feed and individual views. Controllers should only be concerned with presenting data. In the case of an RSS viewer on iOS, you would likely use a UINavigationController with a root view controller of the UITableViewController class. Tapping on a table cell pushes another UIViewController responsible for displaying an individual RSS item.
While the UITableController has a default view to display a list of items, the individual item likely needs custom logic to be displayed well. You might want to create a view class or .xib to present these. The UIViewController is responsible for populating data on the view (setting values on IBOutlets on the .xib, etc).
As a general guideline, you should try to adhere to the single responsibility principle--every class should have a single responsibility, and it can perform its tasks more or less autonomously.
In this vein, controllers are responsible for handling the display of a single kind of view and for delegating messages from that view. Views are responsible for displaying data. Models are responsible for the singular purpose they were created for--an RSS item for mapping data from an RSS feed to an object, an RSS feed object for managing a group of RSS items (adding, removing, possibly fetching more via an NSURLRequest).
Note: Your question is a bit vague according to Stack Overflow guidelines, so that may be why it is being down-voted. Consider adding a specific example or description of the dilemma you're facing.
I am trying to figure out the purpose of what the .parent property achieves in this method and the "get[ClassNameHere]" methods in general that feature this property being called.
-(HudLayer*) getHud
{
return (HudLayer*)[self.parent.parent.parent getChildByTag:kTagHudLayer];
}
It's not possible to know the details from just this method shown here. But the .parent does return the Cocos parent, sprite or layer, to which the current cocos object belongs as a child. Essentially this code suggests you have a sprite or layer with a child that has more children and more children of those children, and this is a way to find out who the big parent up the stream is, and then get a new child from that parent.
Personally it seems pretty sloppy to me. I'd never code that way myself. Hard to read (as you can see) and having so many parent properties strung together like this is opening a lot of room for bugs. It would be wiser if the top parent did what it needs to do rather than a distant grandchild going up the chain; it breaks the MVC model a bit to do it as shown here.
Probably class HudLayer has a parent property that points to another object of the same kind, thus having a parent property pointing to another HudLayer and so on, climbing up for three levels. Then it just sends a getChildByTag message to it.
I'm trying to re-implement an old Reversi board game I wrote with a bit more of a snazzy UI. I've looked at Jens Alfke's GeekGameBoard code for inspiration, and CALayers looks like the way to go for implementing the UI.
However, there is no clean separation of model and view in the GeekGameBoard code; the model is the view, which makes it hard to, for example, make a copy of the game state in order to perform game-tree search for the AI player. However, I don't seem to be able to come up with an alternative way to structure that allows a separation of model and view that doesn't involve a constant battle to keep two parallel grids (on for the model, one for the view) in synch. This, of course, has its own problems.
How do I best best implement the relationship between an AI search-friendly model structure and a display-friendly view? Any suggestions / experiences would be appreciated. I'm dreading / half expecting an answer along the lines of "there is no good answer: deal with it as best you can" but I'm prepared to be surprised!
Thanks for the answer Peter. I'm not entirely sure I understand it fully, however. I can see how this works if you just have an initial set of pieces that are moved around, and even removed, but what happens when a person puts a new piece down? Would it work like this:
User clicks in the view.
View click is translated to a board location and controller is notified.
Controller creates a new Board with the successor state (if appropriate, i.e. it was a legal move).
The view picks up the new board via its bindings, tears down the existing view/layer hierarchy and replaces it with the current state.
Does that sound right?
PS: Sorry for failing to specify whether it was for the iPhone or Mac. I'm most interested in something that works for the iPhone, but if I can get it to work nicely on the Mac first I'm sure I can adapt the solution to work on the iPhone myself. (Or post a new question!)
In theory, it should be the same as for an NSView-based UI: Add a model property (or properties), expose it (or them) as bindings, then bind the view (layer) to the model through a controller.
For example, you might have a Board class with Pieces on it (each Piece having a reference to the Player who owns it), with all of those being model classes. Your controller would own a Board, and your view/layer would be able to display a Board, possibly with a subview/sublayer for each Piece.
You'd bind your board view/layer to the controller's board property, and in your view/layer's setter for that property, create a subview/sublayer for each piece, and bind it to any properties of the Piece that it will need. (Don't forget to unbind and remove all the subviews/sublayers when replacing the main view/layer's Board.)
When you want to move or modify a Piece, you'd do so using its own properties; these will translate to property accesses on the view/layer. Ostensibly, you'll have your layer's properties set up to animate changes (so that, for example, changing a Piece's position will cause the layer for it to move accordingly).
The same goes for the Board. You might let the user change one or both tile colors; you'll bind your color well(s) through your game controller to its Board object, and with the view/layer bound to the same property of the same Board, it'll pick up the change automatically.
Disclaimers: I've never used Core Animation for anything, and if you're asking about Cocoa Touch instead of Cocoa, the above solution won't work, since it depends on Cocoa Bindings.
I have an iPhone application where almost all of the interface is constructed using Core Animation CALayers, and I use a very similar pattern to what Peter describes. He's correct in that you want to treat your CALayers as if they were NSViews / UIViews and manage their logic through controllers and data via model objects.
In my case, I create a hierarchy of controller objects which also function as model objects (I may refactor to split out the model components). Each of the controller objects manages a CALayer, so there ends up being a parallel CALayer display hierarchy to the model-controller one. For my application, I need to perform calculations for equations constructed using this hierarchy, so I use the controllers to provide calculated values from the bottom of the tree up. The controllers also handle user editing events, such as the insertion of new suboperations or deletion of operation trees.
I've created a layer-hosting view class that allows the CALayer tree to respond to touch or mouse events (the source of which is now available within the Core Plot project). For your boardgame example, the CALayer pieces could take in the touch events, and have their controllers manage the back-end logic (determine a legal move, etc.). You should just be able to move pieces around and maintain the same controllers without tearing everything down on every move.