views:

149

answers:

2

I have an Objective-C protocol:

typedef enum {
    ViewStateNone
} ViewState;

@protocol ViewStateable

- (void)initViewState:(ViewState)viewState;
- (void)setViewState:(ViewState)viewState;

@end

I'm using this protocol in the following class:

#import "ViewStateable.h"

typedef enum {
    ViewStateNone,
    ViewStateSummary,
    ViewStateContact,
    ViewStateLocation
} ViewState;

@interface ViewController : UIViewController <ViewStateable> {

}

@end

I won't go too far into the specifics of my application, but what I'm doing here is typedefing an enumeration in a protocol so that the protocol's methods can take an input value of that type.

I'm then hoping to redeclare or extend that typedef in the classes that conform to that protocol, so that each class can have their own view states. However, I'm running into the following two errors:

  1. Redeclaration of enumerator 'ViewStateNone'
  2. Conflicting types for 'ViewState'

I'm ashamed to admit that my knowledge of C (namely typedefs) is not extensive, so is what I'm trying to do here, firstly, possible and, secondly, sensible?

Cheers friends.

+1  A: 

It is neither possible nor sensible. This comes from the fact that typedefs and enums are basically just defines. (Well, not really, but for this purpose, they are.) If you need to do things like this, you might want to review your design (see below).


More info

typedef type newtype;

is (almost) equivalent to

#define newtype type;

and

enum {
  ViewStateNone
};

is basically the same as

#define ViewStateNone 1

There are a few finer points withe regards to differences between the two, and the most compelling argument for using enums and typedefs is of course compile time checking of integer constants.

However; once an typedef enum {} type; has been seen, it cannot be unseen, and once it has been seen, its name is reserved for it, and it alone.

There are ways around all of this; but those are paths rarely traveled, and generally for good reason. It quickly becomes incredibly unmanageable.

As a solution, you might want to create a new class, MyViewState, which represents a view state and associated information, which could easily just be a wrapper around an NSInteger.


In closing: Review your design. I fear you might be doing something overly convoluted.

Williham Totland
Thanks for a very clear and considered response Williham. Basically, I have x amount of views, with x amount of states, all being handled by a central controller. By abstracting out the state-switching I was hoping to inititalise and switch numerous view's states externally with a single method call. If the above technique was possible, I reckon it would have likely ended up remarkably simple. Alas, I will reconsider my design. Thanks again.
David Foster
+1  A: 

It's certainly not possible in the form you have it, for reasons that the errors fairly succinctly explain. An enum constant can only be declared once in any scope, and similarly a typedef.

Moreover, there's a bit of a conceptual difficulty with defining a type in a protocol that implementors can then redefine. The implementors should be conforming to the type, not adding to it. If the class needs to be able to determine its own set of values, the protocol must use a type that is general enough to hold all those that might be wanted. In this case you could use int or, probably more sensibly, something readable like NSString. You might also add another method to the protocol that will report back the values supported by the implementing class.

walkytalky