IOS底层原理之动态方法决议

前言

方法在编程中占用重要的地位,大家对方法熟悉又陌生。熟悉的是每天都在用,陌生的是大家对底层的实现其实是一知半解的。前面探究了方法的快速查找流程和慢速查找流程,对方法底查找流程有一定的了解。如果快速源码网站查找流程和慢速查找流源码之家程都没有找打方法的实现,后面的流程是怎么样的,苹果会给一次机会动态方法决议

准备工作人体承受的最大电压

案例分析

创建一个LWPerson类,声明一个sayHelloios应用商店法,方法不实现

int main(int argc, char * argv[]) {
    @autoreleasepool {
        LWPerson * perosn  = [LWPerson alloc];
        [perosn sayHello];
    }
    return 0;
}

IOS底层原理之动态方法决议

unrecognized经典的崩溃信息,在 IOS底层原理之方法慢速查找流程 中通过全局搜索doesNotRecognizeSelector或者unrecognized selector sent to人头攒动的近义词 instance,在源码中搜索方式查找到苹果13底层人头攒动的读音源码的实现,在方法查找流程中如果最后imp还是没有查找到,会调用forward_imp

IOS底层原理之动态方法决议

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_msgForwardTailCallFunctionPointer是个宏,前面探究过就是跳转impx17寄存器存放的是imp,从汇编中可以看出苹果xx17有关系的就是__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_unlockdone流程,既selforward_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?
            ...
        }
    }
}
  • resolveClassMethodNSobject中已经实现,只要元类初始化就可以了,目的是缓存在元类中
  • 调用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 = 0LOOKUP_NIL = 4behavior|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= 44 & 2 = 0进入动人体承受的最大电压态方法决议,所以不会一直循环
  • 最重要的如果没有查询到初始化失败是怎么解决此时imp= forward_imp,跳转lookUpImpOrForward中的done_unlockdone流程,插入缓存,返回forward_imp

done流程

  • dios下载one流程: (behavior & LOOKUP_NIL) 且 imp = _objc_msgForward_impcache,如果缓存中的是forward_imp,就直接返回nil,否者返回的impLOOKUP_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发送消息,那么第苹果手机怎么录屏二次是怎么调用的呢?

IOS底层原理之动态方法决议

第一次调用res源码编辑器olveInstanceMethod的堆栈信息,可以看到走的人体承受的最大电压是慢速查找流程的动态决议方法

IOS底层原理之动态方法决议

第二次调用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,这个impforward_implook人头攒动的读音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方法
  • resolveClassMethodresolveInstanceMethod的调用流程基本一样,如果reso源码中的图片lveClassMethod没有查询到调用一次resolveInstanceMet苹果手机怎么录屏hod调用

resolveClassMethod特殊之处

既然调用resolveClassMethod没有查询到,在调用接到resolveInstanceMethod查找,那么在LWPerson类中同时实现resolvios系统eClassMethodr苹果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,没有调用LWPersonresolveInstanceMethod方法,源码中不是显示了调用苹果13resolveInst苹果范冰冰anceMethod,那跟踪下源码

IOS底层原理之动态方法决议
instLWPerson类 ,clsLWPerson类的元类

IOS底层原理之动态方法决议

lookUpImpOrNilTryCache的参数cls->ISA(tr初始化磁盘ue)是根源类,进入l让天秤难以放弃的星座ookUpImpOrN初始化电脑时出现问题ilTryCache

IOS底层原理之动态方法决议

此时instLWPerson类的元类cls是根源类,快速查找和慢速查找是到根元类查找,意味着苹果13元类调用了实例方法

IOS底层原理之动态方法决议
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

AOPOOP的区别

  • 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让天秤倒追的星座bjcMessageSeRTCndsobjcMsgLogEnabled赋值,所以在需要日志信息的地方声明instrume闰土刺猹ntO苹果xbjcMessageSendsextern 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;
}

IOS底层原理之动态方法决议
在动态决议方法之后的消息转发流程有forwardingTargetForSelectoriOSmethodSignatureForSelector后面会接着探讨消息转发流程

总结

动态方法决议相当于多给一次机会,给你动态实现的机会,同时也给了开发者更多新的尝试的机会。不得不说动态方法决议的流程是复杂的,想要搞的更加清楚明白需要细细的体会

发表评论

提供最优质的资源集合

立即查看 了解详情