一个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种策略)
AbortPolicy
:直接抛出RejectedExecutionExeception
异常来阻止系统正常运行CallerRunsPolicy
:将任务回退到调用者DisOldestPolicy
:丢掉等待最久的任务DisCardPolicy
:直接丢弃任务
method_swizzling
- 需要保证只交换一次,写在dispatch_once中
- 在子类分类中实现方法交换,交换的原方法如果是父类的方法,那么父类在调用时,会出现崩溃。因为方法被交换了,交换后的实现在子类分类中,父类中找不到对应实现,导致崩溃。优化建议:先判断原方法在要交换的类中存不存在对应的实现,不存在,先添加,然后交换;如果存在,则直接交换;
- 需要交换的原方法,在子类和父类中都没有实现。则交换时会交换失败,调用会进入递归循环,导致崩溃;优化建议:如果不存在原始方法,那么为了避免无意义交换,可先给原方法添加一个空的实现。
+ (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);
}
}