When an user deletes some table row with swipe-to-delete action,
Instruments Tool shows that the deleted UITableViewCell instance is still alive.
I used very ordinary approach that is:
-(UITableViewCellEditingStyle) tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellEditingStyleDelete;
}
-(void) tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if(editingStyle == UITableViewCellEditingStyleDelete){
// Do Some Processing Model things...
[self.tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation: UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];
}
}
I can't sure but I think It is bug that is related with ARC.
May I leave this problem or should I have to find any walk around?
TableView holds on to the cell so it can reuse them later.
Related
I'm trying to implement the swipe left to display the delete button.
The cell moves left, but there are no visible buttons. Why does this happen? What is the solution?
To be clear, I have searched on StackOverflow and tried at least a dozen posted "solutions", but none of them have worked for me.
Thanks in advance.
I tried using the following code, which does seem to make the table cell move, but the log does not show NSLog(#"commitEditingStyle");. Why does this happen?
// Swipe to delete.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"commitEditingStyle");
if (editingStyle == UITableViewCellEditingStyleDelete) {
NSLog(#"UITableViewCellEditingStyleDelete");
[listData removeObjectAtIndex:indexPath.row];
[self.tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView reloadData];
}
}
And I have tried adding:
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
Here is a screenshot:
The problem was that the table size was larger than my screen size. The solution is to set the constraints to match the width of the view.
// During startup (-viewDidLoad or in storyboard) do:
self.tableView.allowsMultipleSelectionDuringEditing = NO;
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
// Return YES if you want the specified item to be editable.
return YES;
}
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
//add code here for when you hit delete
}
}
I prepared a TableView containing data from NSMutableArray. There is an option to edit and reorder rows. All works fine, until the phone is shut down or too many applications are running in the background - there is an error message in Xcode that the application exited unexpectedly due to memory pressure.
I would like to add some command to remain and remember previous cell order so after iPhone shut down user will have the same order as before.
Below is the code I am using for enabling reorder. Is there anything missing? Please bear with me, these are just my initial developing attempts.
Thanks in advance for any help!
Matus
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath: (NSIndexPath *)indexPath {
return UITableViewCellEditingStyleDelete;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle: (UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
[_Title removeObjectAtIndex:indexPath.row];
[_Images removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
NSString *item = [self.Title objectAtIndex:fromIndexPath.row];
[self.Title removeObject:item];
[self.Title insertObject:item atIndex:toIndexPath.row];
NSString *image = [self.Images objectAtIndex:fromIndexPath.row];
[self.Images removeObject:image];
[self.Images insertObject:image atIndex:toIndexPath.row];
}
- (void)tableView:(UITableView *)tableView didEndReorderingRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:indexPath.section]
withRowAnimation:UITableViewRowAnimationNone];
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
I really wish I could comment at this point... So, I already apologize for writing this as an answer.
You really shouldn't discard the fact that your app is being shut down by the OS. This is the main issue. Not the persistence of the data.
After you fix that, you can then look into how to persist your data (using Core Data, or a simple plist file) when leaving the app (using either one of the method in the UIApplicationDelegate protocol, or one of the application notifications). And loading it back when reopening it.
You need to make sure that you're persisting the changes to self.Title and self.Images.
If you add a call to the code you use to save the order of your rows at the end of tableView:MoveRowAtIndexPath:toIndexPath: then any change in the order of the rows should always be saved.
You can test that this is working by stopping the app (either by Cmd+. or the stop sign) immediately after you move a row.
I took approach of the UITableview to get cell click ExpandView. I want something like this to be implement.
So, UITableView would be best approach for this or suggest me any good way of implementing, also I am not able to get subview to adjust according to screenSize.
Could be there are another ways to accomplish this but this is how I am expand UITableViewCell on the fly. This could give the idea and you can implement your solution.
I keep row heights in my data model:
- (void)viewDidLoad {
[super viewDidLoad];
//Data source
datasource = [[NSMutableArray alloc] init];
NSMutableDictionary *aDicti = [[NSMutableDictionary alloc] init];
[aDicti setValue:#"a TEXT" forKey:#"text"];
[aDicti setValue:#(50) forKey:#"cellheight"]; // here
}
When selection changed, just updating related key in data source.
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView beginUpdates];
[[datasource objectAtIndex:indexPath.row] setObject:#(50) forKey:#"cellheight"];
[tableView endUpdates];
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView beginUpdates];
[[datasource objectAtIndex:indexPath.row] setObject:#(200) forKey:#"cellheight"];
[tableView endUpdates];
}
Once [tableView endUpdates]; executed heightForRowAtIndexPath and numberOfRowsInSection delegate methods fired and automatically adjust cell height with the value from data source.
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return [[[datasource objectAtIndex:indexPath.row] objectForKey:#"cellheight"] intValue];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return datasource.count;
}
If you do not want to keep row height in your data source you can basically apply this.
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView beginUpdates];
[tableView endUpdates];
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView beginUpdates];
[tableView endUpdates];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (tableView.indexPathForSelectedRow.row == indexPath.row) {
return 100;
}
return 50;
}
That's call, accordion, this site having good examples (with demos) for it, here's the link.
Basically when you are working with TableView you should play with number of section headers and cells.
In case of using section headers you should set numberOfRowsInSection to 0 (roll up) to X when you want to expand it. After that call
tableView.reloadData
I implemented this behavior here, with animation, with different heights:
https://github.com/rudald/expandedTableViewIOSSwift/
There are numerous open source projects regarding this feature. I've downloaded a few projects and the most customizable and issue-less, for me, was SLExpandableTableView
SDNestedTable does exactly what you want.
The module concept is that of having all the default functionality of
a UITableView and its cells while at the same time adding for each
cell a child UITableView. Each cell (SDGroupCell) in the main
SDNestedTableViewController tableview acts as controller for its own
sub table. The state, population and behavior of the table and
subtable is instead mostly controlled by
SDNestedTableViewController.
If you’re looking for a straight forward easy-to-setup library for expandable views, HVTableView is your choice. It provides an acceptable performance which is sufficient for using in regular projects.
I have a TableView with three sections. Section one and two can be deleted, (delete with swipe)
section three can't. My problem now is that when I swipe on a cell in the third section, it gets selected. I tried deselecting it when "canEditRowAtIndexPath" is called(and it really gets called), but that doesn't work and the cell remains selected. My "canEditRowAtIndexPath" looks like this:
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.tableView deselectRowAtIndexPath:indexPath animated:NO];
if (indexPath.section == 2)
{
return NO;
}
return YES;
}
I found ( in my opnion ) a better solution to this matter
self.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Right)
I hope that helps!!
Regards
You may check and close the 3rd section cell selections in -(UITableViewCell *) tableView:(UITableView *) tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath by using tableViewCell.selectionStyle = UITableViewCellSelectionStyleNone;
You should call [self.tableView deselectRowAtIndexPath:indexPath animated:NO]; in this method -
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
Or in -
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
Set selection style none. cell.selectionStyle = UITableViewCellSelectionStyleNone;
Use this delegate method of UITableView
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
I found a great workaround.
A swipe on the cell, forces the app to call viewWillAppear.
Add [self.tableView reloadData];into that method and the selected state will be removed.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
this seems to work with a break point on the deleteRowsAtIndexPaths: line, but when I take it out I get EXC_BAD_ACCESS and a crash. NO idea why - its the default code in there for a TableViewController - I added some code and it didn't work. Put break points in and it turned out it was that line, so stripped it right down to the original code and it still doesn't work! :( Argh...
Any ideas?
Thanks
When you delete a row in a tableView numberOfRowsInSection needs to update to return the number of rows before deleting the row minus 1, or else you get this ambiguous crash.