Objective C protocol as an equal to Java Interface? - objective-c

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.

Related

Xcode now generates an empty category. Why?

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.

Using a different Superclass, instead of NSObject

This might be a straight forward answer, and I know that you don't have to set NSObject as the Superclass when creating a new class.
But say, for example, I wanted to create a class which held a set of custom CABasicAnimations. Although it may be perfectly ok for me to use CABasicAnimation as the superclass, is it recommended that I follow the unwritten rule and still use NSObject or would you, if you were writing such a class, use CABasicAnimation as the Superclass?
I would assume that it wouldn't matter as long as the Class only contained properties and methods relative to CABasicAnimation.
It would be interesting to here your thoughts!
The rule is to subclass whatever object you are trying to extend. NSObject is used for many subclasses because it is the root object, but if I was going to write a class that was very similar to NSTableView, then I would subclass NSTableView.
In your case, if you are writing a custom animation that you want to call, then you should consider subclassing from CABasicAnimation. On the other hand, if you animation is really just a collection of pre-exisiting CA animations, then NSObject would be fine.
a class which held a set of custom CABasicAnimations.
In this case, I'd like to use Category instead of Subclass.

When do I need to subclass UIViewController and when can I just instantiate it?

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.

Why can't new ObjC classes descend from UIViewController?

So, I've been making iOS apps since the first iPod touch came out, but something has always flabbergasted me; why is the list of new Cocoa Touch classes restricted to subclasses of NSObject, UIView, and UITableView? I routinely make subclasses of UIImageView and UIViewController.
Am I "Doing It Wrong™?" Have I totally misunderstood MVC to the point where I make Controller classes where I shouldn't? What is the philosophical reasoning for requiring classes to never descend from a basic controller class?
What gives you the idea that you aren't supposed to subclass UIViewController? This is directly from the documentation for UIViewController:
In a typical iPhone application, there is usually at least one custom subclass of UIViewController and more often there are several.
The C of MVC is supposed to be the least re-usable part it's whole job is to mediate between M & V. If you find something that is in the C section of your code that you have to copy and paste into several subclasses of a given object or into several projects that code should be moved elsewhere.
If you are just basing this off the fact that there is not a nice popup menu item that says UIViewController, don't worry about it Apple has just not bothered to write a template file for that class yet.
Uhm... maybe it's just me, but I see a UIViewController subclass template when I choose new File.
UIViewController template http://files.me.com/aclark78/obnp83
Like #theMikeSwan says, there simply aren't GUI templates for this when you create a new class in Xcode GUI. But you can always create a new subclass whose parent is initially NSObject. After that, you just go to your code and change the parent class to whatever you like.
So... no, you are not doing it wrong in the sense that you rightly understand that often you want to subclass UIViewController; but yes, you are doing it wrong since you assume you shouldn't do this only because Xcode GUI does not support it :)

What would you do instead of using NSViewController to be compatible with 10.4?

All I need to do is load and swap some nibs in a NSView of a window. I know how to do it with NSViewController and have it working perfectly with 10.5-10.6, but I don't know what to do for 10.4.
Tutorial links very welcome, I have trouble finding legacy stuff.
(Yes, I really do need to support 10.4.)
From working with NSViewController in Leopard, I can tell you that its functionality is very basic, and that you should be able to replicate it with fairly minimal effort.
Essentially, it has a view property/outlet, and an initWithNibName:bundle: method. Beyond that, it doesn't do anything especially fancy. It has some convenience things, like adopting NSEditor, and a representedObject property. You should be able to bang out an equivalent class in an hour or two.
Now, what you will give up if you do this is compatibility with later versions of Cocoa. Eventually, you'll probably drop 10.4 support and you'll be left with your class and the real NSViewController. When that happens, I'd recommend re-basing your custom view controller on Cocoa's NSViewController. If you've named the properties with the same names/data types as NSViewController, you should only have to drop the properties and methods you've declared yourself.
Use NSBundle to load the nib:
YourController *controller = [[YourController alloc] init];
BOOL success = [NSBundle loadNibNamed:#"YourNibName" owner:controller];
Basically, you write your own controller class that does the same things that NSViewController does. The controller classes were added to the AppKit because so many of us were writing essentially the same code over and over.