I'm looking a macro to detect if a variable is an object or a primitive in Objective-C.
In this context, I know the parameter must be a variable and will never be an expression.
Here is the best thing I've come up with:
#define IS_OBJECT(x) ( @encode(__typeof__(x))[0] == '@' )
#define IS_PRIMITIVE(x) ( !IS_OBJECT(x) )
Usage:
NSString *testString = @"test";
NSString *nilString = nil;
NSInteger testInteger = 1;
STAssertTrue(IS_OBJECT(testString), @"IS_OBJECT(testString) must be YES");
STAssertTrue(IS_OBJECT(nilString), @"IS_OBJECT(nilString) must be YES");
STAssertFalse(IS_OBJECT(testInteger), @"IS_OBJECT(testInteger) must be NO");
There must be a better way.
Update
Considering @ChrisDevereux comment, I updated the IS_OBJECT macro.
#define IS_OBJECT(x) ( strchr("@#", @encode(__typeof__(x))[0]) != NULL )
It now passes:
NSString *testString = @"test";
NSString *nilString = nil;
NSInteger testInteger = 1;
Class classTest = [NSString class];
STAssertTrue(IS_OBJECT(testString), @"IS_OBJECT(testString) must be YES");
STAssertTrue(IS_OBJECT(nilString), @"IS_OBJECT(nilString) must be YES");
STAssertFalse(IS_OBJECT(testInteger), @"IS_OBJECT(testInteger) must be NO");
STAssertTrue(IS_OBJECT(classTest), @"IS_OBJECT(classTest) must be YES");
I still don't like this answer, and hope there is something slicker. Is there something in the runtime library which does this?
Here's another way using C11's generic selection mechanism. _Generic
is standard (modern) C and supported in clang for a while.
#define IS_OBJECT(T) _Generic( (T), id: YES, default: NO)
It feels a bit less runtime-ish to me so I prefer it over the @encode
way. But to be honest I just used it for this answer because I love the power _Generic
gives to macros and think more people should start using it. If you don't know it you should read Robert Gamble's article linked above.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With