iOS基础面试题:iOS基础知识| ProcessOn免费在线作图,在线流程图,在线思维导图
iOS高级面试题:https://juejin.cn/post/6844903752835530765
先自我介绍,看有无亮点,了解一下做过的项目类型
了解技术栈(oc、swift、swiftUI、flutter、RN、前端)
讲讲之前公司的开发流程,开发中常用的工具有哪些?
如何采集和监控线上曝光数据点击数据以及崩溃数据?
一般如何定位bug产生的原因?
讲一个比较有印象的项目,过程中有没有遇到什么问题,如何解决的?
一、常见的消息传递机制以及他们之间区别
- 1、KVO
- 2、通知
- 3、delegation
- 4、block
- 5、target-action
二、事件响应机制(结合案例:如何扩大 Button 的点击范围)
- 事件的传递顺序是这样的:
产生触摸事件->UIApplication事件队列->[UIWindow hitTest:withEvent:]->返回更合适的view->[子控件 hitTest:withEvent:]->返回最合适的view
- 事件的响应: 首先看initial view能否处理这个事件,如果不能则会将事件传递给其上级视图(inital view的superView);如果上级视图仍然无法处理则会继续往上传递;一直传递到视图控制器view controller,首先判断视图控制器的根视图view是否能处理此事件;如果不能则接着判断该视图控制器能否处理此事件,如果还是不能则继续向上传 递;(对于第二个图视图控制器本身还在另一个视图控制器中,则继续交给父视图控制器的根视图,如果根视图不能处理则交给父视图控制器处理);一直到 window,如果window还是不能处理此事件则继续交给application处理,如果最后application还是不能处理此事件则将其丢弃
事件的传递是从上到下(父控件到子控件),事件的响应是从下到上(顺着响应者链条向上传递:子控件到父控件。
三、为什么不能在子线程中刷新UI?
- 线程安全:UIKit不是线程安全的,所有UI操作都必须在主线程上执行。直接在子线程中更新UI可能导致数据竞争和不一致的状态,从而引发崩溃或未定义的行为。
- 主线程的职责:主线程负责处理用户交互和UI更新。如果在子线程中进行UI更新,可能会导致主线程的任务被阻塞,从而影响用户体验,导致界面卡顿或无响应。
- 崩溃风险:如果在子线程中尝试更新UI,可能会导致应用程序崩溃,通常会抛出
[<NSObject> setValue:forUndefinedKey:]
或类似的异常。
四、有做过性能优化吗?哪些方面入手?(开放性,答出部分言之有理即可)
卡顿优化:CPU
- 尽量用轻量级的对象,比如用不到事件处理的地方,可以考虑使用CALayer取代UIView
- 不要频繁地调用UIView的相关属性,比如frame、bounds、transform等属性,尽量减少不必要的修改
- 尽量提前计算好布局,在有需要时一次性调整对应的属性,不要多次修改属性
- Autolayout会比直接设置frame消耗更多的CPU资源
- 图片的size最好刚好跟UIImageView的size保持一致
- 控制一下线程的最大并发数量
- 尽量把耗时的操作放到子线程:文本处理(尺寸计算、绘制),图片处理(解码、绘制)
卡顿优化:GPU
- 尽量避免短时间内大量图片的显示,尽可能将多张图片合成一张进行显示
- GPU能处理的最大纹理尺寸是4096x4096,一旦超过这个尺寸,就会占用CPU资源进行处理,所以纹理尽量不要超过这个尺寸
- 尽量减少视图数量和层次
- 减少透明的视图(alpha<1),不透明的就设置opaque为YES
- 尽量避免出现离屏渲染
离屏渲染
在OpenGL中,GPU有2种渲染方式
- On-Screen Rendering:当前屏幕渲染,在当前用于显示的屏幕缓冲区进行渲染操作
- Off-Screen Rendering:离屏渲染,在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作
离屏渲染消耗性能的原因
- 需要创建新的缓冲区
- 离屏渲染的整个过程,需要多次切换上下文环境,先是从当前屏幕(On-Screen)切换到离屏(Off-Screen);等到离屏渲染结束以后,将离屏缓冲区的渲染结果显示到屏幕上,又需要将上下文环境从离屏切换到当前屏幕
哪些操作会触发离屏渲染?
- 光栅化,layer.shouldRasterize = YES
- 遮罩,layer.mask
- 圆角,同时设置layer.masksToBounds = YES、layer.cornerRadius大于0
-
- 考虑通过CoreGraphics绘制裁剪圆角,或者叫美工提供圆角图片
- 阴影,layer.shadowXXX
-
- 如果设置了layer.shadowPath就不会产生离屏渲染
五、项目中哪些地方用到多线程,有无案例?
技术方案 | 简介 | 语言 | 线程的生命周期 | 使用频率 |
pthread | 一套多线程API;可跨平台使用;使用难度大 | C语言 | 程序员管理 | 几乎不用 |
NSThread | 使用面向对象;简单易用,可直接操作线程对象 | OC | 程序员管理 | 偶尔使用 |
GCD | 旨在替代NSThread等线程技术;充分利用设备的多核; | C语言 | 自动管理 | 经常使用 |
NSOperation | 基于GCD(底层是GCD);比GCD多了一些简单实用的功能;使用更加面向对象 | OC | 自动管理 | 经常使用 |
六、讲讲RunLoop项目中有用到吗?
- 1、定时器切换的时候,为了保证定时器的准确性,需要添加runLoop
- 2、在聊天界面,我们需要持续的把聊天信息存到数据库中,这个时候需要开启一个保活线程,在这个线程中处理
七、RunLoop和线程的关系?常用到哪几种mode?
- 1、每一条线程都有唯一的一个与之对应的RunLoop对象
- 2、RunLoop保存在一个全局的Dictionary里,线程作为Key,RunLoop作为Value
- 3、线程刚创建时,并没有RunLoop对象,RunLoop会在第一次获取她时创建
- 4、RunLoop会在线程结束的时候销毁
- 5、主线程的RunLoop已经自动获取(创建),子线程默认没有开启RunLoop
kCFRunLoopDefaultMode //App的默认Mode,通常主线程是在这个Mode下运行
UITrackingRunLoopMode //界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响
八、常见crash原因,以及避免的方法(碰到过线上crash吗?如何补救?)
- 1、unrecognized selector crash
(可扩展问runtime)
(unrecognized selector类型的crash在app众多的crash类型中占着比较大的成分,通常是因为一个对象调用了一个不属于它方法的方法导致的。)
方法调用流程 runtime中具体的方法调用流程大致如下:
- 1、在相应操作的对象中的缓存方法列表中找调用的方法,如果找到,转向相应实现并执行。
- 2、如果没找到,在相应操作的对象中的方法列表中找调用的方法,如果找到,转向相应实现执行
- 3、如果没找到,去父类指针所指向的对象中执行1,2.
- 4、以此类推,如果一直到根类还没找到,转向拦截调用,走消息转发机制。
- 5、如果没有重写拦截调用的方法,程序报错。
在一个函数找不到时,runtime提供了三种方式去补救:
- 1、调用resolveInstanceMethod给个机会让类添加这个实现这个函数
- 2、调用forwardingTargetForSelector让别的对象去执行这个函数
- 3、调用forwardInvocation(函数执行器)灵活的将目标函数以其他形式执行。
通过重写NSObject的forwardingTargetForSelector方法,我们就可以将无法识别的方法进行拦截并且将消息转发到安全的桩类对象中,从而可以使app继续正常运行
- 2、KVO crash
- 3、NSNotification crash
- 4、NSTimer crash
- 5、Container crash(数组越界,插nil等)
- 6、NSString crash (字符串操作的crash)
- 7、Bad Access crash (野指针)
- 8、UI not on Main Thread Crash (非主线程刷UI(机制待改善))