1、对象直接调用
[对象 方法名:参数]
2、performSelector:withObject:方式(参数>2或有返回值则不适合使用)
[对象 performSelector:@selector() withObject:];
3、使用方法签名:NSMethodSignature和NSInvocation
//获取方法签名
NSMethodSignature *signatureStr = [self methodSignatureForSelector:@selector()];
//获取方法签名对应的invocation
NSInvocation *invocationStr = [NSInvocation invocationWithMethodSignature:signatureStr];
//设置调用者
[invocationStr setTarget:self];
//设置调用方法SEL
[invocationStr setSelector:@selector()];
//设置参数(index从0开始,用户设置参数从第3个参数开始,前两个默认是self和cmd,与消息机制有关)
[invocationStr setArgument: atIndex:];
//开始执行
[invocationStr invoke];
利用NSInvocation调用block?
//block结构
struct __main_block_impl_0 {
// impl结构体
struct __block_impl {
void *isa; //block的isa指针
int Flags; //位移枚举标记(标记desc中有无 copy , dispose方法,有无方法签名字符 Signature 等...)
int Reserved;
void *FuncPtr; //实现block的功能函数
} impl ;
struct __main_block_desc_0 {
size_t reserved;
size_t Block_size; //block 的 内存大小
/** 以下两个函数是在 isa 指针指向 _NSConcreteMallocBlock时才会有 **/
void (*copy)(void);
void (*dispose)(void);
/** 以下字符串是在impl.flag 包含((1 << 30)这个值是才有的变量),对应oc中的方法签名NSMethodSignature**/
const char *signatureStr;
} * Desc;
/** 以下都是block捕获的变量 ,变量顺序和是否捕获进来根据block的定义来决定 ,这里只是简单举例**/
struct __Block_byref_var_0 *var ; // __block变量
TestClass *__strong strongTestVar ; // strong 变量
TestClass *__weak weakTestVar ; // weak 变量
int a ; //局部普通数据类型
int *b ;//局部静态变量
/**全局静态变量是直接通过变量的地址访问的不需要捕获进来*/
}
① 定义一个与block结构体相同的结构体
struct BlockLayout {
void *isa;
int flags;
int reserved;
void (*invoke)(void *, ...);
struct block_descriptor {
unsigned long int reserved;
unsigned long int size;
void (*copy)(void *dst, void *src); // (1<<25)
void (*dispose)(void *src);
const char *signature; // (1<<30)
} *descriptor;
// 捕获的变量
};
enum {
DescFlagsHasCopyDispose = (1 << 25),
DescFlagsIsGlobal = (1 << 28),
DescFlagsHasSignature = (1 << 30)
};
typedef int BlockDescFlags;
② 将创建的block桥接(将OC和C环境内存管理权限替换)成自定义的结构体函数指针对象
void(^testBlock)(int a , int b) = ^(int a , int b){
NSLog(@"成功调用了 block");
NSLog(@"参数1 -> a = %d , 参数2 -> b = %d" , a , b);
};
struct BlockLayout * blockLayoutPointer = (__bridge struct BlockLayout *)testBlock;
③ 想使用第三种方式,要先获取block的签名,首先对block结构指针偏移找到结构体中signatureStr字段(自定义结构体中的signature)的地址,使用该值生成方法签名
int flags = blockLayoutPointer -> flags;
if (flags & BlockDescFlagsHasSignature) { //有signature字符串
void * signaturePoint = blockLayoutPointer -> descriptor;
signaturePoint += sizeof(unsigned long int); //reserved
signaturePoint += sizeof(unsigned long int); //size
if (flags & BlockDescFlagsHasCopyDispose) {
signaturePoint += sizeof(void (*)(void *dst , void *src)); //copy
signaturePoint += sizeof(void (*)(void *src)); //dispose
}
//拿到 signature 字符串内容
const char * signatureStr = (* (const char **) signaturePoint);
④ 根据方法签名生成NSInvocation对象,并设置调用方法、参数、调用者,因为block的调用是自身调用invoke函数指针方法,所以调用者target设置为block本身,参数与方法设置不同,从第二个开始
NSMethodSignature * blockSignature = [NSMethodSignature signatureWithObjCTypes:signatureStr];
NSInvocation * invocation = [NSInvocation invocationWithMethodSignature:blockSignature];
invocation.target = testBlock;
//将要传紧block的参数
int param1 = 1 ;
int param2 = 2 ;
[invocation setArgument:¶m1 atIndex:1];
[invocation setArgument:¶m2 atIndex:2];
[invocation invoke];
}
网友评论