Unable to refresh UITableView when rows are deleted - ios

I have a UITableView having many rows that contains UITextFields. User enters data to these fields. user can delete or add any rows. When i am trying to delete any row it deletes the correct row from the array(that contains all the cell's reference) but the UITextfield always shows that the last row is deleted.
-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _countEmailValues.count ;
}
-(NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"CustomEmailCell";
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
if (!cell) {
cell = [[LACustomEmailCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.emailTextField.tag = 555;
cell.deleteEmailFieldButton.tag = indexPath.row;
NSLog(#"delete email Field tag %i",cell.deleteEmailFieldButton.tag );
cell.emailTextField.delegate = self;
if ([_countEmailValues count] > 1 )
{
cell.deleteEmailFieldButton.hidden = false;
}
else
{
cell.deleteEmailFieldButton.hidden = true;
}
// Reason why I am adding cell.emailtextfield in this delegate? is should be in addButtonclick but cell.emailtextfield is not
// initialized there. Also adding of only cell will give null for the emailTextField.
// So adding all cells here and then removing duplicates entires and accessing over the app.
[_emailValues addObject:cell.emailTextField];
// Remove Duplicate elements.
NSArray *emailFieldCollection = [_emailValues copy];
NSInteger index = [emailFieldCollection count ] -1;
for (id object in [emailFieldCollection reverseObjectEnumerator])
{
if ([_emailValues indexOfObject:object inRange:NSMakeRange(0, index)] != NSNotFound)
{
[_emailValues removeObjectAtIndex:index];
}
index--;
}
NSLog(#"Row : %i",indexPath.row);
return cell;
}
- (IBAction)deleteEmailClick:(UIButton *)sender
{
NSIndexPath *index = self.emailTableView.indexPathForSelectedRow;
// [self.emailTableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row inSection:0] animated:YES scrollPosition:0];
NSIndexPath *indexPath = [_emailTableView indexPathForSelectedRow];
NSLog(#"Tags %i", sender.tag);
// [self.emailTableView reloadData];
if ([_countEmailValues count] > 0)
{
[ _countEmailValues removeObjectAtIndex:sender.tag];
}
// NSLog(#"array after %#",_countEmailValues);
if ([_countEmailValues count] == 0)
{
// _deleteEmailButton.hidden = true;
_doneButton.hidden = true;
}
NSLog(#"array before %#",_emailValues);
if ([_emailValues count] > 0)
{
[_emailValues removeObjectAtIndex:sender.tag];
}
[self.emailTableView reloadData];
}
The _emailValues gets updated properly but the data in the fields is always getting cleared of the last one.
EX: in the image if i delete "b" the _emailValues gets cleared properly but the ui shows two field having data "a" & "b" . what have i missed here?
pls help.

You are not deleting the cell . In deleteEmailClick add this line
[self.emailTableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationLeft];
Also I would like to point out another way of implementing delete using a block. This will ensure that you always have the correct cell and no need to tag your delete button. This would be cleaner and maintainable. In your custom cell class LACustomEmailCell declare a block property like so
#property (strong, nonatomic) void (^deleteButtonTappedBlock)();
Connect the IBAction of your delete button in the LACustomEmailCell class and from there call this block. I am assuming the name as deleteButtonPressed
- (IBAction)deleteButtonPressed:(id)sender {
self.deleteButtonTappedBlock();
}
Now in -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
You can set the block like this
[cell setDeleteButtonTappedBlock:^(){
//Action to perform when cell is deleted. In your case the code in `deleteEmailClick` will go here.
//In the end delete the cell.
[self.emailTableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationNone];
}];
i hope this helps

Related

why selection of a cell in one section affect to cells in other sections in iOS tableview, objective c [duplicate]

I have a table view with 5 sections and I have set the tableview selection to multiple. Each section have different number of rows. What I want is to set that the user can select only one cell from each section(in my table user can select any number of cells).
ex: 5 cells from 5 sections.
It should be impossible to select more than one cell from any section. If user select another cell from same section, previously selected cell should be deselected. How can I do this. This is a sample implementation of didSelectRowAtIndexPath.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
HoteldetalcelloneTableViewCell *cellone = (HoteldetalcelloneTableViewCell *)[self.detailtableView cellForRowAtIndexPath:indexPath];
HoteldetailcelltwoTableViewCell *celltwo = (HoteldetailcelltwoTableViewCell *)[self.detailtableView cellForRowAtIndexPath:indexPath];
//I have implement for two sections to test.
if(indexPath.section == 0)
{
HotelDetailsone *secone = [roomonearray objectAtIndex:indexPath.row];
HoteldetailsforBooking *book = [HoteldetailsforBooking new];
if([secone.offerallow isEqualToString:#"True"])
{
celltwo.selectedsignLabel.hidden = NO;
}
else
{
cellone.selectedsignLabelone.hidden = NO;
}
// [self.detailtableView reloadData];
NSLog(#"price for room 1 : %#", secone.itempriceText);
}
else
{
HotelDetailsone *sectwo = [roomtwoarray objectAtIndex:indexPath.row];
HoteldetailsforBooking *book = [HoteldetailsforBooking new];
if([sectwo.offerallow isEqualToString:#"True"])
{
celltwo.selectedsignLabel.hidden = NO;
}
else
{
cellone.selectedsignLabelone.hidden = NO;
}
// [self.detailtableView reloadData];
NSLog(#"price for room 1 : %#", sectwo.itempriceText);
}
}
You need to keep track on the selection of cell. So you need to store selected indexpath in array.
in ViewController.h declare property like this
#property(nonatomic,strong) NSMutableDictionary *selectionData;
Now in ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
self.selectionData=[[NSMutableDictionary alloc]init];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
TestTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"mycell"];
if ([self.selectionData objectForKey:[NSString stringWithFormat:#"%ld",(long)indexPath.section] ] != nil) {
NSMutableArray *sectionData=[[self.selectionData objectForKey:[NSString stringWithFormat:#"%ld",(long)indexPath.section]] mutableCopy];
if (![sectionData containsObject:[NSNumber numberWithLong:indexPath.row]])
{
cell.accessoryType = UITableViewCellAccessoryNone;
cell.numberlabel.text = #"2";
}
else
{
cell.numberlabel.text = #"***";
cell.accessoryType=UITableViewCellAccessoryCheckmark;
}
}
else
{
cell.numberlabel.text = #"2";
cell.accessoryType = UITableViewCellAccessoryNone;
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"selected section :%li ---> selected row :%li",(long)indexPath.section, (long)indexPath.row);
[self handleSelectionForSection:indexPath.section row:indexPath.row];
[self.tablev reloadData];
}
-(void)handleSelectionForSection:(long)sectionIndex row:(long)rowIndex
{
if ([self.selectionData objectForKey:[NSString stringWithFormat:#"%ld",sectionIndex] ] != nil) {
NSMutableArray *sectionData=[[self.selectionData objectForKey:[NSString stringWithFormat:#"%ld",sectionIndex]] mutableCopy];
if (![sectionData containsObject:[NSNumber numberWithLong:rowIndex]])
{
//removing previous selected rows
[sectionData removeAllObjects];
[sectionData addObject:[NSNumber numberWithLong:rowIndex]];
[self.selectionData setObject:sectionData forKey:[NSString stringWithFormat:#"%ld",sectionIndex]];
}
else
{
//cell you tapped is already selected,
// you can deselect it by removing object
//if you dont want to deselect it comment following lines
[sectionData removeObject:[NSNumber numberWithLong:rowIndex]];
[self.selectionData setObject:sectionData forKey:[NSString stringWithFormat:#"%ld",sectionIndex]];
}
}
else
{
//section key not available so we need to create it
NSMutableArray *sectionData=[[NSMutableArray alloc]init];
[sectionData addObject:[NSNumber numberWithLong:rowIndex]];
[self.selectionData setObject:sectionData forKey:[NSString stringWithFormat:#"%ld",sectionIndex]];
}
NSLog(#"All Selection : %#",self.selectionData);
}
Your numberOfRowsInSection, numberOfSectionsInTableView and titleForHeaderInSection will remain same.
Let me know if you have any query.
You can set selection property of tableview from interface builder. Select your tableview in IB and then select attribute inspector and setsingle selectiontoselection` property like below screenshot.
Or you can set programattically,
self.tableView.allowsMultipleSelection = NO;
Update :
If you want single selection per section then you can implement willSelectRowAtIndexPath as below,
- (NSIndexPath*)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath*)indexPath {
for ( NSIndexPath* selectedIndexPath in tableView.indexPathsForSelectedRows ) {
if ( selectedIndexPath.section == indexPath.section )
[tableView deselectRowAtIndexPath:selectedIndexPath animated:NO] ;
}
return indexPath ;
}
In this case you should allow multiple selection in tableview i think.
Reference : Answer of John Sauer
Looks like you are updating celltwo / cellone selectedsignLabel.hidden on table selection. so #Lion solution will not working. You have to save the last selected index using below code :
#property (nonatomic, strong) NSMutableDictionary *selectedIndexPathDict;
// in viewDidLoad:
self.tableView.allowsMultipleSelection = YES;
self.selectedIndexPathDict = [[NSMutableDictionary alloc] init];
//In table view delegate.
- (NSIndexPath*)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath*)indexPath {
NSString *indexSection = [NSString stringWithFormat:#"%ld", (long)indexPath.section];
NSIndexPath *indexPath1 = self.selectedIndexPathDict[indexSection];
if ( indexPath1) {
HotelDetailsone *secone = [roomonearray objectAtIndex:indexPath.row];
secone.offerallow ^= YES; //toggle bool value
// update new selected index path.
[self.selectedIndexPathDict setObject:indexPath forKey:indexSection];
//reload previous selected cell.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(),^{
[tableView beginUpdates];
[tableView reloadRowsAtIndexPaths:#[indexPath1] withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
});
} else {
//initialise selected index path
self.selectedIndexPathDict[indexSection] = indexPath;
}
[tableView deselectRowAtIndexPath:indexPath animated:NO] ;
return indexPath ;
}
I have not update the complete working code. But this is the way to achieve. You can also use the userdefault instead of self.selectedIndexPathDict.

How to show Updated values of UITableViewCell from another method ?

I declared globally
NSIndexPath *selectedIndexPath;
and here is my didselectmethod
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath: (NSIndexPath *)indexPath
{
UIAlertView *loAlert = [[UIAlertView alloc]initWithTitle:#"Are you sure you want to redeem?" message:nil delegate:self cancelButtonTitle:#"Yes" otherButtonTitles:#"No", nil];
loAlert.tag = 10;
[loAlert show];
selectedIndexPath = indexPath;
}
After selecting row i am showing alert
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex: (NSInteger)buttonIndex
{
if(alertView.tag == 10)
{
if(buttonIndex == 0)
{
[self redeemOfferService];
}
}
}
Then calling redeemOfferService, in this method i am facing problem
- (void)redeemOfferService
{
OffersBoughtCellTableViewCell * selectedCell1 = [offersTableView cellForRowAtIndexPath:selectedIndexPath];
NSLog(#"%# ************", selectedCell1.quantity.text);
// for e.g. selected cell's quantity is 0 (here i can see selected cell quantity)
i want to change and update here as follow
selectedCell1.quantity.text = #"Quantity : 5";
// after this i can see quantity in my cell is 5 but
when i scroll values are again showing from
cellForRowAtIndexPath i want to show updated value on cell,
how to do this ?
}
For more details here is my cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
OffersBoughtCellTableViewCell *cell = (OffersBoughtCellTableViewCell *)
[tableView dequeueReusableCellWithIdentifier:#"offersCell" forIndexPath:indexPath];
OfferDetail * offerDetailObj=[[OfferDetail alloc]init];
// OfferDetail, OffersBoughtDetails are NSObject class
// #property (nonatomic, strong) OfferDetail *offerObj;& OffersBoughtDetails * selectedOfferBoughtObj;
// and #property (nonatomic, strong) NSArray *offersBought;
offerDetailObj=[self.listOfOffers objectAtIndex:indexPath.row];
OffersBoughtDetails * offerBoughtObj=[self.offerObj.offersBought objectAtIndex:indexPath.row];
selectedOfferBoughtObj=offerBoughtObj;
cell.quantity.text=[NSString stringWithFormat:#"Quantity : %#",offerBoughtObj.quantity];
}
The problem is that when you scroll to your changed cell again, - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath get invoked, but your data would not change,cell.quantity.text=[NSString stringWithFormat:#"Quantity : %#",offerBoughtObj.quantity];, so your cell's quantity still shows what your data model offerBoughtObj is.
Since iOS uses MVC, a solution is you change your data model, and then reflect your model changes to your view.
- (void)redeemOfferService {
OffersBoughtDetails * offerBoughtObj=[self.offerObj.offersBought objectAtIndex:selectedIndexPath];
// change offerBoughtObj to the value you want
offerBoughtObj.quantity = whateveryoulike;
// reload your tableview
[tablview reloadRowsAtIndexPaths:#[selectedIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
As far As I understand your problem after selecting a Cell You want to remove that cell from UITableView.
To do this put all your UITable data in NSMutableArray
And In your - (void)redeemOfferService method after doing all task
just remove that selected object like:
[dataArray removeObject:#"selectedObject"];
And reload the table Data
[tableView reloadData];
You have to update the source of the table, the offerDetailObj in your case, so in - (void)redeemOfferService methods, fetch the data from the array and get the selected object, update it's value and save it again to your array. I think this should work:
- (void)redeemOfferService
{
OffersBoughtCellTableViewCell * selectedCell1 = [offersTableView cellForRowAtIndexPath:selectedIndexPath];
NSLog(#"%# ************", selectedCell1.quantity.text);
// for e.g. selected cell's quantity is 0 (here i can see selected cell quantity)
//i want to change and update here as follow
selectedCell1.quantity.text = #"Quantity : 5";
//Update your source array to the correct value
offerDetailObj=[self.listOfOffers objectAtIndex:indexPath.row];
OffersBoughtDetails * offerBoughtObj=[self.offerDetailObj.offersBought objectAtIndex:indexPath.row];
OffersBoughtDetails.quantity = 5;
[offerDetailObj replaceObjectAtIndex:indexPath.row withObject:offerBoughtObj];
self.listOfOffers replaceObjectAtIndex:indexPath.row withObject:offerDetailObj];
}
Your Array should be mutable so you can add/remove/replace object from it, means that your listOfOffers and offersBought should be NSMutableArray.
I think in your alertViewDelegate method you should set selectetdIndexPath to nil if the user selects NO
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex: (NSInteger)buttonIndex
{
if(alertView.tag == 10)
{
if(buttonIndex == 0)
{
[self redeemOfferService];
}
else
selectedIndexPath = nil;
}
}
and in your redeemOffService you should reload cell
- (void)redeemOfferService
{
OffersBoughtCellTableViewCell * selectedCell1 = [offersTableView cellForRowAtIndexPath:selectedIndexPath];
NSLog(#"%# ************", selectedCell1.quantity.text);
// for e.g. selected cell's quantity is 0 (here i can see selected cell quantity)
i want to change and update here as follow
selectedCell1.quantity.text = #"Quantity : 5";
[self.tableView reloadRowsAtIndexPaths:#[selectedIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
selectedIndexPath = nil;
}
Hope this helps :D

Unable to add and delete rows simultaneously

I am following a tutorial,where I can expand the table view by adding some sub-cells and collapse the table by removing the sub-cells. I am trying to change how the expand operation should execute. When I tap on a row,it expand and shows the sub-cells,and when I tap on other row,the previous expanded row should close. I am not able to do this . I tried the following but I couldnt make the one row expandable at a time,and the other row should close when one expands.
Note: This code works fine,but to collapse the row,we need to tap twice on the same row. I am trying to collapse when other parent is tapped.
Here is the code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
Node *node = [self nodeForIndexPath:indexPath];
// differenet table view cell prototypes for different node levels
UITableViewCell *cell;
if(node.level == 0)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"level1cell" forIndexPath:indexPath];
}
else
{
cell = [tableView dequeueReusableCellWithIdentifier:#"level2cell" forIndexPath:indexPath];
}
// set the nodes title as row text
cell.textLabel.text = node.title;
// attach the nodeId for later lookup when selected
cell.tag = node.nodeId;
// Configure the cell...
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Node *node = [self nodeForIndexPath:indexPath];
// NSLog(#"node id is %ld level is %ld and indexpath.row is %d",(long)node.nodeId,(long)node.level,indexPath.row);
node.expanded = !node.expanded;
if (node.level==0) {
NSLog(#"you tapped parent");
//now check other parents are expanded or not
}else{
NSLog(#"you tapped child");
}
//insertion always happen after deletion
// NSLog(#"you touched at %#,index row is %d",indexPath,indexPath.row);
if(node.expanded )
{
// add n rows
NSMutableArray *indexPaths = [NSMutableArray array];
for(NSInteger i=indexPath.row; i< indexPath.row+node.subNodes.count; i++)
{
[indexPaths addObject:[NSIndexPath indexPathForRow:i+1 inSection:0]];
}
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
}
else
{
//you store the node refe after row is expanded
// delete n rows
NSMutableArray *indexPaths = [NSMutableArray array];
for(NSInteger i=indexPath.row; i< indexPath.row+node.subNodes.count; i++)
{
[indexPaths addObject:[NSIndexPath indexPathForRow:i+1 inSection:0]];
}
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
}
}
#pragma mark - Private helper
-(Node*) nodeForIndexPath:(NSIndexPath*)indexPath
{
int idx = 0;
for(Node *node in _nodes)
{
if(idx == indexPath.row)
{
return node;
}
idx++;
if(node.expanded)
{
for (Node *subNode in node.subNodes)
{
if(idx == indexPath.row)
{
return subNode;
}
idx++;
}
}
}
return nil;
}
KMAccordionTableViewController can helps you?
https://github.com/klevison/KMAccordionTableViewController
Hm... If your current code is working, but you need to tap twice to collapse the open/selected row, perhaps it's because didDeselectRowAtIndexPath: is being called during that first tap in place of didSelectRowAtIndexPath: in order to deselect the selected row. I'd recommend configuring your tableview to allow for multiple selection so that didSelectRowAtIndexPath: is called every time, ex:
- (void)viewDidLoad {
[super viewDidLoad];
tableView.allowsMultipleSelection = YES;
}

Why am I getting an assert Error When trying to Delete a section in a tableview ios

I have a tableView with some sections, which all have a footer, and then I have a tableViewFooter on the Tableview itself.
If I scroll down to the bottom of my tableview and delete the last item(therefore deleting the section altogether) in any sections above the last section (second last and up) it gives me this error
2014-02-21 13:19:55.066 xxxx[5436:60b] *** Assertion failure in -[UIViewAnimation initWithView:indexPath:endRect:endAlpha:startFraction:endFraction:curve:animateFromCurrentPosition:shouldDeleteAfterAnimation:editing:], /SourceCache/UIKit/UIKit-2903.23/UITableViewSupport.m:2661
Uncaught exception: Cell animation stop fraction must be greater than start fraction
at endUpdates
this is my code
[self.tableView beginUpdates];
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
if(indexPath != nil){
TableSection * sec = [self.sections objectAtIndex:indexPath.section];
NSMutableDictionary *dic =[sec.items objectAtIndex:indexPath.row];
Product* product = [dic valueForKey:PRODUCT];
//removing the item in the section
[sec.items removeObject:dic];
//deleting item from products
NSMutableArray *temp = [NSMutableArray array];
for (Product *p in self.dataCon.listPersister.products) {
if ([p.product.objId isEqualToString: product.product.objId]) {
[temp addObject:p];
}
}
for (Product *p in temp) {
[self.dataCon.listPersister.products removeObject:p];
}
//if it was the last object in section, delete the section else just delete the single row
if(sec.items.count == 0)
{
[self.sections removeObject:sec];
[self.footers removeObjectAtIndex:indexPath.section];
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationFade];
} else
{
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
USFooterView *footer = [self.footers objectAtIndex:indexPath.section];
footer.totalLabel.text = [self.dataCon.listPersister getTotalForShopId:sec.title];
self.footerView.totalLabel.text = [self.dataCon.listPersister getTotalForAllProducts];
}
}
[self.tableView endUpdates];
I had the same code earlier, just without my tableView and table sections having footers, where it worked, so I think they might be the problem, but I'm not entirely sure that's the reason it's acting up.
I have seen this post
UITableView tableFooterView may cause crash?
And the post that it links to, but that didn't help me.
Any help is appreciated :)
In the else statement you delete row from table view:
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
But not from data source. Delete row from array which you use as data source and it should works.
I found a "fix", but I'm avoiding the use of sectionFooter, because that seems to be bugged.
I created an extra cell at the end of each section, with the same setup I had for my footer View before, and made that last cell not editable with
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
TableSection * sec = [self.sections objectAtIndex:indexPath.section];
if (sec.items.count != indexPath.row) {
return YES;
} else
return NO;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [sec.items count] +1 ;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"normalcell";
static NSString *CellIdentifier1 = #"footercell";
TableSection * sec = [self.sections objectAtIndex:indexPath.section];
if (indexPath.row != sec.items.count) {
//use normal type of cell
return cell;
} else{
//use footer type of cell
return cell;
}
}
So the last cell Imitates a "footer", but it's not stuck to the bottom of the frame, but I'll have to live with that. It's better than crashes.
Try using UITableViewRowAnimationLeft or UITableViewRowAnimationRight as the delete row animation(deleteRowsAtIndexPaths:withRowAnimation:).
It crashed for me when using UITableViewRowAnimationAutomatic, but not with the other two. I have not tried all of them but it seems to be a bug with the animation code for some of the options.

How to create a dynamic size array

What I am trying to achieve:
I have a UITableView and I want to check whether the table was selected or not and keep in an array easy to access the YES or NO values that corresponds to that row so that afterwards i can manipulate the data.
my code as follows
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger row = [indexPath row];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSString *cellLabelText = cell.textLabel.text;
if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryNone;
selected[row] = NO;
}
else {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
selected[row] = YES;
}
}
As it stands out I can create a BOOL selected[some value] but my problem is that the max index needed for me is unknown as my table size changes constantly. thus setting the max index limits me.
I am new to objective C and I come from a PHP background thus I dont know whether it is possible to create an array that does what i want to do in objective-c.
Otherwise what would be my options within objective-c to have an easy way to easy write/read selected[row] = YES/NO.
I need a way to write YES/NO and link it to the indexpath.row
Use an NSMutableSet and store the NSIndexPath of the selected rows. If you select a row you add the path to the set. If you unselect a row, remove the path from the set.
To see if a row is selected, see if the indexPath is in the set or not.
BTW - this only works if the rows are fixed. If the user can add, remove, or reorder rows then this approach will not work. In such a case you need to store data keys, not index paths.
Create an ivar of type NSMutableSet. Let's call it selectedRows:
selectedRows = [[NSMutableSet alloc] init];
Then in didSelectRow you do:
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
BOOL selected = [selectedRows containsObject:indexPath];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSString *cellLabelText = cell.textLabel.text;
if (selected) {
cell.accessoryType = UITableViewCellAccessoryNone;
[selectedRows removeObject:indexPath];
} else {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[selectedRows addObject:indexPath];
}
}
In your cellForRow... method you do something similar:
BOOL selected = [selectedRows containsObject:indexPath];
cell.accessoryType = selected ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
Just use
NSMutableArray *dynamicArray = [NSMutableArray array];
You can add and delete objects from this at will. Just be sure to use the NSNumber wrapper to add primitives:
[dynamicArray addObject:[NSNumber numberWithInt:indexNumber]];
// or
[dynamicArray addObject:#(indexNumber)];
Instead of an array you can use a index set.
#property (nonatomic,strong) NSMutableIndexSet *pickedIndexPaths;
- (void)viewDidLoad
{
_pickedSIndexPaths = [[NSMutableIndexSet alloc] init];
[super viewDidLoad];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//…
if(indexPath.section == 0) {
cell.textLabel.text = self.sports[indexPath.row][#"sport"][#"name"];
if ([_pickedIndexPaths containsIndex:indexPath.row]) {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
} else {
[cell setAccessoryType:UITableViewCellAccessoryNone];
}
}
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([_pickedIndexPaths containsIndex:indexPath.row]) {
[_pickedIndexPaths removeIndex:indexPath.row];
} else {
[_pickedIndexPaths addIndex:indexPath.row];
}
[tableView reloadData];
}
}
When what you need is a variable length array of boolean values, you can use CFBitVectorRef. This will consume much less memory than using a Cocoa collection designed for objc object values (provided of course that array has many elements) because it consumes 1 bit for each value, rather than a full pointer which points to an individual dynamically allocated reference counted object.

Resources