尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

爱奇艺2020校招iOS笔试解析:内存管理、多线程与架构设计核心考点

爱奇艺2020校招iOS笔试解析:内存管理、多线程与架构设计核心考点 爱奇艺2020校招iOS方向笔试题第二场这份卷子我前前后后刷了三遍也拿给几个准备校招的学弟学妹做过模拟。说实话它比很多纯背诵型笔试题要扎实考的不只是iOS语法而是你平时写代码时有没有认真想过“为什么”。如果你是准备iOS开发岗校招或者刚转iOS想摸底自己基础的人这套题值得拿来当一面镜子。下面我就结合这份试卷涉及的核心考点把iOS方向笔试里最容易踩的坑、最应该提前准备的点全部拆开讲一遍。1. 先从试卷结构看校招的筛选逻辑1.1 爱奇艺第二场考察的基本盘先聊点实在的校招笔试不是社招面试面试官大概率不会对你的项目经历穷追猛打更多是用一套题快速筛出基础扎实、思维清楚的人。爱奇艺2020校招iOS方向笔试题第二场整体覆盖了Objective-C语言特性、内存管理、RunLoop、多线程、网络、架构设计、算法这几个大块。从题型上看往往包含单选、多选、填空、简答和编程题最后再带一道和业务场景相关的设计题时间紧张是普遍感受。这套题最值得琢磨的地方在于它把“iOS开发”和“视频类业务”绑在了一起。比如播放页内存优化、视频缓存策略、Feed流卡顿排查这些不是死记硬背能答好的。你不仅要会写tableView还得知道cell复用背后的内存机制不仅会调SDWebImage还得能说明白图片解压为什么会占内存。所以刷这套题时我给自己定的目标不是“把答案背下来”而是把每个考点都落回“线上如果出了这个问题我该怎么定位”。1.2 题型分布与时间分配我整理了一份参考时间分配适合90分钟左右的笔试场景大家可以根据实际卷面调整考察模块常见题型建议用时iOS语言基础与Runtime选择、填空20分钟内存管理与RunLoop选择、简答15分钟多线程与线程安全选择、场景分析15分钟网络与系统框架选择、简答15分钟架构设计与业务场景简答、设计题15分钟算法编程手写代码10分钟以上第二场试卷给人的感觉是“基础题不难但坑多”。比如多选里考atomic到底保证了什么很多人只记得“线程安全”四个字却说不清它保证的是setter/getter的原子性而不是对象内部属性的线程安全。这种题一旦结合代码场景特别容易丢分。所以我建议拿到卷子后先扫一遍所有题目把会做的选择题快速锁定把编程题留出整块时间不要在个别概念题上死磕。2. 基础题最容易被扣分的 iOS 内存与 Runtime 考点2.1 weak 指针的实现原理这份试卷里weak相关题目几乎年年有。最经典的考法是给一段代码NSObject *obj [[NSObject alloc] init]; __weak NSObject *weakObj obj; obj nil; NSLog(%, weakObj);很多人想都不想直接回答“打印出obj”实际上weakObj在obj被置nil后已经变成了nil所以打印结果是(null)。这里背后考察的是weak表的结构Runtime维护了一张全局的weak_table_t以对象地址为key保存所有指向该对象的weak指针地址。当对象释放时Runtime会遍历这张表把所有weak指针置为nil防止野指针访问。笔试里还会进一步追问“weak和assign的区别”。我一般建议从两个方面回答第一assign修饰对象类型不会在释放后自动置nil很容易产生野指针第二weak只能用于对象类型并且会参与ARC的引用计数管理而assign一般用于基本数据类型。答到这里基本能拿满这个考点的大部分分。2.2 autoreleasepool 与 MRC 遗留题爱奇艺的笔试题里有不少关于autoreleasepool的题目形式上通常是“以下代码什么时候释放”或者“ARC下还需要手动添加autoreleasepool吗”。很多人只记得在for循环里加autoreleasepool但说不清原理。autoreleasepool在ARC下仍然存在它的本质是一个延迟释放机制对象收到autorelease消息后被放入当前自动释放池当池子销毁时池内所有对象统一执行release。在主线程RunLoop的每次循环末尾系统会自动创建和销毁autoreleasepool。但在大量创建临时对象的场景里比如循环读图、处理大数组如果依赖系统默认池内存峰值会很高手动加一个局部autoreleasepool就能让临时对象及时释放。这里有一个实操心得我在真机调试时遇到过内存持续上涨定位半天才发现是for循环里创建了大量UIImage并转成NSData临时对象一直堆积到RunLoop循环结束才释放。后来在循环体里手动加了一层autoreleasepool内存曲线立刻稳定下来。笔试如果考到类似场景一定要往“自动释放池的销毁时机”和“内存峰值”这两个方向答。2.3 Category 与 Extension 的区别和作用Category是iOS面试里最常见的概念题但第二场笔试的考法会更细比如“Category能否添加成员变量”答案是不能直接添加但可以通过关联对象objc_setAssociatedObject实现。还会问“Category中的方法和主类方法重名时哪个优先”很多人背过结论但不知道原因。实际上分类方法会被放到类的方法列表前部运行时查找方法时先找到分类方法因此分类方法会“覆盖”主类同名方法。多个分类的同名方法则由编译顺序决定后编译的分类优先。底层是methodizeClass时把category的方法列表通过attachCategories插入到类的方法列表前面。笔试如果让你写出结果直接答“分类方法生效主类方法被覆盖”是没问题的但简答题最好把“方法列表的前插机制”说清楚这样评分会高不少。Extension就不一样它编译期就会合并到主类里可以添加成员变量和属性但不能是独立的文件一般用于隐藏私有接口。把两者对比着答很容易让面试官觉得你基础扎实。3. 多线程与并发死锁、线程安全、性能优化3.1 GCD 队列与死锁的必考题多线程在iOS笔试里占比不小最核心的考点是GCD队列和死锁。典型题目是“在主队列同步执行任务会发生什么”答案是死锁。原因很简单主队列是串行队列dispatch_sync提交的block要等在它前面的任务执行完才执行但这个block又被提交到了主队列末尾前面任务包括当前正在执行的代码所以形成互相等待。我还见过一道变形题“自定义串行队列里执行dispatch_sync到自己队列会死锁吗”答案同样会死锁因为dispatch_sync需要等待block执行完才返回而串行队列当前正在执行任务无法处理新任务。如果是并发队列由于可以同时执行多个任务dispatch_sync到自身一般不会死锁但依然不推荐这么写因为容易产生语义混乱。3.2 如何安全地实现“读多写少”有一道让我印象很深的场景题“视频App的播放进度和缓存状态要被多个线程读取和更新如何设计”这题不能只回答synchronized或者NSLock因为加锁简单但读多写少场景下性能会很差。更好的方案是用多读单写GCD里的dispatch_barrier_async配合并发队列就能实现读操作直接提交到并发队列写操作通过dispatch_barrier_async提交这样保证写操作执行时队列里没有其他任务读操作之间可以并行性能和安全性都兼顾了。我个人的实现习惯是封装一个读写工具类内部持有并发队列外部只暴露读方法、写方法这样调用方不需要关心线程安全细节也方便后续替换实现。如果笔试问到“atomic和nonatomic怎么选”要记得点出atomic只保证属性的读写原子性不保证业务逻辑的线程安全。比如一个数组属性用atomic修饰多个线程同时修改数组内部元素依然可能崩溃。对于大多数UI属性用nonatomic就够了搭配不可变模型和合理的数据隔离性能更好。3.3 视频类App的多线程实践爱奇艺这种视频类产品多线程题目很容易结合播放器场景。比如“视频首帧加载慢怎么优化”除了网络层面还可以把视频解封装、解码初始化放到后台线程不能让主线程阻塞。iOS开发里AVPlayer的创建和准备播放本身就建议在后台线程完成因为AVURLAsset的初始化会涉及磁盘和网络IO放在主线程必然卡顿。另一个常见考点是“imageWithContentsOfFile和imageNamed的区别”。imageNamed会缓存图片适合小图、重复使用的图大图如果用imageNamed内存可能持续被占用更合理的方式是imageWithContentsOfFile加载后手动解码再配合后台线程处理。笔试问到这个本质是考你是不是清楚图片解码发生在主线程。事实上UIImage的imageNamed:在首次显示时可能需要解码如果不做处理就会掉帧。我一般会用UIGraphicsImageRenderer预解码或者用第三方库的解码机制这在列表滚动场景里很关键。4. 网络和系统框架从代码题到场景题4.1 HTTPS 与中间人攻击网络方向的题里HTTPS握手流程是必背项。常见问法是“HTTPS为什么安全”要分几点答第一通过证书验证服务器身份第二通过非对称加密协商对称密钥第三后续通信使用对称加密。笔试如果要求画流程画清楚三次握手后的证书校验和密钥协商过程就行。爱奇艺的第二场还容易考察抓包相关的问题因为做视频App必然要排查网络问题。比如“Charles抓不到HTTPS包怎么办”首先要装证书并信任证书然后在iOS上开启“允许HTTP”或设置代理。这里有个容易忽略的点iOS 10之后App默认不允许明文HTTP请求如果后端接口不是HTTPS需要在Info.plist里配置NSAppTransportSecurity。笔试阶段一般不要求你现场配置但面试官可能会问ATS的具体字段最好能说出NSAllowsArbitraryLoads和NSExceptionDomains的作用。4.2 大图加载与内存峰值爱奇艺的笔试题里有一类题是“给定一张分辨率为4000x3000的图片如何显示到100x100的UIImageView上”直接这么干内存会爆4000乘3000乘4字节约45MB如果还经过imageNamed:缓存内存占用更高。正确做法是先采样缩小图片比如用CGImageSourceCreateThumbnailAtIndex配合kCGImageSourceCreateThumbnailFromImageAlways生成缩略图再用UIImage显示。这道题背后考察的是对图片解码和内存分配的理解。很多人以为UIImage大小只跟文件体积有关实际上内存占用由像素宽高和位深决定和JPG文件大小关系不大。所以实战里列表封面图必须做缩略图不能直接用原图大图预览则用分块加载或者tile显示。我见过不少开发者在collectionView里直接塞高清图结果一滑动内存就涨到几百MB这种问题在视频App里尤其致命笔试场景题基本就是考这个。4.3 后台下载与断点续传视频类App肯定绕不开下载功能。笔试常见题是“如何实现视频离线下载支持断点续传”先答NSURLSession的downloadTask因为系统已经支持断点续传如果服务器不支持Range再考虑自己实现分片下载。NSURLSession在App进入后台后可以通过backgroundSessionConfiguration继续下载但要注意系统不保证后台任务一直存活必须实现application:handleEventsForBackgroundURLSession:completionHandler:回调。另一个隐藏考点是“如何保存下载进度”。我踩过坑每次回调bytesWritten时直接写数据库会造成频繁IO更合理的做法是定期保存比如每1秒或者下载完一个分片后保存一次。如果笔试问你“下载任务被系统挂起后怎么恢复”要答到通过session的getTasksWithCompletionHandler:拿到所有任务再根据NSURLSessionDownloadTask的resumeData恢复下载。这个知识点不常用但很容易出现在进阶题里。5. 架构题MVC、MVVM 与组件化5.1 为什么爱奇艺会问架构视频类App的业务复杂度比一般工具类App高很多播放器、弹幕、评论、会员、搜索、推荐每一个模块都可能由不同团队维护。如果架构混乱协作成本会非常高。所以爱奇艺第二场笔试几乎一定会有一道架构相关的简答题。考的不是“哪个架构最好”而是你能不能讲清楚不同架构的优缺点以及为什么业务需要这样分层。我一贯建议回答架构题不要只背概念。比如问“MVC有什么问题”不能只说“Controller太臃肿”要具体到场景一个播放页ViewController里同时管理播放器状态、网络请求、弹幕数据源、用户行为统计逻辑全堆在一起后续想复用播放器组件几乎不可能。然后再说MVVM可以通过ViewModel把状态和业务逻辑抽离Controller只做视图绑定和用户事件转发这样代码职责更清晰。5.2 一道常见笔试题的答题模板我见过一种很典型的笔试题“请设计一个视频播放页的架构要求支持横竖屏、倍速播放、清晰度切换。”如果只画一个类很难拿高分。我的答复思路分四层第一层播放器核心层封装AVPlayer对外暴露播放、暂停、跳转、切换清晰度等接口内部处理缓冲和错误回调第二层页面状态层用ViewModel管理播放状态、当前清晰度、播放进度并提供给视图层绑定第三层UI层负责布局、手势、横竖屏适配第四层业务层处理弹幕、评论、会员试看等业务。这样答的好处是思路清晰而且能体现你考虑到了具体业务。如果试卷允许可以画一个简单的分层图哪怕用文字标注模块边界评分也会好很多。记住架构题核心是“职责划分”和“可拓展性”。5.3 播放器页面的模块拆分有时候大题会进一步细化比如“播放器底部控制栏应该怎么拆”。这已经不是单纯的iOS题了而是在考组件化和工程能力。我会把控制栏拆成播放/暂停按钮、进度条、时间标签、清晰度菜单、倍速菜单每个部分一个独立View或子Controller通过代理向外发送事件。这样后续加“跳过片头”“只看TA”等功能时不需要改动原有的控制栏主体。这套思维方式也可以迁移到“组件化”这道题上App里有很多页面要复用播放器就需要把播放器核心抽成Pod库而不是把播放代码写在某个页面里。笔试如果问“组件化怎么做”至少答出按业务模块拆库通过路由进行页面跳转公共基础组件下沉到底层。再来一句“模块之间通过协议通信避免直接依赖”基本就是标准答案。6. 算法与实战题链表、字符串和 LRU 缓存6.1 高频手写题算法部分历来是iOS方向考生的分水岭。爱奇艺2020校招的笔试题里算法难度不算夸张常见的有链表反转、字符串去重、二叉树遍历、最长公共前缀。这些题平时刷LeetCode都能遇到但笔试环境不给你补全代码提示手写时特别容易漏边界。比如反转链表最稳的是迭代法每次保存next节点再反转当前节点的next指针。我见过很多同学写递归写一半卡住因为递归需要把返回值处理好。笔试时间紧张我建议至少把迭代版本写得滚瓜烂熟。字符串去重那道题可以用NSMutableSet做标记但要注意不能改变原字符串顺序所以要先判断“是否出现过”而不是简单地对字符排序。6.2 LRU 缓存实现有一道和视频业务强相关的算法题设计一个LRU缓存用于图片或视频封面的最近使用管理。这道题既考数据结构又考业务理解。最经典的实现是哈希表加双向链表。哈希表负责O(1)查找双向链表负责O(1)删除和插入。每次访问一个key就把对应节点移到链表头部缓存满了就删除链表尾部节点。手写代码时我建议把Node类定义清楚key、value、prev、next。然后实现四个操作get、put、removeNode、addToHead。如果不熟悉双向链表很容易在删除节点时忘记处理prev和next之间的连接笔试里一旦出现空指针或者循环链表整题基本拿不到分。业务上图片缓存就是典型的LRU场景。很多库默认使用LRU算法因为用户大概率会回看短时间内的内容把最近看过的封面保留在内存里把很久不用的淘汰掉能很好控制内存峰值。6.3 从笔试代码到线上问题笔试算法题不是孤立存在的它往往映射着线上问题。比如短视频场景里用户快速上滑内存中的视频封面和播放器实例不能无限创建最好的做法是复用播放器、复用cell、配合LRU缓存。如果你在笔试里能把算法和业务关联起来说明会显得你并不是死刷题。我自己的踩坑经历是在做视频列表时直接把每个cell的AVPlayer都创建出来结果一屏最多六七个播放器同时存在内存和CPU瞬间爆掉。后来改成只保留当前播放和预加载的播放器其他从列表移除再用LRU管理播放器资源问题就解决了。这类经验在笔试简答题里很加分因为它证明你不只会调API还理解资源管理。7. 复盘与准备建议7.1 为什么笔试没通过的人几乎都挂在同一个地方我帮人改过不少笔试复盘发现大多数人挂掉不是因为不会而是因为答题节奏和表达方式。选择题不确定时反复琢磨浪费了时间简答题只写结论不写原因导致丢失过程分算法题没有提前写注释或函数签名bug越找越乱。尤其是简答题如果只写“使用weak防止循环引用”而没有说明weak表的原理很难和其他候选人拉开差距。我建议备考时养成一个习惯每道题都按“结论 原因 例子”三层结构来答。哪怕题目没有明确要求举例写一个小代码片段也能让答案更有说服力。7.2 针对后续校招的延伸准备虽然这是2020年的考题但它的考点到现在依然适用。现在准备iOS校招除了原题还要补上几块SwiftUI和Combine越来越常被问iOS开发者模式、模拟器和真机调试的区别也经常出现在现场面试里上架和证书更新这种工程流程问题偶尔会作为开放性试题出现。我在指导学弟学妹时会让他们在Xcode里自己过一遍完整的开发流程用模拟器跑通界面再切到真机开启开发者模式调试推送和后台任务。这一步能帮你发现很多“模拟器正常、真机崩”的问题比如相册权限、网络权限、推送Token获取失败。面试官如果问“你平时怎么调试”你能说出真机和模拟器的差异会显得实战经验更真实。7.3 我自己的备考节奏参考最后说点个人经验。我准备这类笔试时会分三轮第一轮只做选择题和填空题重点是把iOS基础概念过一遍第二轮专门写编程题尤其是链表、字符串、LRU每天至少手写两题第三轮把所有场景题整理成自己的“答题模板”比如架构题、缓存题、下载题都形成固定表达。考前一周我会把之前的错题和代码片段重新看一遍不再刷新题。参加过校招的人都知道笔试现场心态比知识储备更重要而心态稳的前提是你知道大部分考点都是自己见过的。爱奇艺2020校招iOS方向笔试题第二场给我最大的启发是不要太依赖刷题数量要把每个基础知识点吃透尤其是内存管理、多线程和架构设计这些才是iOS开发真正的护城河。希望这份拆解能帮你少走一些弯路。
返回列表