method_t
method_t是对方法,函数的封装
struct method_t {
SEL name; // 函数名 选择器就代表方法名称
const char * types;// 编码(返回值类型,参数类型)
IMP imp; // 指向函数的指针(函数地址)
};
IMP代表函数的具体实现
typedef id _Nullable (*IMP) (id _Nonnull, SEL _Nonnull, …);
SEL 代表方法\函数名, 一般叫做选择器, 底层结构跟char *类似
NSLog(@"%s",@"123"); // 打印结果为123
NSLog(@"%s", @selector(init)); // init 有些类似于NSLoge=(@"%s",@"init") 所以下次看到SEL 或者@selector(functionName)就当成方法名就可以
如何拿到SEL
- 可以通过@selector()和sel_registerName()获得
- 可以通过sel_getName()和NSStringFromSelector()转为字符串
- 不同类中相同名字的方法,所对应的方法选择器是相同的
typedef struct objc_selector *SEL
SEL sel1 = sel_registerName("test");
SEL sel2 = @selector(test);
const char * types 包含返回值信息和参数信息
Person *per = [[Person alloc]init];
[per test]; // v 16 @0:8
@implementation Person
- (void)test2 {
NSString *str = NSStringFromSelector(_cmd);
NSLog(@"%@",str);
// _cmd 就相等于@selector(test2)
}
@end
上面代码的c语言函数默认回传两个参数id和SEL
-(void)test:(id)self _cmd:(SEL)_cmd {}
//所以他的type 为 v 16 @0:8 , 其中v表示void无返回值 ,@代表id类型, :代表_cmd类型
types包含了函数的返回值,参数编码的字符串 : 返回值 参数1 参数2…
Type Encoding 提供了叫@encode的指令,具体的类型表示成字符串编码
int类型的@encode(int)是i,
id类型的@encode(id)是@,
SEL类型的@encode(SEL)是:,
Class类型的@encode(Class)是#,
// i 24 @0 :8 i 16 f 20
// (0)id (8)SEL (16)int (20)float 其中id ,SEL都是指针各占8个字节,id和SEL共占16个字节 16 + int的4个字节 + float的4个字节 == 24个字节所有参数
-(int)test:(int)age height:(float)height;
SEL就是对方法名称的一种包装。通过SEL类型数据和id就可以找到对应相应的方法地址,找到方法地址就可以调用方法。在内存中每个类的方法都存储在类对象中,每个方法都有一个与之对应的SEL类型的数据(_cmd),根据一个SEL数据和id就可以找到对应的方法地址,进而调用方法。
注意:
这个过程是有缓存的,第一次找方法是逐条找,比较耗性能,但是找过一次之后,便会留下缓存数据,再找就直接访问缓存了。
例如,声明方法:
@interface Person : NSObject
+ (void)test1;
- (void)test2;
- (void)test3:(NSString *)abc;
@end
实现后,像如下一样直接调用:
Person *per = [[Person alloc]init];
[per test2];
[per performSelector:@selector(test2)]; // SEL 就是@selector(test2)
[per performSelector:@selector(test3:) withObject:@"123"];
NSString *name = @"test2";
SEL s = NSSelectorFromString(name);
[per performSelector:s]; // 等价于 [per performSelector:@selector(test2)];
@implementation Person
- (void)test2 {
NSString *str = NSStringFromSelector(_cmd);
NSLog(@"%@",str);
// _cmd 就相等于@selector(test2) 上面的打印语句就是将当前的方法名打印出来,这里的_cmd其实就相当于@selector(test2
}
@end
所以有SEL 等价于 @selector(test2) , 在方法实现中_cmd 也等价于 @selector(test2), 所以有 SEL == _cmd == @selector(test2)
SEL类型数据和selector的用法
这个链接中的说法感觉不是很正确,但也可以借鉴