【问题标题】:iOS Blocks introspectioniOS 块内省
【发布时间】:2014-01-06 18:26:04
【问题描述】:

我想知道两件事:

1- 是否可以通过objective-c的自省来知道一个block的返回类型。

例如:int (^CountBlock)(NSArray *array) 我想知道它将返回的类型是int

第二个问题是:

2- 我可以持有对通用块的引用吗?我的意思是,基本上我可以做类似id myBlock 之类的事情,并回答第一个问题。

我尝试了什么

这种东西是不可能的:

id aBlock = ^{

    NSString * aString = @"OMG";

    return aString;
};

aBlock();

正如编译器看到的那样,id aBlock 不是函数或函数指针。

【问题讨论】:

  • 这可能有助于#1 realmacsoftware.com/blog/…
  • @Cy-4AH 关键是要知道通用块的返回类型。 (问题2)
  • 您是否有想要解决的特定用例,或者您只对技术上可行的事情感兴趣?如果它是针对特定用例的,那么我建议您将您的解决方案重新考虑为内省块,并且将它们强制转换不是一个好主意。但是,如果您只想了解技术上的可能性,那么我鼓励您做尽可能多的疯狂事情!
  • 我不认为这有资格作为答案,但您可能会感兴趣:github.com/fjolnir/Tranquil/blob/master/Source/Tranquil/Runtime/… 这是一个包装任意块并生成一个包含所有对象参数的类,这些参数被拆箱为原始块想要的任何参数。 (它采用的编码格式为 )

标签: ios objective-c block introspection


【解决方案1】:

1) This answer 讨论如何获取区块的签名。以下是相关代码:

static const char *BlockSig(id blockObj)
{
    struct Block *block = (void *)blockObj;
    struct BlockDescriptor *descriptor = block->descriptor;

    int copyDisposeFlag = 1 << 25;
    int signatureFlag = 1 << 30;

    assert(block->flags & signatureFlag);

    int index = 0;
    if(block->flags & copyDisposeFlag)
        index += 2;

    return descriptor->rest[index];
}

这真的不太理想,因为你只得到了签名的@encode 字符串,看起来像这样:@"i16@?0@8"。我很想看看是否有人有更好的方法。

2) 你绝对可以在id 类型之间转换块:

typedef void(^MyBlockType)(void);
id aBlock = ^ { };
((MyBlockType)aBlock)();

当然,如果你转换为错误的块类型,你最终会出现未定义的行为。

【讨论】:

  • 我不知道该块的原始签名,所以我无法对其进行类型转换。
  • 你能不能创建一个类来存储一个块和一些签名的表示,这样你就可以正确地调用这个块?
  • 那是我没有想到的,但是有可能做到这一点。
  • @godel9:“你能创建一个类来存储一个块和一些签名的表示,以便你可以正确调用块吗?”调用具有仅在运行时已知的签名的函数不能在 C 中移植,因为它需要了解特定体系结构的调用约定,并使用汇编将参数放在寄存器和堆栈中的正确位置。
  • @newacct 你完全正确。我在想只有少数几种在编译时已知的块类型,但问题中没有任何东西可以支持这个假设。
【解决方案2】:

我认为数字 2 的问题是块被命名为类型定义的一部分,例如

void (^blockName)(void) = ^{};

一种解决方法是定义一个通用块类型:

typedef void(^BlockType)(void);
BlockType myBlock = ^{};
myBlock();

编辑:@neilco 指出,一种使用调度块类型的更简单的方法(不返回任何内容并且不接受任何参数):

dispatch_block_t myBlock = ^{};
myBlock();

【讨论】:

  • 已经有一个带有该签名的内置块类型。它被称为dispatch_block_t
  • 所以您建议将块类型转换为不同的(对于该块不正确)块类型?
  • @newacct 不,这只是一个为块设置“类型”的示例,我没有尝试将 typdef 与给定示例中的任何一个匹配
  • 对,但这似乎比使用idNSObject * 更糟糕,这两者至少都是正确的
  • 我误解了一点,认为 OP 知道块类型,所以对于这种情况,这绝对不比使用 id 差,但是将任何块转换为随机块类型不是一个好主意跨度>
猜你喜欢
  • 1970-01-01
  • 2012-04-13
  • 2018-11-03
  • 1970-01-01
  • 1970-01-01
  • 2017-09-15
  • 1970-01-01
  • 2016-03-13
  • 1970-01-01
相关资源
最近更新 更多