Moya入门

Moya是一个Swift网络抽象库。 它为我们提供了一种无需直接与Alamofire进行通信即可进行网络呼叫的抽象方法。 通过本教程,我们将学习如何开始使用框架,发现一些技巧和窍门以及从代码示例中学到所有基础知识。

让我们首先讨论为什么不使用 Moya:

  1. 它为您的项目引入了依赖性。 项目的成功部分取决于Moya的稳定性。
  2. 有更多原因使您不想使用Moya,但它们都是第一点的衍生副作用。 您应该始终考虑为任何项目添加依赖项的成本。 要更深入地分析为什么最好在Swift中从头开始构建自己的API管理器,请帮个忙,并阅读Matteo Manferdini撰写的精彩文章。

刚开始使用Cocoapods时,我以为找到了一些开发人员的超能力。 我最终意识到,了解事物的实现方式比拥有库中的超级代码更为重要。 这就是您提高开发人员技能的方式。 Moya背后没有一些与服务器通信并返回JSON的黑魔法代码!

如果我们允许别人去思考,我们将失去力量和收缩的能力。 —艾伦·怀特

为什么您会选择Moya:

  1. 立即设置API管理器。
  2. 干净的代码和最佳实践。
  3. 专注于应用程序的核心功能,而不是网络。
  4. 易于为单元测试添加网络响应。
  5. 了解如何使用流行的Swift网络库。 您是否曾在工作岗位上看到“使用REST API的最佳实践和知名库的经验”? 我一定有

使用Moya这些和其他包含的内容有很多好处,但这并不意味着用纯Swift编写网络层是困难的或不希望的。

可以使用首选的依赖安装方式来安装Moya:https://github.com/Moya/Moya#installation

提示:安装依赖项时,请始终指定库版本。 例如,如果您正在使用Cocoapods,请为您的项目指定一个特定的版本号!

  pod'Moya','10 .0.1'#撰写本文时为最新版本。 

在建立网络经理之前,我会事先建议一些设计和规划! 是的,我知道,作为开发人员,我们只想获取代码。 但是花一些时间来计划我们的工作将是值得的投资。

那么,我应该计划构建一个网络管理器吗? 没有那么多! 让我们保持简单,直到两个问题。 我总是在计划时会先提出一些需要提供答案的问题:

  1. 我将向哪些端点请求数据?
  2. 如何建模从端点返回的数据?

当回答这两个问题时,我只需简单地在笔记中列出所有端点,然后从预期的JSON创建伪代码模型。 如果您正在使用已经有文档的API,则可以使用提供的文档作为参考。 对于大多数示例,我将使用The Movie Database API🍿。

借助Swift 4的Codable协议,我们无需使用任何对象映射库或编写自定义映射器即可将JSON转换为模型。 让我们建立我们的电影模型,MovieResults模型。

电影模特

如果我们向The Movie Database API请求获取播放电影的请求,则返回的JSON响应如下所示。 通过此JSON,我们希望为两个对象MovieResultsMovie建模 我们将利用这两个结构对JSON响应进行建模。

注意事项:

  • 如果您使用的变量名称与API提供的名称不同,则需要实现CodingKey枚举。 它确切地告诉Swift如何映射JSON。

MovieResults模型

与电影模型类似,我们需要遵循可解码协议。

注意事项:

  • 在这里,我们看到Decodable甚至可以为我们映射对象数组。

创建一个枚举以容纳所有端点。 每种情况都应采用要传递给该特定端点的参数。

注意事项:

  • 为每个端点创建一个案例。
  • 当您的EndPoint需要很多参数时,情况可能会变得很冗长和丑陋。 您可以通过传递字典来保持整洁:
  //首先导入Alamofire以使用“参数” 
case endPointWithLotsOfParams(参数:参数)

我们将研究目标类型协议,构建网络管理器,依赖注入和插件。

目标类型协议

现在,您已经创建了列出所有端点的API枚举,我们需要导入Moya并遵守Target Type Protocol。 Moya的目标类型协议包含7个属性: baseUrl,path,method,sampleData,task,validate,header

让我们使MovieApi枚举符合TargetType协议。

我们使用枚举在不同环境之间切换。 这是提供在环境之间切换的功能的一种巧妙方法。 确保此属性是静态常量,因为您不希望应用程序动态切换环境。 我建议将这样的配置绑定到Xcode构建配置,而不是代码中。

baseUrl

URL的根。

红色是我们的baseURL,后面是API版本。 所以https://api.themoviedb.org/3/ 将是我们的baseURL。 在某些情况下,我们可以使用不同的baseURL进行多个环境(例如质量检查,分段和生产)。 让我们看看如何满足这两种情况。

当我们有一个baseURL时,它很简单。 创建一个带有字符串的URL到baseURL并返回一个URL。 URL(字符串:字符串) 返回一个可选的URL,因此我们解开该值并在得到nil时抛出错误。 让我们看一下处理多个环境的配置。

创建一个名为NetworkManager的Swift文件 然后 创建一个枚举,该枚举将为我们可能拥有的每个环境提供一个案例。 接下来,创建一个结构,该结构将具有我们的提供程序和环境的静态实例。

注意事项:

  • 我们的网络管理器是一种值类型的结构。
  • 由于我们不希望该文件之外的任何人直接访问提供者,因此我们将提供者设为私有。

路径

路径最好用Moya自己的代码来描述。 通过按“选项”,然后单击path属性,Xcode将为您提供一个弹出框。

方法

用于特定端点的HTTP请求方法的类型。 Moya为我们提供了执行所有CRUD操作所需的所有HTTP请求方法。

有时,您只需要使用GET方法即可。 在这种情况下,无需打开“自我”。 不必要时,请勿使用开关盒。 您可以返回get

当您执行其他方法时,需要打开self。 确保为每个请求提供正确的方法。 将删除请求发送到API的getter方法时,您会看到漂亮的错误和意外行为。

小费:

  • 使用Moya.Method,因为有时Xcode找不到Method命名空间。

样本数据

为了提供测试数据。 在编写单元测试时,您的应用程序永远不应与API通信。 您需要单独测试您的应用程序。 这就是为什么您需要提供sampleData的原因。 我个人喜欢将生产代码和测试代码分开,因此我为我的sampleData创建了一个单独的文件,还为每个端点创建了单独的JSON文件。

在MovieAPI + Testing内部,我将拥有我的sampleData和一个从StubbedResponses组中的JSON文件返回JSON数据的方法。

从我们的JSON文件创建存根响应。

小费:

要在Xcode中创建JSON文件,只需CMD + N,然后选择空文件并命名,最后添加“ .json”即可。

任务

不同的API期望数据以不同的方式提供给他们。 您可以在task属性中进行处理。 每个任务中的参数可以通过各种方式发送。

  1. requestPlain —当请求不需要任何其他数据时使用。 例如一个简单的获取请求。
  2. requestData —当请求期望数据在请求的正文中传递时使用。
  3. requestJSONEncodable-当请求需要一个JSON可编码对象,而第2个需要Data时使用。
  4. requestParameters 当您要传递参数并定义自己的编码类型时使用。 (看下面的例子)
  5. requestCompositeData 用于当您希望将Data作为请求主体传递并且同时传递urlParameters时。
  6. requestCompositeParameters 与5号相同,但取而代之的是参数。
  7. downloadParameters 顾名思义,它用于下载并在需要时传递参数。
  8. uploadCompositeMultipart 用于上传带参数的多部分。

验证

Alamofire使用此属性来验证响应。 默认情况下将其设置为false,因此不会验证响应。 您可以使用它来验证您得到的响应是否与标题中期望的相匹配。 验证还用于确认响应状态代码。 有关更多信息,您可以查看“甚至”那个。

标头

您通过HTTP发出的每个请求都有标头。 有关标题的更多信息,请阅读本文。

我们需要创建一个可联网协议。 该协议定义了您的经理需要的所有属性和方法。

创建您的NetworkManager。 正如Moya文档所建议的那样,请为您的Manager使用一个结构。

小费:

  • Moya有一个请求方法,可以返回进度块。 使用此属性和进度视图,您可以轻松地在应用程序中实现漂亮的加载器。

依赖注入

很多时候,开发人员编写网络层时,都会使用可以在任何地方访问的单例类将其公开给ViewController。 这曾经是一种糟糕的做法,甚至我也参与其中。这种方法的问题是您的代码与网络管理器紧密耦合,几乎无法测试。 单例很难测试,相信我,我已经尝试过了。 那么,如何将网络管理器放入ViewController? 依赖注入! 我们只需创建一个Network Manager实例,然后将其传递给需要它的ViewController。

在这里,我们创建一个提供程序并将其传递给我们的MainViewController。 MainViewController 需要一个提供程序( 取决于提供程序),因此我们注入 )网络提供程序的实例。

使用这种实现时,您可以完全控制注入的NetworkManager对象。 使代码更少耦合,更易于测试!

注意事项:

  • 我们传递一个类型为Networkable的对象。 这样,我们可以传入实现此协议的任何对象。
  • 通过使用Networkable,我们可以轻松创建模拟并将它们传递给此类。

外挂程式

Moya已经带有一些您可以使用的漂亮插件。 我喜欢利用networkLoggerPlugin,它只是将所有网络活动记录在控制台上。

  let provider = MoyaProvider (插件:[NetworkLoggerPlugin(详细:true)]) 

更改您的提供程序实例,使它看起来像上面的实例,您的应用程序的网络流量将被记录到控制台。 您可以将其他插件添加到提供商中。 您甚至可以编写自己的自定义插件。 有关插件的更多信息 这里。

总而言之,使用Moya可以归结为创建符合TargetType协议的枚举。 Swift枚举和面向协议的编程的结合可以实现令人惊奇的事情。 通过此实现,我们可以清晰地定义清晰的网络层,任何新开发人员都可以一目了然地阅读和理解。

希望您喜欢阅读。 也许我说服您在下一个项目中试用Moya。 您更喜欢使用网络库还是自己编写代码? 🤔请在评论中分享您的想法。

一些随机的有趣事实:
莫亚语 恰好是 祖鲁语中的 “精神”, 这是南非11种官方语言之一。

参考文献:

Moya的Github官方页面