views:

702

answers:

7

I'm currently building a tabbed iPhone application where each tab's view controller is an instance of UINavigationController, and where every subcontroller of every one of the UINavigationController instances is an instance of UITableViewController. Ideally, I'd like to subclass UINavigationController so that the controller for each tab is a subclass of UINavigationController that (in addition to having all the standard UINavigationController functionality, obviously) serves as the datasource and the delegate for each of the table views associated with its subcontrollers. Trying to do this seems to break the basic UINavigationController functionality in the subclass.

Seeing as Apple says in their iPhone documentation that one shouldn't subclass UINavigationController, and things seem to break when one does, I'm wondering how I should go about extending UINavigationController's functionality without subclassing, and generally speaking, how one should work around subclassing limitations when doing Cocoa development.

Thanks!

A: 

Because they want to avoid the UI inconsistency that plagues every other platform.

Azeem.Butt
+2  A: 

Try looking into categories.

Alex Reynolds
I don't think they'd help in this case.
U62
It might not, but it is one approach to extending a class with additional methods.
Alex Reynolds
+12  A: 

Why on earth do you want the UINavigationController to act as a datasource for the table? The whole point of UITableViewController is that you subclass it, and it acts as the datasource for the UITableView that it also places in, and fills, the parent view.

U62
Agreed. In this case Apple is simply saving you from making a terrible design decision. If you truly believe you have a much better idea, then you're free to write your own controls from scratch.
Azeem.Butt
A: 

As I understand it, subclassing is not encouraged because Objective C allows a subclass too much access to the internal workings of its superclass.

The suggested alternative to writing a subclass is to write a delegate, in this case a UINavigationControllerDelegate. You can then encapsulate the specific behavior you want to extend into this delegate class, and link it up to the UINavigationController whenever you need it.

Tobias Cohen
A: 

If the available controller heirarchy does not serve your needs in terms of handling data (my assumption, since we don't know why you want one object to be the datasource for multiple views), you can always create additional data and/or controller classes (subclasses of NSObject at least).

You can have a data or other object persist while changing views in various ways. (1) a property of your application delegate class. Any object in your app can get your app delegate instance with

[[UIApplication sharedApplication] delegate]

Use this sparingly since it's essentially creating globals.

(2) You can pass data or other objects from controller to controller as you push view controller subclasses or bring them up within tabs.

(3) Core Data is another way but requires a lot of Cocoa under your belt, and you still have to manage the context instance(s).

Paul Collins
+1  A: 

I'm going to go ahead and say your idea has some merit, if at every level you are truly using the same kind of data and each level perhaps has a different delegate to handle cell creation.

Basically there's no reason you cannot subclass UINavigation controller to add a totally orthogonal layer of data atop it, because it has nothing to do with the UI or behavior that UINavigationController is managing (which is what Apple is concerned you will be messing with). To those opposed to the idea, think of it as a per-tab data store that all pages in a tab can access instead of every page in the system having to go to the AppDelegate, or have a bunch of singletons. Well basically it's a singleton, but at least one that is already there and gets the reference passed around automatically.

All that said, I'll end with an alternate design proposal - I think what you are probably wanting to do is drill down through multiple layers reusing the same code to generate cells and such because you have the same kinds of data at each layer. A better approach to handle that is to have one view controller that you feed the subset of data to display, and when a user drills down it simply creates another instance of the same view controller with that new subset of data. That approach is much better than the idea of having the navigation controller act as a table delegate for each level, because you'd have to do a ton of rewiring moving back and forth and it would require even more work to remember scroll position at each level to boot. That's why you want to keep drill-downs using multiple instances of view controllers, but multiple instances doesn't have to mean multiple classes.

Kendall Helmstetter Gelner
Understood. Thanks for the clarifcation and proposal.
Matthew McCroskey
A: 

Thanks to everyone for their comments and suggestions. After mulling over the issue a bit more, I think I'll be implementing Kendall's "alternate design proposal".

Matthew McCroskey