IOS circular dependencies between block definitions

In my iOS application, I want to define two types of blocks that treat each other as parameters:

typedef void (^BlockA)(BlockB b); typedef void (^BlockB)(BlockA a); 

This does not compile with the name of the unknown type BlockB in the first typedef (which makes sense).

I have a workaround that defines these types:

 typedef void (^BlockA)(id); typedef void (^BlockB)(BlockA a); 

Then I return to the BlockB type inside the BlockA definition, but at the expense of type safety.

I also considered not using typedefs, but this leads to an infinite nesting of extended block definitions.

I know how to allow circular dependencies for structs with declarations ahead, but I don't see how to do this with blocks.

If there is no solution for circular dependency, is there a way that I can limit the BlockA parameter like any block type, rather than a common id , this will provide a certain level of type safety.

+4
source share
1 answer

typedef does not define a "real" type. It is basically like a macro that expands wherever it is used. Therefore, typedef cannot be recursive.

Another way to think about the fact that typedef never required is that you can always take any piece of code with typedef and just replace every appearance with a base type (what the compiler does when you compile), and it will always work and be completely equivalent . Think about it - how would you do it without a typedef ? You can not. Thus, you cannot do this with typedef .

The only ways to do this: use id as the argument type to erase the type, as you do; or, encapsulate a block inside a "real" type of type struct or class. However, if you do this last, you must explicitly place the block and extract the block from the structure or class, which makes the code confusing. In addition, struct dangerous because struct is a scalar C-type, and if you need to capture it with a block, it does not automatically manage the memory of objects inside the structure. As for the class, the definition of the packaging class is very verbose, and using it for this causes the selection of an extraneous fictitious object for each block that it wraps.

In my opinion, using id as you use is fine and is the cleanest way. However, keep in mind that if you want this block to be passed as id , captured by another internal block, you must return it to the type of the block before it is captured, since the capture semantics are different for the block and another object types (blocks are copied, while others objects are saved). Just return it to the block type in the earliest place.

+2
source

Source: https://habr.com/ru/post/1440089/


All Articles