写点什么

2021- iOS 开发者一份你一定会被问到的面试题(附参考答案)

用户头像
iOSer
关注
发布于: 7 小时前

当您准备 iOS 技术面试时,重要的是要了解您可能会被问到哪些主题以及对经验丰富的 iOS 开发人员的期望。许多公司使用这些问题和主题(以一种或另一种形式)来衡量 iOS 候选人的经验水平。它们涵盖了 iOS 开发的各个方面,旨在广泛了解该平台。毕竟,高级开发人员应该能够从头到尾发布完整的 iOS 产品。但在拥有大型 iOS 开发团队(想想 25 人以上)的大公司中,专业化和专注于特定问题(如网络)的深入知识也会发生。这绝不是一份详尽的清单,但它可以帮助您为即将到来的 iOS 技术面试做好准备。


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


#提问:


  1. Swift 的主要特点和优点或缺点是什么?

  2. 什么是 iOS 应用程序,您的代码在哪里适合它?

  3. iOS 上的内存管理是如何处理的?

  4. 什么是 MVC?

  5. 你对单身人士了解多少?你会在哪里使用,你不会在哪里?

  6. 解释一下委托和 KVO 之间的区别?

  7. iOS 应用中常用的设计模式有哪些?

  8. 除了常见的 Cocoa 模式,你还知道哪些设计模式?

  9. 解释和展示 SOLID 原则的例子?

  10. 在 iOS 上实现存储和持久化有哪些选择?

  11. 在 iOS 上实现网络和 HTTP 有哪些选择?

  12. 如何以及何时在 iOS 上序列化和映射数据?

  13. 在 iOS 上布局 UI 的选项有哪些?

  14. 如何优化动态调整大小的表格或集合视图的滚动性能?

  15. 你如何在 iOS 上执行异步任务?

  16. 你如何管理依赖关系?

  17. 你如何在 iOS 上调试和分析代码?

  18. 你有 TDD 经验吗?你如何在 iOS 上进行单元和 UI 测试?

  19. 模拟、存根和假货之间有什么区别?

  20. 您是否进行代码审查和/或结对编程?

  21. 什么是 FRP(Functional Reactive Programming)及其在 iOS 平台中的地位?

  22. 你知道哪些 iOS 架构有这么大的规模?


在下面的部分中,我将详细介绍每个问题、其背后的推理、预期答案以及可能会给面试官带来危险的答案。在适用的情况下,问题有进一步阅读部分,您可以在其中找到与它们相关的更多材料的链接和参考。

1.Swift 的主要特点和优点或缺点是什么?

这听起来像是一个初学者的问题,但事实并非如此。有时可能会要求评估您使用其他语言的经验以及您对所使用语言的更广泛理解及其优点、缺点和局限性。


预期答案:


TLDR:主要的 Swift 特性 - 静态类型、协议、引用类型、值类型、选项、泛型。


Swift 是一种强类型语言,这可能是它最大的特点,同时也是优点和缺点。静态类型允许存在协议、泛型和选项,并帮助您进行开发。静态类型给你很多编译时警告和编译错误,但提供了更好的运行时安全性和确定性(可选、var/let、泛型或具体类型等)。这是该语言提供的最大优势之一。在以下场景中拥有严格的类型安全是最有帮助的:


  • 当您构建客户端应用程序并且需要更严格的明确性而不是动态性和灵活性时

  • 当您在这样的环境中工作时,您希望限制经验不足的开发人员(初学者和初级人员)拥有过多的权力并让自己陷入困境

  • 当您需要重构代码并且编译器可以帮助您正确正确地编写代码时


所有这些恰好是 iOS 开发人员构建的大多数面向客户的应用程序。


同时,当您构建需要更多灵活性的东西(例如构建库或框架)时,静态类型可能过于严格。在这方面,Objective-C 可能是更好的选择,因为它比 Swift 具有更好的元编程功能。(虽然可以说此时 Objective-C 已经过时了,Apple 平台的所有开发都应该在 Swift 中完成)


注意点:


只要您能阐明每个功能提供的内容,即协议和泛型实际上允许您在代码中做什么,您就可以了?但同样,与严格的类型系统相比,这些可以说是次要的语言功能。


这个问题的进一步阅读:


2.什么是 iOS 应用程序,您的代码在哪里适合它?

这是一个以一种或另一种形式提出的宏观问题,以衡量您对 iOS 应用程序是什么的理解,以及您编写的代码在其中的位置以及在整个 iOS 系统中的位置。


预期答案:


我们可能认为我们构建的应用程序很特别,因为它们涵盖了一个独特的用例。但是您典型的 iOS 应用程序只是一个巨大的、美化的运行循环。它等待用户输入并被外部信号中断,例如电话、推送通知、家庭手势/按钮按下和其他应用程序生命周期事件。唯一的区别在于,它不仅仅是一个简单的主循环函数,每次用户点击您的应用程序图标时都会启动它,它具有更高级别的抽象,开发人员可以使用UIApplicationAppDelegateSceneDelegate


您为实现应用程序的业务逻辑而编写的其余代码放置在该主循环通过AppDelegate或委托给我们的应用程序的“触发点”中的某个位置SceneDelegate。在 iOS 13AppDelegate负责接收应用程序的所有外部事件并启动 UI 之前;但是从 iOS 13 开始,所有与 UI 相关的逻辑都移到了 SceneDelegate。


而已。简单的。您为应用编写的代码可以像方法/函数调用一样简单,也可以像 VIPER 架构一样复杂。这是你的选择。


注意点:


通常,开发人员将 iOS 应用程序视为他们编写的 MVC 代码以及实现的复杂细节,这是事实。但是如果你退后一步看大局,你会看到 iOS 应用程序真正是什么——一个运行循环。


这个问题的进一步阅读:


3.iOS 中的内存管理是如何处理的?

内存管理在任何应用程序中都非常重要,尤其是在具有内存和其他硬件和系统限制的 iOS 应用程序中。本题涉及 ARC、MRC、引用类型和值类型。


预期答案:


Swift 使用自动引用计数 ( ARC )。这在 Swift 和 Objective-C 中在概念上是一样的。ARC 跟踪对类实例的强引用,并在您将类(引用类型)的实例分配或取消分配给常量、属性和变量时相应地增加或减少它们的引用计数。它释放引用计数降至零的对象使用的内存。ARC 不会增加或减少值类型的引用计数,因为在赋值时,这些被复制。默认情况下,如果您不另行指定,则所有引用都将是强引用。


注意点:


这是每个 iOS 开发者都必须知道的!由于 iOS 应用程序中的内存管理不善,内存泄漏和应用程序崩溃非常普遍。


这个问题的进一步阅读:


4.什么是 MVC?

哦,好老的 MVC。这是 Apple 不断推给 iOS 开发人员的基本设计模式。很可能每个面试官都会问这个,不管你是申请高级职位还是初级职位。不过,您作为大四学生的回答会有所不同。


预期答案:


MVC代表模型视图控制器。这是 Apple 选择的一种软件设计模式,作为 iOS 应用程序开发的主要方法。模型代表应用数据;视图在屏幕上绘制东西;控制器管理模型和视图之间的数据流。模型和视图从不直接相互通信,而是依靠控制器来协调通信。这种设计模式被 Apple 从其最初的 SmallTalk 实现演变成其他的东西 。


iOS 应用程序中每个 Apple MVC 层的典型表示是:



MVC 是一种很棒的通用设计模式,但作为高级开发人员,您应该知道它只是视图层的一种设计模式,单独使用它会限制您的架构,并经常导致臭名昭著的“大规模视图控制器”问题。


大规模视图控制器是代码库的状态,其中许多逻辑和责任被推入不属于那里的视图控制器。这种做法会使您的代码僵化、臃肿且难以更改。还有其他设计模式可以帮助您解决这个问题,例如 MVVM、 MVP和 Coordinator。还有一些架构,例如VIPER和 RIB,专门用于扩展 iOS 代码和避免 Massive View Controller 问题。


尽管 Apple 一直告诉我们 MVC 是一切,但要更好地了解并坚持SOLID原则。


注意点:


您绝对必须知道什么是 MVC,因为它是任何 iOS 开发的基础。不过,探索替代方案和附加功能,例如 MVVM、MVP、VIPER 和 RIB。


这个问题的进一步阅读:


5.你对 Singleton 了解多少?你会在哪里使用,你不会在哪里?

Singleton 是许多 OOP 语言中常用的设计模式,Cocoa 将其视为“Cocoa 核心能力”之一。这个问题出现在面试中,以衡量您对 Singleton 的体验,或者了解您是否拥有 iOS 以外的其他方面的背景。


预期答案:


Singleton是一个类,无论您请求多少次,它都只返回一个相同的实例。


单例有时被认为是一种反模式。使用单例有多个缺点。主要是全局状态、对象生命周期和依赖注入。当您只有一个实例时,很容易直接在任何地方引用和使用它,而不是将它注入到您的对象中。这会导致代码中不必要的具体实现耦合,而不是使用接口抽象。


“Singleton”的另一个副作用是全局状态。单例通常可以实现全局状态共享,并扮演每个对象用来存储状态的“公共包”的角色。当这种不受控制的状态被某人覆盖或删除时,这会导致不可预测的结果和错误或崩溃。


注意点:


尽管在某些语言和平台中单例被认为是好的,但它们实际上是一种反模式,应该不惜一切代价避免。


这个问题的进一步阅读:


6.Delegate 和 KVO 之间有什么区别?

通过这个问题,您的面试官正在评估您对 iOS 中使用的不同消息传递模式的了解。


预期答案:


两者都是在对象之间建立关系的方法。Delegate是一种一对一的关系,其中一个对象实现委托协议;另一个使用协议定义的方法向它发送消息。KVO是一种多对多关系,其中一个对象广播一条消息,一个或多个其他对象侦听它并做出反应。KVO 不依赖于协议。KVO 是反应式编程(RxSwiftReactiveCocoa等)的 第一步和基本块


注意点:


经验丰富的开发人员应该知道两者之间的区别,以及在哪里使用它们。


这个问题的进一步阅读:


7.iOS 应用中常用的设计模式有哪些?

这个问题在所有级别职位的面试中都很常见,除了初级职位。使用 iOS 平台的开发人员应该熟悉 iOS 上常用的技术、架构和设计模式。


预期答案:


构建 iOS 应用程序时典型的常用模式是 Apple 在其 Cocoa、Cocoa Touch、Objective-C 和 Swift 文档中提倡的模式。这些是每个 iOS 开发人员都学习的模式。Apple 将它们称为“核心竞争力”设计模式。它们包括MVCSingletonDelegateObserver


注意点:


当面试官问这个问题(以一种或另一种形式)时,他正在寻找 MVC 之外的东西。因为 MVC 是首选设计模式,所以期望每个 iOS 开发人员都知道它。但是,他们想从您那里听到的是我们通常开箱即用的其他内容。


这个问题的进一步阅读:


8.除了常见的 Cocoa 模式,你还知道哪些设计模式?

这是一个高级问题,面试官在你面试高级或建筑师职位时会问这个问题。期望您了解 iOS 应用程序中使用的更多实用设计模式,而不是前面问题中涵盖的基本设计模式。准备好回忆一堆四人组模式和其他类似模式。


设计模式本身就是一个很大的话题(它们在我的书中有更好的介绍),所以在这里我将只总结那些我在 iOS 代码库中常见的内容。


预期答案:


除了常用的 MVC、Singleton、Delegate 和 Observer 模式之外,还有许多其他模式非常适用于 iOS 应用程序:Factory MethodAdapterDecoratorCommandTemplate


工厂方法用于替换类构造函数,抽象和隐藏对象初始化以便在运行时确定类型,以及隐藏和包含switch/if确定要实例化的对象类型的语句。


适配器是一种设计模式,顾名思义,它可以帮助您使一个对象的接口适应另一个对象的接口。当您尝试调整无法更改为您的代码的第三方代码时,或者当您需要使用具有不方便或不兼容的 API 的东西时,通常会使用此模式。


装饰器是另一个类的包装器,可增强其功能。它环绕着你想要装饰的东西,实现它的接口,并将发送给它的消息委托给底层对象,或者增强它们或提供它自己的实现。


命令是一种设计模式,您可以在其中实现一个对象,该对象表示您想要执行的操作。该操作可以有自己的状态和逻辑来执行它所做的任务。这种设计模式的主要优点是您可以对用户隐藏操作的内部实现,您可以为其添加撤消/重做功能,并且您可以在稍后的时间点(或根本不)执行操作而不是立即创建操作。


模板是一种设计模式,其主要概念是拥有一个基类,该基类概述了需要完成的工作的算法。基类有几个抽象方法,需要由它的具体子类来实现。这些方法称为钩子方法。模板方法类的用户仅使用实现算法步骤的基类进行交互;这些步骤的具体实现由子类提供。


注意点:


当您刚开始使用 iOS 平台时,仅坚持使用 MVC、单例、委托和观察者模式是没问题的,但是对于高级的东西,您需要更深入地研究更抽象和更高级的东西,例如四人组 OOP 设计模式。它们非常有用,可以使您的代码库更加灵活和可维护。


这个问题的进一步阅读:


9.解释和展示 SOLID 原则的例子?

SOLID 原则是相对古老但非常有用的概念,可以应用于任何语言的任何 OOP 代码库。观看鲍勃叔叔关于该主题的一些演讲,以充分了解他们背后的历史。


在 YouTube 上:Bob Martin 面向对象和敏捷设计的 SOLID 原则


不幸的是,SOLID原则本身就是一个很大的话题(它们在我的书中也有更好的介绍),所以在这里我将只给出它们的概述。


预期答案:


SOLID 代表单一职责原则开放/封闭原则Liskov 替换原则接口隔离原则依赖倒置原则。这些原则相互补充和支持,是您可以为代码采用的最佳通用设计方法之一。让我们来看看它们中的每一个。


**单一职责原则(SRP)**是团队中最重要的原则。它指出每个模块应该只有一个更改的责任和理由。SRP 从小的具体和特定案例开始,例如一个类和/或一个只有一个目的并且仅用于一件事的对象。


**开放/封闭原则 (OCP)**规定您的模块应该对扩展开放,但对修改关闭。这是听起来很容易的事情之一,但当您开始思考它的含义时,有点难以理解。实际上,这意味着在编写代码时,您应该能够通过使用接口、抽象和依赖注入实现对象的继承、多态和组合来扩展对象的行为。


**Liskov 替换原则 (LSP)**指出,程序中的对象应该可以替换为其子类型的实例,而不会改变该程序的正确性。这意味着当您从类或抽象类继承或实现接口(协议)时,您的对象应该是可替换和可注入的,无论您使用哪个接口或类的子类。这个原则通常被称为契约设计,或者在 Swift 社区的后期,被称为面向协议的编程。这个原则的主要信息是你不应该违反你的接口从承诺到实现的子类的约定,并且通过子类化,这些子类可以在以前使用超类的任何地方使用。


**接口隔离原则 (ISP)**说,许多特定于客户端的接口比一个通用接口要好。它还指出,不应强迫任何客户端依赖和实现它不使用的方法。这意味着当你创建你的类实现的接口(协议)时,你应该争取并依赖抽象而不是特异性,但直到它成为一种浪费,你必须实现一堆你的新类没有的方法甚至使用。


**依赖倒置原则 (DIP)**指出,“依赖于抽象,而不是具体化。” 展示此原则的最佳示例是依赖注入 (DI) 技术。使用依赖注入技术,当你创建一个对象时,你在它的初始化或配置时提供和注入它的所有依赖项,而不是让对象为自己创建或获取/找到它的依赖项。


注意点:


SOLID 原则是良好的 OOP 设计的基石。应用这些原则将帮助您构建更好、更易于维护的软件。如果您正在申请 iOS 高级职位,强烈建议您精通它们。


这个问题的进一步阅读:


10.在 iOS 上实现存储和持久化有哪些选择?

面试官问这个问题是为了让你了解你有哪些工具和方式可以在 iOS 上存储和持久化数据。


预期答案:


通常有以下几种方式来存储数据,从简单到复杂的顺序:


  • 内存中的数组、字典、集合和其他数据结构

  • NSUserDefaults/钥匙串

  • 文件/磁盘存储

  • 核心数据,领域

  • SQLite


内存中的数组、字典、集合和其他数据结构非常适合中间存储数据,或者如果不需要持久化数据。


NSUserDefaults/Keychain 是简单的键值存储。一个是不安全的,另一个是安全的。


文件/磁盘存储是一种使用NSFileManager向/从磁盘写入数据(序列化或非序列化)的方式


Core Data Realm 是简化数据库工作的框架。


SQLite 是一个关系型数据库,当你需要实现复杂的查询机制而 Core Data 或 Realm 不会削减它时,它是很好的。


注意点:


您应该了解在 iOS 上存储数据的不同方式及其优缺点。不要将自己局限于一种您习惯的解决方案(例如 Core Data)。知道什么时候一个比另一个更可取。


这个问题的进一步阅读:


11.哪些选项可用于 iOS 上的网络和 HTTP?

如今,每个应用程序都使用网络从 API 和其他外部资源获取数据。许多应用程序在未连接到互联网时是无用的。每个 iOS 开发人员都应该知道他们可以使用什么来构建应用程序的服务/网络层。


预期答案:


在 iOS 中有几种实现HTTP网络的选项。您可以使用旧的NSURLSession,但除非您将其抽象得足够好,否则使用它可能会令人生畏。另一种选择是在它周围使用包装器库。iOS 上最流行的解决方案是Alamofire


一般来说,如果您有一个小团队,您可能希望依赖开源解决方案,例如 Alamofire,它为您抽象出大量样板代码;但是如果你在一个大团队中并且可以节省资源,你会希望对数据如何传入/传出服务器有更多的控制权,并使用 NSURLSession 自己实现它。


高级开发人员应该记住,在 iOS 应用程序中构建网络层不仅意味着处理 HTTP 请求,还意味着实现您的代码所做的与此相关的整套任务:HTTP 网络、数据序列化和数据映射。


注意点:


现在,NSURLSession 和 Codable 是 iOS 上用于网络的两种主要技术,但了解开源解决方案(例如 Alamofire)也是有益的。


这个问题的进一步阅读:


12.如何以及何时在 iOS 上序列化和映射数据?

数据序列化是构建 iOS 应用程序时的一项常见任务。面试官问这个问题是想看看你是否知道它适合哪里,是否知道处理数据时所需的任务,无论是网络还是存储数据。


预期答案:


有两种最常见的场景需要在 iOS 应用程序中序列化和映射数据:在网络层接收或发送数据(例如 JSON 或 XML 或其他东西),以及在存储层(NSData)中持久化或检索模型,NSManagedObject)。


每次您从后端 API 接收 JSON 或 XML 或任何其他响应类型的响应时,您很可能会以 JSON 或二进制或其他“不方便”的格式获得它。要处理收到的数据,您需要做的第一件事是将其序列化为您的应用程序可以理解的内容。在最简单和基本的层面上,这将是一个字典或一个包含来自该响应的其他字典、数组和基元的对象数组。NSJSONSerialization 负责解决这个问题。下一步是将该数据映射到应用程序的域模型中。这些将是应用程序其余部分要使用的模型对象或结构。您可以手动完成,也可以使用CodableApple 提供的协议或使用 Mantle 或 SwiftyJSON 等库。数据和序列化/映射的流程是:binary data->json-> NSDictionary/NSArray-> your domain model objects


同样,在存储层中,您需要将数据序列化并映射到您的自定义域模型对象和从您的自定义域模型对象映射到您的存储理解的格式。读取数据的“映射”链:db-> raw data format-> custom domain models; 和写作:custom domain models-> raw data format-> db。您将在这里使用 NSManagedObject 或 NSCoding 或 Codable 协议来实现这一点。


注意点:


这里的主要危险信号是没有意识到在使用 iOS 应用程序的网络和存储层时需要进行这些数据操作。事情不会“自动”发生,使用原始 NSDictionaries 也不合适且可维护。


这个问题的进一步阅读:


13 在 iOS 上布局 UI 的选项有哪些?

当您需要在 iOS 上解决不同的 UI 挑战时,了解在屏幕上布置内容的选项至关重要。这个问题有助于衡量您如何在屏幕上放置和对齐视图的知识。在回答这个问题时,你至少应该提到 CGRect、Fframes 和 AutoLayout 和 SwiftUI,但最好提到其他选项,例如 Texture (ASDK)、ComponentKit 和其他 Flexbox 和 React 在 iOS 上的实现。


预期答案:


在屏幕上布置视图的首选选项是旧的 CGRect Frames 和 AutoLayout。框架以及自动调整大小的遮罩,过去在 iOS 6 之前使用过,现在不是首选选项。框架太容易出错且难以使用,因为很难计算各种设备的精确坐标和视图大小。


从 iOS 6 开始,我们有了 AutoLayout,这是当今的首选解决方案,也是 Apple 更喜欢的。AutoLayout 是一种技术,可帮助您以声明方式定义视图之间的关系(称为约束),让框架计算 UI 元素的精确框架和位置。


在 iOS 13 中,Apple 引入了一种布局视图的新方法 - SwiftUI,这是一种声明式方法,支持使用 Combine 进行 FRP(功能反应式编程)数据绑定。FRP 和声明式 UI 并不是新概念,但 SwiftUI 和 Combine 是 Apple 支持它的新框架。SwiftUI 的声明性质允许您非常简洁地声明您的 UI 元素,然后通过数据绑定声明 UI 的哪些部分,例如文本标签,以更新哪些数据模型更改。实际上,它允许你做以前用 RxSwift 已经可以做到的事情,但现在用 Apple 框架。


布局视图还有其他选项,例如 ASDK(Texture)、ComponentKit 和 LayoutKit,其中一些或多或少受到 React 的启发,而另一些则以不同的方式解决布局异步性。这些替代方案在某些情况下非常有用,例如,您需要构建高度动态且快速的表视图和集合视图。AutoLayout 并不总是完美的,知道有其他选择总是好的。


注意:我们将在未来看到 SwiftUI 如何证明自己解决复杂的 UI 问题和复杂的异步 UI 布局问题,在撰写本文时,它是一项非常新的技术。


注意点:


至少不要提到 AutoLayout 以及框架很难正确的事实,这对你的面试官来说是一个危险信号。如今,除非有必要(例如,当您进行疯狂绘图时),否则没有理智的人会进行 CGRect 框架计算。


这还不是危险信号,但请提及 SwiftUI,这可能是 Apple 在未来几年推动我们的目标。


这个问题的进一步阅读:


14.如何优化动态大小的表或集合视图的滚动性能?

面试中与 UITableView 问题一起的重要问题之一是关于滚动性能。


预期答案:


滚动性能是 UITableViews 的一个大问题,而且通常很难做到正确。主要难点是单元高度计算。当用户滚动时,每个下一个单元格都需要计算其内容和高度才能显示。如果您进行手动框架视图布局,那么它的性能会更高,但挑战在于正确计算高度和大小。如果您使用 AutoLayout,那么挑战是正确设置所有约束。但即使是 AutoLayout 本身也可能需要一些时间来计算单元格高度,并且您的滚动性能会受到影响。


滚动性能问题的潜在解决方案可能是:


  • 自己计算单元格高度

  • 保留一个用内容填充的原型单元格并使用它来计算单元格高度


或者,您可以采取完全激进的方法,即使用不同的技术,例如 ASDK(纹理)。ASDK (Texture) 专为具有动态内容大小的列表视图而设计,并针对在后台线程中计算单元格高度进行了优化,使其具有超强的性能。


这个问题的进一步阅读:


15.你将如何在 iOS 上执行异步任务?

如今,多线程是任何客户端、面向用户的应用程序的重要组成部分。这个问题可以在网络环境中提出,也可以作为关于 GCD 或异步开发的独立问题提出。


预期答案:


现在在 iOS 上,异步任务的首选解决方案是 NSOperations 和 GCD 块。Grand Central Dispatch 是一种与多个后台队列一起工作的技术,这些队列反过来确定哪个后台线程处理工作。主要的是,这是从你那里抽象出来的,这样你就不必担心了。NSOperation 是 GCD 之上的 OOP 抽象,它允许您执行更复杂的异步操作,但是您可以使用 NSOperations 实现的所有操作都可以使用 GCD 完成。许多 Cocoa 框架在底层使用 GCD 和/或 NSOperations(例如 NSURLSession)。


有使用第三方库的帮助处理异步工作的替代方法。最著名的是 Promises (PromiseKit)、RxSwift 和 ReactiveCocoa。RxSwift 和 ReactiveCocoa 尤其擅长建模需要在后台完成并在线程之间协调的时间和工作的异步性质。


注意点:


每个 iOS 开发人员都应该了解的有关异步工作的基础知识是 GCD 和 NSOperations。RxSwift 和 Promises 是高级概念,但高级开发人员应该知道它们。


这个问题的进一步阅读:


16.你如何管理依赖关系?

依赖管理是每个 iOS 项目中的一项重要任务。这个问题衡量您对问题及其解决方案的理解。


预期答案:


几年前,我们在 iOS 上没有任何依赖管理器,不得不将第三方代码复制粘贴和拖放到我们的项目中或使用 Git 子模块。随着我们的代码库和依赖项的增长,这些方法被证明是难以管理的。


现在我们有其他依赖管理器可供选择:CocoaPods、Carthage 和 Swift Package Manager。


到目前为止,最具统治力和最强大的是CocoaPods。我是本着 Ruby Bundler gem的精神构建的,它本身就是一个 Ruby gem。它的工作方式是安装 gem,Podfile在项目的根目录中创建,声明要使用的 pod(库),然后运行pod install. 而已。


使用Carthage,您可以创建一个名为的依赖声明文件,Cartfile但与 Cocoapods 不同的是,您需要进行 Xcode 项目设置才能使其工作。


Swift Package Manager是任何 Swift 项目依赖管理的未来,但它只支持库和框架,不能用于生成 iOS 目标,尽管 iOS 目标可以依赖于 SPM 构建的模块。


注意点:


每个 iOS 开发人员都应该了解为什么将第三方库复制粘贴到您的代码库中会导致维护噩梦,因为多个库可能依赖于另一个库的两个不同版本,从而导致不匹配以及编译和运行时问题。


这个问题的进一步阅读:


17.你如何在 iOS 上调试和分析代码?

没有人会写出完美的代码,开发人员需要调试他们的代码并分析应用程序的性能和内存泄漏。


预期答案:


在 iOS 应用程序中 总是有NSLogging 和printing。您可以使用 Xcode 设置断点。对于单个代码段的性能,您可以使用 XCTest 的 measureBlock。


您可以使用Instruments. Instruments 是一种分析工具,可帮助您分析应用程序并在运行时查找内存泄漏和性能问题。


这个问题的进一步阅读:


18.你有 TDD 经验吗?你如何在 iOS 上进行单元和 UI 测试?

尽管从历史上看,iOS 社区在 TDD 上并不大,但由于工具的改进和其他社区(例如很久以前接受 TDD 的 Ruby)的影响,它现在变得越来越流行。


预期答案:


TDD 是一种技术和学科,您首先编写失败的测试,然后再编写使它们通过的生产代码。测试驱动生产代码的实现和设计,帮助您只编写通过测试实现所需的代码,不多也不少。该学科起初可能令人生畏,您不会立即看到这种方法的回报,但如果您坚持下去,从长远来看,它会帮助您更快地前进。它在帮助您进行重构和代码更改方面特别有效,因为在任何给定时间,您都有测试的安全网来告诉您是否有问题发生,或者在您更改时一切是否仍然正常。


最近,Apple 对 XCTest 框架进行了改进,使我们的测试更容易。他们还对 Xcode (XCUITest) 中的 UI 测试进行了大量改进,因此现在我们有一个很好的编程界面来与我们的应用程序交互并查询我们在屏幕上看到的内容。或者,您可以使用 KIF、iOSSnapshotTestCase、EarlGrey 等框架。


关于单元测试,也有多种选择,但最流行的两个是 XCTest 和 Quick 和 Nimble。


XCTest 是由 Apple 构建的类似 xUnit 的测试框架。这是他们推荐使用的,它与 Xcode 的集成度最高。


Quick 是一个类似于 RSpec 的 BDD 框架,可帮助您根据行为而非“测试”来描述规范/测试。RSpec 的粉丝非常喜欢它。


Nimble 是一个匹配器库,可与 XCTest 或 Quick 一起使用以断言您的测试/规范中的期望。


注意点:


越来越多的团队和公司采用 TDD,它已成为 iOS 开发过程中的重要组成部分。如果您不想被抛在后面,请加入它并学习如何测试驱动您的代码。


这个问题的进一步阅读:


19.mocks、stubs 和 fakes 之间有什么区别?

随着测试在 iOS 世界中成为一种更加突出和重要的实践,在编写测试时了解自己在做什么很重要。您的测试代码与您的应用程序代码一样重要。此问题衡量您对用于辅助单元测试的对象的测试术语的理解。


预期答案:


不同的人有多种调用和分类测试对象的方式,但最常见的测试对象可以按以下方式分类:mocks、stubs 和 fakes。


Fakes 是任何类型的 mock、fake、stub、double 等的通用总称。就其本身而言,它们通常没有实现,仅满足它们所替代的类型的接口 API 要求。


stubs 是假的,它做了一些有意义的工作,这些工作是测试中涉及的对象运行所必需的,但除此之外没有其他用途。它们不能代替真实的生产对象,但可以返回存根值。他们不能断言。


mocks 是可以判定真假。Mocks 被用来代替其他对象,就像假的一样,但它们本身记录了一些数据,例如方法调用的数量或传递给测试的变量数量,以便稍后进行断言。


注意点:


许多开发人员错误地将任何测试对象称为 mocks,但是测试对象有一个特定的不同命名法,指示每个测试对象的目的。作为一名高级开发人员,您不仅要编写测试,还应该知道如何维护它们以及您的应用程序代码库。


这个问题的进一步阅读:


20.您是否进行 Code review 或者 Pair programming?

尽管有很多应用程序是由单独的开发人员构建的,但应用程序的复杂性不断增加,需要一个开发人员团队来开发。在团队中工作在代码维护、协作和知识共享方面带来了不同的挑战。


预期答案:


Pair programming 是一种实践,其中两个开发人员在同一台机器上一起处理相同的任务(希望不要共享相同的屏幕和键盘并拥有两套自己的)。目标是在生成代码的地方促进协作、讨论、代码审查和 QA。这个过程使知识转移和架构讨论成为日常事务,防止人们孤立并成为代码特定部分的“专家”(当那个人离开或生病时会发生什么?)。它还提高了代码质量,因为在编写代码时,有两组眼睛在查看代码。这个过程同时发生在两个开发者身上,有时被称为同步。


结对编程并不适合所有人,如果人们的个性不匹配,则可能是一个令人筋疲力尽的过程。尽管如此,它仍然是软件开发中最有效的协作技术之一。


Code review 是一个类似的协作和知识转移过程,但与结对编程不同,它不会同时发生,因此是异步的。通过代码审查,在开发人员编写一段代码或功能后,团队中的其他人会查看它。审阅者检查代码是否有意义并建议进行更改和重构以改进它。这开启了关于代码的在线或离线讨论,这很棒。这会将有关该代码段的知识传递给其他团队成员,并有助于尽早发现错误和设计异味。


代码审查是一种参与较少的协作类型,它实现的结果与结对编程的结果大致相同。这也是一种同理心的练习,您可以向他人提供有关他们工作的反馈。


这个问题的进一步阅读:


21.什么是 FRP(Functional Reactive Programming)及其在 iOS 平台中的地位?

函数式反应式编程 (FRP) 是 iOS/Swift、JavaScript 和其他开发社区的新热点。除了它实际上不是那么新。期待这个关于 Swift 特性的问题,或者作为一个更大的架构和概念讨论问题。


预期答案:


函数式反应式编程 (FRP) 是一种声明式编程范式,它结合了函数式编程和反应式(异步数据流编程)范式。它是一种声明式编程风格,您可以在其中声明您的代码做什么,而不是说明它是如何做的。FRP 的反应式组件允许我们引入和描述时间的概念,这在纯函数式编程中很难使用。FRP 帮助我们处理用户输入和 iOS 应用程序的一般异步特性;用户输入发生在某个时间点,网络将在未来某个时间完成,等等。


FP 和 FRP 依赖于 map、reduce 和 filter 等高阶函数,它们以函数为参数并返回其他函数,这使得它们具有高度的可组合性。


Swift 没有对 FRP 的原生支持,但是有两个优秀的库实现了函数式响应式编程概念并使我们可以轻松使用它们:ReactiveCocoa 和 RxSwift。


在 iOS 13 中,Apple 还宣布了一个内置于 iOS 中的新 FRP 框架,名为 Combine。Combine 实际上是一个类似于 RxSwift 的 FRP 框架实现。它有两个优点:它与 SwiftUI 集成,允许将 UI 元素绑定到数据更改,并且它是 Apple 内置和支持的。缺点是:它不如 RxSwift 成熟,而且 Apple 对其进行更改和添加的速度会很慢。


注意点:


FRP 在 iOS 应用程序中变得越来越普遍,并且随着 Apple 对这种编程范式的官方支持和 Combine 的支持,FRP 将被更多地使用。iOS 开发人员应该开始接受它。


这个问题的进一步阅读:


22.你知道哪些 iOS 架构有这么大的规模?

这个问题可能会在面试一家拥有庞大 iOS 开发团队的大公司时被问到。iOS 应用程序变得越来越复杂,MVC 设计模式不能很好地支持大规模应用程序架构。对于老年人、主管、架构师等来说,这是一个非常高级的问题。


预期答案:


MVC、MVVM、MVP 和类似的设计模式都很棒,而且每一种都是彼此的改进,但对于超过 10 或 20 人的团队,它们仍然不能很好地扩展。如果您超出了该团队规模,则需要使用更通用和可扩展的架构方法。有这样一种概念方法,称为清洁架构。


Clean Architecture 是一个概念性的规模应用架构,可以简单地描述为“洋葱分层架构”。主要思想是使依赖项向内指向域逻辑和域模型,并保持其他所有内容可插入和可选(存储数据、呈现 ui、接收或发送网络请求的方式等)。对于 100 多名开发人员的大型团队,这种架构的扩展性特别好。


在 iOS 上有两个具体的 Clean Architecture 实现:VIPER 和 RIBs。


毒蛇代表视图、交互器、演示者、实体和路由器。这些是该架构的构建块。在这种架构中,一切都以路由器开始,以视图结束。每个 VIPER 堆栈(意味着一组视图、交互器、展示器、实体和路由器)是应用程序的一个屏幕或一个逻辑 UI 部分。要导航和使用 VIPER 堆栈,您需要实例化它的路由器,然后要求它创建它的视图控制器。路由器创建一个视图控制器、一个相应的表示器,用于为视图格式化数据并接收视图的用户输入,一个包含业务逻辑并与演示器通信的交互器,以及交互器工作所需的实体。然后 VC 拥有 Presenter,Presenter 拥有 interactor,interactor 拥有实体和路由器。生成的视图控制器在您的视图层次结构中使用,并根据需要插入、推送或呈现。由于您的应用程序的每个部分现在都是一个 VIPER 堆栈,因此该架构允许针对团队规模进行强大的逻辑封装和可扩展性。


RIBs 代表路由器、交互器、构建器。RIBs 是 Clean Architecture 的另一种实现,它是对 VIPER 的改进。在 RIB 体系结构中,主要构建块是一个 RIB,一组一个路由器、一个交互器和一个带有可选视图和展示器的构建器。没有视图的 RIB 称为无头 RIB。就像在 VIPER 架构中一样,您使用路由器从一个 RIB 路由到另一个 RIB,并将您的应用程序的整个运行时构建为具有父级和子级 RIB 的树结构。由于视图是可选的,与 VIPER 不同,您的应用程序树结构可能会也可能不会模仿您的视图层次结构。


Builder 负责为交互器、路由器以及组装和初始化它们的视图/展示器获取或创建依赖项。


路由器负责导航到特定的子 RIB。


Interactor 负责所有业务逻辑并使用路由器启动路由。


Presenter 和视图通常组合在一个视图控制器中,其中 Presenter 负责对数据进行按摩和格式化以在视图中显示。


View 负责在屏幕上显示数据并收集用户输入。


这个问题的进一步阅读:


结论

这篇文章中涵盖的问题涉及 iOS 开发人员应该了解的广泛主题。这绝不是一个全面的清单。这些问题基于《iOS 面试指南》一书所做的研究。


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

文末推荐:iOS 热门文集

用户头像

iOSer

关注

微信搜索添加微信 mayday1739 进微信群哦 2020.09.12 加入

更多大厂面试资料进企鹅群931542608

评论

发布
暂无评论
2021- iOS开发者一份你一定会被问到的面试题(附参考答案)