其实最重要的就是拿到block的方法签名
block的本质也是一个对象,其结构就是LD_Block_literal_1这种,LD_Block_literal_1来源见Block-ABI链接
LD_Block_literal_1就是编译后block的真实结构
/**
Type Encodings:
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100
Block-ABI:
http://clang.llvm.org/docs/Block-ABI-Apple.html
*/
enum {
// Set to true on blocks that have captures (and thus are not true
// global blocks) but are known not to escape for various other
// reasons. For backward compatibility with old runtimes, whenever
// BLOCK_IS_NOESCAPE is set, BLOCK_IS_GLOBAL is set too. Copying a
// non-escaping block returns the original block and releasing such a
// block is a no-op, which is exactly how global blocks are handled.
LD_BLOCK_IS_NOESCAPE = (1 << 23),
LD_BLOCK_HAS_COPY_DISPOSE = (1 << 25),
LD_BLOCK_HAS_CTOR = (1 << 26), // helpers have C++ code
LD_BLOCK_IS_GLOBAL = (1 << 28),
LD_BLOCK_HAS_STRET = (1 << 29), // IFF BLOCK_HAS_SIGNATURE
LD_BLOCK_HAS_SIGNATURE = (1 << 30),
};
struct LD_Block_literal_1 {
void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
int flags;
int reserved;
void (*invoke)(void *, ...);
struct LD_Block_descriptor_1 {
unsigned long int reserved; // NULL
unsigned long int size; // sizeof(struct Block_literal_1)
// optional helper functions
void (*copy_helper)(void *dst, void *src); // IFF (1<<25)
void (*dispose_helper)(void *src); // IFF (1<<25)
// required ABI.2010.3.16
const char *signature; // IFF (1<<30)
} *descriptor;
// imported variables
};
NSMethodSignature *ld_blockMethodSignature(id block) {
if (!block) {
return nil;
}
struct LD_Block_literal_1 *_block = (__bridge void *)block;
if (_block->flags & LD_BLOCK_HAS_SIGNATURE) {
void *_descriptor = _block->descriptor;
_descriptor += (2*sizeof(unsigned long int)); // 地址偏移(针对reserved和size)
if (_block->flags & LD_BLOCK_HAS_COPY_DISPOSE) { // 是否有copy_helper以及dispose_helper这两个函数
_descriptor += (2*sizeof(void *)); // 地址偏移(针对copy_helper和dispose_helper)
}
// 此时_descriptor存储的地址就是signature的地址
const char *_signature = (const char *)(*(int64_t *)_descriptor);
// const char *_signature = (*(const char **)_descriptor); //跟上面一句作用相同
NSLog(@"%s", _signature);
return [NSMethodSignature signatureWithObjCTypes:_signature];
}
return nil;
}
void * _Nullable ld_invokeBlock(id _Nullable block, NSArray * _Nullable arguments) {
// 调用者自己保证arguments的数量和block中参数的数量相等即可
NSMethodSignature *_signature = ld_blockMethodSignature(block);
NSLog(@"%@", _signature);
NSInvocation *_invocation = [NSInvocation invocationWithMethodSignature:_signature];
_invocation.target = block;
NSUInteger numberOfArguments = _signature.numberOfArguments;
for (int i = 0; i < numberOfArguments - 1; i++) {
id argument = arguments[i];
[_invocation setArgument:&argument atIndex:i + 1];
}
[_invocation invoke];
const char *type = _signature.methodReturnType;
if (strcmp(type, "v") == 0) {
return nil;
}
void *result = NULL;
[_invocation getReturnValue:&result];
return result;
}
//调用示例
int res = ld_invokeBlock(^int(id obj, NSNumber *num) {
NSLog(@"%p, %@", obj, num);
return 88;
}, @[[NSObject new], @66]);