对我来说,Objective-C 的 react 、描述和扰乱周围环境的能力就在那里。这从根本上开始,具有在任何时候引用 _cmd
并获取当前 SEL
的坚定能力。从那里开始,您可以选择参与什么 NSInvocation
咒语或运行时诡计。
现在,在 block 内,您仍然可以调用 _cmd
并获得当前“上下文”的模糊描述,即
__30-[RoomController awakeFromNib]_block_invoke123RoomController
描述性的? 是的。 信息丰富? 好的...但不是很有用。如何在 block 的内部获取动态和准确的运行时信息,特别是调用签名、参数等?
I have found a useful little method to "describe" a block提前给出了我希望在 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'
最佳答案
如果你挖掘得够深,确实可以使用一些特定于目标的程序集。
您将在三种主要架构上运行 Objective-C 代码,它们是:
- x86:iOS 模拟器和古老的 Mac
- x86_64:苹果操作系统
- ARM:iOS 设备。
使用 lldb 调试器,以及大量的 hacking,我想出了用于每个平台的寄存器(用于保存 block 指针):
- 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:
this is: 0x17e7c890 blockPtr is: 0x17e7c890
如有任何关于此代码的问题,请随时告诉我,希望对您有所帮助!
关于objective-c - 内省(introspection)当前 block 上下文,就像方法内部的 _cmd,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17416999/