How do you make a UITableView with Sections using NSFetchedResultsController?

38 Views Asked by At

So we have to use CoreData and we have to use a UITableView, now I'm asking how does that work with a NSFetchedResultsController? We have something already set up for other basic sectioned views where we dont need a fetchresultscontroller and that was pretty easy, but this seems a little trickier. There is a little support out there for our old pal Objective-C that has been around for years but we are looking for a Swift solution. Swift 5 at the time of this post.

Have already implemented the plain list (which is fairly well documented) and now we just want to add some sections...

1

There are 1 best solutions below

0
AMAN77 On

So we have a UITableView and a NSFetchedResultsController and we get a nice list of Entities. Now we want to add a few sections into the tableview. No Problem so we update the sortDescriptors to include a section:

     fetchRequest.sortDescriptors = 
          [NSSortDescriptor(key: "sectionLabel", ascending: false),
          NSSortDescriptor(key: "unixTimestamp", ascending: false)]

and the entity to include the sectionLabel, this part is a bit more custom depending on what kind of sections you want.

Then we add a few section functions :

     func numberOfSections(in tableView: UITableView) -> Int {
          return self.fetchController?.sections?.count ?? 0
     }

     func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
          guard AllTheThings( fetchController -> sections -> entity -> cell )
          if sections.count > 1 {
            cell.configureCell(value: entity.sectionLabel ?? "myLabel")
            return cell.contentView 
          } else { return UIView() }
     }
     
     func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 20.0
     }

     func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
          guard let sections = fetchController?.sections else { return 0 }
          return sections[section].numberOfObjects
    }

So things are starting to shape up but theres still some work needed on the cellForRowAt indexPath and other standard cell functions. So in order to get an entity for the index to use in those we create a cool function:

func returnEntity(indexPath: IndexPath) -> MyEntity? {
        
        guard let sections = fetchController.sections else {
            return nil
        }
        
        guard let objects = sections[indexPath.section].objects else {
            return nil
        }
        
        if objects.isEmpty {
            return nil
        }
        
        guard let entity = objects[indexPath.row] as? MyEntity else {
            return nil
        }
        
        return entity
    }

Left the guards in this time ;)

Now all you have to do to get your entity is use returnEntity(indexPath: indexPath)