最近不少读者在后台问我关于校招笔试的事尤其是iOS方向。正好手头有一套「哔哩哔哩2020校园招聘 iOS 方向笔试卷一」的题目记录当年我完整做过一遍也用这套题帮好几个学弟学妹做过模拟训练。今天不聊虚的直接把这套卷子拿出来逐类拆一遍说说每道题背后到底在考什么、出题人想看到什么样的答案、以及哪些地方最容易丢分。先说个总体印象这套卷子难度中等偏上不考偏题怪题但特别考验基础功是否扎实以及有没有真正写过工程代码。我见过不少基础不错的同学在OC底层问题上翻车也见过算法题写得飞快但iOS基础题大面积空白的情况。这类试卷的筛选逻辑很明确——先看你的知识面全不全再看你对核心机制的理解深不深最后用算法题拉开区分度。下面我按题型分布和考点类别把整套卷子做一个系统拆解。1. 这套笔试卷到底在考什么1.1 从题目分布看B站的出题风格整套卷子的题型分布大致是客观题单选多选约占三成主要覆盖Objective-C基础、内存管理、Runtime、多线程、网络、UI控件主观题和代码题约占四成重点考察iOS内存管理机制、消息传递机制、GCD并发编程剩余部分为算法题与开放设计题。这个配比在当年的互联网校招里属于比较典型的「重基础、轻框架」类型说明B站iOS团队更看重候选人对底层原理的理解而不是单纯背了多少API。如果横向对比其他大厂的笔试卷你会发现B站的题目有一个明显特点很少直接问「某个API怎么用」而是喜欢换一个场景化的问题。比如同样考KVO很多公司会问「KVO的原理是什么」B站可能会问「在一个对象被释放后它的KVO观察者还能否收到回调」。这种问法其实是在逼你把原理理解透而不是停留在「KVO能监听属性变化」这个层面。1.2 给求职者的定位判断从这套卷子的难度曲线来看如果你正在准备iOS校招需要先做一个自我定位你的基础能否支撑你在一小时内完成至少80%的客观题主观题能否做到不仅写对结论还能画出关键流程图算法题能否在纸上写出无语法错误的代码这三个问题基本决定了你能不能进入面试轮。我当年带过的一个学员算法很强LeetCode刷了三百多道但在这套卷子上栽了跟头——他连atomic和nonatomic的区别都答得模棱两可__weak和__block混为一谈。最后他复盘时跟我说以前总觉得iOS开发就是写UI、调接口笔试前突击一下底层就行结果发现底层不是突击能补上的。这也是我写这篇文章的初衷让你看清楚这套卷子背后要求的真实能力栈别再走弯路。2. 语言基础题每一道都是在问「你写没写过真代码」2.1 属性关键字与读写安全这套卷子里有一道题问strong、weak、copy、assign四者区别并且给出了几个典型使用场景让你选。单看题目并不难但选项里埋了不少坑。比如copy修饰的NSMutableArray属性赋值一个可变数组后再往原数组里添加元素属性对应的数组会发生什么这个问题问倒过不少人。正确答案是copy会让属性指向原数组的一个不可变拷贝后续对原可变数组的修改不会反映到属性上。如果你用strong修饰那属性和原数组指向同一块内存原数组一变属性跟着变。出题人用这个场景实际上是在考察你日常写代码时有没有思考过「修饰符到底修饰的是什么」。实际开发中NSString和NSArray这类有可变子类的类型属性一般用copy目的是防止外部传入可变对象后被意外修改而strong适用于普通对象weak适用于可能循环引用的代理、Block、UI控件assign则用于CGFloat、NSInteger等基本类型或者 unsafe_unretained 这种特殊场景。笔试时如果你只背结论不举例子很难拿满这道题的分数。2.2 Block的循环引用这道送命题Block几乎是所有iOS校招笔试的必考题B站这套卷子自然也不例外。题目给了几种写法问你哪个会造成循环引用。表面看是在考察self在Block内的持有关系实际上考的是你对Block捕获变量机制的理解。Block捕获外部变量时如果捕获的是对象类型会默认强引用在ARC环境下或需要手动 copy。当self持有BlockBlock内部又强引用了self就形成了 self → block → self 的闭环谁都释放不了。解决方法是__weak或者__block但在ARC下__block同样会产生强引用问题正确姿势是用__weak加__strong配合。我建议笔试遇到这类题不要只写「会循环引用」四个字可以补一句__weak让Block弱引用self但如果Block执行期间self可能被释放需要在Block开头用__strong持有一份确保执行期间对象存活。这能体现出你对内存管理的完整思考而不是背答案。实际开发中网络请求回调、定时器Block、通知Block都是循环引用的高发区值得专门整理一份排查清单。2.3 KVC/KVO 的实现基础与坑这套卷子对KVC/KVO的考察不只一道题。一道是「KVC设置值时会按什么顺序查找 key」一道是「KVO能否监听数组元素的变化」还有一道是「如何手动触发KVO」。KVC的查找顺序是先找setKey:或_setKey:找不到再看accessInstanceVariablesDirectly是否返回YES如果是则按_key、_isKey、key、isKey的顺序查找实例变量都找不到则调用setValue:forUndefinedKey:。这套机制出题人经常细化到「如果同时存在_key和key两个实例变量setValue:forKey:会修改哪一个」——答案是_key。KVO监听数组元素变化是另一个大坑直接对NSMutableArray调用addObject:是不会触发KVO通知的必须通过mutableArrayValueForKey:获取代理数组再操作或者手动调用willChangeValueForKey:和didChangeValueForKey:。B站的题就在这里设了个选项一个误写成addObject:能触发KVO另一个误写成对NSArray也能KVO。如果你没动手写过KVO监听数组这两个坑踩一个就丢分。手动触发KVO的答案就是调用willChangeValueForKey:和didChangeValueForKey:但要注意的是如果你重写了属性的 setter或者属性本身是计算属性手动触发的方式会略有不同。计算属性没有对应的实例变量KVO默认不会工作必须手动触发。这套卷子后续有一个「如何监听一个计算属性变化」的延伸题本质就在考这一点。3. 内存管理笔试重灾区回报率最高3.1 ARC是编译器做的事还是运行时做的事关于ARC这套卷子有一道多选题以下哪些是ARC所做的选项包括「在编译期插入 retain/release 调用」「在运行时维护 weak 表」「自动将dealloc中的[super dealloc]移除」「对__bridge转换自动管理内存」等。这道题非常经典。ARC本质是编译期行为编译器在合适位置自动插入retain、release、autorelease等引用计数管理代码。但weak变量的置nil操作是由运行时维护的weak表完成的dealloc中对__weak变量的清理也是运行时行为。__bridge转换则不改变所有权需要开发者自己保证对象生命周期这不算ARC自动管理的范畴。很多同学因为没搞透「ARC到底替你做了什么」遇到这种组合题就容易多选或漏选。我建议复习时把内存管理的职责画一张表编译器做什么、运行时做什么、开发者做什么。这样不仅笔试不会乱面试被追问「ARC下dealloc里应该做什么」也能接住——基本只需要释放非ObjC资源比如CFRelease、注销通知、关闭文件。3.2 循环引用完整排查链B站这套卷子的主观题里有一道给出几段代码找出循环引用并说明如何修改。代码里既有Block循环引用也有NSTimer循环引用还有delegate用strong修饰的典型错误。题目本身不难但评分标准要求写出「为什么这样修改」。NSTimer循环引用是个很经典的案例Timer持有target通常是selfself又持有Timer形成闭环。修改方案不只是把self改成weak因为scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:的target是强引用即使传入weakSelfTimer依然会强引用这个weakSelf指向的对象吗实际上Timer对target是强引用weakSelf传进去后Timer持有的是这个weak指针本身吗这里有个容易混淆的点如果你在Block里写[weakSelf doSomething]是从weakSelf读取对象再发消息对象此刻是存活的而NSTimer的target参数是直接强引用传入的对象如果传weakSelfweakSelf指向的对象可能已被释放Timer再向这个悬垂指针发消息就会崩溃。所以NSTimer的正解是在viewWillDisappear或dealloc里invalidate并且从iOS 10起用Block形式的scheduledTimerWithTimeInterval:repeats:block:配合__weak更加安全。我在实际排查循环引用时有一套固定流程先看dealloc有没有打印没打印说明对象没释放再用Instruments的Leaks模板跑一遍定位环的位置最后逐段代码审查引用关系。这套流程线上排障也很管用笔试时把思路写完整得分率会高很多。3.3 深拷贝浅拷贝经典拷问这套卷子的客观题里有一道关于copy和mutableCopy的题一个不可变字符串执行copy返回的是什么类型不可变数组执行mutableCopy返回的是什么数组内对象是否也被拷贝了答案分别是返回不可变字符串且与源对象是同一对象浅拷贝返回可变数组但数组内元素仍是原来的对象引用单层深拷贝。这个「单层深拷贝」的概念是这道题的核心。copy对不可变对象通常只是增加引用计数mutableCopy会生成新对象但不会递归拷贝内部元素。笔试时如果只是回答「copy是浅拷贝mutableCopy是深拷贝」是不完整的必须说清楚「深拷贝到什么程度」。B站这道题的坑在于选项里有一个说「数组的mutableCopy会对数组内每个元素都执行copy」这就是在混淆「容器拷贝」和「元素拷贝」。实际开发中如果你需要真正意义上的深拷贝要调用initWithArray:copyItems:这类API并要求内部元素遵守NSCopying协议。这个知识点面试官如果继续深挖通常还会问你对自定义对象如何实现深拷贝建议提前准备一个实现示例。4. Runtime笔试不考OC底层考的是组合应用4.1 消息发送、消息转发、动态方法解析B站这套卷子在Runtime部分出了好几道题其中最典型的是一个对象调用了一个不存在的方法系统在崩溃之前会按什么顺序做哪些事情。完整的顺序是先走objc_msgSend按isa指针查找方法列表找不到进入动态方法解析阶段调用resolveInstanceMethod:或resolveClassMethod:如果返回NO进入快速转发阶段调用forwardingTargetForSelector:如果这一步也返回nil进入完整转发阶段调用methodSignatureForSelector:获取方法签名然后调用forwardInvocation:如果这里也没处理最终才抛出unrecognized selector sent to instance异常。这道题的难点不在于背顺序而在于区分「动态方法解析」和「消息转发」的使用场景。动态方法解析适合在运行时用class_addMethod给类动态添加方法快速转发适合把消息转给另一个对象处理完整转发则适合对参数和返回值做包装处理。B站有一道选择题就是给两个场景让你选应该重写哪个方法。我见过有同学在这道题上答出「消息转发是给实例找备用的方法实现」这个层面就停了其实出题人希望看到的是你能写出完整的时序以及每种方案对应的应用场景。这里的经验之谈是复习Runtime时不要只看理论最好能写一个forwardInvocation:的demo体会一下消息转发在「多继承替代方案」「AOP埋点」「热修复」中的实际应用逻辑。4.2 Method Swizzling的正确姿势与坑这套卷子关于Method Swizzling的题目很有区分度给出一个在load方法里交换viewWillAppear:的代码片段问有哪些潜在问题。常见的坑有这么几个一是交换时要保证dispatch_once否则重复交换会导致方法实现互相调用形成死循环二是交换后要记得调用原实现否则会破坏原有功能三是不要在load方法里做复杂操作因为load是类加载时执行的此时环境尚未完全就绪四是交换操作要考虑父类子类的关系如果不判断是否为同一实现就去交换可能影响父类行为。更隐蔽的坑是viewWillAppear:在分类里定义的方法和原类方法交换时由于分类方法实际上被附加到了类的method_list尾部交换后的IMP指针可能不是你想的那一个。如果你对method_exchangeImplementations的实现原理不够清楚很容易写出「看起来对跑起来崩」的代码。我建议遇到Method Swizzling的题不要只答「可以hook方法」要说明白Swizzling基于Runtime的消息查找机制本质上是在方法列表里把IMP指针对调后续消息发送时查找到的IMP已经换了。这样答面试官才相信你不是只会复制粘贴网上的代码。4.3 关联对象与Category的本质B站这套卷子还有一道题问Category能否添加属性以及关联对象的原理是什么。答案是Category可以声明属性但不会自动生成实例变量和getter/setter需要开发者自己用objc_getAssociatedObject和objc_setAssociatedObject实现关联存储。这里有个连带知识点为什么Category不能直接添加实例变量因为实例变量是在类对象的内存布局中分配的Category是在运行时把方法附加到类上不参与类的布局所以无法添加实例变量。关联对象的本质不是加实例变量而是通过一个全局的AssociationManager以key → value的方式暂存数据再在对象释放时统一清理。这道题如果深入一层会问关联对象的释放时机和内存管理语义。objc_setAssociatedObject的policy参数等价于属性的内存修饰符用OBJC_ASSOCIATION_RETAIN_NONATOMIC会强引用关联对象用OBJC_ASSOCIATION_ASSIGN不会持有后者在对象被释放后访问会有悬垂指针风险。笔试时如果能提到这一层基本上就能拿满Runtime部分的分数。5. 多线程与并发死锁题永远有人写错5.1 GCD队列、任务、死锁GCD相关的题在这套卷子里占了不小比重首先是概念题串行队列、并发队列、同步任务、异步任务两两组合各有什么执行特点。这道题只要背过就能答对但接下来那道「以下哪段代码会产生死锁」才是重头戏。典型死锁场景在主队列执行dispatch_sync(dispatch_get_main_queue(), {})因为主队列是串行队列同步任务要求立即执行而当前线程已经占用主队列执行到这段代码新任务必须等待当前任务结束当前任务又等待新任务执行就形成了互相等待。同理在一个自定义串行队列里外层用dispatch_async内层对同一个串行队列执行dispatch_sync也会死锁。容易想错的是并发队列交叉同步的情况。B站这道题给了四种组合让选哪个不死锁不少同学选了「在并发队列里dispatch_sync到另一个并发队列」其实只有「不同队列之间同步派发」且队列本身不是串行阻塞关系时才不会死锁。这里考察的不只是死锁定义还包括你对队列层级关系的掌握。实际操作里任何dispatch_sync在当前队列内同步派发到同一个串行队列都要警惕。5.2 从一道经典死锁题看队列嵌套这套卷子有一道结合信号量的题目代码大致是主线程创建一个信号量初始为0然后dispatch_async到全局并发队列执行任务任务内部在某个条件满足时dispatch_semaphore_signal主线程再dispatch_semaphore_wait。问主线程会卡住吗。答案是要看signal和wait的时序。如果wait先执行主线程会阻塞直到信号量被signal如果signal在wait前已经执行信号量计数从0变成1wait会直接通过。单纯这样考太简单B站加了个条件如果把dispatch_async的目标队列改成主队列主线程在 wait 时会怎样。这时会造成死锁因为wait阻塞了主线程而signal需要主线程执行任务才能触发主线程被阻塞了就无法执行任务信号量永远不会被增加。这种嵌套队列信号量的组合题考查的是你对线程阻塞和执行流两个维度的同时理解。答题时建议画一张执行流向图先标出线程A在哪一步阻塞再标出解除阻塞需要哪个线程做什么。我记得这套卷子答题区后面还特意留了空白估计就是希望你画图说明。5.3 线程安全的正确打开方式除了死锁B站还有一道关于线程安全的题问下面几种方案哪些可以保证计数器自增的线程安全atomic修饰、OSSpinLock、NSLock、dispatch_semaphore、synchronized。这道题很容易错在atomic上因为atomic只能保证读写操作本身是原子的无法保证「读-改-写」复合操作的原子性。比如self.count 1用atomic修饰依然可能在多线程下出问题。这背后是原子性 vs 线程安全的经典区别也是面试官最爱追问的地方。实际开发中如果只是读取一个值atomic够用如果要做累加、判断再修改这类复合操作就要用锁或者信号量。我在项目里实测过OSSpinLock在iOS 10之后因为优先级翻转问题不再推荐使用os_unfair_lock是它的替代pthread_mutex性能也很稳。笔试时答「用dispatch_semaphore或synchronized都能保证线程安全」但要补一句「synchronized底层是递归锁性能略低高频率操作建议用信号量或os_unfair_lock」才能加分。多线程部分还有一个高频考点是并发队列如何安全地写数据。现在常用的方案是用dispatch_barrier_async在一个并发队列中做写操作读操作可以并发执行写操作执行时队列里其他任务会等待。这套卷子的延伸题里就问到了「barrier和dispatch_async有什么区别」这个点值得好好准备因为它既是高频考点也是实际项目里「多读单写」的经典实现。6. 网络与UI的实战题贴近真实开发的得分点6.1 HTTPS握手与中间人攻击网络题在B站这套卷子里也有不少。有一道简答题是简述HTTPS的握手流程以及用Charles抓包时为什么需要安装证书。题目看起来是送分题但想拿高分需要把TLS握手的关键步骤写完整客户端发起ClientHello服务端返回ServerHello和证书和公钥客户端验证证书合法性、生成预主密钥并用服务端公钥加密发送服务端用私钥解密得到对称密钥后续通信用对称加密。Charles抓包的本质是中间人代理Charles向客户端冒充服务端向服务端冒充客户端两边各建立一条TLS连接所以客户端需要信任Charles的根证书否则校验会失败。有些同学把HTTPS和HTTP的区别只答成「多了一层加密」这不够。你至少要能说出「混合加密」四个字非对称加密用于协商对称密钥对称加密用于实际数据加密。B站这道题后续还可能追问「如何防止中间人攻击」结合iOS开发就是SSL Pinning把服务端证书或公钥打包进App在URLSession的URLSession:didReceiveChallenge:回调里做二次校验防止证书被信任链上的任意CA签发。这套试卷里的网络题整体偏向「有没有真实用过抓包工具调试线上问题」而不是纯理论。我建议复习时多动手抓几次HTTPS包看看握手流程每一步的耗时这样答题时写的步骤都是基于实际观察的真实感强很多。6.2 从输入URL到渲染这一条链路还有一道题是「从输入一个URL到页面展示中间经历了哪些过程」这是前端和后端面试都常考的经典链路题B站把它放进了iOS卷考察的是你整体网络栈的掌握程度。我的建议是分几个阶段作答DNS解析递归查询/缓存、TCP三次握手若有TLS则叠加TLS握手、发送HTTP请求可能先走缓存或重定向、服务端处理并返回HTTP响应、客户端解析页面或接口数据、App拿到数据后刷新UI。如果能结合iOS细节写URLSession的复用、NSURLCache的缓存策略、ATS对HTTP的限制、以及WKNavigationDelegate在页面加载各阶段的回调分数会明显不同。这道题的本质是看你能不能把「网络协议」和「iOS端到端数据流」打通。单纯背七层模型没有用要把每一层对应到iOS开发里的具体组件传输层对应Network.framework的NWConnection会话层对应URLSession表示层对应JSON/Protobuf解析。把链路和组件一一对应是这类综合题拿高分的诀窍。6.3 UITableView/Masonry/Auto Layout 的隐藏考点UI部分B站考了几道题其中一道涉及UITableView的复用机制和高度计算另一道涉及Auto Layout的约束优先级和Masonry使用。UITableView的复用机制是iOS面试高频中的高频。B站这道题问到如果一个cell内部有异步加载的图片滚动时如何避免图片错乱。答案通常包括用cellForRowAtIndexPath时根据indexPath先取缓存图片没有则异步请求请求回来后在主线程刷新并且判断当前cell对应的indexPath是否和请求发起时一致或者用cell.tag记录indexPath。更进一步可以答「复用池的prepareForReuse里清空旧图片、取消旧任务」这样才完整。Auto Layout这道题我印象很深题目给了一个UILabel在Masonry布局中文本变长但约束不更新的场景问如何解决。答案是检查约束是否有优先级冲突、是否需要setNeedsUpdateConstraints和layoutIfNeeded、以及UILabel的preferredMaxLayoutWidth是否有设置。特别是多行UILabel在自动布局中经常需要明确preferredMaxLayoutWidth否则系统不知道文本换行的宽度上限导致高度算错。如果你用Masonry建议关键位置用setContentCompressionResistancePriority和setContentHuggingPriority告知系统哪个视图可以拉伸、哪个不能。UI部分准备起来比较费时间但性价比高因为这些都是实际开发天天遇到的问题。B站这套卷子的UI题不算难但选项里的干扰项都是真实踩坑才会懂的细节对没写过完整项目的同学不太友好。7. 算法与原题区分度都藏在边界条件里7.1 常见笔试题类型B站这套2020校招iOS笔试卷的算法部分题型围绕字符串、链表、数组、动态规划展开属于中等难度偏下至少一两道是LeetCode原题或改编。我印象里有一道是「反转字符串中的单词顺序」另一道是「给定一个数组将0移动到末尾且保持非0元素相对顺序」还有一道二叉树层序遍历变种。这些题目本身不吓人但B站的代码题默认你是在纸上或文本框里完成没有IDE提示和编译验证这就要求你写出的代码语法正确、边界处理完整。很多同学在LeetCode上能跑通到了笔试环境因为手写代码不熟练各种低级错误就来了。7.2 边界条件比算法本身更值钱拿「移动零」这道题举个例子。最常见的双指针解法是一个指针遍历数组遇到非0就往前放最后把剩下的位置补0。这题有个隐藏的陷阱是——如果数组里全是0或者全是非0你的写法会不会越界如果输入是空数组第一行为int j 0之后直接返回没问题但如果用「滑动窗口交换」的写法在数组长度为0时while (j n)的循环本身就不会执行所以边界处理一般OK。真正的坑在于统计非0个数后补0时如果用memset对整个数组补0可能会把前面已经放到正确位置的非0元素也清掉。这类边界问题的核心是「先想空数组和极端情况再写核心逻辑」。我在指导别人笔试时反复强调一个习惯写完代码后第一时间拿空数组、全0数组、全非0数组、单个元素数组四组用例在心里跑一遍比多刷一百道题都管用。算法题做对容易做全难但校招笔试的评分标准往往就看你的边界覆盖和代码规范。7.3 答题规范和思路展示B站这套卷子的算法题旁边明确写了「请写出解题思路和复杂度分析」所以答题时不能只贴代码还要用一两句话说清楚思路以及时间复杂度和空间复杂度。比如链表反转那道题可以写「思路迭代每次将当前节点的next指向前驱节点需要先用临时变量保存后继节点时间复杂度O(n)空间复杂度O(1)」。如果题目有多种解法最好把最优解写上。比如「反转字符串中的单词顺序」可以先整体反转再逐单词反转也可以按单词拆分再逆序拼接前者空间复杂度O(1)更优优先写这个。笔试改卷时会重点关注你是否意识到空间优化而不只是跑通。我个人的经验是校招笔试的算法题不追求你写出最优中的最优而是看你能否在有限时间内给出一个正确、清晰、可维护的解法。宁可写得朴素但绝对正确也不要为了炫技写一个容易出错的位运算版本。8. 从这套卷子延伸出的复习路线和面试心得8.1 按优先级排的复习顺序如果你问我按这套卷子透露出来的考点准备iOS校招笔试应该按什么顺序复习我会建议按下述优先级排列第一梯队内存管理ARC、循环引用、深拷贝浅拷贝、Objective-C语言基础属性关键字、Block、KVC/KVO。这部分题量大、高频、相对固定是笔试的基本盘。第二梯队Runtime消息转发、Method Swizzling、关联对象、多线程GCD、死锁、线程安全。这部分难度中等一旦掌握就是稳定的得分点。第三梯队网络HTTP/HTTPS、抓包原理、UITableView复用、Auto Layout。这部分需要结合项目实践理解理论加实操并重。第四梯队Swift语法和iOS新特性。虽然这套卷子是iOS方向但Swift比重也在逐年增加至少要能用Swift写算法题。8.2 答题时的几个实操技巧笔试答题时间有限我总结几个在这类「基础主观算法」混合卷上很实用的技巧。一是先做客观题控制每道题不超过两分钟不会的先标出来跳过不要在一道记忆模糊的题上死磕。二是主观题先画图再写字比如Runtime消息转发、死锁形成、HTTPS握手画张简单的流程图或时序图不仅帮自己理清思路也能让阅卷人觉得你理解透彻。三是算法题先写思路再写代码哪怕代码没写完有思路和复杂度分析也能拿一部分分。四是代码书写要规范变量命名单词完整函数拆成小块不要一个几十行的函数写到底阅卷人看着也舒服。还有一个很容易被忽略的技巧试卷里出现「请说明原因」「为什么这样修改」这类问法时一定要分点作答用「第一、第二、第三」列出理由。校招笔试的阅卷时间很紧张条理清晰的答案更容易拿到高分。8.3 我自己的看法最后说说我对这套2020年B站iOS校招笔试的整体评价。它的难度定位是「筛掉没写过工程代码的人留下基础扎实且可培养的人」。整张卷子几乎没有直接问「某个API参数是什么」这种死记硬背的问题而是通过场景化、组合化的方式考察你对iOS底层机制的理解。你在复习时如果没有亲手写过KVO监听数组、没有用Instruments排查过循环引用、没有用Charles抓过HTTPS包碰到这套卷子会明显感到吃力。但反过来想这也说明校招考察的不是你有多天才而是你有多愿意沉下心去把基础原理弄透。我遇到过不止一个候选人算法题刷得很溜但一问到atomic和nonatomic的底层区别就卡壳。iOS开发门槛不高但想要在笔试面试中脱颖而出靠的还是那些「看似基础、实则需要深挖」的知识点。如果你正在准备iOS校招我建议按我上面整理的复习路线把基础概念先串成知识网再针对每类题型做专项训练。尤其是内存管理和Runtime这两块一定要做到闭卷也能画出完整的流程图和代码示例。把功夫花在核心机制的理解上远远比你背一百道面经有效。