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!
Related
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).
I noticed this while using iOS6 beta 3
When I create a new subclass of a UIViewContoller (no other parent classes generate this behavior that I've noticed), the .m file now has an empty category at the top of the file. In the past when learning about categories I noticed that some people would use this same technique to indicate private methods (although not truly private).
Is that what the intent is here? Has there been any change to making things actually private now? I notice the #private directive out there too.
What is your person coding style regarding private vars and methods?
UPDATE: Since XCode is pushing us to use the class extensions, I went ahead and used them for private methods/ivar for this project. I found a drawback though. I saw that I could reuse one of my subclassed UIViewControllers along with all of it's UIButtons, UILabels, etc.... I had this inheritance:
UIViewController <- FirstViewController <- SecondViewController.
Well, all of the private methods that I put in the class extension of FirstViewController do not pop up in the autocomplete when I code in SecondViewController. A slight annoyance....
You're referring to this interface definition:
#interface MYViewController ()
#end
This is technically a class extension rather than a category. Categories have a string inside the parentheses. Class extensions are added to the class at compile time, and so can add ivars (usually in the form of properties). Categories are added at runtime and cannot add ivars.
All that said, your point is correct. This is used to define private methods and properties.
In the ObjC world, "private" is a "no trespassing" sign, not a razor-wire wall. While there is a #private keyword (that adds compiler enforcement), it only applies to ivars, and generally isn't necessary. This type of warning-based privacy works very well in ObjC and is quite sufficient.
Put your private properties in this class extension, and outside callers will get "may not respond to selector" warnings if they try to access them (just like they would get for calling any undefined method). You should never allow warnings to exist in an ObjC project, so this enforces data encapsulation.
EDIT
If they're private, then they shouldn't pop up in your subclass. What you want is protected. There's no great scheme for protected methods in ObjC, but a common technique is to put them into a category in a .h file like MYViewController+Protected.h. I find this comes up very seldom in practice, since so much of good ObjC design doesn't subclass. It uses composition and delegation instead.
Regarding "Why just view controllers." First, it's not just view controllers. It's just view controllers on iOS (well, VC, TableViewController, and GLKViewController). On Mac, it's also window controllers and spotlight importers. Look in:
.../Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Templates
.../Library/Xcode/Templates
But why those? Well, those are all controllers, and it's insanely common for controllers to need private properties. In fact, if you don't have private properties in a controller, you're probably making too much public. That's not as universal of model and view classes. I suspect that played into their decision. It might also have been different people who owned the templates, or that they were updated at different times. Sometimes you see little inconsistencies that smooth out over time.
You can make your own templates as well. See Creating Custom Xcode 4 File Templates.
Sorry for the stupid post, but I am new to Objective-C programming and Cocoa and have a couple of questions which I can't find the answers to, I'm hoping someone can enlighten me.
Firstly, in XCode, when using the Interface builder, when I want to create a new object I drag the object to my 'assets'. However I can't specify methods or anything without manually creating a new class file. Is there any point using the interface builder's 'object'?
The first app I built to test things with, I put most of the code in the AppDelegate class files. Research has shown me that the AppDelegate's purpose is simply handling application events like launching and closing. Was I wrong in putting the methods in this class? Does it make any difference?
Finally, if I have several class files created, each handling their own functionality with an interface built and linked to the classes, then what do I do with the 'main' file? It seems to me that the 'main' file and 'appdelegate' class files will be for the most case left as-is?
I hope that makes sense. Again i'm sorry for the silly-sounding questions but I can't find any answers.
Thanks in advance everyone!
Firstly, in XCode, when using the Interface builder, when I want to create a new object I drag the object to my 'assets'. However I can't specify methods or anything without manually creating a new class file.
Sure you can. Just set the class of the object using the inspector.
Note that you can only connect nib objects to an outlet or action. You can't specify any random methods, nor should you—the whole point of the IBOutlet, IBOutletCollection, and IBAction keywords is to declare in code that these properties/methods are used by a nib.
Is there any point using the interface builder's 'object'?
Yes, but pretty rarely. Usually you create objects in code and connect outlets to them.
The application's delegate is one object you may want to create in the MainMenu or MainWindow nib, if you build your application that way (the iOS templates have changed away from it for some reason).
The first app I built to test things with, I put most of the code in the AppDelegate class files. Research has shown me that the AppDelegate's purpose is simply handling application events like launching and closing. Was I wrong in putting the methods in this class?
Probably. The application's delegate generally should only handle business relating to the NS/UIApplicationDelegate protocol.
On the flip side, it's OK to make your root view controller the application's delegate, if it makes sense to do so (and the NS/UIApplicationDelegate implementation code is not too voluminous). The question you have to answer—and only you can answer it for your application—is whether you are making your root view controller the application's delegate or the application's delegate the root view controller. If in doubt, keep them separate.
Does it make any difference?
Long-term, yes. It's very easy, especially in the class of the application's delegate, to create a Big Ball of Mud class—one without well-defined and clearly-delineated responsibilities. Take dynamite to such a class as soon as possible.
Finally, if I have several class files created, each handling their own functionality with an interface built and linked to the classes, then what do I do with the 'main' file? It seems to me that the 'main' file and 'appdelegate' class files will be for the most case left as-is?
Yes. They're boiler-plate.
If you haven't written any code in the application's delegate (or have removed everything you had put there into new and better-delineated classes), such that all that's left are empty method bodies or none at all, you can safely remove the application's delegate. You can always create it again later if you change your mind.
Note that if you delete your application delegate class, you should also change the main.m file—or the MainMenu/MainWindow nib, if you have one—to not refer to it. Your application won't build if your UIApplicationMain call (or any other code) refers to a class that doesn't exist, and it will crash if your MainMenu/MainWindow nib (or any other nib) refers to a class that doesn't exist.
There is no shame in your application having a delegate if you need it to, but if you don't, removing it and the class you were using for it eliminates future temptation to stuff code there or use it to store third-order globals.
The point of using objects in interface builder is to connect methods of the object to UI elements.
It partly depends on what your methods are doing, but for the most part the app delegate class is going to be left alone. It isn't an actual requirement (your program will work either way) but it is common practice because it generally creates more maintainable code. The app delegate should just handle the application events ( using other classes to do any complex logic or heavy lifting ).
The 'main' file will most likely not change. I can't think of any reason to do so, but I wouldn't rule it out for some advanced cases.
To be honest I only used the Object thing in IB once, when I wanted a separate object to have some UI bindings.
About the app delegate and main file, yes, you'll leave them as-is most of the time. But if you try to do something besides test apps you'll need to handle open events to, for example, connect to a server, ask the user for a review, increment some launch counter, etc... Those are just examples!
The main file I advise you to left it alone and use the object oriented tools provided. You should have a view controller hierarchy, isolate your views from the data, and use the view controller to comunicate between view and model. Read about MVC if you want more info on how your application should be organized.
Overview
I have a iOS project in which the view controller implementation which has become large and thought it would be better to break into categories based on the functionality
The outlets in the view controller implementation file are not available in the category's implementation file.
Note - I am using ARC (automatic reference counting)
Question
I have an outlet to the textfield created in my view controller's implementation file. Now can I create another outlet to the same text field in my view controller category's implementation file ?
Would it cause any memory not be released or any other memory issues (Both the outlets are going to be weak and non atomic) ?
Is this acceptable from a design perspective or is there a better way to do it ?
Can category's methods be accessed in view controller's implementation ? I can include the header file but I want to know if at runtime there would be any unpredictable behavior
If you need to access declared IBOutlet properties in the categories of your view controller class, why not declare them in the class header file so that they are available to your categories? The ability to declare properties and ivars in implementation files now is meant to hide messy details of your implementation, but not at the risk of making your code unmanageable. Your functional design seems sensible.
You can have as many outlets as you want, they are pointers that will allow you to modify the object trough them.
If you are using arc and assuming you used the Interface Builder to create your text field then no, since you set them to weak it just means that these pointers wont count towards the retain count of the object, so the object will be kept alive as long as at least 1 strong pointer points to it. in this case the Interface builder's view is retaining it, when that view is deallocated so will the object be. Being non atomic means that its not tread safe but this doesn't matter for your purpose.
It really depends on your program, since i cant picture it with your description i can only advice into trying to stick to the MVC model when developing on iOS.
https://developer.apple.com/library/ios/#documentation/General/Conceptual/CocoaEncyclopedia/Model-View-Controller/Model-View-Controller.html
The question is not only regarding the headline, but more of a "how will I achieve this, without trying to force a Java/Flash design into an Objective C (iPhone)program".
I have 6 views that extends UIView, these views all have different behavior but share certain methods, like -(void) update and -(void) changeState:(NSInteger)state.
A viewController, whose job is it to update, instantiate and display these views has a switch block to do this. So switch(4) {...} instantiates UIView4, but as I need a reference to the currently instantiated view (to do update and changeState:), I have a UIView property on my ViewController called self.currentView. As the instantiated UIView4 extends UIView I can easily go [self.currentView addSubview:UIView4instance] and then release the UIView4instance.
Now how will I call the [UIView4instance update] method on the view? or the [UIView5instance changeState] etc. etc.
Since I added it to self.currentView which is of type UIView it no longer has any reason to believe it has an update or changeState: method, meaning I cannot iterate the views and send them these messages.
This approach brings on a ton of other problems, I would need to test and typeCast my views each time I needed to do any operations on them.
If I were doing something like this Composite Pattern approach in, say, Java. I would either write an interface that all the views (UIView1, UIview2.... UIViewN) would implement. Or maybe an abstract class that all the views inherited the changeState: and update methods from.
This way I could have self.currentView just know that I'm adding objects to your view and they all conform to these methods.
The two solutions I can think of, with my very small Objective-C experience is:
doing it with delegation or categories, but this seems overkill in every way :/
I guess I could also extend UIView and then extend my class extending UIView again, but there is probably a reason Objective-C does not directly support abstract classes...
Hope someone could point me in the right direction regarding these issues.
Thanks:)
Yes it is equal. You can declare a protocol
#protocol MyViewProtocol
-(void)update;
-(void)changeState:(NSInteger)state;
#end
and declare your subclasses like
#interface MyUIView3 : UIView<MyViewProtocol> {
....
}
....
#end
Then, the declaration
UIView<MyViewProtocol>* view=[[MyUIView3 alloc] init];
means that view is an instance (of a subclass of) UIView which also conforms to MyViewProtocol.
Just the way it works in Java, I think. See the apple doc on protocols.
One thing to be aware of is that while defining a protocol like this is a convenience and certainly makes things clearer, it is by no means necessary to make your solution work. Objective-C binds methods at runtime, and so all you really need to do is to make sure all your view classes implement the methods you care about and call them.
You will get a complier warning for this, but it will work.
Now, in general it's probably preferable to define a protocol like this and it's what I generally do. But it's also important to remember that runtime binding is there and can be incredibly powerful.