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.
Related
I've got what (I would think) is an extremely simple case where an NSTreeController is bound to an array of root objects, each of which might have a few child objects. I am using an NSBrowser to show them.
They display fine and the hierarchy is correct.
The problem is the Tree Controller is not making any of the items editable. I want to be able to edit and remove (but not necessarily add) items. canRemove, canEdit always return NO, and the NSBrowser will not edit the labels.
The Tree Controller is marked editable and the count key path is not specified. "Conditionally sets editable" is set in the binding.
I am binding to "Content Array", not "Content", since the root level of items is an array.
Just to eliminate the possibility of mutability being a factor, The array and children are mutable arrays from readwrite properties (for now).
What am I doing wrong? Is binding through an NSTreeController not the right approach here? At this point, it seems easier just to revert to using a data source delegate.
UPDATE: stupid, but probably helpful to people who don't do Cocoa UIs every day (like me), so I'm leaving this question up.
I didn't have the selectionIndex bound between the control and the controller.
I'm a fairly experienced programmer, but I've always struggled with this particular issue..
You have your main class that maybe displays pop-ups over everything else, transitions between screens and so forth, and then you have the screen objects themselves, and the pop-up objects. when you click "close" on a pop-up, or click "go to a new screen" on a screen, or whatever it may be, these objects then need to communicate with the main class and tell it to do stuff. And often you need to pass data to the main class aswell. In your experience does it work out better to have the children dispatch events with data, that the main class picks up, or somehow pass the main class down to all the children through constructors, and have a bunch of public methods in the main class that the children can call?
or are both equally valid?
edit: And also, what made me post this: In my game, the user goes through a bunch of different menu screens, and in each screen, he adds something to a game-config object that at the end will be used to generate the gameScreen. I dont want to keep saying dispatchEvent("addValueToGameConfig", value) or something, i just want to say bigController.gameConfig.value = "whatever";
If the hierarchy of children is deep, I would go for events or observer. It leads to a lower coupling between classes. Any substantial refactoring of your main class can have a huge avalanche effect on the dependent children. They become too knowledgeable (higher change of breaking Law of Demeter) about their parent and take on effectively an additional responsibility (arguably breaking SRP) besides managing their own state, of informing it constantly about their own state in a custom manner compatible with their parent. Firing a specialized meaningful notification about their state change into "space", not just about an arbitrary property change, releases them from worrying about the parent's state. It is a parent's duty now to be informed about changes of the state of its children. Furthermore, having a set of meaningful events can lead to narrower public interface of children. It may as well help readability, not having to constantly go up and down through the hierarchy.
I am working on a music notation app which has is a music staff class (CCNode) and a note class (CCSprite).
Notes are added to the music staff like:
// MusicStaff.m
[self addChild:note];
Notes have a particle emitter, and this needs to be added to the parent.. I am of the opinion that doing something like:
// Note.m
[self.musicStaff addChild:self.emitter];
is not cool because I don't like the idea of notes controlling the staff--- I like to think of the staff as the one in control of what children it has.
I honestly feel like this particle emitter should be a child of Note, since it technically is part of the note, not part of the music staff-- so adding it to the music staff inherently feels wrong. However, from what I understand about cocos2d, although you can add a child to a CCSprite, the sprites do not manage the drawing of their children, so this particle emitter would not be visible.
That said, since as far as I know the only way to go about this is to add the emitter to the staff, I would prefer doing:
// MusicStaff.m
[self addChild:note];
[self addChild:note.emitter];
However, a team member on my project feels this is "backwards" and "dumb", and that the note should add the emitter directly to its parent. I just seeking some feedback as to if my thoughts on this are indeed "backwards" and "dumb", or if I have a valid point…
Also I am curious if there is another way to solve this problem, like adding the emitter directly to the note and making it draw its children somehow?
In terms of object-oriented design, if the Emitter is created by its parent the Note, I don't think it should add itself to the Staff. If anyone has to talk to the Staff, let it be its direct child, the Note. Even better, make the Note respond to questions asked by the Staff, so in the end the Staff controls what it wants to show.
You can add the particles as children of the sprite and they will be drawn. Whatever resource gave you the idea that child nodes are not drawn is wrong.
What I think you may have misunderstood is the issue of sprite batching. In that case, when you do use CCSpriteBatchNode, you can only add CCSprite objects to the batch node and the batch node's children. So in that case trying to add a particle effect or any other node as child of a sprite-batched sprite will cause an assertion in cocos2d telling you that this is illegal.
As for the "issue of dumbness": Neither option is really dumb, but adding the emitter to the parent has a minor benefit in that the note takes control over what is inherently the note's responsibility: managing the lifetime of the note's particle effect.
I have always found it hard to decide when I should create a single object and pass it to every object that needs it, or create a new object for every object which needs that item.
Some cases are so obvious, like entity objects which are readonly after allocation and instantiation. You can pass the same object anywhere and not worry about another object modifying it, which ruins the other objects holding a reference to it.
My problem mainly lies with objects that represent themselves to the user. Objects like CCSprite in cocos2d, NSMenuItem in Cocoa (AppKit) and other objects with visual representation..
Examples:
In cocoa, i know that I have to create an NSMenu for each NSPopUpButton, so that the selection for a specific button does not affect the rest. But, what about the NSMenuItems contained within? Can I create a single set and pass them to all the menus? What are your grounds, or how did you come to such a conclusion?
Other example:
In cocos2d, and almost all GUI based applications, you can pass to a button two images/sprites/...etc. such that one is for the normal state, and the other is for the selected (highlighted, pressed, clicked) state. Can I pass the same image/sprite/...etc. to both, making them point to the same object?
I hope this is not an implementation related issue (that it ultimately depends on the implementation) , since I face it in a lot of my programming projects, in cocoa, cocos2d, Java ... etc.
PS: I need help with choosing the proper tags
I suggest creating new instances unless doing this causes a performance problem. Sharing an NSMenuItem instance among many NSMenu makes it more difficulty to maintain control over that instance, which increases the risk of errors.
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.