2020小红书iOS笔试题深度解析:从Runtime到性能优化

2020小红书iOS笔试题深度解析:从Runtime到性能优化 1. 从一份笔试题看小红书的出题逻辑1.1 这份卷子到底在考什么先聊点题外话。2020年这个时间节点比较特殊iOS 14刚发布Swift 5.1正式稳定SwiftUI虽然已经亮相但社区生产环境用得还不多绝大多数团队的业务代码仍然是Objective-C为主、Swift为辅的混合状态。小红书作为头部内容社区App它的iOS笔试题注定不是单纯考语法背诵而是围绕“如何构建一个稳定、流畅、可扩展的客户端”来设问。我当时拿到卷三的时候第一感觉是题目量不大但每道题都值得反复琢磨。它不像有些公司喜欢把题库里的八股文堆满整张卷子而是更偏向于考察你对iOS底层运行机制的理解深度以及用代码解决问题的能力。整张卷子大致可以分成四个模块语言基础与内存管理、多线程与并发、Runtime与动态性、UI与性能优化外加一两道开放性设计题。这种布局说明出题人不希望你死记硬背而是真的写过代码、真的排查过线上问题。1.2 2020年iOS技术栈背景与考点风向要理解这份卷子的出题逻辑得先还原当年的技术背景。2020年iOS端有几个热点话题一是App瘦身和启动优化几乎成了大厂标配因为Apple对包体积和启动速度的审核要求越来越严二是5G刚商用图片和视频的加载策略需要重新设计三是组件化、模块化架构在行业内大规模落地小红书这类内容产品对列表复用、异步加载、内存峰值控制的要求极高四是Flutter和RN跨端方案对原生开发者形成了一波冲击所以面试题里经常会夹杂“你如何看待原生和跨端”这类开放性问题。这些背景直接反映在笔试题目里。你会发现它考的不只是某一个API怎么用而是会问“在什么场景下选择什么方案”“这个方案的瓶颈在哪里”“如果线上出问题你怎么排查”。这种考察方式其实就是大厂面试官在用自己的日常思维出题背后考察的是工程化能力和问题拆解能力而不只是知识储备量。我再补充一点2020年校招笔试还有一个明显趋势——开始把“系统设计”类题目引入笔试环节。以前这类题目基本都在面试环节才出现但小红书卷三里明显有一道“设计一个图片缓存机制”或类似的题目。这说明公司希望在笔试阶段就筛掉那些只能单纯刷题、缺乏整体架构思维的人因为社区类产品每天的图片请求量是千万甚至上亿级别缓存策略设计得是否合理直接决定了用户体验和服务器成本。1.3 这张卷子适合谁来参考如果你是正在准备iOS校招或实习面试的在校学生这份卷子能帮你快速摸清大厂笔试的出题套路和重点方向如果你工作一两年想跳槽它也能给你一些复习参考——尤其是Runtime、内存管理、多线程这几个必考点几乎所有大厂都逃不掉。哪怕是已经带团队的技术Leader回看这份卷子也能发现一些值得借鉴的面试设计思路比如怎么通过题目区分“背书型”和“实战型”候选人。我自己在带新人、做技术面试的时候也参考过类似的题目结构。说实话能写出一张高质量笔试题的团队通常内部技术沉淀也不会差到哪里去因为它要求出题人自己对知识点有足够深的理解而且还要能设计出符合业务场景的题目载体。所以这篇博文不只是带大家“解题”更想带大家站在出题人的角度把每个考点背后的原理和边界条件聊透。这是比单纯对答案更有价值的事情。2. 高频考点深度拆解从原理到实战2.1 语言基础OC与Swift那些绕不开的坑先说说语言基础部分。2020年的笔试试卷里OC和Swift的占比大概是7比3因为当时小红书的存量代码还是OC为主但新业务已经逐步切Swift。笔试不会直接问你“OC和Swift哪个好”而会用具体的语法题来考察你对两者差异的敏感度以及是否理解混编时的一些潜在风险。比如有一类高频题是考属性关键字。我们知道OC里strong、weak、copy、assign的区别几乎人人都能背出来但真正有区分度的题会这么出给一个NSMutableArray类型的属性要求写出能规避外部修改的声明方式。正确答案是声明为copy并在setter里做一次不可变拷贝但很多人会把copy写在NSArray上或者直接用strong然后寄希望于调用方自觉。这种题考察的是你是否真正理解“可变与不可变”这对边界以及防御性编程思维。Swift这边最常见的是值和引用类型的区别。类class是引用类型结构体struct是值类型这个大部分人都知道但笔试会进一步问数组在Swift里是值类型为什么把一个数组赋值给另一个变量后修改其中一个不会影响另一个这就牵扯到Copy-on-Write机制。面试官真正想听的是你不仅知道数组是值类型还知道Swift在底层做了写时复制的优化只有真正发生修改时才进行深层拷贝。如果你能顺着这个点再提到NSArray与Swift数组在桥接时的性能差异那就更好了。记忆里还有一个比较容易翻车的考点分类Category和扩展Extension的区别。OC里分类可以给已有类添加方法但不能直接添加成员变量除非通过关联对象Associated Object曲线救国而扩展在编译期就把方法直接合并进了主类所以添加的属性会生成真正的实例变量。这道题很多人能答出一半但答不出“分类中的方法在运行时会被放在类的方法列表前面导致同名方法覆盖主类方法”这个底层细节。如果你能讲清楚方法覆盖的顺序规则和load与initialize的调用时机差异面试官基本可以确认你是写过底层代码的人。关于语言基础怎么准备我的建议是不要只刷博客动手写几个小Demo去验证。比如自己建一个工程往一个类上挂两个同名分类方法再用class_copyMethodList去打印方法列表顺序亲眼看一遍远比背答案印象深刻。这类小实验耗时不到半小时但对理解Runtime的布局非常有帮助。2.2 内存管理与引用计数内存管理是iOS笔试的压轴考点也是区分度最大的一块。ARC时代虽然不需要手动管理引用计数但你必须理解它背后的机制否则遇到循环引用、野指针、内存泄漏问题会一头雾水。2020年小红书卷三里有一道题让我印象很深它给出了一段代码里面有一个block捕获了self而self又持有这个block让我判断是否会产生循环引用。表面上看答案很简单但出题人加了一个细节block里用的是self-_name直接访问成员变量而不是self.name。细心的同学应该知道如果在block里直接访问实例变量编译器会隐式地强引用self哪怕你写的是__weak typeof(self) weakSelf self;只要在block里用了_nameweakSelf就白写了因为strongSelf的语义已经被隐式触发。这就是典型的“看起来避开了却仍踩坑”的题目。关于内存管理还需要重点准备dealloc的线程安全、weak变量自动置nil的时机、autoreleasepool在循环中的使用等场景。比如在一个for循环里创建大量临时对象如果不手动加autoreleasepool峰值内存会持续累积因为循环结束前自动释放池不会drain。这个考点不仅笔试会考线上性能优化也经常会用到。另外2020年ARC已经非常成熟MRC的坑基本没人考但它可能会问Block的存储类型_NSConcreteStackBlock、_NSConcreteGlobalBlock、_NSConcreteMallocBlock分别出现在什么场景下。这类题的价值在于考察你对“栈上对象如何拷贝到堆上”的理解以及为什么block的属性要用copy修饰。如果你能补充一句“在ARC下编译器会自动拷贝栈上block但显式声明copy仍然是最佳实践”这个回答就完整了。我当时备考时总结过一个内存管理自查清单这里分享给大家每一个dealloc里是否移除通知观察者或KVOiOS 9之后虽然系统做了优化但依赖系统行为不靠谱。block里对self的引用是否已经用weak-strong dance处理清楚NSTimer是否被self强持有同时又强引用了self记得在viewWillDisappear或dealloc里invalidate。属性声明是否选择了正确的修饰词委托务必用weak字符串和block多用copy。2.3 多线程GCD与OperationQueue的边界认知多线程这块2020年校招笔试几乎必考GCD而且不会只考“什么是死锁”这么简单。它会给你一段嵌套同步任务的代码问你输出结果是什么、会不会死锁。典型的就是dispatch_sync在serial queue里调用自身导致的死锁以及主队列里调用dispatch_sync导致的死锁。这两个应该是基础中的基础但很多人在快速答题时依然会判断错因为忽略了队列的串行属性和当前执行上下文。让我再往深一层说。GCD最容易被笔试考到但又被面试者忽略的知识点是“队列与线程的关系”。很多人会误以为dispatch_queue_create创建的就是线程实际上队列只是任务的组织结构底层的线程池由系统统一管理。系统会根据CPU核数、任务类型QoS动态调整线程数量你无法也不应该手动控制某个任务具体在哪个线程上执行。所以如果你在代码里对当前线程做缓存或者依赖线程ID做状态管理本身就是一种反模式。另一个常见考点是信号量与并发控制的区别。面试官可能会问“假设有100个图片下载任务怎么控制同时最多只有3个在下载”两种主流方案是信号量dispatch_semaphore_wait/signal配合dispatch_async或者使用OperationQueue的maxConcurrentOperationCount。这个题其实没有标准答案考察的是你有没有真正用过它们。我的建议是答OperationQueue因为它不仅可以限制并发数还能方便地设置依赖关系、取消任务、监听完成状态这些在复杂的业务场景里非常有用。关于多线程还有一种容易出错的题型是Race Condition的输出顺序预测。给定两个并发队列同时读写同一个变量问最终结果可能是多少。这类题考察的是原子性问题需要提到atomic与nonatomic的区别以及为什么atomic并不能保证线程安全它只保证读写完整不保证业务逻辑的互斥。说实话多线程题目是最能拉开实战经验和理论背诵之间差距的模块。建议备考时多写一些多线程的小Demo用os_signpost或者Xcode的Thread Sanitizer工具观察数据竞争这比看十篇文章都有用。2.4 Runtime与消息转发机制Runtime是iOS面试里绕不开的核心话题也是小红书笔试里的重点内容。为什么内容社区App特别爱考Runtime因为动态性对于埋点、热修复、AOP面向切面编程、页面路由这些需求来说太重要了而这些恰恰是大型App赖以生存的基础设施。笔试里最常见的Runtime题目有消息发送的完整流程是什么objc_msgSend的查找顺序是怎样的动态方法解析和消息转发分别在什么阶段触发除了背诵机制有区分度的题目会让你结合场景设计解决方案。比如“如果线上有一个紧急Bug但App审核需要几天你能用什么手段临时规避”这就考察到了method_exchangeImplementations方法交换和class_replaceMethod的使用场景。当然热修复在2020年后被Apple严格管控但Method Swizzling本身作为埋点和防御性编程手段仍然是合法且常用的。我强烈建议备考时把Runtime的对象模型理清楚包括isa指针、类对象与元类、方法缓存机制。笔试虽然很少直接考元类图因为太理论且容易死记硬背但对它的理解会直接影响你对“类方法本质上是元类实例方法”的判断。这个知识点在回答“OC类方法存在哪”这类问题时有奇效。另外一个容易出题的点KVO的实现原理。为什么给对象添加KVO后它的isa指针会指向一个中间类NSKVONotifying_XXX为什么KVO回调里能拿到旧值和新值如果你能把KVO的整套实现机制讲清楚包括为什么要重写setter、为什么要重写class方法、以及如何手动触发KVO那这道题基本满分。2.5 UI与布局从AutoLayout到列表流畅度UI和性能优化是小红书这类内容社区非常看重的技能因为用户看到的直接就是一个展示内容的列表页。2020年的笔试里出现了一道经典的列表优化题要求分析一个UIScrollView滚动的卡顿原因并给出优化方案。常规答案大概有减少视图层级用drawRect或AsyncDisplayKit、异步解码图片、避免透明图层混合、减少离屏渲染、复用Cell、尽可能用不变量高度等等。但要做到答出区分度必须能解释底层原理。比如为什么圆角masksToBounds会触发离屏渲染因为cornerRadius和maskToBounds的组合意味着图层需要先裁剪成圆角再绘制到屏幕上这个过程无法在GPU的渲染循环里直接完成。但如果只是给一个UIImageView设置圆角背景色不触发mask就可以利用backgroundColor加cornerRadius直接走GPU合成性能高很多。还有一道让我困扰很久的题是“在AutoLayout下如何实现一个等高的动态高度Cell”。2019年至2020年iOS开发者还在和UITableViewAutomaticDimension斗智斗勇常见坑有估算高度不准确导致的跳动、约束冲突导致的自动布局卡死、以及preferredMaxLayoutWidth在多行Label上忘记设置导致的宽度计算错误。如果你能系统性地讲清楚“从model到视图高度”的计算链路包括如何利用systemLayoutSizeFitting手动预计算高度缓存起来这道题就答透了。我还想强调一个点笔试中如果让你写UI布局相关代码千万不要一上来就frame硬编码。即使你的方案是纯代码编写也要体现出你对不同屏幕适配的思考。用Masonry或原生NSLayoutAnchor都可以但一定要写出比例约束、动态间距等细节最好能提到“对于复杂布局使用子类化UIView布局方法统一管理”的思路。这样能让面试官看到你不只是会拖Storyboard。3. 编程题与算法题备考方法论3.1 笔试中的算法题怎么准备虽然定位是iOS方向但大厂校招笔试基本都逃不掉算法题。小红书卷三的算法题难度大约在LeetCode Medium水平不会出现太过分的Hard题但会有几道经典题型的变种。备考时别盲目追求刷题数量我建议重点掌握几类数组与哈希表、链表操作、二叉树遍历与递归、字符串处理、动态规划入门以及偶尔出现的贪心或二分法。这些足够应付90%的客户端笔试场景。一个容易被忽略的点是明确题目对输入输出的限制条件。客户端笔试题和纯算法题有一个区别它通常会和实际的业务场景结合。比如题目可能不是单纯的“给一个数组排序”而是“给一批图片下载任务按优先级排序并要求稳定排序且时间复杂度尽量低”。这时候如果你只回答快速排序可能忽略了“稳定”这个隐含条件正确答案应该是归并排序或对排序字段做复合处理。我备考时的做题策略是每个知识点至少手写三遍代码第一遍不看任何参考答案第二遍对照优化第三遍按笔试的时间限制比如15分钟模拟。编程题写到第三遍时基本就形成肌肉记忆面试时即使紧张也能流畅输出。3.2 书写代码时这些细节决定成败笔试时代码写得对不对是一回事代码写得好不好看是另一回事。面试官看到的是一段最终代码他在心里会默默评价你的代码风格、命名规范、边界处理能力。2020年很多公司开始使用在线笔试平台比如牛客网、赛码网这类平台很可能不支持自动补全你写出的每一个字母都会呈现在面试官眼前。第一个细节是命名。不要用a、b、tmp这种随意的变量名尽量使用有语义的命名。就算题目里给的是简短的变量名你也应该在代码里用imageURLs、maxConcurrentCount这类名字。这是给面试官传递“我有良好工程习惯”的信号。第二个细节是边界条件的处理。找出数组里的最大值之前是否判空链表操作时头节点为空会不会崩溃递归函数是否设置了终止条件这些都是笔试里最容易被扣分的隐形项也是区分“有经验”和“没经验”的直观指标。第三个细节是内存和释放意识。手动创建了指针或对象时在合适的位置是否需要释放或置nil虽然在ARC环境下这不是硬性要求但如果你写的是C语言风格的代码比如CoreFoundation框架下的CF对象就必须注意CFRelease。这种细节会让面试官觉得你不仅会写Swift/OC还理解底层。我还有一个建议笔试在线提交前留出3到5分钟专门检查一下有没有“编译不过”的低级错误。比如大括号是否配对、方法结尾是否加分号、import是否齐全。这些错误非常可惜因为即使算法思路正确编译不过也拿不到分。4. 项目经验与开放题答题技巧4.1 如何回答“印象最深的项目”开放题部分是最容易暴露真实水平的地方也是最难临时抱佛脚的部分。小红书2020年笔试题里有一道典型开放题大意是让你描述一个自己独立完成或深度参与的iOS项目讲清楚技术难点、解决方案和个人收获。回答这道题时要特别注意“技术难点”和“解决方案”的比例。很多人会陷入流水账项目背景、功能模块、用了什么框架、做了什么事。但真正能打动面试官的写法是先抛出这个项目里最棘手的问题然后描述你是围绕什么原理、做了哪些实验、最终选择了什么方案以及这个方案上线后的效果数据。最好还能加一句“如果再遇到类似问题我会从哪个方向优先排查”显得有复盘思维。我强烈建议每位准备笔试的同学提前把简历里两三个项目的技术细节整理成稿。每个项目准备300到500字的口述版重点覆盖项目规模代码量、日活量级、你在项目中的角色、最大的技术挑战、最终的效果和量化数据。不要追求大而全一段经历只需要突出一个高潮点。比如你优化过列表启动时间就重点讲你是怎么用Instruments定位到耗时点做了哪些优化最终从多少毫秒降到多少毫秒。4.2 开放性设计题的回答框架开放设计题在2020年校招笔试中的出现频率明显上升。这类题通常没有标准答案但有一个可以参考的回答框架需求分析、架构设计、关键细节、容灾与扩展性。先说需求分析。不管题目给出的是什么场景第一步一定是把限制条件说清楚。比如设计一个图片缓存机制你需要先定义支持多大的图片图片的生命周期是多久缓存命中率目标是多少本地缓存和内存缓存的容量各是多少这些需求点直接影响后续的设计方案所以一定要先解析需求不要上来就画架构图。其次说架构设计。合理的缓存机制一般分三层内存缓存NSCache、磁盘缓存文件系统、网络层。每一层都有自己的淘汰策略比如LRU最近最少使用、LFU最不经常使用或者两者的结合。这里建议提到NSCache与NSDictionary的区别NSCache在系统内存紧张时会自动清空并且有线程安全特性是内存缓存的更优选择。再往下是关键细节。图片的解码放到子线程还是主线程SDWebImage为什么默认在子线程执行图片解码磁盘缓存是按URL做哈希还是直接用URL作为文件名这里涉及文件系统对文件名长度的限制255字节以及特殊字符的兼容问题有经验的人会直接给出哈希方案。把这些细节写清楚比堆很多技术名词更能体现专业性。最后是容灾与扩展性。如果磁盘缓存写失败怎么办缓存版本升级如何兼容旧数据图片CDN故障时是否有降级方案这些思路能体现一个工程师的工程素养而不是停留在功能和性能层面。5. 新人备考iOS笔试题的实操路线图5.1 时间规划与资料选择如果你现在是大三或研二准备2021年秋招留出三到四个月的系统复习时间是必要的。我自己的经验是把备考周期划分为三个阶段基础巩固期、专项突击期、模拟冲刺期。基础巩固期大概占六周任务是过一遍iOS核心知识框架包括但不限于OC语言特性、Swift基础语法、Runtime、RunLoop、内存管理、多线程、网络。这一阶段不要急于刷题重点是建立完整的知识地图。参考书方面推荐《Objective-C高级编程iOS与OS X多线程和内存管理》、《Effective Objective-C 2.0》和Apple官方文档。不要贪多两本经典书配合官方文档完全足够。专项突击期大概占四周任务是针对薄弱环节做定点打击。如果你在自动布局上总是理不清约束优先级就找专门的教程和实战项目练如果对网络层理解不深就自己用URLSession封装一个带重试和缓存的基础网络库。这一阶段的核心不是你看了多少资料而是你写下了多少代码做了多少实验。模拟冲刺期大概占两周任务是做整套的模拟题和往年真题。可以找朋友组队互相出题也可以自己做限时练习。目标是训练出考试节奏单选和判断题每道不超过2分钟简答题每道控制在8到10分钟编程题每道留足20分钟。这样分配时间能确保整张卷子覆盖到尽可能多的题不会因为卡在一道题上导致后面的题没时间做。5.2 如何用最小成本搭建一个iOS学习环境说到准备面试学习环境的搭建也是一道坎。很多同学还在犹豫要不要买Mac这里我可以给一些参考如果你只是刷题和写Demo一台二手MacBook Air或Mac mini完全可以胜任iOS模拟器并不需要太高的配置8GB内存起步其实已经能做大部分实验了。如果你想跑真机调试到闲鱼淘一个iPhone 8或iPhone X支持的最新系统版本基本能满足2020年那一代的知识点验证需求。如果你手头暂时没有Mac也还有另一条路在Linux或Windows上装虚拟机跑macOS。这种做法虚拟机性能损耗比较大模拟器会卡但如果你是零基础先用来写OC和Swift的简单命令行程序做练习也是可行的过渡方案。等真正到了需要跑UIKit的阶段再考虑专属设备这样成本压力小很多。工具链方面必备的有Xcode版本选择要看目标iOS系统、CocoaPods或Swift Package Manager用于管理第三方库、Git版本管理、Charles抓包工具用于学习网络协议调试。Instruments这个工具一定要提前练熟它是性能优化的核心工具笔试虽然不会直接考但面试环节的追问往往离不开它。提醒一句正式笔试前建议先去牛客网或赛码网熟悉一下在线编辑器的操作方式尤其是JavaScript或C之外的代码补全和切输入法的问题不要因为这些环境问题影响发挥。6. 常见问题与踩坑实录6.1 笔试中最容易失分的几个点我围观和参与过不少校招笔试总结出几个常见失分点基本都是可以提前避免的但每年还是有很多人踩进去。第一个是审题不清。笔试题为了严谨通常会写很长一段题面包括背景、前置条件、输入输出格式、边界约定。很多同学扫一眼就开始做题结果漏掉了“输入数组可能为空”“需要保持稳定排序”“不允许使用系统库函数”这些关键条件。我个人建议拿到卷子后先花3分钟通读所有题目再逐题细看尤其注意加粗和标注的限定条件。第二个是时间分配失衡。我知道有人喜欢先把编程题做完觉得编程题分值高但最后发现简答题全空着反而丢了大分。2020年小红书卷三的题型分布里简答和设计题占比并不低每一道都是有区分度的题空着非常可惜。合理的做法是先把所有题目都浏览一遍优先作答自己最有把握的题把不确定的题标记出来留到最后。确保“会做的全做对、不会做的也能蒙几分”。第三个是代码风格和注释。上传代码前不检查缩进、不写任何注释或者注释写了但和实际代码不符这些都会给面试官留下不好的印象。代码本身是给人看的不是只给机器执行的。至少在关键步骤旁边写一行“这里用LRU是因为……”能大大增加你的印象分。第四个是忽略团队协作和版本管理相关的试题。现在大厂笔试偶尔会出一两道和Git相关的题比如“代码冲突怎么解决”“怎么在多个commit里挑出某个改动”。虽然这类题占比不高但因为大多数候选人完全没准备反而成了拉分项。建议至少掌握git rebase、git cherry-pick、git merge --abort这几个命令的用途。6.2 我自己的备考和踩坑经历最后一次分享一点个人经验。我第一次参加大厂笔试的时候遇到一道多线程的题分析得很顺自我感觉良好结果提交后才发现把serial queue和concurrent queue的概念搞混了整道题的输出顺序全错。那次失利给我的教训是知识点不能只停留在“好像懂了”的层面必须能用自己的话讲一遍最好能写在纸上。这也是为什么我后来坚持做“知识输出法”——每天找两到三个知识点用大白话讲给室友听讲不出来就是没掌握。还有一个踩坑是我把大量时间花在了刷LeetCode的Hard题上但笔试题里的算法实际上以Medium偏Easy为主。与其在Hard题里挣扎不如把基础数据结构和常见题型练到“不看题解也能写出无Bug版本”的程度。比如反转链表、二叉树层序遍历、最长回文子串这类经典题要做到闭着眼睛都能写对边界条件这比会做一两道Hard题有用得多。另外备考期间一定要保持写代码的手感。我见过不少同学理论知识背得很熟一到现场手写代码就短路连NSMutableArray的增删改查方法名都要想半天。最好的方式是把iOS面试常见代码题整理成一个项目每天写两三个小函数保持代码输出的流畅度。如果你也是正在准备iOS方向校招的应届生我想说的是笔试只是整个求职流程的第一步既不要过度焦虑也不能轻视。它能帮你筛查出基础薄弱项但不能完全定义你的工程能力真正的成长还是来自于你日后一行行代码的积累和一次次线上问题的排查。把这份小红书卷三的考点吃透在面试时能讲清楚原理、展示出你对工程细节的关注相信你会收获理想的结果。