ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

iOS研发岗春招笔试复盘:从内存管理到架构设计的实战解析

iOS研发岗春招笔试复盘:从内存管理到架构设计的实战解析 2023年小满春招iOS研发岗的第一批笔试我是在一个工作日上午参加的统共两个小时成绩出来后侥幸通过了。当时在牛客上蹲了几天发现关于这场笔试的复盘帖子少得可怜大部分都是“求面经”“求真题”的零散讨论。今天闲下来我把能记住的题目脉络、踩过的坑、还有答题时的思考过程完整梳理一遍尽量还原当时真实作答的情况。这篇内容更多是站在“复盘”的角度来写我会先把整场笔试的考察方向拆开再说每类题目背后的考点意图最后给出我自己的备考思路和实战建议。不管你目标是iOS研发岗还是想看看大厂/独角兽春招笔试的出题风格这篇都能给你一个相对立体的参考。1. 笔试整体情况与考察方向1.1 这一场笔试考了什么整场笔试分三个部分客观题、简答题、编程题。客观题大概20道覆盖语言基础、内存管理、多线程、Runloop、系统机制简答题有4道考察设计思路和工程问题排查编程题有3道其中一道是纯粹的算法另外两道是偏iOS场景的代码实现。先说整体感受题目难度不低但没到“劝退”的程度。给我印象最深的是这套卷子非常看重“系统机制理解”和“工程落地细节”不是单纯背八股文就能扛住的。举个例子客观题里出现了“iOS分屏状态下App生命周期回调顺序”这种题这要求你不仅知道applicationDidEnterBackground这类回调的名字还得理解多任务场景下系统到底怎么调度。这种题背题库很难命中因为它本质上在考你有没有真正做过iPad适配或者多窗口调试。再有一个感受是这场笔试对“架构”的权重明显偏高。简答题里有一道是“如果让你设计一个轻量级网络层你会怎么拆分模块”这已经超出了“会调用URLSession”的层面它要求你有方案设计的能力。后面我会单独拆这道题。1.2 从试题反推企业用人偏好笔试是最直接的“用人画像”。我个人从这套卷子里读出三个信号第一是希望候选人有系统级思维。卷子里涉及了不少iOS系统机制类问题比如App前后台切换、SceneDelegate多窗口、蓝牙权限状态区分、电池优化等。这类知识光靠写业务代码积累不快得主动去翻官方文档和WWDC Session。第二是希望候选人有工程化经验。比如简答题里有关于证书签名、开发者模式、真机调试报错的题。这些内容哪怕你在小公司自己搞过一遍TestFlight上架都能答出几分。第三是不排斥跨端知识。笔试里提到了混合开发方案、uniapp打包iOS的流程相关知识点说明对方团队很可能有跨端业务或者希望候选人具备“原生为主、跨端为辅”的技术视野。这点在准备笔试的时候容易被忽视大家往往只看纯原生知识点结果遇到这类题就懵了。2. 客观题考点复盘基础与系统机制2.1 iOS核心基础内存管理、Runloop与多线程客观题里基础部分占的比重最大。一类是内存管理题比如分析一段代码的引用计数变化区分weak和assign在对象释放后的行为差异还有autoreleasepool在for循环里的应用场景。这类题说白了就是考ARC下的内存管理直觉。我当时答得比较顺是因为把weak的底层实现机制看明白了——SideTable、weak_entry_t这套东西理解了之后很多题目都不用猜直接推导就行。还有几道Runloop的题集中在source0、source1、timer和observer的触发顺序以及performSelector:afterDelay:在子线程不生效的原因。这种题不会直接问“Runloop是什么”而是给你一段代码问你某个回调为什么没执行或者某个UI为什么卡顿。核心还是要理解Runloop是一个事件循环每个循环处理消息并决定是否休眠。多线程的题也跑不掉。GCD的队列类型、dispatch_barrier_async的作用、NSOperationQueue的依赖关系这些高频考点基本全覆盖了。有一道题让我印象很深问的是dispatch_group_notify和dispatch_group_wait的区别看似简单但选项中埋了“notify是异步回调wait是同步阻塞”这个坑。这种题在笔试里很常见因为面试官想通过客观题快速筛选出“真正用过、且理解同步异步差异”的人。2.2 系统机制题分屏、多任务、前后台状态切换这一块是试卷里的“进阶题”也是我复盘时觉得拉分的关键。iPad分屏、SceneDelegate生命周期、前台后台切换的回调顺序这些在普通App开发里不一定碰得到但只要做过iPad适配或者在新版Xcode里创建过支持多窗口的工程就能很直观地回想起来。我记得有一道题是这样一个支持分屏的App当用户在Split View中调整窗口比例时viewWillTransitionToSize:withTransitionCoordinator:和scene(_:willConnectTo:options:)的调用顺序是什么——这种题考的不是单点知识而是整个Scene生命周期和视图控制器转场机制之间的关系。答题时要特别注意“窗口尺寸变化”和“场景连接/断开”是两条独立的事件链路不能混着答。App前后台切换也是必考。applicationDidEnterBackground、applicationWillEnterForeground这套回调在普通开发里大家都会用但笔试会加一层如果开启了Background Modes哪些行为可以在后台继续执行哪些会被系统挂起。比如URLSession的background配置可以继续传输数据但普通的Timer会被暂停。这类题本质上是考“你对系统资源调度的敬畏心”——iOS是一个极度强调省电和流畅的系统所有后台行为都要经过系统审批。2.3 UI布局与自动布局UIStackView与约束冲突排查客观题里UI的占比也不小而且考法很活。有道题问你UIStackView中某个arrangedSubview设置了hidden YES之后其余子视图的布局会发生什么变化。这个题特别有意思因为很多人用UIStackView只是在Storyboard里拖一拖对它的“隐藏即移除”机制没有直观认识。正确答案是隐藏的视图会从布局计算中移除剩余视图会按distribution属性重新分布。如果你用过UIStackView做动态表单这个特性简直是神器笔试考到它说明出题人很清楚实际业务里的高频用法。还有一个高频方向是Auto Layout约束冲突。考法通常是给你一段console输出里面有Unable to simultaneously satisfy constraints然后让你判断是哪个约束出了问题。做题的时候别慌先看NSLayoutConstraint的description里有没有提到具体的View地址再看priority最高的那条约束基本就是问题所在。这种题与其说是考概念不如说是考“你有没有在真机上处理过这类崩溃”。3. 工程与架构题复盘从会写到会设计3.1 高频架构题MVC、MVVM与组件化的取舍笔试简答题里有一道是“谈谈你对MVVM在iOS项目中应用的理解以及在什么场景下会选型MVVM而不是MVC”。这类题目没有标准答案但答题必须展示出清晰的逻辑结构。我的答题思路分四步先定义MVC和MVVM各自的角色边界再说明MVVM引入ViewModel层之后ViewController被“瘦身”带来的可测试性提升接着指出MVVM在轻量页面中容易造成“过度设计”——很多页面模型简单、逻辑单一硬套MVVM反而多了一层无意义的“胶水代码”最后落到自己的选型原则ViewController超过几百行、业务逻辑与UI状态强耦合时才会考虑引入MVVM。组件化也是热词笔试如果考到大概率不是让你写一套完整方案而是问“模块间通信怎么做”。我当时答的是基础组件和业务模块分清楚业务模块之间的调用可以通过Protocol或中间件解耦整个架构里要保留“模块注册表”或“路由表”这类统一入口。答题的时候要带出一些真实项目里的数据比如你拆过几个组件、接口怎么设计的、解决了什么问题这比空谈理论有说服力得多。3.2 混合开发与跨端方案原生视角下的认知边界笔试里专门有一道跨端相关的题提到uniapp打iOS测试包的全流程问我“如何理解原生iOS和跨端框架的关系”。说实话这道题如果只看热词列表可能觉得奇怪但结合行业背景就合理了——很多中小团队会同时维护原生App和跨端App。我的作答重点没有放在“uniapp怎么用”上而是放在“原生能力边界在哪里”。跨端框架最终都会通过JSBridge或原生SDK间接调用iOS系统能力所以原生开发者要做的不是抵制跨端而是把原生模块沉淀成稳定的能力层供上层统一调用。比如蓝牙、定位、推送这类系统能力在跨端框架里往往就是插件封装原生的职责就是保证这些封装的稳定性和性能。这道题还延伸出一个点wns、本地构建、证书配置跨端工程的打包和原生其实高度重合。如果你有过在Xcode里配过Development Team、管理过Provisioning Profile的经验再去看跨端打包流程会发现很多概念是相通的——这就是为什么笔试里会问开发者证书、签名这类看似基础但很关键的问题。3.3 签名、证书与真机调试容易失分的工程题证书和签名是笔试里客观题容易考、简答题也容易顺带一提的内容。核心考点是Development Certificate、Distribution Certificate、Provisioning Profile、Entitlements这几个概念之间的区别以及Bundle Identifier不匹配时会出现什么报错。我印象很深的是有一道判断对错题“所有的iOS App都必须通过App Store Connect审核才能安装到真机上”。这句话是错的因为还有Ad Hoc和In-House两种企业分发方式。但要注意企业证书的使用范围是有限制的而且苹果对这类证书的管控越来越严个人开发者走正规的TestFlight流程才是常规操作。答题时最好把三种分发方式的特点都列出来让阅卷人看到你对整套机制有完整认知。真机调试的题也常见比如Could not launch because of the problem with the code signature这种报错怎么排查。这类题的做法是先确认证书是否有效、描述文件里的设备列表是否包含当前设备、Build Settings里的Code Signing Identity是否选对三步走基本能覆盖80%的问题。4. 编程题实操复盘从思路到代码4.1 手写题常见类型与时间分配编程题3道我当时的策略是先扫一眼所有题目把最有把握的那道先写掉保证基础分再回头啃难啃的。第一道题是纯算法——“给定一个数组找出所有能组成三角形的三元组数量”第二道是“实现一个支持倒计时和循环任务的定时器封装”第三道是“设计一个轻量级磁盘缓存”。时间分配上我没有按题目顺序走。先花20分钟做第一道因为这类题思路明确了就是码代码再花15分钟做第二道最后剩下的时间全部砸在第三道设计题上。设计题需要写出接口定义和关键实现不是几行代码能糊弄过去的所以时间要留足。4.2 一道数组算法题的完整答题过程数组算法题的原题大概是给定一个包含n个整数的数组判断能组成三角形的三元组有多少个。暴力解法是三层循环时间复杂度O(n^3)大概率超时所以我当时直接用排序双指针。思路先把数组排序固定最大边nums[i]然后在它左侧用双指针找两数之和大于nums[i]的对数。因为排过序只要nums[left] nums[right] nums[i]成立那left到right-1之间的所有元素和right配对都能满足条件直接累加区间长度就行。我当时写出来的核心代码大概是这样func triangleCount(_ nums: [Int]) - Int { let sorted nums.sorted() var count 0 let n sorted.count guard n 3 else { return 0 } for i in (2..n).reversed() { var left 0 var right i - 1 while left right { if sorted[left] sorted[right] sorted[i] { count (right - left) right - 1 } else { left 1 } } } return count }写完之后我特意检查了两个边界一是n 3时直接返回0二是循环里right - left的累加逻辑别重复计数。这类题只要思路对、边界处理好基本上不会丢分。4.3 定时器封装与磁盘缓存设计题的做法定时器封装题是让实现一个“支持暂停、恢复和倒计时的Timer管理器”。我第一时间想到的是用DispatchSourceTimer因为它可以随时cancel和setEventHandler比Timer更好控制生命周期也能避免循环引用。我先定义了一个CountDownTimer类内部持有DispatchSourceTimer用state枚举标记运行状态然后对外暴露start(seconds:onTick:onComplete:)、pause()、resume()、cancel()这几个接口。pause和resume的实现需要记录剩余时间——我用了remainingSeconds变量每次tick递减暂停时cancel掉当前timer恢复时用剩余时间重新创建一个timer。这道题的重点不在“会不会用Timer”而在于“有没有处理过循环引用”。我在接口设计时故意把回调闭包全部标注为escaping并声明了一个weak var delegate来承接回调这样能向阅卷者展示你清楚闭包捕获列表带来的隐患。磁盘缓存设计题更偏工程。我定义了一个DiskCacheT: Codable的泛型类核心接口是set(_:forKey:)和object(forKey:)。存储用文件系统路径放在Caches目录下写入时用JSONEncoder编码读取时用JSONDecoder解码。为了防止缓存无限膨胀我做了一个简单的LRU策略每个缓存文件带一个lastAccessDate在写入新文件时检查总缓存大小超过阈值就删除最旧的文件。虽然这个策略比较粗糙但在笔试有限时间里能完整表达出“缓存淘汰”的思路比只写出读写方法要加分不少。5. 易错点与避坑记录独家经验5.1 客观题里最容易被绕进去的三个坑第一个坑是弱引用和归零。题目里说“weak修饰的对象在释放后会自动变成nil”听起来没错但如果让你选择__weak和__unsafe_unretained的区别很多人就会漏掉“unsafe_unretained不会置nil访问已释放对象会野指针崩溃”这个关键点。第二个坑是Runloop和performSelector的组合。题目给了一段“在子线程里执行performSelector:afterDelay:”的代码问会不会崩溃。正确答案是“不会立即崩溃但回调不会被执行”因为子线程默认没有开启RunloopafterDelay的定时事件根本不会被调度。很多人直接选“崩溃”就是没理解Runloop的事件循环机制。第三个坑是分屏下的生命周期。前面也提到iPad分屏时窗口尺寸变化viewWillTransitionToSize和SceneDelegate的sceneDidDisconnect都可能触发但顺序不同。我复盘时特意记了一下窗口尺寸变化会走视图控制器的转场方法而Scene断开会走sceneDidDisconnect两者层级不同。做题的时候如果题目里同时出现这两个方法一定要看清问的是哪个层级。5.2 编程题边界与内存细节编程题里最容易丢分的不是主逻辑而是边界条件。第一道三角形计数题如果输入数组的长度小于3直接返回0这个很多人会漏。再比如数组元素有负数的情况——三角形三边必须是正数排序后如果最大值小于或等于0那结果应该是0。这类隐藏条件在题目描述里不一定明说但工程思维会提醒你“这个数据合法吗”。定时器封装题还有一道陷阱如果App进入后台DispatchSourceTimer会被系统挂起导致倒计时不准。这个知识点出现在笔试里就很有区分度因为很多候选人只在“前台正常跑”的维度写代码不会考虑系统级调度的影响。我当时在代码注释里特意提了一句“如果用Timer在后台模式下的行为会不同”至少说明我有这方面的意识。5.3 笔试环境与心态管理小满这场笔试用的是在线编程平台支持在网页里切到Xcode写代码。我需要提醒你的是在线编译器基本不提供代码联想平时用Xcode写习惯了很多API名字会突然想不起来。我当时为了避免这种情况在备考阶段特意练习过在纯文本编辑环境下手写UITableViewDataSource的完整实现。这个习惯救了我一命因为在写定时器的时候DispatchSourceTimer的初始化方法名不带提示我自己写就很容易拼错。再就是时间管理。我的经验是客观题每道不要超过2分钟简答题每道控制在10分钟以内剩余时间全部给编程题。有些选择题确实很难纠结太久容易崩盘先标记一版答案回头有时间再回来验证。编程题如果一道卡了超过25分钟就果断换下一道因为一道题满分也就20分左右为了它丢掉后面整道设计题不划算。提示在线笔试平台一般有“代码自动保存”功能但千万不要依赖它。当时我旁边有个考场的同学反馈因为网络波动导致代码没保存上白写了半天。建议每隔几分钟手动点一次保存好习惯不亏。6. 备考建议给下一个入场者6.1 系统知识用官方文档打底这次笔试让我重新意识到网上零散的面经文章只能覆盖“高频考点”很难覆盖“系统机制细节”。我建议有时间的同学老老实实过一遍苹果官方文档特别是App Programming Guide for iOS里关于App生命周期、状态恢复、后台执行的部分。这些英文文档读起来确实枯燥但笔试里有些“偏题”就是直接脱胎于文档原文的。WWDC Session也是好东西。有一年讲SceneDelegate的Session我把Managing Your Apps Life Cycle那篇反复看了三遍。看完之后再去看笔试的分屏题脑子里会自动浮现那张生命周期状态图做选择的时候准确率会高很多。6.2 手写代码要练到肌肉记忆笔试不像面试没有“提示点”。你平时在Xcode里写代码编译器会帮你纠错但笔试时这些外部辅助全没了所以关键API的拼写、常见框架的结构体名都必须了然于胸。我的训练方法是每天晚上手写一遍UITableView的数据源和代理方法再手写一个用URLSession发起网络请求的完整流程包括URLRequest、URLSessionConfiguration的创建。这些不一定考但能让你在考试时把基础分拿稳。更进阶一点Codable的解析、Combine的基本框架也都值得手写练几遍。6.3 跨端知识不要盲目学但要懂原理如果目标岗位明确要求原生iOS跨端知识不用掌握到“能用uniapp独立开发”的程度但要懂原理。至少要知道跨端框架是怎么把JavaScript调用映射到原生模块的、JSBridge的通信机制是什么、为什么原生能力在跨端框架里需要“插件”来桥接。这些概念类知识笔试考的是“你有没有行业认知和技术视野”不是“你能不能上手干活”。我当时复习混合开发时看了一些关于WKWebView拦截URL通信方案的资料重点理解“URL Scheme调用原生能力”的流程。后来笔试加试里确实问了类似问题我回答起来算是有的放矢。6.4 热词与行业的结合点复盘这场笔试我强烈感受到热词和真实考点之间是强关联的。比如“iOS自动化”“iOS抓包”“iOS上架”这些词在笔试里转化成的是“如何用XCTest做UI测试”“Charles抓HTTPS包需要配置什么证书”“App Store审核被拒的常见原因有哪些”。这些转化后的题目没有一个可以靠死记硬背解决都得靠真实项目经验支撑。如果你还在准备阶段我建议你对照着热词列表把每一个词都尝试转化成“笔试/面试可能会怎么问”。这个转题的过程本身就是最好的备考训练。比如看到“iOS电池优化”去查Energy Log和Xcode的能耗调试面板看到“iOS设备模拟”去了解一下Simulator支持哪些系统能力看到“windows和ios共享文件夹”想想局域网文件传输场景下Bonjour和SMB协议的关系。这样一来你复习的内容就从“考点清单”变成了“知识网络”考场上遇到任何形式的题目都能接得住。我个人考完这场笔试之后最大的体会是能不能通过iOS开发岗笔试看的不是你会写几个控件而是你对整个iOS生态有没有成体系的理解。从基础的内存管理、Runloop、多线程到进阶的架构设计、跨端方案、工程化分发再到一线的排错能力和代码手感每一样都会在卷子上找到对应的位置。如果你能把“笔试”当成一次系统性的知识体检而不是临时抱佛脚的应试冲刺那你收获的不只是一张通行证还会真正发现自己技术体系里那些需要补上的薄弱环节。最后再分享一个小技巧笔试结束后不管感觉好不好一定要趁热把自己能回忆起来的题目和答案记下来。哪怕最后没过这份复盘笔记也会成为你下一次笔试前最高价值的复习材料。我自己就是这么做的这套整理习惯帮我省掉了大量重复刷题的时间也让我在下一次更重要的面试里多了一份“我确实认真准备过”的底气。
返回列表