views:

186

answers:

2

I have a defined a custom error domain that I want to publish in a protocol. The domain is defined in the implementation file like this:

//in the .m file
static void *MyErrorDomain = (void *)@"MyErrorDomain";

The .h file implements a protocol, and I would like to publish MyErrorDomain there as well. I can't, however, figure out the correct form. The one that gives the fewest errors is:

// in the protocol    
static extern void * TBPluginErrorDomain;

The Xcode error is: "Multiple storage classes in declaration specifiers".

I thought that the static void construction turns MyErrorDomain into a kind of function, but "static extern void TBPluginErrorDomain();" only incremented the number of errors. In short, I'm wandering in a morass of ignorance and all guidance will be greatly appreciated.

A: 

Protocols only define the names and parameters of methods to be implemented by other classes. They do not contain any data or functional code.

If you want custom data returned by a protocol method, you should define a class that provides the data and have one of the protocol's required methods return and instance of that class. That will force those implementing the protocol to #import the class.

TechZen
What made you think that I am trying to include data or functional code in the protocol? I've edited my question to show which line of code I put in the implementation file and which in the protocol.
Elise van Looij
Because you said you wanted to publish the error domain in a protocol. A protocol has no implementation file. A protocol is nothing but the method declarations between `@protocol...@end`. You can't "publish" any variables at all in a protocol. I think you might be confusing protocol with interface.
TechZen
Ah, I think we have a different interpretation of the word 'publish'. I meant 'let the world at large know about its existence', you read it as 'provide a value'. Interestingly, Merriam-Webster's Online Dictionary appears to support both meanings [www.merriam-webster.com/dictionary/publish].
Elise van Looij
+2  A: 

At the top-level, static means “not directly accessible (without a pointer) outside this file” (file scope). extern means “defined in some other object file”. static extern does not really make any sense. It is like asking for access to a private member from another class. You do not want to use static here.

Just make a normal definition in your .m:

void *MyErrorDomain = @"MyErrorDomain";

And make an extern declaration in your .h:

extern void *MyErrorDomain;

The be sure to link in the .o from the .m whenever you link together something that uses the variable (after including the .h file). In Xcode, in the Targets tab of the Get Info window for the .m file, be sure to check each target that uses the variable (maybe slightly different in newer versions, mine is old!).

You can probably add in const (const … and extern const …), but NSString instances are immutable, so it is not totally necessary. You might make it into a const pointer though, so the pointer can not be directly changed at runtime (without casting away the constness). Together you have const void * const MyErrorDomain in the definition. Just prefix it with extern in the declaration.

Also, depending on your purposes, you might consider using a NSString * instead of void *.

Chris Johnsen
Not worried about no futzing, no. I implemented your solution, but unfortunately, I now get the error "Conflicting types for MyErrorDomain". I've read that the (void *) pointer will be automatically cast to the right type, so that's rather puzzling.
Elise van Looij
The “conflicting types” error means that there is something extra (or something missing) in the definition or the declaration. Copy and paste one to a line before the other and stare-and-compare or just replace the definition type with the declaration type (without the `extern`).
Chris Johnsen
Stare-and-compare? Would be a good name for a company, but too much honesty probably doesn't sell. Anyway, a project-wide find revealed that I had already defined MyErrorDomain as an NSString const somewhere else. May I ask why you changed void *MyErrorDomain = (void *)@"MyErrorDomain"; to void *MyErrorDomain = @"MyErrorDomain";?
Elise van Looij
Elise van Looij
In C, The cast to/from `void *` is automatic when you supply or need another pointer type. See http://stackoverflow.com/questions/108768/needless-pointer-casts-in-c for arguments for and against including the cast in C (it is required in C++).
Chris Johnsen