《出一套iOS高级面试题》基础题 解答
J_Knight_大神的《出一套 iOS 高级面试题》基础题 解答
原文
1.分类和扩展有什么区别?可以分别用来做什么?分类有哪些局限性?分类的结构体里面有哪些成员?
类扩展(extension)能为某个类附加额外的私有的属性,成员变量,方法声明,一般写在.m文件中。
分类(category)作为是在不修改原来类的基础上,为一个类扩展方法。通常为系统类的添加额外的方法。
分类局限性:
- 不能扩展属性和成员变量,如果添加属性,则只会生成setter和getter的声明,不会生成实现和成员变量;
- 分类中的方法和原有类中方法同名,会覆盖原来的方法。
- 如果多个category中存在同名的方法,运行时到底调用哪个方法由编译器决定,最后一个参与编译的方法会被调用。
分类的结构体:
typedef struct category_t {
const char *name; //类的名字
classref_t cls; //类
struct method_list_t *instanceMethods; //category中所有给类添加的实例方法的列表
struct method_list_t *classMethods; //category中所有添加的类方法的列表
struct protocol_list_t *protocols; //category实现的所有协议的列表
struct property_list_t *instanceProperties; //category中添加的所有属性
} category_t;
2.讲一下atomic的实现机制;为什么不能保证绝对的线程安全(最好可以结合场景来说)?
系统自动生成的getter/setter方法会进行加锁操作。
atomic的加锁只保证getter和setter存取方法的线程安全,不能保证线程之外的其他操作。(比如:如果当一个线程正在get或set时,又有另一个线程同时在进行release操作,可能会直接crash)
3.被weak修饰的对象在被释放的时候会发生什么?是如何实现的?知道sideTable么?里面的结构可以画出来么?
释放时,调用clearDeallocating函数。clearDeallocating函数首先根据对象地址获取所有weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entry从weak表中删除,最后清理对象的记录。
sideTable结构
struct SideTable {
// 保证原子操作的自旋锁
spinlock_t slock;
// 引用计数的 hash 表
RefcountMap refcnts;
// weak 引用全局 hash 表
weak_table_t weak_table;
}
4.关联对象有什么应用,系统如何管理关联对象?其被释放的时候需要手动将所有的关联对象的指针置空么?
关联对象的应用:
- 添加公共属性。当需要在分类中添加属性,可以用到runtime关联对象;
- 添加私有成员变量。如为UI控件关联事件Block体
- 关联观察者对象。有时候我们在分类中使用NSNotificationCenter或者KVO,推荐使用关联的对象作为观察者,尽量避免对象观察自身
当对象被释放时,会根据这个策略来决定是否释放关联的对象,当策略是RETAIN/COPY时,会释放(release)关联的对象,当是ASSIGN,将不会释放。
值得注意的是,我们不需要主动调用removeAssociated来接触关联的对象,如果需要解除指定的对象,可以使用setAssociatedObject置nil来实现。
5.KVO的底层实现?如何取消系统默认的KVO并手动触发(给KVO的触发设定条件:改变的值符合某个条件时再触发KVO)?
系统KVO的实现:
当你观察一个对象时,一个新的类会动态被创建。这个类继承自该对象的原本的类,并重写了被观察属性的 setter 方法。自然,重写的 setter 方法会负责在调用原 setter 方法之前和之后,通知所有观察对象值的更改。最后把这个对象的 isa 指针 ( isa 指针告诉 Runtime 系统这个对象的类是什么 ) 指向这个新创建的子类,对象就神奇的变成了新创建的子类的实例。
6.Autoreleasepool所使用的数据结构是什么?AutoreleasePoolPage结构体了解么?
双向链表。
AutoreleasePoolPage结构体:
class AutoreleasePoolPage
{
static size_t const SIZE = PAGE_MAX_SIZE;
magic_t const magic; // 16字节
id *next; // 8字节
pthread_t const thread; // 8字节
AutoreleasePoolPage * const parent; // 8字节
AutoreleasePoolPage *child; // 8字节
uint32_t const depth; // 4字节
uint32_t hiwat; // 4字节
...
}
#define PAGE_MAX_SIZE PAGE_SIZE
#define PAGE_SIZE I386_PGBYTES
#define I386_PGBYTES 4096
7.讲一下对象,类对象,元类,跟元类结构体的组成以及他们是如何相关联的?为什么对象方法没有保存的对象结构体里,而是保存在类对象的结构体里?
对象结构体:
/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;
/// Represents an instance of a class.
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
/// A pointer to an instance of a class.
typedef struct objc_object *id;
这里的isa 指针,指向的是当前实例的类对象
类对象结构体:
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class _Nullable super_class OBJC2_UNAVAILABLE; // 父类
const char * _Nonnull name OBJC2_UNAVAILABLE; //类名
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE; //实例大小
struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE; //成员变量列表
struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE; //方法列表
struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE; //方法缓存
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE; //协议列表
#endif
}
这里的isa 指针,指向的就是元类
所有的对象调用方法都是一样的,没有必要存在对象中,对象可以有无数个,类对象就有一个所以只需存放在类对象中就可以了。
8.class_ro_t 和 class_rw_t 的区别?
ro标识readonly只读的不可变,class_rw_t rw标识readwrite可读可写
9.iOS 中内省的几个方法?class方法和objc_getClass方法有什么区别?
内省的几个方法:
评估继承关系
- 使用类和超类的方法
- 使用isKindOfClass:方法
方法实现和协议遵循 - 使用respondsToSelector:方法
- 使用conformsToProtocol:方法
对象的比较 - 使用isEqual:方法
- 重载isEqual:方法
class方法和objc_getClass方法区别:
调用class方法不能得到isa的指向链,而通过objc_getClass方法,经过多次调用,可以获得isa的类甚至元类。
10.在运行时创建类的方法objc_allocateClassPair的方法名尾部为什么是pair(成对的意思)?
创建class和meta-class
11.一个int变量被__block修饰与否的区别?
int变量被block修饰后能在block修改变量的值。
本质:block的作用就是只要观察到该变量被 block 所持有,就将“外部变量”在栈中的内存地址放到了堆中。进而在block内部也可以修改外部变量的值。
12.为什么在block外部使用weak修饰的同时需要在内部使用strong修饰?
weak修饰是防止循环引用,在block里面用strong修饰是保证对象不会被释放
13.RunLoop的作用是什么?它的内部工作机制了解么?(最好结合线程和内存管理来说)
RunLoop是保证线程不会退出,并且能在不处理消息的时候让线程休眠,节约资源,在接收到消息的时候唤醒线程做出对应处理的消息循环机制。
14.哪些场景可以触发离屏渲染?(知道多少说多少)
- shadows(阴影)
- shouldRasterize(光栅化)
- masks(遮罩)
- edge antialiasing(抗锯齿)
- group opacity(不透明)
- 复杂形状设置圆角等…
- 渐变
- UILabel, CATextLayer, Core Text……