在我的iOS应用程序中,我想定义两个以彼此为参数的块类型:
typedef void (^BlockA)(BlockB b);
typedef void (^BlockB)(BlockA a);
在第一个typedef中使用'未知类型名称BlockB'编译失败(这是有意义的)。
我有一个解决方法,它定义了这样的类型:
typedef void (^BlockA)(id);
typedef void (^BlockB)(BlockA a);
然后我回到BlockA定义中的BlockB类型,但代价是安全性。
我还考虑过不使用typedef,但这会导致扩展块定义的无限嵌套。
我知道如何使用前向声明来解析结构的循环依赖关系,但是我看不到如何使用块来执行此操作。
如果没有循环依赖的解决方案,有没有办法可以将BlockA的参数限制为任何Block类型而不是通用id
,这将提供某种级别的类型安全性。< / p>
答案 0 :(得分:2)
typedef
未定义&#34;真实&#34;类型。它基本上就像一个宏,它扩展到它所使用的任何地方。这就是为什么typedef
不能递归的原因。
考虑它的另一种方法是,typedef
s永远不是必需的 - 你总是可以使用typedef
来获取任何代码,并简单地用基础类型替换它的每一个代码(这是编译器在编译时所做的事情),它将始终有效并且完全等效。想一想 - 没有typedef
你会怎么做?你不能。因此,您无法使用typedef
进行此操作。
唯一的方法是:使用id
作为参数类型来删除你正在做的类型;或者,将块封装在&#34; real&#34;类似于struct
或类。但是,如果以后一种方式执行此操作,则必须将块显式放入并从结构或类中提取块,这会使代码混乱。此外,struct
是危险的,因为struct是标量C类型,如果您需要通过块捕获它,它不会自动内存管理结构内的对象。至于类,定义一个包装类非常冗长,并且使用它会导致为它包装的每个块分配一个无关的虚拟对象。
在我看来,像你一样使用id
使用很好,是最干净的方式。但是,请记住,如果您需要将该块传递为id
被另一个内部块捕获,则应该在捕获之前将其强制转换为块类型,因为块的捕获语义不同其他对象类型(复制块,而保留其他对象)。只需在最早的地方将其重新放回块类型即可。