小米、百度、bigo 、滴滴 、快手等iOS 面试后的一次阶段性总结

面试过程

在疫情期间都是远程面试,下边先介绍一下疫情期间面试的一些公司的面试情况。同时拿到了其中几家的 offer。下边介绍的面试题只还原了其中印象比较深的部分,会存在不足的情况,并不代表面试的全部。

小米

一面

  • 介绍有哪些设计原则,并让比较详细的说了其中开闭原则在项目中的应用。
  • 介绍设计模式,然后其中主要问了我抽象工厂和适配器两种模式。
  • 介绍 runloop 相关的知识和在实际开发中的使用情况
  • 要求详细的描述事件响应链

二面

  • 介绍过往的项目经验,因为曾经的项目和所面试的部门岗位需求匹配度较高,所以这块的时间占比较多。
  • 回文算法
  • (算法)判断一个字符串是不是对称的字符串,比如 abba 或者 aba 这样的就是对称的。
  • block 的实现原理
  • 比较详细的介绍 https 的过程。
  • 过往开发中做过哪些优化向的工作,问的也比较详细。
  • 如何检测项目中的卡顿问题(比如假死)
  • 比较详细的介绍消息转发流程和事件响应链
  • GCD 的底层线程调度原理
  • 介绍 hash 算法的原理

三面

  • 一个二叉树逐层打印的算法题
  • 介绍自己的过往的项目经验,会结合项目问一些架构向的思考
  • 如果现在做一个新的网络层框架,有哪些需要考量的点

百度

百度只有一面,因为面得是百度的商业化部门,对于细节的要求非常严格。个人感觉自己的表现确实不是很好。

  • 判断一个字符串是不是 ipv6 地址(要求尽全力的考虑所有异常的情况)

PS:当时面试官明确告诉我,这个面试题做不好,面试是直接结束的。

  • 介绍界面卡顿的优化有哪些可以优化的点。

  • 介绍 UIResponder 的继承链。然后说事件响应链。

Bigo

感觉面试的这些公司,Bigo 对于基础的考察最全面。

一面

  • (算法)找出一个页面中漏出部分面积最大的试图,重合的部分按照最上层的面积算漏出,会有时间复杂度的要求。
  • 简单地介绍的过往的项目经验
  • 控件的点击事件和添加在上边的手势谁先响应,并说明原因
  • 谈 CoreAnimation 和 CoreGraphic 的区别
  • 说 @synchronized 锁的实现原理,并说明其中可能存在的问题。同时介绍了 iOS 开发中常见的锁。
  • 介绍编译的过程和原理
  • 谈对于 bitcode 的理解和作用。
  • 详细的介绍了 Https 的过程。

二面

  • 介绍属性常用修饰符,介绍 assign 和 weak 之间的区别。这块会延伸到内存管理相关,比如引用计数的方式。
  • 聊对于 GCD 的理解,和 GCD 底层是如何进行线程调度的。聊 GCD 中常见方法的使用 (group ,信号量
    ,barrier 等)
  • 详细的介绍了 KVC 和 KVO 的原理。
  • 介绍消息转发过程
  • 介绍对于 Runloop 并介绍知道的应用场景。再具体场景中会有追问。
  • 介绍项目优化的经验,这一块会聊的比较细。
  • 介绍对于静态库和动态库的理解。
  • 在 webview 使用过程中存在的问题和解决方案。

三面

  • 介绍了过往 RN 的使用经验和对于 Flutter 的理解。
  • 谈对于组件化的理解和市面上常见的组件化方案
  • 问了一些 APM 向上的问题。
  • 谈个人对于项目架构选择的理解。自己如何进行架构的选择(主要对于 MVVM,MVC等,后文有个人对于这一块的理解)
  • 谈个人规划

滴滴

一面

滴滴的一面分为两部分。

  • 第一部分:过往项目经验,会对自己的过往项目经验,结合自己的描述,面试官问你介绍到的项目中涉及到问题,然后会据此引申出一些问题,这一部分占比比较大。
  • 第二部分是基础知识面
  • 谈属性修饰符,如果 assign 修饰对象可能存在的问题和原因。
  • 比较的深入的聊了内存管理的内容,包含引用计数和 weak 修饰的对象的内存管理的过程。问的会比较深入。
  • 讲 runloop 的过往使用经验。
  • 介绍自己比较熟悉的三方库的实现原理

二面

  • 对于锁的理解(自旋锁和互斥锁),以及 iOS 开发中常见的锁。同时要求介绍个人在开发过程中在哪些场景下用到过锁。
  • 在实际开发中遇到过哪些多线程问题以及如何进行解决的。
  • 为什么不能在异步线程中更新页面,介绍原因。
  • 对于内存泄漏的了解,以及介绍知道的解决方案。
  • 一些优化向上的问题,主要是根据自己介绍的优化进行较为深入的追问。
  • 一个坦克从一个空间的起点到终点,中间在某些位置上有阻隔的情况下,判断从起点到终点是否有可行路径的算法题。

三面

  • 比较详细的介绍之前的项目经验和主要负责的内容
  • 介绍过往项目中最有挑战的事情,并会据此深入的聊。
  • 介绍了一些架构向的理解
  • 谈个人规划

快手

快手的一面是跨部门面试,二面是本部门面,所以一二面面试题会有一些重复,只写了一次。

一面

  • 介绍过往的项目经验
  • 两个不算难的算法题(具体的忘记了...)
  • 聊了 assign 修饰对象可能存在的问题
  • 聊过往项目中的优化经验
  • 介绍消息转发流程

二面

  • 比较详细的聊到的 block,深入的讲了其中的实现原理,并介绍不同变量的引用方式。
  • 介绍开发中常见的循环引用,并说明其中的原因和解决的方案和原理。
  • 介绍 Runloop 并讲应用场景。
  • 二叉树翻转

三面

  • 一道多线程实际场景下的问题,要求远程写出实现方案的代码
  • 聊对于 MVVM,MVC 和 MVP 的理解。
  • 介绍过往项目中 RN 的使用经验和遇到的问题。
  • 讲如何将一张内存极大的图片可以像地图一样的加载出来(只说实现思路)
  • 聊对于组件化的理解,对于市面上的组件化方案的理解,优劣分析等。

其他

除了上边介绍的公司外,还面了平安,51 talk,58 同城,好未来,美篇。

因为绝大部分面试内容和上边的基本上只是重复,只对差异性的面试题进行了总结。

  • 对图像编解码的了解
  • 在子线程中是如何进行内存管理的
  • JSBridge 是如何实现的,以及和原生的调用关系。
  • 问到了一些 AFNetworking 和 SDWebImage 相关的实际开发中的问题。

iOS 的一些面试准备

上边聊完了面试过程中遇到的面试题,下边聊聊自己在面试之前的一些准备工作。

其实这次跳槽对于个人而言是很早之前就有准备了的,所以疫情对于我的影响并不是很大。此外想突出强调的是 iOS 面试中的基础知识在于日常的积累和总结,单纯的靠面试前的短期准备个人感觉是不够的。

下边根据上边的面试题和之前个人的面试准备,对整个面试过程做了一次梳理。

1.算法

《剑指 offer》 半个多月的时间用 Swift 敲了一遍,然后用 OC 手写了一遍。

之前断断续续刷了 LeetCode 上 Medium 和 Easy 的题有 150+

对于国内的小伙伴,基本上客户端面试涉及到的算法知识是足够覆盖的了。当然快手的三面算法题还是被虐了...

如果你正在跳槽或者正准备跳槽不妨动动小手,添加一下咱们的交流群1012951431来获取一份详细的大厂面试资料为你的跳槽多添一份保障。

2.基础

其实个人认为 iOS 基础知识部分真的需要个人日常的一些积累,在面试准备阶段对整个积累的整体串联,然后再查缺补漏的过程,下边是我自己面试准备阶段的一些知识主线。

  • 网络

    • 1.近些年客户端 WEB 劫持的现象依然常见。所以 DNS 是什么和相关的问题。

    其中包含从 localDNS 到 HTTPDNS 转变目的和原因。以及在 DNS 场景中 CDN 的使用。

    • 2.对于 tcp / ip 和 http 协议,以及 SSL 和 物理层和数据链路层的部分协议的掌握。

    当时对于这一部分,我的准备过程就是自下而上的方式进行复习的。

    • 3.有兴趣的小伙伴也可以了解一下 BFF。
  • 内存管理(对象视角)

    • 1.isa 是如何使用 bitmask 的方式来进行内存管理的,其中相关的字段有哪些。

    • 2.对象的引用计数的管理分为哪两部分。以及思考为什么有这两部分的设计。

    • 3.弱引用的内存管理方式。

    • 4.在分类中使用 Associate 方式添加的属性是如何进行内存管理的。

  • 内存管理 (运行时视角)

    • 1.在主线程中的内存管理方式,其实就是 Runloop 的触发的时机。

    • 2.如果在子线程中如何进行内存管理的。

    • 3.AutoReleasePool 的使用原理和数据结构。

  • 内存管理 (项目视角)

    • 1.项目中存在的循环引用的问题的场景和解开循环的方案。(代理,Block,timer,A-B-C-A 等)

    • 2.当下主流的内存管理的快速追溯方案有哪些,思路是什么。比如 FBRetainCycleDetector ,MLeaksFinder,PLeakSniffer。

  • 多线程问题

    • 1.iOS 开发中常用锁的总结,以及对于自旋锁和互斥锁的理解。

    • 2.GCD 中的线程池的原理。串行和并行两种队列模型在底层实现中的区别。为什么会用到 overcommit 等。(其实这里很多是涉及到对于 GCD 相关源码的理解),主要在于理解队列中线程的创建和调度。

    • 3.NSOeration 的使用场景等。

    • 4.一些开发中常见的多线程问题的场景和解决方案。

  • runtime & runloop 相关的问题

    • 1.其实上边内存管理(对象视角)下就是 runtime 中很多相关的核心代码。

    • 2.runtime 中 method swizzle 的使用场景和可能存在的问题(比如 hook viewdidLoad 统计页面加载市场不准确的原因)。

    • 3.消息响应链。

    • 4.从 isa 中的 data 的数据结构,到 class_ro_t 和 class_rw_t 的理解。如果这里的转换过程理解足够,是完全可以解释为什么 category 不能添加属性的。此外是对于内存对齐问题的理解。

    • 5.对于 runloop 的理解,以及一些常见的使用场景。(比如系统中主线程的场景和 AFNetwork 中的场景,以及主线程卡顿抓取方案的场景等等)

  • 其他

    • block 相关的知识。

    • 对于动静态库的在项目中结合导入可能存在的问题和解决方案,以及动态库过多可能造成的问题等等。

    • 基于 pod 的项目管理。

    • KVC 和 KVO 的实现原理。

    • 一些跨平台方案的考察(RN 和 Flutter 其实这一部分比较锦上添花,没有也不是一定不行),笔者之前写过一段时间 RN 对于 Flutter 也有一些经验。个人认为未来跨平台的方案是未来的一种趋势。

上边大致是我在面试之前和面试之后对于 iOS 基础知识的梳理出来的主线。感觉不够全面,但是面对市场上主流的 iOS 面试应该足够了,很多同学可能对于上边涉及的知识点会有一个问题就是面试造火箭的感觉,对于实际开发中真正能用到的东西十分有限,对于项目的实际开发,实际使用十分有限。

下边谈一下个人对于类似观点的理解。

首先面试是一次筛选的过程,而上边的知识点就是相对而言更有筛选的辨识度。而日常开发中所谓的扭螺丝的内容对于绝大部分开发者而言都没有很好的区分能力。面试官在面试过程中更希望看到的是候选人在日常中的积累和学习的能力。而基础知识的扎实是学习能力和学习意愿的一种体现。

此外,其实现在的客户端市场上,因为多年前培训机构的原因,不缺乏初级开发者,对于大厂而言,项目的复杂度和代码的维护成本都是很多项目很关注的点,当下市场上需要的基础知识扎实,然后可以根据基础知识来做各种项目优化相关的 developer。所以有一些对于基础的要求也无可厚非。

聊到项目优化,下边是在面试准备阶段对于项目优化结合过往项目经验和之前知识积累做的一些准备。

3.项目优化

  • 包大小管理

    • 1.对于资源的优化

      其中涉及到的一些思路,图片的优化,图片的压缩,Assets -> 网络加载的转换,无用类和无用方法的查找分析工具的了解,以及使用 linkmap 的方式查找包各个模块的占比,从工程视角下做代码和架构层面的调整和优化。

    • 2.工程视角下的优化

      通过 WorkSpace 中的设置实现打包的架构的优化,删除对于不在支持架构的打包。

    • 3.项目打包方式的优化

      开发阶段有很多的辅助工具,帮助我们寻找和发现问题,甚至对于一些项目而言还存在类似模拟数据相关的很多类或者库,这些其实对于线上项目而言是不需要的,所以可以整体上实现将对应的辅助工具整体归整收集到一个或几个组件,通过 #DEBUG 的方式引入,然后通过脚本的方式保证线上环境的包不包含对应库的方式实现项目的瘦身。

  • 界面卡顿的优化

    • 1.卡顿成因

    对于卡顿成因,比较常见的有主线程中的逻辑卡顿和离屏渲染。

    关于离屏渲染个人感觉即刻团队的总结很赞,离屏渲染优化

    • 2.快速追溯工具

    其实 Xcode 为我们提供了 instrunments 工具,但是对于线上问题的上报和追溯能力也很重要,其实这一块就可以参考在主线程的 Runloop 中添加 Observer 来实现。当然实现过程中可能还会有堆栈抓取不全等等问题,此时可能尝试的方向就包含 fishhook 的方式的尝试。这个过程中又要回归最初的很多基础知识,这个过程就会发现,面试事的造火箭也并不是那么不可理解,因为还是有很多进阶的场景下需要一些造火箭的能力...

  • 网络层优化

    • 1.从 jpg 到 webp 格式的转化。(新闻和资讯,电商等图片浏览量大的项目)

    • 2.从 json 到 protobuffer 的优化。

    • 3.将一些收集性的数据整合打包上传,减少请求次数,并且可以结合 Runloop 来择机上传。

  • 耗电量和定位相关的优化(笔者没有对应的经验)

  • 工程视角下的优化

    • 1.启动阶段的优化。可以看看杨潇玉的文章

    • 2.抖音的二进制重排方案

    • 3.APM 的建设

    笔者对于 2,3 暂时没有线上实践经验...

4.架构

其实聊到架构,不知道从什么时候开始 iOS 圈子里的话题就集中在了 MVC,MVP,MVVM 和 Viper 这几种之间的比较。

由于笔者只是对于 MVC 和 MVVM 有相对多的使用,所以谈谈自己对于架构的理解。

个人认为这几种架构不存在绝对意义上的孰优孰略,每一种架构都有其产生的对应的背景。而且不认为说一个项目一定就全是 MVC 或者 MVVM。或者说脱离了 RAC 就不能使用 MVVM 的方式来做设计项目中的部分代码。

笔者个人认为,项目的架构选择的问题上需要考量业务背景,效率方面的因素。

比如传统的 MVC 架构,最大的槽点就在于很多人认为 view 和 model 层很轻,但是 controller 层代码冗余较多,于是产生了 MVVM 的架构,笔者个人对于 MVVM 是这个背景下产生的说法是否定的。

笔者个人认为, 传统的 MVC 架构如果 controller 的代码过多最大的原因在于 developer 本身的问题,其实完全可以根据业务将对应的逻辑进行拆分分别的放到一些对应的 manager 管理类中做处理。将一个页面拆分成更多小得 MVC 的方式来解决项目过多的在一处维护困难的问题。个人认为这样的方式一样可以提高代码的可维护性。此时看 manager 很像 MVVM 中的 VM 。

笔者的观点貌似就是在说 MVVM 的产生没有什么价值。其实并不是这样的。我们在聊一个架构模式的时候需要了解 MVVM 的优点。其实 MVVM 的架构设计较早的出现在前端领域。个人认为当一个页面的交互非常多,数据传递链比较深的时候,通过 MVVM 和 RAC 的结合的方式可以大大的降低代码的维护成本和提高代码的可读性,而且可以很好且方便的做状态管理。在这种场景下使用 MVVM 是我认为很好的场景。而对于一个偏静态的页面而言,我并认为 MVVM 和 MVC 存在孰优孰略。从维护成本的角度考量,反而 MVC 可能更优。

所以个人认为 MVC 和 MVVM 对于一个项目而言不是二选一的关系,而是可以结合场景选择来使用。

此外就是效率问题,对于很多项目而言,很多人说 MVVM 更好就一定要 MVVM + RAC 。我认为这有些偏激的成分存在,需要考虑团队整体技术储备和维护成本的整体考量。

如果组里只有一两个人会 MVVM + RAC ,而剩下的人对于类似的知识点根本不掌握,不是说其他人不应该学习和进阶。而是说应该在考量开发效率和成本,对应的选择性放弃,之后条件允许后在逐步做迁徙。个人比较反对架构的非黑即白。

此外,想表达一点个人观点在于大多人的关注点貌似都注意在了对于 MVVM 和 MVC 的比较之中,而忽略了设计模式和设计原则的重要性。

其实个人认为尤其是日常的业务开发,设计模式和设计原则的使用在模块或者业务中更为重要。

笔者觉得关于设计模式和设计原则的知识可以读读《Objective-C 编程之道》。

此外对于改善和提高代码能力可以看看《重构》《代码整洁之道》。

5.成长的思考

上边的总结的很多知识点,并不是我在准备面试的阶段才去看对应的知识的,而是在日常开发中积累的知识的一次梳理和总结。将日常琐碎不体系的积累的一次梳理和总结。

上边的知识的获取的途径都很方便,网上有很多前辈有非常好的总结。比如 runtime 的部分我就是看了源码+霜神的神经病院系列+ draveness 的很多文章来进行学习的。

笔者认为比较好的学习方式在于体系化整体的学习,而对于公众号或者简书文章的碎片化记忆。个人觉得当下碎片化学习的概念炒得火热,但是碎片化的学习的核心是可以用碎片的时间高效的学习知识体系中小的点,提高学习的效率,但归根结底,还是知识要成体系,还是要将碎片化的内容整体的串联起来才更高效,如果只是一个个碎片化的知识,没有整体性的视角,个人感觉随着时间线的推移,用不了多久在不使用的情况下就被遗忘了。

然后就是优秀的源码的学习,我在很早之前就读过 Aspect 的源码,代码量不大,但是设计质量非常高,后来 JSPatch 开源的时候去读相关的源码,虽然不知道 Bang 神的消息转发机制有没有参考过 Aspect,但是发现消息转发机制上的源码有很多的相似之处,因为之间的积累,JSPatch 源码的阅读相对而言很顺畅。后来自己在工作中写一些小的工具也有过类似的尝试。

此外个人认为技术的深度比技术的广度更为重要。对于 iOS 端个人认为进阶的方向有 Clang 和 LVVM 相关的知识,汇编,逆向等等。上述知识体系,也只有汇编有过比较多的接触。对于一些奇怪的问题的追溯,汇编真的很好用。当然其他知识也在学习,最近戴铭老师出了一本 《iOS 变成理顺核心知识点》,书的质量很高,就是深入学习的一个起点。

对于技术广度的问题,笔者的经验是挖掘自己的一些需求,然后根据自身的需求出发,比如 Swift 的学习之后,如果我们工作的项目还是 OC ,我们可以有一些优化的需求需要用到脚本的时候可以尝试用 Swift 来写脚本。或者尝试将一些简单一些的开源库用 Swift 重写。亦或者我日常对于理财和经济学的东西较为关注,我会用 Swift 写一些自己手机上使用的软件,比如真实利率的计算。曾经为了利用好碎片时间用 Swift 写过一个很简单地 JS 编辑器等等。

其实自己后来学习 Python 的过程也是和生活中的一些需求有直接的关系,还是认为兴趣是最好的老师,建立起兴趣,然后在玩的过程中学习,简单又高效。当然说起来容易,做起来对我同样很难...

结尾

当然上边的内容是自己对于过往经验的一个总结,有些部分难免有片面甚至错误的地方,还希望大家能够指正。

希望本文能为部分准备求职和在职的处在迷茫期的同学提供一种思路。成长永远不可能一蹴而就,都是在不断积累和学习中完成的厚积薄发。

之后希望和大家多多交流。

面试资料:

看完文章如果你正在跳槽或者正准备跳槽不妨动动小手,添加一下咱们的交流群1012951431来获取一份详细的大厂面试资料为你的跳槽多添一份保障。

 
posted @ 2020-07-07 13:32  Julday  阅读(896)  评论(0编辑  收藏  举报