【问题标题】:Performance Issue while blurring image in UITableViewCell在 UITableViewCell 中模糊图像时的性能问题
【发布时间】:2023-04-04 06:00:01
【问题描述】:

我的自定义 UITableViewCell 中有一个 UIImageView。包含的图像应该是模糊的。我知道UIVisualEffectsView,但首先这在iOS8 之前是不可用的,其次对于我的用例来说模糊有点重。

这就是我想出这个解决方案的原因:

示例 cellForRowAtIndexPath:

- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellIdentifier = @"showCell";

    DEShowCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

    if (cell == nil)
    {
        [tableView registerNib:[UINib nibWithNibName:@"DEShowCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:cellIdentifier];
        cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    }

    [cell setBackgroundImageWithBlur:[UIImage imageNamed:@"sampleBanner"]];

    return cell;
}

我的自定义单元格:

-(void)setBackgroundImageWithBlur:(UIImage *)image {
    [self.backgroundImageView setImage:[self blurWithCoreImage:image]];
}

- (UIImage *)blurWithCoreImage:(UIImage *)sourceImage
{
    CIImage *inputImage = [CIImage imageWithCGImage:sourceImage.CGImage];

    // Apply Affine-Clamp filter to stretch the image so that it does not
    // look shrunken when gaussian blur is applied
    CGAffineTransform transform = CGAffineTransformIdentity;
    CIFilter *clampFilter = [CIFilter filterWithName:@"CIAffineClamp"];
    [clampFilter setValue:inputImage forKey:@"inputImage"];
    [clampFilter setValue:[NSValue valueWithBytes:&transform objCType:@encode(CGAffineTransform)] forKey:@"inputTransform"];

    // Apply gaussian blur filter with radius of 30
    CIFilter *gaussianBlurFilter = [CIFilter filterWithName: @"CIGaussianBlur"];
    [gaussianBlurFilter setValue:clampFilter.outputImage forKey: @"inputImage"];
    [gaussianBlurFilter setValue:@10 forKey:@"inputRadius"];

    CIContext *context = [CIContext contextWithOptions:nil];
    CGImageRef cgImage = [context createCGImage:gaussianBlurFilter.outputImage fromRect:[inputImage extent]];

    // Set up output context.
    UIGraphicsBeginImageContext(self.frame.size);
    CGContextRef outputContext = UIGraphicsGetCurrentContext();

    // Invert image coordinates
    CGContextScaleCTM(outputContext, 1.0, -1.0);
    CGContextTranslateCTM(outputContext, 0, -self.frame.size.height);

    // Draw base image.
    CGContextDrawImage(outputContext, self.frame, cgImage);

    // Apply white tint
    CGContextSaveGState(outputContext);
    CGContextSetFillColorWithColor(outputContext, [UIColor colorWithWhite:1 alpha:0.2].CGColor);
    CGContextFillRect(outputContext, self.frame);
    CGContextRestoreGState(outputContext);

    // Output image is ready.
    UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return outputImage;
}

不幸的是,当我尝试滚动 UITableView 时,这给我带来了巨大的性能问题。

所以我问我如何解决?我可以使用一些库来进行像GPUImage 这样的模糊处理,我猜这会更快,但我不知道这是否会产生很大的不同。

我认为UITableView 将包含大约 20-60 行

还有其他想法,比如缓存或其他什么?

【问题讨论】:

    标签: ios objective-c iphone uitableview image-processing


    【解决方案1】:

    WWDC 2013 code samples 之一,iOS_UIImageEffects,介绍了如何使用 vImage 高性能框架来模糊图像。当我测试它时,它比 CoreImage 快得多。

    但在回答您关于缓存的问题时,是的,绝对使用缓存。使用NSCache 作为主缓存,使用持久内存作为二级缓存。


    顺便说一句,您似乎在为每个单元格模糊相同的图像。如果是这样,您应该将其模糊一次,然后为所有单元格重复使用该模糊图像。

    同样,您要多次注册 NIB。预先注册一次。

    【讨论】:

      【解决方案2】:

      如果您确实希望使用 CoreImage,则不应不断地创建要与它一起使用的上下文。您应该创建一次上下文并重新使用它,因为不这样做会导致此类性能问题。

      您可以通过使用时间分析器工具分析您的代码来确定这是否是上述代码中的问题,或者是否是其他问题。为此,只需从 Xcode 的“Product”菜单中选择“Profile”,然后在运行时选择“Time Profiler”。然后,您将能够看到占用时间最多的调用的堆栈跟踪。

      【讨论】:

        【解决方案3】:

        我将使用 FXBlurView 并设置动态 = NO。它的性能不错。

        【讨论】:

          【解决方案4】:

          没有理由继续计算模糊的背景图像。由于所有内容都使用相同的,因此只需将其模糊一次,并在配置单元格时分配它:

          if (cell == nil)
          {
              [tableView registerNib:[UINib nibWithNibName:@"DEShowCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:cellIdentifier];
              cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
              // Inside the initial configuration; not outside.
              [cell.backgroundImageView setImage:self.blurredBackgroundImage];
          }
          

          设置self.blurredBackgroundImage 一次:

          - (void)viewDidLoad {
              self.blurredBackgroundImage = [self blurWithCoreImage:[UIImage imageNamed:...]];
          }
          

          当然,鉴于此代码,我可能只是在 PhotoShop 中模糊图像并将其保存为资源。没有理由以编程方式模糊静态资源(除非您在其他地方使用相同的图像并且它足够大以至于磁盘空间很重要)。

          【讨论】:

          • 是的,谢谢。我应该举一个更好的例子。图像将在我以后的应用程序中更改。我现在只使用了一个示例图像......但是我明白了我现在不模糊图像而是一个覆盖的 UIView 可以一直重复使用。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-03-18
          • 1970-01-01
          • 2023-03-20
          相关资源
          最近更新 更多