在 Swift 3 上对视图控件实践面向协议编程

简介: 本文讲的是在 Swift 3 上对视图控件实践面向协议编程,你可能听人说过,学到了知识却缺失了行动就好比人长了牙却还老盯着奶喝一样。那好,我们要怎样开始在我的应用中实践面向协议编程
本文讲的是在 Swift 3 上对视图控件实践面向协议编程,

学习如何对 buttonlabelimageView 创建动画而不制造一串乱七八糟的类

你可能听人说过,学到了知识却缺失了行动就好比人长了牙却还老盯着奶喝一样。那好,我们要怎样开始在我的应用中实践面向协议编程? :thinking:

为了能更加高效的理解下面的内容,我希望读者能够明白 Complection Handlers,并且能创建协议的基本实现。如果你还不熟悉他们,可以先查看下面的文章和视频再回来接着看:

前景提要:

看完这篇文章你会学到这些内容

你将会明白如何使用协议给 UIButtonUILabelUIImageView 等 UI 组件添加动画,同时我也会给你演示传统方法和使用 POP 方法之间的差异。 :sunglasses:

UI

这个演示程序名为「欢迎来到我家的聚会」。我将会使用这个应用程序来验证你是否获得邀请,你必须输入你的邀请码。这个应用并没有逻辑判断,所以只要你按下按钮,无论如何动画都将会被执行。 将会有 passcodeTextFieldloginButton,errorMessageLabel 和 profileImageView 四个组件参与动画过程。

这里有两个动画:1. 左右晃动 2. 淡入淡出

不用担心遇到问题,现在我们干的就像写流水账一样,如果你不耐烦了,直接滑动到下面下载源代码就可以了,

我们接着来

想要完整的在应用中体验 POP 的魔力,那就先让我们和传统方式来比较一下,假设你想给 UIButton 和 UILabel 添加动画,你先将他们都子类化,再给他们添加一个方法:

class BuzzableButton: UIButton {
    func buzz() { /* Animation Logic */ }
}

class BuzzableLabel: UIButton {
    func buzz() { /* Animation Logic */ }
}

然后,在你点击登录按钮的时候让他抖动

@IBOutlet wear var errorMessageLabel: BuzzableLabel!
@IBOutlet wear var loginButton: BuzzableButton!

@IBAction func didTapLoginButton(_ sender: UIButton) {
    errorMessageLabel.buzz()
    loginButton.buzz()
}

看到我们是如何写重复的代码了吗?这个动画逻辑至少有 5 行,更好的选择是使用 extension,因为 UILabel 和 UIButton都继承自 UIView,我们可以给它添加这样的扩展:

extension UIView {
    func buzz() { /* Animation Logic */ }
}

然后,BuzzableButton 和 BuzzableLabel 就都有了 buzz 方法。现在,我们不用再写重复的内容了。

class BuzzableButton: UIButton { }
class BuzzableLabel: UIButton { }

@IBOutlet wear var errorMessageLabel: BuzzableButton!
@IBOutlet wear var loginButton: BuzzableLabel!

@IBAction func didTapLoginButton(_ sender: UIButton) {
    errorMessageLabel.buzz()
    loginButton.buzz()
}

那好,为什么要用 POP?  :thinking:

正如你锁看到的,errorMessageLabel 将会显示 "Please enter valid code  :joy: ",并且具有淡入和淡出效果,在传统形式下我们会怎么做?

有两种方式来完成这一步。首先,你可以再向 UIView 添加一个方法

// Extend UIView
extension UIView {
    func buzz() { /* Animation Logic */ }
    func pop() { /* UILabel Animation Logic */ }
}

然而,如果我们把方法添加到 UIView,那么不光是 UILabel,其他所有 UI 组件都将会拥有 pop 这个方法,继承了不必要的函数让它变得过于臃肿了。

而另一种方式则是创建 UILabel 的子类:

// Subclass UILabel
class BuzzableLabel: UILabel {
    func pop() { /* UILabel Animation Logic */ }
}

这样是可用的,我们可能会希望将类名改成 BuzzablePoppableLabel 来更清晰的声明它的用途。

现在,如果你想给 UILabel 添加更多的方法,你就要再次给他起个新名字比如BuzzablePoppableFlashableDopeFancyLovelyLabel,这恐怕不是一个可维护的方案,我们可能需要想想别的方法。

面向协议编程

看到这里还没给文字点赞吗?动动手指点个赞然后继续往下看吧

我们受够了各种子类了,让我们先来创建一个协议,让他抖动起来。

我并没有在这里写动画代码,因为它很长,并且 gist 在移动设备上支持不佳

protocol Buzzable {}

extension Buzzable where Self: UIView {
    func buzz() { /* Animation Logic */ }
}

任何 UI 组件只要遵循 Buzzalbe 协议就能拥有 buzz 方法,与直接给 UIView 添加 extension 不同,只有遵循协议的类才会拥有这些方法。另外,where Self: UIView 表示只有 UIView 或者从 UIView 继承的组件才能够遵循这个协议。

现在,我们将 Buzzable 应用给了 loginButtonpasscodeTextFielderrorMessageLabel 和 profileImageView。等等,那 Poppable 呢?

看起来差不多的:

protocol Poppable { }

extension Poppable where Self: UIView {
    func pop() { /* Pop Animation Logic */ }
}

是时候动真格的了!

class BuzzableTextField: UITextField, Buzzable { }
class BuzzableButton: UIButton, Buzzable { }
class BuzzableImageView: UIImageView, Buzzable { }
class BuzzablePoppableLabel: UILabel, Buzzable, Poppable { }

class LoginViewController: UIViewController {
    @IBOutlet weak var passcodTextField: BuzzableTextField!
    @IBOutlet weak var loginButton: BuzzableButton!
    @IBOutlet weak var errorMessageLabel: BuzzablePoppableLabel!
    @IBOutlet weak var profileImageView: BuzzableImageView!

    @IBAction func didTabLoginButton(_ sender: UIButton) {
        passcodTextField.buzz()
        loginButton.buzz()
        errorMessageLabel.buzz()
        errorMessageLabel.pop()
        profileImageView.buzz()
    }
}

POP 是一件很酷的事情,你可以在任何时间把这个协议应用给任何一个 UI 组件都不需要再去子类化任何东西。

class MyImageView: UIImageVIew, Buzzable, Poppable { }

现在,你可以更加灵活的给类来命名,因为你已经知道它遵循了哪些协议,并且每个协议的名称就能很清晰的描述它在干什么。所以你不会再有 MyBuzzablePoppableProfileImage 这样的东西。

TL;DR

少用子类

灵活的类名

就像一个 Swift 开发者一样

下一步

一旦我这篇文章(译注:指英文原文)获得超过 200 个 like,并且你想了解如何将 POP 运用在 UITableView 和UICollectionView 中,请关注我的 Medium。

资源

源代码

Last Remarks

我想希望你已经学到了一些新知识,如果有的话,请给本文点赞。如果你觉得本文内容很有用,请将本文分享给大家,以便世界各地的 iOS 开发者都能运用面向协议编程,以在写视图控件的时候写更少和更清晰的代码。回顾于 EST 时间星期六上午 8 点。

Swift 会议

Andyy Hope ,我的一个朋友,目前正在组织在澳大利亚墨尔本最大的 Swift 会议之一 ———— Playground,我只是想让大家都知道这个。 有来自市值亿万美元公司的讲者,比如 Instagram,IBM,Meet Up,Lyft,Facebook,Uber。 在这里 网站 你可以了解到更多信息。

https://twitter.com/playgroundscon

Shoutout

感谢大家给我的支持:

我本周在韩国首尔遇见了 David,他在蓝牙上需要一些帮助,我喜欢说...「 :fearful: ,让我试试」。

即将开课

我目前正在制作一个课程,和 Bob 一起在 Udemy 上教 UIKit 基本原理,这个课程是为中级 Swift 开发者设计的,目前还没有完成。自上个月以来已经有超过 180 个读者给我发邮件,如果你也想加入我们那就给 bobleesj@gmail.com 发邮件吧,直到课程发布前都是免费的。

辅导

如果你正需要帮助来成为一个 iOS 开发者或者创建你喜欢的应用来帮助大家,请联系我活动更多的细节。





原文发布时间为:2017年2月8日

本文来自云栖社区合作伙伴掘金,了解相关信息可以关注掘金网站。
目录
相关文章
|
6月前
|
Swift iOS开发
Swift 语言: 什么是协议(Protocol)?如何实现和使用协议?
Swift 语言: 什么是协议(Protocol)?如何实现和使用协议?
192 2
|
算法 Swift C++
34 Swift为了协议 关联类型
Swift为了协议 关联类型
72 0
|
存储 Swift iOS开发
31 Swift 继续聊聊协议扩展
Swift 继续聊聊协议扩展
108 0
|
13天前
|
存储 Swift 开发者
Swift 协议
Swift 协议
23 0
|
6月前
|
设计模式 Swift iOS开发
【Swift开发专栏】Swift中的协议与委托模式
【4月更文挑战第30天】Swift编程语言强调协议与委托模式。协议定义了类型需实现的方法和属性,如`SomeProtocol`示例。遵循协议的类、结构体或枚举需实现协议要求。协议可继承,也可作为类型使用。委托模式让对象间通信更灵活,通过协议实现,如`DataSourceDelegate`示例。实战案例展示了在`UITableView`和自定义下载器中使用委托模式。
122 0
|
4月前
|
存储 安全 Swift
Swift高级特性:泛型与协议
【7月更文挑战第10天】Swift高级特性:泛型与协议增强代码复用与类型安全。泛型允许编写通用代码,如`swap`函数和泛型`Stack`结构体,支持类型约束如`Comparable`。协议定义行为蓝图,类型遵循协议需实现其要求。通过两者结合,构建高效灵活的代码结构。
|
6月前
|
安全 算法 Swift
【Swift开发专栏】Swift中的泛型编程
【4月更文挑战第30天】Swift的泛型允许开发人员创建可重用的组件,操作多种数据类型,无需针对每种类型编写特定代码。本文分为三部分:1) 泛型基本概念,包括类型参数、泛型函数和类型;2) Swift中的泛型实现,如类型推断、关联类型和泛型约束;3) 泛型编程最佳实践,如明确使用场景、选择有意义的类型参数名称和避免过度泛化。通过理解并应用这些概念,开发者能编写出更灵活、安全和高效的代码。
59 2
|
6月前
|
Swift 图形学 iOS开发
【Swift开发专栏】Swift中的自定义视图与绘制
【4月更文挑战第30天】本文探讨了Swift中自定义视图的创建与绘制,分为基础知识、绘制步骤和性能优化三部分。开发者通过继承`UIView`,重写`draw(_:)`方法并利用Core Graphics进行2D绘图。提高性能的技巧包括避免重复绘制、使用轻量级视图、优化图形上下文使用、启用图层背板及避免阻塞主线程。自定义视图让iOS和macOS界面更独特高效,进阶可探索Core Animation和Metal等技术。
80 0
|
6月前
|
JSON IDE Swift
Swift语言的实践编程
Swift语言的实践编程
70 3
|
Swift C++ Ruby
32 Swift面向协议编程初探
32 Swift面向协议编程初探
71 0