Beginning Table Views · Sectioning by Priority | Ray Wenderlich


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/5995-beginning-table-views/lessons/53

Hi! Could you please, please, please not do video transition like from 2:55 to 3:00. It’s very distracting and confusing. On 2:55 we have two errors:
22

And on 3:00 we’re fixing a completely different error and previous errors are magically fixed:
07

Maybe it’s a good idea to add annotation about this under the video.

1 Like

Looks like a bug during editing. We’ll take look. Thanks for the heads up!

1 Like

Hi! Actually, looks like there is one issue in deleteItems function: you loop through indexes of items that should be deleted, but when you delete items consistently your model will crush, cause models indexes and indexes in array through you loop become unsynchronized.
UPD: Ooops! Didn’t see that you actually fixed it, though there is still bug. I mean even if you fix out of bound error you still may delete another item.
For example:
[‘Do app’, ‘Wake up’, ‘Go to sleep’, ‘Study design pattern’].
When you select first ‘Do app’ and then select ‘Go to sleep’ he will take array[0, 2]. And when you delete ‘Do app’, next item that will be deleted is ‘Study design pattern’, cause now he contained in todos[2].
Easy way to fix this:

@IBAction func deleteItems(_ sender: Any) {
    var was: [Int] = []
    if let selectedRows = tableView.indexPathsForSelectedRows {
        for indexPath in selectedRows {
            print(indexPath.row)
            var actualPath = indexPath
            for i in was {
                if i < indexPath.row {
                    actualPath.row -= 1
                }
            }
            was.append(indexPath.row)
            if let priority = priorityForSectionIndex(indexPath.section) {
                let todos = todoList.todoList(for: priority)
                print(todos[actualPath.row].text)
                let item = todos[actualPath.row]
                todoList.remove(item, from: priority, at: actualPath.row)
            }
        }

Minor changes, but app will work properly.

Thanks for the heads up - we’ll get this fixed in the next iteration.

I gave up on following along in Xcode at this point, because following just the changes in the video isn’t enough to get the app to work again.

@dschuler Please let us know what errors you get exactly when you get a chance. Thank you!

Tapping ‘add’ errors out in the debugger - the backing array and table view get out of sync. There were a couple of other bugs in previous lessons that actually ended up being informative from a learning perspective, but this tutorial should probably be re-worked for errors.

@dschuler Thank you for your feedback - much appreciated! We will fix everything soon. Thanks again!

I think I’ve came up with an even simpler solution: just sort and iterate in reverse order like this:

@IBAction func deleteItems(_ sender: UIBarButtonItem) {
    if let selectedRows = tableView.indexPathsForSelectedRows?.sorted() {
        for i in stride(from: selectedRows.count - 1, through: 0, by: -1) {
            let indexPath = selectedRows[i]
            
            if let priority = priorityForSectionIndex(indexPath.section) {
                let todos = todoList.todoList(for: priority)
                let item = todos[indexPath.row]
                
                todoList.remove(item, from: priority, at: indexPath.row)
            }
        }
        
        tableView.beginUpdates()
        tableView.deleteRows(at: selectedRows, with: .automatic)
        tableView.endUpdates()
    }
}

@hettiger Thank you for sharing your solution - much appreciated! :]

Really bad editing at 2.55 - 3 min mark as others have said, this has happens several times in the series where errors and code changes are quickly and quietly done, you need hawk eyes to catch.

If you are getting the error “Variable used within its own initial value” you need to change “indexPath” to “IndexPath”

@idesignpixels Thank you for the heads up! We will definitely fix these in the next edition.

to correct the deleteItems bug, if you
i. change selectedRows into a var instead of a let.
ii. then add this as the first statement in the if clause to sort all these indexPaths by rows descending:
selectedRows.sort { $0.row > $1.row }
Then things will work fine because then as items that are removed they won’t affect the index numbers of the items before them in the individual arrays and so the row numbers on each selectedRow will still work to delete the correct item.

@hashmo Thank you for sharing your solution - much appreciated! :]

even simpler

for indexPath in selectedRows.sorted(by: >) { ... }

completed code

@IBAction func deleteItems(_ sender: Any) {
    if let selectedRows = tableView.indexPathsForSelectedRows {
      for indexPath in selectedRows.sorted(by: >) {
        if let priority = priorityForSectionIndex(indexPath.section) {
          let todos = todoList.todoList(for: priority)
          let item = todos[indexPath.row]
          todoList.remove(item, from: priority, at: indexPath.row)
        }
      }
      tableView.beginUpdates()
      tableView.deleteRows(at: selectedRows, with: .automatic)
      tableView.endUpdates()
    }
  }

The function for swiping to delete stopped working at the end of this video. I’m super unskilled at swift, but managed to get it to work like this (if anyone else is strugglign with it). Tested it several times and it seems to work.

  override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
        if let priority = priorityForSectionIndex(indexPath.section) {
          let todos = todoList.todoList(for: priority)
          let item = todos[indexPath.row]
          todoList.remove(item, from: priority, at: indexPath.row)
          let indexPaths = [indexPath]
          tableView.deleteRows(at: indexPaths, with: .automatic)
        }
  }

Good luck.

@ys_xs @hangman Thank you for sharing your solution - much appreciated!

Thanks for the video series @bdmoakley ! I was using it as a refresher and found it to be very helpful.

Some suggestions:

I like to keep my completed tutorials around for reference, and will do so with this one as well. The issue here is that there are really 3 different versions of the task list app as it evolved: One section, collated sections, prioritized sections. What I did was to create GitHub branches at each natural breaking point in the evolution of the app. Could be a useful tip to suggest to viewers.

The collated version of the app was very interesting. It still needed a fair amount of work though, so I completed it on my own in a branch. A future video update might consider spending a little more time on this piece.

I did spot the issue with sorting for deletion as I watched the video, and then read the comments to confirm. I was wondering if it would make sense for videos to maintain a “known issues” section that could be an temporary remedy for issues until a video is updated?

Again, great job overall - thanks.

Cc @shogunkaramazov

Thanks Scarter, I really appreciate the thoughtful feedback. This course evolved from our iOS Apprentice book and we also wanted to focus just on table views so it caused problems being too complex. We’ve since went back to the drawing board on this course and doing a complete rethink.

Thanks again for your thoughts and notes. Cheers!