iOS - 面试宝典

iOS之学习总结

2021-05-09  本文已影响0人  枫叶无处漂泊

一、load 方法

1、load方法加载

2、调用顺序

  1. 先调用类的+load方法

    • 按照编译先后顺序调用(先编译,先调用)
    • 调用子类的+load方法之前会先调用父类的+load方法
  2. 再调用分类的+load方法

    • 按照编译先后顺序调用(先编译先调用)

3、load加载过程底层原发源码执行顺序

  1. _objc_init: 加载对象的入口方法,_objc_init里面调用load_images方法

  2. load_images :加载所有类load的方法,里面调用prepare_load_methods、call_load_methods.

  3. prepare_load_methods:加载load方法的准备工作

    1. classref_t *classList = _getObjc2NonlazyClassList(mhdr, &count)方法获取所有类,遍历classList
      • 遍历classList,调用schedule_class_load(class cls):
        • 先 递归调用schedule_class_load(cls->superclass)调用父类
        • add_class_to_loadable_list:讲cls加载到数据的后面
    2. category **categoryList = _getObjc2NonlazyCategoryList(mhdr, &count);获取所有分类。
      • 遍历categoryList,调用add_category_to_loadable_list把分类加到列表最后面。

(categoryList是一个二维数组里,第一维代表是某一个类,第二维代表的是某个类下面有多个分类。
[person_category_list,stu_categorylist].
person_category_list = [category_t, category_t]
stu_category_list = [category_t, category_t]

  1. call_load_methods:调用load方法列表
    • call_class_loads():先加载完类的load方法

      • 类的加载过程,遍历add_class_to_loadable_list中类,调用load_method函数调用load方法。
    • call_category_loads():在加载分类的load方法

      • 分类的加载过程,遍历add_class_to_loadable_list中类,调用load_method函数调用load方法。

类和分类最后都会调用(*load_method)(cls, SEL_load) 这个函数,+load方法是根据方法地址直接调用,并不是经过objc_msgSend函数调用。

二、initialize方法

一、initialize调用时机

二、底层源码实现

  1. 调用objc_msgSend
    • class_getClassMethod(Class cls,SEL sel)(找类方法,传的就是元类)

    • lookUpImpOrNil 找方法

    • lookUpImpOrForward 继续查找

    • if (initialize && !cls->isInitialize) {
      _class_initialize方法调用initialize
      } 先判断是否需要初始化,需要的话就调用

    • callInitialize调用initialize

    • 最后调用到 objc_msgSend(cls, SEL_initialize)

三.load 与initialize区别

1、调用方式

2、调用时刻

3、l调用顺序

load调用顺序:
initialize调用顺序

三、关联对象

给分类添加属性,分类只声明没有方法的实现,实现的方式是关联对象。
关联对象所用的相关类主要是下面4个类:

使用方式

分类.h文件
@property(nonatomic,copy)NSString *name;

分类.m文件

- (void)setName {
    objc_setAssociatedObject( self,
                                @slector(name), OBJC_ASSOCIATION_COPY_NONATOMIC)
}

- (void)name {
    objc_getAssociatedObject( self,
                                @slector(name), OBJC_ASSOCIATION_COPY_NONATOMIC)
}

第一个参数给关联对象

第二个是key

第三参数是关联策略

关联对象的核心原理

class AssociationManager {
    static AssociationHashMap *_map;
}
 AssociationHashMap : public unordered_map<disguised_prt_t, Object  AssociationMap>

如下面表格:

key value
disguised_prt_t Object AssociationMap
disguised_prt_t Object AssociationMap
class ObjectAssociationMap : public std ::map <void *, ObjcAssociation>

如下面的表格:

key value
void * ObjcAssociation
void * ObjcAssociation
class ObjcAssociation {
    uintptr_t _policy;
    id _value;
}

关联对象的原理执行流程如下图:

[图片上传失败...(image-212701-1620575201542)]

3、移除关联对象

4.关联对象总结

四、KVO

1、kvo 使用

/*
@observer:就是观察者,是谁想要观测对象的值的改变。
@keyPath:就是想要观察的对象属性。
@options:options一般选择NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld,
这样当属性值发生改变时我们可以同时获得旧值和新值,如果我们只填NSKeyValueObservingOptionNew则属性发生改变时只会获得新值。
@context:想要携带的其他信息,比如一个字符串或者字典什么的。
*/
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath 
options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
/*
@keyPath:观察的属性
@object:观察的是哪个对象的属性
@change:这是一个字典类型的值,通过键值对显示新的属性值和旧的属性值
@context:上面添加观察者时携带的信息
*/
- (void)observeValueForKeyPath:(nullable NSString *)keyPath 
ofObject:(nullable id)object change:(nullable NSDictionary<NSKeyValueChangeKey, id> *)change 
context:(nullable void *)context;

如下图:

KVO执行过程.png

五、KVC实现原理

执行流程如下图:


KVC赋值.png

执行流程如下图:

KVC取值.png

六、关联对象结构图

关联对象.png

七、Notification通知心原理

Notification通知心原理

八、响应链和事件传递

响应链和事件传递

九、编程中的六大设计原则

编程中的六大设计原则

上一篇 下一篇

猜你喜欢

热点阅读