iOS开发高频面试题及详细答案(实战版)_第1页
iOS开发高频面试题及详细答案(实战版)_第2页
iOS开发高频面试题及详细答案(实战版)_第3页
iOS开发高频面试题及详细答案(实战版)_第4页
iOS开发高频面试题及详细答案(实战版)_第5页
已阅读5页,还剩3页未读, 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

iOS开发高频面试题及详细答案(实战版)一、Objective-C基础核心面试题1.讲一下OC的消息机制,objc_msgSend执行流程OC本质是消息传递机制,所有方法调用本质都是给对象发送消息,核心函数是objc_msgSend。整体执行流程分为三步:第一步:查找方法缓存调用方法时,首先通过对象的isa指针找到对应的类对象,优先在类的方法缓存列表(cache)中查找方法实现。缓存采用哈希表存储,查询速度极快,如果命中直接执行方法,结束流程。第二步:查找方法列表缓存未命中时,遍历当前类的methodList方法列表查找,如果找到,将方法加入缓存,再执行方法。如果当前类没有该方法,沿着父类指针逐级向上查找父类的方法列表,直到根类NSObject。第三步:消息动态解析与转发如果整个继承链都找不到方法,不会直接崩溃,会进入OC的消息容错机制:1.动态解析:调用+resolveInstanceMethod:或+resolveClassMethod:,开发者可以动态添加方法实现;2.快速转发:调用-forwardingTargetForSelector:,可以将消息转发给其他对象处理;3.完整转发:调用-methodSignatureForSelector:生成方法签名,再通过-forwardInvocation:转发消息;4.所有流程走完仍无实现,触发doesNotRecognizeSelector:崩溃。2.讲一下OC中Category的底层原理,以及为什么不能添加成员变量底层原理:分类的底层结构是category_t,内部存储实例方法、类方法、协议、属性列表,不存储成员变量。编译时分类的方法不会直接合并到主类,运行时通过runtime将分类的方法、协议附加到主类的方法列表和协议列表中,多个分类方法会按编译顺序叠加,同名方法后编译的会覆盖先编译的。不能添加成员变量的原因:1.类的成员变量内存空间在编译时已经确定,运行时无法修改类的内存布局;2.category_t结构体中没有ivar成员变量数组,无法存储变量;3.分类的核心设计是方法扩展,而非属性扩展。延伸:分类如何模拟添加属性通过runtime的objc_setAssociatedObject和objc_getAssociatedObject关联对象实现,关联对象存储在全局哈希表中,不属于类的本身内存,仅做关联绑定。3.深浅拷贝的区别,nonatomic、atomic区别深浅拷贝核心区别:拷贝的是指针还是内存对象1.浅拷贝(copy、mutableCopy对不可变对象部分场景):只拷贝对象指针,新旧对象指向同一块内存地址,修改一个会影响另一个;2.深拷贝:重新开辟内存,拷贝对象内容,新旧对象内存独立,互不影响;3.OC规则:不可变对象copy是浅拷贝,mutableCopy是深拷贝;可变对象copy、mutableCopy均为深拷贝。nonatomic/atomic1.atomic:原子属性,读写加锁,线程安全,但仅保证单条读写操作安全,不保证业务逻辑线程安全,性能较低;2.nonatomic:非原子属性,无锁,读写速度快,日常开发99%场景使用,多线程手动加锁保证安全。4.strong、weak、copy、assign、unsafe_unretained区别及使用场景1.strong:强引用,持有对象内存,引用计数+1,引用计数为0时对象销毁。场景:普通OC对象、自定义对象,是默认修饰符。2.weak:弱引用,不持有对象,引用计数不变。对象销毁时指针自动置空,避免野指针。场景:代理、block循环引用、子控件引用。3.copy:拷贝修饰,赋值时拷贝对象,生成新内存。场景:NSString、NSArray、NSDictionary等不可变集合,防止外部可变修改导致数据异常。4.assign:直接赋值指针,不计数、不置空,会产生野指针。场景:基本数据类型(int、float)、枚举、结构体。5.unsafe_unretained:和weak逻辑类似,无引用计数,但对象销毁后指针不置空,会产生野指针,基本废弃不用。二、内存管理面试题(高频必问)1.iOS内存管理机制,MRC和ARC区别核心机制:引用计数机制,对象创建计数+1,持有引用计数累加,释放计数-1,计数为0时系统回收内存。MRC(手动引用计数)开发者手动编写retain、release、autorelease、dealloc代码管理内存,极易出现内存泄漏、过度释放崩溃,现在项目基本淘汰。ARC(自动引用计数)编译器在编译阶段自动插入内存管理代码,无需手动管理,编译期检测内存逻辑,大幅降低内存问题,但不解决循环引用问题,循环引用仍需手动打破。2.什么是循环引用?如何解决?常见场景有哪些?循环引用定义:两个或多个对象互相强引用,导致引用计数无法归零,内存无法释放,造成内存泄漏。常见场景1.父子对象互相strong引用;2.Block内部引用外部对象,外部对象又持有Block;3.代理属性使用strong修饰。解决方案1.代理、回调属性使用weak修饰;2.Block中使用__weak修饰外部对象,必要时搭配__strong保活;3.双向引用中,一端强引用、一端弱引用,打破闭环。3.autorelease原理,自动释放池机制autorelease是延迟释放机制,调用后不会立即让对象计数-1,而是将对象加入当前自动释放池,等待释放池销毁时统一批量release。执行流程1.主线程默认开启自动释放池,RunLoop每次循环迭代结束,自动销毁并重建释放池;2.子线程需要手动创建@autoreleasepool{},否则临时对象无法及时释放,造成内存峰值;3.大量循环创建临时对象时,手动嵌套自动释放池,可有效降低内存占用。三、Block核心面试题1.Block的类型、底层结构、变量捕获规则Block三种类型1.全局Block(__NSGlobalBlock__):没有访问外部变量,存储在全局区,生命周期跟随APP;2.栈Block(__NSStackBlock__):访问外部变量,存储在栈区,函数结束后立即销毁;3.堆Block(__NSMallocBlock__):栈Block被copy后转移到堆区,需要手动管理内存(ARC自动处理)。变量捕获规则1.全局变量:直接访问,不捕获;2.局部基本变量:值捕获,拷贝常量值,外部修改不影响block内部;3.局部对象变量:指针捕获,持有对象指针;4.__block变量:结构体包装,捕获变量地址,内外可相互修改。2.__block原理,为什么基本类型需要加__block普通局部变量block是值捕获,内部是常量副本,无法修改原值。__block会将变量包装成一个结构体对象,block捕获的是结构体的地址,而非变量值,因此可以在block内部修改外部变量的值,同时解决变量跨栈访问失效问题。四、多线程&RunLoop面试题1.GCD队列类型、同步异步区别、死锁场景队列类型1.串行队列:任务顺序执行,同一时间只执行一个任务;2.并发队列:任务并发执行,系统自动分配线程,同时执行多个任务。同步/异步1.同步dispatch_sync:阻塞当前线程,等待任务执行完成再继续;2.异步dispatch_async:不阻塞当前线程,直接派发任务,线程继续往下执行。常见死锁场景主线程中调用dispatch_sync执行主队列任务,互相等待造成死锁;串行队列嵌套同步任务也会触发死锁。2.RunLoop原理及作用,RunLoop和线程的关系RunLoop是运行循环,本质是事件循环机制,让线程不执行任务时休眠,有任务时唤醒执行,避免线程空转消耗CPU。线程与RunLoop关系1.线程和RunLoop一一对应,保存在全局字典中;2.主线程RunLoop默认自动开启,保活主线程,处理UI、触摸、定时器事件;3.子线程默认无RunLoop,执行完任务立即销毁,如需常驻子线程,需手动开启RunLoop。核心作用:保活线程、处理事件回调、管理定时器、自动释放池刷新、UI刷新时机把控。3.NSTimer为什么会卡顿、不准?如何解决?NSTimer依赖RunLoop运行,存在两个核心问题:1.RunLoop是循环执行模式,如果当前线程有耗时任务,RunLoop被阻塞,定时器触发时机延后;2.NSTimer是加入当前RunLoop的指定模式,切换模式后定时器失效。解决方案1.将定时器添加到RunLoop通用模式NSRunLoopCommonModes;2.使用GCD定时器dispatch_source_t,不依赖RunLoop,精度更高、无卡顿问题。五、UI与布局、渲染原理1.UIView和CALayer的区别与关系1.UIView:是界面交互载体,继承自UIResponder,负责处理触摸、点击、手势等用户交互,依赖CALayer展示内容;2.CALayer:是图层渲染载体,负责画面绘制、颜色、圆角、阴影、边框渲染,无交互能力;3.一一对应关系:每个UIView内部都有一个CALayer,UIView处理事件,CALayer渲染画面。2.iOS渲染流程、卡顿原因、离屏渲染渲染流程:布局(Layout)>绘制(Display)>图层合成(Compositing)1.Layout:执行frame、约束布局,调用layoutSubviews;2.Display:绘制内容,调用drawRect,绘制位图;3.Compositing:GPU合成所有图层,渲染到屏幕。卡顿核心原因:主线程耗时操作、UI渲染耗时、离屏渲染过多、图层层级复杂。离屏渲染:GPU需要提前开辟额外缓冲区渲染图层,再合成到屏幕,耗时极高。常见触发场景:圆角+裁剪、阴影、遮罩、光栅化。优化方案:预渲染圆角、避免同时开启圆角和阴影、合理使用shouldRasterize。六、性能优化实战面试题1.日常开发中iOS性能优化方案UI渲染优化1.减少图层层级,避免多余View嵌套;2.避免频繁离屏渲染,优化圆角、阴影实现;3.滑动列表按需加载、缓存Cell、复用视图。主线程优化所有耗时操作(网络、文件解析、数据计算、图片处理)全部放入子线程,主线程只做UI刷新。内存优化1.解决循环引用,及时释放无用资源;2.大图压缩、图片缓存管理、避免内存暴涨;3.监听内存警告,及时清理临时缓存数据。启动优化1.拆分启动任务,优先主线程必要任务;2.非必要第三方SDK懒加载;3.减少main函数之前的编译耗时、动态库替换静态库。2.如何检测内存泄漏、卡顿?1.内存泄漏:使用XcodeLeaks工具、MLeaksFinder第三方工具、手动分析循环引用;2.卡顿检测:XcodeTimeProfiler分析耗时函数、主线程卡顿监控、RunLoop超时检测。七、Swift基础面试题(混合开发必问)1.swift中let、var、lazy区别1.var:可变变量,可多次修改值;2.let:常量,初始化后不可修改,推荐优先使用;3.lazy:懒加载属性,首次访问时才初始化,延迟加载,节省内存,常用于耗时初始化属性。2.Swift闭包和OCBlock的区别1.语法更简洁,自动捕获上下文变量;2.解决循环引用使用[weakself]、[unownedself];3.逃逸闭包@escaping、非逃逸闭包默认,区分是否超出函数生命周期。八、网络与项目实战面试题1.HTTP和HTTPS区别1.HTTP明文传输,无加密,端口80,不安全,数据易被劫持、篡改;2.HTTPS基于TLS/SSL加密,端口443,传输加密、身份认证、数据防篡改,安全可靠,主流项目全部使用HTTPS。2.网络层封装

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论