【问题标题】:What happens to a block at compile time, and can I create one at runtime?编译时块会发生什么,我可以在运行时创建一个块吗?
【发布时间】:2013-04-25 17:49:22
【问题描述】:
这是一个关于 Objective-C 中的 blocks (^{}) 的两部分问题。我已经搜索了一些答案,但在 Google 或 SO 中没有出现任何内容。这个问题源于希望为 iOS 创建一个自定义 XML 布局引擎,支持块 - 这意味着我想解析 NSStrings 并在运行时创建一个块。
1) 这可能吗?如果可以,怎么做?
在NSString to Block 上找不到太多内容,我认为原因可能是编译器如何处理块 - 所以我再次寻找答案但空手而归。所以:
2) 在 Objective-C 中编译时块会发生什么?
【问题讨论】:
标签:
objective-c
objective-c-blocks
introspection
【解决方案1】:
一个块是两个东西;执行通过块时捕获的一大块可执行代码和状态。
即给定:
myBlock = ^{ return someVariable + someOtherVariable; };
编译时,这会创建一段代码,其行为非常类似于将两个变量相加返回结果的函数。没有创建块实例。
执行时,当表达式myBlock = ^{...}; 被求值时,就会创建一个块实例。在该块实例中是对编译器创建的代码的引用以及两个变量中包含的值的副本在分配给myBlock 时(当然,除非@987654324 @ 在游戏中,等等...)。
回答 (2),但与回答 (1) 相关。
在运行时,您可以整天创建现有的、已编译的块的实例。但是,您不能创建新的 kinds 块。这样做需要一个编译器,并且仅限于可以编译新的可执行代码并实际执行它的运行时环境。
【解决方案2】:
你不能轻易做的是在运行时编译 Objective-C 代码来创建块。您可以做的是为您的布局 DSL 创建一个小型解析器并创建一个块树。例如,可以使用嵌套块来实现数学表达式解析器。
这是表达式“2 + 3 * 4”的示例:
typedef double(^MathBlock)(void);
MathBlock exprL = ^(void) { return 3.0; };
MathBlock exprR = ^(void) { return 4.0; };
exprR = ^(void) { return exprL() * exprR(); };
exprL = ^(void) { return 2.0; };
exprR = ^(void) { return exprL() + exprR(); };
double result = exprR();
显然,您需要编写解析函数来解释您的 XML 以返回这些块。这对于递归下降解析器来说尤其简单。
【解决方案3】:
1) 如果你的意思是在运行时编译一个块,不。编译器在运行时不可用。
2)显然,一个块是在编译时编译的。它是运行时的可执行代码,如函数或方法或其中任何一个的一部分。但是块的编译方式可以将它们发送到后期执行和处理块变量魔法。