博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用协议作为可组合扩展
阅读量:6177 次
发布时间:2019-06-21

本文共 4242 字,大约阅读时间需要 14 分钟。

今天我们将会谈论使用协议作为我们的视图控制器的可组合部分。协议和协议扩展是我第二喜欢的Swift的特性,仅次于可选值。它帮助我们创建高可用的可组合与可重用的代码,而不需要继承。多年来,我们一直使用继承作为黄金编程标准。但是它真的好么?让我们看一下一个简单的BaseViewController,我们在每一个文件中都使用它。

import UIKitclass BaseViewController: UIViewController {    private let activityIndicator = UIActivityIndicatorView(style: .whiteLarge)    override func viewDidLoad() {        super.viewDidLoad()        view.addSubview(activityIndicator)        activityIndicator.translatesAutoresizingMaskIntoConstraints = false        NSLayoutConstraint.activate([            activityIndicator.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor),            activityIndicator.centerYAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerYAnchor)            ])    }    func presenActivity() {        activityIndicator.startAnimating()    }    func dismissActivity() {        activityIndicator.stopAnimating()    }    func present(_ error: Error) {        let alert = UIAlertController(title: error.localizedDescription, message: nil, preferredStyle: .alert)        alert.addAction(.init(title: "Cancel", style: .cancel))        present(alert, animated: true)    }}复制代码

上面的代码看起来非常的简单易用,因为大部分的ViewController在从因特网下载数据需要活动指示器,并且在数据下载的过程中出现错误时需要进行错误处理。但是我们并不止于此,并且我们在一段时间内往BaseViewController添加越来越多的特性。在拥有了非常多通用目的的函数后,它变得非常的臃肿。这里我列出了两个主要的问题:

  1. 我们的BaseViewController在同一个地方实现了所有的特性,打破了单一职责原则。过了一段时间后,它将变得非常的臃肿,这会变得难以理解,并且难以进行覆盖测试。
  2. 在我们的app中,所有的ViewController都继承自BaseViewController,并且使用所有这些功能。假如有个bug在BaseViewController,那么我们的app的所有ViewController都会有这个bug,即使ViewController没有使用这个BaseViewController的错误功能。

使用协议来救援

协议扩展特性是在Swift 2.0版本的时候发布的,并且携带了非诚强力的协议类型,它声明了一种新的变成范式:面向协议编程。我建议你去看WWDC的关于协议与协议扩展的。

让我们回到我们的主题。协议怎么能帮助我们解决问题?让我们开始声明一个ActivityPresentable协议来呈现和消失一个活动指示器。

protocol ActivityPresentable {    func presentActivity()    func dismissActivity()}extension ActivityPresentable where Self: UIViewController {    func presentActivity() {        if let activityIndicator = findActivity() {            activityIndicator.startAnimating()        } else {            let activityIndicator = UIActivityIndicatorView(style: .whiteLarge)            activityIndicator.startAnimating()            view.addSubview(activityIndicator)            activityIndicator.translatesAutoresizingMaskIntoConstraints = false            NSLayoutConstraint.activate([                activityIndicator.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor),                activityIndicator.centerYAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerYAnchor)                ])        }    }    func dismissActivity() {        findActivity()?.stopAnimating()    }    func findActivity() -> UIActivityIndicatorView? {        return view.subviews.compactMap { $0 as? UIActivityIndicatorView }.first    }}复制代码

我们提取presentActivity和dismissActivity方法到一个特定的协议类型中。对于采用此协议的Type为ViewController的情况,我们通过协议扩展来添加默认的实现。它给我们一个可以在我们的协议中使用ViewController的方法和属性的机会。

让我们为错误处理逻辑做相同的操作。

protocol ErrorPresentable {    func present(_ error: Error)}extension ErrorPresentable where Self: UIViewController {    func present(_ error: Error) {        let alert = UIAlertController(title: error.localizedDescription, message: nil, preferredStyle: .alert)        alert.addAction(.init(title: "Cancel", style: .cancel))        present(alert, animated: true)    }}复制代码

现在我们有了两个可重用的协议类型,它们都遵守单一职责原则。我们可以为任何需要这些功能的ViewController添加这个扩展。好的事情是我们可以为需要的ViewController添加单一的扩展,并且不用继承所有的BaseViewController的功能。下面是使用这些协议的例子:

class ViewController: UIViewController {    override func viewDidLoad() {        super.viewDidLoad()        presentActivity()    }}extension ViewController: ActivityPresentable, ErrorPresentable {}复制代码

另一个机会是我们可以轻易的去忽略协议的默认实现,去为某些ViewController实现我们自定义的视图指示器。让我们看下面这个例子:

class CustomViewController: UIViewController {    override func viewDidLoad() {        super.viewDidLoad()        presentActivity()    }}extension CustomViewController: ActivityPresentable {    func presentActivity() {        // Custom activity presenting logic    }    func dismissActivity() {    }}复制代码

当为CustomViewController实现ActivityPresentable协议的时候,我们指定presentActivity和dismissActivity方法的自定义实现。

小结

就像你看到的那样,我们可以将协议用作ViewController类型的简单扩展。在未来的文章中,我们将会继续使用协议去为ViewController构建可重用的模块。我们将会接触可关联的类型和条件一致性功能,以便为ViewController开发更通用的基于数据的扩展。

转载地址:http://fszda.baihongyu.com/

你可能感兴趣的文章
我的友情链接
查看>>
利用logrotate切割nginx日志
查看>>
McAfee EPO迁移
查看>>
vsftp如何配置虚拟用户实现不同用户拥有不同权限和不同目录
查看>>
cisco 开启 snmp
查看>>
第一篇
查看>>
SQL Server 2012 安装
查看>>
Nginx配置:负载均衡和SSL配置
查看>>
复选框checkbox全选与否js
查看>>
我的友情链接
查看>>
Office文档,pdf文档转swf
查看>>
新博客 新开始
查看>>
苹果新一代iPad被指"过热" 测评报告5天后发布
查看>>
linux系统结构
查看>>
如何解决你的电脑不断地弹出MSVBVM50.dll。
查看>>
常用的bundles清单
查看>>
我的友情链接
查看>>
01—Shell脚本基础
查看>>
java-快速排序法
查看>>
我要把写博客当成一种习惯
查看>>