纯自己记笔记,如有错误还请大神不吝赐教

2024-05-11 07:48

本文主要是介绍纯自己记笔记,如有错误还请大神不吝赐教,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原文:https://mp.weixin.qq.com/s/R1a1UPxr4a--quYM7RBc1Q

iOS的方法执行转发

MyClass *myClass = [[MyClass alloc] init];

[myClass printLog];


这个方法会被动态转成 objc_msgSend(myClass,@selector(printLog));

官方将此方法的定义为

objc_msgSend(void /* id self, SEL op, ... */ )


self:消息接收者

op:消息的方法名

c:参数列表 例:v@: 其中 v表示void,@表示消息接收者self,:表示sel方法



用这张图看一下 id类型,id其实里面只包含了 指向Class的 指针isa

1.class包含

①.指向元类对象的class的指针isa 我理解就是object_getClass(class)

②.class的name

③.class的变量列表 objc_ivar_list

④.class的方法列表objc_method_list

⑤.class的方法缓存 objc_cache,这里面存的是上一次被执行的方法,以便减少遍历objc_method_list的开支

2.objc_method_list包含

①.mothod_count 方法总数

②.方法体objc_method

③.objc_method_list ,将来备用的

3.objc_method包含

①.SEL类型的方法名

②.char *方法类型

③.IMP 方法实现

所以,执行一个方法的大概逻辑

·首先被动态编译成objc_msgSend(myClass,@selector(pirntLog));

·查找myClass的isa指针,找到myClass的类对象(Class),也就是MyClass

·在MyClass的method_list中查找对应的方法

·最后在找到的方法里的IMP指针,执行实现

二、消息转发

当一个对象执行selector,但没有实现的时候 [self printTest]; 系统会给三次补救机会。我们用通俗的话讲:

第一次

这个方法找不到,我们就换个已实现的方法

+(void)resolveInstanceMethod:(SEL)sel;实例方法

+(void)resolveClassMethod:(SEL)sel;类方法

示例

// ViewController.m 中

void myMethod(id self, SEL _cmd,NSString *nub) {

NSLog(@"ifelseboyxx%@",nub);

}

+ (BOOL)resolveInstanceMethod:(SEL)sel {

#pragma clang diagnostic push

#pragma clang diagnostic ignored "-Wundeclared-selector"

    if (sel == @selector(myTestPrint:)) {

#pragma clang diagnostic pop

        class_addMethod([self class],sel,(IMP)myMethod,"v@:@");

        return YES;

    }else {

        return [super resolveInstanceMethod:sel];

    }

}

第二次

如果没有方法可以替换,那我们就换个tagert

-(id)forwardingTargetForSelector:(SEL)aSelector;

示例

@interface Person : NSObject

@end

@implementation Person

- (void)myTestPrint:(NSString *)str {

NSLog(@"ifelseboyxx%@",str);

}

@end


// ViewController.m 中

- (id)forwardingTargetForSelector:(SEL)aSelector {

#pragma clang diagnostic push

#pragma clang diagnostic ignored "-Wundeclared-selector"

    if (aSelector == @selector(myTestPrint:)) {

#pragma clang diagnostic pop

        return [Person new];

    }else{

        return [super forwardingTargetForSelector:aSelector];

    }

}

第三次

第一梯队的对象没实现,我们就换其他的对象咯

-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector; 该方法可以被签名广撒网

-(void)forwardInvocation:(NSInvocation *)anInvocation;实现一样方法的对象去执行

示例

@interface Person : NSObject

@end

@implementation Person

- (void)myTestPrint:(NSString *)str {

NSLog(@"ifelseboyxx%@",str);

}

@end


@interface Animal : NSObject

@end

@implementation Animal

- (void)myTestPrint:(NSString *)str {

NSLog(@"tiger%@",str);

}

@end


// ViewController.m 中

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {

#pragma clang diagnostic push

#pragma clang diagnostic ignored "-Wundeclared-selector"

if (aSelector == @selector(myTestPrint:)) {

#pragma clang diagnostic pop

return [NSMethodSignature  signatureWithObjCTypes:"v@:@"];

}

return [super methodSignatureForSelector:aSelector];

}

- (void)forwardInvocation:(NSInvocation *)anInvocation {

Person *person = [Person new];

Animal *animal = [Animal new];

if ([person respondsToSelector:anInvocation.selector]) {

[anInvocation invokeWithTarget:person];

}

if ([animal respondsToSelector:anInvocation.selector]) {

[anInvocation invokeWithTarget:animal];

}

}




这篇关于纯自己记笔记,如有错误还请大神不吝赐教的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/978930

相关文章

解决tomcat启动时报Junit相关错误java.lang.ClassNotFoundException: org.junit.Test问题

《解决tomcat启动时报Junit相关错误java.lang.ClassNotFoundException:org.junit.Test问题》:本文主要介绍解决tomcat启动时报Junit相... 目录tomcat启动时报Junit相关错误Java.lang.ClassNotFoundException

Java NoClassDefFoundError运行时错误分析解决

《JavaNoClassDefFoundError运行时错误分析解决》在Java开发中,NoClassDefFoundError是一种常见的运行时错误,它通常表明Java虚拟机在尝试加载一个类时未能... 目录前言一、问题分析二、报错原因三、解决思路检查类路径配置检查依赖库检查类文件调试类加载器问题四、常见

Windows Docker端口占用错误及解决方案总结

《WindowsDocker端口占用错误及解决方案总结》在Windows环境下使用Docker容器时,端口占用错误是开发和运维中常见且棘手的问题,本文将深入剖析该问题的成因,介绍如何通过查看端口分配... 目录引言Windows docker 端口占用错误及解决方案汇总端口冲突形成原因解析诊断当前端口情况解

C/C++错误信息处理的常见方法及函数

《C/C++错误信息处理的常见方法及函数》C/C++是两种广泛使用的编程语言,特别是在系统编程、嵌入式开发以及高性能计算领域,:本文主要介绍C/C++错误信息处理的常见方法及函数,文中通过代码介绍... 目录前言1. errno 和 perror()示例:2. strerror()示例:3. perror(

Go标准库常见错误分析和解决办法

《Go标准库常见错误分析和解决办法》Go语言的标准库为开发者提供了丰富且高效的工具,涵盖了从网络编程到文件操作等各个方面,然而,标准库虽好,使用不当却可能适得其反,正所谓工欲善其事,必先利其器,本文将... 目录1. 使用了错误的time.Duration2. time.After导致的内存泄漏3. jsO

Python中ModuleNotFoundError: No module named ‘timm’的错误解决

《Python中ModuleNotFoundError:Nomodulenamed‘timm’的错误解决》本文主要介绍了Python中ModuleNotFoundError:Nomodulen... 目录一、引言二、错误原因分析三、解决办法1.安装timm模块2. 检查python环境3. 解决安装路径问题

如何解决mysql出现Incorrect string value for column ‘表项‘ at row 1错误问题

《如何解决mysql出现Incorrectstringvalueforcolumn‘表项‘atrow1错误问题》:本文主要介绍如何解决mysql出现Incorrectstringv... 目录mysql出现Incorrect string value for column ‘表项‘ at row 1错误报错

SpringBoot项目启动错误:找不到或无法加载主类的几种解决方法

《SpringBoot项目启动错误:找不到或无法加载主类的几种解决方法》本文主要介绍了SpringBoot项目启动错误:找不到或无法加载主类的几种解决方法,具有一定的参考价值,感兴趣的可以了解一下... 目录方法1:更改IDE配置方法2:在Eclipse中清理项目方法3:使用Maven命令行在开发Sprin

前端bug调试的方法技巧及常见错误

《前端bug调试的方法技巧及常见错误》:本文主要介绍编程中常见的报错和Bug,以及调试的重要性,调试的基本流程是通过缩小范围来定位问题,并给出了推测法、删除代码法、console调试和debugg... 目录调试基本流程调试方法排查bug的两大技巧如何看控制台报错前端常见错误取值调用报错资源引入错误解析错误

部署Vue项目到服务器后404错误的原因及解决方案

《部署Vue项目到服务器后404错误的原因及解决方案》文章介绍了Vue项目部署步骤以及404错误的解决方案,部署步骤包括构建项目、上传文件、配置Web服务器、重启Nginx和访问域名,404错误通常是... 目录一、vue项目部署步骤二、404错误原因及解决方案错误场景原因分析解决方案一、Vue项目部署步骤