views:

225

answers:

2

Hi

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:)

+5  A: 

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.

Yuji
Hi Yuji Thanks! this is great, it is like I have done with delegation a few times, I just couldn't "translate" that approach into the simple solution you present here. I'll try it out straight away!
RickiG
+3  A: 

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.

Paul Franceus
Hi Paul, thanks for the input.I did get a runtime error because I had self.currentView cast as a UIView.So you say that I could have cast my currentView as *id* and then just sent it the message any ways?
RickiG
You don't have to cast it as anything. You can send any message to any object at any time. You may get a compiler warning, but it will work if the class implements the method. If it doesn't you'll get an error, unless you also implement -forwardInvocation. You should read the documentation for that in the NSObject documentation, it's pretty enlightening.
Paul Franceus