前言
方法
在编程中占用重要的地位,大家对方法熟悉又陌生。熟悉的是每天都在用,陌生的是大家对底层的实现其实是一知半解的。前面探究了方法的快速查找流程和慢速查找流程,对方法底查找流程有一定的了解。如果快速源码网站查找流程和慢速查找流源码之家程都没有找打方法的实现,后面的流程是怎么样的,苹果会给一次机会动态方法决议
准备工作人体承受的最大电压
- objc4-818.2 源码
- 冰镇
案例分析
创建一个LWPerson
类,声明一个sayHello
方ios应用商店法,方法不实现
int main(int argc, char * argv[]) {
@autoreleasepool {
LWPerson * perosn = [LWPerson alloc];
[perosn sayHello];
}
return 0;
}
unrecognized
经典的崩溃信息,在 IOS底层原理之方法慢速查找流程 中通过全局搜索doesNotRecognizeSelector
或者unrecognized selector sent to人头攒动的近义词 instance
,在源码中搜索方式查找到苹果13底层人头攒动的读音源码的实现,在方法查找流程中如果最后imp
还是没有查找到,会调用forward_imp
forward_imp
= _objc_msgForward_imp人头攒动c人体肠道结构示意图ache
,源码查看下 _objc_msgForward_impcache
的底层实现,全局搜索_objc_msgForward_im初始化英文p人头攒动cache
STATIC_ENTRY __objc_msgForward_impcache
// No stret specialization.
b __objc_msgForward //跳转 __objc_msgForward
END_ENTRY __objc_msgForward_impcache
ENTRY __objc_msgForward
adrp x17, __objc_forward_handler@PAGE
ldr p17, [x17, __objc_forward_handler@PAGEOFF]
TailCallFunctionPointer x17
END_ENTRY __objc_msgForward
...
.macro TailCallFunctionPointer
// $0 = function pointer value
br $0 //跳转 imp
.endmacro
...
-
__objc_msgForward_impcache
底层是汇编实现,主要代码b __objc_msgFor苹果因不送充电器被判赔7000元ward
-
__objc_msgForward
中TailCallFunctionPointer
是个宏,前面探究过就是跳转imp
。x17
寄存器存放的是imp
,从汇编中可以看出苹果x跟x17
有关系的就是__objc_forward_handler
- 全局搜索
__obj初始化游戏启动器失败c_forward_haios15ndler
汇编中没有具体的实现,那就不在汇编中,可能在C/C++
源码中,全局搜rtc是什么意思索objc_forward_handler
,源码如下
// Default forward handler halts the process.
__attribute__((noreturn, cold)) void
objc_defaultForwardHandler(id self, SEL sel)
{
_objc_fatal("%c[%s %s]: unrecognized selector sent to instance %p "
"(no message forward handler is installed)",
class_isMetaClass(object_getClass(self)) ? '+' : '-',
object_getClassName(self), sel_getName(sel), self);
}
void *_objc_forward_handler = (void*)objc_defaultForwardHandler;
_objc_fatal
中报错熟悉不,经典的崩溃信息报错方法没有实现
在快速和慢速查找流程过程中没有找到imp
,难道就直接崩溃,不给一次机会的嘛。不行必须给苹果次机会,不然我不服气,系统还是干不过苹果7我哈,给了次机会就是动态方法决议
动态方法决议
在探究慢速查找流程lookUpImpOrForward
中,如果没有查找到imp
就会走动态方法决议流程resol源码编辑器下载veMethod_locked
NEVER_INLINE
IMP lookUpImpOrForward(id inst, SEL sel, Class cls, int behavior){
...
// No implementation found. Try method resolver once.
// 如果查询方法没有实现,系统会尝试一次方法解析
if (slowpath(behavior & LOOKUP_RESOLVER)) {
behavior ^= LOOKUP_RESOLVER;
//动态方法决议
return resolveMethod_locked(inst, sel, cls, behavior);
}
...
}
下面看看resolveMeth初始化英文od_lock初始化磁盘ed
动态方法决议到底干了什么,源码如下
static NEVER_INLINE IMP
resolveMethod_locked(id inst, SEL sel, Class cls, int behavior)
{
runtimeLock.assertLocked();
ASSERT(cls->isRealized());
runtimeLock.unlock();
//判断cls类是否是元类,如果类说明说明调用的是实例方法
if (! cls->isMetaClass()) {
// try [cls resolveInstanceMethod:sel]
resolveInstanceMethod(inst, sel, cls);
}
else { //如果是元类,说明调用的是类方法
// try [nonMetaClass resolveClassMethod:sel]
// and [cls resolveInstanceMethod:sel]
resolveClassMethod(inst, sel, cls);
//如果没有找到,在元类的对象方法中查找,类方法相当于在元类中的对象方法
if (!lookUpImpOrNilTryCache(inst, sel, cls)) {
resolveInstanceMethod(inst, sel, cls);
}
}
// chances are that calling the resolver have populated the cache
// so attempt using it
// 快速查找和慢速查找sel对应的imp返回imp 实际上就是从缓存中取,因为前面已经缓存过了
return lookUpImpOrForwardTryCache(inst, sel, cls, behavior);
}
- 首先判断
cls
是否是元类
- 如果不是
元类
只是普通类,那么肉跳测吉凶说明调用的实例方法跳转resolveInstanceMethod
流程 - 如果是
元类
,源码中的图片那么说明调用的是类方法跳转resolveClassMethod
流程 -
lookUpImpOrForwardTryCache
快速查找和慢速查找sel
对应的imp
然后返回imp
resolveInstanceMethod
方法
static void resolveInstanceMethod(id inst, SEL sel, Class cls)
{ // inst 对象 // cls 类
runtimeLock.assertUnlocked();
ASSERT(cls->isRealized());
SEL resolve_sel = @selector(resolveInstanceMethod:);
//只要cls的元类初始化 resolve_sel方法一定实现因为NSObject默认实现了resolveInstanceMethod
//目的是将resolveInstanceMethod方法缓存到cls的元类中
//通过lookUpImpOrNilTryCache的数我们知道`resolve_sel`是类方法
if (!lookUpImpOrNilTryCache(cls, resolve_sel, cls->ISA(/*authenticated*/true))) {
// Resolver not implemented.
return;
}
//发送消息调用resolveInstanceMethod方法
//通过 objc_msgSend 发送消息 接收者是cls说明是类方法
BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
//判断 resolve_sel 方法有没有实现,注意是`resolve_sel`方法
bool resolved = msg(cls, resolve_sel, sel);
//为什么还有调用 lookUpImpOrNilTryCache 查询缓存和慢速查找呢
//虽然 resolveInstanceMethod 方法调用了。但是里面不一定实现了sel的方法
// 所以还是要去查找sel对应的imp,如果没有实现就会把imp = forward_imp 插入缓存中
// 以为慢速查找流程动态决议方法已经走过了,此时imp = forward_imp走down和down_unlock
IMP imp = lookUpImpOrNilTryCache(inst, sel, cls);
// resolved 和 imp 存在说明动态添加了
if (resolved && PrintResolving) {
if (imp) {
...
}
else {
// Method resolver didn't add anything?
...
}
}
}
- 首先创建
resolveInstanceMethod
的SEL resolve_sel
- 根据
lookUpImpOrNilTryCache (cls, resolve_sel, cls->ISA(true))
知道resolveInstaiOSnceMethod苹果7
是类方法,通过快速和慢速查找流程查找resolv苹果手机怎么录屏e_sel
对应的imp
,缓存resolveInstanceMethod
方法 - 直接通过
msg(cls, resolve_sel, s源码编程器el)
给类发送消初始化电脑的后果息,从这里也能看到re源码1688solveInstanceMethod
是类方法
lookUpImpOrNilTryCache(inst, sel, cls)
快速和慢速查找流程
- 通过
lookUpImpOrNilTryCache
来确定resolveInstanceMethod
方法中有没ios模拟器有实现sel
对应的imp
- 如果实现了,缓存中没有,进入
lookUpI初始化磁盘mpOrForward
查找到sel人头攒动的读音
对应imp
插入缓存,调用imp
查找流程结束 - 如果没有实现,缓存中没有,进入
lookUpImpOrForward
查找,sel
没有查找到对应的imp
,此时苹果7imp
=闰土刺猹forward_imp
,动态方法决议
只调用一次,此时会走done_unlock
和done
流程,既sel
和forward_imp
插入缓存,进行消息转发
resolveInstanceMethod
方法
static void resolveClassMethod(id inst, SEL sel, Class cls)
{
runtimeLock.assertUnlocked();
ASSERT(cls->isRealized());
ASSERT(cls->isMetaClass());
// inst 类 //cls元类
//查询元类有没有实现 NSObject默认实现resolveClassMethod方法
if (!lookUpImpOrNilTryCache(inst, @selector(resolveClassMethod:), cls)) {
// Resolver not implemented.
return;
}
//返回类
Class nonmeta;
{
mutex_locker_t lock(runtimeLock);
nonmeta = getMaybeUnrealizedNonMetaClass(cls, inst);
// +initialize path should have realized nonmeta already
if (!nonmeta->isRealized()) {
_objc_fatal("nonmeta class %s (%p) unexpectedly not realized",
nonmeta->nameForLogging(), nonmeta);
}
}
BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
//向类中发送消息
bool resolved = msg(nonmeta, @selector(resolveClassMethod:), sel);
//类方法相当于元类中的实例方法,同样去快速和慢速的查找
IMP imp = lookUpImpOrNilTryCache(inst, sel, cls);
if (resolved && PrintResolving) {
if (imp) {
...
}
else {
// Method resolver didn't add anything?
...
}
}
}
-
resolveClassMethod
在NSobject
中已经实现,只要元类初始化就可以了,目的是缓存在元类中 - 调用
resolveClassMethod
类方法,目的是实现可能resolveClassMethod``方法中动态实现seios应用商店l对应的imp
-
imp = lookUpImpOrNilTryCache(inst, sel, cls)
缓存s苹果el
对应的imp
,不管imp
有没有动态添加,如果没有缓存的就是forward_源码imp初始化失败是怎么解决
lookUpImpOrNilTryCache
方法
lookUpImpOrNilTryCache
方法名字,可以理解就是查找imp
或者nil
尽可能的通过查询cache
的方式,在resolveInstanceMethod
方法和resolveClassMethod
方法都调用lookUpImpOrNilTry苹果xCache
extern IMP lookUpImpOrNilTryCache(id obj, SEL, Class cls, int behavior = 0);
IMP lookUpImpOrNilTryCache(id inst, SEL sel, Class cls, int behavior)
{
// LOOKUP_NIL = 4 没有传参数behavior = 0 0 | 4 = 4
return _lookUpImpTryCache(inst, sel, cls, behavior | LOOKUP_NIL);
}
首先苹果手机最后一个参数默认是behios应用商店avior
= 0
,LOOKUP_NIL
= 4
, behavior
|LOOKUP_NIL
大于等于LOOKUP_NIL
ALWAYS_INLINE
static IMP _lookUpImpTryCache(id inst, SEL sel, Class cls, int behavior)
{
runtimeLock.assertUnlocked();
//cls 是否初始化
if (slowpath(!cls->isInitialized())) {
// 没有初始化就去查找 lookUpImpOrForward 查找时可以初始化
return lookUpImpOrForward(inst, sel, cls, behavior);
}
//在缓存中查找sel对应的imp
IMP imp = cache_getImp(cls, sel);
// imp有值 进入done流程
if (imp != NULL) goto done;
#if CONFIG_USE_PREOPT_CACHES
//是否有共享缓存
if (fastpath(cls->cache.isConstantOptimizedCache(/* strict */true))) {
imp = cache_getImp(cls->cache.`preoptFallbackClass(), sel);
}`
#endif
// 缓存中没有查询到imp 进入慢速查找流程
// behavior = 4 ,4 & 2 = 0 不会进入动态方法决议,所以不会一直循环
if (slowpath(imp == NULL)) {
return lookUpImpOrForward(inst, sel, cls, behavior);
}
done:
//(behavior & LOOKUP_NIL) = 4 & 4 = 1
//LOOKUP_NIL 只是配合_objc_msgForward_impcache 写入缓存
if ((behavior & LOOKUP_NIL) && imp == (IMP)_objc_msgForward_impcache) {
return nil;
}
return imp;
}
判断cls
是否初始化一般都会初始化的
缓存中查找
- 在缓存中查找
sel源码编程器
对应的imp
- 如果
imp
存在跳转done
流程 - 判断是否有共享人体肠道结构示意图缓存给系统底层库用的
- 如果缓存中没有查询到
imp
,进入慢速查找流程
慢速查找流苹果7程
- 慢速查找流程中,
behavior
=4
,4
&2
=0
进入动人体承受的最大电压态方法决议,所以不会一直循环 - 最重要的如果没有查询到初始化失败是怎么解决此时
imp
=forward_imp
,跳转lookUpImpOrForward
中的done_unlock
和done
流程,插入缓存,返回forward_imp
done
流程
-
dios下载one
流程: (behavior
&LOOKUP_NIL
) 且imp
=_objc_msgForward_impcache
,如果缓存中的是forward_imp
,就直接返回nil
,否者返回的imp
,LOOKUP_NIL
条件就是来查找是否动态添加了imp
还有就是苹果手机将im苹果范冰冰p
插入缓存
lookUpImpOrNilTryCache
的主要作用通过LOOKUP_NIL
来控制插入缓存,不管sel
对应的imp
有没有实现,还有就是苹果x如果im人体承受的最大电压p
返回了有值那么一定是在动态方法决议中动态实现了iiOSmp
resol苹果手机veInstanceMethod
实例探究
实现resolveInstanceMethod
方法
在LWPerson
类中添加r苹果范冰冰esolveInstanceMethod
方法
int main(int argc, const char * argv[]) {
@autoreleasepool {
LWPerson * person = [LWPerson alloc];
[person sayHello];
}
return 0;
}
@implementation LWPerson
+(BOOL)resolveInstanceMethod:(SEL)sel{
NSLog(@"--进入%@--",NSStringFromSelector(sel));
return [super resolveInstanceMethod:sel];
}
@end
2021-07-03 12:57:22.582805+0800 KCObjcBuild[7949:330351] --进入sayHello--
2021-07-03 12:57:22.583624+0800 KCObjcBuild[7949:330351] --进入sayHello--
在崩溃之前确实调用了resolveI肉跳测吉凶nstanceMethod
方法
疑问:为什么会调用ios是苹果还是安卓两次resolveInstanceMethod
方法初始化呢
第一次是走动态方法决议系统自动向resolveInstanceMethod
发送消息,那么第苹果手机怎么录屏二次是怎么调用的呢?
第一次调用res源码编辑器olveInstanceMethod
的堆栈信息,可以看到走的人体承受的最大电压是慢速查找流程的动态决议方法
第二次调用resolveInstanceMethod
的堆栈信息,由底层系统库CoreFoundation
调起,在消息转发完成以后再次开启慢速查找流程,进入动态方法决议又调用一次resolveInstanceMethod人头攒动的近义词
,所以总共是两次,第二次调用的详细流程在后面会作详细的阐述
动态添加sayHello
方法
@implementation LWPerson
+(BOOL)resolveInstanceMethod:(SEL)sel{
NSLog(@"--进入%@--",NSStringFromSelector(sel));
if (@selector(sayHello) == sel) {
IMP imp = class_getMethodImplementation(self , @selector(sayHello2));
Method meth = class_getInstanceMethod(self , @selector(sayHello2));
const char * type = method_getTypeEncoding(meth);
return class_addMethod(self ,sel, imp, type);;
}
return [super resolveInstanceMethod:sel];
}
- (void)sayHello2{
NSLog(@"--%s---",__func__);
}
@end
-
resolveInstanceMethod
只初始化英文调用一次,因为动态添加了sayHel苹果lo
方法lookUpImpOrForwardTryCache
直接获取imp
,直接调用imp
,查找流程结束 - 崩溃也解决了动态方法决议系统给了一次苹果手机机会
- 具体流程:
resolveMethod_locked
–>resolveInstanceMethod
–> 调用resolveInstanceMethod
–>lookUpImpOrNilTryCache(inst, sel, cls初始化电脑时出现问题未进行更改)
–>lookUpImpOrFor源码中的图片wardTryCache
–> 调用苹果8im苹果8p
resolv苹果官网eClasios越狱sMethod
实例探究
实现resol源码编辑器veClassMethod
方法
在LWPerson
类中添加resolveInstios14.4.1更新了什么anceMethod
方法,不动态实现tios16est
方法
int main(int argc, const char * argv[]) {
@autoreleasepool {
LWPerson * person = [LWPerson alloc];
[LWPerson test];
}
return 0;
}
@implementation LWPerson
+(BOOL)resolveClassMethod:(SEL)sel{
NSLog(@"--进入%@--",NSStringFromSelector(sel));
return [super resolveClassMethod:sel];
}
@end
2021-07-03 13:51:22.784897+0800 KCObjcBuild[8483:359482] --进入test--
2021-07-03 13:51:22.785774+0800 KCObjcBuild[8483:359482] --进入test--
- 在崩溃之前确实调用了
resolveClassMethod
方法,而且调用了两次,调用两次的逻辑和resolveInstanceMethod
方法调用两次是一样的 - 调用
resolveClassMethod
以后,会去查找lookUpImpOrNi让天秤难以放弃的星座lTryCache
有没有具体动态实现sel
对应的imp
,元类的缓存中此时有sel
对应的imp
,这个imp
是forward_imp
。look人头攒动的读音UpImpOrNilTryCache
里面有判断直接返回nil
,此时直接到resolveInstanceMethod
查找,因为类方法实际上就是元类中的实例方法 - 如果最后还是没有实现
lookUpImpOrFo人头攒动的近义词rwardTryCache
获取到forward_imp
进入消息转发流程
动态添加te源码中的图片st
方法
+(BOOL)resolveClassMethod:(SEL)sel{
if (@selector(test) == sel) {
NSLog(@"resolveClassMethod--进入%@--",NSStringFromSelector(sel));
IMP imp = class_getMethodImplementation(object_getClass([self class]), @selector(newTest));
Method meth = class_getClassMethod(object_getClass([self class]) , @selector(newTest));
const char * type = method_getTypeEncoding(meth);
return class_addMethod(object_getClass([self class]) ,sel, imp, type);;
}
return [super resolveClassMethod:sel];
}
+(void)newTest{
NSLog(@"--%s---",__func__);
}
2021-07-03 16:14:04.262688+0800 KCObjcBuild[9964:434208] resolveClassMethod--进入test--
2021-07-03 16:14:04.263331+0800 KCObjcBuild[9964:434208] --+[LWPerson newTest]---
-
resolveClassMethod
只调用一次,因为动态添加了test
方法 -
resolveClassMethod
和resolveInstanceMethod
的调用流程基本一样,如果reso源码中的图片lveClassMethod
没有查询到调用一次resolveInstanceMet苹果手机怎么录屏hod
调用
resolveClassMethod
特殊之处
既然调用resolveClassMethod
没有查询到,在调用接到resolveInstanceMethod
查找,那么在LWPerson
类中同时实现resolvios系统eClassMethod
和r苹果12esolveios越狱InstanceMethod
方法,理论上方法都能调用
int main(int argc, const char * argv[]) {
@autoreleasepool {
LWPerson * person = [LWPerson alloc];
[LWPerson test];
}
return 0;
}
@implementation LWPerson
+(BOOL)resolveClassMethod:(SEL)sel{
NSLog(@"resolveClassMethod--进入%@--",NSStringFromSelector(sel));
return [super resolveClassMethod:sel];
}
+(BOOL)resolveInstanceMethod:(SEL)sel{
NSLog(@"resolveInstanceMethod--进入%@--",NSStringFromSelector(sel));
return [super resolveInstanceMethod:sel];
}
@end
2021-07-03 14:52:55.076902+0800 KCObjcBuild[9158:391254] resolveClassMethod--进入test--
2021-07-03 14:52:55.077890+0800 KCObjcBuild[9158:391254] resolveClassMethod--进入test--
结果和我们想的不一样,只调用LWPerson
类中的resolveClassMethod
,没有调用LWPerson
类resolveInstanceMethod
方法,源码中不是显示了调用苹果13resolveInst苹果范冰冰anceMethod
,那跟踪下源码
inst
是LWPerson
类 ,cls
是LWPerson
类的元类
lookUpImpOrNilTryCache
的参数cls->ISA(tr初始化磁盘ue)
是根源类,进入l让天秤难以放弃的星座ookUpImpOrN初始化电脑时出现问题ilTryCache
此时inst
是LWPerson
类的元类
,cls
是根源类,快速查找和慢速查找是到根元类
查找,意味着苹果13元类
调用了实例方法
msg(cls, resolve_sel, sel)
也可以验证objc_msgSend
发送消息不区分-
和+
方法。objc_msgSen苹果8d
的接收者cls
是元类
,意味着像让天秤倒追的星座元类
中发消息,消息查找会到根元类
去苹果手机怎么录屏查找,所以
resolveInstanceMethod
在元类
中,才会被调用,所以在类初始化电脑时出现问题中的res苹果xolveInstanceMethod
方法不会被调用,不是说元类
和类
的名字是一样的嘛,但是地址不一样哦
创建一个NS苹果12Object + LW人体承受的最大电压
,在分类中添加resolveInstanceMethod
方法,因为根元类
的父类是根类
,根元类
找不到会到根类
中查初始化电脑找,因为根元类
没法创建所以只能用根类
@implementation NSObject (LW)
+(BOOL)resolveInstanceMethod:(SEL)sel{
if (@selector(test) == sel) {
NSLog(@"resolveInstanceMethod--进入%@--",NSStringFromSelector(sel));
}
return NO;
}
@end
2021-07-03 16:00:21.999137+0800 KCObjcBuild[9755:425282] resolveClassMethod--进入test--
2021-07-03 16:00:22.000222+0800 KCObjcBuild[9755:425282] resolveInstanceMethod--进入test--
2021-07-03 16:00:22.000579+0800 KCObjcBuild[9755:425282] resolveClassMethod--进入test--
2021-07-03 16:00:22.000681+0800 KCObjcBuild[9755:425282] resolveInstanceMethod--进入test--
跟源码分析的逻辑是一样的先调用resolveClassMethod
,再调用resolveInstanceMethod
,都是两次
整合
动态方法决议
resolveClassMethod
方法中如果没有动态源码网站添加类方法,会调用元类
中的resolveInstanceMethod
。那么能不能把ios下载resolveInstanceMethod
写到一个公用类中,使类方法
和实例方法
都能调用
- 实例方法查找流程:
对象
–>类
–>直到根类
(NSObject
) –>ni初始化英文l
- 类方法查找流程:
类
–>元类
–>直到ios是什么意思根类
(NSObject
) –>nil
到最后都找到NSObj初始化是什么意思ect
类中,所以这个公用类就是NSObject
分类
@implementation NSObject (LW)
+(BOOL)resolveInstanceMethod:(SEL)sel{
if (@selector(sayHello) == sel) {
NSLog(@"--进入%@--",NSStringFromSelector(sel));
IMP imp = class_getMethodImplementation(self , @selector(sayHello2));
Method meth = class_getInstanceMethod(self , @selector(sayHello2));
const char * type = method_getTypeEncoding(meth);
return class_addMethod(self ,sel, imp, type);;
}else if (@selector(test) == sel){
NSLog(@"--进入%@--",NSStringFromSelector(sel));
IMP imp = class_getMethodImplementation(object_getClass([self class]), @selector(newTest));
Method meth = class_getClassMethod(object_getClass([self class]) , @selector(newTest));
const char * type = method_getTypeEncoding(meth);
return class_addMethod(object_getClass([self class]) ,sel, imp, type);;
}
return NO;
}
- (void)sayHello2{
NSLog(@"--%s---",__func__);
}
+(void)newTest{
NSLog(@"--%s---",__func__);
}
@end
2021-07-03 16:54:56.295564+0800 KCObjcBuild[10394:453264] --进入sayHello--
2021-07-03 16:54:56.296146+0800 KCObjcBuild[10394:453264] ---[NSObject(LW) sayHello2]---
2021-07-03 16:54:56.296443+0800 KCObjcBuild[10394:453264] --进入test--
2021-07-03 16:54:56.296615+0800 KCObjcBuild[10394:453264] --+[NSObject(LW) newTest]---
实例方法是类方法调用,系统都自动调用了resolveInstanceMethod
方法,和上面探究苹果7的吻合。
动态苹果8方法决议优点
- 可以统一处理方法崩溃的问题,出现方法崩溃可以上报服务器,或者跳转到首页ios系统
- 如果项目中是不同的模块你可以根据命名不同,进行业务的区别
- 这种方式叫切面编程熟成
AOP
AOP
和OOP
的区别
-
OOP
:实际上是对对象的属性和行为的封装,功能相同的抽取出来单独封装,强依赖性,高耦合 -
AOP
:是处理某个步骤和阶段的,从中进行切面的提取,有重复的操作行为,AOP就可rtc是什么意思以提取出来,运用动态代理,实现程序功能的统一维护,依赖性小,耦合度小,单独把AOP
提取出来的功能移除也不会对主代码造成影响。AOP
更像一个三维的纵轴,平面内的各个苹果类有共同逻辑的通过Aios下载OP
串联起来,本身平面内的各个类没有任何的关联
流程图后面补
消苹果因不送充电器被判赔7000元息转发
快速和慢速查找初始化电脑的后果流程没有查询到,动态决议方法也没有查找到,下面就会进入消息转发流程,但是让天秤难以放弃的星座在objc4-818.2
源码中没有发现相关的源源码1688码,CoreFunction
提供的源码也不详细查询不到。苹果还是提供了日志辅助功能
日志辅助
通过loo苹果因不送充电器被判赔7000元kUpImpOrForward
–> log_and_fill初始化电脑_cache源码精灵永久兑换码
–&g初始化电脑时出现问题未进行更改t; logMessageSend
,进入l初始化sdk什么意思og初始化sdk什么意思MessageSend
看到源码的实现
if (slowpath(objcMsgLogEnabled && implementer)) {
bool cacheIt = logMessageSend(implementer->isMetaClass(),
cls->nameForLogging(),
implementer->nameForLogging(),
sel);
if (!cacheIt) return;
}
logMessageSend
能调用objcMsgLogEnabled
必须是YES
bool objcMsgLogEnabled = false;
static int objcMsgLogFD = -1;
bool logMessageSend(bool isClassMethod,
const char *objectsClass,
const char *implementingClass,
SEL selector)
{
char buf[ 1024 ];
// Create/open the log file
if (objcMsgLogFD == (-1))
{
//文件的路径
snprintf (buf, sizeof(buf), "/tmp/msgSends-%d", (int) getpid ());
objcMsgLogFD = secure_open (buf, O_WRONLY | O_CREAT, geteuid());
if (objcMsgLogFD < 0) {
// no log file - disable logging
objcMsgLogEnabled = false;
objcMsgLogFD = -1;
return true;
}
}
// Make the log entry
snprintf(buf, sizeof(buf), "%c %s %s %sn",
isClassMethod ? '+' : '-',
objectsClass,
implementingClass,
sel_getName(selector));
objcMsgLogLock.lock();
write (objcMsgLogFD, buf, strlen(buf));
objcMsgLogLock.unlock();
// Tell caller to not cache the method
return false;
}
/tmp/msgSends
是日志保存的沙盒路径,开启以后直接到沙盒路径初始化磁盘下就能获取文件。默认的o让天秤难以放弃的星座bjcMsgLogEnabled
= false
所以要找到赋值的地源码精灵永久兑换码方
void instrumentObjcMessageSends(BOOL flag)
{
bool enable = flag;
// Shortcut NOP
if (objcMsgLogEnabled == enable)
return;
// If enabling, flush all method caches so we get some traces
if (enable)
_objc_flush_caches(Nil);
// Sync our log file
if (objcMsgLogFD != -1)
fsync (objcMsgLogFD);
objcMsgLogEnabled = enable;
}
通过instrumentO让天秤倒追的星座bjcMessageSeRTCnds
给objcMsgLogEnabled
赋值,所以在需要日志信息的地方声明instrume闰土刺猹ntO苹果xbjcMessageSends
既 extern void instrumentObjcMessageSends(BOOL flag)
;初始化游戏启动器失败
extern void instrumentObjcMessageSends(BOOL flag);
int main(int argc, const char * argv[]) {
@autoreleasepool {
LWPerson * p = [LWPerson alloc];
instrumentObjcMessageSends(YES);
[p sayHello];
instrumentObjcMessageSends(NO);
}
return 0;
}
在动态决议方法之后的消息转发流程有forwardingTargetForSelector
和iOSmethodSignatureForSelector
后面会接着探讨消息转发流程
总结
动态方法决议相当于多给一次机会,给你动态实现的机会,同时也给了开发者更多新的尝试的机会。不得不说动态方法决议的流程是复杂的,想要搞的更加清楚明白需要细细的体会