行业资讯
📅 2026/9/1 22:34:25
拆解爱奇艺iOS校招笔试:从内存管理到Runtime的工程考察逻辑
如果有人问起“爱奇艺2020校招iOS方向笔试题第二场”到底考了什么我通常不会直接给答案而是先反问一句你做题的时候有没有意识到这套题其实在模拟你入职后的第一周我见过太多备考的同学把大厂校招笔试当成期末考试周刷题拿到卷子开始默写概念结果复盘时才明白笔试从来不是考你会不会背API而是考你在真实项目里能不能把技术用对、把问题定位清楚。这篇文章就围绕这场笔试从考察逻辑、语言基础、内存线程、网络播放稳定性、算法设计题到后续面试递进把题目背后真正想验证的东西拆开讲一遍。适合正在准备校招的iOS方向同学也适合想自测基础扎实程度的初级开发。1. 第二场的基本盘大厂校招笔试不看分数看技术嗅觉1.1 多场次笔试背后的筛选逻辑很多同学把“第一场、第二场”理解成AB卷其实不是。以爱奇艺2020校招iOS方向为例第一场往往偏基础面筛选题目概念性强、覆盖广能过的基本是简历和基础都没大问题的人而第二场更像“预演入职”题量更大、场景更具体、对底层原理的挖掘更深。为什么大厂要设计这种多轮笔试因为在真实项目中iOS开发很少需要默写接口名更多时候是面对一个现象去定位原因。笔试如果只考概念很容易被短期刷题冲刺的人钻空子一旦加入底层原理和场景排查题浮于表面的储备立刻露馅。爱奇艺是长视频平台移动端要处理播放器状态、码率切换、缓存淘汰、Feed流复用、崩溃治理、网络弱网兜底这些事情。第二场笔试的题目方向基本都从这些真实问题里长出来。所以准备时得换心态不是背标准答案而是建立“看到现象→猜测原因→设计方案→验证结论”的工程直觉。1.2 题型配置和我的时间分配建议从当时考生的反馈来看第二场比较典型的配置是40%左右的客观题单选、多选、填空30%左右的简答和场景题20%左右的代码题剩下10%是开放设计题。客观题集中在语言细节、Runtime、内存管理简答题喜欢考网络、多线程代码题一般有算法也有手写实现开放题会给一个业务场景比如视频列表页、播放器缓存让你给出设计方案。时间分配上强烈建议按分值占比倒推不要按题号顺序死磕。一道客观题纠结五分钟最多换一分而开放题写出一套完整的分层设计可能直接决定能不能进面试。我的习惯是先花十分钟扫一遍整张卷子标出“一眼会”“要推理”“完全没思路”三类题。先把确定能拿的分拿住再去做能推理的开放题放到第二优先位保证思考时间充足。如果一道代码题卡了二十分钟还没有清晰思路先跳过往下走回头再补。死磕一道题是笔试里最亏的决策。1.3 从爱奇艺的业务反推考点权重复习前先想清楚目标公司是做什么的能省掉很多无用功。爱奇艺的核心是长视频和短视频iOS端每天都要面对播放器状态机、码率切换、缓存淘汰、页面复用、弱网兜底、崩溃监控。所以在第二场笔试里网络状态处理、线程安全、内存泄漏、UI复用与性能优化出现概率远高于冷门语法。同时要意识到时间背景。2020年那会儿iOS 13/14刚普及深色模式、SceneDelegate、SwiftUI刚开始进入视野但工业界绝大多数代码还是Objective-C和UIKit笔试重心也绝不会是新特性而是Class、Block、Delegate、KVO、Auto Layout这些老而弥坚的东西。你要是把SwiftUI动画原理背得很熟却写不出避免Block循环引用的代码这场笔试基本没戏。先把日常开发中反复使用、反复出问题的模块吃透比追逐一两年后才普及的新框架划算得多。2. 语言与运行时基础题送分题也有送命陷阱2.1 Category背着原类悄悄做事的扩展者Category是每张iOS笔试卷的常客爱奇艺第二场也不会放过它。核心考点高度集中Category里能不能声明属性、能不能直接添加实例变量、Category方法和原类方法重名时谁生效、多个Category的load方法调用顺序怎么确定。标准答案先说清楚Category可以声明属性但不会自动合成成员变量只会生成setter/getter的声明直接使用会崩溃需要借助关联对象在runtime层管理存储多个Category的load方法执行顺序和编译顺序有关不是按书写顺序或文件名字母序原类方法会被Category方法覆盖如果多个Category都有同名方法最终生效的是最后一个编译进二进制的那一个。这题的价值在于往深挖一层为什么Category不能直接添加实例变量因为实例变量的布局在编译期就已经确定而Category是运行时加载的直接改变实例布局会破坏底层内存偏移计算。这个问题面试官特别喜欢追问笔试时能写出“编译时布局 vs 运行时扩展”这个本质就已经超过一半的人。再加上一句“Category适合做横向扩展但不适合替代子类去改变类的内部存储结构”会让答案更有工程味道。2.2 Block捕获、存储与循环引用Block是绕不开的高频题。爱奇艺笔试里考过很多种问法block有哪几种类型捕获普通变量为什么不能直接修改__block到底做了什么为什么block里要用weakSelf这四问基本一次出齐。基础部分不复杂block根据存储区域分为三种——全局block没有捕获外部变量、栈block捕获了外部变量但没被拷贝到堆上、堆block被copy过ARC下系统会在很多场景自动copy。捕获普通变量时block拿到的是变量副本所以直接修改外部局部变量是编译不过的加上__block之后变量被放进一个堆上的结构体block持有的是这个盒子的引用修改自然能传出去。能用“盒子”作类比的人一般是真的理解了。循环引用是重点。典型错误代码长这样self.testBlock ^{ [self doSomething]; };self持有blockblock又捕获了self形成闭环谁都释放不了。正确的写法是weak-strong dance__weak typeof(self) weakSelf self; self.testBlock ^{ __strong typeof(weakSelf) strongSelf weakSelf; if (strongSelf) { [strongSelf doSomething]; } };为什么要多这一道__strong因为weakSelf是弱引用block开始执行后如果self已经被释放weakSelf会变成nil把weakSelf赋值给strongSelf能在block执行期间持有self保证方法调用有效判空之后也避免对象已释放却继续执行后续逻辑。这个“先取strong再判空”的习惯笔试能写上去面试官会高看一眼。2.3 KVO和KVC底层不是黑魔法KVO是iOS笔试里另一道钉子题而且爱奇艺这种内容型App特别爱考因为现在很多页面都依赖数据绑定和状态刷新。常见核心问题只有一个KVO的底层是怎么实现的回答要有层次当你对一个对象调用addObserver:forKeyPath:时系统会在运行时动态创建一个该类的子类子类重写被观察属性的setter在setter内部调用willChangeValueForKey和didChangeValueForKey然后把对象的isa指针指向这个子类从而实现监听。这也是为什么KVO是同步的为什么直接改成员变量而不走setter不会触发通知。补充一点“KVO是依赖setter的模型对象最好通过属性赋值而非直接操作_ivar”就能把原理和工程习惯连起来。真实开发里最常见的坑有两个重复添加观察者或忘记移除观察者导致的崩溃dealloc移除观察者时对象已经被释放。正确做法是让add和remove成对出现比如init里add、dealloc里remove或者放到viewWillAppear/viewWillDisappear这种明确成对的生命周期方法里不要在随机位置散落注册和移除。KVC虽然不如KVO出镜率高但偶尔会考查找顺序setValue:forKey:和valueForKey:会先找对应的getter/setter方法再找带下划线和不带下划线的成员变量找到后直接操作。能记住这个顺序KVC题基本全对。2.4 Runtime消息转发被问烂但没人答全的问题Runtime是iOS技术栈里绕不开的大头。笔试常见问法给一个对象发送一个它没有实现的方法会经历什么只答“会崩溃”或者“找不到方法”只能拿基础分。完整链路是第一次找不到方法时系统先调resolveInstanceMethod:你还有机会用class_addMethod动态添加实现返回NO之后走forwardingTargetForSelector:可以返回一个能处理该消息的替代对象再返回nil才会进入完整转发也就是methodSignatureForSelector:加forwardInvocation:把消息封装成NSInvocation交给别的对象处理。全部没接住最后才抛unrecognized selector。把这个顺序讲清楚已经及格。爱奇艺这类公司不会满足于背流程他们会换一种问法线上有一批老版本App频繁出现unrecognized selector崩溃又来不及发版你会怎么处理这就是典型的AOP思路在消息转发最后一步做统一兜底动态接管methodSignatureForSelector和forwardInvocation让崩溃不再发生。虽然无法真正执行原逻辑但能打日志、统计调用栈为下个版本修复提供依据。能答到这个层面说明你不是背概念而是知道Runtime怎么帮业务兜底。3. 内存、线程与渲染这三块不过关简历再亮也白搭3.1 ARC不是自动垃圾回收weak表也不是玄学很多校招生觉得ARC就是“不用管内存了”这是笔试里最致命的误解。ARC只是编译器帮你插入retain、release、autorelease代码它解决的是手动管理太繁琐的问题不代表不会泄漏。笔试一旦问“ARC下为什么还会内存泄漏”答不出来就说明对内存管理理解还停留在表面。常见泄漏场景包括Block循环引用、NSTimer对target的强持有、Delegate没有用weak、NotificationCenter里的block observer没移除、CLLocationManager或CADisplayLink被长期持有。每一个都能出一道选择题。再深一层的weak实现原理也常考系统维护一张全局weak表以对象内存地址为keyvalue是存储所有weak引用的数组对象释放时根据引用计数表找到weak表把所有weak引用置为nil。也正是这个机制保证了weak变量在对象销毁后安全变成nil而不是野指针。笔试里我还见过一个变体能不能在dealloc里给self发消息这是个陷阱。dealloc调用self的方法一般不建议尤其不要触发生成新的生命周期逻辑因为对象已经进入销毁流程内部实例变量可能已经释放。能答出“dealloc里只做资源释放和通知移除”的观点比背一堆API更让阅卷人放心。3.2 autoreleasepool和RunLoop的默契autoreleasepool在笔试里经常和RunLoop绑定考。要理解一个问题在ARC下谁在替我们管理autorelease对象很多人只背了autoreleasepool {} 能延迟释放对象却不清楚为什么。实际机制是App启动后RunLoop会在每次事件循环开始前创建一个autorelease pool在事件循环结束后释放它。主线程里的autorelease对象生命周期被拉长到事件循环边界而不是方法返回的那一刻。这解释了为什么一个for循环里大量创建临时对象内存峰值会飙升这些对象都被当前RunLoop周期的pool持有要等到事件循环结束才统一释放。如果每轮循环手动加一个autoreleasepool对象就能在循环体结束时及时释放这是很实战的优化。笔试出这道题时补一句“RunLoop的autorelease pool不是让对象永久存活而是让对象活到事件边界”会显得你真懂底层。如果再结合播放器循环加载帧数据的场景说“帧渲染循环外层手动控制autorelease pool的粒度”这就是加分项了。3.3 GCD和NSOperation死锁题永远做不完多线程基本是iOS笔试大分项。GCD最常考死锁、信号量、并发队列、串行队列、线程安全核心概念其实不复杂队列决定任务在哪里等待和执行任务类型决定当前线程是否阻塞。组合起来就衍生出各种坑。经典送命代码如下dispatch_queue_t queue dispatch_get_main_queue(); dispatch_sync(queue, ^{ NSLog(不会走到这里); });主线程在主队列里同步提交任务主线程等任务完成任务在主队列里等主线程空闲互相等待死锁。理解了队列和线程的关系就不会再踩这个坑。还可以顺手记住一个结论同步提交到当前串行队列一定会死锁同步提交到其他队列不一定会但要注意阻塞当前线程。NSOperationQueue在笔试里的存在感稍弱但一旦考到往往是它比GCD好用的地方可以设置最大并发数、添加依赖、取消任务。做下载器这种场景NSOperation 依赖关系比用GCD semaphore更容易写出清晰代码。笔试里能主动写出“NSOperation适合精细控制任务状态GCD适合轻量级并发任务”这种对比会显得你是真的都用过。3.4 渲染优化圆角、阴影和UIStackView的正确用法渲染优化题在大厂笔试里频率很高尤其内容型App列表多、图片多、播放器多。考察点不是“记得多少函数”而是“知不知道哪些操作会破坏性能”。先说离屏渲染。一个视图设置了cornerRadius和masksToBounds为YES或者给layer设置了shadow、mask、光栅化等属性系统可能需要先把内容渲染到屏幕外缓冲区再做合成这个开销很大。列表里几百个cell都带圆角和阴影卡顿几乎必然。优化思路通常是在GPU和CPU之间做权衡能用圆角图片就不做layer裁切能用贝塞尔路径裁切就不开masksToBounds能用Core Graphics提前绘制生成圆角图就不让系统每次合成时重复计算。要注意shouldRasterize开启后如果视图内容频繁变化缓存失效重建反而更慢不是万金油。UIStackView也是当年的高热考点尤其“ios oc uistackview”这个搜索词下面很多人在问。UIStackView的本质是自动布局容器帮你管理子视图的排列、间距和约束。好处是代码量少、结构清晰坏处是动态增删、隐藏子视图时约束更新可能比手动管理更隐蔽。笔试如果问“UIStackView和传统Auto Layout约束的取舍”可以从可维护性和动态性两个维度答不要神化它。我见过太多同学一上来就说“用UIStackView就不卡了”这是把布局工具和性能问题混为一谈。3.5 启动与耗电视频App逃不掉的性能问题长视频App对启动速度和耗电极其敏感笔试里的综合题很可能问一个iOS App启动很慢你从哪些方向排查