Flexible table views with descriptor arrays

综合技术 2018-02-23 阅读原文


Frequently, in our work as iOS developers, we have to present some kind of data in a table view or in a collection view. There are many ways to customise the standard Apple components by implementing the their datasource and delegate methods. Most of the time, our task comes down to implementing the required methods for how many rows the table/collection view has and how should each row in that view look like. As a datasource, we usually have an array of model objects. The length of that array determines the first requirement (number of rows) and the data in each entry determines what will be presented in each row.

However, sometimes we have to implement more advanced table views, where some combination of cells might be hidden in one state and displayed in others. In this post, we will see how we can implement this in a more elegant manner, with a very simple, but powerful trick.

The problem

Let’s say we have a requirement where we need to display information about a book. The user interface for our simple app should look something like this.

Implementing this should not be a big of a problem for any iOS developer. However, one subtle requirement changes it all – some of the info for the book might be missing . In that case, that particular row of the book should not be displayed in the table view.

The book info is stored in a simple struct, with the following information.

As you can see, the subtitle, the author’s location, the publisher, its logo and the image of the book might be missing. Maybe one of them is missing, maybe all of them or maybe none. We don’t have that information, it depends on some data we get from a server.

First try

Let’s see how we can implement this with our traditional approach when implementing table views.

We take every index path row and we check its value. If it’s zero, then we know we have to present the cell which displays the title. If it’s the first row, we check whether we have a subtitle. If we do, then we present the subtitle cell, otherwise we display the author cell. Not that cool, but we can still manage this. Now we have the second row. Here, we first need to check whether we had a subtitle in the previous row, so we know whether we should display the author cell or the one after (the publisher). We will have few extra conditions.

The further we go with the rows, the more complicated this code becomes. We should always keep track whether we had a subtitle cell, an author location cell, a publisher cell etc. Let’s do some simple math – in our simple Book struct, we have 5 optional values and each one of them can either have a value or not. This means that there are 32 possible combinations of having a value or not, that we should handle in our code.

That’s really hard to code and impossible to maintain. And if we have even more optional values, that would be even more complex.

And imagine one day that the product manager comes to you and says “Let’s put the book’s publishing year in the fourth row and the book’s number of pages in the seventh row”. As you’ve probably guessed it, adding new elements is pretty hard with this approach.

Also, think about the number of rows in the table view. You will need to have the same crazy amount of “if” statements, which will return the number of rows for each state.

Descriptor arrays to the rescue

Simplicity is the ultimate sophistication – Leonardo da Vinci.

There has got to be a better way. Code should be simple and understandable in order for it to be beautiful. Let’s see how we can fix this with one small change – changing the datasource for the table view methods .

We will first create an enumeration called Descriptor, which will define the different types of cells our table view supports.

The raw values of the enumeration will correspond to the reuse identifiers of our table view cells. Next, we will define a descriptor array, which will contain elements of this enumeration type. The array will be filled with data, based on whether there’s value for that property in the book model.

This array can have minimum 2 elements (if only the mandatory title and author are present), up to the total of five possible types of cells.

Now, let’s see how we can use this array in our table view methods.

No single “if” was found in this code! The descriptor array now determines the size of the table view. In the cellForRowAtIndexPath method, we take the descriptor and use it to dequeue the cell. Then, we abstract away the configuration of the cell in a newly created class, called CellConfigurator. Let’s see the code for this class.

Based on the value of the enumeration, we are configuring and returning the cell. For example, for the author cell, we will have the following.

Something similar needs to be done for the other types of cells as well. And basically that’s everything we needed to do in order to have flexible table view cells. Now, let’s create one book and test this.

If we run the app now, we will have something like this.

Now, try putting any of the optional values of the book to nil and re-run the app. The UI will adjust itself accordingly, by removing those cells.

Adding new types of cells is also pretty simple. You will just need to update the Descriptor enum and the loadDescriptorArray method, and possibly add another type of cell configuration in the CellConfigurator. You will not change the existing code, but just implement the new functionality. Now, you can stand firm and tell the product manager that adding the book’s publishing year in the fourth row and the book’s number of pages in the seventh row is a piece of cake.

Another benefit is that your view controllers will be pretty small, even if you are using the MVC pattern.

Source code

What do you think about descriptor arrays? Have you used them already in your apps? Do you know some other approaches that you want to share? Give me your thoughts in the comments. You can find the source code for this project here .

责编内容by:martinmitrevski 【阅读原文】。感谢您的支持!


UI issues in UITabBarController UITabBarController and rotation I'm having a real issue wi...
Manage the data (object, key&am... I want to save some object in form of collection (object,key) in objective C. I...
iOS 转场动画简单实现 (push) 先看效果 项目中有要求要用一个切换特效,研究了下发现是拿转场动画做的,所以把之前的知识重新复习下,这里提供一个简单的思路实现转场动画,具...
Spring MVC注解、标签库、国际化 本篇文章主要介绍自己在学习Spring MVC常用注解、标签库、国际化遇到的一些问题,分享给大家,希望对你有所帮助。 问题一:指定扫描包的位置 应该将所...
每周一算法2017.11.24 Longest Harmonious Subsequence We define a harmonious array is an array where ...