views:

910

answers:

2

Couldn't think of an intuitive way to paraphrase the topic for this question, and I apologize for that. My question is the following:

I have several UIViewController's which need to call in a UIDatePicker. I didn't want to subclass the Date Picker several times as it's the same interface. The problem I'm having is figuring out what tools Cocoa/Objective-C provide in order for me to abstract my child controller so it does not need to know who the parent controller is that instantiated it. The parent controller just needs to tell the child controller who they are, by passing self in to some child controller instance variable. The problem with that is, the child controller cannot access methods/instance variables of the parent without importing the class's interface file. That again means the child knows each individual parent who calls it.

Looking for an optimal way to solve this, what appears to be, very common problem.

A: 

You can have a "base" view controller, BaseViewController for example. This controller would have any datepicker specific code in it. Then, all the related view controllers would then be subclasses of that base controller. Customize the behavior as needed for each controller, but you'll still have the basic picker-handling code in each one. If you're using a single nib for all of these controllers, make sure it's "File's Owner" object class is set to your BaseViewController. All subclasses will still be able to access the nib just fine.

August
+2  A: 

It's not obvious from the question if you're creating a custom UIDatePicker subclass, or if you are just implementing UIDatePicker delegate methods in several different custom UIViewController subclasses.

In either case, I think some combination of a delegate and a protocol is what you're looking for.

The parent controller just needs to tell the child controller who they are, by passing self in to some child controller instance variable

This is exactly what a delegate is useful for. Declare it in your Objective-C class as type id. You can make it a property if you like using the usual symantics.

id delegate;

Now, to address the second concern:

The problem with that is, the child controller cannot access methods/instance variables of the parent without importing the class's interface file

You definitely don't want to access ivars directly, and in Objective-C, you can always send any message to any object (you'll get a compiler warning, but it is not an error).

There is a way to get rid of those warnings though, called Protocols. A protocol is like a Java interface; it lets you define a list of methods, and classes can declare that they implement the protocol.

The syntax for creating a protocol looks like this:

@protocol ProtocolName

- (void)sometMethod;

@end

When you declare your class, you say it implements a protocol like this:

@interface MyClass <MyProtocol>

Use a comma separated list to implement multiple protocols.

The last trick you'll want to know is how to define a pointer that requires the asignee implement a specific protocol. Going back to our delegate implementation before, we can add the same angle bracket syntax, which tells the compiler that we expect the object we're assigning to implement this protocol.

id<MyProtocol> delegate;

You can declare the protocol in its own file, and you need only to import that protocol file in any class that uses the protocol. You can also use this in combination with August's suggestion above, and implement the common functionality in a common base controller object, having each custom controller subclass that base.

(another overview of protocols: http://en.wikipedia.org/wiki/Objective-C#Protocols)

Ross Boucher