I have a problem with data being displayed in a UITableViewCell I have created.
I have a CoreData Model which I have a custom Cell which I am loading from a Xib. The layout loads correctly and the correct number of cells are generated. The problem comes when updating the button.titleLabel.text and description.
Here is my uitableview and uitableviewcell related code:
#pragma mark - UITableViewDatasource Methods.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [pointsHistoryItems count];
}
// Row display. Implementers should *always* try to reuse cells by setting each cell's reuseIdentifier and querying for available reusable cells with dequeueReusableCellWithIdentifier:
// Cell gets various attributes set automatically based on table (separators) and data source (accessory views, editing controls)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *CellIdentifier = [NSString stringWithFormat:#"Cell%d",indexPath.row];
PointsHistoryItemCell* cell = (PointsHistoryItemCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
return [self createCustomCell:cell cellForRowAtIndexPath:indexPath];
}
- (PointsHistoryItemCell *)createCustomCell:(PointsHistoryItemCell *)cell cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (cell == nil)
{
cell = (PointsHistoryItemCell *)[[[NSBundle mainBundle] loadNibNamed:#"PointsHistoryItemCell" owner:self options:nil] objectAtIndex:0];
}
AwesomePointsHistoryItem *aphi = (AwesomePointsHistoryItem *)[pointsHistoryItems objectAtIndex:indexPath.row];
cell.description.text = aphi.description;
NSString* pointsText = [NSString stringWithFormat:#"%# Points", [aphi.points stringValue]];
[cell.button.titleLabel setText:pointsText];
NSLog(#"is reaching createCustomCell");
NSLog(#"points %#", cell.button.titleLabel.text);
return cell;
}
the log prints:
is reaching createCustomCell
points 600 Points
However.. The cell.button.titleLabel.text does not update!
What am I doing wrong?
Use
[cell.button setTitle: pointsText forState: UIControlStateNormal];
instead of
[cell.button.titleLabel setText:pointsText];
Note : hope cell.button is a UIButton
Related
I have added tableview on top of UIViewController and I have also implemented the UITableViewDataSource and UITableViewDelegate methods
For some reason, I am not getting the value out of didSelectRowAtIndexPath. I get the expected value of indexPath.row but the selectedCell.textLabel.text returns nil.
I am not able to figure out what may be the problem. I am using the dynamic table.
//Array of multiple objects is filled through the delegated arrays and the arrays are properly filled.
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return _arrayForMultipleObjects.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
array = [[NSMutableArray alloc]init];
// Configure the cell...
_singleSelectionLabel= (UILabel *) [cell viewWithTag:2];
_singleSelectionLabel.text=[self.arrayForMultipleObjects objectAtIndex:indexPath.row];
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *valu ;
NSLog(#"%i count",indexPath.row);
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
NSString *cellText = selectedCell.textLabel.text;
NSLog(#"%#",cellText);
//Here cellText is null
if([tableView cellForRowAtIndexPath:indexPath].accessoryType==UITableViewCellAccessoryNone)
{ [tableView cellForRowAtIndexPath:indexPath].accessoryType=UITableViewCellAccessoryCheckmark;
valu = cellText;
}
NSLog(#"%#",valu);
}
If you are using storyboard then the default cell style of table cells is Custom which gives you a blank cell where you can add other types of controls to it.
If you dragged a label onto the cell and changed its text, then you are likely using a Custom style of UITableViewCell.
The property textLabel is only available on cells of types other than Custom, such as Basic, or Detailed.
Please double check if this is the case for you.
Edit: As ready suggested you can fetch the text like this:
self.arrayForMultipleObjects[indexPath.row]
I have a table view & a custom cell. the cell contains 3 buttons (check box type) . on button click the respective buttons text i need to change (check / uncheck).
I achieved this, but when i click 1st button on top cell and scroll down the new cell at the bottom also has this check mark, and when i scroll back to top the check mark is moved to next cell.. how to fix this??
code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *strCellIdentifier = #"RemoteCell";
RemoteCustomCell *cell = (RemoteCustomCell*)[tableView ![dequeueReusableCell][2]WithIdentifier:strCellIdentifier];
if (cell == nil) {
cell = [[RemoteCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:strCellIdentifier];
}
else {
cell = [cell initWithStyle:UITableViewCellStyleDefault reuseIdentifier:strCellIdentifier];
}
[cell.btnCheck1 addTarget:self action:#selector(CheckButton1_Click:) forControlEvents:UIControlEventTouchUpInside];
}
return cell;
}
- (void)CheckButton1_Click:(UIButton*)sender
{
RemoteControllCustomCell *clickedCell = (RemoteControllCustomCell *)[[sender superview] superview];
if(clickedCell.btnCheck1.selected)
{
[clickedCell.btnCheck1 setTitle:#"O" forState:UIControlStateNormal];
clickedCell.btnCheck1.selected = NO;
}
else
{
[clickedCell.btnCheck1 setTitle:#"X" forState:UIControlStateSelected];
clickedCell.btnCheck1.selected = YES;
}
}
screenshot:
In your RemoteCustomCell.m file you should implement
- (void)prepareForReuse
{
[super prepareForReuse];
cell.btnCheck1.selected = NO;
}
This way every cell that is reused will have it's btnCheck1.selected value set to NO, and when you load your cell in cellForRowAtIndexPath it will only set it to YES when the cell comes visible and you set it to that.
But it is key to store all your values in an NSMutableArray. There is no such thing as storing your values in the cells only, they get reused on a basis that can not be foreseen. Add your values to the array and use [myArray objectAtIndex:indexPath.row]; to open those values in a cell.
An example:
Somewhere in viewDidLoad
NSMutableArray *myArray = [[NSMutableArray alloc] initWithObjects:#"1", #"0", #"1", #"1", nil];
In your cellForRowAtIndexPath
BOOL yesOrNo = [[myArray objectAtIndex:indexPath.row] boolValue];
And then set your button.selected to the boolean.
This is a typical issue, where you are relying on the UI to the job of your model. The model, the thing that you should pass to your UITableViewCell, so it can be built, would tell it, if it should be displaying an "X" or an "O". Since you are not doing this, the easiest solution, would be to simply reset the state of the cell everytime it gets dequeued.
I think you need to store the state in a array and check the state in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
CheckButton1_Click do change the state, but when dequeueReusableCell , it loads from cellForRowAtIndexPath again.
It seems like you have dequeue of cell issue. You may implement cellForRowAtIndexPath method as below.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"RemoteCell";
RemoteCustomCell *cell = (RemoteCustomCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell==nil) {
NSArray *arrNib=[[NSBundle mainBundle] loadNibNamed:CellIdentifier owner:self options:nil];
cell= (RemoteCustomCell *)[arrNib objectAtIndex:0];
}
[cell.btnCheck1 addTarget:self action:#selector(CheckButton1_Click:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
...
for (int i = 0; i < 6; i++) {
VVUserInformationCell *cell = (VVUserInformationCell*)[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
NSLog(#"%#", array[i][1]);
[cell.userData setText: array[i][1]];
[cell.userData setTag:i];
NSLog(#"%#", cell.userData.text);
NSLog(#"%d", cell.userData.tag);
}
}
In iOS6 it work very well. But in iOS7 in array[i][1] is what I want but in cell.userData.text after setText is null and after setTag in everything is 0.
cell is part of UITableView which is subview of my controller and userData is UITextField inside cell.
[self.tableView cellForRowAtIndexPath:...]
returns nil for rows that are currently not visible (and it may return nil
generally in viewWillAppear:).
In that case cell.userData is nil, and setting a text or a tag has no effect at all.
It seems that you are (ab)using
the table view cells as data source. That cannot work, due to the above reason, and
because table view cells are reused.
You have to fill the cell contents in the
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
method instead.
I think you should use the UITableViewDataSource/cellForRowAtIndexPath methods to configure your cell with what's in array[i][1]
Something like this:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section; {
return [array count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
VVUserInformationCell *cell = [tableView dequeueReusableCellWithIdentifier:#"VVUserInformationCellID"];
if (!cell) {
cell = [[[NSBundle mainBundle] #"VVUserInformationCell" owner:nil options:nil] objectAtIndex:0];
}
[cell.userData setText:array[indexPath.row][1]];
[cell.userData setTag:indexPath.row]
return cell;
}
i have a uitableview with custom cells.. with normal code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
DDMainCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil)
{
cell = [[DDMainCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
}
the problem is when i select one cell i add progress bar on the cell that download data online.. but when i Scroll down i find that every 10 cells have the same progress bar .. how can i prevent this behavior ?
Try this,
- (void)viewDidLoad
{
[super viewDidLoad];
dataarr=[[NSMutableArray alloc]init];
indexarr=[[NSMutableArray alloc]init];
mytableview=[[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStylePlain];
mytableview.dataSource=self;
mytableview.delegate=self;
[self.view addSubview:mytableview];
for (int i=0; i<30; i++) {
[dataarr addObject:[NSString stringWithFormat:#"%d",i]];
}
// Do any additional setup after loading the view, typically from a nib.
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [dataarr count];
}
- (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] ;
}
cell.textLabel.text=[dataarr objectAtIndex:indexPath.row];
UIActivityIndicatorView *act=[[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[act setFrame:CGRectMake(50, 20, 20, 20)];
act.hidden=YES;
[cell.contentView addSubview:act];
cell.selectionStyle=UITableViewCellSelectionStyleNone;
if ([indexarr containsObject:[dataarr objectAtIndex:indexPath.row]])
{
[act startAnimating];
act.hidden=NO;
return cell;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([indexarr containsObject:[dataarr objectAtIndex:indexPath.row]])
{
[mytableview reloadData];
return;
}
[indexarr addObject:[dataarr objectAtIndex:indexPath.row]];
[mytableview reloadData];
}
Make sure, when downloading is complete, then remove this object from indexarr....
That's because your cells are getting reused; UITableView will put off-screen cells into the reusable cell queue, and dequeue them for reuse if the reuseIdentifier matches. You should use some other data structure (e.g. NSArray or NSDictionary) to track which indices/cells have already been tapped. Then, in the method you showed above, regardless of whether the cell was init-ed or dequeued, set the progress bar according to your underlying data structure.
Here your used UITableViewCellIdentifier is reuseIdentifier. Which will work for all Cells are same type. Now your are taking once cell with progress bar. Now it will different from all cells data.
So use one more tableview cell for progress bar, or while reloading table remove the Progress bar which is exists already and add again. for this use tag for progress bar.
I've embedded horizontal table views inside of table cells (ala the Pulse Reader). The interesting behavior that I'm getting is that dequeueReusableCellWithIdentifier: seems to be correctly remembering the offset of the embedded table views, without me doing anything. But there are two flavors to "remembering"
First (expected)
I create a table with 100 sections and 1 row per section. Each cell (each section) gets an embedded table view that I force to have 100 rows and 1 section. When I scroll the vertical table view, cells are reused (checked by looking at the instance names of the cells after dequeueReusableCellWithIdentifier:
VerticalTableViewCell *cell = (VerticalTableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
If I scroll the first table view cell's embedded table view to the right, say 10.5 cells, when I scroll down a couple cells in the vertical table view, the reused table cell has its embedded table view offset by those 10.5 cells. This makes sense, the cell was just reused and I didn't reset any offsets. Let's say that reused cell was the 7th row. If I now slide the 7th row's embedded table view (this is the same embedded table view as row one, due to the reuse) to position 20, when I go to the top of the vertical table view that embedded table view (which I had originally moved to 10.5), is now at 20. Again, expected, those table cells are the same. Just reused.
Second (desired, but have no idea how it works)
Now I fill in my real data (instead of just printing
[cell.textLabel setText:[NSString stringWithFormat: #"here: %d", indexPath.row]];
to the cell.
Now, all of a sudden, my embedded table views DO remember where they were. I once again ensure the cells are being reused (same method as above). But this time, when I scroll the first embedded table view (to position 10.5) and scroll down to the seventh row, the seventh row is at its starting point. When I scroll the first row back into view, it's right where I left it.
This is using Xcode 4.2 and iOS 5.0. Is there something smart that dequeueReusableCellWithIdentifier: does?
In old school (pre-iOS 5.0), I would have checked the
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease];
}
bits of logic to see what was happening, but with StoryBoards those are no longer necessary.
The 2 sample projects that behave differently are kind of big, but if there's any relevant code you'd like to see, let me know.
Sorry to be so vague, I'm just trying to grasp exactly whats going on with the memory management of these table views.
All the connections are via IBOutlets and made in the StoryBoard.
Thanks!
First Vertical Table View Controller
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
//#warning Potentially incomplete method implementation.
// Return the number of sections.
return 100;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//#warning Incomplete method implementation.
// Return the number of rows in the section.
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"PlayerCell";
PlayerCell *cell = (PlayerCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
cell.games = [NSMutableArray arrayWithCapacity:1];
if(indexPath.section <40){
//[cell.textLabel setText:[NSString stringWithFormat:#"h343: %d", indexPath.section]];
}
CGAffineTransform rotateTable = CGAffineTransformMakeRotation(-M_PI_2);
cell.htv.transform = rotateTable;
cell.htv.frame = CGRectMake(0, 0, 320, 120);
return cell;
}
First Horizontal Table View Delegate/Data Source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return 100;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
//UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UITableViewCell *cell = (UITableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
CGAffineTransform rotateImage = CGAffineTransformMakeRotation(M_PI_2);
cell.transform = rotateImage;
//[cell.myLabel setText:[NSString stringWithFormat:#"%d", indexPath.row]];
[cell.textLabel setText:[NSString stringWithFormat: #"here: %d", indexPath.row]];
return cell;
}
Second Vertical Table View Controller
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return [self.leagues count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"VerticalTableViewCell";
VerticalTableViewCell *cell = (VerticalTableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSLog(#"Cell: %# for index: %d", cell, indexPath.section);
cell.games = [self.leagues objectAtIndex:indexPath.section];
CGAffineTransform rotateTable = CGAffineTransformMakeRotation(-M_PI_2);
cell.horizontalTableView.transform = rotateTable;
cell.horizontalTableView.frame = CGRectMake(0, 0, 320, 120);
// Configure the cell...
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.section = indexPath.section;
return cell;
}
Second Horizontal Table View Delegate/Data Source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.games count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"HorizontalTableViewCell";
//UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
GameTableCell *cell = (GameTableCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
CGAffineTransform rotateImage = CGAffineTransformMakeRotation(M_PI_2);
cell.transform = rotateImage;
//[cell.myLabel setText:[NSString stringWithFormat:#"%d", indexPath.row]];
NSDictionary *game = [self.games objectAtIndex:indexPath.row];
[cell.homeTeamLogo setImage:[UIImage imageNamed:[NSString stringWithFormat:#"%#",[game objectForKey:#"LogoImage_HomeTeam"]]]];
[cell.visitingTeamLogo setImage:[UIImage imageNamed:[NSString stringWithFormat:#"%#",[game objectForKey:#"LogoImage_VisitingTeam"]]]];
[cell.homeTeamName setText:[NSString stringWithFormat:#"%#", [game objectForKey:#"AbbreviatedName_HomeTeam"]]];
[cell.visitingTeamName setText:[NSString stringWithFormat:#"%#", [game objectForKey:#"AbbreviatedName_VisitingTeam"]]];
NSDictionary *gameTime = [game objectForKey:#"GameTime"];
NSString *minutes = [NSString stringWithFormat:#"%#", [gameTime objectForKey:#"Minutes"]];
if([minutes length]==1){
minutes = #"00";
}
NSString *timeOfGame = [NSString stringWithFormat:#"%#:%#",[gameTime objectForKey:#"Hours"], minutes];
[cell.gameTime setText:timeOfGame];
return cell;
}
My fault.
I was saving the state of the the embedded Table View.
FYI: I was using the tableView.contentOffset (in case anybody needs to do this later).
Whoops.