【问题标题】:Can an Obj-C Block execute itself?Obj-C 块可以自己执行吗?
【发布时间】:2011-09-06 12:52:01
【问题描述】:

这是此问题的扩展: Is it possible to create a category of the "Block" object in Objective-C.

基本上,虽然似乎可以通过 NSObject 或 NSBlock 在块上创建类别,但我无法理解块如何评估自身。最后一个问题的答案中给出的例子:

- (void) doFoo {
  //do something awesome with self, a block
  //however, you can't do "self()".  
  //You'll have to cast it to a block-type variable and use that
}

暗示可以以某种方式将 self 转换为块变量,但是如何执行块本身呢?例如,假设我在 NSBlock 上做了一个类别,而在一个方法中做了:

NSBlock* selfAsBlock = (NSBlock*)self;

我可以向 selfAsBlock 发送任何消息以评估该块吗?

【问题讨论】:

  • 是的,你可以。您可以在此找到更多信息(已经在 SO)stackoverflow.com/questions/4824613/…
  • 我不明白这是如何解决这个问题的。该答案似乎集中在如何从其自己的块定义中调用块。我说的是从块对象本身评估块。更具体地说,我希望通过此实现的是能够向块(在 NSObject 或 NSBlock 上)添加方法以执行基于块的控制流(即 [block whileTrueDo: block])。为此,我需要该块在方法中重新评估自身。

标签: objective-c objective-c-blocks objective-c-category


【解决方案1】:

暗示可以以某种方式将 self 转换为块变量

像这样:

- (void)doFoo {
    // Assume the block receives an int, returns an int,
    // and cast self to the corresponding block type
    int (^selfBlock)(int) = (int (^)(int))self;

    // Call itself and print the return value
    printf("in doFoo: %d\n", selfBlock(42));
}

请注意,(在大多数情况下)您需要修复块签名,以便编译器能够根据目标平台 ABI 设置调用站点。在上面的例子中,签名是返回类型intint类型的单个参数。

一个完整的例子是:

#import <Foundation/Foundation.h>
#import <objc/runtime.h>

@interface Foo : NSObject
- (void)doFoo;
@end

@implementation Foo
- (void)doFoo {
    // Assume the block receives an int, returns an int,
    // and cast self to the corresponding block type
    int (^selfBlock)(int) = (int (^)(int))self;

    // Call itself and print the return value
    printf("in doFoo: %d\n", selfBlock(42));
}
@end

int main(void) {
    [NSAutoreleasePool new];

    // From Dave's answer
    Method m = class_getInstanceMethod([Foo class], @selector(doFoo));
    IMP doFoo = method_getImplementation(m);
    const char *type = method_getTypeEncoding(m);
    Class nsblock = NSClassFromString(@"NSBlock");
    class_addMethod(nsblock, @selector(doFoo), doFoo, type);

    // A block that receives an int, returns an int
    int (^doubler)(int) = ^int(int someNumber){ return someNumber + someNumber; };

    // Call the category method which in turn calls itself (the block)
    [doubler doFoo];

    return 0;
}

【讨论】:

  • 太棒了。运行时显式动态方法是否需要添加代码?或者这也可以通过一个类别来完成?
  • @don 正如您所链接问题的答案中所解释的那样,我认为不可能使用类别,因为编译器在解析类别时需要原始接口声明。
【解决方案2】:

NSBlock 有一个 invoke 方法,可用于调用块。

NSBlock* b = ^() { /* do stuff */ };
[b invoke];

请注意,这是一个私有的、未记录的方法。

【讨论】:

  • 这就是我一直在寻找的方法。当然,我想我在这里所做的一切都是危险的,因为 NSBlock 本身是私有的并且可能会改变。
  • 如果你想调用这个块,你可以简单地做这个 block();而不是[块调用]; stackoverflow.com/a/9484268
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-09
  • 2011-05-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-27
  • 2020-07-15
  • 2011-02-11
相关资源
最近更新 更多