method_t结构体
struct method_t {
SEL name;//存储消息
const char *types;//返回值种类
IMP imp;//指向name的方法在内存中的地址
/*下面这部分看不懂*/
struct SortBySELAddress :
public std::binary_function<const method_t&,
const method_t&, bool>
{
bool operator() (const method_t& lhs,
const method_t& rhs)
{ return lhs.name < rhs.name; }
};
};
SEL(消息选择器)
是一种数据类型 也是typedef类型 已经加了*
SEL是一个类型
SEL对象是一个唯一标识用来存储一个方法名 不包含参数和返回值类型(消息选择器+参数类型+返回值类型 = 签名(signature))
获取SEL @selector
SEL s1 = @selector(fun);//这里就是获取到了fun的SEL消息
这样s1完全等价于这个方法名
_cmd (当前这个方法的selector)
每个类对象都有的 跟self的性质类似
merhod signature(方法签名)
是什么?
SEL,Method,IMP
SEL很熟悉了 就是消息的名字 所以你单纯拿到一个SEL是根本不知道要做什么
IMP是 typedef id (*IMP)(id, SEL, ...)
函数指针 函数指针就存储某个函数的地址
id是这个函数的返回值 id和SEL是需要的参数
IMP就是指向一个已经定义了的方法在内存中的地址 也就是你单纯拿到IMP你是能知道要干嘛的
IMP有两个参数 id 是一个是指向self的指针 SEL就是当前指针指向方法的名字
Method包含了SEL和IMP 这个应该就是传统意义上理解的方法
我觉得应该通过self找到分发表 然后在分发表中通过SEL找到对应的IMP 通过IMP就能知道定义的函数地址在哪
可以这么理解 每个class都有一个分发表 表中的每一个实体都代表一个方法(Method) 一个Method的名字叫做SEL然后地址被IMP存储了
还有个method_type 是char指针 存储方法的参数类型和返回值类型
void objc_msgSend(id self, SEL cmd,…);//是一个可变参数函数
编译器会把一个消息表达式转换为objc_msgSend方法的调用 如
[receiver(接受消息的对象) message(消息):参数] 转化为 objc_msgSend(receiver(接受消息的对象),selector(@selector(message)),参数)
例如
[a func:x];//被转化为
objc_msgSend(a,@selector(func),x);
手动发送SEL消息
SEL s1 = @selector(fun);//这里就是获取到了fun的SEL消息
[a performSelector:s1];//发送s1的SEL消息给a对象 类比与[a fun];
//这样a对象就会通过ISO指针找到他在代码段中的类 去他的类里面找是否
//有与s1消息相匹配的SEL消息
//如果此消息是带有参数的
SEL s2 = @delector(fun1:);//这里就必须带:冒号 因为函数名是fun1:(NSString *)str{}
[a performSelector:s2 withObject:@"hello"];
//多个参数就是[a performSelector:s2 withObject:@"hello" withObject:1];
//最多只能传两个参数 因为这个方法只重装了一个参数 和两个参数版本
//如果需要更多参数 只能将参数都放在一个类里面 然后将这个类作为参数
和C++函数指针做对比
你可能会觉得SEL就是一个函数指针 但是只能说很像
但是函数指针是通过指针记录函数在内存中的地址,只能静态的调用,也就是说你记的是哪个函数的地址就只能调用哪个函数,在编译的时候就决定了,而SEL只是记录了函数名,但是不同的类,不同的对象可能相应的函数并不一样,所以SEL会在运行时才能确定要调用的是哪个函数,动态的执行不同的方法
OC也可以使用函数指针(因为以函数的方式调用方法还是更快些)
@interface A:NSObject
-(void)funcWithAge:(int)a num:(int)n;
@end;
IMP funcp; // IMP是implementation
funcp = [a methodForSelector@select(A:func)];//说实话没弄懂 methodForSelector的参数是SEL 那怎么能知道具体函数的地址,不还是动态调用吗 和SEL调用有什么区别 是只省略了一个去找这个函数的过程吗
xyz = (*funcp)(a,@select(A:func),x,y);// x,y是参数
(IMP)methodForSelector:(SEL)aSelector 搜索和指定选择器相对应的方法,并返回指向该方法实现的函数指针
NSStringFromSelector从选择器获取方法名
NSString *funcName;
funcName = NSStringFromSelector(selector);
respondsToSelector(判断该类中是否有该对象方法)
不能判断是否有类方法
A *a = [A new];
BOOL b1 = [a resondsToSelector:@selector(funa)];
if(b1 == YES)
{
[a funa];
}
重写respondsToSelector
-(BOOL)respondsToSelector:(SEL)aSelector
{
if([super respondsToSelector:aSelector])//递归调用 查找父类中是否有这个函数
return YES;
if([self methodForSelector:aSelector] != (IMP)NULL)//递归到顶层 也就是NSObject类 就会执行这一条 这个直接返回对应方法的函数指针
return YES;
if([content respondsToSelector:aSelector])
return YES;
return NO;
}
merhodForSelector:(直接返回对应方法的函数指针)
可以这样写
[self methodForSelector:aSelector] != (IMP)NULL
判断是否找到
instancesRespondToSelector(判断该类中是否有该类方法)
BOOL b1 = [A instancesRespondToSelector:@selector(funa)];
isKindOfClass(判断对象类型是否是该类或子类)
A *a = [A new];
A *a1 = [B new];
A *b = [B new];
B *b1 = [A new];
BOOL s1 = [a isKindOfClass:[A class]];//判断a对象的类型是否是A类型或者A的子类型 结果是1
BOOL s2 = [b isKindOfClass:[A class]];//1
BOOL s3 = [a1 isKindOfClass:[A class]];//1
BOOL s4 = [b1 isKindOfClass:[A class]];//1
isMemerOfClass(判断对象类型是否是该类 注意不包括子类)
A *a = [A new];
A *a1 = [B new];
A *b = [B new];
B *b1 = [A new];
BOOL s1 = [a isMemerOfClass:[A class]];//判断a对象的类型是否是A类型或者A的子类型 结果是1
BOOL s2 = [b isMemerOfClass:[A class]];//0
BOOL s3 = [a1 isMemerOfClass:[A class]];//0
BOOL s4 = [b1 isMemerOfClass:[A class]];//1
很明显是否为该类型主要看创建对象的时候是什么类型 而不是看指针类型
isSubclassOfClass(判断一个类是否为另一个类的子类)
BOOL s1 = [B isSubclassOfClass:[A class]];//判断B是否为A的子类
手写一个打印方法列表
-(void)printClassAllMethod(Class)CLSIZE{
unsigned int count = 0;
Method *methodList = class_copyMethodList(cls,&count);
for(int i =0; i<count;i++)
{
Method method = methodList[i];
SEL sel = methofImplementation(cls,sel);
NSLog(@"%@-%p",NSStringFromSelector(sel),imp);
}
free(methodList);
}