2022年iOS面试题简答题

级别方面:
iOS中级:基础70%,底层原理20%,架构10%
iOS高级:基础10%,底层原理50%,架构20%,算法20%
iOS架构:底层原理50%,架构20%,算法20%,手写算法10%
iOS专家:底层原理20%,架构20%,算法40%,手写算法20%

总的来说就是:
中级偏向运用,会不会使用,怎么使用,有没有使用过。
高级偏向底层原理,底层是怎么实现的,你在哪里使用过
架构偏向为什么这么设计(这样设计解决了什么问题,又出现了什么新的问题)一般都是第三方框架,比如ASI和AFN,http2.0和http3.0
专家偏向这两个算法有什么区别,为什么这里要用这个算法,而不是用别的算法,比如:NSHashTable,NSMapTable,NSOrderedSet

价格方面:(广州)
iOS中级:15+都要问底层,手写冒泡或快速排序,简单的算法
iOS高级:20+都要问算法,手写链表反转、二叉树反转等
iOS架构:25+,手写比高级难的算法
iOS专家:30+ 先手撸一套sd伪代码

# 一、runtime
### isa指针
实例对象的isa指向类对象,类对象的isa指向元类,元类的isa指向nsobject
![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7042f3fe3f37431bb34459b02c45eba7~tplv-k3u1fbpfcp-watermark.image?)


### runtime结构
super class指向父类的指针,cache_t,class_data_t(class_ro)
![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4f84584af8c94b80b80dbf4a1db5184a~tplv-k3u1fbpfcp-watermark.image?)

### [消息转发机制]

1.动态方法解析
首先是征询接收者所属的类,看其是否能动态添加调用的方法,来处理当前这个未知的选择子;
2.快速消息转发
寻找是否在其他对象内有该方法实现,并将该消息转发给这个对象.如果目标对象实现了该方法,Runtime这时就会调用这个方法,给你把这个消息转发给其他对象的机会.只要这个方法返回的不是nil和self,整个消息发送的过程就会被重启,当然返回的对象会变成return的对象,否则就会继续nurmal fowarding
3.标准消息转发
获取方法签名
如果失败就抛异常,如果成功了,并获取参数和返回值,就会创建invocation 对象,并将forworadinvocation消息转发给该对象


### associate
1.增加属性
2.KVO
a.必须有set方法
b.动态生成子类,并创建set方法,将isa指向子类
c.进行消息转发的时候,转发到该子类中


### Method Swizzling(iOS的机制)钩子
实用:防奔溃,防止hook
第三方库:fishhook
原理:方法交换
1.method_exchangeImpmentations
2.class_replaceMethod
3.method_setImpementation


### 利用ptrace防护debugserver
拿到dylib的句柄,强制指定ptrace函数指针
用方法交换,防止被ptrace调试


### Selector, Method 和 IMP 的区别与联系
一个类(Class)持有一个分发表,在运行期分发消息,表中的每一个实体代表一个方法(Method),它的名字叫做选择子(SEL),对应着一种方法实现(IMP)
/// Method
struct objc_method {
    SEL method_name; 
    char *method_types;
    IMP method_imp;
};
Method包含SEL 方法名,IMP函数地址


# 二、NSRunloop的五大类
一个线程至少有一个runloop
main的默认开启,子线程的默认关闭


### 1.RunloopRep
底层C的runloop


### 2.Model 相当于进程的状态
Default默认模式
Tracking用户交互模式
Common伪模式model集合
initialtialzation启动模式
eventRecei接受内部事件模式


### 3.Timer
等价于NSTimer
刷新有三种:GCD,NSTimer,CADisaplaytime
Timer失效:1. Runloop 没有开启,2.runloop被释放了
Timer无法释放:重写调用方法,用虚类来引用父类进行消息转发
GCD依赖于系统内核,不会长生时差
NSTimer、CADisplayLink:到一定时间后,在进行消息转发,会存在一定的时差
GCD依赖于系统内核,自身不会有
NSTimer、CADisplayLink:会循环引用,需要结合NSProxy,进行消息转发
NSProxy:虚类,消息转发的代理,主要用于弱引用父类,实现消息转发的循环引用问题
多继承:将类名传入,再进行消息转发


### 4.Observer 监听线程状态
监听七种状态
1.即将进入runloop 
2.即将处理timer 
3.即将处理source 
4.即将sleep 
5.刚被唤醒,即将退出sleep.
6.即将退出exit 
7.全部活动all activity


### 5.Source 
1自旋锁
0 互坼锁
 Source1 :基于mach_Port的,来自系统内核或者其他进程或线程的事件,可以主动唤醒休眠中的RunLoop(iOS里进程间通信开发过程中我们一般不主动使用)。mach_port大家就理解成进程间相互发送消息的一种机制就好, 比如屏幕点击, 网络数据的传输都会触发sourse1。
苹果创建用来接受系统发出事件,当手机发生一个触摸,摇晃或锁屏等系统,这时候系统会发送一个事件到app进程(进程通信),这也就是为什么叫基于port传递source1的原因,port就是进程端口嘛,该事件可以激活进程里线程的runloop,比如你点击一下app的按钮或屏幕,runloop就醒过来处理触摸事件,你可以做个实验,在主线程的runloop中添加一个CFRunLoopObserverRef,用switch输出runloop6个状态,这时候你每点击一次屏幕,他就会输出Runloop六个状态,然后进入休眠。

• Source0 :非基于Port的 处理事件,什么叫非基于Port的呢?就是说你这个消息不是其他进程或者内核直接发送给你的。一般是APP内部的事件, 比如hitTest:withEvent的处理, performSelectors的事件.
执行performSelectors方法,假如你在主线程performSelectors一个任务到子线程,这时候就是在代码中发送事件到子线程的runloop,这时候如果子线程开启了runloop就会执行该任务,注意该performSelector方法只有在你子线程开启runloop才能执行,如果你没有在子线程中开启runloop,那么该操作会无法执行并崩溃。

简单举个例子:一个APP在前台静止着,此时,用户用手指点击了一下APP界面,那么过程就是下面这样的:
我们触摸屏幕,先摸到硬件(屏幕),屏幕表面的事件会被IOKit先包装成Event,通过mach_Port传给正在活跃的APP , Event先告诉source1(mach_port),source1唤醒RunLoop, 然后将事件Event分发给source0,然后由source0来处理。
如果没有事件,也没有timer,则runloop就会睡眠, 如果有,则runloop就会被唤醒,然后跑一圈。


# 三、[block的三种形式]

### 堆block:
在堆上的block,
用__block修饰的外部参数,会将block拷贝(copy修饰)到栈上,从栈复制到堆并被block持有


### 栈block:
在栈上的block
未copy到堆的block,有外部参数
有值域的问题,用__block将block复制到堆解决值域的问题,从而解决值域问题


### 全局block:
在静态区的block
 不使用外部变量的block,或值用static修饰的,是全局block


### copy修饰:
堆block:引用计算+1
栈block:会copy到堆block
全局block:啥也不做

栈block会有值截取的域问题,其他都会随着值变化
解决block循环引用:用weak修饰
解决block延迟执行闪退问题:被释放用strong修饰


# 四、内存管理:
### 五大区
1.栈区(向下增长)(高地址)
2.堆区(向上增长)
3.静态区(全局区)
4.常量区
5.代码区(低地址)


### 循环引用
1.父类持有子类,子类强引用父类
2.weak弱引用


### SideTables()
1.自旋锁
a.自旋锁 
轮询任务
Source 1

b.互斥锁
系统激活
Source 0

2.引用计数表

3.弱引用表


### copy
1.block
a.堆
引用计数+1
b.栈
copy到堆并持有
c.全局
不做任何操作

2.深copy浅copy
a.array copy 不可变copy为深copy:开辟内存
b.其余为浅copy:只创建指针

3.可变对象


# 五、多线程:
### dispatch_queue线程
1.
2.

### dispatch_semaphore信号量
1.create+1
2.signal-1
3.wait为0时执行

### dispatch_group_async
1.分组任务
2.
3.

### 自旋锁与互斥锁
1.自旋锁
a.Source 1
b.pthread_mutex、@ synchronized、NSLock、NSConditionLock 、NSCondition、NSRecursiveLock

2.互斥锁
a.Source 0
b.pthread_mutex、@ synchronized、NSLock、NSConditionLock 、NSCondition、NSRecursiveLock

### 异步执行任务,并同步
1.信号量
2.分组任务dispatch_group_async
3.队列 NSOprationQueue

### 线程锁:lock,@sythasy,


# 六、离屏渲染:
### 定义
1.当前屏幕缓冲区外新开辟一个缓冲区进行渲染操作
2.onscreen 跟 offscreen 上下文之间的切换,这个过程的消耗会比较昂贵


### 触发:
1.使用了 mask 的 layer (layer.mask)
2.需要进行裁剪的 layer (layer.masksToBounds / view.clipsToBounds)
3.设置了组透明度为 YES,并且透明度不为 1 的 layer (layer.allowsGroupOpacity/ layer.opacity)
4.添加了投影的 layer (layer.shadow*)
5.采用了光栅化的 layer (layer.shouldRasterize)
6.绘制了文字的 layer (UILabel, CATextLayer, Core Text 等)


# 七、性能优化面
### 一、Tableview优化
1.减少计算,缓存高度
2.减少线程等待,图片异步加载
3.复用机制,减少UI绘制
4.减少离屏渲染的使用,用图片代替圆角,阴影等
5.时间换空间,尽量注册多的cell,减少cell的重布局

### 二、卡顿优化
1.减少主线程的等待,尽量放到子线程
2.减少一些炫酷动画和炫酷图片的使用
3.尽量把图片的

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值