Dave
Dave

Reputation: 12206

Why is my UITableView 'Tap to Edit' Function SLOW?

I have a UITableView list. I added code so when a list-item/row is tapped, the user can edit the cell contents in a modal view:

  1. Upon tapping, the code saves the cell's title/desc to vars
  2. Then launches my modal editor view
  3. The main VC passes the editor VC the title/desc vars
  4. The var values are loaded into the text boxes so the user can edit them

The problem:

It's a weird behavior. When I test the app, the first time I tap a cell after opening the app, there's sometimes a delay of 2-3 seconds before the modal view appears. I also notice that the delay happens the first time I tap each cell, but not the second. Lastly, sometimes after opening the app up, it appears to ignore the first tap. Is this normal core data fetch request behavior?

Code loaded on main VC ViewDidLoad

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    //Break

    //Load the list from Core Data
    let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    let managedContext = appDelegate.managedObjectContext!
    let fetchRequest = NSFetchRequest(entityName:"TodayTask")
    var error: NSError?
    let fetchedResults = managedContext.executeFetchRequest(fetchRequest, error: &error) as? [NSManagedObject]

    if let results = fetchedResults {
        todayTaskList = results
    } else {
        println("Could not fetch \(error), \(error!.userInfo)")
    }

    //Break

    //This provides a variable height for each row
    tableView.rowHeight = UITableViewAutomaticDimension
    tableView.estimatedRowHeight = 80.0

    //Break

    //Part of code for cell drag and drop functionality
    let longpress = UILongPressGestureRecognizer(target: self, action: "longPressGestureRecognized:")
    tableView.addGestureRecognizer(longpress)
}

Code run on cell tap

//Action: Performs 'tap on edit' segue
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    passingEdit = true
    performSegueWithIdentifier("modalToEditor", sender: nil)
}

//Prepares variables to be passed for editing
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if (segue.identifier == "modalToEditor") && passingEdit == true {

        //Assign selection to a variable 'currentCell'
        let indexPath = tableView.indexPathForSelectedRow();
        let currentCell = tableView.cellForRowAtIndexPath(indexPath!) as! CustomTableViewCell;

        //Set cell text into variables to pass to editor
        var cellNameForEdit = currentCell.nameLabel!.text
        var cellDescForEdit = currentCell.descLabel.text

        //Pass values to EditorView
        var editorVC = segue.destinationViewController as! EditorView;
        editorVC.namePassed = cellNameForEdit
        editorVC.descPassed = cellDescForEdit
        editorVC.indexOfTap = indexPath
    }
}

Upvotes: 1

Views: 545

Answers (1)

Dave
Dave

Reputation: 12206

Fixed!

After receiving a few comments and researching the suggestions, I've been able to resolve this issue of my cell-taps not segueing quickly on first tap (but a double tap gets a quick response!).

One comment was that I should call CoreData in the background, if that works, then lots of opinions I read are wrong. I read a lot that said background threads might actually be causing the issue. I didn't try this though, so I can't confirm if it is right or wrong.

Instead, the comment by @pdasdf set me on the right path. If you're creating a table that segues when a cell is tapped, you're probably doing so in code that looks like this:

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

    performSegueWithIdentifier("modalToEditor", sender: nil)

}

That is what my code looked like. I had a few other things for telling my prepareForSegue what was coding on, but above is the important part. All I did was change from that to this:

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

    dispatch_async(dispatch_get_main_queue()) { () -> Void in
        self.performSegueWithIdentifier("modalToAllocEditor", sender: nil)
    }
}

I had never used dispatch before. It is, however, inline with my reading that there's some kind of queueing issue behind cell-tap-segues being delayed... so I assume this is remedying whatever the specific queue issue is.

Side note:

If the above fixed all your problems, stop reading! This is likely not relevant to everybody.

If your didSelectRowAtIndexPath is like mine, you actually have a little more code than above. I had a variable call 'passingEdit' that would be updated when a cell was tapped and it would tell my prepareForSegue if data needs to be passed.

In the new method, if I set this variable within the dispatch {} brackets, it wouldn't run. So if you need to do other stuff, make sure you do it within the tableView function but outside of the dispatch function:

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

    dispatch_async(dispatch_get_main_queue()) { () -> Void in
        self.performSegueWithIdentifier("modalToAllocEditor", sender: nil)
    }
    passingEdit = true
}

Good luck.

Upvotes: 3

Related Questions