年后归来,温故知新。
1、类方法和实例方法之间的区别
/*
*1.实例方法和类方法的调用
*/
CFPerson *person = [[CFPerson alloc]init];
[person eating]; //实例方法调用
[CFPerson sleeping]; //类方法调用
((void (*)(id,SEL))(void *)objc_msgSend)((id)person,sel_registerName("eating"));
((void (*)(id,SEL))(void *)objc_msgSend)(objc_getClass("CFPerson"),sel_registerName("sleeping"));
// [person performSelector:@selector(sleeping)];
// [CFPerson performSelector:@selector(eating)];
/*
*实例->类->元类
获取isa,在isa对象的方法列表中查找指定方法
传入实例对象,在类的方法列表中查找
传入类对象,在元类的方法列表中查找
*/
/*
*2.验证
class_getMethodImplementation
从指定的类方法列表中查找指定的方法,返回此方法的地址
*/
IMP eatIMP = class_getMethodImplementation([CFPerson class], @selector(eating));
eatIMP();
Class metaCls = objc_getMetaClass(class_getName([CFPerson class]));
IMP sleepIMP = class_getMethodImplementation(metaCls, @selector(sleeping));
sleepIMP();
2、objc_msgSend介绍
int main(int argc, const char * argv[]) {
@autoreleasepool {
/*
*1.正常调用方法
*/
CFPerson *person = [CFPerson new];
CFStudent *student = [CFStudent new];
[person eatingWithFood:@"apple" inPlace:@"kitchen"];
[person playing];
[CFPerson sleeping];
/*
*2.使用objc_msgSend
*/
SEL eatSel = @selector(eatingWithFood:inPlace:);
SEL playSel = @selector(playing);
SEL sleepSel = NSSelectorFromString(@"sleeping");
objc_msgSend(person,playSel);
objc_msgSend(person,eatSel,@"apple",@"kitchen");
objc_msgSend([CFPerson class],sleepSel);
/*
objc_msgSend_stret:消息返回的是结构体
objc_msgSend_fpret:消息返回的是浮点数
objc_msgSendSuper:给父类发消息
*/
struct objc_super objSuper;
objSuper.receiver = student;
objSuper.super_class = [CFPerson class];
objc_msgSendSuper(&objSuper,playSel);
}
return 0;
}
3、消息发送流程
int main(int argc, const char * argv[]) {
@autoreleasepool {
CFPerson *person = [[CFPerson alloc]init];
SEL eatSel = @selector(eatingWithFood:inPlace:);
IMP eatIMP = [person methodForSelector:eatSel];
/*
消息发送流程部分是通过汇编实现的,所以实际上差距也不大
*/
NSDate *begin = [NSDate date];
for (int i =0; i<100000000; i++) {
eatIMP(person,eatSel,@"apple",@"kitchen");
}
NSDate *end = [NSDate date];
NSLog(@"跳过消息发送流程,时间花费为:%.5f",[end timeIntervalSinceDate:begin]);
begin = [NSDate date];
for (int i =0; i<100000000; i++) {
[person eatingWithFood:@"apple" inPlace:@"kitchen"];
}
end = [NSDate date];
NSLog(@"正常消息发送流程,时间花费为:%.5f",[end timeIntervalSinceDate:begin]);
}
return 0;
}
执行结果:
直接跳过消息发送流程[1658:85755] 跳过消息发送流程,时间花费为:2.82438
直接跳过消息发送流程[1658:85755] 正常消息发送流程,时间花费为:3.01274
image
image
4、直接跳过消息发送流程
int main(int argc, const char * argv[]) {
@autoreleasepool {
CFPerson *person = [[CFPerson alloc]init];
SEL eatSel = @selector(eatingWithFood:inPlace:);
IMP eatIMP = [person methodForSelector:eatSel];
/*
消息发送流程部分是通过汇编实现的,所以实际上差距也不大
*/
NSDate *begin = [NSDate date];
for (int i =0; i<100000000; i++) {
eatIMP(person,eatSel,@"apple",@"kitchen");
}
NSDate *end = [NSDate date];
NSLog(@"跳过消息发送流程,时间花费为:%.5f",[end timeIntervalSinceDate:begin]);
begin = [NSDate date];
for (int i =0; i<100000000; i++) {
[person eatingWithFood:@"apple" inPlace:@"kitchen"];
}
end = [NSDate date];
NSLog(@"正常消息发送流程,时间花费为:%.5f",[end timeIntervalSinceDate:begin]);
}
return 0;
}
image
5、消息转发流程
image@implementation RuntimeObject
void testIMP (void){
NSLog(@"testIMP invoke");
}
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
if (sel == @selector(test)) {
NSLog(@"resolveInstanceMethod:");
return NO;
}
return [super resolveInstanceMethod:sel];
}
- (id)forwardingTargetForSelector:(SEL)aSelector{
if (aSelector == @selector(test)) {
NSLog(@"forwardingTargetForSelector:");
return nil;
}
return [super forwardingTargetForSelector:aSelector];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
if (aSelector == @selector(test)) {
NSLog(@"methodSignatureForSelector:");
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
NSLog(@"forwardInvocation:");
}
@end
@interface CFPerson : NSObject
- (void)eating;
@end
@implementation CFPerson
- (void)eating
{
NSLog(@"Person eating!");
}
@end
-------------------------------------------------------------------
@interface CFStudent : NSObject
@end
@implementation CFStudent
- (id)forwardingTargetForSelector:(SEL)aSelector {
if (aSelector == @selector(eating)) {
return [CFPerson new];
}
return [super forwardingTargetForSelector:aSelector];
}
@end
-------------------------------------------------------------------
int main(int argc, const char * argv[]) {
@autoreleasepool {
/*
打印runtime信息
开启:call (void)instrumentObjcMessageSends(YES)
关闭:call (void)instrumentObjcMessageSends(NO)
/private/tmp/ 文件夹,找到最新的 msgSends-xxxx文件
*/
CFStudent *student = [CFStudent new];
[student performSelector:@selector(eating)];
[student performSelector:@selector(eating)];
}
return 0;
}
6、类方法和实例方法的动态消息解析
@interface CFPerson : NSObject
//姓名
@property(nonatomic,copy)NSString *name;
//年龄
@property(nonatomic,copy)NSString *age;
@end
-------------------------------------------------------------------
NSString *_name;
@implementation CFPerson
@dynamic name;
@synthesize age;
void playIMP(id cls,SEL cmd){
NSLog(@"Person playing!");
}
void eatIMP(id cls,SEL cmd){
NSLog(@"Person eating!");
}
- (void)sleeping
{
NSLog(@"Person sleeping!");
}
+ (BOOL)resolveClassMethod:(SEL)sel
{
//动态添加类方法
/*
*v:返回void @:表示对象 :表示_cmd
*/
if (sel == NSSelectorFromString(@"playing")) {
// class_addMethod(object_getClass([CFPerson class]), sel, (IMP)playIMP, "v@:");
class_addMethod(objc_getMetaClass("CFPerson"), sel, (IMP)playIMP, "v@:");
return YES;
}
//methodForSelector
if(sel == @selector(sleeping)){
class_addMethod(objc_getMetaClass("CFPerson"), sel, [[CFPerson new] methodForSelector:@selector(sleeping)], "v@:");
return YES;
}
return [super resolveClassMethod:sel];
}
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
if (sel == NSSelectorFromString(@"eating")) {
class_addMethod([CFPerson class], sel, (IMP)eatIMP, "v@:");
return YES;
}
if (sel == @selector(setName:)) {
class_addMethod(self, sel, (IMP)setName, "v@:@");
return YES;
}
if (sel == @selector(name)) {
class_addMethod(self, sel, (IMP)getName, "@@:");
return YES;
}
return [super resolveInstanceMethod:sel];
}
void setName(id cls,SEL cmd, NSString *name)
{
_name = name;
}
id getName(id cls,SEL cmd)
{
return _name;
}
@end
-------------------------------------------------------------------
int main(int argc, const char * argv[]) {
@autoreleasepool {
//1.类方法
[CFPerson performSelector:NSSelectorFromString(@"playing")];
[CFPerson performSelector:NSSelectorFromString(@"sleeping")];
//2.实例方法
CFPerson *person = [[CFPerson alloc]init];
[person performSelector:NSSelectorFromString(@"eating")];
[person performSelector:NSSelectorFromString(@"sleeping")]; //可以执行成功
/*
*3.@dynamic
*/
person.name = @"lilei";
NSLog(@"person.name:%@",person.name);
person.age = @"20";
NSLog(@"person.age:%@",person.age);
}
return 0;
}
7、重定向
@interface CFPerson : NSObject
@end
-------------------------------------------------------------------
@implementation CFPerson
- (id)forwardingTargetForSelector:(SEL)aSelector
{
if (aSelector == NSSelectorFromString(@"studying")) {
return [CFStudent new] ;
}
return [super forwardingTargetForSelector:aSelector];
}
@end
-------------------------------------------------------------------
@interface CFStudent : NSObject
//学习
- (void)studying;
@end
-------------------------------------------------------------------
@implementation CFStudent
//学习
- (void)studying
{
NSLog(@"Student studying!");
}
@end
-------------------------------------------------------------------
int main(int argc, const char * argv[]) {
@autoreleasepool {
CFPerson *person = [[CFPerson alloc]init];
[person performSelector:NSSelectorFromString(@"studying")];
}
return 0;
}
8、转发
image@interface CFPerson : NSObject
//吃东西
- (void)eating;
@end
-------------------------------------------------------------------
@implementation CFPerson
//吃东西
- (void)eating;
{
NSLog(@"Person eating!");
}
//生成对应的方法签名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
if (aSelector == NSSelectorFromString(@"playing")) {
// return [self methodSignatureForSelector:@selector(eating)];
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}
if (aSelector == NSSelectorFromString(@"studying")) {
return [[CFStudent new] methodSignatureForSelector:@selector(studying)];
}
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
if (anInvocation.selector == NSSelectorFromString(@"playing")) {
//1.改变执行的函数
anInvocation.selector = @selector(eating);
[anInvocation invokeWithTarget:self];
}
if (anInvocation.selector == NSSelectorFromString(@"studying")) {
//2.改变执行的目标
[anInvocation invokeWithTarget:[CFStudent new]];
}
//3.同时改变执行函数和执行目标....
}
@end
-------------------------------------------------------------------
@interface CFStudent : NSObject
//学习
- (void)studying;
@end
-------------------------------------------------------------------
@implementation CFStudent
//学习
- (void)studying
{
NSLog(@"Student studying!");
}
@end
-------------------------------------------------------------------
int main(int argc, const char * argv[]) {
@autoreleasepool {
CFPerson *person = [[CFPerson alloc]init];
//把执行playing方法,变成执行person里的eating
[person performSelector:NSSelectorFromString(@"playing")];
//把执行studying方法,交给student类
[person performSelector:NSSelectorFromString(@"studying")];
}
return 0;
}
网友评论