UITableview lags when scrolling. - ios

I'm trying to implement events table like in iOS 6 calendar.
I have UITableView with 500 rows(events). When I start scrolling animation is smooth.
But after two hundred rows begins lags. In native iOS 6 calendar events list all work smoothly.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
double begin = CFAbsoluteTimeGetCurrent();
if(!self.isNoResults)
{
NSString *cellIdentifier = [NSString stringWithFormat: #"Cell %i %i", indexPath.row, indexPath.section];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
UIImageView *circleImgView;
NSString *startTimeStr;
NSDateFormatter *formatter;
UILabel *timeLbl;
UILabel *titleLbl;
UILabel *endsLbl;
UIImageView *eventTypeImgView;
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
circleImgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"newMesIcon.png"]];
circleImgView.frame = CGRectMake(14, 19, 12, 12);
[cell.contentView addSubview:circleImgView];
timeLbl = [[UILabel alloc] init];
[timeLbl setBackgroundColor:[UIColor clearColor]];
timeLbl.frame = CGRectMake(35, 15, 200, 20);
timeLbl.font = [UIFont systemFontOfSize:13];
timeLbl.tag = 333;
[cell.contentView addSubview:timeLbl];
titleLbl = [[UILabel alloc] init];
titleLbl.frame = CGRectMake(123, 15, 200, 20);
titleLbl.font = [UIFont fontWithName:#"Arial-BoldMT" size:18];
[titleLbl setBackgroundColor:[UIColor clearColor]];
titleLbl.tag = 444;
[cell.contentView addSubview:titleLbl];
[cell.contentView setBackgroundColor:[UIColor colorWithRed:243 / 255.0 green:245 / 255.0 blue:247 / 255.0 alpha:1.0]];
endsLbl = [[UILabel alloc] init];
[endsLbl setBackgroundColor:[UIColor clearColor]];
endsLbl.frame = CGRectMake(49, 11, 40, 8);
[endsLbl setFont:[UIFont fontWithName:#"Arial-BoldMT" size:7]];
[endsLbl setTextColor:[UIColor redColor]];
endsLbl.tag = 555;
[cell.contentView addSubview:endsLbl];
eventTypeImgView = [[UIImageView alloc] init];
eventTypeImgView.frame = CGRectMake(95, 16, 16, 17);
eventTypeImgView.tag = 666;
[cell.contentView addSubview:eventTypeImgView];
}
startTimeStr = [[self.sortedEventsDict[[[[self.sortedEventsDict allKeys] sortedArrayUsingSelector:#selector(compare:)] objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row] valueForKey:#"starts"];
formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"yyy-MM-dd HH:mm"];
NSDate *startDate = [formatter dateFromString:startTimeStr];
NSDateFormatter *timeFormatter = [[NSDateFormatter alloc] init];
[timeFormatter setDateFormat:#"HH:mm"];
NSString *timeStr = [timeFormatter stringFromDate:startDate];
NSString *endTimeStr = [[self.sortedEventsDict[[[[self.sortedEventsDict allKeys] sortedArrayUsingSelector:#selector(compare:)] objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row] valueForKey:#"ends"];
NSDateFormatter *endformatter = [[NSDateFormatter alloc] init];
[endformatter setDateFormat:#"yyy-MM-dd HH:mm"];
NSDate *endDate = [endformatter dateFromString:endTimeStr];
NSDateFormatter *endtimeFormatter = [[NSDateFormatter alloc] init];
[endtimeFormatter setDateFormat:#"HH:mm"];
NSString *endTime = [endtimeFormatter stringFromDate:endDate];
if([[[self.sortedEventsDict[[[[self.sortedEventsDict allKeys] sortedArrayUsingSelector:#selector(compare:)] objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row] valueForKey:#"type"] isEqualToString:#"event"])
{
((UIImageView *)[cell.contentView viewWithTag:666]).image = [UIImage imageNamed:#"eventsIcon.png"];
}
else
{
((UIImageView *)[cell.contentView viewWithTag:666]).image = [UIImage imageNamed:#"appointmentsIcon.png"];
}
((UILabel *)[cell.contentView viewWithTag:555]).text = #"";
if([timeStr isEqualToString:#"00:00"] && [endTime isEqualToString:#"23:59"])
{
timeStr = #"all-day";
}
else if([timeStr isEqualToString:#"00:00"] && ![endTime isEqualToString:#"23:59"])
{
timeStr = endTime;
((UILabel *)[cell.contentView viewWithTag:555]).text = #"ENDS";
}
((UILabel *)[cell.contentView viewWithTag:333]).text = timeStr;
((UILabel *)[cell.contentView viewWithTag:444]).text = [[self.sortedEventsDict[[[[self.sortedEventsDict allKeys] sortedArrayUsingSelector:#selector(compare:)] objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row] valueForKey:#"title"];
startDate = nil;
timeFormatter = nil;
timeStr = nil;
endTimeStr = nil;
endformatter = nil;
endDate = nil;
endtimeFormatter = nil;
endTime = nil;
startTimeStr = nil;
formatter = nil;
[cell setBackgroundColor:[UIColor colorWithRed:243 / 255.0 green:245 / 255.0 blue:247 / 255.0 alpha:1.0]];
double finish = CFAbsoluteTimeGetCurrent();
NSLog(#"TIME DIFF = %f", finish - begin);
return cell;
}
else
{
NSString *cellIdentifier = [NSString stringWithFormat: #"Cell No Results %i %i", indexPath.row, indexPath.section];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
if(indexPath.row == 2)
{
UILabel *noResultsLbl = [[UILabel alloc] init];
noResultsLbl.text = self.noResultsString;
[noResultsLbl setFont:[UIFont fontWithName:#"Arial-BoldMT" size:20]];
[noResultsLbl setTextColor:[UIColor colorWithRed:204 / 255.0 green:204 / 255.0 blue:204 / 255.0 alpha:1.0]];
noResultsLbl.frame = CGRectMake(60, 15, 200, 20);
noResultsLbl.textAlignment = NSTextAlignmentCenter;
[cell.contentView addSubview:noResultsLbl];
}
}
[cell.contentView setBackgroundColor:[UIColor colorWithRed:243 / 255.0 green:245 / 255.0 blue:247 / 255.0 alpha:1.0]];
cell.userInteractionEnabled = NO;
double finish = CFAbsoluteTimeGetCurrent();
NSLog(#"TIME DIFF = %f", finish - begin);
return cell;
}
}
Please, help me.

Your cellForRowAtIndexPath is 140 lines long, that is the reason its not running smoothly. I would recommend going over the code and trying to refactor out as much as you can. Formatters are incredibly expensive, and you're alloc/initing several. Make a prototype or xib based cell rather than setting it up programmatically every single time. Id also recommend against using tags for views, put that into a xib or prototype cell and make it an outlet.
Those changes will speed up your scrolling.

Check the size of the images you are using in the cell. I had this problem once when the images were larger than they needed to be. Try reducing the image sizes to their optimal size for the table.

You sort all your data for each cell.
if([[[self.sortedEventsDict[[[[self.sortedEventsDict allKeys] sortedArrayUsingSelector:#selector(compare:)] objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row] valueForKey:#"type"] isEqualToString:#"event"])
Try to use prepared data for each [table reloadData] call. Basically you could perform all calculations in one place, and then just fill cells with results.
And best way to find what goes wrong is to use Profiler. It will show you which part of code eats all your cpu between frames.

No cell reuse, several alloc/init-s and a lot of NSDateFormatter's with is really expensive
Todo:
Subclass UITableViewCell and make your custom cell
Reuse cell using a constant identifier
Reuse NSDateFormatters with DFDateFormatterFactory or manually use NSDateFormatter separated by format, because each format is like a new formatter
Reuse cell:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
// Setup new cell and constant elements of cell
}
// Setup data like images, strings and stuff with minimal calculations and formatting
return cell;
}

My solution might be for a very rare case but it for sure helps.
I had a cell which contained a label with string of currency rubles "₽" (i think this also might be caused by other currency chars). This string was added to the label dynamically every time cell was reused. And the table view was very laggy. Then I removed only Ruble sign and lagging disappeared.
Solution: create a ready label and input the char into the label from the storyboard.

For me lags were caused by another tableView inside the main tableView cell (weird situation, I know). I've fixed it by removing additional tableView and rethinking my app's architecture without "tableView inside tableView" approach.

Related

Error: property 'label1'not found on object of type 'UITableViewCell'

Anyone got any ideas on the below? The error comes about on lines 6 & 8 from the bottom. I have synthesized the labels. Cheers.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateStyle:NSDateFormatterShortStyle];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
}
UILabel *label1 = [[UILabel alloc]initWithFrame:CGRectMake(10, 12, 240, 20)];
UILabel *label2 = [[UILabel alloc]initWithFrame:CGRectMake(250, 12, 50, 20)];
label1.text = #"Left";
label2.text = #"Right";
[cell.contentView addSubview:label1];
[cell.contentView addSubview:label2];
// Configure the cell...
President *p = (President *)[self.importedRows objectAtIndex:indexPath.row];
cell._label1.text = [NSString stringWithFormat:p.no ];
cell._label2.text = [NSString stringWithFormat: p.name ];
return cell;
}
Instead of:
cell._label1.text = [NSString stringWithFormat:p.no ];
cell._label2.text = [NSString stringWithFormat: p.name ];
use:
label1.text = [NSString stringWithFormat:p.no ];
label2.text = [NSString stringWithFormat: p.name ];
You just added them as subview but there are not properties of cell.
If you want to encapsulate it like that, create your custom class that will extend UITableViewCell and than you can use it this way.

cellForRowAtIndexPath: UILabel overlaps after scroll

cellForRowAtIndexPath:
cell.textLabel.text works fine.
UILabel is overlapping after scrolling. Here is the code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell==nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
// I have tried it by removing views and without. No difference.
NSArray *viewsToRemove = [self.tableView subviews];
for (UITableView *table in viewsToRemove)
{
[table removeFromSuperview];
}
}
NSManagedObject *managedObject = [newClass objectAtIndex:indexPath.row];
NSString *entityName= [[managedObject entity]name];
cell.textLabel.text = [NSString stringWithFormat:#"%# %i", entityName, [indexPath row]];
cell.textLabel.font=[UIFont systemFontOfSize:14.0];
NSDate *date = [managedObject valueForKey:#"lastmoddate"];
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
[formatter setDateFormat:#"EEE, MMM d, YYYY h:mm a"];
NSString *dateString = [formatter stringFromDate:date];
UILabel *lblDate = [[UILabel alloc] initWithFrame:CGRectMake(10, 30, 215, 10)];
lblDate.text = dateString;
lblDate.textColor = [UIColor grayColor];
lblDate.font = [UIFont systemFontOfSize:10.0];
[lblDate setBackgroundColor:[UIColor clearColor]];
[cell.contentView addSubview:lblDate];
return cell;
}
Here is the image:
This is what I came up with and it works well:
- (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];
}
NSManagedObject *managedObject = [newClass objectAtIndex:indexPath.row];
NSString *entityName= [[managedObject entity]name];
NSDate *date = [managedObject valueForKey:#"lastmoddate"];
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
[formatter setDateFormat:#"EEE h:mm a MMM d, yy'''"];
NSString *dateString = [formatter stringFromDate:date];
UILabel *lblUser = [[UILabel alloc] initWithFrame:CGRectMake(30, 8, 215, 14)];
lblUser.text = [NSString stringWithFormat:#"%# %i", entityName, [indexPath row]];
lblUser.textColor = [UIColor blackColor];
lblUser.font = [UIFont systemFontOfSize:16.0];
lblUser.tag = 1;
[lblUser setBackgroundColor:[UIColor clearColor]];
UILabel *lblDate = [[UILabel alloc] initWithFrame:CGRectMake(30, 21, 215, 20)];
lblDate.text = dateString;
lblDate.textColor = [UIColor grayColor];
lblDate.font = [UIFont systemFontOfSize:12.0];
lblDate.tag = 2;
[lblDate setBackgroundColor:[UIColor clearColor]];
if ((([cell.contentView viewWithTag:1]) && ([cell.contentView viewWithTag:2])))
{
[[cell.contentView viewWithTag:1]removeFromSuperview];
[[cell.contentView viewWithTag:2]removeFromSuperview];
}
[cell.contentView addSubview:lblDate];
[cell.contentView addSubview:lblUser];
return cell;
}
dequeueReusableCellWithIdentifier:forIndexPath: is guaranteed to return a cell (either a new one, or one from the reuse queue), so your if (cell == nil) clause never gets executed -- that's why it doesn't make a difference whether you remove the views or not. The labels overlap because that's the way you're setting it up. The default label is on the left side of the cell, and lblDate is also on the left (10 points from the left). Even if you move lblDate to the right, it might not show, because I think the default label goes full width of the cell. It would be better to make a custom cell with two labels that you place where you want them.
You also need to test whether the label already exists before you add another one. You can give the labels a unique tag, and check for a view with that tag, or, the easier way, I think, is to just make a custom cell in the storyboard or xib, and add the labels there. Then you only need to add the content to them in code.
Try this
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell==nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
UILabel *lblDate = [[UILabel alloc] initWithFrame:CGRectMake(10, 30, 215, 10)];
[cell.contentView addSubview:lblDate];
}
NSManagedObject *managedObject = [newClass objectAtIndex:indexPath.row];
NSString *entityName= [[managedObject entity]name];
cell.textLabel.text = [NSString stringWithFormat:#"%# %i", entityName, [indexPath row]];
cell.textLabel.font=[UIFont systemFontOfSize:14.0];
lblDate.text = dateString;
lblDate.textColor = [UIColor grayColor];
lblDate.font = [UIFont systemFontOfSize:10.0];
[lblDate setBackgroundColor:[UIColor clearColor]];
NSDate *date = [managedObject valueForKey:#"lastmoddate"];
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
[formatter setDateFormat:#"EEE, MMM d, YYYY h:mm a"];
NSString *dateString = [formatter stringFromDate:date];
return cell;
}
This is problem with recreating cell contents. Try with following code segment.
for(UIView *view in cell.contentView.subviews){
if ([view isKindOfClass:[UIView class]]) {
[view removeFromSuperview];
}
}
Add this line:
[cell.contentView.subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
Before:
[cell.contentView addSubview:lblDate];
You are right in writing the code for removing all contents from cell's subview. But you wrote it at wrong place.
UITableView's dequeueReusableCellWithIdentifier will return you the cell after it has been allocated and initialized once. So the code you wrote for removing the cell.contentView.subViews will never run and you get the Overlapped views.
You can either right that code in the else statement but I do not prefer that way. Why allocate and initialize all the contentView's every-time the UITableView needs cell. Rather I would create UILabel once and give it a tag to access it later. Like this:
UILabel *lblDate = nil;
if (cell == nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
lblDate = [[UILabel alloc] initWithFrame:CGRectMake(10, 30, 215, 10)];
lblDate.textColor = [UIColor grayColor];
lblDate.font = [UIFont systemFontOfSize:10.0];
lblDate.tag = 1;
[lblDate setBackgroundColor:[UIColor clearColor]];
[cell.contentView addSubview:lblDate];
}
else
{
//get a reference to the label in the recycled view
lblDate = (UILabel *)[cell.contentView viewWithTag:1];
}
Try this code. Your problem will be resolved.
-(NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section
{
return [arrTableData count];
}
-(UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UILabel *lblName;
UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier] autorelease];
lblName = [[[UILabel alloc] initWithFrame:CGRectMake(10, 20, 300, 20.0)] autorelease];
lblName.tag = LBLNAME;
lblName.numberOfLines=1;
lblName.textAlignment=UITextAlignmentLeft;
lblName.font = [UIFont systemFontOfSize:16.0];
lblName.textColor = [UIColor blackColor];
lblName.backgroundColor = [UIColor clearColor];
lblName.autoresizingMask = UIViewAutoresizingFlexibleRightMargin ;
[cell.contentView addSubview:lblName];
}else{
lblName = (UILabel *)[cell.contentView viewWithTag:LBLNAME];
}
if (arrTableData.count>0) { lblName.text=[NSString stringWithFormat:#"%#",[arrTableData objectAtIndex:indexPath.row]];
}
return cell;}
Try This
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
NSManagedObject *managedObject = [newClass objectAtIndex:indexPath.row];
NSString *entityName= [[managedObject entity]name];
NSDate *date = [managedObject valueForKey:#"lastmoddate"];
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
[formatter setDateFormat:#"EEE h:mm a MMM d, yy'''"];
NSString *dateString = [formatter stringFromDate:date];
UILabel *lblUser = [[UILabel alloc] initWithFrame:CGRectMake(30, 8, 215, 14)];
lblUser.text = [NSString stringWithFormat:#"%# %i", entityName, [indexPath row]];
lblUser.textColor = [UIColor blackColor];
lblUser.font = [UIFont systemFontOfSize:16.0];
lblUser.tag = 1;
[lblUser setBackgroundColor:[UIColor clearColor]];
UILabel *lblDate = [[UILabel alloc] initWithFrame:CGRectMake(30, 21, 215, 20)];
lblDate.text = dateString;
lblDate.textColor = [UIColor grayColor];
lblDate.font = [UIFont systemFontOfSize:12.0];
lblDate.tag = 2;
[lblDate setBackgroundColor:[UIColor clearColor]];
[cell.contentView addSubview:lblDate];
[cell.contentView addSubview:lblUser];
return cell;
}
if ([cell.contentView viewWithTag:tagnumber]
{
[[cell.contentView viewWithTag:tagnumber]removeFromSuperview];
}
lblDate.tag = tagnumber;
[cell.contentView addSubview:lblDate];
this line is enough just remove the previous tag subviews and added new subview with tag .. Thanks for your answer
In my case same issue is happened,allocating the tableviewcell in 2places,one is allocated in tableviewcell custom class,and customview controller has to been allocated,after i was changed the alllocation then everything will be working fine.

setAccessoryType destroys TableViewCell

I use a custom tablecell, labels and images are connected with tags.
If i add
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator]
it destroys my tableview. the image destroys and the background-color.
here are the differences:
Does anyone have any idea where the problem could be?
Thanks
EDIT:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"TableCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
if ([self labelCellNib]) {
[[self labelCellNib] instantiateWithOwner:self options:nil];
} else {
[[NSBundle mainBundle] loadNibNamed:#"LabelCell" owner:self options:nil];
}
cell = self.labelCell;
self.labelCell = nil;
}
static NSDateFormatter *dateFormatter = nil;
if (dateFormatter == nil)
dateFormatter = [[NSDateFormatter alloc] init];
static NSCalendar *calendar;
if(calendar == nil)
calendar= [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSString * timeStampString = [sqlTime objectAtIndex:indexPath.row];
NSTimeInterval _interval=[timeStampString doubleValue];
NSDate *createdAt = [NSDate dateWithTimeIntervalSince1970:_interval];
[dateFormatter setDateStyle:NSDateFormatterLongStyle];
// Datum in die Tabellen-Zelle einfügen
UILabel *label4 = (UILabel *)[cell viewWithTag:LABEL4];
label4.text = [NSString stringWithFormat:#"%#", [dateFormatter stringFromDate:createdAt]];
// Configure the cell...
UILabel *label1 = (UILabel *)[cell viewWithTag:LABEL1];
label1.text = [NSString stringWithFormat:#"%# %#", [sqlData objectAtIndex:indexPath.row], sonderzeichen];
UILabel *label2 = (UILabel *)[cell viewWithTag:LABEL2];
label2.text = [NSString stringWithFormat:#"Preis pro %#: %# €", sonderzeichen, [sqlPreis objectAtIndex:indexPath.row]];
UILabel *label3 = (UILabel *)[cell viewWithTag:LABEL3];
UIImageView *image = (UIImageView *)[cell viewWithTag:IMAGE_TAG];
if (indexPath.row==[itemsArray count]-1) {
image.image = [UIImage imageNamed:#"default.png"];
label3.text = #"-";
} else if ([itemsArray count]>1) {
int data_old = [[NSString stringWithFormat:#"%#", [sqlData objectAtIndex:indexPath.row]] intValue];
int data_new = [[NSString stringWithFormat:#"%#", [sqlData objectAtIndex:indexPath.row+1]] intValue];
label3.text = [NSString stringWithFormat:#"%i", data_old-data_new];
NSLog(#"%d -- %d", data_old, data_new);
if (data_new>data_old) {
image.image = [UIImage imageNamed:#"pfeil_runter.png"];
} else if (data_new<data_old) {
image.image = [UIImage imageNamed:#"pfeil_hoch.png"];
} else {
image.image = [UIImage imageNamed:#"minus.png"];
}
}
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
cell.contentView.backgroundColor = indexPath.row % 2? [UIColor colorWithRed:228.0/255.0 green:244.0/255.0 blue:199.0/255.0 alpha:1]:[UIColor whiteColor];
return cell;
}
You need to set the background color of the cell, rather than the contentView, but this doesn't work in cellForRowAtIndexPath. It needs to be in willDisplayCell:forRowAtIndexPath:
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
cell.backgroundColor = indexPath.row % 2? [UIColor colorWithRed:228.0/255.0 green:244.0/255.0 blue:199.0/255.0 alpha:1]:[UIColor whiteColor];
}
As far as the images getting squashed, that has to do with the size of your subviews, and their constraints. I think you can fix those by giving width constraints to two of your labels (a pair over and under each other), but make their priority <1000, so when the accessory view is added, the width of those labels will get smaller. Also give the image view on the left a fixed width.

Why does my UITextField always return the last value in my array?

static NSString *cellIdentifier = #"Cell";
NSMutableArray *fields=[[NSMutableArray alloc] init];
MDSpreadViewCell *cell = [aSpreadView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[[MDSpreadViewCell alloc] initWithStyle:MDSpreadViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease];
for (i =0; i < N; i++){
NSLog (#"tag = %i", i);
[fields addObject:[[UITextField alloc] initWithFrame:CGRectMake(10, 10, 185, 30)]];
[[fields objectAtIndex:i] setTag:i];
NSString *John = [NSString stringWithFormat:#"%i", i];
[[fields objectAtIndex:i] setText:John];
[[fields objectAtIndex:i] setBackgroundColor:[UIColor redColor]];
[[fields objectAtIndex:i] setDelegate:self];
[[fields objectAtIndex:i] setUserInteractionEnabled:TRUE];
viewWithTag:i]).text;
[cell addSubview:[fields objectAtIndex:i]];
}
return cell;
What is output to the console is correct: Tag = 0, 1, 2, 3, etc., but every cell just says the last value in the array. I've tried putting the for statement in different locations as well as returning the cell in different blocks. I am sure it is something simple that I am overlooking.
This may only be a partially useful answer, since you have some other issues to consider that I don't see addressed in the code snippet you've shown so far (most notably, that you'll need some sort of Model, such as a multidimentional array, that holds the spreadsheet data independently of the table view, and also code that will update the Model when the user changes any of the values in the text fields.)
But I think at this point you are just trying to create textfields in your table cells and get some numbers to appear in them. You might try something like this:
static NSString *cellIdentifier = #"Cell";
MDSpreadViewCell *cell = [aSpreadView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[[MDSpreadViewCell alloc] initWithStyle:MDSpreadViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease];
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(10, 10, 185, 30)]];
textField.tag = 1;
textField.backgroundColor = [UIColor redColor];
textField.delegate = self;
[textField setUserInteractionEnabled:YES];
[cell addSubview:textField];
}
UITextField *textFieldForCell = [cell viewWithTag:1];
int numberInCell = rowPath.row + columPath.column;
textFieldForCell.text = [NSString stringWithFormat:#"%i", numberInCell];
return cell;
Just as a future note, it would have been helpful in your original question to indicate that you are using MDSpreadView

Custom subviews on UITableViewCell and scrolling issue

I would like to get some suggesstions about the code shown below. The scrolling is kind of slow on iPhone, but not on simulator. What I am trying to do is to show multiple hours and messages on each row and each row may have different numbers of hours and messages.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// message + hours
static NSString *CellIdentifier = #"Cell1";
// others
static NSString *CellIdentifier1 = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UITableViewCell *cell1 = [tableView dequeueReusableCellWithIdentifier:CellIdentifier1];
UILabel *hoursLabel;
UILabel *infoLabel;
UILabel *dayLabel;
switch (indexPath.section) {
case 0:
cell1 = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier1] autorelease];
if ([hoursArray count] > 0 && [infoArray count] > 0) {
harray = [self seperateString:[hoursArray objectAtIndex:indexPath.row]];
iarray = [self seperateString:[infoArray objectAtIndex:indexPath.row]];
// check how many hours in an array
int loop = [harray count];
int currentInfoHeight = 0;
int currentHourHeight = 0;
int labelHeight = 0;
for (int i = 0; i < loop ; i++) {
NSString *Text = [[NSString alloc] initWithFormat:#"%#", [harray objectAtIndex:i]];
NSString *Text1 = [[NSString alloc] initWithFormat:#"%#", [iarray objectAtIndex:i]];
UIFont *cellFont = [UIFont systemFontOfSize:hourfontSize];
UIFont *cellFont1 = [UIFont systemFontOfSize:messageFontSize];
CGSize constraintSize = CGSizeMake(180.0f, MAXFLOAT);
CGSize labelSize = [Text sizeWithFont:cellFont constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];
CGSize labelSize1 = [Text1 sizeWithFont:cellFont1 constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];
/* HourLabel */
hoursLabel =
[[[UILabel alloc]
initWithFrame:
CGRectMake(
70.0 + 2.0 * cell1.indentationWidth,
currentHourHeight + gap,
tableView.bounds.size.width - 70.0 - 4.0 * cell1.indentationWidth,
labelSize.height)]
autorelease];
hoursLabel.text = [NSString stringWithFormat:[harray objectAtIndex:i]];
hoursLabel.backgroundColor = [UIColor clearColor];
hoursLabel.textColor = [UIColor blackColor];
// hoursLabel.shadowColor = [UIColor blackColor];
// hoursLabel.shadowOffset = CGSizeMake(0, 1);
hoursLabel.font = [UIFont systemFontOfSize:hourfontSize];
[cell1.contentView addSubview:hoursLabel];
if (![[iarray objectAtIndex:i] isEqualToString:#"-"]) {
/* infoLabel */
infoLabel =
[[[UILabel alloc]
initWithFrame:
CGRectMake(
70.0 + 2.0 * cell1.indentationWidth,
currentInfoHeight + gap + labelSize.height,
tableView.bounds.size.width - 70.0 - 4.0 * cell1.indentationWidth,
labelSize1.height)]
autorelease];
infoLabel.text = [NSString stringWithFormat:[iarray objectAtIndex:i]];
infoLabel.numberOfLines = 0;
infoLabel.backgroundColor = [UIColor clearColor];
infoLabel.textColor = [UIColor colorWithRed:51.0/255 green:51.0/255.0 blue:51.0/255.0 alpha:1.0];
infoLabel.font = [UIFont systemFontOfSize:messageFontSize];
[cell1.contentView addSubview:infoLabel];
labelHeight = (infoLabel.bounds.size.height);
}
else
{
labelHeight=0;
}
/* store current height of label */
currentHourHeight = (hoursLabel.bounds.size.height) + labelHeight + gap + currentHourHeight;
currentInfoHeight = (hoursLabel.bounds.size.height) + labelHeight + gap + currentInfoHeight;
}
}
/* dayLabel */
dayLabel =
[[[UILabel alloc]
initWithFrame:
CGRectMake(
2.0 * cell1.indentationWidth,
[self tableView:tableView_ heightForRowAtIndexPath:indexPath] / 2.0f - dayFontSize/2 ,
tableView.bounds.size.width -
70.0 - 4.0 * cell1.indentationWidth,
dayFontSize)]
autorelease];
[cell1.contentView addSubview:dayLabel];
/* Configure the properties for the text that are the same on every row */
dayLabel.backgroundColor = [UIColor clearColor];
dayLabel.textColor = [UIColor colorWithRed:207.0/255 green:181.0/255.0 blue:59.0/255.0 alpha:1.0];
dayLabel.font = [UIFont boldSystemFontOfSize:dayFontSize];
/* Draw a line to divide info and message into two sections */
UIView *lineView = [[[UIView alloc] initWithFrame:CGRectMake(79, 0, 1.5, cell1.contentView.bounds.size.height)] autorelease];
lineView.backgroundColor = [self.tableView_ separatorColor];
lineView.autoresizingMask = 0x3f;
[cell1.contentView addSubview:lineView];
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
[formatter setDateFormat:#"EEE"];
dayLabel.text = [NSString stringWithFormat:[daysArray objectAtIndex:[indexPath row]]];
[cell1 setSelectionStyle:UITableViewCellSelectionStyleNone];
return cell1;
case 1:
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = #"View information for this location";
cell.textLabel.font = [UIFont systemFontOfSize:16];
cell.textLabel.textAlignment = UITextAlignmentCenter;
return cell;
case 2:
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = #"Show building on campus map";
cell.textLabel.font = [UIFont systemFontOfSize:16];
cell.textLabel.textAlignment = UITextAlignmentCenter;
return cell;
case 3:
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = #"Direction to building";
cell.textLabel.font = [UIFont systemFontOfSize:16];
cell.textLabel.textAlignment = UITextAlignmentCenter;
return cell;
default:
break;
}
return cell;
}
You are allocating a NSDateFormatter for each cell. In my experience NSDateFormatter allocation and configuration are some of the most expensive calls available. They take significant amount of time.
Make that NSDateFormatter an instance variable so you have to allocate and configure it exactly one time.
you are not reusing your cells. If you don't reuse your cells your performance will suffer.
The pattern to reuse is something like this:
.
- (NSDateFormatter *)weekDayDateFormatter {
if (!myWeekDayDateFormatter) {
myWeekDayDateFormatter = [[NSDateFormatter alloc] init];
[myWeekDayDateFormatter setDateFormat:#"EEE"];
}
return myWeekDayDateFormatter;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSInteger secondLabelTag = 1001;
static NSInteger imageViewTag = 1002;
static NSString *CellIdentifier1 = #"Cell1";
static NSString *CellIdentifier2 = #"Cell2";
UITableViewCell *cell = nil;
switch (indexPath.section) {
case 0: {
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier1];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier1];
// allocate subviews and configure properties that never change
UILabel *secondLabel = [[UILabel alloc] initWithFrame:CGRectZero];
secondLabel.tag = secondLabelTag;
secondLabel.textColor = [UIColor orangeColor];
[cell.contentView addSubview:secondLabel];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectZero];
imageView.tag = imageViewTag;
imageView.contentMode = UIViewContentModeScaleAspectFill;
[cell.contentView addSubview:imageView];
}
// Whatever happened before you have a valid cell here
UILabel *secondLabel = (UILabel *)[cell.contentView viewWithTag:secondLabelTag];
UIImageView *imageView = (UIImageView *)[cell.contentView viewWithTag:imageViewTag];
secondLabel.text = [self.weekDayDateFormatter stringFromDate:[dataSource objectAtIndex:indexPath.row]];
imageView.image = [dataSource objectAtIndex:indexPath.row];
break;
}
case 1: {
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier2];
// configure properties that never change between cells
cell.textLabel.textColor = [UIColor greenColor];
cell.selectionStyle = UITableViewCellSelectionStyleGray;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
// configure properties that are different between cells
cell.textLabel.text = [dataSource objectAtIndex:indexPath.row];
cell.textLabel.backgroundColor = [dataSource objectAtIndex:indexPath.row];
break;
}
}
The code in the tableView:cellForRowAtIndexPath: parts that are called every time should execute as fast as possible. During scrolling this method is called for every single cell.
I guess, the performance isn't lost here, but in -cellForRowAtIndexPath:
Do you use – prepareForReuse / – dequeueReusableCellWithIdentifier:?

Resources