tableview工厂是异构列表的有用工具

介绍 (Introduction)

As an iOS developer, it is very common to face situations where you must deal with collections to display multiple content widgets in the same screen. I'm talking about tableviews and collection views. They are very useful to handle different contents that should be displayed as a list or a some kind of grid UI structure.

作为iOS开发人员,经常遇到必须处理集合才能在同一屏幕上显示多个内容小部件的情况。 我说的是表视图和集合视图。 它们对于处理应显示为列表或某种网格UI结构的不同内容非常有用。

Apple really did a fantastic way to feed tableviews(and collection views) by giving us the power to define exactly which item should be filled in a given row and section, how many items does the table have, which height by each cell, how should a section identified by a given index be customised, etc. All you need is an object that implements UITableViewDataSource and UITableViewDelegate protocols defining the internal behaviour of your table view.

Apple确实提供了一种神奇的方式来馈送表格视图(和集合视图),这使我们能够准确地定义应在给定的行和节中填充哪些项目,表格中有多少项目,每个单元格的高度,应该如何填充。您需要做的是一个对象,该对象实现UITableViewDataSourceUITableViewDelegate协议,这些协议定义表视图的内部行为

Respectively, the protocols described above care about what is the content to be displayed with which appearance and what should happen when some predefined events are triggered in our tableview(such as a cell was tapped at an index path, a cell disappeared or maybe the table just bounced).

上面描述的协议分别关心在表视图中触发某些预定义事件(例如,在索引路径中轻击单元格,单元格消失或表可能出现时)要显示的内容,外观以及应该发生的情况。刚刚弹跳)。

This framework works good when you have a totally homogeneous collection of cells just displaying analogous instances of some kind of data, because you just need a list to be accessed in each index and map to the a tableview position at an index path:

当您具有完全同质的单元格集合仅显示某种数据的相似实例时,此框架会很好用,因为您只需要在每个索引中访问一个列表并映射到索引路径的tableview位置即可:

Image for post
Basic structure of a UITableView
UITableView的基本结构

As you can see in the image, a UITableView can consume the content of other indexed data structures like arrays and multidimensional arrays to display in its UI. The given tableview has the exact same number of rows in its single unique sections as the array "array" and each cell(which are default UITableViewCell instances) has the element of the array correspondent of its index path. The same for the heights that are taken from the "heights" array to map each cell's height.

如您在图像中看到的,UITableView可以使用其他索引数据结构(例如数组和多维数组)的内容来显示在其UI中。 给定的tableview在其唯一的唯一部分中具有与数组“ array”完全相同的行数,并且每个单元格(它们是默认的UITableViewCell实例)都具有与其索引路径相对应的数组元素。 从“ heights”数组获取以映射每个单元格高度的高度相同。

This model works fine to homogeneous tableviews, as each method only uses an index path and a tableview to determine its info, but what about if we had to display different types of cell in a single table view? If each set of cells has a different source of information? That would be complicated, as long as we need to code nested "ifs" to check an index path and determine which type of UITableViewCell should be filled in that position.

该模型对于同构的表视图非常有效,因为每种方法仅使用索引路径和表视图来确定其信息,但是如果我们必须在单个表视图中显示不同类型的单元格呢? 是否每个单元格都有不同的信息源? 只要我们需要对嵌套的“ if”进行编码以检查索引路径并确定应在该位置填充哪种类型的UITableViewCell,那将很复杂。

I know you were excited when you first learned about tableviews because you thought it would be simple as that, but in real life, you may deal with a lot of complex screens that use tableviews to display lots of different contents. It is time to learn about some architecture to build a simple way of building a tableview exactly with the types of cell and data you are supposed to display. Fortunately, i am here to teach you a great solution I learned while working in a bank app: the UITableView factory pattern.

我知道您初次了解表视图时会感到很兴奋,因为您认为那样简单,但是在现实生活中,您可能会处理许多使用表视图显示许多不同内容的复杂屏幕。 现在是时候学习一些体系结构,以构建一种简单的方法来精确构建表格视图,并准确地使用您应该显示的单元格类型和数据类型。 幸运的是,我在这里教您一个在银行应用程序中学习到的出色解决方案:UITableView工厂模式。

There are some protocols I will teach you in this tutorial, but the basic idea is to delegate all the UITableView protocol methods to a single object that will have an array of sections, also defined as protocols, each one also having an array of objects that shall each one create a tableview cell. The creation of the array of sections is delegated to an object known as the Factory.

在本教程中,我将教您一些协议,但是基本思想是将所有UITableView协议方法委托给一个对象,该对象将具有一组节,也定义为协议,每个节也具有一组对象,这些对象每个人都应该创建一个表格单元格。 段数组的创建委托给一个称为Factory的对象。

Well, enough of talking, let's talk about the special protocols we are aiming in this tutorial which guarantee the flexible building of an heterogeneous tableview:

好了,足够多的讨论,让我们谈谈本教程中针对的特殊协议,这些协议可确保灵活构建异构表视图:

TableViewCellBuilderProtocol (TableViewCellBuilderProtocol)

This protocol corresponds to the most basic data structure which must instantiate an UITableViewCell according to its index path and makes its setup. It is responsible for defining the particular properties of a tableview cell such as its heigh. The builder must also implement a method for registering the UITableViewCell subtype to its respective tableview(s).

该协议对应于最基本的数据结构,该结构必须根据其索引路径实例化UITableViewCell并进行设置。 它负责定义表格视图单元格的特定属性,例如其高度。 构建器还必须实现一种方法,用于将UITableViewCell子类型注册到其各自的tableview中。

Please, take a look at its appearance:

请看一下它的外观:

Image for post

Note that we have three mandatory methods:

请注意,我们有三种强制性方法:

  1. registerCell: takes the respective type of the tableview cell we are dealing and registers in a tableview

    registerCell :获取我们要处理的表格单元格的相应类型,并在表格视图中注册

  2. cellHeight: returns the height the cell in case must have

    cellHeight :返回单元格必须具有的高度

  3. cellAt: creates the tableview cell dequeuing from a tableview with an index path

    cellAt :创建具有索引路径的tableview单元从tableview出队

It is important to mention that a cell builder is only meant to be an interface to that cell, so, it only builds everything we need to see that cell in the tableview. Each builder is associated with only with a cell type.

值得一提的是,单元格生成器仅是该单元格的接口,因此,它仅构建我们需要在tableview中查看该单元格的所有内容。 每个构建器仅与一个单元格类型相关联。

Let me illustrate with an example:

让我用一个例子来说明:

Image for post

This builder was built in one of my projects, which works with a tableview listing characters. Note that it has an image URL and a name for presenting the character and a height property to be the cell height. The builder registers its associated UITableViewCell in the tableview and when instantiating the cell, it makes its setup before returning it. It is the basic mechanism of a TVCBuilder.

这个构建器是在我的一个项目中构建的,该项目使用列出字符的表格视图工作。 请注意,它具有图像URL,用于表示字符的名称和作为单元格高度的height属性。 生成器将其关联的UITableViewCell注册到表视图中,并在实例化单元格时在返回之前进行设置。 它是TVCBuilder的基本机制。

TableViewSectionProtocol (TableViewSectionProtocol)

As the name tells, this protocol is responsible for a tableview section data source. It must tell us about how a section is built and which kind of cells it must have. It must have an array of cell builders, which can be totally heterogeneous and every time we want to retrieve a cell or a cell's property which comes from a builder, we retrieve it having an index path.

顾名思义,此协议负责tableview部分的数据源。 它必须告诉我们有关如何构建节以及必须具有哪种单元格的信息。 它必须具有一组单元格生成器,它们可以是完全异构的,并且每当我们要检索一个单元格或来自一个生成器的单元格属性时,我们都会检索具有索引路径的单元格。

Image for post

See that each tableview section which implements this protocol is composed by an array of cell builders and other properties describing how we see this section UI on the device screen. Here we have a bunch methods that we usually access when defining a tableview section in a UITableViewDataSource instance.

看到实现此协议的每个tableview部分均由一系列单元格构建器和其他属性组成,这些属性描述了我们如何在设备屏幕上查看此部分UI。 在这里,我们有一堆方法,当在UITableViewDataSource实例中定义tableview节时,通常可以使用这些方法。

For a better notion what i am talking about, let's define the most basic type of a tableview section bellow:

为了更好地理解我在说什么,让我们定义一个下面的tableview部分的最基本类型:

Image for post

We created a BaseSection type, which implements the TVSectionProtocol. As you can see, this is supposed to only hold the builders of tableview cells and when requested, retrieve specific information a cell through its builder and index path.

我们创建了一个BaseSection类型,该类型实现了TVSectionProtocol。 如您所见,这应该仅包含tableview单元格的构建器,并且在被请求时,通过其构建器和索引路径检索单元格的特定信息。

We can split those methods into two different categories:

我们可以将这些方法分为两个不同的类别:

  1. Header information: A tableview section may have a header view which defines some appearance to that section(Like a title or something like that). We have two methods to define that header: headerView, which returns a UIView corresponding to the header and heightForHeader, defining its height. As you can see above, or BaseSection does not have a header as we are returning nil to its view and 0 to its height

    标头信息:表视图部分可能具有标头视图,该标头视图定义了该部分的外观(例如标题或类似名称)。 我们有两种方法来定义该标头: headerView (它返回对应于标头的UIView)和heightForHeader (定义其高度)。 如您在上方所见,或者BaseSection没有标题,因为我们将nil返回其视图并将0返回其高度

  2. Cells information: Methods which define the cells content in this section. We have three methods: first, numberOfRows, which tells us how many cells we have by retrieving the array's size. The other two depend on an index path to access a cell's builder and retrieve its information through the builder protocol methods.

    单元格信息:在此部分中定义单元格内容的方法。 我们有三种方法:首先是numberOfRows ,它通过获取数组的大小来告诉我们有多少个单元格。 其他两个依赖于索引路径来访问单元的构建器并通过构建器协议方法检索其信息。

It is important to note that we created a mechanism that always avoid cell registering errors. As we call the register method for each builder in the section initialiser, we are always handling cells which are known by the tableview.

重要的是要注意,我们创建了一种始终避免单元注册错误的机制。 当我们在部分初始化程序中为每个构建器调用register方法时,我们始终会处理tableview已知的单元格。

TableViewOutputProtocol (TableViewOutputProtocol)

You must be used to make the tableview's own view controller the instance of its data source and delegate. Almost every developer does that, but I would rather create another type for implementing those protocols since I like to follow the SOLID principles. What i like to do is merge the two tableview protocols into a single one called TableViewOutput and then create a new type for implementing those methods for a specific tableview.

必须习惯于使tableview自己的视图控制器成为其数据源和委托的实例。 几乎每个开发人员都这样做,但是我宁愿创建另一种类型来实现那些协议,因为我喜欢遵循SOLID原则。 我想做的是将两个表视图协议合并为一个称为TableViewOutput的协议,然后创建一种新类型来为特定的表视图实现这些方法。

Take a look at what I did:

看看我做了什么:

Image for post

I defined a new type named TableViewOutput, which implements both UITableViewDelegate and UITableViewDataSource. The DefaultTVOutput that we created above must handle all the tableview delegate events and at the same time describe the content of its sections and cells.

我定义了一个名为TableViewOutput的新类型,该类型同时实现UITableViewDelegateUITableViewDataSource 。 我们在上面创建的DefaultTVOutput必须处理所有tableview委托事件,并同时描述其节和单元格的内容。

The data about a specific section is retrieved by accessing the section through the indexPath.section and the data about a section's cell is defined by accessing the section and then the builder of that cell through the indexPath.row.

通过访问indexPath.section来访问有关特定节的数据,并通过访问该节,然后通过indexPath.row来访问该节的构建器来定义有关节的单元格的数据

建立我们的TableViewFactory (Building our TableViewFactory)

With all this we created a hierarchy for our architecture:

有了这些,我们为架构创建了一个层次结构:

Image for post
Architecture diagram
架构图

The tasks sequence shall be:

任务顺序应为:

  1. The UIViewController, which holds a UITableView must create a tableview factory giving as parameters the tableview, the data models to be filled in the cells, and any kinds of delegates the cells must have to notify their interactions.

    拥有UITableView的UIViewController必须创建一个tableview工厂,该工厂将tableview,要填充到单元格中的数据模型作为参数,并指定单元格必须通知其交互作用的任何类型的委托。
  2. The factory creates the sections through its method buildSections defined in its protocol

    工厂通过其协议中定义的方法buildSections创建节
  3. When creating a section, the factory must send the tableview cell builders in its initialiser.

    创建节时,工厂必须在其初始化程序中发送tableview单元格生成器。
  4. When being initialised, the section instance register all the cells associated with the builders.

    初始化时,节实例将注册与构建器关联的所有单元格。
  5. When the data source with the sections and cells is finally done, it is sent to the tableview output by the view controller. Don't forget to define the DefaultTableViewOutput instance as the delegate of your tableview.

    当包含节和单元格的数据源最终完成时,视图控制器将其发送到tableview输出。 不要忘记将DefaultTableViewOutput实例定义为表视图的委托。

We haven't defined the core of our factory yet, it would be like that:

我们还没有定义工厂的核心,就像这样:

Image for post
Image for post

Observe that the only needed method is buildSections. Everything else is defined as a private method or computed variable defining fixed sections or builders to be accessed by the section builder. In this factory we have one single section which is composed by the character builders and loading builders. The parameters of the factory are a character model array which shall feed the builders, a selected index, the tableview and some cell constants to be sent to the builders. It is an old project of mine which I won't discuss details now. Which is really important is the building process of a tableview.

观察到,唯一需要的方法是buildSections 。 其他所有内容都定义为私有方法或计算变量,用于定义固定的节或由节构建器访问的构建器。 在这个工厂中,我们只有一个部分,由角色构建者和加载构建者组成。 工厂的参数是一个字符模型数组,该数组应提供给构建器,选定的索引,表格视图和一些要发送给构建器的单元常量。 这是我的一个老项目,我现在不讨论细节。 真正重要的是表视图的构建过程。

Now that the factory has created all the data source our tableview will consume, we need to send the sections array to the tableview output, which will define exactly the shape of our tableview:

现在工厂已经创建了我们的表视图将使用的所有数据源,我们需要将sections数组发送到表视图输出,这将精确定义表视图的形状:

Image for post

As you can see, the two methods that are called in sequence create the sections through the factory and send it to the default output assigning it as the tableview output. Now everything is ready to be displayed on the screen

如您所见,依次调用的两个方法在工厂中创建了各个部分,并将其发送到默认输出,并将其分配为tableview输出。 现在一切准备就绪,可以在屏幕上显示了

结论 (Conclusion)

In this article we described about a very important architecture to making easy to create heterogenous tableviews by defining some core protocols and some retrieving mechanisms to find exactly the kind of cell we want at the right index path. With all this, we don't need to worry about conditionals for each index path in the tableview methods. It is important to say that a collection view factory would behave in a very similar way.

在本文中,我们描述了一种非常重要的体系结构,该体系结构通过定义一些核心协议和一些检索机制以在正确的索引路径中准确找到所需的单元格类型,从而易于创建异构表视图。 有了这些,我们不必担心tableview方法中每个索引路径的条件。 重要的是要说集合视图工厂的行为将非常相似。

I hope you enjoyed, and if you are interested in seeing how I built my characters project, leave your clap here. See ya ;)

我希望您喜欢,如果您有兴趣了解我如何构建我的角色项目,请在这里保持鼓掌。 拜拜 ;)

翻译自: https://medium.com/@pedroalvarez_29395/tableview-factories-an-useful-tool-for-heterogeneous-lists-600db092dbca

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值