Swinject Tutorial for iOS: 入门教程
我们通过一个简短教程来探索Dependency Injection (DI),主要介绍一款Swift语言写的框架——Swinject。
在本教程中,您将通过Swinject探索依赖注入(DI)。通过改进一个名为Bitcoin Adventurer(Bitcoin冒险家)的iOS小程序来实现这一点,该程序可以显示当前比特币的价格。在阅读本教程时,您将重构应用程序,并完成单元测试。
依赖注入(DI)是一种组织代码的方法,目的使其依赖项由其他不同的对象提供,而不是由其本身提供,通过本教程的代码演示更容易理解一些。使用依赖注入技术可以让代码耦合更松散,便于单元测试和重构。
实现依赖注入技术并不一定非要使用第三方库来实现,但是使用Swinject可以让工作更简单,即使在代码复杂度不断升高时。
为什么使用依赖注入?
依赖注入技术依赖于一种称为控制反转的原理。其主要思想是,一段需要依赖关系的代码不会为自己创建依赖关系,而是将提供这些依赖关系的控制权交给更高的抽象对象。这些依赖关系通常被传递到对象的初始化代码中。
使用了DI框架中流行的模式:依赖项注入(DI)容器。这种模式使依赖项的解析变得简单,即使代码复杂度增加。
在代码实践中,控制反转的主要好处是代码更改仍然是独立的。一个DI Container提供某些对象来支持控制主体倒置,而这些对象本身知道如何提供依赖关系。你所需要做的就是向容器请求你需要的这些对象! 听起来很难理解的样子,下面来看看代码实例。
开始吧
这里下载项目代码(链接地址 )。打开Bitcoin Adventurer.xcworkspace
,然后按Command+R运行项目。
当应用程序启动时,你会看到屏幕上显示的比特币的当前价格。点击Refresh会发出HTTP请求来检索最新的数据,这些数据被记录到Xcode控制台。比特币是一种易波动的加密货币,其价值经常波动,因此Coinbase API大约每30秒就有一个新的比特币价格可用。
您可能还注意到控制台记录了一个错误。您现在可以忽略它,因为您将在本教程的后面介绍它。
返回Xcode检查项目:
- 这个app包含一个
UIViewController
,BitcoinViewController
,在main.storyboard
中引用。 - 所有的网络层和数据逻辑层都位于BitcoinViewController.swift中。按照目前的代码,独立于UIViewController生命周期测试逻辑是很困难的,因为视图层与它的底层逻辑和依赖关系高度耦合。
- 我们已经通过CocoaPods为您添加了一个依赖项Swinject。目前它还没有在你的任何Swift文件中使用,但这即将改变!
依赖注入DI和解耦合
如前所说的依赖关系定义,就是为另一个对象完成工作的一段代码,最好是由单独的对象提供的,或者说是注入一段代码来完成依赖关系建立。
来探索下Bitcoin Adventurer
项目代码中的依赖关系。
打开BitcoinViewController.swift
,可以看到有三个主要职责:网络请求、数据解析、格式化
网络请求和数据解析
大部分网络请求任务通过一个函数requestPrice()
private func requestPrice() { |
解析代码:
创建请求Bitcoin价格的
URLRequest
。创建
URLSessionDataTask
网络请求Bitcoin价格任务。如果HTTP请求成功,会返回一段JSON格式的数据:{
"data": {
"base": "BTC",
"currency": "USD",
"amount": "15840.01"
}
}每个HTTP请求后都应该检测错误,这里也不例外。
使用JSONDecoder解析JSON数据,并map到modle对象
PriceResponse
异步传输model数据及更新UI。
格式化
BitcoinViewController
中的updateLabel(price:)
函数任务是更新Label内容,确保正确显示比特币价格,包括整数的美元及小数的美分。
总结下,一个UIViewController
内包含了不同的业务逻辑,如网络请求、数据解析、格式化,而且他们紧紧的耦合在一起。很难独立于整个BitcoinViewController
对象测试它的任何部分,也很难在其他地方重用相同的逻辑。
That doesn’t sound good – can we fix this?
对于紧密耦合的另外一面就是建立松散耦合对象,可以轻松链接,轻松解除。
是时候重构BitcoinViewController
了,以便它为网络请求和数据解析职责创建单独的对象。完成之后,您将使用Swinject调整它们的使用,以实现真正的解耦组件。
剥离依赖关系
首先创建一个名为Dependencies的新文件夹。这将保存您将在本教程其余部分中提取的所有逻辑块。右键单击Bitcoin Adventurer文件夹并选择New Group。然后将其名称设置为Dependencies。
下面开始分离业务逻辑之旅吧!让代码更利于测试,更健壮,更漂亮。
剥离网络层逻辑
在Dependencies文件夹下创建一个文件:HTTPNetworking.swift。添加以下的代码,根据注释理解代码含义。
// 1.定义Networking协议,包含一个方法request(from:completion:),返回Data或者Error |
好了,开始使用网络逻辑层代码,打开BitcoinViewController
,并在顶端三个IBOutles
下面添加如下代码:
let networking = HTTPNetworking() |
可以修改requestPrice()代码了,如下:
networking.request(from: Coinbase.bitcoin) { data, error in |
再次运行项目,依然可以正常工作。漂亮!你已经成功的剥离出网络层业务逻辑。然而为了最终的依赖注入,还有更多的解耦合要做。
剥离数据解析层逻辑
同样在Dependencies目录下建立一个文件:BitcoinPriceFetcher.swift。写入如下代码:
protocol PriceFetcher { |
注意:PriceFetcher协议定义了一个方法: 一个执行获取并返回PriceResponse对象的方法。这个“fetch”可以从任何数据源发起请求,而不一定是HTTP请求。当您开始编写单元测试时,需要Mock一些本地数据,这将成为该协议的一个重要特征。这里fetch发起的请求使用的是新创建的网络协议。
现在有个一个更具体的抽象层逻辑来获取比特币价格,是时候再出重构BitcoinViewController
来使用它了。
替换代码:
let networking = HTTPNetworking() |
为:
let fetcher = BitcoinPriceFetcher(networking: HTTPNetworking()) |
然后再出修改requestPrice()
的实现代码:
private func requestPrice() { |
现在上面的代码看上去更简洁和易读,因为把繁重的任务交给依赖项BitcoinPriceFetcher
去处理了。
再次运行项目,依然可以正常工作,恭喜你,你通过使用依赖注入技术(DI)提高了代码质量。
那么,下一篇我们一起看看单元测试。
~ END ~
- 标题: Swinject Tutorial for iOS: 入门教程
- 作者: tree_fly
- 创建于 : 2018-12-27 22:31:48
- 更新于 : 2018-12-27 22:31:48
- 链接: https://itreefly.com/posts/a457df3.html
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。