Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Syntax to define a Block that takes a Block and returns a Block in Objective-C

I find in Apple's document Working with Blocks that the syntax to define a block that returns the result of multiplying two values:

double (^multiplyTwoValues)(double, double);

is different than defining a block that takes another block as an argument and returns yet another block:

void (^(^complexBlock)(void (^)(void)))(void);

Why is the second syntax not void (^)(void)(^complexBlock)(void (^)(void))?

like image 296
lu yuan Avatar asked Nov 27 '14 03:11

lu yuan


People also ask

How do you define a block in Objective C?

Declaring Block VariablesStart with a return type followed by the variable name and a parameter list. You'll need a caret (^) before the variable name and two sets of parentheses. With that in mind, the following example declares a completion block, identical to the one you just saw, but without using custom typedefs.

What is Typedef Objective C?

We can use Objective C to rename a datatype using the typedef fucnction. The typedef function is used to assign the new name to the datatype. So that you can use a custom name for predefined long names of the datatypes. This will not only save time but also aids in having more understandable and easy-to-read code.


2 Answers

This is just how C syntax works. The Block syntax is based on that of function pointers, which boils down to Dennis Ritchie's idea that "the declaration of a thing should look like the use of that thing".

If you were to use the "complex Block" you defined, and then to also call the returned Block in the same line, it would look like this:

complexBlock(void (^argBlock)(void){ /*...*/ })();
//           ^ Argument (a literal Block) to the main Block
//                                              ^ Invocation of the returned Block

Further, the parsing of C declarations follows a so-called "right-left rule". The first step is "find the identifier". For your declaration, that's complexBlock.

void (^(^complexBlock)(void (^)(void)))(void);
//       |     !    | Found identifier: "complexBlock is..."

Then, look to the right. We hit a closing parenthesis, so this is the end of a declaration "unit".

void (^(^            )(void (^)(void)))(void);
//       |           ! Right parenthesis closes a part of the declaration

Go back to the beginning of the current part, and read leftwards until an opening parenthesis. We find the caret indicating a Block type. Keep reading left, and find an opening parenthesis, closing off this part of the declaration.

void (^(^             (void (^)(void)))(void);
//     |!            | "...a Block..."

Next, go right again. Here we find an opening parenthesis, indicating the start of a parameter list. Skip the parameter list since you're concerned with the return type, but it's parsed as a standalone declaration would be.

void (^              (void (^)(void)))(void);
//     |             !              | "...taking something or other and returning..."

Now that we've consumed the parameter list:

void (^                              )(void);
//     |                            |

continue moving right, and we hit a closing parenthesis:

void (^                              )(void);
//     |                             !

So, again, back up to the beginning of the current part and move left where we find the Block caret.

void (^                               (void);
//    !                              | "...a Block.."

Here's the key part for your question about this declaration:

Moving left, again we find an opening parenthesis, so we return to moving right. That's why the return Block's parameter list goes at the end of the declaration.

void (                                (void);
//   !                               | Left parenthesis closes part of declaration,
//                                     **now move rightwards again**

Having gone through all that, the rest should be self-evident.

Incidentally, the page I linked to about the right-left rule has a few demonstrations like mine, one of which involves function pointers. You may also be amused by http://cdecl.org, which is an online implementation of a program that parses C declarations and can help you understand the woolier varieties.

like image 114
jscs Avatar answered Oct 12 '22 11:10

jscs


Obj-C block syntax is pretty hard to read, this can be simplified a bit with the use of typedefs.

//setup
typedef void (^ReturnedBlock)(void);
ReturnedBlock retBlock = ^void(void){};

typedef void (^ParamBlock)(void);
ParamBlock paramBlock = ^void(void){};

//the thing you want to do
ReturnedBlock (^someBlock)(ParamBlock) = ^ReturnedBlock(ParamBlock param){

    return retBlock;
};

//perform the block
ReturnedBlock r = someBlock(paramBlock);
like image 44
Nick Avatar answered Oct 12 '22 13:10

Nick