2020年面向高级开发人员的iOS面试题总结(附答案)

北城余情 提交于 2020-08-08 07:37:09

前言:

欢迎关注我的简书查看更多好文章
这是许多硅谷公司用来衡量iOS候选人资历水平的一系列问题。
这些问题涉及iOS开发的各个方面,旨在触及对平台的广泛理解。
毕竟,高级开发人员应该能够从头到尾地发布完整的iOS产品。
这绝不是一个详尽的列表,但它可以帮助你为即将到来的技术iOS面试做准备。




目录

你使用的最新版本的iOS是什么?你喜欢什么,为什么?
什么是iOS应用程序,你的代码适合哪里?
你喜欢或不喜欢什么Swift特性?为什么?
内存管理在iOS上如何处理?
你对单身人士有什么了解?你会在哪里使用一个,你不在哪里?
你能否解释一下Delegate和KVO有什么不同?
iOS应用中通常使用哪些设计模式?
你知道除了常见的可可模式外还有哪些设计模式?
你能否解释并展示SOLID原则的例子?
你有什么选择在iOS上实现存储和持久性?
你有什么选择在iOS上实现网络和HTTP?
如何以及何时需要在iOS上序列化和映射数据?
在iOS上布置UI有什么选择?
你将如何优化动态大小的表或集合视图的滚动性能?
你将如何在iOS上执行异步任务?
你如何管理依赖关系?
你如何在iOS上调试和配置文件?
你有TDD经验吗?你如何在iOS上进行单元和UI测试?
你编码审查和/或配对计划?


















在下面的章节中,我们将讨论每个问题,背后的原因,预期的答案,以及可能为面试官带来危险的答案。

1.你使用的最新版本的iOS是什么?你喜欢什么,为什么?

通常会询问这个问题,以了解如何使用Swift和iOS平台上的最新iOS技术和开发进行联系。

预期的答案:

期望的是,你至少使用了最新的稳定iOS版本。但是如果你已经玩过或甚至更新了你的应用程序,那么你会得到额外的分数。谈论iOS令人兴奋的新功能,以及为什么你喜欢它们。让团队中的开发人员对最新的iOS技术充满热情是很好的。通常情况下,充满好奇心的人可以使用新的功能提出有趣的新功能创意或想出创造性的解决方案。

注意:

如果候选人对当前稳定版本的iOS没有太多的工作或对其不感兴趣,这通常是一个不好的迹象。这意味着这个人很可能没有及时了解iOS提供的最新技术,解决方案和功能,这很可能意味着这个人会错过利用iOS系统的机会,或者更糟糕的是,他们不知道最新系统有一些新的缺陷。

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

这是一个很大的图片问题,可以通过这种或那种形式进行询问,以评估您对iOS应用程序的理解以及您编写的代码适用于iOS系统的整体情况。

预期的答案:

可能会认为我们构建的应用程序是特殊的,因为它们涵盖了一个独特的用例。但是你典型的iOS应用程序只是一个巨大的,美化的运行循环。它等待用户输入并被外部信号中断,如电话呼叫,推送通知,主页按钮按下以及其他应用程序生命周期事件。唯一的区别是,它不仅仅是一个简单的邮件循环函数,每次用户点击应用程序图标时都会启动它,它具有更高的抽象级别,UIApplication并且AppDelegate是我们开发人员的工作内容。

您为编写应用程序的业务逻辑而编写的代码的其余部分放置在由主循环委托给我们的应用程序的“触发点”中AppDelegate。这是非常多的。简单。但是,为应用程序编写的代码可以像调用方法/函数一样简单,也可以像VIPER体系结构一样复杂。你用它做什么是你的选择。

注意:

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

3.你喜欢或不喜欢什么Swift特性?为什么? 

随着最新的Swift更新,它一次又一次地证明这种语言是iOS开发的未来。这些日子里,特别是经验丰富的开发人员的期望是,您对Swift及其提供的功能非常熟悉。

预期的答案:

你可以谈论强大的语言输入和功能特点,以及你喜欢或不喜欢它们的原因。本身没有正确或错误的答案,但期望是您熟悉语言及其提供的功能(泛型,协议,选项等)。此外,你应该能够解释和争论,如果你喜欢或不喜欢这种语言的东西(我不喜欢可选的链接,因为它打破了德米特定律,例如)。

注意:

Swift正在成为iOS平台的主要稳定语言,所以现在忽略它是没有意义的。

4.在iOS中如何处理内存管理?

内存管理在任何应用程序中都非常重要,特别是在具有内存和其他硬件和系统限制的iOS应用程序中。因此,这是以某种形式提出的问题之一。它涉及ARC,MRC,引用类型和值类型。

预期的答案:

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

注意:

这是每个iOS开发人员必须知道的!内存泄漏和应用程序崩溃太常见了,原因是iOS应用程序内存管理不善。

5.你对Singletons有什么了解?你会在哪里使用一个,你不在哪里?

Singleton是许多OOP语言中常用的设计模式,Cocoa认为它是“可可核心竞争力”之一。这个问题不时出现在面试中,用来衡量你对Singletons的体验,或者看看你是否拥有背景不仅仅是iOS。

预期的答案:

Singletons是一个只返回一个和同一个实例的类,不管你请求了多少次。

有时被认为是反模式。使用时有许多缺点。两个主要的是全局状态/状态和对象生命周期以及依赖注入。当你只有一个东西的实例时,直接在任何地方引用和使用它是非常诱人的,而不是将它注入到对象中。这会导致代码中具体实现的不必要的耦合,而不是接口抽象。  “方便”另一个恶意副作用是全球状态。很多时候,可以实现全局状态共享,并扮演每个对象用来存储某个状态的“公共包”的角色。这导致不可预知的结果和错误和崩溃时,这种不受控制的状态被覆盖或被某人删除。

注意:

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

6.你能否解释代表和KVO有什么不同?

面对这个问题,面试官正在评估你对iOS中使用的各种消息模式的了解。

预期的答案:

两者都是在对象之间建立关系的方法。委托是一对一的关系,一个对象实现委托协议,另一个使用它并向它发送消息,假设这些方法是由于接收方承诺遵守协议而实现的。KVO是一种多对多的关系,一个对象可以播放一条消息,一个或多个其他对象可以听到它并作出反应。KVO不依赖协议。KVO是响应式编程的第一步和基本模块(RxSwift,ReactiveCocoa等)

注意:

一位经验丰富的开发人员应该知道两者之间的区别,以及哪一个应该用在另一个之上。

iOS应用中通常使用哪些设计模式?

这个问题是各级职位面试的常见问题,也许除了初级职位之外。基本上这个想法是,在使用iOS平台时,作为开发人员您应该熟悉iOS上常用的技术,体系结构和设计模式。

预期的答案:

构建iOS应用程序时的典型常用模式是Apple在Cocoa,Cocoa Touch,Objective-C和Swift文档中倡导的模式。这些是每个iOS开发人员学习的模式。它们包括MVC,Singleton,Delegate和Observer。

注意:

当面试官提出这个问题时(采用这种或那种形式)面试官正在寻找除MVC以外的东西。由于MVC是一种前瞻性设计模式,因此期望每个iOS开发人员都知道它是什么。但是,他们希望从您那里听到的是常用和可用的开箱即用功能。

8.除了常见的可可模式外,你知道的设计模式是什么?

面试官会在面试高级或建筑师职位时询问这个高级问题。期望的是,除了上一个问题中介绍的基本类型外,您还可以了解iOS应用中使用的更实用的设计模式。准备好回忆一堆四人帮和其他类似的模式。

不幸的是,设计模式本身就是一个巨大的话题(它们在我的书中也有更好的介绍),所以在这里我只给出一些我在iOS代码库中常见的概述。

预期的答案:

除了常用的MVC,Singleton,Delegate和Observer模式之外,还有许多其他应用程序完全适用于iOS应用程序:Factory Method,Adapter,Decorator,Command,Template等等。

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

适配器是一种设计模式,它可以帮助您(如名称所示)使一个对象的界面适应另一个对象的界面。当您尝试修改无法更改为代码的第三方代码,或者需要使用具有不方便或不兼容API的内容时,通常会使用此模式。

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

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

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

注意:

当你刚刚开始使用iOS平台时,只坚持使用MVC,Singleton,Delegate和Observer模式是很好的,但对于需要深入到像Gang of Four OOP设计模式这样更抽象和高级的东西的高级事物来说,它们非常有用,使您的代码库更加灵活和可维护。

9.你能解释并展示SOLID原则的例子吗?

SOLID原则相对比较陈旧,但却非常适用于任何语言的任何OOP代码库。观看一些关于这个话题的Bob叔叔的谈话,以充分理解他们背后的历史。

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

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

预期的答案:

SOLID代表单一责任原则,开放/闭合原则,Liskov替代原则,界面隔离原则和依赖倒置原则。这些原则是相互支持的,并且是您可以为您的代码采用的最佳通用设计方法之一。我们来看看它们中的每一个。

单一责任原则(SRP)是该组织最重要的原则。它指出,每个模块应该只有一个责任和理由要改变。SRP从小的具体和特定情况开始,例如只有一个目的的类和/或对象,仅用于一件事情。

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

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

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

依赖倒置原则(DIP)指出,“取决于抽象而不是结核”。展示这一原理的最好例子是依赖注入(DI)技术。通过依赖注入技术,当你创建一个对象时,你可以在其初始化或配置时提供并注入它的所有依赖关系,而不是让对象为自己创建或获取它的依赖关系。

注意:

固体原则是良好的面向对象设计的基础。应用这些原则将帮助您构建更好,更易维护的软件。如果您正在申请高级iOS职位,建议您熟悉这些技巧。

10.您有什么选择来实现iOS上的存储和持久性?

访问者询问这个问题,以了解您可以在iOS上存储和保存数据的工具和方式。

预期的答案:

一般来说,存储数据的方式有以下几种:从简单到复杂:

内存数组,字典,集合和其他数据结构

NSUserDefaults的/钥匙扣

文件/磁盘存储

核心数据,领域

SQLite的

内存数组,字典,集合和其他数据结构对于存储数据或者不必持久化来说都是非常好的。

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

文件/磁盘存储实际上是一种使用NSFileManager将数据片段(序列化或不存在)写入磁盘的方法。

核心数据和领域是简化数据库工作的框架。

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

注意:

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

11.您有什么选择可以在iOS上实现网络和HTTP?

几乎每个应用程序现在都在使用某种网络来从API和其他外部资源获取数据。很多应用程序在没有连接到互联网时都没用。每个iOS开发者都应该知道他们可以构建他们应用程序的服务/网络层。

预期的答案:

在iOS中有几个选项来实现HTTP网络。你可以使用旧的NSURLSession,但除非你把它抽象出来,否则使用它可能会很艰巨。另一个选择是围绕它使用一个包装库。iOS上最流行的解决方案是Alamofire / AFNetworking。

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

注意:

现在,AFNetworking和Alamofire是iOS上进行HTTP网络的事实标准,每个开发者都应该知道如何使用它们。同时,它们都基于Apple框架,并且知道NSURLSession的内部细节也是有益的。

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

数据序列化是构建iOS应用程序时需要执行的常见任务。访问者问这个问题,看看你是否认识到它适合的情况,并且知道你需要执行数据处理的任务,无论它是网络还是存储数据。

预期的答案:

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

每当您收到来自后端API的JSON或XML或任何其他类型的响应时,您最有可能以JSON或二进制或其他“不方便”的格式获取它。为了能够处理收到的数据,您需要做的第一件事就是将其序列化为应用程序理解的内容。在最简单和最基本的层次上,它将是包含来自该响应的其他字典,数组和基元的字典或对象数组。NSJSONSerialization负责处理这个(并且很快的Codable协议)。下一步是将这些数据映射到应用程序的域模型中。那些将是您的应用程序的其余部分使用的模型对象。您可以手动执行,也可以使用诸如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协议来实现这一点。

注意:

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

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

当你需要在iOS上解决不同的UI问题时,了解你在屏幕上布局的选项至关重要。这个问题有助于衡量你对如何在屏幕上放置和对齐视图的知识。在回答这个问题时,你至少应该提到CGRect框架和AutoLayout,但是在iOS上提及其他选项比如ComponentKit和其他Flexbox和React实现将是非常好的。

预期的答案:

在屏幕上布置视图的前往选项是很好的旧CGRect框架和AutoLayout。框架以及自动调整大小的遮罩在iOS 6之前已被使用,并且今天不是首选。由于很难计算各种设备的精确坐标和视图大小,因此帧太容易出错并且难以使用。

自iOS 6开始,我们推出了AutoLayout,这是目前最流行的解决方案,也是Apple喜欢的解决方案。AutoLayout是一种技术,可以用声明的方式定义视图之间的关系,称为约束,让框架计算UI元素的精确框架和位置。

还有其他用于布置视图的选项,比如ASDK(Texture),ComponentKit和LayoutKit,这些选项或多或少都受React的启发。例如,当您需要构建高度动态且快速的表格视图和集合视图时,这些替代方法在某些情况下很好。AutoLayout并不总是完美的,知道有其他选项总是好的。

注意:

至少没有提及AutoLayout,Frames的臭名昭着的难以得到的事实肯定会成为面试官的一面红旗。现在没有一个理智的人会做CGRect框架计算,除非它是绝对必要的(例如,当你做一些疯狂的绘画时)。

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

与UITableView问题一起在面试中有时会问到的一个重要问题是关于表视图滚动性能的问题。

预期的答案:

滚动性能是UITableViews的一个重大问题,往往很难得到正确的结果。主要困难是细胞高度计算。当用户滚动时,每个下一个单元需要计算其内容,然后才能显示高度。如果你做手动的框架视图布局,那么它更高性能,但挑战是让高度和大小的计算恰到好处。如果你使用AutoLayout,那么挑战就是设置所有的约束。但即使AutoLayout本身可能需要一些时间来计算单元高度,并且您的滚动性能会受到影响。

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

自己计算细胞高度

保留一个原型单元格,填充内容并用于计算单元格高度

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

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

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

预期的答案:

现在,iOS上的异步任务的解决方案是NSOperations和GCD块。Grand Central Dispatch是一种技术,它可以处理多个后台队列,后台队列又可以确定后台线程处理工作。最重要的是,这是从你身上抽象出来的,所以你不必担心它。NSOperation是GCD之上的面向对象抽象,允许您执行更复杂的异步操作,但是您可以使用GCD执行的NSOperations获得的所有内容。许多Cocoa框架使用GCD和/或NSOperations(例如NSURLSession)。

使用第三方库的帮助还有其他方法可以处理异步工作。最显着的是Promises(PromiseKit),RxSwift和ReactiveCocoa。RxSwift和ReactiveCocoa特别擅长建模时间和工作的异步性质,需要在后台完成并在线程间进行协调。

注意:

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

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

依赖关系管理是每个iOS项目的一项重要任务。这个问题被要求衡量你对这个问题的理解以及如何解决这个问题。

预期的答案:

几年前,我们在iOS上没有任何依赖管理器,必须将第三方代码复制粘贴并拖放到我们的项目中或使用git子模块。随着我们的代码库和依赖性增长,所有这些方法很快就被证明是无法管理的。

现在我们有其他的依赖管理者可以选择:CocoaPods,Carthage和Swift Package Manager(SPM)。到目前为止,最强大和最强大的是CocoaPods。它是建立在Ruby Bundler宝石的精神之上的,并且是一个Ruby宝石本身。它的工作方式是安装gem,在项目的根目录下创建Podfile,声明要使用的pods(库)并运行pod install。而已。

注意:

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

17.你如何在iOS上调试和配置文件?

没有人写出完美的代码,偶尔开发人员需要调试他们的代码和配置文件应用程序,以查找性能和内存泄漏等问题。

预期的答案:

我们可以在iOS应用程序中做到这一点,永远都有很好的NSLog成就感print。还有可以使用Xcode设置的断点。为了执行单个代码片段,您可以使用XCTest的measureBlock。

您可以使用仪器进行更高级的调试和分析。Instruments是一款分析工具,可帮助您分析应用程序并在运行时发现内存泄漏和性能问题。

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

尽管从历史上看,iOS社区在TDD方面并不算大,但由于工具的改进和来自其他社区(如Ruby)的影响力,现在变得越来越受欢迎,而Ruby等其他社区很早就接受了TDD。

预期的答案:

TDD是一种技术和学科,在您编写使其通过的产品代码之前,您首先编写失败的测试。这些测试将推动您的产品代码的实施和设计,帮助您仅编写通过测试实施所必需的代码,不多也不少。这门学科起初可能令人望而生畏,你没有立即看到这种方法的收益,但如果坚持下去,它可以帮助你从长远来看加快步伐。它在帮助你重构和修改代码方面特别有效,因为在任何时候你都有测试的安全网告诉你是否有什么东西坏了,或者在你改变的时候一切仍然正常。

最近,Apple对XCTest框架进行了改进,以使测试更轻松。他们在Xcode的UI测试中也做了很多改进,现在我们有了一个很好的编程接口来与我们的应用进行交互并查询我们在屏幕上看到的东西。或者,你可以使用像KIF这样的框架。

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

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

Quick是一种类RSpec的BDD框架,可帮助您根据行为而不是“测试”来描述您的规格/测试.RSpec的粉丝喜欢它。

Nimble是一个匹配器库,可以与XCTest或Quick一起使用,在您的测试/规格中声明期望值。

注意:

越来越多的团队和公司都接受TDD,它已经成为iOS开发过程中的重要组成部分。如果你不想被抛在后面,那就试试它,并学习如何测试你的代码。

19.你是否编码审查和/或配对计划?

尽管有很多应用程序是由独立开发人员构建的,但应用程序的复杂性却不断增加,要求开发团队在其上开展工作。在团队中工作在代码维护,协作和知识共享方面提出了不同的挑战。

预期的答案:

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

结对编程并不适合每个人,如果人物的个性不匹配,这可能是一个耗尽的过程。但它是软件开发中最有效的协作技术之一。

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

代码评审是一种较少涉及的协作类型,与对编程所获得的结果大致相同。它也是一种同情的练习,你在其他人的工作上给予他人反馈。


今天的分享到这里就结束了,欢迎各位关注我的简书查看更多好文章

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!