I have a button on my tableview cell.
But after scrolling the buttons look like this:
It looks like there is sometimes one button above the other.
How can I solve this problem?
That's my code for the button in cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
Chapter *chapter = nil ;
UITableViewCell *cell = nil;
NSUInteger row = [indexPath row];
switch (indexPath.section) {
case 0:
chapter = [[einfuerung objectAtIndex:row]retain];
break;
case 1:
chapter = [[vertiefung objectAtIndex:row]retain];
break;
case 2:
chapter = [[spezial objectAtIndex:row]retain];
break;
}
if ([self filesFromFolderWithChapter:chapter] > 1)
{
static NSString *SimpleTableIdentifier = #"SimpleTableIdentifier";
cell = [tableView dequeueReusableCellWithIdentifier: SimpleTableIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:SimpleTableIdentifier] autorelease];
}
}
else {
static NSString *ButtonTableIdentifier = #"ButtonTableIdentifier";
cell = [tableView dequeueReusableCellWithIdentifier: ButtonTableIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ButtonTableIdentifier] autorelease];
}
}
NSString *firstString;
NSString *lastString;
switch (indexPath.section) {
case 0:
chapter = [[einfuerung objectAtIndex:row]retain];
[dataInstance extractFromString: [chapter title]: &firstString: &lastString];
cell.textLabel.text = firstString;
cell.detailTextLabel.text = lastString;
cell.backgroundColor = [UIColor whiteColor];
break;
case 1:
chapter = [[vertiefung objectAtIndex:row]retain];
[dataInstance extractFromString: [chapter title]: &firstString: &lastString];
cell.textLabel.text = firstString;
cell.detailTextLabel.text = lastString;
cell.backgroundColor = [UIColor whiteColor];
break;
case 2:
chapter = [[spezial objectAtIndex:row]retain];
[dataInstance extractFromString: [chapter title]: &firstString: &lastString];
cell.textLabel.text = firstString;
cell.detailTextLabel.text = lastString;
cell.backgroundColor = [UIColor whiteColor];
break;
}
if ([self filesFromFolderWithChapter:chapter] > 1)
{
//VersionButton *button = [VersionButton buttonWithType:UIButtonTypeRoundedRect];
VersionButton *button = [[VersionButton alloc]initWithFrame:CGRectMake(500, 15, 150, 30) andTitle:#"ältere Versionen"];
button.chapter = chapter;
[button addTarget:self action:#selector(versionTapped:)
forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:button];
[button release];
}
[chapter release];
return cell;
}
First of all it would be helpful to see your entire cellForRowAtIndexPath function.
It looks like you are not accounting for cell reuse correctly. You should only add a button to your cell if you are creating a cell from scratch and not if a cell is being reused. If a cell is being reused you should have a way to access the button it already has and make any changes necessary to it.
are you calling setNeedsDisplay somewhere else that would cause it to call the drawRect?
Related
When I scroll UITableView the memory keeps on increasing and I get this sort of results when I run "Allocations".
I see their that VM:UITableViewLabel memory keeps on increasing and is persistent, Is their any way to I could remove this constant increase in memory
-(UITableViewCell*) tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
NSString *text = #"";
BOOL defaultStyle = YES;
static NSString *CellIdentifier = #"Cell";
UITableViewCell *defaultCell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (defaultCell == nil) {
defaultCell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
else{
NSLog(#"reusing the cell");
}
defaultCell.textLabel.textAlignment = NSTextAlignmentLeft;
defaultCell.userInteractionEnabled = YES;
defaultCell.textLabel.font = [UIFont systemFontOfSize:26.0f];
UIImageView *iv = defaultCell.imageView;
int totalSections = [self numberOfSectionsInTableView:tableView];
NSInteger computedSection = indexPath.section;
if (defaultStyle)
{
defaultCell.selectionStyle = UITableViewCellSelectionStyleBlue;
defaultCell.backgroundColor = [UIColor whiteColor];
defaultCell.textLabel.textColor = [UIColor blackColor];
}
else if (computedSection == 0)
{
const int totalRows = [self tableView:self.tableView numberOfRowsInSection:indexPath.section];
if (indexPath.row == 0) {
text = #"Style1";
defaultStyle = NO;
if (self.style1 == nil)
{
defaultCell.selectionStyle = UITableViewCellSelectionStyleNone;
defaultCell.textLabel.textColor = [UIColor grayColor];
}
else
{
defaultCell.selectionStyle = UITableViewCellSelectionStyleBlue;
defaultCell.textLabel.textColor = [UIColor blackColor];
}
iv.image = [UIImage imageNamed: #"Style1.png"];
}
if(indexPath.row == totalRows - 2){
// Categories
text = #"Style2";
iv.image = [UIImage imageNamed: #"Style2.png"];
defaultStyle = NO;
if ( self.style2 == nil) {
defaultCell.selectionStyle = UITableViewCellSelectionStyleNone;
defaultCell.textLabel.textColor = [UIColor grayColor];
} else {
defaultCell.selectionStyle = UITableViewCellSelectionStyleBlue;
defaultCell.textLabel.textColor = [UIColor blackColor];
}
}
else if (indexPath.row == totalRows - 1){
// Search
text = #"Style3";
iv.image = [UIImage imageNamed: #"Style3.png"];
}
}
else if (computedSection == 1)
{
MyCustomTableViewCell *cell = [mTableView dequeueReusableCellWithIdentifier:kCustomTableCellIdentifier];
if ( cell == nil ) {
cell = [CustomTableViewCell loadFromNibNamed:#"CustomTableViewCell"];
}
cell.titleLabel = #"custom cell";
cell.openImage =[UIImage imageNamed: #"custom.png"]
return cell;
}
else if (indexPath.section == totalSections - 1)
{
if (indexPath.row == 0)
{
text = #"Account";
defaultStyle = NO;
if (self.hasAccount == nil)
{
defaultCell.selectionStyle = UITableViewCellSelectionStyleNone;
defaultCell.textLabel.textColor = [UIColor grayColor];
}
else
{
defaultCell.selectionStyle = UITableViewCellSelectionStyleBlue;
defaultCell.textLabel.textColor = [UIColor whiteColor];
}
iv.image = [UIImage imageNamed: #"Account.png"];
}
}
defaultCell.textLabel.text = text;
return defaultCell;
}
I have copied your code into a new project, and made some tests. It has never used more than 10 Mb memory on a real device, so there can be 2 cases.
Calling a method which leaks. At this point you call only one method in cellForRow because: BOOL defaultStyle = YES; This method is:
int totalSections = [self numberOfSectionsInTableView:tableView];
Could you post also this method please?
UITableViewCell subclass leaks while reusing. This isn't an option now since you are using UITableViewCell.
Small note #1: remove the autorelease if the project is in ARC.
Small note #2: Use
static NSString *CellIdentifier = #"Cell";
UITableViewCell *defaultCell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
instead of:
static NSString *CellIdentifier = #"Cell";
UITableViewCell *defaultCell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (defaultCell == nil) {
defaultCell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
else{
NSLog(#"reusing the cell");
}
and you don't need to check and alloc new cells manually.
Thanks all for your help, the following solution worked for me
1.
-(void) viewDidLoad
{
[super viewDidLoad];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:kDefaultCellIdentifier];
[self.tableView registerNib:[UINib nibWithNibName:#"CustomTableViewCell" bundle:nil] forCellReuseIdentifier:kCustomTableCellIdentifier];
}
as told by #Péter Kovács
2.
Used indexPath method for both cells
static NSString *CellIdentifier = kDefaultCellIdentifier;
UITableViewCell *defaultCell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
static NSString *CellIdentifier = kCustomTableViewCellIdentifer;
UITableViewCell *defaultCell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
3.
Main problem I was using the defaultCell globally, it dequeued the defaultCell also for the CustomTableViewCell, so in the case CustomTableViewCell block was triggered it dequeued two cells. Dequeue ing respective cell based on their rows solved the problem.
I think you are not reusing the cells used in your table view
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"myCell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"myCell"];
} else {
// reset your cell values here
}
Use this inside your -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
I am re-using an Objective-C code where there is a dynamic tableView that display bluetooth devices in the area.
I would like to add a button on each row of this tableView that would trigger an action and display a content at the bottom of the screen.
The current and interesting part of code is
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MyIdentifier"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"MyIdentifier"];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
CLBeacon *beacon = (CLBeacon*)[self.beacons objectAtIndex:indexPath.row];
NSString *proximityLabel = #"";
switch (beacon.proximity) {
case CLProximityFar:
proximityLabel = #"Far";
break;
case CLProximityNear:
proximityLabel = #"Near";
break;
case CLProximityImmediate:
proximityLabel = #"Immediate";
break;
case CLProximityUnknown:
proximityLabel = #"Unknown";
break;
}
cell.textLabel.text = proximityLabel;
NSString *detailLabel = [NSString stringWithFormat:#"Major: %d, Minor: %d, RSSI: %d, UUID: %#",
beacon.major.intValue, beacon.minor.intValue, (int)beacon.rssi, beacon.proximityUUID.UUIDString];
cell.detailTextLabel.text = detailLabel;
return cell;
}
I am wondering what would be the best way to do it, and where to insert the button in this code.
I am not familiar with Objective-C dev and looking for all kind of example/illustration for this problem.
You can add your button in your cell's init part, that is
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"MyIdentifier"];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
// create your button and add it to your cell
UIButton *button = ....
[cell.contentView addSubview:button];
}
I'm new to iOS developing. I have a UITableViewCell which has three buttons and they were not appearing to be pressed to touch. I implemented the following code. The pressing appeared to have been solved but the scrolling have been disabled. Here's my code to make buttons appear to be pressed on touch. The loop in the code is important otherwise the table will not behave the way I want it to. Here's my code for cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
static NSString *CellIdentifier = #"customCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
UILabel *textLabel = (UILabel *) [cell.contentView viewWithTag:5];
switch ([indexPath section]) {
case 0:
textLabel.text = [patientRoom objectAtIndex:[indexPath row]];
break;
case 1:
textLabel.text = [patientsBathroom objectAtIndex:[indexPath row]];
break;
}
if (shown){
if (selectedIndexPath.row == indexPath.row)
comments.hidden = NO;
}
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
// Configure the cell...
for (id obj in cell.subviews){
if ([NSStringFromClass([obj class]) isEqualToString:#"UITableViewCellScrollView"]){
UIScrollView *scroll = (UIScrollView *) obj;
scroll.delaysContentTouches = NO;
break;
}
}
return cell;
}
I have 3 sections in a table view and only using the middle section, section 2, to show various cells. Sections 1 and 3 only show one cell and I am making them unclickable since I want to display buttons and text on them. I made them and it was working fine until I made sections 1 and 3 userInteractionEnabled=NO.
Code: I know I can make this Object Oriented, and it was, but once this problem came up I tried to make it differently but it is still the same.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
UIView *selectedBackgroundView = [[UIView alloc] initWithFrame:CGRectZero];
selectedBackgroundView.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.1];
cell.selectedBackgroundView = selectedBackgroundView;
if(cell==nil) { NSLog(#"Cell is nil");}
}
if(indexPath.section == 0)
{
cell.textLabel.text = nil;
cell.accessoryView = nil;
cell.detailTextLabel.text = nil;
dosageButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
amountButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[dosageButton addTarget:self action:#selector(showDosages:) forControlEvents:UIControlEventTouchUpInside];
[amountButton addTarget:self action:#selector(showAmount) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:dosageButton];
[self.view addSubview:amountButton];
cell.userInteractionEnabled = NO;
return cell;
}
else if (indexPath.section == 1)
{
if (self.nameMutable.count != 0 )
{
cell.textLabel.text = [self.nameMutable objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [NSString stringWithFormat:#"$%#",[self.priceMutable objectAtIndex:indexPath.row]];
cell.accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"chevron"]];
return cell;
}
else
{
//Empty for now. Waiting for data fetching to finish
return cell;
}
}
else if (indexPath.section == 2)
{
cell.userInteractionEnabled = NO;
cell.accessoryView = nil;
cell.detailTextLabel.text = nil;
return cell;
}
else
{
NSLog(#"Something went wrong");
return cell;
}
}
For some reason my table view cell in section 1 where it is supposed to be clickable the color changes to a dark grey and is not clickable anymore. Its usually cell 3 and cell 10. Also, when I scroll down and Section 0 is no longer visible and then I scroll back up and Section 0 is visible, some of the cells become non-clickable and the color of the text changes.
Also, how can I make a certain cell, inside section 1, have bigger height because the text is too long to display and it starts to display "..." or covers the detailTextLabel. Thanks in advance.
You have to remember that these cells are being reused or 'recycled' so if you're setting userInteractionEnabled=NO for an if statement you need to set it to userInteractionEnabled=YES in your else statement, or set it as YES before all your statements. You also want to make sure that you're adding any other subviews (buttons etc.) that are unique to certain index paths to cells that are newly created, where you would stick that piece of code inside your if(cell==nil) statement. Something like this:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
UIView *selectedBackgroundView = [[UIView alloc] initWithFrame:CGRectZero];
selectedBackgroundView.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.1];
cell.selectedBackgroundView = selectedBackgroundView;
if(indexPath.section == 0) {
dosageButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
amountButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[dosageButton addTarget:self action:#selector(showDosages:) forControlEvents:UIControlEventTouchUpInside];
[amountButton addTarget:self action:#selector(showAmount) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:dosageButton];
[self.view addSubview:amountButton];
}
if(cell==nil) { NSLog(#"Cell is nil");}
}
cell.userInteractionEnabled = YES;
cell.accessoryView = nil;
cell.textLabel.text = nil;
cell.detailTextLabel.text = nil;
if(indexPath.section == 0)
{
cell.userInteractionEnabled = NO;
}
else if (indexPath.section == 1)
{
if (self.nameMutable.count != 0 )
{
cell.textLabel.text = [self.nameMutable objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [NSString stringWithFormat:#"$%#",[self.priceMutable objectAtIndex:indexPath.row]];
cell.accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"chevron"]];
}
else
{
//Empty for now. Waiting for data fetching to finish
}
}
else if (indexPath.section == 2)
{
cell.userInteractionEnabled = NO;
}
else
{
NSLog(#"Something went wrong");
}
return cell;
}
And if you want to change the height of certain index paths (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath Docs delegate method.
My table only has 2 sections. I have a UITextView as a subview in the 2nd section of my table. and a list of possible quotes in the first section.
I'm having a problem where once the user selects a particular quote which gets "pasted" into the UITextView like so:
replyTextView.text = [NSString stringWithFormat:#"#%# UserName writes... \n[\"%#\"]", replyPostCode,[separatedString objectAtIndex:indexPath.row]];
or types text into the textview, after they scroll away from the textview so it's off the screen it gets cleared. I guess this is because I keep releasing it from my table..
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
NSString *replyCellIdentifier = #"replyCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
if ([indexPath section] == 0) {
cell = [self CreateMultilinesCell:CellIdentifier];
}
else if ([indexPath section] == 1) {
//NSLog(#"TextField");
cell = [self CreateMultilinesCell:replyCellIdentifier];
if ([indexPath row] == 0) {
replyTextView = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, 300, 150)];
//replyTextView.adjustsFontSizeToFitWidth = YES;
replyTextView.textColor = [UIColor blackColor];
replyTextView.keyboardType = UIKeyboardTypeASCIICapable;
replyTextView.returnKeyType = UIReturnKeyDefault;
replyTextView.backgroundColor = [UIColor whiteColor];
replyTextView.autocorrectionType = UITextAutocorrectionTypeNo;
replyTextView.autocapitalizationType = UITextAutocapitalizationTypeNone;
replyTextView.textAlignment = UITextAlignmentLeft;
replyTextView.tag = 0;
replyTextView.editable = YES;
replyTextView.delegate = self;
replyTextView.scrollEnabled = YES;
//[replyTextView becomeFirstResponder];
//replyTextView.clearButtonMode = UITextFieldViewModeNever;
//[replyTextView setEnabled: YES];
[cell.contentView addSubview:replyTextView];
[replyTextView release];
//cell.detailTextLabel.text = #"";
}
}
}
//NSLog(#"%d", [indexPath section]);
if ([indexPath section] == 0) {
cell.detailTextLabel.text = [separatedString objectAtIndex:indexPath.row];
}
return cell;
}
I'm just wondering just what is the best way to keep the text in my UITextView when the user scrolls the uitextview off the screen and back again?
update
- (UITableViewCell*) CreateMultilinesCell :(NSString*)cellIdentifier
{
//NSLog(#"Entering CreateMultilinesCell");
UITableViewCell *cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:cellIdentifier] autorelease];
cell.detailTextLabel.numberOfLines = 0;
cell.detailTextLabel.font = [self SubFont];
cell.detailTextLabel.textColor = [UIColor colorWithRed:10.0/255 green:10.0/255 blue:33.0/255 alpha:1.0];
[cell setBackgroundColor:[UIColor clearColor]];//]colorWithRed:.98 green:.98 blue:.99 alpha:1.0]];
[self.tableView setBackgroundColor:[UIColor clearColor]];//colorWithRed:.94 green:.96 blue:.99 alpha:1.0]];
//NSLog(#"Exiting CreateMultilinesCell");
return cell;
}
The easiest solution is to use a different cell identifier for the two types of cells.
Edit: I see you are using two different types, but you are not taking that into account in the dequeue call.