Generate @property implementations with C preprocessor (upper case character in preprocessor)

Maybe I'm trying to abuse the preprocessor. I want to see if it is possible that I mean.

My @properties class has all the same bodies. I want to generate these bodies using a preprocessor macro. For instance:.

- (float) accelerometerSensitivity { return [dict floatForSelector:_cmd or:1]; } - (void) setAccelerometerSensitivity:(float) n { [dict setFloat:n forSelector:_cmd]; [dict writeToFile:[self globalDataFilename] atomically:YES]; } - (float) returnSpringTension { return [dict floatForSelector:_cmd or:0]; } - (void) setReturnSpringTension:(float) n { [dict setFloat:n forSelector:_cmd]; [dict writeToFile:[self globalDataFilename] atomically:YES]; } // set*ForSelector methods are in a category on NSMutableDictionary and depend on a function that translates selectors into strings: // NSString* keyFromSelector(SEL selector); 

The idea is that instead of using string literals (or string constants) as keys in a dictionary, I get a string from the name of the selector. Thus, I am sure that the spelling of the key matches the name of the property and, in fact, has the advantage of checking the dictionary time with keys.

What I want to do is say something like SELECTOR_PROPERY(accelerometerSensitivity) and propagate it to getter and setter. The main difficulty that I experience when implementing this as a preprocessor macro is to generate the installer name from the property name. I need to smooth out the first letter of the property name, and I do not know how to do this in the preprocessor.

+4
source share
3 answers

No, you cannot do this.

But you can combine identifiers, so theoretically you can define this as:

 MACRO(A,a,ccelerometerSensitivity) 

It is somewhat klugey, but it is more concise than an alternative.

+5
source

Here's how I would do it:

 #define MACRO(_a) { \ const char *name = #_a; \ NSString *getterName = [NSString stringWithUTF8String:name]; \ NSString *setterName = [NSString stringWithFormat:@"set%c%s:", toupper(name[0]), (name+1)]; \ NSLog(@"getter name: %@", getterName); \ NSLog(@"setter name: %@", setterName); \ } 

Basically, you scribble a macro parameter, then use the simple C function to capitalize the first letter and use the offset to get everything after the first letter.

Now that you do this:

 MACRO(foo); MACRO(bar); 

He logs this:

 2011-07-19 21:21:24.798 EmptyFoundation[16016:903] getter name: foo 2011-07-19 21:21:24.800 EmptyFoundation[16016:903] setter name: setFoo: 2011-07-19 21:21:24.801 EmptyFoundation[16016:903] getter name: bar 2011-07-19 21:21:24.802 EmptyFoundation[16016:903] setter name: setBar: 

HOWEVER, these are strings. You cannot use them as method names. Sorry.: (

0
source

Actually, you probably really do not want to do this solely for architectural reasons.

You will most likely be better off if you:

  • separates the concept of plant status from persisting state. That you invoke I / O with every little small change is terribly inefficient. It is also a mode with potential for problems; what happens if you go to the user interface where the values ​​track the user interface continuously? ... you really don't want an input / output disk for every time the dial / slider is tracked under your finger!

  • use @synthesize for all your @properties and don't even declare ivars. Use the tool to create exactly the right setters / getters for you.

  • Does this code look awful, as if you reinvented NSUserDefaults? Use NSUserDefaults for any user preference.

0
source

All Articles