cellForRowAtIndexPath Usage Pattern - iphone

In the below code I want to perform some DB actions when a cell is deleted, therefore I need to send my Server information about the cell being deleted. If I remember correctly cellForRowAtIndexPath should never be called directly, However I cannot think of any other way to get cell info in the below method, so my question is:
Is it acceptable to call cellForRowAtIndexPath manually below:
[tableView cellForRowAtIndexPath:indexPath]);
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
[localGlobalNotifications removeObjectAtIndex:indexPath.row];
[notificationTableView beginUpdates];
[notificationTableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationLeft];
[self postLeaveRequest];
NSLog(#"Row is : %#", [tableView cellForRowAtIndexPath:indexPath]);
[notificationTableView endUpdates];
}
}
To clarify: I understand that I can invoke a delegate call of cellForRowAtIndexPath by calling reloadData, what I'm trying to do is access the cell being deleted within commitEditingStyle. I'm not trying to reload my tableView, instead I want to get a reference to the cell being deleted. - Is it acceptable to obtain a reference to said cell by calling cellForRowAtIndexPath directly?

There's nothing wrong with asking the TableView to give you the cell, just as you do in your sample code.
Here's the documentation for the return value:
An object representing a cell of the table or nil if the cell is not visible or indexPath is out of range.
If you're annotating the cell with 'model' data then I think you're breaking the MVC pattern. Your view doesn't need to know about the model data in this way, and so querying the view to make a database change will make life difficult you in the future (readability, extensibility and reusability for example)
You would be better off having your DB metadata stored in a collection such as an NSArray - or an NSArray of NSArrays.
Then you could get all the data you need with something like:
id modelData = myModel[indexPath.section][indexPath.row];

Yes you can use cellForRowAtIndexPath: as they have also used in apple docs or you can create an array of your cells then you can delete it from there and reflect it in your database.

You can call cellForRowAtIndexPath: method using following line, here it will automatically calls all delegate and datasource methods.
[tableView reloadData];
or
[tableViewObjct reloadData];
Hope this solves your problem!

Related

UITableViewDataSource methods not getting called

I am updating my UITableView with the following code:
int index = [self.guests indexOfObject:_guests];
[[self tableView] beginUpdates];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:index inSection:0]] withRowAnimation:UITableViewRowAnimationLeft];
[[self tableView] endUpdates];
But after calling [[self tableView] endUpdates], its not calling its datasource methods. In case of adding row, it calls its datasource methods. I think in case of deletion it does not need to ask anything to its datasource, but in case of adding a row it needs to ask its datasource about pretty much everything about the new row added like cellForRow, height etc etc. I just want to make sure that is it right if deleteRowsAtIndexPaths is not calling any of its datasource methods??
deleteRowsAtIndexPaths:indexPaths doesn't call delegate methods in all situation. It just simply deletes rows, If the rows being deleted are so many that they are occupying screen area, then it may call your delegate method. You have to explicitly call reloadData so that it refreshes its rows.
But calling reloadData immediately will spoil your animation or produce weird errors, since its rows are being deleted and you call reload method. (It may go crazy). The alternate solution is to call reloadData after a slight delay like 0.2 or greater like this:
[self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationLeft];
[self.tableView performSelector:#selector(reloadData) withObject:nil afterDelay:0.2]; //calling reloadData after a short delay. 0.2 or whatever suits you.
Don't forget about deleting data from your datasource's array or whatever you are using to hold data.
The answer is a question " why should it call all the datasource and delegate methods if the view is already popuated and all cells are readily available"?
well it Should be the behavior

Flushing UITableView queue for cells

I was wondering if some one can please reply me with if the UITableView queue gets flushed when UITableView reloadData is called.I am trying to do so and this isnt helping me.Any suggestions?
if you look at the header file for UITableView, you can see that there is a private NSMutableDictionary (iVar) called "_reusableTableCells". This is a dictionary with cell reuse identifiers as key and with array with cells that are currently offscreen as value.
If you want to manually flush queued cells in way that may change with the implementation, you can do so in ugly manner, like so:
NSMutableDictionary *cells = (NSMutableDictionary*)[self.tableView valueForKey:#"_reusableTableCells"];
[cells removeAllObjects];
Hope this helps...
Once the table is loaded, the cells are reused. Reloading the table does not flush the queue. reloadData calls - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
In this method the if(cell==nil) condition is present so that cells are not flushed once they have been loaded into memory, and therefore reused.
To get around this you reset your cells before applying the correct information.
cell.detailTextLabel.text = #"";
cell.accessoryType = UITableViewCellAccessoryNone;
Or if you are using an accessoryView
cell.accessoryView = nil;
Also take a look at this example. UITableView not updating correctly when scrolling.

rebuild table cells in UITableViewController

I have a UITableViewController that when loaded gets data from a web-service and stores it locally in an NSMutableArray, once that is loaded I need to loop through that data to build my table cells.
I have all of the code for looping through my array working fine I just need to know how to fire my controller to rebuild the table so my it displays my data.
[self.tableView reloadData];
After saving the datas in mutatable array after calling webservices, call tableview reloadData
[self.tableView reloadData];
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [datas count];
}
Make sure that you update the mutable array "datas" value after storing content in mutable array, such as datas will have the web service contents.
Here is sample program of parsing and displaying the parsed content in table, you can refer it how they are reloading their table after parsing
All the best.
I ended up following the instructions here for creating a UITableViewDataSource class, works like a champ!
UITableViewDataSource simplified

How to delete table rows programmatically?

I have a table which I am manipulating with a tableViewController (no nib, and the controller is creating the table behind the scenes)
I'm trying to delete a row from the table based on its row number; I can delete it from the array I use to create the cell in cellForRowAtIndexPath, but I get a strange error if I try to do the following, which is the same code as in tableView:commitEditingStyle:forRowAtIndexPath:
where it works fine
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i+1 inSection:1]
[self.tableView deleteRowsAtIndexPaths:[NSArray
arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
It gives an error
-[_WebSafeForwarder forwardInvocation:]
and then jumps out of the method but does not crash the app
Can anyone help?
You need to do that in this block.
[self.tableView beginUpdates];
///
[self.tableView endUpdates];
do notice one thing that when the the block reaches its end
- (void) numberOfRowsInSection:(NSInteger)section
will be called again. so u need to update the number of rows in table view also.
Hope this helps.
Thanks,
Madhup
Well you are missing a semi-colon on your first line.
When in doubt, clean up your syntax...
As a point of observation, most of the programmers I have worked with and talked to really hate UITableViewController. It really adds nothing to the functionality for the user and only obfuscates things that developers might really like to control... such as the position of the table via a XIB.
It's just a convenience class and in my experience, causes more issues than it prevents.

iPhone/Obj-C - Archiving object causes lag

Hi I have a table view, and when I delete a cell I am removing an item from an NSMutableArray, archiving that array, and removing the cell.
However, when I do this, it is causing the delete button to lag after I click it. Is there any way to fix this?
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
int row = [indexPath row];
[savedGames removeObjectAtIndex:row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
//this line causing lag
[NSKeyedArchiver archiveRootObject:savedGames toFile:[self dataFilePath]];
}
}
Thanks
It sounds like you know the answer already -- don't archive everything on every delete. This can be done a number of ways -- archiving only pieces at a time, delayed archiving (periodically/when quitting/other policies), or making your custom archiving code considerably faster, which I doubt would even help that much in the scheme of things. I've heard that MAKeyedArchiver was faster than NSKeyedArchiver, but I believe this was some time ago, and designed for the mac+potentially platform specific (on the bright side it was intended as a drop in replacement for the NSKeyedArchiver API of the time, so it should be little integration time if you choose to use it).