In my project (a game) I have multiple objects that are manipulated by touch, so I thought that having all touchable objects as subclasses of a "Touchable" abstract class would be a good idea, something along the lines of:
Touchable is a subclass of CCSprite
Box is a subclass of Touchable
Motor is a subclass of Touchable
therefore Box and Motor are CCSprites, and they inherit the common methods of Touchable, and can override them
Is this a correct way to go about this, or is there some other way to tackle this hierachy?
I previously explained why subclassing CCSprite is almost always a bad idea.
"Touchable" as the name suggests is an ability of an object. A node can either be touched, or it can not. Moreover, this must not be restricted to sprites. What if later on you want a touchable label, a touchable particle effect, or some other touchable node class?
Obviously you can't subclass CCNode to make it touchable and then turn subclasses of that touchable node class back into sprites, labels, etc. because cocos2d already established a class hierarchy - this is where the inflexibility of such a hierarchical system surfaces, and starts becoming a real pain.
You could add such a touchable (or killable, flying, jumping, drivable, swipeable, etc) ability to any object, at any time, and you could take it away at any time as well. That makes it a candidate for a plugin class (a component). Any ability, especially those that may be temporary, should not be part of a superclass but instead be additional objects that you can add to an existing object, and enable/disable as needed.
One way to go about this is to use the userObject property of nodes. Write an Abilities container class, and assign it to the userObject of your nodes. Then add the desired Ability classes to the container of a node. The node then updates the userObject container class by forwarding the update method, which forwards update to all abilities. Or the Ability container itself registers with CCScheduler to receive updates. The only thing the container class and ability classes need is a (weak) reference to the owning node.
Depends on if "Touchable" represents a random set of behaviors that each class must explicitly implement to support or if there can be a single implementation that "just works" with inheritance (with, maybe, a bit of customization).
If the former, then your thinking is mostly correct. If the latter, then Jack's suggestion of using an #protocol (which is a lot like an Interface in Java) makes sense.
Personally, I'd keep it really simple. Start with an SPAbstractSprite class that is a subclass of CCSprite. Then, subclass that into SPBox and SPMotor.
Start your implementation in SPBox and/or SPMotor and, as common things fall out, refactor them into SPAbstractSprite.
As for the notion of "touchable", I wouldn't worry about trying to make that a named thing for now. Approach it the same way as above; implement touchable support in your motor or box, then refactor up to the abstract parent class later.
I am, quite admittedly, a very design-and-code-interleaved person, though, and fully acknowledge that there are those who really like to sit down and draw out a nice set of box/lines/hierarchy before writing a line of code.
In any case, you should note that the class hierarchies across the Apple provided classes and examples tend to be quite shallow and don't tend to do a huge amount of this abstraction, though abstraction is still used heavily (UIView is an abstract container for all the view like goop that all those subclasses need, for example).
Related
I have a MacOS appkit app with a LOT of different NSWindows (hundreds), and they are each created from storyboards.
Many of these NSWindows have container views with complex embedded view/view controller hierarchies.
During initialization, it's necessary to know the model object associated with any given NSWindow, so its subviews and controls can be properly initialized. Since any NSController can know its NSView, and any NSView can know its NSWindow, it would be nice for that information to stored with the NSWindow.
It would be great to set a "representedObject" for the NSWindow, but unlike NSViewController, it doesn't really have one.
Is the only real solution to create a simple custom class (derived from a small base class) for each and every NSWindow storyboard object, so NSViews & NSViewControllers down the view hierarchy can get to my model data (pointer)?
A CLARIFICATION: very few of my NSWindow objects in our hundreds of storyboards have custom classes or code derived from NSWindow. So while a Category is definitely helpful for adding an API to classes to ACCESS the model data associated with the NSWindow, it's not helpful in creating a property or instance variable and initializing it in all those NSWindow storyboards.
ULTIMATELY I PRESENT A SIMPLE BUT DISGUSTINGLY BAD SOLUTION NO ONE SHOULD COPY:
Our app does not use NSDocument, which would provide a facility for associating NSWindow objects with a document/model architecture. So our goal has been to allow each and every NSController and NSView to get access to the appropriate singular document model object required to initialize the view's controls.
I've been warned by Apple engineering gurus that I cannot depend on the order in which views and subviews are created and initialized. That makes passing data down into complex storyboard embedded subviews tricky and error-prone.
But -- with all UI on the main thread, it is not possible for a single application on MacOS to create, initialize, and display one storyboard AND have another storyboard initialization & display interrupt that process (at least not our user-invoked application storyboards). So the simple solution is...
...to have a temporarily set application-level global with the desired document model pointer. That, and a stack-based lock count to insure that the above assumptions are never violated. Terrible design. Efficient solution.
No one needs to remind me WHY this is not good. But if there's a better solution it has escaped my testing. I found that even viewDidLoad and viewWillAppear can't be trusted to have a solid pointer back to its NSWindow...
Without knowing your application structure; you will need a mechanism to assign the model pointer to each individual window. This will necessitate adding some code somewhere. An NSWindow subclass does seem appropriate.
In the AppKit MVC pattern, model data usually fits between the view and the view controller. Attempting to associate the model with the window is fighting against this pattern to some extent.
That being said; the Objective C runtime does allow you to add custom properties to existing classes using categories. This is achieved using Associative References. The relevant functions are:
objc_setAssociatedObject
objc_getAssociatedObject
objc_removeAssociatedObjects
This article has a good rundown of the benefits and downsides of that approach.
I am wanting to create a base class that inherits from CCLayer. My reason is because I have a single-image, full screen CCSprite that I want to overlay on every scene of my application. Creating a base class, and adding a CCSprite containing the image as the top-most Z object seems to make sense because it will prevent me from having to re-code the same overlay implementation again and again for each scene.
I've been able to derive a class from CCLayer with relative ease. However, I cannot figure out how to correctly create a scene another layer class that is a child, of a child of CCLayer. How can this be done, and work?
I understand that when most users ask such questions, the first follow is "Show us your code." I can show you the code but I am most interested in is a very generic implementation of Cocos2d object, that is derived from CClayer and can be used as a base class for other layers, pre-wiring common sprites and objects.
I think this may be your problem:
"I cannot figure out how to create a scene that is a child, of a child of CCLayer."
As I understand it, Cocos layers are added as children to Cocos scenes, not the other way around, as the quote seems to imply.
I think you could simply make a custom layer class, deriving it from CCLayer and adding your CCSprite. Then simply go to everywhere you are creating or deriving a CCLayer and instead create or derive it from your custom layer class and then show or hide the sprite when needed.
Alternatively, and probably more easily, you could create a category on CCLayer adding a "showFullscreenSprite" method which simply creates the sprite and sets its image, then calls
[self addChild:yourSprite z:yourSprite.zOrder tag:9999];
You would also need a corresponding "hideFullscreenSprite" method which would simply do this
[self removeChildByTag:9999 cleanup:YES];
The nice thing about this approach is you wouldn't need to sub-class at all and all of your CCLayers would now have your "showFullscreenSprite" and "hideFullscreenSprite" methods available.
(Note: "9999" has to be some number you're not already using as a CCNode tag. Make it big enough so you don't have to worry about it. Maybe pull it out into a constant such as "FULL_SCREEN_SPRITE_TAG" or some such for readability.)
Hope this helps!
I have a custom UIView class which needs to know about its parent (another different custom UIView class).
The parent class has to import the header of the child class, so it can add subviews of that class.
The child class has to import the header of the parent class, so it can access its methods and properties. It has to do the import in its .h file rather than its .m, because I need to make the child's parent an instance variable.
If I do this, I get circular import issues.
If anyone can make any sense of this, can you help to resolve this? Thanks.
What you want is commonly known as a forward declaration.
refer to Objective-C: Forward Class Declaration for more information
There are many ways to solve this, for example by just declaring the reference to the other class as an id, and to send forward messages to it (in Objective-C you don't even need to cast them, the compiler wouldn't complain about that).
For example:
#property(nonatomic,weak) id child;
But you may review your design in a way that you use a root controller that handles both the classes. This way A doesn't directly speak to B and B doesn't directly speak to A. Instead if A wants to speak with B, speaks with C and C speaks with B, and viceversa.
While you could use a forward declaration (#class ParentClass) and a weak reference to the parent (#property (nonatomic, weak) ParentClass *parent) in the child's header file, this is generally not a good programming practice.
Reasons why this is generally not a good idea:
1) As the project gets bigger, you're likely going to violate DRY ("don't repeat yourself") as the child necessitates a parent of a certain class... what if another parent later needs to create the same child object? You'd have to create a new class that declares another forward class of the new parent and has a weak property to it.
2) This is also likely going to lead to spaghetti code... what if you want to add a new feature to the parent that affects a method the child is using? Do you create a new yet similar method that's slightly different (see point 1 about violating DRY)? Do you create an input to the original method (you'd also have to make sure that the child now knows about this change and passes the appropriate input).
Instead, the Delegation design pattern works better here. Apple also frequently uses this throughout their libraries. In example, UITableView declares a delegate and a datasource so that it can delegate actions (clicks on cells) and data input (creation of custom cells) to other owning classes, without the UITableView object having to know about the implementation of said parent class.
For more information on the Delegation pattern in general, see Wikipedia on it here:
http://en.wikipedia.org/wiki/Delegation_pattern
For a tutorial on creating your own protocols (how delegation is implemented in iOS), see this tutorial here:
http://mobile.tutsplus.com/tutorials/iphone/ios-sdk-custom-delegates/
For high quality tutorials and introductions on iOS in general, including delegation and other necessary iOS concepts, see Ray Wenderlich's site also here:
http://www.raywenderlich.com/
Good luck!
I have a custom graphic that is to be displayed to a user when an event occurs. The graphic needs to be displayed on whichever viewController is currently being displayed to the user.
The way i have programmed it so far is by adding to ALL viewcontrtollers:
1) the .h file for the custom graphic class
2) an observer for the NSNotification event that is raised
3) the method which actually draws the graphic.
This doesnt feel like a very efficient way of doing things and i was wondering if anyone has a better way of doing things?
To me it sounds like you've done it in a fairly sane way. The only other way I can think is to just add the graphic to the window which would then overlay on the current view controller and you'd only need to have one object listening for the notification. You could use the app delegate for instance. But then you would have to worry about rotation of the screen yourself when adding the graphic over the top.
What you are doing is correct .. The only thing you can improve is to mauve the drawing graphics part to the custom graphic class.. (if you are not already doing so...
just Make a UIViewController variable as a member variable to the graphics class..and then set it up to the current view displaying..after you receive the notifications..and the class will itself draw the code based on the ViewController you set it up to
The reason it doesn't feel efficient is that you're duplicating a lot of code. That's more work at the outset, and it creates a maintenance headache. You should be taking advantage of the inheritance that's built into object oriented languages, including Objective-C.
If you want all your view controllers to share some behavior, then implement that behavior in a common superclass. Derive all your other view controllers from that superclass, and they'll all automatically get the desired behavior. Your superclass's initializer can take care of registering the view controller for the notification(s) that you care about, and -dealloc can unregister it. This way, you don't have to clutter up each view controller with the same repeated code, and if you want to change the code you only have to do it in one place.
I am learning iOS programming through the Big Nerd Ranch guide by Hillegass and Conway. I’m writing an app of my own as I go through the book, and one of the questions that has been bugging me is exactly when I need to subclass UIViewController (and its ilk) and when I can just instantiate it.
For example, my app consists of generic building blocks: the interface is tabbed, and the tabs lead to a UITableView, a UINavigationController that creates UITableViews, and so on. Following the book’s instructions, I have subclassed UITableViewController to create the table views. However, in creating the UITabBarController that contains all of my app’s content, it seems sufficient to instantiate a UITabBarController and then add a bunch of views to it. (All of this is done in the application:didFinishLaunchingWithOptions: method of my app delegate. Since most of my app consists of simple combinations of basic UI parts, I’m trying to do build the UI programmatically whenever possible.)
I get the impression that what I should be doing is creating a subclass of UIViewController (or UITableViewController or whatever) for every interface in my project. This seems weird to me, since most of these classes would only ever be instantiated once. Am I just misunderstanding how OO should be used in this case? (I have a good amount of programming experience but relatively little has been with OOP.) Should I be creating a subclass for each and every screen that the user will see?
Should I be creating a subclass for each and every screen that the user will see?
If each view requires different logic, yes.
Don't shy away from creating new classes for conceptually separate things. Programmers coming from non-OOP to OOP might feel that a file with only a small amount of code is a waste. Suppress this feeling. Classes are cheap, and help enormously to organise your thinking.
So you have two types of UIViewControllers in iOS. "Container" viewControllers and "Content" viewcontrollers. Both are subclasses of UIViewController but have very different purposes.
The Container type is what the UINavigationController and UITabController are. They are rarely subclassed and typically used as is (in fact, I believe Apple doesn't allow the subclassing of UINavigationController at all). These "Containers" take care of moving "Content" view controller around for you. They do not have much content of their own, beyond adding things like a tab bar or a navigation bar.
The "Content" view controller are the ones you create most of the time. You will rarely be able to use a UIViewController as is, because it will not have any functionality. That is why you subclass them. These are meant to represent a single "screenful" of content. So in effect, every "screen" the user sees should be controlled by a UIViewController subclass.
The UITableViewController is simply a specialized sublass of UIViewController that already contains some methods for managing tables.
The way the UIKit framework was designed was for you to use subclasses of UIViewController to display content and to use out-of-the-box "Container" controllers to facilitate the management of your UIViewController subclasses.
You need a subclass of UIViewController if you want to do any of the following (not an exhaustive list, but some examples)
customize the view hierarchy when the view hierarchy is loaded (in
viewDidLoad)
provide some behaviour as the view controller's views become visible
(or not) (in viewWillAppear:, viewDidAppear:, viewWillDisappear:,
etc.)
clean up after yourself as needed in viewDidUnload
create outlets to views in the hierarchy so you can adjust them as
needed in the above lifecycle methods
My reasoning behind subclassing UIViewController, and other classes is that:
Almost always you must initialize variables and assign values to the instances of classes. You add subviews and set their frames, define actions for the UIViewController instance, etc. If this UIViewController instance is directly from the base class, its initialization should be done outside of it. If this initialization is required at different places for multiple times, you may have to deal with repeated initialization process.
So, you've compiled these processes into a method, making it reusable from wherever this UIViewController instance is used. But where do you want to put it? Don't you think it's much better to put it inside the subclass of UIViewController? Also, you don't even have to come up with specific name for this initialization method. Just override the default -(id)init from the super class.
Though you may think it's suffice to use UIViewController without subclassing it for now, as your project grows, it will be challenged to deal with reusability issues. Take some time to look at your codes. Check if there is too much repetition for such as initializing an object, or assigning values to it. If you are doing same things with an instance of a class in multiple places, compile them into a method to be reused. And as number of such methods grow, you will find the need to use subclass which will contain these relevant methods for the instance.
No matter the size of your project, using classes to distinguish different objects is important. Almost always, the basic essential classification is done by the framework, making it unnecessary to introduce new concept for a class. However, this doesn't mean the framework also knows how your project and its objects can be classified into. By using subclass, you can utilize every benefit the development framework can provide and still keeping the objects in your project to be as unique as possible, based on the purpose you've designed for them.
Well about the UITabBarController you are right. There is no reason for you to subclass anything if the default behavior is sufficient. However once you need to do some custom things you will need to subclass it..
Also, why are you trying to build the GUI programmatically? For the learning curve? There is no real reason not to use InterfaceBuilder, it saves you a lot of time.
You should subclass the UITableViewController in order to get your data in the view, that is how the MVC model works. The default implementation does not offer anything in order to get your data in the view, I don't think they will ever do that in order to make sure that nothing is wasted, their 'connection' to the model object might be different from the one you want and you would end up writing an adapter if your model object is not compatible.
I hope this will help you out a bit.
And merry x-mas.