【问题标题】:Introspect the current block context, à la _cmd inside a method内省当前块上下文,à la _cmd 在一个方法中
【发布时间】:2013-06-29 07:31:43
【问题描述】:

对我来说,Objective-C 对环境做出反应、描述和干扰的能力就是它的所在。从根本上说,这首先具有在任何时候引用_cmd 并获得当前SEL 的坚定能力。从那里开始,您可以选择参与什么NSInvocation 咒语或运行时诡计。

现在,在一个块内,您仍然可以调用_cmd 并获得对当前“上下文”的模糊描述,即

__30-[RoomController awakeFromNib]_block_invoke123RoomController

描述性的? 是的。 信息丰富? 好的……但没那么有用。如何获取动态且准确的运行时信息inside 块,特别是调用签名、args 等?

I have found a useful little method to "describe" a block 提前提供了一个很好的例子,说明了我希望在区块内获得的信息类型。

typedef void(^blockHead)(NSString*);
blockHead v = ^(NSString*sandy) {  NSLog(@"damnDog",nil); };
Log([v blockDescription]);

[v blockDescription] = <NSMethodSignature: 0x7fd6fabc44d0>
    number of arguments = 2
    frame size = 224
    is special struct return? NO
    return value: -------- -------- -------- --------
        type encoding (v) 'v'
        flags {}
        modifiers {}
        frame {offset = 0, offset adjust = 0, size = 0, size adjust = 0}
        memory {offset = 0, size = 0}
    argument 0: -------- -------- -------- --------
    type encoding (@) '@?'
    flags {isObject, isBlock}
    modifiers {}
    frame {offset = 0, offset adjust = 0, size = 8, size adjust = 0}
    memory {offset = 0, size = 8}
argument 1: -------- -------- -------- --------
    type encoding (@) '@"NSString"'
    flags {isObject}
    modifiers {}
    frame {offset = 8, offset adjust = 0, size = 8, size adjust = 0}
    memory {offset = 0, size = 8}
        class 'NSString'

【问题讨论】:

  • 除非你能以某种方式引用它,否则你无法真正了解块内部的块本身。 BTW,你为什么想知道这些信息?
  • 随着块 API 的激增.. 通常很难告诉块的调用者等。编译器允许不匹配的签名...不正确的参数数量和多个具有相同名称的方法,但不同的块类型等 = 无怨无悔地共存......有时很高兴知道实际发生了什么......而不仅仅是“我认为”正在发生的事情。
  • 你可以在调用它之前检查块的类型,但是你不能在块内做很多事情,因为它已经被调用了,可能参数不正确
  • Block 确实在第一个参数中传递了自己,如您所见,à la self,但该参数的 name 在您的代码。没有办法参考它。我认为您能做的最好的事情就是围绕每个 Block 调用进行某种包装。
  • "现在,在一个块内.. 你仍然可以调用 _cmd 并获得当前“上下文”的模糊描述.. 即 __30-[RoomController awakeFromNib]_block_invoke123RoomController" 不,你不能。那不是来自_cmd

标签: objective-c objective-c-blocks introspection objective-c-runtime


【解决方案1】:

如果你挖掘得足够深,确实可以使用一些特定于目标的程序集。

您将在三种主要架构上运行 Objective-c 代码,它们是:

  • x86:iOS 模拟器和古老的 Mac
  • x86_64:Mac OSX
  • ARM:iOS 设备。

使用 lldb 调试器,以及大量的黑客攻击,我想出了每个平台正在使用的寄存器(用于保存块指针):

  • x86: ecx / edi
  • x86_64: rcx / rdi
  • ARM:r0/r4

在所有平台上,值似乎位于两个单独的寄存器中,可能一个来自调用点,一个来自传递的参数。

使用这些信息,我制作了一些宏,它们可以与 GCC 和 Clang 一起使用,以将所述寄存器的值放入 C 变量中:

#if TARGET_CPU_X86_64 
// OSX, the block pointer is in the register 'rcx'.
// The 'mov' instruction does not clobber the register,
// So we can simply (ab)use that here.
#define BLOCK_GET_SELF() ({ id __block_self_tmp; __asm__("mov %%rcx, %0" : "=r"(__block_self_tmp)); __block_self_tmp; })
#elif TARGET_CPU_X86 
// iOS Simulator, the block pointer is in the register 'ecx'.
// Same deal as with x86_64 code, except it's in a 32-bit register.
#define BLOCK_GET_SELF() ({ id __block_self_tmp; __asm__("mov %%ecx, %0" : "=r"(__block_self_tmp)); __block_self_tmp; })
#elif TARGET_CPU_ARM64
// iOS Device, ARM64 (iPhone 5S, iPad Mini 2, iPad Air).
// The block pointer is in the x0 register, and the x4 register.
// Similar code to the TARGET_CPU_ARM function.
#define BLOCK_GET_SELF() ({ id __block_self_tmp; __asm__("str x0, [%0]" :: "r"(&__block_self_tmp)); __block_self_tmp; })
#elif TARGET_CPU_ARM 
// iOS Device, the block pointer is in register 'r0'.
// The 'mov' (move) instruction clobbers the r0 register
// (which messes up the debugger) for whatever reason,
// so we use the 'str' (store) instruction instead.
#define BLOCK_GET_SELF() ({ id __block_self_tmp; __asm__("str r0, [%0]" :: "r"(&__block_self_tmp)); __block_self_tmp; })
#endif

void blockTest() {
    __block void *blockPtr = NULL;
    void (^myBlock)() = ^{
        id this = BLOCK_GET_SELF();

        printf("this is:\t\t0x%.8lx\n", (uintptr_t) this);
        printf("blockPtr is:\t0x%.8lx\n", (uintptr_t) blockPtr);
    };

    // example using dispatch
    blockPtr = (__bridge void *) myBlock;
    dispatch_async(dispatch_get_main_queue(), myBlock);
}

输出,运行 iOS 7 Beta 2 的 iPhone 5:

这是:0x17e7c890 块指针是:0x17e7c890

如果此代码有任何问题,请随时告诉我,希望对您有所帮助!

【讨论】:

    猜你喜欢
    • 2014-03-07
    • 2012-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多