字节跳动 2022 校招抖音中台 iOS 客户端方向面经(凉经)

个人基本情况

双非计算机本科,刚考完研,春招和复试两手准备。绩点年级前 25%,在校做过若干 iOS 客户端开发的有关项目,面的这个组主要做跨端。

一面

自我介绍

Q:介绍一下项目经历?
A:把简历上写的三个项目说了一遍。(期间面试官有一些对于项目细节的反问就不写出来了)

Q:可以说一下简历中第一个项目的架构吗?
A:(把项目中用到的单例、MVC 架构啥的说了一遍)

Q:你有没有考虑在自己做的这些项目中做一些性能优化呢?
A:没有,其实感觉自己目前做的这些还是挺简单的,不涉及到什么复杂的逻辑,对性能要求也不是特别高,我们测试基本上是能跑起来没有明显的卡顿就行。但如果是像抖音这种规模的业务,恐怕就不能一点优化都不做了。如果我有幸被录用的话,性能优化这方面也是我需要重点去学习的。

Q:对跨端(跨平台)开发有了解吗?
A:(讲了一下跨端的定义),跨端的好处是写一套代码可以在多个平台运行,减少了开发工作量;缺点是性能有损失,且初学者不易掌握(一般需要先学原生再学跨端)。

Q:你觉得在学校中做了这些项目之后,最大的收获是什么?
A:个人感觉应该是解决问题的能力得到了加强,一开始的时候遇到问题只会去问学长学姐,后来能够通过逛一些技术论坛、技术博客和阅读官方文档来解决。

(代码题)设计一个 Person 类,继承于 NSObject 类,有 name(string类型) 和 weight(float类型) 两个成员变量,实现 Person 类的构造函数、比较两个对象是否相等以及更新 name 的函数。

面试官一开始说是用 OC 实现,我表明只会 Swift 后同意我用 Swift 写,感觉这就是考察面向对象的一些基本性质和语法?

八股:

TCP 三次握手四次挥手的详细过程,以及为什么四次挥手后要等待 2MSL?

输入网址敲下回车后发生了什么事?越详细越好。

HTTP 和 HTTPS 有什么区别?

HTTPS 是如何实现加密传输的?
没答上来(考研不考orz),整理如下:
1. 浏览器将支持的加密算法信息发给服务器。
2. 服务器选择一套浏览器支持的加密算法,以证书的形式回发给浏览器,证书中包含服务器的公钥。
3. 客户端(SSL/TLS)解析证书验证证书合法性,生成对称加密的密钥,我们将该密钥称之为 client key,即客户端密钥,用服务器的公钥对客户端密钥进行非对称加密。
4. 客户端会发起 HTTPS 中的第二个 HTTP 请求,将加密之后的客户端对称密钥发送给服务器。
5. 服务器接收到客户端发来的密文之后,会用自己的私钥对其进行非对称解密,解密之后的明文就是客户端密钥,然后用客户端密钥对数据进行对称加密,这样数据就变成了密文。
6. 服务器将加密后的密文发送给客户端。
7. 客户端收到服务器发送来的密文,用客户端密钥对其进行对称解密,得到服务器发送的数据。这样 HTTPS 中的第二个 HTTP 请求结束,整个 HTTPS 传输完成。
更详细的 HTTPS 加密原理介绍,可参见彻底搞懂HTTPS的加密原理 – 顾伊凡 YGY的文章 – 知乎

假设硬盘中有 32G 的数据,要在 1G 的内存中实现对这些数据的排序该如何做?
显然是一个外部排序问题,用归并排序的思想解决。但是细节上面有些遗忘,最终还是没能把逻辑说全,这就去看王道书【爬了

(智力题)假设有 n 只老虎和 1 只羊,老虎都是喜欢吃羊的,但吃了羊之后自己就会变成羊,可能会被其他老虎吃掉。老虎在自己有被吃掉的风险时是不会吃这只羊的。问 n 在什么范围的时候这只羊不会被吃掉?

这道题看起来挺无厘头的,和技术无关,但可以用动态规划的思想去想。设函数 f(n),f(n) 可取 1 或 0,1 代表羊在老虎数为 n 时会被吃,0 代表不会被吃。先考虑 f(1)——显然老虎吃羊是安全的(吃了之后自己就变成羊,但没有其他老虎了,自然也不会被吃,f(1)=1),故羊会被吃;再考虑 f(2),此时若其中一只老虎吃羊,那么就转化成了 f(1) 的情况,因为 f(1)=1,此时由于吃羊变成羊后的老虎会被吃掉,故 f(2) 时羊不会被吃(f(2)=0);同理 n=3 时其中一只老虎吃羊就转化成了 f(2) 的情况,又之前我们得到 f(2)=0,故 n=3 时老虎可以放心吃羊,f(3)=1…… 以此类推我们可以得到 n 为奇数时羊会被吃掉,n 为偶数时羊不会被吃掉。

(代码题)假设服务器中存储了用户登录日志,每一条记录的结构体描述如下:

struct User {
    int userid; //用户ID
    int loginTime; //用户登录时间戳,单位秒
    int logoutTime; //用户登出时间戳,单位秒
};

已知日志的数据量很大,编程找出用户在线的峰值人数和峰值时间段。

注意到日志数据量很大,既然一天 86400 秒,那就干脆设一个 86400 长度的标记数组 flag(初始化全 0)来记录每个时段的登录人数。遍历一遍日志,对于每条记录,执行 flag[登录登出时间戳区间内的所有数]++ 就能统计出每个时间点的在线人数了,通过遍历标记数组求出数组最大值就是用户在线的峰值人数;同时记录一下取最大值的 index,再输出对应的点或者区间作为峰值时间段。

二面

自我介绍

Q:介绍一下项目经验?
A:(同一面)

Q:我看你做了很多 iOS 的项目,你是如何找到这么多实践机会的?
A:(讲了对 iOS 开发的兴趣、加入社团参与项目开发等经历)

Q:最后一个项目你用到了 SwiftUI,用下来对 SwiftUI 的整体感觉如何?
A:首先我觉得 SwiftUI 最大的好处就是写起来简单,比如 UIKit 中的 UITableView,需要用代理才能把数据放进去,而 SwiftUI 对应的 List 只要简单堆叠即可;其次 SwiftUI 是数据驱动的框架,绑定的数据修改后会立即体现在 UI 上,而 UITableView 还需要有刷新的操作;最后,感觉 SwiftUI 还不是很成熟,会有一些很神奇的 bug。

Q:你在开发的时候有没有用一些开源库?
A:有的,主要用到了 SnapKit、Moya、SDWebImage(并简要介绍了一下这些库的作用和原理、是谁的封装)。

Q:有没有去看一下 iOS 有关网络请求的实现呢?
A:没有,目前仅仅是使用,还没有研究它的实现。

Q:Swift 内存管理了解吗?
A:(讲了一下 Swift 引用计数机制)

Q:那我们一般用什么方法解决循环引用的问题呢?
A:使用 weak 关键字来声明其中一个变量,weak 是不增加引用计数的,自然两者都能正常释放。

Q:weak 在实际开发中经常用在哪里呢?
A:一般在声明代理(delegate)的时候把它声明为 weak。

Q:还有用到 weak 的地方吗?
A:我印象里没有了(其实还有一个地方是为了防止闭包直接或间接被 self 持有导致循环引用,在闭包捕获列表中把 self 声明为 weak self,当时没想到)。

Q:Swift 中 class 和 struct 有什么区别?
A:class 是引用类型,struct 是值类型。

Q:那什么时候用 class 什么时候用 struct 呢?
A:(阿巴阿巴阿巴,直接和面试官说没有想过这方面的问题)

八股:

编译原理学过吗?源程序编译需要经历哪几个步骤?
1. 词法分析
2. 语法分析
3. 语义分析
4. 中间代码生成
5. 代码优化
6. 目标代码生成

快速排序的时间复杂度和空间复杂度是什么?为什么?

什么是满二叉树和完全二叉树?

进程和线程有什么区别和联系?

进程的内存映象有哪几块区域?(今年考研 408 新增考点)
操作系统内核区、用户栈区、堆区、代码段、共享库的存储映射区。

多线程在实际开发中有什么应用?多进程呢?

如何理解同步、异步、阻塞、非阻塞?

如何理解串行和并行?

知道锁吗?它的作用是什么?(今年考研 408 新增考点)

死锁是怎么产生的?如何解决死锁问题?

(算法题)爬楼梯
可以说是最简单的 dp 了,不解释。

(算法题)设水管长为 l,100 只虫子离管口的距离为 n[0…99],虫子相遇会转向。虫子爬行的速度为 v,求这 100 只虫子爬出水管的用时。
找了一下是 LeetCode 第 1503 号问题换了个说法。面试的时候并没有最终写出代码,只是在面试官的引导下说了下思路(先考虑 2 只虫子再推广),面试时间就到了。

总结

二面结束后被通知凉了,“不是很匹配,建议先试试业务团队”。个人感觉本次凉面是在情理之中:客观上从通知面试到一面只有一个星期的时间,很仓促,面的这个部门难度也比业务部门高一些;外加刚考完研,一年没碰 iOS,确实对 iOS 的一些东西忘的差不多了,准备的一星期基本都在刷算法。虽然二面八股文什么的都答出来了(考研人的优势),但是 iOS 相关的内容答的不是特别好。建议后来者如果要在简历上写 iOS 相关项目经历的话,一些 Swift/OC 相关的语言特性需要掌握,一些常见的库需要去看一下源码、研究一下是怎么实现的,以免被问到只能阿巴阿巴阿巴(这是笔者的切身教训)。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注