Search code examples
iosswiftuitableviewios9reloaddata

TableView not reloading after executeFetchRequest


When the app starts I send a notification to my ViewController that executes refreshCategories function, the problem is tableView only reloads if I scroll or after a long time (20 secs or more).

Heres is my code:

class PopularCategoriesTableViewController: UITableViewController {

    var categoryList:[Category]!

    override func viewDidLoad() {
        super.viewDidLoad()

        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("refreshCategories"),
            name: Constants.NotificationKeys.shouldReloadCategories, object: nil)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // MARK: - 
    func refreshCategories() {
        categoryList = DataModelUtil.sharedInstance.getRecordsFromEntity(Category.classString()) as! [Category]
        self.tableView.reloadData()

    }

    // MARK: - Table view data source
    override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 0.01
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if categoryList == nil {
            return 0
        }

        return categoryList.count
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let item = categoryList[indexPath.row]

        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
        cell.textLabel?.text = item.name

        return cell
    }

}

This is the method that does the fetch:

func getRecordsFromEntity(entity:String) -> [NSManagedObject]! {
    let fetchRequest = NSFetchRequest(entityName: entity)
    do {
        return try appDelegate.managedObjectContext.executeFetchRequest(fetchRequest) as! [NSManagedObject]
    } catch let error as NSError {
        print("Could not execute FetchRequest \(error), \(error.userInfo)")
    }
    return nil
}

Note: I discover it works fine when using dispatch_async.

dispatch_async(dispatch_get_main_queue(),{ ()->() in
                self.tableView.reloadData()
            })

but I didn't need this in iOS 8 with objective-c, and I don’t think is correct to use dispatch every time I want to reloadData.


Solution

  • Any UI operation must be done on main queue. If you don't obey this rule, you will get weird crashes. I also suggest you to use NSFetchedResultsController since you are using a tableView. Save your data anywhere by obeying Core Data threading rules, and your table will update automatically. You can manually refresh your table anywhere by resetting NSFetchedResultsController and initializing again.