2018网易iOS实习生笔试真题解析:从Runtime到架构设计全考点梳理 1. 先看懂这份题网易实习生笔试的出题逻辑网易的实习生招聘笔试在当年校招圈里一直有个说法——基础扎实的人能拿到高分但真正拉开差距的往往是几道偏工程实践的题目。iOS开发实习生的试卷尤其典型它不是单纯问你“API怎么用”而是想看你在“懂原理”和“能落地”之间找到了什么样的平衡点。说白了一场笔试解决三个问题你有没有吃透iOS开发的核心知识体系有没有真实项目或Demo级别的实操经验以及遇到没见过的问题时能不能用已有知识推演出合理答案。到了2018年这个时间点iOS 11刚普及iPhone X的刘海屏适配刚刚成为新考点Swift和Objective-C混编也进入常态化所以试卷里既有老牌必考知识点也加入了大量跟上时代节奏的新内容。那一年网易iOS笔试的题型比例大概是这样分布的题型占比考察方向选择题单选多选30%-40%OC语言基础、内存管理、多线程、网络基础简答题20%-30%Runtime机制、Runloop、视图生命周期、崩溃排查思路编程题30%左右数据结构和算法偶尔有UI相关手写题开放题5%-10%架构设计、方案选型考察工程思维后面这几个板块我按当年题目风格结合iOS面试通用考点逐个拆给你看。如果你想参加的是更晚年份的招聘考察框架大差不差把新系统特性往上叠加就行。2. Objective-C语言细节选择题里的“送分题”和“送命题”2.1 对象模型一道题能挖出三层理解选择题中“以下关于atomic和nonatomic的描述正确的是”这类题目几乎年年出现。很多人只背了结论atomic线程安全nonatomic非线程安全然后果断选完走人。但实际上后面的简答题往往紧接着一句“请说明atomic为什么不能保证对象操作绝对安全”。这里你得把人家的内部实现说清楚。atomic的本质是给属性生成带加锁的getter/setter方法底层用的是spinlock锁保证的是“读写这个属性本身”不被打断。比如两个线程同时给一个atomic的NSMutableArray赋值不会出现悬空指针但如果两个线程同时读写这个数组里面的元素或者先取出来再修改那atomic就管不着了。这就是为什么我们实际开发中很少用atomic它性能有损耗又不能真正保证多线程下的数据安全真实工程里更常见的是nonatomic加上手动加锁或串行队列。再往下深挖一层面试官想听的是为什么nonatomic更快因为属性的getter/setter直接就是内存存取指令没有加锁开销。你回头对比Swift里的atomic概念会发现当年的OC在这个设计上其实相当朴素。2.2 内存管理引用计数背后的三条铁律2018年那会儿虽然ARC已经普及好几年了但笔试依然喜欢考MCR时期的概念为的就是考察你是不是只停留在“用”的层面。有一道经典选择题NSString *str [[NSString alloc] initWithFormat:hello]; [str retain]; [str release]; [str release];问最后str的引用计数是多少或者问有没有崩溃。这类题在ARC时代看似没意义但你要是能讲清楚之前提到的那三条铁律就完全不会被绕晕alloc/new/copy/mutableCopy 开头的持有对象引用计数1retain使计数1release使计数-1当计数归零时系统执行dealloc顺着这个逻辑上面那段代码走一遍就明白了alloc后是1retain后是2两次release后归零对象被销毁后面的访问就是野指针操作。本质上ARC做的事情就是编译器在合适的位置自动帮我们插入了retain和release规则一点没变。如果能把这个逻辑线讲通一些涉及__strong、__weak、__unsafe_unretained的选择题也就成了送分题。__weak修饰的对象在释放后会自动置nil而unsafe_unretained不会它会变成野指针。笔试里有道典型题就是问这两种修饰符的区别很多人选错是因为只记住了“weak会自动nil”忽略了unsafe_unretained在iOS 4时代才被更安全的weak替代这段历史。2.3 笔试里反复出现的循环引用场景循环引用这块选择题、简答题都爱考而且特别贴近项目实战。最常见的三个版本第一个是delegate代理属性必须用weak或assign。如果你用strong持有delegate同时delegate又强持有当前对象就形成了循环。很多新手写自定义控件时把delegate声明成了strong页面退出后两个对象谁都释放不掉。第二个是block。Block对截获的变量默认是强引用所以你在block里面直接使用selfself又持有这个block就会循环。解法是用__weak typeof(self) weakSelf self; 进去之后再判断一下weakSelf是否存在。这里有个容易被忽略的细节如果是异步延迟执行的block你用了weakSelf等block真正执行时对象可能已经释放了那就要考虑在block内部用__strong再持有一下防止执行到一半对象被回收。第三个是NSTimer。Timer会对target强引用如果你把Timer作为self的属性timer又持有self同样循环。解决思路在iOS 10之后有一个系统级APIscheduledTimerWithTimeInterval:repeats:block:用block方式可以避免对target的强引用。2018年笔试的简答题里已经开始出现这个知识点了系统API更新是紧跟面试风向的。我当时给团队新人培训的时候总喜欢用一句话总结循环引用问题只要记住“谁强引用了我我又强引用了谁”几乎所有场景都能自己推出来。3. Runtime、Runloop与多线程笔试拉开分数的三座山3.1 Runtime动态性消息发送与Method SwizzlingRuntime在网易笔试里从来不是可选题而是必考项。它考察的形式很直接请简述Objective-C的消息传递机制或者问“Category能否添加属性为什么”。如果你只是背了面试题答案看到变体提问就容易翻车。消息传递机制的核心是objc_msgSend当你写[self doSomething]编译后并不直接调用函数而是给对象发送了一条消息。消息的查找过程是先找类对象的方法缓存再找方法列表找不到就沿着继承链往上找最后都找不到会走消息转发流程动态方法解析、备用接收者、完整消息转发三步。为什么这玩意儿重要因为它是理解Method Swizzling、KVO底层实现、关联对象这一切的基础。比如KVO它的底层是在运行时动态生成一个子类重写被观察属性的setter方法在setter里调用willChangeValueForKey和didChangeValueForKey。你知道了这个原理再看网上那些“KVO为什么在子线程触发有问题”的讨论就不会一头雾水。Method Swizzling也是笔试和面试的高频词。考察到它的时候比较深入的问题会是Swizzling之后还能调用原来的实现吗答案是能因为交换之后原方法名对应的是新实现你想调用原来的逻辑就得先持有旧的IMP。很多人在工程里实现埋点、日志、防崩溃时用Swizzling结果写出来的代码层层覆盖最后一个Swizzle盖掉了前一个这种来自真实开发的案例笔试常拿来当开放性题目。3.2 Runloop决定你“会不会做体验优化”的分水岭Runloop在选择题里经常和autoreleasepool搭配出现问你一个autorelease对象什么时候释放。这个答案跟Runloop的运行机制紧密相关主线程的Runloop在每次事件循环结束前会销毁当前自动释放池创建一个新的。所以如果你在一个循环体里面大量创建临时对象它们的释放时机不是“每次循环结束”而是“整个Runloop循环结束”这就会导致内存峰值。更常见的简答题是如何利用Runloop做卡顿监控思路就是用子线程监听主线程Runloop的状态切换从kCFRunLoopBeforeSources到kCFRunLoopBeforeWaiting之间如果耗时过长就说明主线程卡了记录下来调用栈就能定位是哪个方法阻塞了UI。还有一道很经典的题NSTimer注册到Runloop的什么模式下默认是NSDefaultRunLoopMode但用户拖拽ScrollView时Runloop切换到UITrackingRunLoopModeTimer就会暂停。解决方案有两个要么把Timer加到一个特有的common mode下要么用dispatch_source定时器替代。这种题考察的就是你有没有真正处理过类似问题只背概念的人写到这里就露馅了。3.3 GCD、NSOperation与线程安全多线程的考察点集中在GCD和NSOperation的区别、死锁问题、线程安全的实现方式。GCD的经典死锁题是这样的dispatch_queue_t queue dispatch_get_main_queue(); dispatch_sync(queue, ^{ NSLog(hello); });这段代码会发生什么主线程上同步派发一个任务到主队列任务永远等不到执行造成死锁。原因在于dispatch_sync会阻塞当前线程而任务又在当前线程的队列里排队形成了互相等待。NSOperation相比GCD的优势在于可以取消、可以设置依赖关系、可以设置最大并发数。这些字面差别只是基础题真正的延伸题是让你设计一个图片下载器用GCD设计会怎么做用NSOperation呢如果你是面试官你会怎么判断这份答案的水平关键就在于有没有考虑到并发下载导致的资源竞争、内存峰值控制和取消逻辑。很多人能写个大概但忽略了一个细节内存缓存和磁盘缓存的位置还有回调是不是在主线程更新UI。线程安全方面2018年还很流行考synchronized、NSLock、dispatch_semaphore的性能对比现在看起来其实核心思想没有变同步方式的粒度、等待策略、性能开销三者之间的平衡。4. 网络与本地存储从笔试看真实项目素养4.1 TCP与HTTP三道绕不开的基础题网络层面的考点在iOS方向的试卷里通常会以选择题形式出现但偶尔也以简答题形式考TCP三次握手的过程以及为什么是三次而不是两次HTTPS的加密流程对称加密和非对称加密的分工HTTP状态码的代表含义有一道网易风格比较明显的题是客户端把一张图片上传到服务器中途断网了如何保证上传成功这题考察的是HTTP的幂等性、断点续传和失败重试机制。合格答案会提到把图片数据分块每一块带着唯一的标识和偏移量服务端记录已接收的块客户端断线重连后从服务端查进度继续传。很多人只记得“要重试”但忘了“重试之前先查询服务端状态”这就是方案设计上的差距。4.2 断点续传和图片缓存方案设计这几乎是大厂笔试必出的设计题模板。题目通常这样问请设计一个图片加载库支持内存缓存、磁盘缓存和异步加载要求高性能且不阻塞主线程。标准答案的结构应该是这样的先去内存缓存NSCache查命中就直接回调没有就去磁盘缓存查有的话返回并缓存到内存磁盘也没有发起网络请求拿到图片后先写磁盘再写内存然后回调展示。这中间还涉及占位图怎么处理、失败要不要重试、并发请求怎么避免重复下载。一个加分的细节网络请求回来时要用URL作为key去查一下是否还是当前ImageView需要的图片。这是因为UITableViewCell复用可能出现一张旧图覆盖到新内容上的问题。这个细节写上去整个答案的工程感一下就出来了。本地持久化方面笔试喜欢考iOS提供了几种数据持久化方式以及各种方式的适用场景。NSUserDefaults适合小数据plist适合简单配置归档适合自定义对象SQLite适合结构化数据Core Data适合对象图管理复杂的场景。2018年那会儿还流行用FMDB封装SQLite现在则是WCDB、GRDB之类的库更多但原理一直没变。4.3 从一道“网络差”场景题看回答套路网易2018年的开放性题目里有一道让我印象很深用户反馈App在网络很差的情况下页面一直转圈作为iOS开发你会怎么排查和优化这个题目考察的不是某一个知识点而是从上到下的链路思考能力。我当时整理的思考路径是这样的也在面试复盘时用过很多次先区分是DNS解析慢还是TCP建连慢还是请求响应慢用Charles抓包或Network分析工具看时间线如果是DNS慢考虑HTTPDNS方案如果是响应慢检查接口有没有做缓存策略是否需要展示缓存数据客户端层面超时时间有没有合理设置请求失败有没有自动重试和指数退避UI层面加载失败页面是否有重试按钮弱网环境下图片是否可以先加载占位这样回答下来面试官能明显看出你不是只停留在“用AFNetworking请求数据”的层面。5. 笔试中的编程题怎么在有限时间内写出能跑通的代码5.1 高频考点与典型题目分析网易的笔试编程题一般有两种形式一种是在线OJ给出题目直接写另一种是手写代码写在纸上或电子板里。不管哪种形式高频考点都集中在链表、字符串、二叉树、动态规划这几个模块。链表题是我建议优先拿分的。典型题目包括反转链表、判断链表是否有环、合并两个有序链表、找倒数第K个节点。其中反转链表几乎是必背题目迭代和递归两种写法都要熟练。字符串题里最长公共前缀、字符串去重、判断回文串是高频题。二叉树方面前中后序遍历、层序遍历、二叉树的最大深度这些基础题要用递归和非递归两种方式都能写。动态规划那一类像“爬楼梯”“最大子序和”这种入门级题目也是笔试常客。5.2 手写代码的三个救命原则以我参加过校招笔试和后来帮部门出题的经验编程题想要拿分不是靠刷了多少题而是靠三个习惯第一先写思路再写代码。哪怕你最后代码没写完思路也能拿一半分。很多在线笔试系统会保留你的编辑记录阅卷人能看到你从一片空白到逐步形成方案的思考过程。第二边界条件优先处理。链表的空节点、字符串的空字符串、数组越界先把这些if判断写好代码的稳定性显著提升。第三选自己最熟的API。比如遍历数组你用for-in还是for i用enumerateObjectsUsingBlock还是快速遍历一定要选自己能保证一次写对的不要为了炫技写不常用的方法。5.3 一道现场编码题的完整拆解拿一道当年考生反馈比较多的题举例实现一个方法判断一个字符串括号是否匹配括号包含()、[]、{}三种。这个题的标准解法是用栈遇到左括号入栈遇到右括号时检查栈顶是不是对应的左括号是则出栈否则直接返回不匹配。最后栈为空才说明全部匹配。复杂度也很清晰时间复杂度O(n)空间复杂度O(n)。但真正要拿高分还得补充几个细节例如字符串里有空格或其他字符怎么办是要忽略还是直接判不匹配括号嵌套非法的情况怎么处理你把这些边界条件在代码注释里写清楚比单纯写一个能跑的代码更让阅卷人认可。类似这样的一道题在笔试里通常占20到30分如果还能坚持用规范命名、缩进清晰、加上适当注释基本上编程题的分数就比较稳了。6. 架构设计、新版本适配与上架发布容易拿分也容易丢分的隐藏考点6.1 架构题MVC、MVVM与组件化的取舍网易的笔试开放性题目里喜欢出“请设计一个IM聊天页面的架构”或者“谈谈你对MVVM的理解以及相比MVC的优势”。这类题目看起来没有标准答案但本质上在考察你有没有真正理解分层思想。我的建议是回答的时候先讲清前提不同的业务规模和数据流复杂度决定了选哪种架构。传统MVC在ViewController变得臃肿后难以维护MVVM把视图状态和业务逻辑做了绑定比较适合页面交互复杂的场景。组件化能解决多人协作下的模块依赖问题但代价是维护成本和管理成本提升。答题时如果能结合自己的项目经验说一点具体痛点比如“我上一个项目把UITableView的DataSource直接写进了ViewController后来加需求的时候发现改动量巨大于是抽了ViewModel”会明显比空洞的理论描述更有说服力。6.2 iOS 11适配、iPhone X安全区与64位问题2018年的笔试特别强调新系统适配。iOS 11带来的变化包括导航栏的LargeTitle、安全区域SafeArea、以及更严格的ATSApp Transport Security限制。当时有一道选择题是问iPhone X的底部Home Indicator区域应该如何适配答案就是使用safeAreaInsets和safeAreaLayoutGuide来约束布局而不是硬编码一个固定的44像素。64位适配也是一道经典题你从32位迁移到64位哪些类型长度发生变化哪些API已经废弃。这类题在大厂笔试中出现过多次核心是让考生意识到系统版本每更新一代iOS开发者的知识库就得同步刷新。6.3 证书、描述文件与自动化发布流程从热搜词里可以看到很多人关心的还有“开发者证书更新”“iOS上架流程”这些工程化问题。这部分虽然不是网易笔试的重头戏但在简答题中有时候会以“请描述一下App从开发到上架需要哪些步骤”出现。完整的流程应该覆盖这几点注册Apple开发者账号、创建App ID、生成开发证书和发布证书、配置开发/发布描述文件、在Xcode中进行Code Signing配置、构建Archive、上传到App Store Connect、填写审核信息等待审核。很多人在这里失分是因为只说了“配置证书”四个大字没有细化到Provisioning Profile包含了哪些信息。其实描述文件本质上是一个包含“证书设备列表App ID权限”的打包文件它规定了哪些设备可以装这个App。把这个逻辑说清楚阅卷人能一眼看出你确实发布过应用而不是只背了流程。另外自动化发布也是一个加分项用fastlane来自动化构建、签名、上传、截图配合CI平台实现提交代码后自动打包。如果你实习期就接触过这一套流程笔试里提到它是很不错的差异化加分点。7. 面试官视角之外的几条真实经验7.1 时间分配和做题顺序我当年参加笔试时犯过一个错误在选择题上犹豫太久结果最后一道编程题只剩15分钟。后来我自己也有了出题和阅卷视角发现时间分配真的很重要。比较合理的策略是先把所有题目快速扫一遍标记出自己100%会做的题然后从编程题开始再做简答题最后回来处理选择题。原因很简单编程题分值高而且需要完整的思考时间选择题即使时间不够也还有蒙对的概率。具体到时间分配上如果整场笔试是90分钟建议编程题预留40分钟左右简答题30分钟选择题压到20分钟以内。千万不要在“某道题有两个选项拿不准”上死磕你先跳过去回头再看可能会因为后面题目的提示而灵光一闪。7.2 简历和技术栈之外大厂更在意什么经历过多场实习生招聘后我发现网易这类大厂在“基础扎实”和“学习潜力”之间往往更看重后者。笔试成绩只是门槛真正决定能不能拿到offer的很多时候是你简历上有没有体现“独立学习、动手实践、遇到问题主动解决”的痕迹。一个比较管用的做法是在简历里放一个不是“照着教程敲出来”的小项目哪怕只是你自己给某个开源库写过一个组件或者给校园App做过一个小功能。关键是能讲清楚三件事你解决了什么问题你怎么解决过程里踩了什么坑。经常有学生问我要不要把网上那些很火的“仿某某App”项目写在简历里。我的建议是可以写但千万要诚实。因为面试官一定会往深了问你“你这个仿写项目里网络层你是怎么设计的图片缓存是自研还是用了SDWebImage有没有做过内存优化”一戳就破的简历不如不写。7.3 一个问题一套模板怎么把开放题答出深度最后分享一个我自己整理开放题答案时常用的模板很简单就四步明确目标先复述题目里到底要解决什么问题圈定范围 分析现状当前方案的缺陷或题设中的约束条件是什么 给出方案分点说清楚做什么、怎么做、为什么这么做 评估代价说清楚方案的取舍复杂度、维护成本、风险是什么这个模板用在“设计一个IM消息列表”“优化App启动速度”“解决TableView卡顿”这类题上都非常好用。启动速度优化为例三步下来就是明确目标减少启动阶段主线程耗时提升首屏展示速度 分析现状启动过程中执行了同步网络请求、大量文件IO、动态库加载 给出方案异步化、懒加载、预编译、减少load方法 评估代价异步后状态一致性变复杂需要用状态机管理这样一来开放题就变成了结构清晰的小论文阅卷人哪怕不细看也能第一眼感受到你的思路是完整的。7.4 笔试结束之后还有更重要的事笔试不是终点是起点。如果你通过了笔试进入面试你会发现面试官会拿着你笔试里的答案一个个把你问透。那时候你会发现真正能拉分的不是“背了多少题”而是你在准备过程中有没有把每个知识点连成一张网。我见过太多人疯狂刷题但问到“为什么HTTP要用TCP而不是UDP”“为什么runloop要设计成事件循环”就哑火了。这类问题其实不需要背只要平时写代码时多问几层“为什么”答案就浮在水面上了。如果你还在备战我这里有一个可落地的建议拿一个月时间按照知识点模块快速过一遍基础题然后给自己定一个“每周写一个能跑的小Demo”的目标再翻翻近两三年的系统更新日志写清楚每一项更新对现有代码的影响。按这个节奏走下来不管考哪家大厂你都不会慌。