objective-c - 检查 Objective-C block 类型?

标签 objective-c oop closures objective-c-blocks introspection

这主要是出于好奇,我不太确定它的实际用途是什么,但这里是。

由于 block 也是 Objective-C 对象,是否可以检查它们的类型?也就是说,它是否响应 isKindOfClass: 消息以及如何针对 block 使用该消息?

我天真的以为大概是这样的:

-(void) aMethod {
    typedef int (^BlockA)(int x, int y);
    id blockVar = ...; // get a block from somewhere
    if([blockVar isKindOfClass:BlockA]) {
        BlockA blockVarA = blockVar;
        int result = blockVarA(1,2);
    }
}

上面的代码可能行不通。但是,如果可以检查 block 的类型,那么正确的方法是什么?

最佳答案

可以,有点。

但首先,让我们消除歧义。 -[NSObject isKindOfClass:] 可以告诉你它是一个 block ,仅此而已。例如。我相信行代码——表面上但不幸的是一个坏主意——将为当前 Lion 和 iOS 5.x 上的 block 返回 YES:

[myBlock isKindOfClass:NSClassFromString(@"NSBlock")]

这不会帮助您区分块的函数签名。

但这可以通过从 block 记录的内部结构中获取签名来完成。下面是一个示例 OS X 命令行应用程序的代码,其中大部分摘自 Mike Ash 的 MABlockClosure。 (很棒detailed explanation)。 (更新:Github 项目 CTObjectiveCRuntimeAdditions 显然也为此目的提供了库代码。)

#import <Foundation/Foundation.h>

struct BlockDescriptor {
    unsigned long reserved;
    unsigned long size;
    void *rest[1];
};

struct Block {
    void *isa;
    int flags;
    int reserved;
    void *invoke;
    struct BlockDescriptor *descriptor;
};

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];
}

int main(int argc, const char * argv[])
{
    @autoreleasepool {

        int (^block)(NSNumber *) = ^(NSNumber *num) { 
            NSLog(@"%@ %@", NSStringFromClass([num class]), num); 
            return [num intValue]; 
        };
        NSLog(@"signature %s", BlockSig(block));
        NSLog(@"retval %d", (int)block([NSNumber numberWithInt:42]));
    }
    return 0;
}

运行这个,你应该得到类似的东西:

[58003:403] signature i16@?0@8
[58003:403] __NSCFNumber 42
[58003:403] retval 42

可以去除签名中的数字(我听说它们是偏移量)以简化i@?@

签名在@encode中格式,这并不完美(例如,大多数对象映射到相同的 @),但应该让您一些能够在运行时区分具有不同签名的 block 。

虽然它没有记录在 Apple 链接中,但我的测试指向 @? 是 block 类型的代码,这使得上面的签名有意义。我找到了一个 clang-developers discussion在这个似乎支持这一点的问题上。

关于objective-c - 检查 Objective-C block 类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9048305/

相关文章:

objective-c - 在 Objective-C 中在另一个自定义类中使用自定义类

python - 在子类python中调用基类方法

javascript - forEach 无法读取新节点元素 - js

Javascript 闭包和 onload

objective-c - Admob 横幅针对不同屏幕尺寸更改框架

ios - 登录 View 后的 SWRevealViewController

ios - "lldb"测试内购错误

iphone - UISlider 事件

c++ - 这是 "recognised"OO 模式吗?需要健全性检查!

node.js - 循环中的 Node Grunt 异步任务,闭包不起作用