Program received Signal SIGABRT when scrolling up UITableView - ios

When i scroll my UITableView down and then scrolling up, the app crashes with the stack below:
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 2147483647 beyond bounds [0 .. 48]'
I know it's saying that i am accessing a cell index that exceed the UITableView size, but i am not able to figure out how to fix it. this may be my relevant code:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"CheckedTableViewCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
NSDictionary *rowData = [self.tableData objectAtIndex:[self tableIndexFromIndexPath:indexPath]];//this line may be the source of the crash
cell.textLabel.text = [rowData objectForKey:kCellTextKey];
if ([[rowData objectForKey:kCellStateKey] boolValue]) {
UIImageView *imageView1 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"checked.png"]];
cell.accessoryView = imageView1;
} else {
UIImageView *imageView2 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"unchecked.png"]];
cell.accessoryView = imageView2;
}
return cell;
}
EDIT:
Here is my tableIndexFromIndexPath method implementation
- (NSUInteger)tableIndexFromIndexPath:(NSIndexPath *)indexPath {
// Get list of items at selected section
NSArray *listData = [tableContents objectForKey:[sortedKeys objectAtIndex:indexPath.section]];
// Get name of selected row within the section
NSString *textKey = [listData objectAtIndex:indexPath.row];
// Look up that name in the tableData array
for (int i=0; i < [tableData count]; i++) {
NSDictionary *dict = [tableData objectAtIndex:i];
if ([[dict objectForKey:kCellTextKey] isEqualToString:textKey]) {
return i;
}
}
//In case Name was not found
return NSNotFound;
}

Change
NSDictionary *rowData = [self.tableData objectAtIndex:[self tableIndexFromIndexPath:indexPath]];
to
NSDictionary *rowData = [self.tableData objectAtIndex:indexPath.row];

As several have noted, your tableIndexFromIndexPath: is incorrect. Specifically it's returning NSNotFound, which suggests your using something like indexOfObject: for an object that is not in the array.

At first check that are you getting all value of your NSMutableArray?
If you are getting then check your number of section of tableView is equal to number of NSMutableArray array or not?
If same then there is a reload problem then reload your table view when you are inserting data into the NSMutableArray.
I hope you will find your solution among them.

Related

iOS UItableView remove object from array by index path

I have custom contact book sorted by A-Z sections. I am trying to add to an array selected contacts
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSMutableDictionary *contactInfo = [NSMutableDictionary new];
Cell *cell = (Cell *)[self.contTableView cellForRowAtIndexPath:indexPath];
//NSLog(#"CELL %#", cell.contact.fullname);
if (!cell.contact.contactChecked) {
cell.contactImage.image = [UIImage imageNamed:#"cell_blue_circle.png"];
cell.contact.contactChecked = YES;
//NSLog(#"DID SELECT %#", cell.contact.fullname);
NSLog(#"index checked row %d section %d", indexPath.row, indexPath.section);
[contactInfo setValue:cell.contact.fullname forKey:#"name"];
[contactInfo setValue:cell.contact.numbers.firstObject forKey:#"phone"];
[self.seletedPeople insertObject:contactInfo atIndex:indexPath.row];
} else {
NSLog(#"index unchecked row %d section %d", indexPath.row, indexPath.section);
cell.contactImage.image = [UIImage imageNamed:#"cell_gray_circle.png"];
cell.contact.contactChecked = NO;
[self.seletedPeople removeObjectAtIndex:indexPath.row];
}
NSLog(#"DICT SELECTED %#", self.seletedPeople);
}
What happens, that in some cell app crashing with error
* Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArrayM insertObject:atIndex:]: index 1 beyond
bounds for empty array'
*** First throw call stack: (0x29c02fef 0x38150c8b 0x29b1cf8f 0xf7fe9 0x2d36e56b 0x2d41d43b 0x2d2d2a91 0x2d24d38f 0x29bc8fed 0x29bc66ab
0x29bc6ab3 0x29b13201 0x29b13013 0x313f2201 0x2d2b7a59 0x10c075
0x386dcaaf) libc++abi.dylib: terminating with uncaught exception of
type NSException
UPDATE:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellID = #"Cell";
Cell *cell = [tableView dequeueReusableCellWithIdentifier:cellID forIndexPath:indexPath];
if (searchResults) {
//NSLog(#"CELL %#", cell.contact.fullname);
contact = [searchResults objectAtIndex:indexPath.row];
cell.contact = contact;
cell.firstNameLabel.text = contact.fullname;
cell.avatar.image = contact.image;
cell.avatar.layer.borderColor = [UIColor grayColor].CGColor;
cell.avatar.layer.borderWidth = 0.5;
cell.avatar.layer.cornerRadius = 25.0;
cell.avatar.layer.masksToBounds = YES;
cell.number.text = contact.numbers.firstObject;
} else {
NSString *sectionTitle = [[[namesDictionary allKeys] sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)]
objectAtIndex:indexPath.section];
NSArray *sectionContacts = [namesDictionary objectForKey:sectionTitle];
contact = [self getContactFromArray:[sectionContacts objectAtIndex:indexPath.row]];
cell.firstNameLabel.text = [sectionContacts objectAtIndex:indexPath.row];
cell.avatar.image = contact.image;
cell.avatar.layer.borderColor = [UIColor grayColor].CGColor;
cell.avatar.layer.borderWidth = 0.5;
cell.avatar.layer.cornerRadius = 25.0;
cell.avatar.layer.masksToBounds = YES;
cell.number.text = contact.numbers.firstObject;
cell.contact = contact;
cell.tag = indexPath.row;
}
if (contact.contactChecked) {
cell.contactImage.image = [UIImage imageNamed:#"cell_blue_circle.png"];
} else {
cell.contactImage.image = [UIImage imageNamed:#"cell_gray_circle.png"];
}
return cell;
}
The way I use in such cases. I create a model class and load the tableview with models. Now when i select a cell or deselect a cell. I just add that model in another array. After that when i de select the already selected cell, i can get the same model from the indexpath.row and then i can use NSArray method to fetch that model in that selected array and remove it from there. To fix your issue you can use indexPath.row as another key in dictionary during selection. After that when you deselect the cell use a predicate to get the added dictionary from the array that you are using to store selected ones. Once you find it delete it from the array.
the problem here is the coupling of model with view objects , you shouldn't inquire about a certain property from the view itself (in your case the Cell) however the contact checked should have a reflect on its model from the data source object (the one you used to feed the cellForRowAtIndexPath: , where it should be inquired from.
Otherwise the code is buggy and unstable due to that coupling since it might point to an empty object
The problem is here:
[self.seletedPeople insertObject:contactInfo atIndex:indexPath.row];
if selectedPeople is empty and the user clicks on row 2, then it's going to try to insert contactInfo into row 2 which is "beyond the bounds of an empty array". Simply use addObject: instead. You'll also need to change how you remove items from that array then (probably better to use a dictionary instead).
The solution was adding contact record id to my dictionary and search with predicate this contact id. then remove it. kudos to #jassi
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSMutableDictionary *contactInfo = [NSMutableDictionary new];
Cell *cell = (Cell *)[tableView cellForRowAtIndexPath:indexPath];
if (!cell.contact.contactChecked) {
cell.contactImage.image = [UIImage imageNamed:#"cell_blue_circle.png"];
cell.contact.contactChecked = YES;
//NSLog(#"DID SELECT %#", cell.contact.fullname);
NSLog(#"index checked %# ", [indexPath description]);
[contactInfo setValue:cell.contact.fullname forKey:#"name"];
[contactInfo setValue:cell.contact.numbers.firstObject forKey:#"phone"];
[contactInfo setValue:#(cell.contact.contactId) forKey:#"contactId"];
[self.seletedPeople addObject:contactInfo];
} else {
NSLog(#"index unchecked %#", [indexPath description]);
cell.contactImage.image = [UIImage imageNamed:#"cell_gray_circle.png"];
cell.contact.contactChecked = NO;
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"contactId == %d", cell.contact.contactId];
NSArray *resultTemp = [self.seletedPeople filteredArrayUsingPredicate:predicate];
if(resultTemp.count>0)
[self.seletedPeople removeObject:resultTemp[0]];
}
NSLog(#"DICT SELECTED %#", self.seletedPeople);
}
As user2320861 said, the problem is on the line where you use insertObject. I would do the following:
Change self.selectedPeople to a NSMutableDictionary using the following code:
//in your #interface
#property (nonatomic, strong) NSMutableDictionary *selectedPeople;
Change the code in didSelectCellAtIndexPath to:
//Since phone numbers are unique.
self.selectedPeople[cell.contact.numbers.firstObject] = contactInfo;
Retrieve all of the contacts later using this code:
for(id key in self.selectedPeople) {
NSDictionary contactInfo = [self.selectedPeople objectForKey:key];
//Do something with that contactInfo
}

Error when selecting the textfield by tag in a UITableView

I have a UITableView with TextFields, I created a command in which you add one more line in my table and thus creates another text field within the table, I'm differentiating each text field by entering a particular tag as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView2 cellForRowAtIndexPath:(NSIndexPath *)indexPath
{//Ja explicado anteriormente
static NSString *simpleTableIdentifier = #"ComissoesTableViewCell";//Ja explicado anteriormente
ComissoesTableViewCell *cell = (ComissoesTableViewCell *)[tableView2 dequeueReusableCellWithIdentifier:simpleTableIdentifier];//Ja explicado anteriormente
if (cell == nil){//Ja explicado anteriormente
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"ComissoesTableViewCell" owner:self options:nil];//Ja explicado anteriormente
cell = [nib objectAtIndex:0];//Ja explicado anteriormente
}
cell.data.tag = indexPath.row;
Return Cell;
}
Below is the command in which inserts a new row in the table, this method is only called when the User clicks a button within the existing view:
- (void)viewDidLoad
{
[super viewDidLoad];
iArray = [[NSMutableArray alloc] init];
numeroCampos = 1;
[tableView reloadData];
}
-(void)AdicionarField{
iArray = [[NSMutableArray alloc] init];
numeroCampos++;
for(int x=0;x<numeroCampos;x++){
[iArray addObject:[self getByTag:x]];
}
}
Have you noticed that it adds a new object to the array and the object it adds nothing is a kind of backup text fields, this method called 'getByTag' Gets the text contained within the existing text fields within the table through the tag:
-(NSString *)getByTag:(NSInteger)myTag {
NSLog(#"Get By Tag -> %d",myTag);
NSString *texto = #"null";
NSMutableArray *cells = [[NSMutableArray alloc] init];
for (NSInteger j = 0; j < [tableView numberOfSections]; ++j)
{
for (NSInteger i = 0; i < [tableView numberOfRowsInSection:j]; ++i)
{
[cells addObject:[tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:j]]];
}
}
for (ComissoesTableViewCell *cell in cells)
{
if (cell.data.tag == myTag){
texto = [NSString stringWithFormat:#"%#",cell.data.text];
}
}
return texto;
}
The problem is that this command works almost perfectly, begins from the moment I enter the tenth row of the column the app crashes and the following error:
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[__NSArrayM
insertObject:atIndex:]: object cannot be nil'
I'm a few days trying to solve this problem but I can not find a solution.
Thanks.

UITableView NSMutableArray and NSDictionary

I’ve got this error when populating a tableview from an nsmutablearray.
The arrays are added to the dictionary and the dictionary added to the mutable array, but the app crashes each time the view is loaded with error:
[__NSArrayI isEqualToString:]: unrecognized selector sent to instance
0x8a87e60 2014-05-24 12:23:02.589 jwStudy[77652:907] * Terminating
app due to uncaught exception 'NSInvalidArgumentException', reason:
'-[__NSArrayI isEqualToString:]: unrecognized selector sent to
instance 0x8a87e60'
The log output confirms that the arrays and keys are added correctly.
But why does the cell in the cellForRowAtIndexPath: method throw an error?
Here’s the code:
- (void)viewDidLoad
{
[super viewDidLoad];
languageArray = [[NSMutableArray alloc] init];
languages = [[NSArray alloc] initWithObjects:#"Abbey", #"Abkhasisk", #"Abua", nil];
downloadURL = [[NSArray alloc] initWithObjects:#"http://download.jw.org/files/content_assets/bb/502013341_ABB_cnt_1_r480P.mp4",
#"http://download.jw.org/files/content_assets/3c/502013341_ABK_cnt_1_r480P.mp4",
#"http://download.jw.org/files/content_assets/7e/502013341_AU_cnt_1_r720P.mp4", nil];
mutedict = [NSDictionary dictionaryWithObjectsAndKeys:languages, #"FirstKey", downloadURL, #"SecondKey", nil];
[languageArray addObject:mutedict];
NSLog(#"%#",languageArray);
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return languageArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
// ERROR HERE!!!
cell.textLabel.text = [[languageArray objectAtIndex:indexPath.row] objectForKey:#"FirstKey”];
if ([checkCellLanguage isEqual:indexPath]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
#Farhan and Joy.
Thank you both for prompt reply. I have realized now that I wasn't clear enough in my question. What I wanted was for each selected row in the tableview to register the row's corresponding URL. So I ended up abandoning the arrays and dictionaries ... too confusing. And going with 2 NSArrays instead. This link got me going on the right track and everything works now:
http://sweettutos.com/2012/08/25/loading-urls-from-uitableview/
In your code, two arrays stored in a dictionary , and the dictionary stored in a array.
Like this :
languageArray ----- mutedict ------ languages (FirstKey)
|
|
----------- downloadURL(SecondKey)
cell.textLabel.text is a NSString, but [[languageArray objectAtIndex:indexPath.row] objectForKey:#"FirstKey”]; is NSArray
So your code throw an error.
If your want put a language as cell.textLabel.text
You could modify your code as cell.textLabel.text = [[mutedict objectForKey:#"FirstKey"] objectAtIndex:indexPath.row]
Hope it can help you :)

When I add a new section (by stepper), the content of the cells in a section mixes with content of another section

I've a tableView with dynamic cells. Each section has 5 rows. In the first 4 rows for each row there is a text field. Instead in the fifth row there is an imageview (when I click on this row, I can choose a photo from my photo library, and this last will be put in imageView). The number of sections is decided at run-time using a stepper. The section 0 is fixed and contains a stepper. When I click on + button (on stepper) a section will be add. So everything is right but if I wrote before in the rows that contain the textfield, and then add one or more sections, the contents of these textfield are mixed with each other (and also between sections).
//In file.h I've declared #property (nonatomic) int numberOfComponents;
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1 + self.numberOfComponents;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == 0) {
return 1;
}
else{
return 4;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0) {
NSString *CellIdentifier = #"cellStepper";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
UILabel *stepperLabel = (UILabel *)[cell viewWithTag:1];
stepperLabel.text = [NSString stringWithFormat:#"%i",self.numberOfComponents];
UIStepper *stepper = (UIStepper *)[cell viewWithTag:2];
stepper.minimumValue = 0;
stepper.maximumValue = 20;
stepper.stepValue = 1;
stepper.autorepeat = YES;
stepper.continuous = YES;
return cell;
}
if (indexPath.row == 4) {
NSString *CellIdentifier = #"cellProfileSnap";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
return cell;
}
NSString *CellIdentifier = #"cellDetail";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
UITextField *cellLabelComponent = (UITextField *)[cell viewWithTag:3];
cellLabelComponent.placeholder = #"detail";
return cell;
}
- (IBAction)stepperClik:(UIStepper *)stepper{
if (stepper.value == 0 && self.numberOfComponents == 0) {
if (stepper.value > self.numberOfComponents) {
self.numberOfComponents += 1;
}
else{
return;
}
}
if (stepper.value > self.numberOfComponents) {
self.numberOfComponents += 1;
}
else{
self.numberOfComponents -= 1;
}
[self.tableView reloadData];
}
Solved by Greg, but now there's another problem: I have a save button, which should save many arrays into a dictionary (containing the details of each section 5) as the number of sections.
Here the code of save button:
- (IBAction)saveButton:(id)sender{
NSMutableArray *arrComponents = [[NSMutableArray alloc] init];
for (int i = 0; i < self.numberOfComponents; i++)
{
NSMutableArray *component = [[NSMutableArray alloc] init];
for (int j = 0; j < [self.arrDetails count]; j++)
{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:j inSection:i+1];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath: indexPath];
if (j == 4){
UIImageView *imageComponent = (UIImageView *) [cell viewWithTag:4];
NSLog(#"%#",imageComponent.image);
if (imageComponent.image == Nil) {
[component addObject: nil];
}
[component addObject: imageComponent.image];
}
else{
UITextField *detailComponent = (UITextField *) [cell viewWithTag:3];
NSLog(#"%#",detailComponent.text);
if ([detailComponent.text isEqualToString:#""]) {
[component addObject:#""];
}
if (detailComponent.text != nil && i != 0)
[component addObject: detailComponent.text];
}
}
[arrComponents addObject: component];
NSLog(#"%#",arrComponents);
}
Where it is shown in the code / / ERROR HERE, at the fourth iteration of 5 iterations (number of rows in a section) of the latest iteration (last section read), the application crashes giving this message:
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '*** -[__NSArrayM
insertObject:atIndex:]: object cannot be nil'
I believe your detailComponent is equal nil and you cannot save nil to the array. Before you call
[component addObject: detailComponent.text]; //ERROR HERE
do check:
if (detailComponent != nil && i != 0)
[component addObject: detailComponent.text];
It could happen because in your section 0 you haven't got any textfield.
//EDITED
The issue is happened here:
if (imageComponent.image == Nil) {
[component addObject: nil];
}
[component addObject: imageComponent.image];
Replace it with:
if (imageComponent.image == nil) {
[component addObject:[NSNull null]];
}
else {
[component addObject: imageComponent.image];
}
You cannot add nil to array if you want to add nil you should add object NSNull.
And you are missing else statement. Your code try to add nil to the array twice (if the image is nil) first time in your if statement ([component addObject: nil];) and second time just after your if statement: [component addObject: imageComponent.image];
// EDITED
Make the changes as suggested in comments in code below. I use the same dictionary, you should change the name because it suggest that it keeps just textfields values, but now it will store the images as well:
if (indexPath.row == 4) {
NSString *CellIdentifier = #"cellProfileSnap";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
//I believe this is where you keep your imageView
// get your image
UIImageView *imageComponent = (UIImageView *) [cell viewWithTag:4];
NSString *key = [NSString stringWithFormat:#"sec:%d,row:%d", indexPath.section, indexPath.row];
if (self.textValueDictionary[key])
imageComponent.image = self.textValueDictionary[key];
else
imageComponent.image = nil; //Your default value (probably you want to set up your plus image)
return cell;
}
The next step you need to make is where the user presses the plus image - you have to save the image in the dictionary. Put this code to your method where you get the image from user. This is a pseudo code so you have to adjust it a little bit:
// Get reference to the cell
UITableViewCell *cell = //have a look on textFieldDidEndEditing method. You have to work out how to get the cell (I cannot do that because I haven't got access to your code);
// Get index path
NSIndexPath *indexPath = [self.myTableView indexPathForCell:cell];
// Get section as a string
NSString *key = [NSString stringWithFormat:#"sec:%d,row:%d", indexPath.section, indexPath.row];
UIImage *img = //get your image here;
//make sure it's not nil before you save it to dictionary
//save it to dictionary
[self.textValueDictionary setValue:img forKey:key];
The last bit is saveButton: method there was mistake in my advices from yesterday. You're trying to get text and image directly from cells, and it works fine if the cells are visible. If you cannot see the cell system put it to reusable pool and you get nils.
To fix it you have to get the data from the dictionary:
Don't use:
UIImageView *imageComponent = (UIImageView *) [cell viewWithTag:4];
instead do:
NSString *key = [NSString stringWithFormat:#"sec:%d,row:%d", indexPath.section, indexPath.row];
UIImage *img = self.textValueDictionary[key];
// make sure is not nil before you save it. If it's nil add [NSNull nil] to your array as I explained before.
When you read text don't do it like that:
UITextField *detailComponent = (UITextField *) [cell viewWithTag:3];
get text from the dictionary:
NSString *key = [NSString stringWithFormat:#"sec:%d,row:%d", indexPath.section, indexPath.row];
NSString *str = self.textValueDictionary[key];
If it complain about data type use cast (UIImage*).
Remember to change your first loop to: for (int i = 1; i < self.numberOfComponents; i++) and when you get NSIndexPath change it to inSection:i instead inSection:i+1.
I haven't run this in Xcode so maybe there are some mistakes but you should be able to find and fix it.
Hope it will work for you.
It happens because you don't save the cellLabelComponent.text property and when you reloadData tableView reuses cell (which cause this problem).
You should save data you entered to your cellLabelComponent (for example in array, you can use UITextFieldDelegate) and in your cellForRowAtIndexPath: method you should assign saved values to desired field.
//EXTENDED
Conform to <UITextFieldDelegate> protocol in your .h file or class extension.
Add
#property (nonatomic, strong) NSMutableDictionary *textValueDictionary;
to your class extension and allocate it and init in viewDidLoad or init method:
self.textValueDictionary = [[NSMutableDictionary alloc] init];
Add this to cellForRowArIndexPath:
cellLabelComponent.placeholder = #"detail";
// Make your class to be delegate for UITextField
cellLabelComponent.delegate = self;
// I use NSString (section) as a key in my dictionary. You can use NSNumber if you like
if (self.textValueDictionary[[NSString stringWithFormat:#"%d", indexPath.section]])
cellLabelComponent.text = self.textValueDictionary[[NSString stringWithFormat:#"%d", indexPath.section]];
else
cellLabelComponent.text = #""; //Your default value
Add your UITextFieldDelegate methods:
- (void)textFieldDidEndEditing:(UITextField *)textField
{
// Get reference to the cell
UITableViewCell *cell = (UITableViewCell*)[[[textField superview] superview] superview];
// Get index path
NSIndexPath *indexPath = [self.myTableView indexPathForCell:cell];
// Get section as a string
NSString *section = [NSString stringWithFormat:#"%d", indexPath.section];
[self.textValueDictionary setValue:textField.text forKey:section];
}
You can use more delegate if you need.
It should be enough to make it works. It will work just when you have one UITextField in your table section if you have more you should use unique key in your dictionary (NSindexPath will work if you have more that one textfield in section but not more that one in row, just remember to convert it to NSNumber).
Let me know is it work.
//EXTENDED
If you have more that one UITextField per section you have to change the dictionary key. This solution above will work just if you have up to one row per section.
This solution (below) will work if you have many textfields per section but not more that one text field per cell (it will work for one textfield per section as well):
Change line in cellForRowAtIndexPath from:
if (self.textValueDictionary[[NSString stringWithFormat:#"%d", indexPath.section]])
cellLabelComponent.text = self.textValueDictionary[[NSString stringWithFormat:#"%d", indexPath.section]];
to:
NSString *key = [NSString stringWithFormat:#"sec:%d,row:%d", indexPath.section, indexPath.row];
if (self.textValueDictionary[key])
cellLabelComponent.text = self.textValueDictionary[key];
And change lines in textFieldDidEndEditing: method from:
NSString *section = [NSString stringWithFormat:#"%d", indexPath.section];
[self.textValueDictionary setValue:textField.text forKey:section];
to:
NSString *key = [NSString stringWithFormat:#"sec:%d,row:%d", indexPath.section, indexPath.row];
[self.textValueDictionary setValue:textField.text forKey:key];

iOS UITableViewCells rows recycled and tag not working

I would like to seek some help in setting tag for buttons in cells. This is a question with a link to the previous I posted : iOS Using NSDictionary to load data into section and rows
However, though I could pass in data dynamically now, my renewal button on each of the rows could not seem to get the data and would only detect the same book title of each section when any of the rows in the section is selected.
Based on what I've read so far, it's because the button is being recycled hence, unable to detect which book is being selected properly. I've tried to set tag:
cell.renewButton.tag = indexPath.row;
How my code looks like now:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell";
UserCustomCell *cell = (UserCustomCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.bookTitle.frame = CGRectMake(12, 0, 550, 40);
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"UserCustomCell" owner:self options:nil];
cell = userCustomCell;
self.userCustomCell = nil;
cell.renewButton.tag = indexPath.row;
}
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
cell.bookTitle.frame = CGRectMake(12, 0, 550, 40);
cell.renewButton.frame = CGRectMake(600, 14, 68, 24);
}
[cell.renewButton useBlackActionSheetStyle];
//########## EDIT STARTS HERE
dataSource = [[NSMutableDictionary alloc] init]; // This would need to be an ivar
for (NSDictionary *rawItem in myArray) {
NSString *date = [rawItem objectForKey:#"date"]; // Store in the dictionary using the data as the key
NSMutableArray *section = [dataSource objectForKey:date]; // Grab the section that corresponds to the date
if (!section) { // If there is no section then create one and add it to the dataSource
section = [[NSMutableArray alloc] init];
[dataSource setObject:section forKey:date];
}
[section addObject:rawItem]; // add your object
}
self.dataSource = dataSource;
//NSLog(#"Data Source Dictionary: %#", dataSource);
NSArray *sections =[[dataSource allKeys] sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
NSString *sectionTitle = [sections objectAtIndex:indexPath.section];
NSArray *items = [dataSource objectForKey:sectionTitle];
NSDictionary *dict = [items objectAtIndex:indexPath.row];
cell.bookTitle.text = [dict objectForKey:#"name"];
cell.detail.text = [NSString stringWithFormat:#"Due Date: %# Due Time: %#",
[dict objectForKey:#"date"], [dict objectForKey:#"time"]];
cell.renewButton.tag = indexPath.row;
return cell;
}
but it doesn't work at all. Would be sooooo grateful for any suggestions :) Thank you!!
P.S: My copy of xcode is not updated, only till version4. Saw some people mentioning storing of tag status in DataModel but it's only available in newer versions. :)
You cannot use the button tags, as these will be the same as those of the cells they have been recycled from. Instead, use the indexPath to determine on which row you are and use that directly. No need to go through the button tag.
I could not see your cell.renewButton being assigned a selector method (the method that should be triggered on tapping the button).
[cell.renewButton addTarget:self action:#selector(renewButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
Also, I would specify a tag number with an offset, as tag of 0 is almost like not tagging at all. First row of tableView will give indexPath.row = 0.
Above your code,
#define OFFSET 100 /* Or any number greater than 0 */
In cellForRowAtIndexPath,
...
[cell.renewButton addTarget:self action:#selector(renewButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
cell.renewbutton.tag = indexPath.row + OFFSET;
...
In the renewButtonPressed method,
-(void)renewButtonPressed:(id)sender
{
tappedNum = [sender tag] - OFFSET;
/* do your stuff */
}
tappedNum will give you the row that the button is tapped, starting with 0.

Resources