2

Let's say I have an uninitialized variable:

UIViewController *vc;

From this variable, I want to reference UIViewController, such that I could call alloc or new on it to return an instantiated object.

Essentially, I want to do:

UIViewController *vc = [*typeof(vc) new];

... which does not compile because the compiler expects an expression rather than a type.

If @encode returned the actual type, I could do something like:

UIViewController *vc = [NSClassFromString(@(@encode(*typeof(vc)))) new];

...however, @encode returns '@', which just means "generic object".

I realize it's a little philosophical in nature, but I get tired of typing and would like to make a macro like NEW(x). I also realize a similar macro could be made if it involves the actual declaration, but I am not satisfied with that syntax/angle.

jscs
  • 63,694
  • 13
  • 151
  • 195
xtravar
  • 1,321
  • 11
  • 24
  • `#define NEW(class, varname) class * varname = [class new]` is unsatisfactory, you're saying? – jscs Sep 07 '14 at 18:32
  • Yeah. I came up with something (see my answer), but it's not awesome. I probably won't end up doing this. – xtravar Sep 07 '14 at 18:34
  • Similar problem, but not identical because you still have access to the local declaration: [ObjC can you test an uninitialized pointer for static class type?](http://stackoverflow.com/q/7680310) It explains why this isn't generally possible, however. – jscs Sep 07 '14 at 18:38
  • 2
    Why are you trying to replace perfectly fine code with obfuscated code? – gnasher729 Sep 07 '14 at 18:45

2 Answers2

0

Here's what I have... it doesn't seem ideal, since it makes a performance hit. Still looking for better answers.

static Class classFromEncoding(const char *encoding) {
    char *className = strndup(encoding + 1, strchr(encoding, '=') - encoding - 1);
    Class retval = NSClassFromString(@(className));
    free(className);
    return retval;
}

#define NEW(variable) [classFromEncoding(@encode(typeof(*variable))) new]

Here's a macro-only version:

#define CLASS_FROM_VARIABLE(variable) \
^(const char *encoding) {             \
char *className = strndup(encoding + 1, strchr(encoding, '=') - encoding - 1); \
Class retval = NSClassFromString(@(className));      \
free(className);                         \
return retval;                              \
}(@encode(typeof(*variable)))

#define NEW(variable) [CLASS_FROM_VARIABLE(variable) new]
#define ALLOC(variable) [CLASS_FROM_VARIABLE(variable) alloc]

Variations can be made using objc_getClass() or NSString initWithBytes, perhaps with performance gains. Still, it's not a no-op, which is what I'd prefer.

xtravar
  • 1,321
  • 11
  • 24
  • I would suggest that everybody who reads your code using this macro is going to put a hex on your gerbil. – jscs Sep 07 '14 at 18:34
  • I'd definitely limit my usage. :) I love Objective-C, but initializers are the most annoying part of my day (which is why I've moved to the +new camp instead of alloc]init]). – xtravar Sep 07 '14 at 18:37
-1

It's [obj class] or [obj className] depending on your needs.

Gobra
  • 4,263
  • 2
  • 15
  • 20