Jon Erickson
Jon Erickson

Reputation: 1976

iOS GCD use for a UITableView

I have a pretty intensive UITableView that needs to be optimized a little. The question is, how to use grand central station to do it effectively. Each cell has a UIView with a couple labels and two images. I have subclassed the TableViewCell and the view's are being reused though it is still a little laggy when the table gets bigger. How would I go about using GCD to optimize the table? OR is there a better way around it? I am not very strong in thread management and looking for some advice.

Here is the code to my tableview:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

static NSString *CellIdentifier = @"Cell";
JointCAD *currentCall = [[xmlParser calls] objectAtIndex:indexPath.row];
self.tableView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"texture3.png"]];

TableViewCell *cell = (TableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil)
{
    cell = [[TableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}

cell.callTypeLabel.text = currentCall.currentCallType;
cell.locationLabel.text = currentCall.location;
cell.unitsLabel.text = currentCall.units;
cell.stationLabel.text = [@"Station: " stringByAppendingString:currentCall.station];
cell.selectedBackgroundView = cell.selectionView;

if ([currentCall.callType isEqualToString:@"F"]) {
    cell.imageType = Fire;
}
else {
    cell.imageType = EMS;
}

if ([currentCall.county isEqualToString:@"W"]) {
    cell.imageType1 = Washington;
}
else {
    cell.imageType1 = Clackamas;
}

return cell;
}

Here is the subclassed tableviewcell:

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {

    callView = [[UIView alloc] initWithFrame:CGRectMake(7.5, 7, 305, 65)];
    [callView setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin |
     UIViewAutoresizingFlexibleRightMargin |
     UIViewAutoresizingFlexibleWidth];
    [callView setContentMode:UIViewContentModeTopLeft];
    [callView setBackgroundColor: [UIColor colorWithRed:240.0/255.0 green:240.0/255.0 blue:240.0/255.0 alpha:1.0]];
    callView.layer.borderWidth = 1.0;
    callView.layer.borderColor = [UIColor colorWithRed:(0/255.0)  green:(0/255.0)  blue:(0/255.0)  alpha:1.0].CGColor;

    [self.contentView addSubview:callView];

    callTypeLabel = [[UILabel alloc]initWithFrame:CGRectMake(5, 2, 190, 21)];
    callTypeLabel.font = [UIFont boldSystemFontOfSize:12.0];
    callTypeLabel.textColor = [UIColor blackColor];
    callTypeLabel.backgroundColor = [UIColor clearColor];
    callTypeLabel.highlightedTextColor = [UIColor whiteColor];
    callTypeLabel.adjustsFontSizeToFitWidth = YES;
    [callView addSubview:callTypeLabel];

    locationLabel = [[UILabel alloc]initWithFrame:CGRectMake(5, 17 , 190, 15)];
    locationLabel.font = [UIFont systemFontOfSize:10.0];
    locationLabel.textColor = [UIColor blackColor];
    locationLabel.backgroundColor = [UIColor clearColor];
    locationLabel.highlightedTextColor = [UIColor whiteColor];
    locationLabel.adjustsFontSizeToFitWidth = YES;
    [callView addSubview:locationLabel];

    unitsLabel = [[UILabel alloc]initWithFrame:CGRectMake(4, 43, 190, 21)];
    unitsLabel.font = [UIFont systemFontOfSize:10.0];
    unitsLabel.textColor = [UIColor blackColor];
    unitsLabel.backgroundColor = [UIColor clearColor];
    unitsLabel.highlightedTextColor = [UIColor whiteColor];
    unitsLabel.adjustsFontSizeToFitWidth = NO;
    [callView addSubview:unitsLabel];

    stationLabel = [[UILabel alloc]initWithFrame:CGRectMake(195 , 25, 75, 20)];
    stationLabel.font = [UIFont systemFontOfSize:12.0];
    stationLabel.textColor = [UIColor blackColor];
    stationLabel.backgroundColor = [UIColor clearColor];
    stationLabel.highlightedTextColor = [UIColor whiteColor];
    stationLabel.adjustsFontSizeToFitWidth = YES;
    [callView addSubview:stationLabel];

    CGRect countyImageFrame = CGRectMake(275, 10, 18, 18);
    UIImageView *countyImageView = [[UIImageView alloc] initWithFrame:countyImageFrame];
    countyImageView.image = countyImage;
    [callView addSubview:countyImageView];

    CGRect callTypeImageFrame = CGRectMake(275, 37, 18, 18);
    UIImageView *callTypeImageView = [[UIImageView alloc] initWithFrame:callTypeImageFrame];
    callTypeImageView.image = callTypeImage;
    [callView addSubview:callTypeImageView];

    selectionView = [[UIView alloc] initWithFrame:CGRectMake(10, 7, 200, 65)];
    [selectionView setBackgroundColor: [UIColor clearColor]];

    }

    return self;
}

- (void)setImageType:(CallType)newImageType {
imageType = newImageType;

if (imageType == Fire) {
    CGRect callTypeImageFrame = CGRectMake(275, 37, 18, 18);
    UIImageView *callTypeImageView = [[UIImageView alloc] initWithFrame:callTypeImageFrame];
    callTypeImageView.image = [UIImage imageNamed:@"red.png"];
    [callView addSubview:callTypeImageView];
}
else if (imageType == EMS) {
    CGRect callTypeImageFrame = CGRectMake(275, 37, 18, 18);
    UIImageView *callTypeImageView = [[UIImageView alloc] initWithFrame:callTypeImageFrame];
    callTypeImageView.image = [UIImage imageNamed:@"yellow.png"];
    [callView addSubview:callTypeImageView];
    }
}

- (void)setImageType1:(County)newImageType1 {
imageType1 = newImageType1;

if (imageType1 == Washington) {
    CGRect callTypeImageFrame = CGRectMake(275, 10, 18, 18);
    UIImageView *countyImageView = [[UIImageView alloc] initWithFrame:callTypeImageFrame];
    countyImageView.image = [UIImage imageNamed:@"blue.png"];
    [callView addSubview:countyImageView];
}
else if (imageType1 == Clackamas) {
    CGRect callTypeImageFrame = CGRectMake(275, 10, 18, 18);
    UIImageView *countyImageView = [[UIImageView alloc] initWithFrame:callTypeImageFrame];
    countyImageView.image = [UIImage imageNamed:@"green.png"];
    [callView addSubview:countyImageView];
    }
}

Upvotes: 4

Views: 381

Answers (1)

David Doyle
David Doyle

Reputation: 1716

This is a little subtle, but the main area your code will hang on is in the setImageType: method.

You're adding a programmatically created Image View into your view hierarchy here:

UIImageView *callTypeImageView = [[UIImageView alloc] initWithFrame:callTypeImageFrame];
callTypeImageView.image = [UIImage imageNamed:@"red.png"];
[callView addSubview:callTypeImageView];

But you never actually remove the old image view. A better way to do this might be to cache the created image view in a property of the cell, then when you set the image type, send the message -[UIView removeFromSuperview] to the old image view before creating a new one.

As your code stands now, every time a cell is dequeued, a new image view is added to it, so every time the user scrolls up and down the table view, a new image view is created and added to the cell. It won't take long for there to be dozens of image views in each cell. I suspect this is causing many times more drawRect calls into image views than is actually necessary to achieve your purpose.

A better way of doing this would be to have both types of image views as properties that you create in the cell's init method, which are only configured in the setType methods. That way you only create one image view per type, and simply set configure its image in the appropriate setType method. Doing it this way, do bear in mind that removeFromSuperview will release the imageview, so you'll have to declare it as a strong property (assuming you're using ARC).

I appreciate neither of these solutions has anything to do with Grand Central Dispatch, but hopefully that should solve your problem without using a sledgehammer to crack a nut :).

Upvotes: 3

Related Questions