显示uitableviewcell时出现CGContext错误

时间:2013-07-01 05:27:14

标签: ios uitableview uiactivityindicatorview

当我向下滚动UITableView时,我正在使用旋转活动指示器来显示进度 加载更多结果。它应该像这样工作:如果我到达数据数组的最后一个索引,UITableView将在下一个单元格上显示一个活动指示器。但是,每当我摆脱旧的数据数组并使用新的数据数组并使用reloadData时,活动指示器就不会消失。活动指示符将位于另一个现有数据单元格的同一单元格中。在调试窗口中,它显示一些CGContext错误:

 <Error>: CGContextSaveGState: invalid context 0x0
 <Error>: CGContextSetBlendMode: invalid context 0x0
 <Error>: CGContextSetAlpha: invalid context 0x0
 <Error>: CGContextTranslateCTM: invalid context 0x0
 <Error>: CGContextScaleCTM: invalid context 0x0
 <Error>: CGContextDrawImage: invalid context 0x0
 <Error>: CGContextRestoreGState: invalid context 0x0
 <Error>: CGContextSetRGBFillColor: invalid context 0x0
 <Error>: CGContextFillRects: invalid context 0x0
 <Error>: CGContextSetFillColorWithColor: invalid context 0x0
 <Error>: CGContextSetFont: invalid context 0x0
 <Error>: CGContextSetTextMatrix: invalid context 0x0
 <Error>: CGContextSetFontSize: invalid context 0x0
 <Error>: CGContextSetTextPosition: invalid context 0x0
 <Error>: CGContextShowGlyphsWithAdvances: invalid context 0x0

如何解决此问题?

这是我在cellForRowAtIndexPath的代码:

TNSTableViewCell *videoCell = [tableView dequeueReusableCellWithIdentifier:@"videoCell"];

if (videoCell == nil) {
    videoCell = [[TNSTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"videoCell"];
}

// When scroll down last index of the index load next page
if (indexPath.row >= self.entries.count) {
    if (!loading) {
        NSLog(@"Loading new records...");
        loading = YES;

        if (fetchBatch != 0) {
            [informationDownloader getSearchRecordsWithKeywords:nil];
        }

    }
}

if (indexPath.row < self.entries.count) {

if (videoCell.activityIndicator) {
    videoCell.activityIndicator = nil;
}
TNSVideoRecord *record = [self.entries objectAtIndex:[indexPath row]];

videoCell.textLabel.text = record.title;
videoCell.textLabel.backgroundColor = [UIColor clearColor];
videoCell.detailTextLabel.numberOfLines = 2;
videoCell.detailTextLabel.text = [@"views: " stringByAppendingFormat:@"%@\n%@", [record.viewCount stringValue], record.uploader];
videoCell.detailTextLabel.backgroundColor = [UIColor clearColor];

if (!record.image) {
    if (self.thumbnailVideoTableView.dragging == NO && self.thumbnailVideoTableView.decelerating == NO) {

        [informationDownloader downloadThumbnailForRecord:record];
    }
    // if a download is deferred or in progress, return a placeholder image
    UIImageView *imageView = videoCell.imageView;
    UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
    indicator.alpha = 1.0;
    indicator.center = imageView.center;
    [imageView addSubview:indicator];
    [indicator startAnimating];
} else {
    videoCell.imageView.image = record.image;
}

videoCell.imageView.userInteractionEnabled = YES;
videoCell.imageView.tag = [indexPath row];

UITapGestureRecognizer *tapped = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(playVideo:)];
[videoCell.imageView addGestureRecognizer:tapped];

UIImage *playButtonImage = [UIImage imageNamed:@"playbutton.png"];

NSString *durationText = [TNSUtilities convertDuration:record.length];
UIImage *image = [TNSUtilities drawText:durationText inImage:[TNSUtilities drawImage:playButtonImage inImage:videoCell.imageView.image]];
videoCell.imageView.image = image;

videoCell.accessoryView.tag = [indexPath row];
videoCell.accessoryView = [self makeAddButton];
videoCell.accessoryView.userInteractionEnabled = YES;

[videoCell setNeedsLayout];

} else {
    NSLog(@"Displaying spinning indicator.");
    videoCell.activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
    videoCell.activityIndicator.backgroundColor = [UIColor clearColor];
    [videoCell addSubview:videoCell.activityIndicator];
    videoCell.activityIndicator.frame = CGRectMake(self.view.frame.size.width/2 - 15, videoCell.frame.size.height/2 - 15, 30, 30);
    videoCell.backgroundColor = [UIColor clearColor];

    [videoCell.activityIndicator startAnimating];
    [videoCell setNeedsLayout];

}

return videoCell;

正如您所看到的,imageView中还有另一个活动指示器,在更新数据阵列后该指示器也保留在imageView上。奇怪的是,指标并没有出现在每个uitableviewcell上。

这是我在TNSTableViewCell中的prepareReuse实现,它是UITableViewCell的子类:

- (void)prepareForReuse
{
    if (self.activityIndicator) {
        [self.activityIndicator stopAnimating];
        self.activityIndicator = nil;
    }

    self.textLabel.text = nil;
    self.detailTextLabel.text = nil;
}

这是drawText方法和drawImage方法:

+ (UIImage *)drawText:(NSString *)text inImage:(UIImage *)image
{
    UIGraphicsBeginImageContext(image.size);
    CGRect bgRect = CGRectMake( 0, 0, image.size.width, image.size.height);
    [image drawInRect: bgRect];

    CGFloat rectWidth;

    if (text.length < 6) {
        rectWidth = 40.0f;
    } else {
        rectWidth = 56.0f;
    }

    CGRect textRect = CGRectOffset(CGRectMake(0, 0, rectWidth, 14), bgRect.size.width - rectWidth, bgRect.size.height - 14);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetRGBFillColor(context, 100.0f/255.0f, 100.0f/255.0f, 100.0f/255.0f, 1.0f);
    CGContextFillRect(context, textRect);

    CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
    [text drawInRect:textRect withFont:[UIFont systemFontOfSize:14] lineBreakMode:NSLineBreakByClipping];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return newImage;
}

+ (UIImage *)drawImage:(UIImage *)fgImage inImage:(UIImage *)bgImage
{
    UIGraphicsBeginImageContextWithOptions(bgImage.size, FALSE, 0.0);
    CGRect bgRect = CGRectMake( 0, 0, bgImage.size.width, bgImage.size.height);
    [bgImage drawInRect:bgRect];
    [fgImage drawInRect:CGRectOffset(CGRectMake(0, 0, fgImage.size.width, fgImage.size.height), bgRect.size.width/2 - fgImage.size.width/2, bgRect.size.height/2 - fgImage.size.height/2)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return newImage;
}

1 个答案:

答案 0 :(得分:0)

当您重复使用单元格并添加子视图时,它会保留在那里。因此,下次重复使用时,您需要检查是否有子视图并明确重新使用它。

对于您的活动指示器,当单元格从显示中移除但指示器仍然是动画时,它将尝试绘制而没有有效的上下文。

当电池离开屏幕并重复使用时,请尝试停止/移除指示灯。或者,考虑简化您的单元格设置并使用页脚视图来保存活动指示器,并在完成后删除页脚。