I'm trying to create an array from selected table rows so I can push it to a new view. My issue is deleting an unselected row from the array it throws an error of index beyond bounds, although I have other items selected.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//listOfItems is a Pre Populated Array for the table
NSString *cellValue = [listOfItems objectAtIndex:indexPath.row];
//the array i want my selected items to be added to
NSArray *array = names;
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[names addObject:cellValue];
NSLog(#"ARRAY: %#", array);
}
else {
cell.accessoryType = UITableViewCellAccessoryNone;
[names removeObjectAtIndex:indexPath.row];
NSLog(#"ARRAY: %#", array);
}
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
}
How do I find the index number in the array that is being created so it can delete the proper value? Any help would be appreciated :-) Thanks!
-----SOLUTION-----
Here's an alternative way too just in case others were wondering.
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSString *selected = [listOfItems objectAtIndex:indexPath.row];
if (cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[names addObject:selected];
NSLog(#"ARRAY ADDED %#", names);
}
else {
cell.accessoryType = UITableViewCellAccessoryNone;
[names removeObject:selected];
NSLog(#"ARRAY DELETED %#", names);
}
If your intention is to pass an array of checked cell values to a view, why adding and removing objects at each cell selection? You could easily achieve this just before you're about to present the new view controller. Something like this:
// In whatever method you have to present the new view controller
// ...
NSMutableArray *names = [[NSMutableArray alloc] initWithCapacity:0];
for (int i = 0; i < listOfItems.count; i++)
{
if ([self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]].accessoryType == UITableViewCellAccessoryCheckmark) //Change section number if not 0
{
[names addObject:[listOfItems objectAtIndex:i]];
}
}
// Pass the array now to the destination controller
Ps. You still have to manage checking/unchecking of cells (just as you're already doing in the code above).
Related
I have a tableview that I can add and remove multiple checkmarks. The only issue is if I put 3 checkmarks and scroll away, when I return the checkmarks are gone. I can't find anywhere on the internet a solution that works, and I've tried several variation and still nothing.
This is my code in cellForRowAtIndex that should be holding the checkmarks in place.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *reuseIdentifier = #"contactCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
NSDictionary *contact = [self.tableData objectAtIndex:indexPath.row];
UILabel *nameLabel = (UILabel *)[cell viewWithTag:1];
NSString *firstName = contact[#"firstName"];
nameLabel.text = [firstName stringByAppendingString:[NSString stringWithFormat:#" %#", contact[#"lastName"]]];
UILabel *phoneNumber = (UILabel *)[cell viewWithTag:2];
NSArray *phones = contact[#"phones"];
if ([phones count] > 0) {
NSDictionary *phoneItem = phones[0];
phoneNumber.text = phoneItem[#"value"];
}
UIImageView *cellIconView = (UIImageView *)[cell.contentView viewWithTag:888];
UIImage *image = contact[#"image"];
cellIconView.image = (image != nil) ? image : [UIImage imageNamed:#"smiley-face"];
cellIconView.contentScaleFactor = UIViewContentModeScaleAspectFill;
cellIconView.layer.cornerRadius = CGRectGetHeight(cellIconView.frame) / 2;
// Need to fix
if([checkedIndexPath isEqual:indexPath])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
Here is the didSelectRowAtIndexPath method
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath: (NSIndexPath *)indexPath
{
UITableViewCell* checkCell = [tableView cellForRowAtIndexPath:indexPath];
if(checkCell.accessoryType == UITableViewCellAccessoryCheckmark)
{
checkCell.accessoryType = UITableViewCellAccessoryNone;
NSMutableArray *i = [[NSMutableArray alloc] init];
for (NSIndexPath *indexPath in [self.tableView indexPathsForSelectedRows]) {
[i addObject:self.tableData[indexPath.row]];
// Go inside pull the numbers from the users and save in an NSArray
// NSArray *contacts = i;
// self.recipients = [[NSMutableArray alloc] init];
for (NSDictionary* dict in i) {
// Grab phones
NSDictionary *contactNumber = [dict objectForKey:#"phones"];
for (NSDictionary* dict2 in contactNumber) {
// Grabs the phone numbers
NSString* value = [dict2 objectForKey:#"value"];
int index = [self.recipients indexOfObject:value];
[self.recipients removeObjectAtIndex:index];
[self.selectedUsers removeObjectAtIndex:index];
NSLog(#"The number that has a checkmark%#", value);
NSLog(#"the array of all%#", self.recipients);
NSLog(#"At index %lu", (unsigned long)[self.recipients indexOfObject:value]);
// [_recipients addObject:value];
}
}
// NSLog(#"Phone Numbers: %#",_recipients);
}
}
else
{
[self getNumber];
NSLog(#"clicking %#", self.recipients);
UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
checkedIndexPath = indexPath;
}
}
I found The Solution:
You must save each indexPath into an array(put this code in didSelectRowAtIndexPath) and then in cellForRowAtIndexPath add the following code
if([self.checkedCells containsObject:indexPath]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
Also in the didSelectRowAtIndexPath
Make sure to delete the indexPath when deselecting the row.
if(checkCell.accessoryType == UITableViewCellAccessoryCheckmark) {
checkCell.accessoryType = UITableViewCellAccessoryNone;
[self.checkedCells removeObject:indexPath];
I hope this helps someone. I been wrestling with this all day.
Make checkedIndexPath a #property (nonatomic, strong) and use self.checkedIndexPath whenever you refer to it. You're losing the reference after didSelectRowAtIndexPath exits. Set a breakpoint in cellForRowAtIndexPath and look at checkedIndexPath, I bet it's nil.
Maybe you should check if the isEqual functionality does what you expect. You could make sure by trying:
if (_checkedIndexPath.section == indexPath.section &&
_checkedIndexPath.row == indexPath.row)
If you still do not get the expected result, perhaps log the values of section and row to see where it goes wrong.
Please note that if for some reason _checkedIndexPath is a weak variable or gets deallocated, this check will fail.
You could also check that your cells are properly dequeued before being modified and that you are returning the correct cells.
If you want to store more than one checked row, of course, you will need more than one indexPath variable (just one _checkedIndexPath will not do it).
I need to get addressability to the UITableView cell so I can set the checkmark if the user has previously selected that row. Initially, the user checks the tableViewCell, I move that to a textField and store it in Core Data. Now if the user wants to change something in the UITableView, I want to be able to show what is already checked or unchecked.
So, I have a UITableView that I present in a UIPopover (outside of -cellForRowAtIndexPath); if a particular cell has a text value equal to an element in a NSArray, I want to set the cell's accessoryType to checked. This is my UPDATED code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// get the timeFormat
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSMutableDictionary *preferencesDict = [[userDefaults dictionaryForKey:#"preferencesDictionary"] mutableCopy];
int iTimeFormat = [[preferencesDict objectForKey:#"timeFormat"] intValue]; // set timeFormat
if(tableView.tag == kServicesTableView) { // services array
static NSString *CellIdentifier = #"servicesCell"; // servicesCell is just an identifier; not used that I can tell
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:(UITableViewCellStyleDefault) reuseIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell
SingletonServicesArray *sharedServicesArray = [SingletonServicesArray sharedServicesArray]; // initialize
[cell.textLabel setText:[sharedServicesArray.globalServicesArray objectAtIndex:indexPath.row]];
if( ![soServices hasText] ) { // no text in text box
for (int i = 0; i < sharedServicesArray.globalServicesArray.count; i++) {
NSIndexPath *path = [NSIndexPath indexPathForRow:i inSection:0];
// if row has been checked, remove the check
UITableViewCell *cell = [servicesTableView cellForRowAtIndexPath:path];
if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryNone;
break;
}
}
}
else { // not empty
for (int i = 0; i < sharedServicesArray.globalServicesArray.count; i++) {
NSIndexPath *path = [NSIndexPath indexPathForRow:i inSection:0];
UITableViewCell *cell = [servicesTableView cellForRowAtIndexPath:path];
// if row is in soServices textfield, add a checkmark
if ([soServices.text containsString: sharedServicesArray.globalServicesArray[i]]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
break;
}
}
}
return cell;
}
It's not working; I know for sure at least two of the services are in the array, so I should have two cells with checkmarks; I'm getting zilch!. How do I get this to work correctly?
If I get it correctly, this cellForRowAtIndexPath is updating the cells of a DIFFERENT tableView. It would be more logical to add the above code to the cellForRowAtIndexPath of the tableView that needs updating.
In case you are trying to update the cells of that tableView, then the following code would not work:
for (int i = 0; i < sharedServicesArray.globalServicesArray.count; i++) {
NSIndexPath *path = [NSIndexPath indexPathForRow:i inSection:0];
UITableViewCell *cell = [servicesTableView cellForRowAtIndexPath:path];
// if row is in soServices textfield, add a checkmark
if ([soServices.text containsString: sharedServicesArray.globalServicesArray[i]]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
break;
}
}
Instead, you would write:
for (int i = 0; i < sharedServicesArray.globalServicesArray.count; i++) {
// if row is in soServices textfield, add a checkmark
if ([soServices.text containsString: sharedServicesArray.globalServicesArray[i]]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
break;
}
}
I am using two NSMutable Arrays for storing multiple checkmarks..repeatDaysToStore and data1.
This is the code in viewDidLoad method...
for (int i=1; i<=[repeatDaysToStore count]; i++)
{
BOOL isTheObjectThere = [repeatArray containsObject:[repeatDaysToStore objectAtIndex:(i-1)]];
if (isTheObjectThere)
{
NSString *into=[repeatArray objectAtIndex:[repeatArray indexOfObject:[repeatDaysToStore objectAtIndex:(i-1)]]];
[data1 addObject:into];
NSLog(#"check did load");
}
}
and after this I am using data1 array for checking the cells...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text=[repeatArray objectAtIndex:indexPath.row];
tableView.allowsMultipleSelection=YES;
for (int j=1; j<=[data1 count]; j++) {
NSLog(#"%d",[[data1 objectAtIndex:(j-1)]intValue]);
NSLog(#"%d",indexPath.row);
if([data1 indexOfObject:[data1 objectAtIndex:(j-1)]]==indexPath.row)
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
and for handling row selections I am using this code in didSelectRowAtIndexPath
{
NSString *myobj=[repeatArray objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryNone;
[repeatDaysToStore removeObject:myobj];
[data1 removeObject:myobj];
} else {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[repeatDaysToStore addObject:myobj];
[data1 addObject:myobj];
}
[tableView reloadData];
}
but its not working.Someone please tell me what is wrong?
I think the issue is with cellForRowAtIndexPath: method's following code:
for (int j=1; j<=[data1 count]; j++)
{
NSLog(#"%d",[[data1 objectAtIndex:(j-1)]intValue]);
NSLog(#"%d",indexPath.row);
if([data1 indexOfObject:[data1 objectAtIndex:(j-1)]]==indexPath.row)
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
Remove the code and write the condition like:
if([data1 containsObject:[repeatArray objectAtIndex:indexPath.row])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
Also remove the [tableView reloadData]; from didSelectRowAtIndexPath:
I think you need a less-complicated data structure to make this work in a way that's easy to understand.
The data for your table should be an array of objects. Each object should contain at least two properties: one is the information you're going to show in cell.textLabel.text and the other is a BOOL property that says whether or not the object is selected.
When a row is selected, set the BOOL to the opposite of what it currently is and reload your table. In cellForRowAtIndexPath:, just use the current setting of the object for the requested row without going through a secondary array.
Recently started developing apps, so excuse my ignorance. I have a tableView, and when a cell in the table view is clicked, I want to insert a new row directly below it. This currently works in my code. However, I also want the row that has been inserted to be removed once the cell has been clicked again. This is giving me the NSRangeException saying I am out of bounds in my array.
I figured this probably has to do with my tableView delegate/data methods, so I set up break points at each of them. With the break points enabled, the cell is removed perfectly. However, when I disable the breakpoints, and let the application run on its own, it crashes. How could break points possibly be affecting this?
Here is the relevant code:
- (NSInteger) numberOfSectionsInTableView:(UITableView *)songTableView{
return 1;
}
- (NSInteger)tableView:(UITableView *)songTableView
numberOfRowsInSection:(NSInteger)section{
bool debug = false;
if (debug) NSLog(#"--TableView: rankings");
if (expandedRow == -1)
return [self.songs count];
else //one row is expanded, so there is +1
return ([self.songs count]+1);
}
- (UITableViewCell *)tableView:(UITableView *)songTableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath{
bool debug = false;
if (debug) NSLog(#"--tableView: tableView");
NSUInteger row = [indexPath row];
if (row == expandedRow){ //the expanded row, return the custom cell
UITableViewCell *temp = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"test"];
return temp;
}
UITableViewCell *cell = [tableViewCells objectAtIndex:row];
return cell;
}
}
- (NSString *)tableView:(UITableView *)songTableView
titleForHeaderInSection:(NSInteger)section{
//todo: call refresh title
return #"The Fresh List";
}
- (CGFloat)tableView:(UITableView *)songTableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 44.0; //same as SongCell.xib
}
- (void)tableView: (UITableView *)songTableView
didSelectRowAtIndexPath: (NSIndexPath *)indexPath {
bool debug = true;
//todo: if the user selects expanded cell, doesn't do anything
SongCell *cell = (SongCell *)[songTableView cellForRowAtIndexPath:indexPath];
if (cell->expanded == NO){
//change cell image
cell.bgImage.image = [UIImage imageNamed:#"tablecellbg_click.png"];
cell->expanded = YES;
//add new cell below
NSInteger atRow = [indexPath row] + 1;
NSIndexPath *insertAt = [NSIndexPath indexPathForRow:atRow inSection:0];
NSArray *rowArray = [[NSArray alloc] initWithObjects:insertAt, nil];
if (debug) NSLog(#"Expanded row: %d", atRow);
expandedRow = atRow;
[tableView insertRowsAtIndexPaths:rowArray withRowAnimation:UITableViewRowAnimationTop];
}else { //cell is already open, so close it
//change cell image
cell.bgImage.image = [UIImage imageNamed:#"tablecellbg.png"];
cell->expanded = NO;
NSIndexPath *removeAt = [NSIndexPath indexPathForRow:expandedRow inSection:0];
NSArray *rowArray = [[NSArray alloc] initWithObjects:removeAt, nil];
if(debug) NSLog(#"--about to delete row: %d", expandedRow);
expandedRow = -1;
[tableView deleteRowsAtIndexPaths:rowArray withRowAnimation:UITableViewRowAnimationTop];
//remove expaned cell below
}
}
This is just a guess, but it's a good idea to wrap code that changes the table structure in calls to
[tableView beginUpdates];
[tableView endUpdates];
I bet this returns null: [NSIndexPath indexPathForRow:expandedRow inSection:0]; and if it does it blows ...
hth
I hate to answer my own questions but I figured it out.
I was loading up my tableView from an array of objects. When I added the cell, that array still only held 30 objects, whereas my table held 31. I was correctly returning the numberOfRowsInSection method.
Here is the modification I made. Notice the extra else if:
NSUInteger row = [indexPath row];
if (row == expandedRow){ //the expanded row, return the custom cell
if(debug) NSLog(#"row == expandedRow");
UITableViewCell *temp = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"test"];
return temp;
}
else if (expandedRow != -1 && row > expandedRow)
row--;
My array of objects and the UITableViewCells were suppose to match up 1-1. After the expanded row, indexPath's row because off by 1. Here is my quick fix to this problem, although I'm sure there is a better way to solve this.
I have a string containing multiple values from a tableview cell,the string maybe multiple or single values.My need is to export these values to googledoc.I have done it,but my problem is the values in the string is exported to googledoc in a single folder,i didn't want this, i have to split the string continuing multiple values and upload it seperatily if it is a multiple value string.
My code for upload is
- (IBAction)doUpload:(id)sender
{
NSMutableString *str = [[NSMutableString alloc] initWithString:#"NOTES:"];
for (int i = 0; i<[appDelegate.notesArray count]; i++) {
// UPLOAD STRINGS HERE
if (selected[i])
[str appendFormat:#"%# ,",[appDelegate.notesArray objectAtIndex:i]];
}
UploadView *uploadview = (UploadView *)self.view;
if (uploadview != nil)
{
[m_owner uploadString:str];
}
}
my tableviewcode didSelectRowAtIndexPath
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSUInteger row = [indexPath row];
selected[row] = !selected[row];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = selected[row] ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
How to do this,Please help me.
Thanks in advance.
Just do the upload before append ...