iOS面试剖析

OC基础特性

2019-10-14  本文已影响0人  huoshe2019
基础特性

一、分类(Category)

问题1:你用分类都做了哪些事情?

1.1、特点

1.2:分类中都可以添加哪些内容?

1.3、分类数据结构

Category 是表示一个指向分类的结构体的指针,其定义如下:
typedef struct objc_category *Category;
struct objc_category {
  //分类名
  char *category_name; 
  //分类所属的类名
  char *class_name;
  //实例方法列表
  struct objc_method_list *instance_methods; 
  //类方法列表
  struct objc_method_list *class_methods; 
  //分类所实现的协议列表
  struct objc_protocol_list *protocols;
 //实例属性列表
  struct property_list_t *instanceProperties;
}

1.4、加载调用栈(了解)

加载调用栈

备注:

1.5、源码分析

这里以添加实例方法举例:
remethodizeClass开始入手分析(只列出主要代码):

1.5.1

我们只分析分类当中实例方法添加的逻辑
因此在这里我们假设 isMeta = NO

bool isMeta = cls->isMetaClass();
1.5.2

生成一个新的二维数组,用来存放分类中的方法

method_list_t **mlists = (method_list_t **)
        malloc(cats->count * sizeof(*mlists));
1.5.3

遍历分类数组,采用倒叙遍历

//宿主分类的总数
int i = cats->count;
    while (i--) {
        //获取一个分类
        auto& entry = cats->list[i];
        //获取该分类的方法列表
        method_list_t *mlist = entry.cat->methodsForMeta(isMeta);
        if (mlist) {
            //最后编译的分类,方法最先添加到分类数组中
            mlists[mcount++] = mlist;
            fromBundle |= entry.hi->isBundle();
        }
    }
1.5.4

获取宿主类当中的rw数据,其中包含宿主类的方法列表信息

auto rw = cls->data();
1.5.5

分类方法拼接到rw的methods上
参数/变量含义:
rw代表类。
methods代表类的方法列表。
attachLists方法:将含有mcount个元素的mlists拼接到rw的methods上。

rw->methods.attachLists(mlists, mcount);
1.5.6

attachLists方法解析
假设列表中原有元素总数为2(oldCount = 2)。
假设将要添加的分类元素总数为3(addedCount = 3)。
[ [method_t , method_t], [method_t],
[method_t , method_t , method_t] ]

这里只分析有数组的情况

//列表中原有元素总数。假设oldCount = 2
uint32_t oldCount = array()->count;
//拼接之后的元素总数
uint32_t newCount = oldCount + addedCount;
//根据新总数重新分配内存
setArray((array_t *)realloc(array(), array_t::byteSize(newCount)));
//重新设置元素总数
array()->count = newCount;
/*
内存移动
[ [ ], [ ], [ ], [原有的第一个元素], [原有的第二个元素]]
*/
memmove(array()->lists + addedCount, array()->lists, 
                    oldCount * sizeof(array()->lists[0]));
/*
内存拷贝
[
    A ---> [addedLists中的第一个元素],
    B ---> [addedLists中的第二个元素],
    C ---> [addedLists中的第三个元素],
    [原有的第一个元素],
    [原有的第二个元素]
]
这也是分类方法会"覆盖"宿主类的方法的原因
*/
memcpy(array()->lists, addedLists, 
                   addedCount * sizeof(array()->lists[0]));

问题2:一个类的多个分类包含同名方法,最后哪个会生效?

解释:
谁最后编译,谁就生效。

1.6、分类总结

二、关联对象

问题3:能否给分类添加成员变量?

解释:
可以添加。
在分类的声明时,不能添加成员变量;但是可以通过关联对象的方法添加。

问题4:给分类添加的成员变量是否添加到宿主中?

解释:
没有添加到宿主中。被存放在一个全局容器中,并且为不同类添加的关联对象都放在同一个全局容器中。

2.1、获取属性值

objc_getAssociatedObject(id object, const void *key);

2.2、添加并设置属性值

objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);
typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
    OBJC_ASSOCIATION_ASSIGN = 0,  // 指定一个弱引用相关联的对象
    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, // 指定相关对象的强引用,非原子性
    OBJC_ASSOCIATION_COPY_NONATOMIC = 3,  // 指定相关的对象被复制,非原子性
    OBJC_ASSOCIATION_RETAIN = 01401,  // 指定相关对象的强引用,原子性
    OBJC_ASSOCIATION_COPY = 01403     // 指定相关的对象被复制,原子性   
};

2.3、移除所有的关联对象

objc_removeAssociatedObjects(id object);

2.4、关联对象的本质

关联对象本质 json对比

这里包含三部分数据结构:

由上面可以知道,关联对象没有存放到原来的对象里面,而是自己维护了一个全局map来存放的

问题5:怎样清除一个关联对象?

解释:
通过objc_setAssociatedObject,将其中value传值为nil,就可以了。

三、扩展(Extension)

问题6:属性和变量的区别?

属性 = 变量 + set方法 + get方法

问题7:分类和扩展的区别?

四、代理

问题8:代理的工作流程是什么?

代理工作流程

问题9:为什么代理声明的时候,要使用weak?

因为代理方一般强引用委托方,为了防止循环引用,委托方必须对代理方进行弱引用。


代理

五、通知

问题10:通知和代理的区别?

问题11:如何实现通知机制?

通知原理
在通知中心,内部维护一个Map表,它的key是通知名称,value是观察者表List观察者表List内部包含多个observer对象;observer对象包含通知接收的观察者,观察者调用的方法等等。

六、KVO

6.1、概念

6.2、KVO调用发生过程图

过程图

问题12:isa混写技术在KVO中是怎么体现的?

见6.2.KVO调用发生过程图

6.3、重写setter方法的具体实现

6.3.1、两个重要方法
重写方法
6.3.2、具体实现
具体实现

备注:

问题13:通过KVC设置value能否生效?

可以生效

问题14:为什么通过KVC设置value能生效?

因为KVC内部原理表明,这样设置value会调用obj对象的setter方法

问题15:通过成员变量直接赋值value能够生效?

6.4、KVO总结

七、KVC

问题16:什么是KVC

问题17:KVC会不会破坏面向对象的编程思想?

会破坏。
因为上面的key是没有限制的,即使是私有变量,也可以通过KVC设置私有变量的value。

7.1、valueForKey系统实现流程

7.1.1、流程图
valueForKey
7.1.2、流程图 get方法是否存在的判断规则
7.1.3、流程图 实例方法是否存在的判断规则

7.2、setValue:forKey:系统实现流程

7.2.1、流程图

setValue:forKey:

八、属性关键字

8.1、属性关键字分类:

1、读写权限

2、 原子性

3、 引用计数

8.2、assign特点

8.2、weak特点

问题18:assgin与weak区别

8.3、copy

问题19:见下图

copy面试题
8.3.1、深拷贝和浅拷贝

九、笔试题总结

9.1、MRC下如何重写retain修饰变量的setter方法?

MRC

9.2、请简述分类的实现原理

1、分类的实现原理是由运行时决议的。
2、不同分类的含有同名分类方法,谁最后编译,谁就生效。
3、如果分类中的方法恰好与目标类中的方法同名,分类会覆盖同名的目标类方法。

9.3、KVO的实现原理是怎样的?

1、KVO是系统关于观察者模式的一种体现。
2、KVO运用了isa混写技术;在动态运行时,为某一个类动态添加一个子类,重写了它的setter方法;将原有类的isa指针指向新创建的子类。

9.4、能否为分类添加成员变量?

不能。因为它的数据结构中,没有成员变量。
可以通过关联对象


问题1:什么是分类?分类的原理和实现机制是什么?

问题5:KVO实现机制?

问题6:KVC实现机制?

问题7:属性关键字?

上一篇 下一篇

猜你喜欢

热点阅读