Working with UITableViewDelegate and UITableViewDataSource methods

iOS Tutorial: Editing TableViews

xCode 7.3 demo

Basics

  1. Declare an Array data structure
  2. numberOfSectionsInTableView
  3. numberOfRowsInSection
  4. cellForRowAtIndexPath
1. Declare an Array data structure

The table always matches an array(s) of some sort to represent data.
Each row matches up to an element in the array.

2. numberOfSectionsInTableView

The first order things is to let the table know how many sections we will represent. Each table can contain m sections.
Each sections can contain n rows. For simplicity purposes, we’ll designate only 1 section for our table.

Usually, use one array to represent one section. Each section will have n number of rows, which matches up to n number of elements in that array.

3. numberOfRowsInSection

Now, we simply specify the number of rows for each section. Each section usually represent an array, where n elements in that array
matches up to n number of rows in that section.

4. cellForRowAtIndexPath

The concept here is that the UITableView keeps a list of reusable cells.

At first, before showing the rows, it will have nothing. So dequeueReusableCellWithIdentifier will return nil. If you run the app, you’ll see the log show that it creates the cell:


-[RootViewController tableView:cellForRowAtIndexPath:] – Creating new cell
row 0 setting text
[RootViewController tableView:cellForRowAtIndexPath:] – Creating new cell
row 1 setting text
-[RootViewController tableView:cellForRowAtIndexPath:] – Creating new cell
row 2 setting text

In the case of UITableView building new cells for displaying the rows, we get the cell variable reference and point it to a newly created
UITableViewCell object allocated on the heap. We only do this if the cell returned is nil.

Once it creates the cell, it will set the cell’s properties.

Notice there is no ‘else’. That’s because whenever dequeueReusableCellWithIdentifier return a valid cell to be displayed, we always want to make sure the properties are correct, by assigning them.

Always reset all content when reusing a cell

https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/TableView_iPhone/TableViewCells/TableViewCells.html

An example of this is if you pull the table up and the rows disappear from the screen.

pull-up-table

Once the table bounces back on the visible screen, you’ll see logs like this:

row 0 setting text
row 1 setting text

That’s because when dequeueReusableCellWithIdentifier returns valid cells, you need to always reset the contents of the cell when the reusable cell is returned.

Cells and Table View Performance

The proper use of table view cells, whether off-the-shelf or custom cell objects, is a major factor in the performance of table views. Ensure that your application does the following three things:

Reuse cells. Object allocation has a performance cost, especially if the allocation has to happen repeatedly over a short period—say, when the user scrolls a table view. If you reuse cells instead of allocating new ones, you greatly enhance table view performance.
Avoid relayout of content. When reusing cells with custom subviews, refrain from laying out those subviews each time the table view requests a cell. Lay out the subviews once, when the cell is created.
Use opaque subviews. When customizing table view cells, make the subviews of the cell opaque, not transparent.

Select Row

When you click on a row, this method will be triggered. Then call method setEditing on the table view object. Once you set it to YES, the row will animate its set settings where your deletion option appears on the left, and the move row button appears on the right.

Click and drag the first row’s move icon for a row and move it to the very bottom. Basically we’ll be switching the topmost row with the bottom most row.

uitableview-move-rows

You can see that by using the fromIndexPath.row, we can get the string by our data array. We use the NSArray’s methods to manipulate the data so that it reflects what’s happening on the UI.

Namely, use removeObjectAtIndex at from index path, and then insertObject on the row string at index toIndexPath.row.
Finally, we use a NO on setEditing to tell the tableView to finish.

Commit your Edit

Once in edit mode, you will commit on a task. A common one is to delete the row. Once you click on the Delete button, you’ll hit the commitEditingStyle:forRowAtIndexPath method in which you commit your deletion.

When the delete button is selected, it will hit commitEditingStyle:forRowAtIndexPath: method where the editingStyle is UITableViewCellEditingStyleDelete.
From there, its the same as moving rows, where you manipulate your array. You remove the object at the data source, then call deleteRowsAtIndexPaths on the UI tableview object.

Once the deletion takes place, the tableview will redraw all the rows, thus, it will go through numberOfSectionsInTableView: and tableView:numberOfRowsInSection: to recalculate how many elements of the array it should show.

Adding a Insertion Row

Adding an insertion row involves 3 steps

1. Return Insert macro for Row

We want to add a row specifically for entering data and inserting that data into our table. Hence, let’s just designate the first row for that. Hence,
we specify in method editingStyleForRowAtIndexPath, where we return the insert macro for the 0th row to tell the table view to show an “Insert” button when the edit mode is on.

For all other rows, show the delete button when the edit mode is on.

editing_styles

Then in your commitEditingStyle:forRowAtIndexPath method, use an option where if the editing style is for insertion
we add a property NSString where it points to the string to be added

2. Setting up a Custom Row to receive data

One easy way to do this is to create a custom cell with a textfield in there that receives a string.

3. ViewController observe UITextFieldTextDidChangeNotification messages from UITextField

Insert a property InsertionCell, where it will point to the 0th row of type InsertionCell.

You assign it in cellForRowAtIndexPath, where when after 0th cell is created, you simply
assign a reference to it so we can keep track of it.

Then, we register for the UITextFieldTextDidChangeNotification notifications on
textfield of the insertion Cell:

This means that whenever the user enter a character, the UITextfield will send UITextFieldTextDidChangeNotification,
in which the ViewController will observer.

It will run textUpdated: method, like so:

The notification message will contain the UITextField with its text. Hence we just have a NSString property point to that text.

When the green plus button is clicked, it will run to commitEditingStyle:forRowAtIndexPath:, check that editingStyle is UITableViewCellEditingStyleInsert and add the string to the data source array. Then it refresh the data by calling the table view’s reloadData method method.