在我的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,这将提供某种级别的类型安全性.
最佳答案 typedef没有定义“真实”类型.它基本上就像一个宏,它扩展到它使用的每个地方.这就是为什么typedef不能递归的原因.
考虑它的另一种方法是,typedef永远不是必需的 – 你总是可以使用typedef获取任何代码片段,并简单地用底层类型替换它的每一个匹配项(这是编译器在编译时所做的),以及它将永远工作,完全相同.想一想 – 没有typedef你会怎么做?你不能.所以你也不能用typedef来做.
唯一的方法是:使用id作为参数类型来擦除你正在做的类型;或者,将块封装在“真实”类型中,如结构或类.但是,如果以后一种方式执行此操作,则必须将块显式放入并从结构或类中提取块,这会使代码混乱.此外,struct是危险的,因为struct是标量C类型,如果您需要通过块捕获它,它不会自动对结构内的对象进行内存管理.至于类,定义包装类非常冗长,并且使用它会导致为它包装的每个块分配一个无关的虚拟对象.
在我看来,使用像你正在使用的id很好,是最干净的方式.但是,请记住,如果您需要将该块传递为另一个内部块捕获的id,则应该在捕获之前将其强制转换为块类型,因为块和其他对象类型的捕获语义不同(块被复制,而其他对象被保留).只需在最早的地方将其重新放回块类型即可.