ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

京东2018秋招iOS笔试题复盘:从基础到实战的备考指南

京东2018秋招iOS笔试题复盘:从基础到实战的备考指南 京东2018秋招的iOS工程师笔试题我至今还留着电子版。那年求职季在牛客上刷到这套题做完的第一感觉是题目不算偏门但覆盖面非常扎实从Objective-C的内存管理、GCD多线程到链表反转、二叉树遍历再到HTTPS握手、离屏渲染几乎把iOS开发日常要面对的每一块都犁了一遍。哪怕放到今天这套题的考点依然是iOS面试的常青树很多技术细节甚至比某些培训机构出的题目更贴近真实开发场景。所以这篇文章不是单纯把题目和答案抄一遍而是带着“为什么这么出、应该怎么答、踩过什么坑”的角度来做一份完整复盘。它适合正在准备iOS面试的开发者也适合带新人的团队负责人用来做知识摸底。如果你已经工作两三年但没系统性复习过底层原理这套题同样值得花一个周末重新过一遍。1. 为什么2018年京东这套笔试题至今仍是iOS面试的标杆先说结论一份笔试题有没有参考价值不看它的新旧而看它考察的是“知识点”还是“知识树”。京东这套题属于后者大多数题目都是从一个基础概念出发向上能追问到系统框架向下能深挖到编译和内存布局这种出题方式天然具备可持续参考的价值。1.1 出题风格基础题与实战题的配比逻辑京东作为头部电商平台App面向的是千万级日活的用户场景iOS端的功能复杂度和性能压力都远高于普通应用。因此在笔试环节他们关注的不是你会不会用某个API而是你有没有能力在高压场景下保证代码的稳定和流畅。从这套题的结构看大概可以分成四类考察模块代表题型考核目的算法与数据结构链表反转、二叉树的层序遍历、字符串处理考察逻辑思维和手写代码的基本功OC语言与内存管理property属性修饰符、Block循环引用、autorelease原理考察是否理解iOS运行时底层机制多线程与并发GCD队列组合、死锁场景分析考察对并发编程中陷阱的敏感度系统框架与性能HTTPS握手、沙盒存储、离屏渲染考察对实际App开发链路是否熟悉这个分布说明了一个关键信息大厂笔试不指望你写出多么惊为天人的算法但要求你在基础问题上零失误。很多人挂在笔试题上不是不会做难题而是栽在“自以为会”的简单题上——比如属性关键字用错、Block变量捕获理解错误、队列组合判断失误。1.2 考点迭代哪些题在2024年依然高频出现可能有读者会问“2018年的题现在面试还考吗”我的答案是核心考点不仅还在考而且考察频率更高了。举个例子内存管理和循环引用从ARC普及那天起就是面试必问题。2018年考的是Block持有self放到现在依然考只是场景从普通的页面回调变成了Swift闭包、Combine订阅、Swift Concurrency的Task隔离。再比如离屏渲染2018年问cornerRadius为什么卡顿现在依然问只是问题包装成了“列表滑动掉帧怎么排查”。所以这套题真正值得保留的价值在于它帮你画出了iOS开发者必须掌握的知识地图。地图上的路标可能换了一些名字但路径是固定的。2. 算法与数据结构考题手撕代码的得分点与出错点算法题在iOS笔试里占比通常是三分之一左右这部分是拉开分数差距的关键。京东2018秋招这套题里的算法难度放在LeetCode上差不多是Easy到Medium的区间不会出Hard题但会在边界条件和复杂度上设坑。2.1 链表类题目反转链表与环形链表判断链表题是面试官最偏爱的基础数据结构题因为代码量短、考察点清晰能快速看出候选人写代码的熟练度。京东这套题里出现过典型的单链表反转。先看最常规的迭代解法struct ListNode* reverseList(struct ListNode* head) { struct ListNode *prev NULL; struct ListNode *curr head; while (curr ! NULL) { struct ListNode *next curr-next; curr-next prev; prev curr; curr next; } return prev; }这段代码的核心逻辑是三个指针prev指向当前节点的前一个节点curr指向当前节点next先暂存下一个节点防止修改next指针后链表断掉。很多人写这题时容易漏掉next的暂存或者忘记最后返回prev而不是head这两个都是扣分点。还有一类必考变体是判断链表是否有环。标准解法是快慢指针快指针每次走两步慢指针每次走一步如果链表有环两者必然相遇。bool hasCycle(struct ListNode *head) { if (head NULL || head-next NULL) { return false; } struct ListNode *slow head; struct ListNode *fast head-next; while (slow ! fast) { if (fast NULL || fast-next NULL) { return false; } slow slow-next; fast fast-next-next; } return true; }边界条件要特别注意空链表、只有一个节点、整个链表构成环的场景。快指针判断fast和fast-next是否为空时顺序不能反否则会访问空指针。我见过不少人在这道题上翻车不是算法思路不会而是写出来的代码一跑就崩溃。面试官看这类题目首先看的就是你对空指针的敬畏程度。2.2 二叉树与字符串处理递归遍历与O(n)解法二叉树题目在iOS笔试里出现频率也很高。京东这套题考过二叉树的层序遍历按层输出属于BFS的经典应用。用队列实现层序遍历的思路void levelOrder(struct TreeNode* root) { if (root NULL) return; struct TreeNode* queue[1000]; int head 0, tail 0; queue[tail] root; while (head tail) { int levelSize tail - head; for (int i 0; i levelSize; i) { struct TreeNode *node queue[head]; printf(%d , node-val); if (node-left) queue[tail] node-left; if (node-right) queue[tail] node-right; } printf(\n); } }要掌握两个核心点第一每轮循环开始前通过tail - head拿到当前层的节点数这样就能区分出每一层第二节点入队的顺序必须保证先左后右否则层序就乱了。字符串题目通常和哈希表、双指针结合。比如判断两个字符串是否是异位词、找出字符串中第一个只出现一次的字符。这类题的时间复杂度通常要求O(n)如果写成了O(n^2)在笔试系统的超大数据集中大概率会超时。2.3 复杂度分析为什么O(n^2)会直接挂笔试和面试口述有一个很大的区别笔试代码会真实运行。京东的笔试系统在后台准备了大批量测试用例如果解法复杂度不达标部分测试点会直接超时判负。举个例子判断一个字符串中有多少不重复的字符。最简单的做法是双重循环比对代码好写但数据量一上来就完了。正确的做法是用一个大小为128或256的数组做哈希计数一趟遍历解决。int countUniqueChars(char *s) { int count[256] {0}; for (int i 0; s[i] ! \0; i) { count[(unsigned char)s[i]]; } int unique 0; for (int i 0; i 256; i) { if (count[i] 0) unique; } return unique; }这提醒了一个备考方向做算法题不能只满足于“能跑通”要养成分析时间和空间复杂度的习惯。读题五秒钟先想清楚最优解能够达到什么复杂度再动手写。3. iOS核心语言题Objective-C内存管理、多线程与Runtime算法题决定你能不能过笔试iOS语言题决定你能不能拿高分。京东这套题在OC语言层面的考察相当细致很多问题不是背概念就能答好的需要真的调试过、踩过坑才能说清楚。3.1 内存管理ARC下还有哪些“送命题”很多人在简历里写“熟悉iOS内存管理”但真遇到追问就露馅。京东这套题里内存管理相关题目占了不少比重而且角度非常刁钻。第一道经典送命题ARC下什么时候使用weak什么时候使用strong标准答案是为了避免循环引用、对象持有者不确定时使用weak默认情况下对象由父视图或持有者强引用时属性使用strong。但更深一层要理解weak的实现机制——Runtime维护了一张weak表当对象dealloc时所有指向它的weak指针会被自动置为nil这一过程在ARC下是编译器插入代码结合runtime实现的。第二道送命题是Block的循环引用。代码如下self.viewController [[MyViewController alloc] init]; self.viewController.onTap ^{ [self doSomething]; };如果MyViewController的onTap被self强持有Block内部又捕获了self就会形成self - viewController - onTap - self的环。解决办法是__weak typeof(self) weakSelf self但这里还有第二个坑如果在Block内部有异步操作weakSelf可能已经在执行前被释放。所以很多大厂会继续追问什么时候需要用__strong修饰weakSelf来保证执行期间的存活。第三道是autoreleasepool的底层逻辑。问的是“以下代码有什么问题”for (NSInteger i 0; i 1000000; i) { NSString *str [NSString stringWithFormat:number-%ld, i]; // ... }如果不加autoreleasepool这百万个临时对象会积压在自动释放池里直到当前RunLoop循环结束才释放内存峰值会非常高。正确的做法是在循环体内套一层autoreleasepool。这个知识点在开发中可能遇不到但笔试就是用来筛掉“只写业务不思考底层”的人。3.2 多线程GCD的队列、死锁与线程安全多线程相关的题目京东考得比较深。最基本的题是辨识以下几种组合分别在哪个线程执行队列类型操作方式执行线程主队列同步死锁主队列异步主线程串行队列同步当前调用线程串行队列异步新开线程并发队列同步当前调用线程并发队列异步多个新开线程主队列同步执行任务造成死锁是笔试中的高频题。原因是主队列上的任务必须按顺序执行而同步提交任务要求等待该任务执行完毕后再继续但任务被追加到了队尾要等当前正在执行的代码先结束两者互相等待就死锁了。这道题不只要回答现象最好还能说出RunLoop的关联主队列的任务是通过RunLoop驱动的当主线程正在执行当前代码时RunLoop无法进入下一次source处理所以队尾的任务永远得不到执行机会。线程安全方面经典陷阱是“atomic是不是绝对线程安全的”。正确答案是atomic只保证属性赋值和获取的原子性不保证业务逻辑的线程安全。比如property (atomic, strong) NSMutableArray *array; // 线程A if (self.array.count 0) { id obj self.array[0]; } // 线程B [self.array removeAllObjects];即使array是atomicA线程先判断count大于0B线程接着清空数组A线程再取下标0就会越界崩溃。正确的做法是用锁或者把可变数组的操作收敛到串行队列里。我在实际开发中更习惯用后者因为GCD的代码可读性比各种锁要好得多。3.3 Runtime与消息机制为什么“黑魔法”必然被考京东这套笔试题里Runtime题目呈现出明显的层次感。初级只问isa指针是什么中级问消息转发流程高级直接给场景问动态添加方法。消息发送的完整流程是先通过isa找到类对象在类对象的method_list中查找方法找不到就沿superclass链往上找仍然找不到进入动态方法解析resolveInstanceMethod允许开发者用class_addMethod动态添加再不行进入消息转发forwardingTargetForSelector / methodSignatureForSelector / forwardInvocation。搞懂这套机制之后很多iOS的“黑魔法”原理就豁然开朗了。京东有一道关联对象的题目也很有代表性为什么Category中不能直接添加属性但可以通过objc_setAssociatedObject实现关联属性答案在于Category的结构体中只包含方法列表、协议列表和属性列表属性声明但不会把实例变量添加到类布局中而关联对象是存在一个全局HashMap里的绕过了类的内存布局。这个知识点做插件化开发和组件化架构的时候特别有用。4. 系统框架题网络、存储与UI渲染的实战倾向京东App作为电商类应用网络请求和页面流畅度是用户感知最强烈的两个维度。所以系统框架题的出题方向明显偏向“真实开发里会用到的知识点”而不是冷门API的默写。4.1 网络层HTTP与HTTPS握手过程与性能优化网络题的第一个必考点是HTTPS的握手流程。常规答案是客户端发送ClientHello服务端返回ServerHello和证书客户端验证证书然后双方交换密钥最后完成握手。但笔试如果要拿高分需要补充两个细节。第一个细节是证书验证的完整链路客户端拿到服务端证书后要验证证书是否由受信任的CA签发、证书是否过期、域名是否匹配。在iOS开发中如果使用了自签名证书需要配置ATS的例外或通过SecTrustEvaluate自定义校验。第二个细节是性能优化方向HTTPS握手比HTTP多了一次RTT所以大厂普遍采用HTTP/2或HTTP/3来优化连接效率或者通过Session Ticket来做会话恢复避免重复握手。京东这种业务体量客户端网络层一定有这套优化方案笔试问握手本质上是问你有没有全链路思维。还有一个容易被忽略的考点POST请求的body在HTTP/2里和HTTP/1.1有什么不同答案是HTTP/2引入了二进制帧header会做HPACK压缩body可以并行传输不会有HTTP/1.1的对头阻塞问题。4.2 数据持久化沙盒目录与存储方案选型iOS沙盒机制是系统框架题里的必考内容。题目通常会问Document、Library/Caches、Library/Preferences、tmp四个目录分别适合存放什么数据Document存放用户生成的重要数据会被iCloud备份Library/Caches缓存文件系统磁盘空间紧张时可能被清理不应存放不可再生的数据Library/Preferences应用的偏好设置NSUserDefaults存储在这个目录tmp临时文件App不运行时系统可能清理存储方案的选型逻辑我一般用一张表来总结存储方式适合场景注意点NSUserDefaults轻量配置、开关项不适合存大量数据每次写入会同步到plist文件读写图片、音视频、JSON等注意IO线程避免主线程直接读写大文件归档NSKeyedArchiver自定义对象序列化模型类需要实现NSCodingSQLite/FMDB数据量大、查询复杂需要管理数据库版本迁移Core Data对象图复杂、需要关系映射学习曲线陡调试成本高京东这种电商App搜索历史、购物车、订单缓存往往用SQLite更多因为数据量级和查询复杂度远超NSUserDefaults能够承载的范围。笔试如果遇到存储方案题最好能答出“先评估数据量、查询需求、是否需要加密、是否多端同步”这个决策过程而不是直接说“用FMDB”。4.3 UI渲染与性能离屏渲染、卡顿优化与列表流畅度UI渲染这块京东的题贴近真实场景考的是“列表滑动卡顿怎么定位和解决”。底层原理先理清楚iOS的视图渲染由Core Animation负责最终要提交给GPU进行合成。当图层属性不满足直接合成的条件时系统会先在离屏缓冲区渲染一份中间结果再合成到屏幕上这个过程就叫离屏渲染。最经典的离屏渲染触发场景是同时设置cornerRadius和masksToBounds为YES。此外还有设置shadow、mask、allowsGroupOpacity等。解决办法通常有几种使用UIBezierPath画圆角、用Core Graphics直接绘制带圆角的图片、或者把shadowPath指定为固定路径来避免动态计算。卡顿优化的排查思路也要有层次先用Instruments的Time Profiler定位CPU耗时方法再用Core Animation工具检查FPS和离屏渲染区域检查主线程是否做了耗时操作比如同步网络请求、大文件读写、复杂布局计算检查列表重用时是否频繁创建新视图或重新计算布局用预排版异步绘制、缓存高度、减少视图层级等手段优化笔试题里容易出现一个迷惑点是不是所有圆角都要避免答案是看数量级。一个两个View用系统圆角没问题但如果是在UITableViewCell里每个cell都有圆角图滚动的时候就会产生大量离屏渲染开销必须优化。5. 从这套笔试题反推备考清单我对iOS面试准备的经验题目复盘完我想把视角拉高一点聊一聊从这套题反推出来的备考方法。很多人准备面试就是刷LeetCode、背八股文但实际面试时发现题目看着眼熟就是答不透。根本原因在于没有建立知识框架只是零散地记忆答案。5.1 分模块建立知识树而不是碎片化刷题我比较推荐按照以下模块做系统复习编程语言Objective-C底层原理、Swift核心特性、内存管理、Runtime并发编程GCD、NSOperation、锁、线程安全设计系统框架UIKit、Foundation、网络层、存储层、Core Animation架构设计MVC/MVVM、组件化、模块化、依赖注入性能优化启动优化、卡顿优化、耗电优化、包体积优化算法与数据结构链表、树、字符串、动态规划、双指针每个模块准备2到3个可以深挖的“个人项目经历”面试时用这些实际案例来证明你理解了这个知识点。比如讲离屏渲染优化时不要只说概念而是说“我当时在XX项目中用预绘制解决了列表滑动的掉帧问题帧率从45提升到59”这样远比背概念有说服力。5.2 手写代码的现场组织技巧笔试写代码和平时在IDE里写代码差别很大没有自动补全、不能边写边编译所以需要养成一套固定的书写习惯。先写注释明确函数用途和入参出参再写核心逻辑最后补充边界条件判断。顺序很重要很多人一上来就写核心逻辑写到一半发现边界条件漏了又回去改容易把代码涂改得乱七八糟影响考官阅读。另一个技巧是即使你觉得思路已经清晰了也要先在草稿纸上画出关键示例的推演过程。比如链表反转拿1-2-3-4走一遍三指针的移动过程能提前发现隐蔽的指针遗漏错误。5.3 时间分配与心态笔试是长期功底的呈现笔试的时间分配通常建议是先花2分钟通读全部题目把会做的题标记出来按照“简单-中等-难”的顺序做题遇到卡了5分钟还没思路的题果断跳过不要恋战最后留10到15分钟检查代码和边界条件。心态上这套题给我最大的启示是不要指望临考突击。Runtime的原理、内存管理的底层实现、网络协议栈的细节这些东西没有一个能靠背题速成。真正扎实的掌握来自平时开发中多问一个“为什么”遇到崩溃和卡顿不急于上网搜答案而是自己用工具分析一轮。6. 写在最后用真题做自检而不是背真题如果把京东这套2018秋招笔试题当作题库来背收获会很有限。但如果把它当成一份“iOS开发者能力自检清单”价值就大了很多。我当时就是这么用的每道题先盖住答案自己做一遍凡是模糊的地方就回到源码或官方文档里查清楚然后在配套的Demo工程里跑一遍验证。一轮下来那些平时开发中模棱两可的概念比如autoreleasepool的具体释放时机、不同队列组合的线程表现、离屏渲染的触发条件都变得特别清晰。最后分享一个实际跳槽时才感受到的体会笔试是一面镜子它照出的不是你会背多少知识点而是你过去几年在iOS开发里到底有没有养成深挖原理的习惯。如果你现在答不上来某个题不用焦虑说明你发现了自己的盲区这正是面试准备里最有价值的时刻。把盲区一个个补上再去面任何一家大厂心里都有底。
返回列表