Delete/Insert UITableViewCell not in Editing mode - ios

What's best solution to remove cell from tableview doing this not in editing mode. Like example switching to one view to another , update number of cells (after a previous delete or insert of cell) in -viewWillAppear: method.

You could use NSFetchedResultsController. It will add/remove/update cells as it gets notifications when changes are made to NSManagedObjectContext that it was created with.

If you changed (added/deleted) the values from the dataSource array then you can simply call
[tableView reloadData];

Look at beginUpdates
Call this method if you want subsequent insertions, deletion, and selection operations (for example, cellForRowAtIndexPath: and indexPathsForVisibleRows) to be animated simultaneously.
You should not call reloadData within the group

Related

Using reloadRowsAtIndexPaths when the update of a NSFetchedResultsController is triggered

I have some rows of my UITableView that get updated and then trigger the method controller:didChangeObject:atIndexPath:forChangeType:newIndexPath of the NSFetchedResultsControllerDelegate delegate.
I usually update the rows in the tableView using reloadRowsAtIndexPaths with an animation, but it happens that sometimes the method is triggered because of a change that is not visible and is that case, I don't want to reload the row with an animation.
The method doesn't give the previous state of the object. Is there a way to do it (I didn't find any method of the delegate that might do)?
If your delegate is also your TableViewController, you could just check your UITableView's data source at the IndexPath. The reloadRowsAtIndexPaths method knows the index.

What is More reliable way to reload UITableView Data?

I have found 2 functions to reload my rows of UITableView
1st.
[tableView reloadRowsAtIndexPaths:[tableView indexPathsForVisibleRows]
withRowAnimation:UITableViewRowAnimationNone];
2nd.
[tableView reloadData];
What is more specific way to reload UITableView Data
Both are "reliable" and possibly "specific" (depending on what you mean by specific) -- in fact, there are even more ways:
reloadData
reloadRowsAtIndexPaths:withRowAnimation:
reloadSections:withRowAnimation:
reloadSectionIndexTitles
Check the developer documentation (https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableView_Class/index.html) on the differences, but the short answer is that they are all reliable -- it just depends on how much information you want to reload, and if you want to do it with animation.
For example, if you only want to reload certain rows, you can use reloadRowsAtIndexPaths:withRowAnimation:. If you want to reload a whole section, use reloadSections:withRowAnimation:.
This answer may have two cases,
a) You've the table with at least a single section (with a title or returning a view for section)
In this case, if you call reloadData then it'll also reload section too. But reloadRowsAtIndexPaths:withRowAnimation: will only reload the visible cells and not the section.
b) You've the table with at least a single section (without a title or returning a view for section)
In this case, if you call reloadData or reloadRowsAtIndexPaths:withRowAnimation: both will reload only the visible cells.
So which one is the better?
As I explained, based on the case, you should call any of the one method. If you have sections which you don't want to reload then you should call reloadRowsAtIndexPaths:withRowAnimation: method. Or if you want to reload cells along with section then should call reloadData method.

iOS UITableView behaviour broken when not active

My current set up is the following:
Root Tab Bar:
Collection view with magazines
Bookmarks (with a table view)
Others
You can add a bookmark from a magazine in the collection view and also remove it from there.
The behaviour I'm seeing is the following:
I start the application, the table view queries the number of sections, number of cells, but not the cellForRowAtIndexPath. I could understand why, as there is no cell in the active view, so no data should be loaded.
When I add a bookmark from the collection view, it adds it to the array (via a notification) and requests the tableview to be reloaded. As there isn't an initial entry, it goes through the motions described above. When I press it again to remove the bookmark the entry is removed from the array. This is where it gets interesting because the first thing the table calls is not the number of sections or rows but the cellForRowAtIndexPath. As the array is empty, the application crashes on a request for data on index 0.
My question is why does the cell creation get called in that order? Is there any way to avoid it?
If you changed the section, try calling - (void)reloadSections:(NSIndexSet *)sections before you call reloadData
https://developer.apple.com/library/ios/DOCUMENTATION/UIKit/Reference/UICollectionView_class/index.html#//apple_ref/occ/instm/UICollectionView/reloadSections:
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationLeft];
The reason this was happening is because I was attempting to change something about the table before I reloaded the data.
[self.tableView setSeparatorStyle: !_helpText.hidden ? UITableViewCellSeparatorStyleNone : UITableViewCellSeparatorStyleSingleLine];
[self.tableView reloadData];
That was for removing the lines so a message can be displayed. However that update was using old data as reloadData had not been called.
[self.tableView reloadData];
[self.tableView setSeparatorStyle: !_helpText.hidden ? UITableViewCellSeparatorStyleNone : UITableViewCellSeparatorStyleSingleLine];
Reversing them fixed the issue.

tableView:didDeselectRowAtIndexPath: not called until first user-initiated selection and deselection

I have a UITableView with four cells, in single selection mode. When the view is first loaded, I programmatically select one of the cells using -selectRowAtIndexPath:animated:scrollPosition: based on a stored preference. After this, the user can interact with the table.
The methods -tableView:willSelectRowAtIndexPath: and -tableView:didSelectRowAtIndexPath: are called on my table view delegate every time the user taps any cell. However, -tableView:willDeselectRowAtIndexPath: and -tableView:didDeselectRowAtIndexPath: (that's DEselect) don't start being called until the user manually taps that first programmatically selected cell.
Any idea why this might be happening? Are there any workarounds besides manually calling -[UITableView selectRowAtIndexPath:animated:] for every cell except the one that the user tapped?
If you do invoke [UITableView selectRowAtIndexPath:animated:] too soon and you are using a UITableViewController, you probably have conflict with the UIViewController clearsSelectionOnViewWillAppear (defaults to YES). Try setting self.clearsSelectionOnViewWillAppear = NO; in your viewDidLoad
This is too long for comment so I'm posting this as an answer.
Just created test project with tableView. I call [UITableView selectRowAtIndexPath:animated:] on viewDidLoad and I have one cell selected. Then I'm selecting another cell (without deselecting first one).
I have this output:
[SDTVTViewController tableView:willSelectRowAtIndexPath:]
[SDTVTViewController tableView:willDeselectRowAtIndexPath:]
[SDTVTViewController tableView:didDeselectRowAtIndexPath:]
[SDTVTViewController tableView:didSelectRowAtIndexPath:]
And I have first cell deselected and second one selected.
I have no idea, why it's not working in your code. When you're calling [UITableView selectRowAtIndexPath:animated:] and can you post code of UITableViewDelegate methods that you've implemented?
I was wrapping my initial data source updates and -selectRowAtIndexPath:... calls in
[_tableView beginUpdates];
// ...
[_tableView endUpdates];
Apparently, like -reloadData, this clears the current selection (not sure if that's by design). I moved the call to -selectRowAtIndexPath:... to after -endUpdates and now everything works as intended.

TableView reloadData vs. beginUpdates & endUpdates

I got a tricky problem regarding updating my TableView, i get different results using different methods of updating it, let me explain:
Situation 1:
I use [tbl reloadData]; where tbl is my TableView, to update the TableView - works as intended.
Situation 2:
I use:
[tbl beginUpdates];
[tbl reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationRight];
[tbl endUpdates];
Where tbl is my TableView, and indexPaths is an array containing all the indexPaths present in the TableView. Now the array is fine, it contains all the correct indexPaths (double and triple checked) but for some reason - this does not work as intended.
Now I realize that this is an X-Y problem (where I ask for Y but my problem is really X because I think solving Y will solve X) and thats only because I feel it's a bit complicated explaining X (the consequence of said above problem) in an easy way, so I'd rather refrain from that if possible.
So, down to my question: Is there a difference between the two ways of updating the TableView (aside from the animation bit of course) or should I suspect the problem to lay elsewhere?
EDIT:
Okay, I'll try to explain what the symptoms are:
In the cellForRowAtIndexPath-method I add a button to each cell with an assigned tag which is equal to the cell's indexPath row, like such:
btn.tag = indexPath.row;
The reason I do this is so I can identify each button as they all call the same function:
- (void)btnPressed:(id)sender
When I then update the cells - because some values in the cells have changed - Situation 1 makes everything work fine, Situation 2 however - mixes up the tags so the next time one of the buttons are pressed, they no longer have the correct tags.
The mix-up does appear random to me, but the randomization occurs differently depending on which cells button I press first. I hope this clarifies my problem.
From the UITableView documentation
beginUpdates
Begin a series of method calls that insert, delete, or
select rows and sections of the receiver.
That means, you should not use this unless you are inserting, deleting or selecting. You are doing neither of these.
Also, you should end beginUpdates with endUpdates, not reloadData. Documentation:
This group of methods must conclude with an invocation of endUpdates.
The first difference between reloadData and reloadRowsAtIndexPaths is that there are 2 UITableViewCell objects allocated simulteaneosuly for the same indexPath when doing reloadRowsAtIndexPaths (because the tableview 'blends' in the the new cell) . This is sometimes not foreseen by the code in cellForRowAtIndexPath .The surprise comes from the fact that even if a cell was already allocated for a particular cell identfier the table view does not give you back this cell in dequeueReusableCellWithIdentifier when calling reloadRowsAtIndexPaths, instead it returns nil. In contradiction reloadData reuses the cells it already allocated .
The 2nd difference is that endUpdates after reloadRowsAtIndexPaths directly calls cellForRowAtIndexPath (if you set a breakpoint there,endUpdates is visible in the stack trace) whereas reloadData schedules the calls to cellForRowAtIndexPath at a later time (not visible in the stack trace).
However you would need to post a bit more code to give us insight what you are doing there. In principle the indexPaths of the new cells are identical to the old ones also with reloadRowsAtIndexPaths as long as you don't delete or insert rows.
Call this method if you want subsequent insertions, deletion, and selection operations (for example, cellForRowAtIndexPath: and indexPathsForVisibleRows) to be animated simultaneously.
I think this is what you want. beginUpdates & endUpdates can change the UItableview with animation.

Resources