multiple cell identifier in tableview in iOS - ios

I am using a array containing objects from two dictionaries and displaying objects of first dictionary on first cell having different identifier and same with second dictionary objects.
check out my code in cellforrowatindexpath
static NSString *cellIdentifier = #"cellIdentifier1";
static NSString *customCellIdentifier = #"cellIdentifiercustom";
if (indexPath.row == 0) {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
// if (cell==nil)
{
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
ExcName = [[UILabel alloc] initWithFrame:CGRectMake(10.0, 2.0, 250.0, 36.0)];
ExcName.font = [UIFont systemFontOfSize:12.0];
ExcName.textColor = [UIColor blackColor];
ExcName.textAlignment = NSTextAlignmentLeft;
ExcName.text=[[exerciseAr objectAtIndex:indexPath.row] objectForKey:#"activityname"];
ExcName.numberOfLines=3;
[cell.contentView addSubview:ExcName];
return cell;
}
else{
UITableViewCell *customcell = [tableView dequeueReusableCellWithIdentifier:customCellIdentifier];
// if (cell==nil)
{
customcell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:customCellIdentifier];
}
customcell.selectionStyle = UITableViewCellSelectionStyleNone;
ExcName = [[UILabel alloc] initWithFrame:CGRectMake(10.0, 2.0, 250.0, 36.0)];
ExcName.font = [UIFont systemFontOfSize:12.0];
ExcName.textColor = [UIColor blackColor];
ExcName.textAlignment = NSTextAlignmentLeft;
ExcName.text=[[exerciseAr objectAtIndex:indexPath.row] objectForKey:#"exercisename"];
// ExcName.text=[[exerciseAr objectAtIndex:indexPath.row] objectForKey:#"exercisename"];
ExcName.numberOfLines=3;
[customcell.contentView addSubview:ExcName];
return customcell;
}
return nil;
}
now I want if any dictionary is null, cell corresponding to that dictionary should not be visible which is visible now.

A few things:
Don't return nil from -tableView:cellForRowAtIndexPath:. That method gets called exactly once for each (visible) row, and the table assumes it has as many rows as you told throught the return value of -tableView:numberOfRowsInSection:. Defaulting to nil reveals an inconsistency in your code.
By that token, cell dequeueing should never fail. I recommend that you switch to the newer method: -dequeueReusableCellWithIdentifier:forRowAtIndexPath:. It takes care of allocation of new cells for you when there is no cell in the reuse pool.
Cells are being reused. A single cell may be reuse multiple times: If you add a new label each time, they will pile up. Instead, add the label to your cells in interface builder and set up an outlet to reference them when configuring the cell.
The Solution:
Instead of "skipping rows", make your data model consistent with what you are going to display. If you have an array with objects some of which you want to skip, first filter your array and then used the filtered array as data source.
// Call this method once before reloading the table view
- (void) filterDictionaries
{
// (filteredArray is an ivar defined as NSMutableArray*)
for (NSDictionary* dictionary in exerciseAr) {
if ([dictionary objectForKey:#"exercisename"] != nil) {
[filteredArray addObject: dictionary];
}
}
// Now you can use filteredArray as the data source
// instead of exerciseAr, without worrying about skipping
// entries.
}
- (NSInteger) tableView:(UITableView*) tableView numberOfRowsInSection:(NSInteger) section
{
return [filteredArray count];
}
- (UITableViewCell*) tableView:(UITableView*) tableView cellForRowAtIndexPath:(NSIndexPath*) indexPath
{
static NSString *cellIdentifier = #"cellIdentifier1";
static NSString *customCellIdentifier = #"cellIdentifiercustom";
UITableViewCell* cell;
if (indexPath.row == 0) {
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forRowAtIndexPath:indexPath];
}
else{
cell = [tableView dequeueReusableCellWithIdentifier:customCellIdentifier forRowAtIndexPath:indexPath];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.excLabel.text = [[filteredArray objectAtIndex:indexPath.row]
return cell;
}

It actually depends what you meant by your dictionary being null. It may be nil, or it just doesn't have any values for the keys e.g the values for the key is an empty string. So, to add to NibolasMiari's answer, I would say, check both of the cases.
- (void) filterDictionaries:(NSArray*) exerciseAr{
filteredArray = [[NSMutableArray alloc]init];
for (NSDictionary* myDict in exerciseAr) {
if ([myDict isKindOfClass:[NSNull class]]) {
continue;
}
else if ([myDict count] == 0) {
continue;
}
else{
[filteredArray addObject: myDict];
}
}
}
- (NSInteger) tableView:(UITableView*) tableView numberOfRowsInSection:(NSInteger) section
{
return [filteredArray count];
}
Now in your cellforIndexPath method everything will be same just changed the lines following way-
In the if block, you had
ExcName.text=[[exerciseAr objectAtIndex:indexPath.row] objectForKey:#"activityname"];
Make it -
ExcName.text=[[filteredArray objectAtIndex:indexPath.row] objectForKey:#"activityname"];
In the else block, you had
ExcName.text=[[exerciseAr objectAtIndex:indexPath.row] objectForKey:#"exercisename"];
Make it -
ExcName.text=[[filteredArray objectAtIndex:indexPath.row] objectForKey:#"exercisename"];

Related

UITableView crashes at cellForRowAtIndexPath with error "EXC_BAD_ACCESS"

One of my ViewControllers has a UITableView inside of it, and it crashes when it loads the cellForRowAtIndexPath with the following error message:
I've placed NSLogs in various parts of the function to see where it crashes, but they all log successfully, so I'm a bit confused as to where it's going wrong.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"cellForRowAtIndexPath has begun");
// parse data for the respective section's items
NSDictionary *currentSectionDictionary = _matchCenterData[indexPath.section];
NSArray *top3ArrayForSection = currentSectionDictionary[#"Top 3"];
// Cell defaults
static NSString *CellIdentifier = #"MatchCenterCell";
MatchCenterCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
// if no cell could be dequeued create a new one
cell = [[MatchCenterCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [NSString stringWithFormat:#"Title"];
cell.textLabel.font = [UIFont systemFontOfSize:14];
tableView.separatorColor = [UIColor clearColor];
// if no results for that item
if (top3ArrayForSection.count-1 < 1) {
cell.detailTextLabel.text = [NSString stringWithFormat:#""];
[cell.imageView setImage:[UIImage imageNamed:#""]];
NSLog(#"no results for this item");
return cell;
}
// if results for that item found
else {
// Load images using background thread to avoid the laggy tableView
[cell.imageView setImage:[UIImage imageNamed:#"Placeholder.png"]];
NSLog(#"FOUND results for this item");
return cell;
}
}

How to get the index path of a tableviewcell that's populated from an array?

I have a tableviewcell with 5 different cells. Each view has a label with one of the following inside of it. 1 textfields, 1 text, view 1, switch, or 1 slider. I am trying to find the tableviewcell for row at index path so I can retrieve the information that the user has entered. Below is the code I have for the cells and different switches. I just need to know how to achieve this if possible. Thanks (p.s) I was thinking about just tagging the elements instead of finding cell for row so that's why you will see tag code.
-(UITableViewCell *)listCell:(UITableView *)tableView IndexPath:(NSIndexPath*)indexPath
{
static NSString *textFieldIdentifier = #"textFieldCell";
static NSString *textViewIdentifier = #"textViewCell";
static NSString *switchIdentifier = #"switchCell";
static NSString *seekBarIdentifier = #"seekBarCell";
static NSString *datePickerIdentifier = #"datePickerCell";
//DBSectionDetailsTableViewCell *cell = (DBSectionDetailsTableViewCell *) [tableView dequeueReusableCellWithIdentifier:textViewIdentifier];
UITableViewCell *cell6 = [tableView dequeueReusableCellWithIdentifier:datePickerIdentifier];
results = [listArray objectAtIndex:[indexPath row]];
if([indexPath row] < listArray.count)
{
if (([[results objectAtIndex:2]isEqualToString:#"EditText"]))
{
DBSectionDetailsTableViewCell *cell2 = [tableView dequeueReusableCellWithIdentifier:textFieldIdentifier forIndexPath:indexPath];
cell2.titleLabel.text = [results objectAtIndex:1];
//title button
cell2.textField.tag = [indexPath row];
cell2.textField.delegate = self;
[cell2.textField addTarget:self action:#selector(textFieldDidEndEditing:) forControlEvents:UIControlEventTouchUpInside];
return cell2;
}
else if (([[results objectAtIndex:2]isEqualToString:#"EditTextLarge"]))
{
TextViewTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:textViewIdentifier forIndexPath:indexPath];
// cell = textFieldCell;
cell.titleLabel.text = [results objectAtIndex:1];
cell.textView.tag = [indexPath row];
cell.textView.delegate = self;
// [cell.textView addTarget:self action:#selector(textViewDidEndEditing:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
else if (([[results objectAtIndex:2]isEqualToString:#"Switch"]))
{
SwitchTableViewCell *cell3 = [tableView dequeueReusableCellWithIdentifier:switchIdentifier forIndexPath:indexPath];
// cell3 = switchCell;
cell3.titleLabel.text = [results objectAtIndex:1];
cell3.switchOutlet.tag = [indexPath row];
return cell3;
}
else if (([[results objectAtIndex:2]isEqualToString:#"SeekBar"]))
{
SeekBarTableViewCell *cell4 = [tableView dequeueReusableCellWithIdentifier:seekBarIdentifier forIndexPath:indexPath];
//cell4 = seekBarCell;
cell4.titleLabel.text = [results objectAtIndex:1];
cell4.slider.tag = [indexPath row];
return cell4;
}
else if (([[results objectAtIndex:2]isEqualToString:#"DatePicker"]))
{
DatePickerTableViewCell *cell5 = [tableView dequeueReusableCellWithIdentifier:datePickerIdentifier forIndexPath:indexPath];
//cell5 = datePickerCell;
cell5.titleLabel.text = [results objectAtIndex:1];
cell5.datePicker.tag = [indexPath row];
cell5.datePicker.delegate = self;
[cell5.datePicker addTarget:self action:#selector(datePickerDidEndEditing:) forControlEvents:UIControlEventTouchUpInside];
return cell5;
}
}
//UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
return cell6;
}
You can fetch visible cells from a table using [tableView cellForRowAtIndexPath:indexPath]. Cells that are offscreen will be removed from the UITableView and you will not be able to access them at all as they will have been put back into the reusable cell queue.
Note 1: You shouldn't be relying on your UITableView to store your current data state. It throws away cells that are scrolled off-screen, so if you don't persist your data in another place, it will be lost forever.
Note 2: This code isn't particularly safe:
results = [listArray objectAtIndex:[indexPath row]];
if([indexPath row] < listArray.count) // This is always true.
// If it isn't true, the above
// objectAtIndex: will crash your app.
You should save the information as the user enters it for each cell because you can't reach a cell once it gets out of the view to be reused later.

iOS Datasource not being set as expected of the TableView

I have a TableView "cannedTv". Each cell contains another TableView "valuesTv". The structure of datasource for cannedTv is { NSString *name, NSArray *valuesArr }. valuesArr is set as datasource for valuesTv. cannedTv is an expandable tableview. Initially just name is displayed, when expanded the valuesTv tableView is displayed. This is my code for didSelectRowAtIndexPath and cellForRowAtIndexPath delegate methods of the tableviews.
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"ROW Selected...TAG = %d", tableView.tag);
selectedValueIndex = -1;
if (tableView == self.cannedTV) {
// USer taps expanded row
if (selectedIndex == indexPath.row) {
selectedIndex = -1;
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath ] withRowAnimation:UITableViewRowAnimationFade];
return;
}
// USer taps differnt row
if (selectedIndex != -1) {
NSIndexPath *prevPath = [NSIndexPath indexPathForRow:selectedIndex inSection:0];
selectedIndex = indexPath.row;
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:prevPath] withRowAnimation:UITableViewRowAnimationFade];
}
// User taps new row with none expanded
selectedIndex = indexPath.row;
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
return;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Table View TAG = %d ROW = %d", tableView.tag, indexPath.row);
if (tableView.tag == 10) { // cell.valuesTv
CannedValueCell *ccell = (CannedValueCell *) [tableView dequeueReusableCellWithIdentifier:#"cannedValueCell"];
if (ccell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CannedValueCell" owner:self options:nil];
ccell = [nib objectAtIndex:0];
}
// Populate valuesTv
ccell.valueTextView.text = [valuesArray objectAtIndex:indexPath.row];
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(valueTextViewTapped)];
[ccell.valueTextView addGestureRecognizer:gestureRecognizer];
//[ccell.valueTextView sizeToFit];
return ccell;
} else {
// cannedTv
static NSString *cellIdentifier = #"CannedCell";
cell = (CannedCell *) [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CannedCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
// Set Datasource & Delegate for valuesTv tableview
cell.valuesTv.dataSource = self;
cell.valuesTv.delegate = self;
if (selectedIndex == indexPath.row) {
// Do expanded cell stuff
[cell.tapInsertLbl setFont:[UIFont fontWithName:#"OpenSans" size:8.0]];
cell.tapInsertLbl.hidden = FALSE;
[cell.contentView setBackgroundColor:[UIColor lightGrayColor]];
[cell.contentView.layer setBorderColor: (__bridge CGColorRef)([UIColor redColor])];
[cell.contentView.layer setBorderWidth:1.0f];
} else {
// Do closed cell stuff
cell.tapInsertLbl.hidden = TRUE;
cell.contentView.backgroundColor = [UIColor whiteColor];
}
if (tableView == self.cannedTV) {
valuesArray = nil;
CannedItem *ci = [candRespList objectAtIndex:indexPath.row];
cell.tagLbl.text = ci.name;
// Set the valuesArray so it be used in populating the valuesTv
valuesArray = [NSMutableArray arrayWithArray: ci.valuesArr];
ci = nil;
} else if (tableView == self.searchDisplayController.searchResultsTableView) {
cell.tagLbl.text = [searchResults objectAtIndex:indexPath.row];
}
[cell.tagLbl sizeToFit];
return cell;
}
}
The problem I am facing is, every time the right datasource is shown shown in valuesTv. At this moment I have 2 arrays in valuesArray with 0th element having 1 object and 1st element having 3 objects (of NSString). Datasource of cannedTv also has 2 rows in it. Sometimes, one time both rows of canndTv shows correct datasource and then both shows same datasource. Sometimes, both rows shows the same datasource. I don't understand why valuesArray can't get the right datasource. While debugging also, I found that at times valuesArray has right datasource but the tableview is showing wrongly, at times the control doesn't go to // Populates valuesTv line and thus previously set valuesArray is only shown. I tried many ways, but can't get the results as expected. Also tried to set valuesArray in didSelectRowAtIndexPath after setting selectedIndex, but that also didn't help.
I am stuck on this since yesterday and can't get thru. Where am I going wrong due to which correct datasource is not shown/reflected on the tableviews. Can you please try to help me out. Any help is highly appreciated. Thanks a lot.
UPDATE :-
Created new datasource & delegate in CannedCell object itself - it contains the valuesTv.
#interface CannedCell : UITableViewCell <UITableViewDataSource, UITableViewDelegate>
#property NSArray *valuesDataSource; // Contains the valuesArray contents
In my VC, removed datasource for cell.values.datasource & cell.valuesTv.delegate lines. In the cellForRowAtIndexPath method for top table, set the datasource like this :-
if (tableView == self.cannedTV) {
valuesArray = nil;
CannedItem *ci = [candRespList objectAtIndex:indexPath.row];
cell.tagLbl.text = ci.name; //[tagsArray objectAtIndex:indexPath.row];
//valuesArray = [NSMutableArray arrayWithArray: ci.valuesArr];
cell.valuesDataSource = ci.valuesArr; // SET DATASOURCE
// This is setting proper array always
ci = nil;
}
Commented the whole if (tableView.tag == 10) { in cellForRowAtIndexPath method.
And in CannedCell :-
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (valuesDataSource != nil)
return valuesDataSource.count;
else
return 0;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
CannedValueCell *ccell = (CannedValueCell *) [tableView dequeueReusableCellWithIdentifier:#"cannedValueCell"];
if (ccell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CannedValueCell" owner:self options:nil];
ccell = [nib objectAtIndex:0];
}
// Populate valuesTv
ccell.valueTextView.text = [valuesDataSource objectAtIndex:indexPath.row];
ccell.valueTextView.tag = indexPath.row;
return ccell;
}
Yet the results are as earlier only. I mean even if array of 3 objects are set as valuedDataSource, the sub-table shows only single object array. What do the think now can be the reason for this ?
As suggested by Paulw11, I created other object to handle TableViewDelegate and datasource for the sub-table. Though that didn't make any difference in the results of the problem.
I set UITableViewDelegate & Datasource in my top table's Cell class. Passed the array to be the datasource of the table.
Importantly, after setting the datasource of sub-table on calling
[cell.valuesTv reloadData]
forced the sub-table to reload its data and that finally did the trick. Till then things weren't working.

How to get value of uiTextField created programmatically in a uiTableView?

I'm a beginner in iOS and I try to get the value of my uiTextField that I created programmatically.
So my problem is that I create a form in an UITableViewController with a .json file. I have created my form, but I don't know how I can get the different values.
In my cellForRowAtIndexPath I created my different elements (I have textFields, textFields with picker and uiswitch). When the user have finished to fill out the form, he click on a "save" button and it is here that I want to get my values.
If someone can help me and put some code for explain .... :) Thanks.
some of my code :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
NSString *cellValue = [self getItemName:indexPath.section and:indexPath.row];
cell.textLabel.text = cellValue;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
NSString *itemType=[self getItemType:indexPath.section and:indexPath.row];
NSLog(#"%#",itemType);
if ([itemType isEqualToString:#"text"]) {
UITextField *Reference = [self createTextField];
[cell.contentView addSubview:Reference];
}else if ([itemType isEqualToString:#"checkbox"]) {
UIView *checkbox = [self createCheckbox:indexPath.section and:indexPath.row];
[cell.contentView addSubview:checkbox];
}else if ([itemType isEqualToString:#"picker"]) {
UITextField *Reference = [self createPicker:indexPath.section and:indexPath.row];
[cell.contentView addSubview:Reference];
}else if ([itemType isEqualToString:#"datePicker"]) {
UITextField *Reference = [self createDatePicker];
[cell.contentView addSubview:Reference];
}
return cell;
}
it is here that i create dynamically the elements. For example an uixtField :
-(UITextField*)createTextField{
UITextField *Reference = [[UITextField alloc] initWithFrame:CGRectMake(200 , 10, 200, 40)];
Reference.layer.borderColor=[[UIColor blackColor]CGColor];
Reference.layer.borderWidth=1.0f;
Reference.textAlignment=NSTextAlignmentCenter;
Reference.tag=_tag;
_tag++;
return Reference;
}
http://hpics.li/04b98ca
here it is an example of that i obtained with my dynamical generation.
Use:
[textField setTag:(integer value)]
when you creating fields in cellForRow... method.
Then use in saveMethod this:
[[tableView cellForIndexPath:indexPath] viewWithTag:(integer value)]
for get concrete field of concrete cell.
if ([itemType isEqualToString:#"text"]) {
UITextField *Reference = [self createTextField];
[Reference setTag:1];
[cell.contentView addSubview:Reference];
}
-(void)saveMethod
{
NSString *string = [[[self.tableView cellForRowAtIndexPath:indexPath] viewwithTag:1] text];
}
You can create elements in the method cellForRowAtIndexPath for your cells if after you want to get info from them, because it will be very difficult to get it.
The best way is creating your custom UITableViewCell with all elements you want and after, in the method didSelectRowAtIndexPath to get the info of your elements.
The way I get an indexPath from a view is by checking the superview until I get the parent cell, then using -indexPathForCell:.
- (UITableViewCell *)cellForView:(UIView *)view
{
while (view != nil && ![view isKindOfClass:[UITableViewCell class]]) {
view = view.superview;
}
return (UITableViewCell *)view;
}
- (NSIndexPath *)indexPathForView:(UIView *)view
{
return [self.tableView indexPathForCell:[self cellForView:view]];
}
Overall, this solution will run into problems. Cells do not persist in a table view. As soon as the cell is off the screen it is recycled by the table view.
This means you should not attempt to store data in a cell. A cell is used to present data and get user input, but never store data. Data is meant to be stored in the table data source.
In addition, it means you need to be careful when adding subviews to a cell. As the cell get recycled, the views you added in it's previous use will still be in the cell. You will need to have a cleanup section to -tableView:cellForRowAtIndexPath: to remove all the views you previously added.
My recommendation is to subclass UITableViewCell. You can either have 4 subclasses, one for each JSON type you have, or have 1 subclass which can be instantiated with in the 4 different ways. In my example, I have 1 subclass that can be instantiated 4 different ways.
Keep the different types of cells differentiated by using different reuse identifiers.
Use target/actions and delegates to get input from the controls on the cell.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = nil;
NSString *itemType=[self getItemType:indexPath.section and:indexPath.row];
NSLog(#"%#",itemType);
if ([itemType isEqualToString:#"text"]) {
cellIdentifier = #"TextCell";
} else if ([itemType isEqualToString:#"checkbox"]) {
cellIdentifier = #"CheckboxCell";
} else if ([itemType isEqualToString:#"picker"]) {
cellIdentifier = #"PickerCell";
} else if ([itemType isEqualToString:#"datePicker"]) {
cellIdentifier = #"DatePickerCell";
}
MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
if ([cellIdentifier isEqualToString:#"TextCell"]) {
cell = [MyTableViewCell textCellWithIdentifier:cellIdentifier];
} else if ([cellIdentifier isEqualToString:#"CheckboxCell"]) {
cell = [MyTableViewCell checkboxCellWithIdentifier:cellIdentifier];
} else if ([cellIdentifier isEqualToString:#"PickerCell"]) {
cell = [MyTableViewCell pickerCellWithIdentifier:cellIdentifier];
} else if ([cellIdentifier isEqualToString:#"DatePickerCell"]) {
cell = [MyTableViewCell datePickerCellWithIdentifier:cellIdentifier];
}
}
NSString *itemName = [self getItemName:indexPath.section and:indexPath.row];
cell.textLabel.text = itemName;
if ([itemType isEqualToString:#"text"]) {
NSString *itemValue = [self getItemValue:indexPath.section and:indexPath.row];
cell.textField.text = itemValue;
} else if ([itemType isEqualToString:#"checkbox"]) {
BOOL itemChecked = [self getItemChecked:indexPath.section and:indexPath.row];
cell.checkbox.selected = itemChecked;
} else if ([itemType isEqualToString:#"picker"]) {
NSString *itemValue = [self getItemValue:indexPath.section and:indexPath.row];
cell.pickerLabel = itemValue;
} else if ([itemType isEqualToString:#"datePicker"]) {
NSDate *itemDate = [self getItemDate:indexPath.section and:indexPath.row];
cell.datePickerLabel = itemDate;
}
return cell;
}
For my problem, I have create a NSMutableDictionaryin which i put my element like that :
key : "name"
value : "UITextField"
Like that i can get the textField everywhere in my class.
in .h file
create the dictionary
in .m
just put the element and when you want to go the text value do :
UITextField* myTextField= [dictionnary objectForKey:key];

why my uitableview cell row is repeating subtitles

In my uitableview I have two sections
first is fetched from core data
other is added through textfield which is stored in NSMutableArray(otherFriends)
here is my code
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
if([otherFriends count]>0)
{
return 2;
}
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)sectionIndex
{
if(otherFriends == 0)
{
return [[[[self fetchedResultsController]sections]objectAtIndex:0]numberOfObjects];
}
return [otherFriends count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"newGroupCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
cell.textLabel.font = [UIFont fontWithName:#"Helvetica-Light" size:20.0];
cell.textLabel.backgroundColor = [UIColor colorWithWhite:1.0f alpha:0.0f];
if(indexPath.section == 0)
{
user = [[self fetchedResultsController] objectAtIndexPath:indexPath];
cell.textLabel.text = user.name;
cell.detailTextLabel.text = user.primaryResource.status;
[cell.imageView setFrame:CGRectMake(0, 0, 50, 50)];
[cell.imageView.layer setMasksToBounds:YES];
if (user.photo != nil)
{
cell.imageView.image = user.photo;
}
else
{
cell.imageView.image = [UIImage imageNamed:#"defaultPerson"];
}
}
else
{
cell.textLabel.text = [otherFriends objectAtIndex:indexPath.row];
cell.imageView.image = [UIImage imageNamed:#"defaultPerson"];
}
return cell;
}
First section also have subtitles but second section cells have no subtitles
when I am adding new friend it works fine till all rows are visible, but when adding new friend and that row is not visible and to view that row I must scroll, then this row show the subtitle of first row in section 0(the very first cell) and its repeating in section 1 third row. Only subtitle is repeating but the main text is not.
For several hours I am trying to figure out this but no luck.
This is because in your else branch you are not setting the cell.detailTextLabel.text.
When a cell gets recycled, the old detailTextLabel stays there. You need to set all properties of the cell in both branches of the conditionsl, on the chance that it has been recycled.
if(indexPath.section == 0)
{
user = [[self fetchedResultsController] objectAtIndexPath:indexPath];
cell.textLabel.text = user.name;
cell.detailTextLabel.text = user.primaryResource.status;
[cell.imageView setFrame:CGRectMake(0, 0, 50, 50)];
[cell.imageView.layer setMasksToBounds:YES];
if (user.photo != nil)
{
cell.imageView.image = user.photo;
}
else
{
cell.imageView.image = [UIImage imageNamed:#"defaultPerson"];
}
}
else
{
cell.textLabel.text = [otherFriends objectAtIndex:indexPath.row];
cell.imageView.image = [UIImage imageNamed:#"defaultPerson"];
// ADDED
cell.detailTextLabel.text = #"";
// You may also need to adjust the frame of the cell.imageView
// because it could have been recycled.
}
Cells get reused. Since you are using the same cells for both sections, you must be sure to set/reset the same set of cell properties in all conditions.
The problem is when the cell is used for section 1, you don't reset the detailTextLabel. In your else block, add:
cell.detailTextLabel.text = nil;
This ensures that in all cases you are setting the textLabel, detailTextLabel, and the imageView properties for the reused cells.

Resources