In my app I am doing tableView. By clicking row, the new view will navigate. Before navigation of new view, application is processing data from server. Until processing of data finished, view will not navigate. In this time period I want to disable userinteraction of tableview, so user can not select further rows.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
tableView.userInteractionEnabled = NO;
}
Note that, When I again come back to the tableview, user will again allowed to select any row.
I do not have any idea, how can I enable userinteracation again.
I assume that you are getting your data asynchronously.
In this case, you can re-enable user interaction from your connection delegate method. If you are using NSURLRequest/NSUrlConnection, the delegate method would be: connectionDidFinishLoading: (don't forget also about connection:didFailWithError:).
From NSURLConnection Reference:
connectionDidFinishLoading:
Sent when a connection has finished loading successfully.
So, when the data is there and you are done with the processing, you re-enable the table view.
For Coming back after navigation, Put following sentence in your viewWillAppear That will again allow your table view user interaction to true.
tableView.userInteractionEnabled = YES;
Related
Ok my First Controller is a UITabel and when a cell is passed it pushes to the Second View Controller. The Second Controller loads data from a webservice so the segue takes a little. I would like to show a SVProgressHUD when the cell is selected and then dismiss it after the data loaded but the SVProgressHUD instead shows after the Second View is loaded and only for a a couple milliseconds.I use this right now:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[SVProgressHUD show];
UITableViewCell *acell = [tableView cellForRowAtIndexPath:indexPath];
[self performSegueWithIdentifier:#"pushCell" sender:acell];
}
Any way to show the SVProgressHUD immediately when cell is selected?
Apple recommends that when the user clicks on a tableViewCell the app should segue to the next view controller immediately. The fact that you feel you need to show a SVProgressHUD while the next view loads suggests to me that you are requesting the data using a synchronous method, which will block the main thread and make it appear that your app has frozen while it waits for the response.
The best practice for retrieving data is to always do so asynchronously (or on a background thread) so that your app always remains responsive. I would recommend changing your request to an asynchronous method (look into the NSURLRequest method initWithRequest:delegate:, for example). If you use that you can then show the SVProgressHUD in your second controller's viewDidLoad method, the transition to the second view controller will happen instantly when the user taps the table cell, and your app won't be locked up while the user waits for the data to download.
Here is more info about this method from the Apple Documentation
Under certain circumstances, UITableView didSelectRowAtIndexPath is being called twice causing the error Pushing the same view controller instance more than once is not supported.
Here's are the sequence of events:
TableView::didSelectRowAtIndexPath.
TableView::viewWillDisappear.
PushedViewController::viewWillAppear.
TableView::didSelectRowAtIndexPath.
Error: Pushing the same view controller instance more than once is not supported'
The only thing worth noting is that the UITableView is loading images asynchronously, but that never calls didSelectRowAtIndexPath. Also, the PushedViewController is reused to avoid having to reload it each time a cell is selected in the UITableView.
Anyone have any idea what may be causing this?
Thanks.
I'm seeing this problem too, probably one out of a 1000 users gets affected, or less. I сan clearly see two didSelectRowAtIndexPath registering 50 ms one after another. My guess is that it is a bug in iOS - no new taps should be directed to old view once new view-controller has been pushed. Alas, it is likely up to us to write code guarding against this. Here's what I'm thinking:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
if (self.navigationController.topViewController != self)
return;
... do other stuff
}
Disable user interaction after the first "didSelectRow". It's possible for multiple taps to "stack up" during the transition.
It usually takes someone with amazing dexterity in their fingers to get this behavior, but still.
if you already created Storyboard Segue don't call;
[self performSegueWithIdentifier:#"TYPE" sender:self];
in this method;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
This occurs because of the segue you are using inside the didSelectRowAtIndexPath method. Ensure that this segue is created by ctrl dragging from the view button on top of the source view controller to destination view controller. The error occurs when you create the segue by ctrl dragging from the table view cell to destination view controller.
You do not need to change any of you code. Just delete the segue and create it in the correct way. Hope this solves your problem, if I got the question right.
Swift 5
In my case also helped to update the cells instead of this code:
tableView.reloadRows(at: [indexPath], with: .automatic)
to use this:
tableView.reloadData()
I have a UITableView with a list of items. On selection of an item I'm navigating to a new view that displays the details of the selected item using:
DetailsVC *detailsView = [[DetailsVC alloc] initWithNibName:#"DetailsVC" bundle:nil];
[self.navigationController pushViewController:detailsView animated:YES];
Now, the details view is getting the data from the remote location so on slow connection it can take a few seconds. What I want to do is display an activity indicator over the selected row on selection.
The problem is the display of the added indicator gets delayed until the next view is ready to navigate to, which makes the indicator usless.
I've tried to add this indicator in those 2 events with the same effect:
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
Is there a way to add the indicator (or more general, modify the content of a UITableViewCell) in the moment of selection, before navigation occurs.
As a experiment I've also tried to pop up an alert view in the same two events which resulted in poping up the alert after navigation to the details view.
So it's [[DetailsVC alloc] init...] that takes a few seconds, right? This problem is that any view changes you make don't fully take effect until returning all the way back to the runloop, so even if you setup the indicator before creating your object, it too is waiting for the init to finish to make itself visible. What you need to do is defer the creation of your DetailsVC until after the indicator is setup.
I might be a simpler change to use blocks but I can't recall the details of that off the top of my head (haven't used blocks much since code I've been writing lately has had to stay compatible with 3.x). But to use performSelector is easy too, take those 2 lines you first quoted in your question and put them into its own method, such as:
- (void)pushDetailsView {
DetailsVC *detailsView = [[DetailsVC alloc] initWithNibName:#"DetailsVC" bundle:nil];
[self.navigationController pushViewController:detailsView animated:YES];
}
And where you had those lines before, setup your indicator and then do this (a delay of 0 doesn't mean to called it immediately, but rather ASAP after returning all the way out of the current call stack):
[self performSelector:#selector(pushDetailsView) withObject:nil withDelay:0]
you can call cell = [self rowForIndexPath:indexPath] in one of your functions. and then add the indicator to cells subview
You can either
add the indicator when u select row and push new view when data came
(simultaneously remove indicator at that time) or
Push new view, call web service to get corresponding cell data (in
viewDidLoad or viewWillAppear) and display indicator simultaneously
and when new data comes remove indicator
Hi
I've got simple question which I don't know how to answer.
In my app I've got UITableViewController with cells. When I select one item (cell) it's getting higlighted and in other thread I'm loading chunk of data to display to the user (after load is done new VC is pushed). When doing it with thread user still can interact with application like, going back to other NavController and I do want that to happen. What I don't want to happen is that when loading isn't complete user can select other cell in table and it get's highlted. How I can prevent that (only highlit, I'm checking if there was a previous request so I'm not putting another thread untli previous request is done).
So basicly my question is, how can you foribd user from interacting with table view controller?
Set the selectionStyle of the UITableViewCell's to UITableViewCellSelectionStyleNone.
You can use the following to check if row can be selected:
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (rowSelected) {
return nil;
}
return indexPath;
}
So, you only select it if no row is selected. In your didSelectRowAtIndexPath method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
rowSelected = YES;
// call method that is going to do something and mark rowSelected = NO;
}
You can deselect the row by using
[[tableView cellForRowAtIndexPath:indexPath] setSelected:NO animated:YES];
There is a risk that your users will be confused. A highlight is not enough. There should be very clear visual feedback that a network opperation is ongoing and that different rules apply.
either push the details view immediately after the user selected a row and show an activity indicator in there.
or give the whole table view a different look while loading data for the selected row: e.g. Show activity indicator in the selected row & hide the disclosure chevrons in all the other. While doing that, you can set the selection style to 'none'
How do I have a UITableView be notified that the data it is using is new and all old data/cells should be flushed.
I have a search bar that will cause the UITableView to be refreshed when new queries are entered.
An example would be:
[myTableView reloadData];