4

在我的 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 类型而不是 generic id,这将提供一定程度的类型安全。

4

1 回答 1

2

typedef没有定义“真实”类型。它基本上就像一个宏,可以在任何使用它的地方扩展。这就是为什么typedefs 不能递归的原因。

另一种思考方式是,typedefs 从来都不是必需的——你总是可以用 a 获取任何一段代码typedef,并简单地将它的每一个出现替换为底层类型(这是编译器在编译时所做的),它会始终工作并完全等效。想一想——如果没有 ,你会怎么做typedef?你不能。所以你不能用一个来做到这一点typedef

唯一的方法是:使用id作为参数类型来擦除你正在做的类型;或者,将块封装在“真实”类型中,如struct或类。但是,如果使用后一种方式,则必须显式地将块放入结构或类中并从结构或类中提取块,这会使代码混乱。此外,struct由于 struct 是标量 C 类型,因此很危险,如果您需要通过块捕获它,它不会自动对结构内的对象进行内存管理。至于类,定义包装类非常冗长,为此使用它会导致为其包装的每个块分配一个无关的虚拟对象。

在我看来,id像你正在使用的那样使用很好,而且是最干净的方式。但是,请记住,如果您需要将该块传递id为由另一个内部块捕获,则应在捕获之前将其转换回块类型,因为块和其他对象类型(块)的捕获语义不同被复制,而其他对象被保留)。只需在最早的地方将其转换回块类型即可。

于 2012-10-16T18:40:54.387 回答