Structure your UITableView better with structs and enums in Swift

IMG_0424.PNG

Structure your UITableView better with structs and enums in Swift

26 Août, 2015
Frédéric ADDA
, ,
9 comments

For my first post, I wanted to present a technique I use a lot when building a UITableViewController in Swift, but which I haven’t seen used by many other people very often.

Background

This technique was inspired by this years’s edition of the legendary Stanford CS193p on iTunes U (presented by the just as legendary Paul Hegarty) : iTunes U – Developing iOS 8 apps with Swift, and by this M2M site which for years now has specialized on giving unofficial solutions to the assignments (I suppose that Stanford students have a chance of having their work corrected, but there is no « official » solution to the assignments for the iTunes U followers). In this course, the 4th assignment dealt specifically with table views. Namely, one of the requirements was:

While you might be tempted to deal with this with large if-then or switch statements in your UITableViewDataSource and navigation methods, a cleaner approach would be to create an internal data structure for your UITableViewController which encapsulates the data (both the similarities and differences) in the sections. For example, it’d be nice if numberOfSectionsInTableView, numberOfRowsInSection , and titleForHeaderInSection were all “one-liners”.

 

Context

Indeed, this requirement reminded me of an app that I have been developing for years and improving a bit at every new iOS release: ZEN Portfolio. Basically, this is a stocks manager that I wanted to be both very simple and very efficient. One of the most important features is that it gives you in your currency the gain or loss for a given share, taking into account both the stock quote and the currency rate if the stock is quoted in a currency different from yours.

General view of your stocks

General view of your stocks

 

The interesting part is here: for a given stock, I wanted to detail the calculation process. So when you tap on a cell of the stock list, you get pushed to another Table view controller, which looks like this:

Detail view of a stock

Detail view of a stock

This table view contains the following sections:

  1. General (number of shares and purchase date)
  2. Share price (purchase / current price)
  3. Stock valuation in the stock currency (purchase cost / current stock value)
  4. Currency rate (purchase / current rate) *
  5. Stock valuation in the user’s currency (purchase cost / current stock value)
  6. Finally, the gain or loss for the stock (value / %)

* should appear only if the stock currency is different from the user’s currency.

 

What does that little footnote means ? Well, let’s suppose you are a US citizen and wish to follow an AAPL stock. There is no currency conversion here, so in that case, there would only be 5 sections (section 4 for currency would not appear here). But if you are, say, a French citizen who happens to buy AAPL stock, then your gain or loss is maybe more dependent on the currency rate than on the stock variation itself. In that case, you would see all 6 sections.

 


In Objective-C

This is what my Table view data source methods would look like up to iOS 7:

number Of  Sections:

 

number Of Rows In Section:

Getting a bit ugly …

 

cell For Row At Index Path:

Sorry, but I really have to paste that here, for the sake of the demonstration …

 

See the issue there? At one point, I needed to add into that kind of stuff:

if (the indexPath.section is x AND the stock currency is different from the user’s portfolio currency) OR (the indexPath.section is x-1 AND the stock currency is the same as the user’s portfolio currency)

That’s ugly, repetitive coding, and very error-prone (you can trust me on this).

 


In Swift

So, what exactly did Paul Hegart mean when he wrote:

Don’t forget about Swift features like enum. Use Swift to its fullest.

I think he had in mind something like this:

 

  1. First, create an Enum for each section and each item that you would like to populate in your table view
  2. Then create a Struct to describe a section

    That means that each section has a type, and includes a list of items.
  3. Finally, create a var for the sections

     

Now let’s build the table structure:

I created the table structure in the didSet of my public property « stock », but you could do that in viewDidLoad: as well.

Notice how readable that is now.

 

What do our data source functions become?

number Of  Sections:

One-liner, as promised.

 

number Of Rows In Section:

Again, one line of code.

 

titleForHeaderInSection

I add this one here, just to show that I created my Section struct with a type, in order to handle section titles in a very simple way.

 

 

cell For Row At Index Path:

This method is the core of the table view display, so it’s still quite long. But it’s really simple to implement.

And the most obvious advantage is that now, I don’t have to manage the order of the sections or the number of cells here. Everything is defined by my sections var. If I wanted to change the order of my sections, or add new items in a section, it would take me 10 seconds.

Note also that, although in this case a unique reusable cell is « dequeued » at the beginning of the function, this model is perfectly compatible with  different types of cells. For that you could just dequeue a different cell type (different subclass of UITableViewCell, different reuse identifier) in each « case » declaration.

In that case and many others, I can confirm that Swift made my code more elegant, more simple, and more reliable.

I hope this technique will help you improve your table view structure, too!

9 Comments


Warning: call_user_func() expects parameter 1 to be a valid callback, function 'green-lantern_comment' not found or invalid function name in /home/novaera/www/wordpress/wp-includes/class-walker-comment.php on line 180

    Warning: call_user_func() expects parameter 1 to be a valid callback, function 'green-lantern_comment' not found or invalid function name in /home/novaera/www/wordpress/wp-includes/class-walker-comment.php on line 180

Warning: call_user_func() expects parameter 1 to be a valid callback, function 'green-lantern_comment' not found or invalid function name in /home/novaera/www/wordpress/wp-includes/class-walker-comment.php on line 180

Warning: call_user_func() expects parameter 1 to be a valid callback, function 'green-lantern_comment' not found or invalid function name in /home/novaera/www/wordpress/wp-includes/class-walker-comment.php on line 180

Warning: call_user_func() expects parameter 1 to be a valid callback, function 'green-lantern_comment' not found or invalid function name in /home/novaera/www/wordpress/wp-includes/class-walker-comment.php on line 180

Warning: call_user_func() expects parameter 1 to be a valid callback, function 'green-lantern_comment' not found or invalid function name in /home/novaera/www/wordpress/wp-includes/class-walker-comment.php on line 180

Warning: call_user_func() expects parameter 1 to be a valid callback, function 'green-lantern_comment' not found or invalid function name in /home/novaera/www/wordpress/wp-includes/class-walker-comment.php on line 180

Warning: call_user_func() expects parameter 1 to be a valid callback, function 'green-lantern_comment' not found or invalid function name in /home/novaera/www/wordpress/wp-includes/class-walker-comment.php on line 180

Warning: call_user_func() expects parameter 1 to be a valid callback, function 'green-lantern_comment' not found or invalid function name in /home/novaera/www/wordpress/wp-includes/class-walker-comment.php on line 180

leave A Comment

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *