面试题收集

一个Objective-C对象如何进行内存布局

iOS 内存调试技巧

iOS 下的读写锁的简单实现

KVC的底层原理

KVO 底层原理

iOS 高级面试题--答案

iOS面试备战-网络篇

OC [objc message]发送消息的过程

(1) 首先根据obj的isa指针进入它的类对象cls里面。
(2) 在obj的cls里面,首先到缓存cache_t里面查询方法message的函数实现,如果找到,就直接调用该函数。
(3) 如果上一步没有找到对应函数,在对该cls的方法列表进行二分/遍历查找,如果找到了对应函数,首先会将该方法缓存到obj的类对象cls的cache_t里面,然后对函数进行调用。
(4) 在每次进行缓存操作之前,首先需要检查缓存容量,如果缓存内的方法数量超过规定的临界值(设定容量的3/4),需要先对缓存进行2倍扩容,原先缓存过的方法全部丢弃,然后将当前方法存入扩容后的新缓存内
(5) 如果在obj的cls对象里面,发现缓存和方法列表都找不到mssage方法,则通过cls的superclass指针进入它的父类对象f_cls里面
(6) 进入f_cls后,首先在它的cache_t里面查找mssage,如果找到了该方法,那么会首先将方法缓存到消息发送者cls的cache_t里面,然后调用方法对应的函数。
(7) 如果上一步没有找到方法,将会重复f_cls的superclass查找流程。直到superclass为nil,如果还没找到,将进入消息机制的动态解析阶段。
(8) 发送 +resolveClassMethod or +resolveInstanceMethod.消息。进入同上面的消息发送流程。

initialize的调用规则

  • +initialize方法会在类对象 第一次 接收到消息的时候调用
  • 调用顺序:调用某个类的+initialize之前,会先调用其父类的+initialize(前提是父类的+initialize从来没有被调用过)
  • 由于+initialize的调用,是通过消息机制,也就是objc_msgSend(),因此如果子类的+initialize没有实现,就会去调用父类的+initialize
  • 基于同样的原因,如果分类实现的+initialize,那么就会“覆盖”类对象本身的+initialize方法而被调用。

线程池原理

  • 【第一步】判断核心线程池是否都正在执行任务
    返回NO,创建新的工作线程去执行
    返回YES,进入【第二步】
  • 【第二步】判断线程池工作队列是否已经饱满
    返回NO,将任务存储到工作队列,等待CPU调度
    返回YES,进入【第三步】
  • 【第三步】判断线程池中的线程是否都处于执行状态

返回NO,安排可调度线程池中空闲的线程去执行任务
返回YES,进入【第四步】

  • 【第四步】交给饱和策略去执行,主要有以下四种(在iOS中并没有找到以下4种策略)
    1. AbortPolicy:直接抛出RejectedExecutionExeception异常来阻止系统正常运行
    2. CallerRunsPolicy:将任务回退到调用者
    3. DisOldestPolicy:丢掉等待最久的任务
    4. DisCardPolicy:直接丢弃任务

method_swizzling

  1. 需要保证只交换一次,写在dispatch_once中
  2. 在子类分类中实现方法交换,交换的原方法如果是父类的方法,那么父类在调用时,会出现崩溃。因为方法被交换了,交换后的实现在子类分类中,父类中找不到对应实现,导致崩溃。优化建议:先判断原方法在要交换的类中存不存在对应的实现,不存在,先添加,然后交换;如果存在,则直接交换;
  3. 需要交换的原方法,在子类和父类中都没有实现。则交换时会交换失败,调用会进入递归循环,导致崩溃;优化建议:如果不存在原始方法,那么为了避免无意义交换,可先给原方法添加一个空的实现。
+ (void)zq_methodSwizzlingWithClass:(Class)cls originSEL:(SEL)oriSEL swizzledSEL:(SEL) swizzledSEL {
    if (!cls) NSLog(@"传入的交换类不能为空");
    
    Method oriMethod = class_getInstanceMethod(cls, oriSEL);
    Method swiMethod = class_getInstanceMethod(cls, swizzledSEL);

    if (!oriMethod) { // 优化不存在原方法时,交换方法后递归调用崩溃问题
        // 在oriMethod为nil时,替换后将swizzledSEL复制一个不做任何事的空实现,代码如下:
        class_addMethod(cls, oriSEL, method_getImplementation(swiMethod), method_getTypeEncoding(swiMethod));
        method_setImplementation(swiMethod, imp_implementationWithBlock(^(id self, SEL _cmd){ }));
    }

    // 一般交换方法: 交换自己有的方法 -- 走下面 因为自己有意味添加方法失败
    // 交换自己没有实现的方法:
    //   首先第一步:会先尝试给自己添加要交换的方法 :personInstanceMethod (SEL) -> swiMethod(IMP)
    //   然后再将父类的IMP给swizzle  personInstanceMethod(imp) -> swizzledSEL
    //oriSEL:personInstanceMethod
    BOOL didAddMethod = class_addMethod(cls, oriSEL, method_getImplementation(swiMethod), method_getTypeEncoding(swiMethod));
    if (didAddMethod) {
        class_replaceMethod(cls, swizzledSEL, method_getImplementation(oriMethod), method_getTypeEncoding(oriMethod));
    }else{
        method_exchangeImplementations(oriMethod, swiMethod);
    }
}

你可能感兴趣的:(面试题收集)