5

My app calls a block in tableView:didSelectRowAtIndexPath and in the block it presents a view controller. If I click the cell second time when the first click is in progress, it crashes. How can I prevent the cell to be clicked second time?

- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath


    [dataController fetchAlbum:item
         success:^(Album *album) {
            ...
            ...

            [self presentViewController:photoViewController animated:YES completion:nil];


               }];
zontragon
  • 780
  • 1
  • 9
  • 27

7 Answers7

10

At the beginning of didSelectRow, turn off user interaction on your table.

- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    tableView.userInteractionEnabled = NO;
    ...

You may want to turn it back on later in the completion of fetchAlbum (Do this on the main thread) so that if the user comes back to this view (or the fetch fails), they can interact with the table again.

Stonz2
  • 6,306
  • 4
  • 44
  • 64
7

For swift 3 :

When user select a row, turn off user interactions :

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

    tableView.isUserInteractionEnabled = false

Don't forget to turn it on back whenever the view appear :

override func viewDidAppear(_ animated: Bool) {
    tableView.isUserInteractionEnabled = true
}
Skaal
  • 1,224
  • 12
  • 10
1

You could either prevent multiple clicks (by disabling the table or covering it up with a spinner) or you could make didSelectRowAtIndexPath present your view controller synchronously and load your "album" after it's been presented. I'm a fan of the latter as it makes the UI feel more responsive.

CrimsonChris
  • 4,651
  • 2
  • 19
  • 30
  • Personally, if the load takes more than about 0.5s (roughly the time it takes to present the new view animated), I find that approach _less_ responsive as it leaves me staring at a blank screen while loading instead of a populated view controller with an activity indicator. However, if the load is quick, I would definitely recommend the synchronous page load you suggest so that the data can load while the animation is in progress. – Stonz2 Jul 22 '14 at 20:21
  • 2
    I wouldn't expect you to be staring at a blank screen. I would show you a blank page with the most beautiful loading spinner you had ever laid eyes on. :) – CrimsonChris Jul 22 '14 at 20:24
  • 1
    Agreed. The data takes the same amount of time to load either way, but with this approach the app reacts to the touch immediately. With the OPs approach I am left wondering if my cell tap is going to be actioned – Paulw11 Jul 23 '14 at 20:50
1

For a cleaner approach:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    defer {
      tableView.isUserInteractionEnabled = true
    }

    tableView.isUserInteractionEnabled = false
}

This way you're much less prone to errors due to forgetfulness.

Tunscopi
  • 97
  • 2
  • 8
0

You want to disable user interaction on the cell:

- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
    cell.userInteractionEnabled = NO;

As Stonz2 points out, you probably want to do it to the entire tableview though, rather than the specific cell if you're presenting a VC.

brandonscript
  • 68,675
  • 32
  • 163
  • 220
  • While the OP did ask about disabling their cell specifically, I would think they probably don't want to present multiple modal photo viewer controllers at the same time. – Stonz2 Jul 22 '14 at 20:16
  • 1
    More than likely, but I answered the question nonetheless ^_^ – brandonscript Jul 22 '14 at 20:17
0
let cell = tableView.cellForRowAtIndexPath(indexPath)
    cell?.userInteractionEnabled = false

then set back to true before you navigate to another view, otherwise when you return back to your table the cell will be still disabled.

Mahesh Lad
  • 169
  • 1
  • 3
0

I have a similar approach like Skaal answered but in a different way. This solution will work for any swift version .

Create a property named isPresentingVC in your view controller and set it to true.

var isPresentingVC: Bool = true

Inside didSelect row, try this

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    if isPresentingVC {
       isPresentingVC = false
       //do your work like go to another view controller
    }
 }

Now in viewWillAppear or viewDidDisappear reset its value to true

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    isPresentingVC = true
}
Mohammad Daihan
  • 538
  • 4
  • 15