how to pass block as a macro's argument in objective-c? - objective-c-blocks

In my code i have a lot of code like:
if (block) block(....)
So I want to define a macro, something like
#define safetyCall(block, ...) if((block)) {block(##__VA_ARGS__)};
But i couldn't get it to work. Any idea?

You don't need the ## and the ; needs moving:
#define safetyCall(block, ...) if((block)) { block(__VA_ARGS__); }

This can run into issues if your block is inline and contains code that has a series of comma separated strings, etc.
Example:
safetyCall(^void() {
NSArray *foo = #[#"alice", "bob"];
};
The compiler will complain about "Expected ']' or '.'" and "Expected identifier or '('".
However, if you were to declare the inline block as a separate block before the macro, it will not generate an error.
Example:
void (^fooBlock)(void) = ^void() {
NSArray *foo = #[#"alice", #"bob"];
}
safetyCall(fooBlock);

Related

How do I make a macro that calls a block with arbitrary arguments? [duplicate]

In my code i have a lot of code like:
if (block) block(....)
So I want to define a macro, something like
#define safetyCall(block, ...) if((block)) {block(##__VA_ARGS__)};
But i couldn't get it to work. Any idea?
You don't need the ## and the ; needs moving:
#define safetyCall(block, ...) if((block)) { block(__VA_ARGS__); }
This can run into issues if your block is inline and contains code that has a series of comma separated strings, etc.
Example:
safetyCall(^void() {
NSArray *foo = #[#"alice", "bob"];
};
The compiler will complain about "Expected ']' or '.'" and "Expected identifier or '('".
However, if you were to declare the inline block as a separate block before the macro, it will not generate an error.
Example:
void (^fooBlock)(void) = ^void() {
NSArray *foo = #[#"alice", #"bob"];
}
safetyCall(fooBlock);

How can I skip includes using libclang?

I am using libclang to parse a objective c source code file. The following code finds all Objective-C instance method declarations, but it also finds declarations in the includes:
enum CXCursorKind curKind = clang_getCursorKind(cursor);
CXString curKindName = clang_getCursorKindSpelling(curKind);
const char *funcDecl="ObjCInstanceMethodDecl";
if(strcmp(clang_getCString(curKindName),funcDecl)==0{
}
How can I skip everything, which comes from header includes? I am only interested in my own Objective-C instance method declarations in the source file, not in any of the includes.
e.g. the following should not be included
...
Location: /System/Library/Frameworks/Foundation.framework/Headers/NSObject.h:15:9:315
Type:
TypeKind: Invalid
CursorKind: ObjCInstanceMethodDecl
...
Answering this question because I couldn't believe that hard-coding paths comparisons was the only solution, and indeed, there is a clang_Location_isFromMainFile function that does exactly what you want, so that you can filter unwanted results in the visitor, like this :
if (clang_Location_isFromMainFile (clang_getCursorLocation (cursor)) == 0) {
return CXChildVisit_Continue;
}
The only way I know would be to skip unwanted paths during the AST visit. You can for example put something like the following in your visitor function. Returning CXChildVisit_Continue avoids visiting the entire file.
CXFile file;
unsigned int line, column, offset;
CXString fileName;
char * canonicalPath = NULL;
clang_getExpansionLocation (clang_getCursorLocation (cursor),
&file, &line, &column, &offset);
fileName = clang_getFileName (file);
if (clang_getCString (fileName)) {
canonicalPath = realpath (clang_getCString (fileName), NULL);
}
clang_disposeString (fileName);
if (strcmp(canonicalPath, "/canonical/path/to/your/source/file") != 0) {
return CXChildVisit_Continue;
}
Also, why compare CursorKindSpelling instead of the CursorKind directly?

Obj-c EXC_BAD_ECCESS error

I'm having a strange crash, at the 4th line below.
{
...
int exp = [[resourceCompletionReward objectAtIndex:experienceD] integerValue];
int xx = mySprite.x;
int yy = mySprite.y;
[self setupRisingText:exp withX:xx withY:yy];
...
}
-(void)setupRisingText:(int)risingValue withX:xx withY:yy {
...
}
When it tries to run the setupRising Text method it just crashes. Can't see anything wrong though?
What ever you do with xx and yy in setupRisingText::: they are treated as id (something like NSObject *, not exactly like that but similar)
So instead of int variables pointers to objects (any object, not just subclasses of NSObject) are accessed and dealt with. That is the default for any parameter without a type.
Use
-(void)setupRisingText:(int)risingValue withX:(int)xx withY:(int)yy {
...
}
instead.
BTW, if you used NSNumber you would have less of a problem here.
I am wondering, shouldn't your method look like this?
-(void)setupRisingText:(int)risingValue withX:(int)xx withY:(int)yy {
//NSLog(#"%d",risingValue+xx+yy);
}

Variadic macro that takes 0 or 1 arguments?

How would you write a variadic macro that can take either 1 or 0 arguments. I.e. something like this:
GREET() // returns #"Hello World"
GREET(#"John") // returns #"Hello John"
It's quite simple, you have something like this:
#define __NARGS(unused, _1, _2, _3, _4, _5, VAL, ...) VAL
#define NARGS(...) __NARGS(unused, ## __VA_ARGS__, 5, 4, 3, 2, 1, 0)
#define __GREET(ARGC, ARGS...) GREET_ ## ARGC (ARGS)
#define _GREET(ARGC, ARGS...) __GREET(ARGC, ARGS)
#define GREET(...) _GREET(NARGS(__VA_ARGS__), __VA_ARGS__)
#define GREET_0(...) #"Hello World!"
#define GREET_1(ARG, ...) #"Hello, " ARG // strings are auto-concatenated in objc
int main()
{
NSLog(#"%#", GREET());
NSLog(#"%#", GREET(#"John"));
}
Output:
2012-09-30 11:56:48.478 TestProj[51823:303] Hello World!
2012-09-30 11:56:48.480 TestProj[51823:303] Hello, John
Now, this is quite complex, but assuming you understand at a basic level how the preprocessor works, you should be in a good position to understand what is happening.
I don't know if this would work for objective C, but for C99 and C11 you can use P99 that has a meta macro P99_IF_EMPTY
#define GREET(...) P99_IF_EMPTY(__VA_ARGS__)("Hello World")("Hello " __VA_ARGS__)
A good way to do this is to build a data structure with a repeating element, such as:
union greet_arg {
char *string;
};
struct greet_args {
union greet_arg *arg[2];
};
void greet_function(struct greet_args *x);
Your macro can then be implemented like this:
#define GREET(x...) greet_function(&(struct greet_args){0, x})
Now the reason this works is that if you call GREET("foo") then you get:
greet_function(&(struct greet_args){0, "foo"});
whereas if you call GREET() you get:
greet_function(&(struct greet_args){0, });
which is still valid; the "0" simply null-fills the rest of the array.
Your greet_function() then simply check x->arg[1].
Either a macro has variadic arguments, or it has a fixed number of arguments. To get the desired result, declare 2 macros, one with 0 parameters and one with 1 parameter.

C preprocessor on Mac OSX/iPhone, usage of the '#' key?

I'm looking at some open source projects and I'm seeing the following:
NSLog(#"%s w=%f, h=%f", #size, size.width, size.height)
What exactly is the meaning of '#' right before the size symbol? Is that some kind of prefix for C strings?
To elaborate on dirkgently's answer, this looks like the implementation of a macro that takes an NSSize (or similar) argument, and prints the name of the variable (which is what the # is doing; converting the name of the variable to a string containing the name of the variable) and then its values. So in:
NSSize fooSize = NSMakeSize(2, 3);
MACRO_NAME_HERE(fooSize);
the macro would expand to:
NSLog(#"%s w=%f h=%f", "fooSize", fooSize.width, fooSize.height);
and print:
fooSize w=2.0 h=3.0
(similar to NSStringFromSize, but with the variable name)
The official name of # is the stringizing operator. It takes its argument and surrounds it in quotes to make a C string constant, escaping any embedded quotes or backslashes as necessary. It is only allowed inside the definition of a macro -- it is not allowed in regular code. For example:
// This is not legal C
const char *str = #test
// This is ok
#define STRINGIZE(x) #x
const char *str1 = STRINGIZE(test); // equivalent to str1 = "test";
const char *str2 = STRINGIZE(test2"a\""); // equivalent to str2 = "test2\"a\\\"";
A related preprocessor operator is the token-pasting operator ##. It takes two tokens and pastes them together to get one token. Like the stringizing operator, it is only allowed in macro definitions, not in regular code.
// This is not legal C
int foobar = 3;
int x = foo ## bar;
// This is ok
#define TOKENPASTE(x, y) x ## y
int foobar = 3;
int x = TOKENPASTE(foo, bar); // equivalent to x = foobar;
Is this the body of a macro definition? Then the # could be used to stringize the following identifier i.e. to print "string" (without the codes).