使用闭包的更好的编程组件

TL; DR:使用闭包在代码中创建模块化且简洁的UI组件。

有无数种方法可以在您的应用程序中实现UI组件。 使用情节提要是一种流行的选择,但是有时您会希望以编程方式对其进行布局。 在本文中,我将向您展示以编程方式构建相同UI,一个简单的登录屏幕的迭代实现。 首先,我将向您展示最简单的方法,该方法写起来快,却难以维护。 其次,我将向您展示使用私有帮助器方法的更好方法。 第三,我将向您展示使用闭包实现UI的最佳方法。 如果您以前没有使用过闭包,那么在阅读本文之后,您将很快意识到它们的强大功能!

在深入探讨编程方法之前,我想简要介绍一下Storyboard。 它们在初学者的iOS教程中无处不在,因为它们易于可视化和理解。 它们也非常强大。 您可以拖放组件,实时自定义UI组件的几乎所有方面(例如,字体大小,背景颜色),并测试UI在各种设备尺寸和方向上的外观。

但是,有时也需要部分或全部以编程方式创建UI。 对我来说,它正在与其他iOS开发人员合作,他们更喜欢仅在代码中构建UI。 在共享的iOS代码库上工作时,情节提要文件肯定会很快变得令人头疼。 在编写程序性UILabelUIButton和其他核心UI组件时,我当然想学习实现它们的最佳实践。 以下是实现简单登录屏幕的三个示例,这些示例说明了编写程序UI代码时的注意事项。

假设我们要创建此屏幕:

在这里,我们有一个标题标签,一个标题标签和两个按钮。 我们如何以编程方式做到这一点? 好吧,最简单的方法是将其全部写入viewDidLoad()

实现#1:实例化viewDidLoad()中的每个UI组件

这确实是实现此目的的最简单方法,但这就是收益的终点。 如果我想要另一个按钮怎么办? 您必须命名它并编写很多重复的代码。 如果我需要重命名标签怎么办? 然后,您必须查找并替换该名称的所有实例。 我什至没有包括布局代码,您可以很快看到它变长的时间! 不仅如此,它还会污染viewDidLoad()函数,随着项目的发展,我们希望避免使用该函数。 也许我们可以使用私人助手功能?

实施#2:私人帮手功能

现在, viewDidLoad()看起来更干净了! 我们将标签和按钮实现重构为private (限制访问)和可重用的帮助器函数(例如, createLabel(text:textColor:font:)用于创建标题和标题标签)。 这样比较好,但是仍然存在一些缺点。

首先,如果我们希望UI组件具有很多自定义项,则init参数开始变得冗长且不可扩展。 在上面的代码段中, createButton(text:textColor:font:backgroundColor:)方法具有四个输入,其中之一具有可选的默认值。 随着我们的按钮变得越来越复杂,我们想权衡可重用的帮助器功能与versus肿的万能包(乍看之下很难理解)的好处。 尽管此函数遵循DRY原理,但我们牺牲了可读性(如果添加其他参数,则线性可能将其标记为太长)。

在第三个实现中,我们将使用不同的东西: 闭包 。 闭包是封装在许多情况下弹出的功能块。 实际上,您一直都在使用闭包-函数(全局和嵌套)是一种闭包! 这只是一个更抽象的术语。 例如,闭包表达式可以存储为变量并在读取时执行。

封盖很棒,值得一读(请参阅Apple的文档)。 您可以对它们做很多事情,并使代码保持模块化。 我们将使用它们来创建我们的UI组件,我将解释为什么这是一种很好的方法:

实施#3:关闭

首先,请注意我们的viewDidLoad()现在有多简洁! 我们不再需要肿的函数调用来创建自定义按钮。 其次,请注意闭包的可读性和简洁性:每个闭包都实例化自己并以大括号形式返回。 Swift中的闭包在推断类型方面很聪明-我们在这里最大限度地利用了它们的语法糖-因此我们可以删除显式地写出闭包的类型签名所附带的样板(有关详细信息,请参见这篇文章)。 第三,我们可以轻松地重命名标签和按钮-我们要做的就是重命名变量! 第四,闭包内部的实现非常通用,可以轻松复制并粘贴到其他用例中。 随着时间的流逝,您可以构建自己的UI组件库,并将其重复用于多个iOS应用。 可能性是无止境!


我希望您了解到有关闭包的一两件事,以及为什么它们成为以编程方式创建UI组件的必经之路。 如果您想自己测试一下,我在这里提供了一个带有闭包实现的演示应用程序。 我受此博客文章的启发,因此请查看以了解更多信息。 谢谢阅读!

有关iOS开发的更多信息,请查看我在Capital One公共工程博客上的文章,标题为《 iOS使用WebKit在iOS上进行JavaScript操作》, 在Twitter上 关注我