结构体method_t,指针SEL,指针IMP的理解

本文深入探讨Objective-C中method_t结构体的细节,解释方法、函数的封装原理,包括SEL选择器、IMP函数指针及类型编码的作用。通过实例演示如何使用SEL与id调用方法,揭示方法查找与缓存机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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的用法
这个链接中的说法感觉不是很正确,但也可以借鉴

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值