版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
iOS进阶面试题及详细答案(工程实战版)一、内存管理进阶1.详细讲讲iOS引用计数的实现原理,引用计数存在哪里?iOS引用计数是Objective-C手动内存管理、ARC机制的核心底层逻辑,其计数存储位置分两种情况,并非统一存在一处:对于普通OC对象:引用计数主要存储在对象对应的isa指针附属信息中。64位系统下isa指针经过优化,是一个联合体结构,预留了extra_rc字段,专门用于存储少量引用计数值,无需额外开辟内存,效率极高。当对象引用计数数值较大,isa内部的extra_rc字段存储空间不足时,系统会自动在堆上开辟一块独立的散列表存储空间,专门存放该对象的引用计数,规避存储空间受限问题。对于TaggedPointer对象(字符串、数字等轻量对象):这类对象没有堆内存、没有isa结构体,引用计数直接编码存储在指针本身的二进制位中,不占用额外内存,这也是TaggedPointer读写效率极高的核心原因。核心底层逻辑:对象执行retain时,系统判断是否为TaggedPointer,若是则直接修改指针位;若为普通对象,优先累加isa内的extra_rc,溢出后操作全局散列表。release操作则反向递减,计数归零时触发dealloc方法。2.ARC下__strong、__weak、__unsafe_unretained底层区别,weak指针如何实现自动置空?__strong(默认修饰符):强引用,持有对象所有权。只要存在强引用指向对象,对象就不会被释放。ARC会自动在赋值时插入retain、出作用域时插入release代码,是日常开发最常用的修饰符。__weak:弱引用,不持有对象所有权,不会增加引用计数。核心作用是解决循环引用问题。__unsafe_unretained:无引用、无置空机制,既不持有对象,也不会在对象释放后自动置空指针。对象销毁后,该指针会变成野指针,极易引发崩溃,仅在兼容老旧代码、追求极致性能场景少量使用。weak指针自动置空原理:系统维护了一张全局的weak表,本质是哈希表。key是对象的内存地址,value是所有指向该对象的weak指针地址数组。当对象执行dealloc时,底层会触发clearDeallocating方法,系统遍历该对象对应的weak指针数组,将所有weak指针统一置为nil,最后从weak表中移除该对象记录,彻底杜绝野指针访问崩溃。3.什么是内存泄漏?日常开发中常见的循环引用场景及解决方案内存泄漏指对象在业务逻辑中已经失去使用价值,但因存在有效强引用,无法触发dealloc释放内存,导致内存持续占用、堆积,最终引发内存飙升、卡顿、闪退等问题。常见循环引用场景:Block内部持有外部self,self又持有Block(最常见);代理协议使用strong修饰,而非weak,控制器与代理对象互相持有;两个自定义对象互相强引用对方的属性;NSTimer、CADisplayLink强持有target,循环执行未及时失效;闭包嵌套、多层Block嵌套导致的隐性循环引用。解决方案:Block场景:使用__weak修饰self,内部如需防止提前释放,可搭配__strong临时变量使用;代理场景:所有代理属性统一用weak修饰;定时器场景:使用weak包裹target,或封装定时器工具类、使用block版定时器;对象互相引用场景:一端用strong,另一端必须用weak。二、多线程进阶1.GCD队列、任务类型详解,主队列、全局队列、自定义队列的核心区别GCD核心由任务(Block/函数)和队列(调度队列)组成,队列负责管理任务、调度线程,任务分同步、异步两种执行方式。任务类型:同步任务sync:阻塞当前线程,必须等待任务执行完毕,才会继续执行后续代码,不开启新线程;异步任务async:不阻塞当前线程,队列会调度线程执行任务,开启新线程(主队列除外)。队列类型及区别:主队列(mainqueue):串行队列,绑定主线程,所有任务在主线程执行。异步提交任务不会立即执行,会加入队列排队;同步提交主队列任务会直接死锁。主要用于UI刷新、主线程业务处理。全局队列(globalqueue):系统提供的并发队列,分高、默认、低、后台四个优先级,无需手动创建,可直接使用。适合执行耗时异步任务,无需管理线程生命周期。自定义串行队列:手动创建,同一时间仅执行一个任务,任务按顺序串行执行,线程唯一。适合处理有序、线程安全的读写任务。自定义并发队列:手动创建,可同时执行多个任务,底层由线程池调度多个线程并发执行。适合无序、可并行的耗时任务。2.GCD死锁的本质、常见场景及规避方案死锁本质:当前线程正在等待队列中未完成的任务,同时又向该队列提交同步任务,导致任务互相等待、线程永久阻塞,代码无法继续执行。高频死锁场景:主线程中执行dispatch_sync提交任务到主队列(100%死锁);串行队列内部,同步提交任务到自身队列;两个串行队列互相同步等待对方任务,形成循环等待。规避方案:主线程禁止使用sync提交主队列任务,统一用async;串行队列内部嵌套任务,优先使用async异步提交;跨队列同步调用时,梳理执行顺序,避免双向阻塞等待。3.GCD栅栏函数、信号量、组调度的实战用途栅栏函数(barrier):分为async_barrier、sync_barrier,仅对自定义并发队列生效。核心作用是隔离读写任务。队列中普通任务正常并发执行,遇到栅栏任务时,会等待前方所有任务执行完毕,单独执行栅栏任务,结束后再继续执行后续任务。实战中用于数据读写线程安全,多读单写场景。GCD信号量(semaphore):通过设置信号量数值控制最大并发数,也可用于线程间等待、唤醒。实战用途:限制网络请求最大并发数、异步任务顺序执行、防止接口重复请求、解决数组遍历修改线程安全问题。GCD组调度(group):可监听多个异步任务的执行状态,所有任务执行完毕后统一回调。实战用途:多个并行网络请求完成后统一刷新UI、多任务异步处理后统一收尾逻辑。核心API:enter、leave、notify、wait。4.NSTimer为什么会卡顿、失效?如何解决?失效、卡顿原因:NSTimer依赖RunLoop运行,默认添加在RunLoop的default模式下。当页面滚动、手势触发时,RunLoop会切换到tracking模式,default模式下的定时器任务会暂停,导致计时不准、卡顿。同时NSTimer会强持有target,容易引发内存泄漏,控制器销毁后定时器仍在执行,造成异常。解决方案:修改RunLoop运行模式:将定时器添加到common模式,common模式包含default、tracking等常用模式,滚动时不会暂停;封装弱引用定时器:通过中间代理类弱化target持有关系,避免循环引用;优先使用GCD定时器:GCD定时器不依赖RunLoop,计时更精准、无模式切换问题、内存可控,是工程首选;页面销毁时手动调用invalidate销毁定时器,彻底释放资源。三、RunLoop进阶1.RunLoop核心作用、运行机制,为什么主线程不会退出?RunLoop本质是线程的循环调度机制,核心作用是保活线程、监听事件、调度任务,让线程有事做事、没事休眠,避免CPU空转,极致优化性能。子线程默认执行完任务立即销毁,生命周期极短;主线程依靠RunLoop永久保活,持续监听用户点击、滑动、网络回调、定时器、渲染等各类事件,支撑App持续运行。RunLoop运行机制:休眠前处理完当前所有待执行的timers、sources、block任务;进入休眠状态,等待新事件触发;收到事件唤醒线程,处理对应任务;任务处理完毕,再次进入休眠,循环往复。主线程RunLoop在App启动时自动开启,永久循环,不会主动退出,这也是App能够持续运行、响应交互的核心基础。2.RunLoop运行模式区别,common模式原理RunLoop模式是任务隔离机制,不同模式下只会处理当前模式对应的任务,切换模式后未匹配的任务会暂停。核心常用模式:kCFRunLoopDefaultMode:默认模式,日常页面刷新、业务任务均在此模式执行,滚动交互时会暂停;UITrackingRunLoopMode:交互模式,页面滚动、手势滑动时的专属模式,仅处理交互相关任务;kCFRunLoopCommonModes:伪模式,并非独立模式,是default、tracking等主流模式的集合。common模式原理:将任务添加到common模式后,任务会自动绑定到所有标记为common的模式中。无论RunLoop处于默认模式还是滚动交互模式,该任务都能正常执行,不会被暂停,完美解决定时器、UI刷新卡顿问题。3.RunLoop如何实现AutoreleasePool自动释放?AutoreleasePool的自动释放完全依托RunLoop生命周期,系统自动创建、销毁,无需手动干预主线程池操作。主线程RunLoop每次循环迭代都会执行两个核心操作:迭代开始前创建新的自动释放池,迭代结束后销毁当前池。单次循环中产生的autorelease对象,都会加入当前池,循环结束后随池一起释放,避免内存堆积。子线程默认无RunLoop、无自动释放池,因此子线程耗时任务中,大量创建autorelease对象会造成内存峰值过高,需要手动添加@autoreleasepool{}包裹循环、批量创建对象的代码,及时释放临时对象。四、UI渲染与性能优化1.UI渲染完整流程,卡顿的根本原因iOSUI渲染遵循CPU预处理+GPU渲染合成的流水线流程,完整步骤:布局阶段(CPU):执行frame、constraint布局计算,确定控件位置、大小;绘制阶段(CPU):调用drawRect、绘图API绘制图层内容,生成位图;打包阶段(CPU):将图层位图、属性信息打包,传递给GPU;渲染合成(GPU):GPU进行纹理渲染、图层叠加、屏幕像素填充,完成画面刷新。屏幕默认刷新频率为60帧/秒,每帧刷新间隔约16ms。卡顿根本原因:CPU布局、绘制耗时过长,或GPU渲染压力过大,导致单帧处理时间超过16ms,无法跟上屏幕刷新节奏,出现掉帧、卡顿。2.离屏渲染是什么?哪些场景会触发?如何优化?离屏渲染:GPU无法直接在当前屏幕缓冲区渲染,需要先开辟额外的离线缓冲区完成渲染计算,再将结果同步到屏幕缓冲区。额外的缓冲区创建、切换、合成操作会极大消耗GPU性能,是UI卡顿的核心元凶之一。常见触发场景:设置cornerRadius+masksToBounds同时开启(圆角裁剪);图层设置shadowPath以外的阴影、模糊效果;光栅化、图层蒙版、透明度叠加、复杂渐变绘制;drawRect自定义复杂绘图逻辑。优化方案:圆角优化:静态图片预裁圆角、UIBezierPath绘制圆角、避免大面积视图开启masksToBounds;阴影优化:手动设置shadowPath,固定阴影路径,减少实时计算;合理开启shouldRasterize光栅化,仅对静态、复用的复杂视图开启,避免动态视图光栅化导致缓存失效;减少图层嵌套、透明度叠加,简化自定义绘图逻辑。3.列表滑动卡顿的核心优化方案(UITableView/CollectionView)列表卡顿核心痛点:Cell复用不彻底、实时计算布局、离屏渲染、主线程大量耗时操作、图片解码耗时。实战优化方案:复用机制优化:严格执行Cell复用,禁止动态创建Cell,统一注册Cell,减少初始化开销;预计算布局:提前在子线程计算Cell高度、控件布局、文本尺寸,缓存高度结果,滑动时直接读取,避免实时计算;减少离屏渲染:批量处理圆角、阴影,使用预渲染图片替代实时绘制;图片优化:子线程解码图片、压缩图片尺寸,避免大图实时渲染,按需加载、懒加载图片;主线程减负:所有数据解析、模型转换、耗时计算放入子线程,主线程仅做UI赋值、刷新操作;滑动节流:滑动过程中停止复杂动画、网络请求、日志打印,停止冗余UI刷新;图层优化:合并多余视图、减少图层嵌套,将多个控件合并为一个图层渲染。五、编译与底层原理1.OC编译过程,clang编译流程OC代码从编写到生成可执行文件,完整编译流程分为4步,由clang编译器主导:预处理:处理宏定义、头文件导入、条件编译,删除注释、展开宏、替换预处理指令,生成纯净源码;编译:语法、语义校验,将OC、C代码转换为汇编代码,检查代码语法错误、类型错误;汇编:将汇编代码转换为机器语言,生成.o目标文件;链接:合并多个.o文件、链接系统动态库/静态库,解析符号引用,最终生成可执行文件。2.静态库与动态库的区别、优缺点及使用场景静态库(.a):编译链接阶段,会将库代码完整拷贝到项目可执行文件中,打包后库代码与项目融为一体。优点:运行时无需依赖外部库文件,加载速度快、兼容性稳定;缺点:包体积增大,库更新需要重新编译项目,无法动态升级。动态库(.dylib/.framework):编译阶段仅记录符号引用,不拷贝代码,运行时动态加载库代码到内存,多个项目可共享同一库内存。优点:包体积更小,库可独立更新、无需重编项目,支持动态按需加载;缺点:首次加载速度略慢,存在版本兼容风险。使用场景:通用稳定、无需频繁更新的基础工具类用静态库;需要迭代更新、插件化、模块化的业务组件用动态库;系统API全部为动态库。3.Category底层原理,为什么分类不能添加属性?Category底层结构是category_t结构体,编译阶段会将分类的方法、协议、属性声明存入结构体,但不会生成成员变量。运行时阶段,runtime会将分类的实例方法、类方法动态追加到原类的方法列表中,实现方法拓展、重写。分类不能直接添加属性的原因:属性的本质是成员变量+setter/getter方法,分类底层结构不支持存储成员变量,仅能声明属性、自动生成方法声明,不会生成方法实现和变量存储。若需通过分类实现属性存储,必须借助runtime关联对象(objc_setAssociatedObject、objc_getAssociatedObject),动态绑定数值,模拟属性存储效果。补充:关联对象不会影响原类的内存布局,仅动态维护一张关联表,轻量化无性能损耗。六、架构与工程实战1.MVC、MVVM、VIPER架构区别及项目落地痛点MVC:Model(数据)、View(视图)、Controller(控制器)。传统架构逻辑简单、上手快,但极易造成Controller臃肿,业务逻辑、视图逻辑、数据逻辑全部堆积在控制器,代码耦合严重,后期维护成本极高,适合小型简单项目。MVVM:在MVC基础上拆分出ViewModel,承接视图的数据处理、业务逻辑、数据转换,View与Model完全解耦,视图仅负责展示,ViewModel负责数据驱动视图。核心优势是代码分层清晰、可复用性强、便于单元测试,是中大型项目主流架构。落地痛点:需要手动处理数据绑定、状态回调,简单页面会增加冗余代码。VIPER:分层最细,分为View、Interactor、Presenter、Entity、Router,职责完全拆分,适合超大型复杂业务、团队协作项目。落地痛点:层级过多、代码繁琐、学习成本高,小型项目使用会过度设计,降低开发效率。2.组件化的核心思路、解决的问题及通信方案核心思路:将庞大的单体项目,按业务模块、功能模块拆分为多个独立组件,每个组件独立开发、独立编译、独立运行,通过统一路由、中间件完成模块通信,实现高内聚、低耦合。解决的核心问题:解决大型项目代码耦合严重、编译速度慢、多人协作冲突、模块复用率低、迭代效率低的问题。主流通信方案:路由跳转:基于URL路由,实现页面无耦合跳转、参数传递;中间件通信:通过统一中间件注册、调用模块服务,完成跨模块方法调用;消息通知:统一封装通知名称,用于跨模块全局事件回调;协议注册:通过协议匹配实现模块服务解耦调用。3.项目包体积优化方案包体积优化从资源、代码、编译、冗余文件四个维度落地:资源优化:压缩图片、去除冗余图片/音视频/文案、使用WebP替代PNG/JPG、适配不同机型裁剪图片尺寸;删除未使用的静态资源、废弃xib、storyboard;代码优化:删除废弃代码、冗余分类、无用宏、未引用库;精简第三方库,替换臃肿三方库为轻量化替代库;编译优化:开启编译优化参数、去除调试符号、压缩可执行文件;关闭多余架构支持,精简架构包;冗余清理:移除项目中冗余配置、重复依赖、无用资源文件,清理缓存文件、编译产物。七、网络与异常处理1.HTTPS握手流程,HTTP1.0/1.1/2.0核心区别HTTPS握手流程
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 江苏省苏教版七年级语文第4章文言文阅读理解专项训练习题及答案
- 2026年人教版三年级英语下册第12单元词汇专项训练习题及答案
- 戒烟干预临床指南(2024版)
- 可再生资源利用合作协议三篇
- 2026智能仓储物流技术发展及市场机会分析报告
- 2026智慧农业技术推广路径与经济效益评估报告
- 2026智能驾驶感知系统技术路线竞争格局与投资风险评估
- 阴式子宫切除术护理
- 2026中医药行业市场竞争格局现状及投资评估规划分析报告
- 2026全国海船船员考试轮机部船舶管理8506历年参考题库含答案详解
- 肝硬化并发脑病护理要点
- 市政工程项目验收与移交管理方案
- 《积的变化规律》(教学设计)-四年级上册数学人教版
- 《工程伦理》课件 第五讲 邻避效应的防范与化解
- 口腔颌面外科住院医师规范化培训结业临床实践能力考核标准方案(2023版)
- 2025年浙江交通集团招聘笔试备考题库(带答案详解)
- 2.30违背或偏离方案处理标准操作规程药物临床试验机构
- 《医疗器械概论》-第二篇第2章-医用放射设备
- 银行催收管理岗竞演
- 2024年大宗互赔协议书模板
- JB-T 14507-2023 环保设备 氟塑料气水换热器
评论
0/150
提交评论