cellforRowAtIndexPath 效率?

发布于 2024-12-24 17:42:00 字数 2028 浏览 2 评论 0原文

每当我滚动桌面视图时,它都非常滞后。我认为这与我加载细胞的方式有关。我尽可能使用 UINib (5.0+),同时仍然提供向后兼容性。然后,我使用 NSArray 中的 NSDictionary 中的项目加载自定义单元格的标签和图像,该 NSArray 是从 ViewDidLoad 中的 NSUserDefaults 加载的。

有什么办法可以提高这个cellForRowAtIndexPath的效率吗?

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

    CustomCell *cell = (CustomCell *)[aTableView dequeueReusableCellWithIdentifier:@"Cell"];
    if (cell == nil) {
        if ([self labelCellNib]) {
            [[self labelCellNib] instantiateWithOwner:self options:nil];
        } else {
            [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
        }
        cell = [self CustomTableCell];
        [self setCustomTableCell:nil];
    }
    NSDictionary *dictionary = [myArray objectAtIndex:indexPath.row];
    NSData *data = [dictionary objectForKey:@"OCRImage"];
    cell.previewPicture.image = [self roundCorneredImage:[UIImage imageWithData:data] radius:60];

    cell.titleLabel.text = [dictionary objectForKey:@"Title"];
    cell.titleLabel.delegate = self;

    cell.dateLabel.text = [dictionary objectForKey:@"Date"];

    if (indexPath.row%2) {
        cell.backgroundImage.image = firstImage;
    }
    else {
        cell.backgroundImage.image = secondImage;
    }
    return cell;
}

编辑:

- (UIImage*)roundCorneredImage: (UIImage*)orig radius:(CGFloat) r {
    UIGraphicsBeginImageContextWithOptions(orig.size, NO, 0);
    [[UIBezierPath bezierPathWithRoundedRect:(CGRect){CGPointZero, orig.size} 
                                cornerRadius:r] addClip];
    [orig drawInRect:(CGRect){CGPointZero, orig.size}];
    UIImage* result = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return result;
}

Edit2:这些是导致滞后的行:

NSData *data = [dictionary objectForKey:@"OCRImage"];
cell.previewPicture.image = [self roundCorneredImage:[UIImage imageWithData:data] radius:60];

Whenever I scroll my tableview it is very laggy. I think it has to do with how I am loading up my cells. I use UINib (5.0+) whenever I can while still providing backwards compatibility. Then I load my custom cell's labels and images with items from a NSDictionary from a NSArray which is loaded from NSUserDefaults in the ViewDidLoad.

Is there any way to improve the efficiency of this cellForRowAtIndexPath?

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

    CustomCell *cell = (CustomCell *)[aTableView dequeueReusableCellWithIdentifier:@"Cell"];
    if (cell == nil) {
        if ([self labelCellNib]) {
            [[self labelCellNib] instantiateWithOwner:self options:nil];
        } else {
            [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
        }
        cell = [self CustomTableCell];
        [self setCustomTableCell:nil];
    }
    NSDictionary *dictionary = [myArray objectAtIndex:indexPath.row];
    NSData *data = [dictionary objectForKey:@"OCRImage"];
    cell.previewPicture.image = [self roundCorneredImage:[UIImage imageWithData:data] radius:60];

    cell.titleLabel.text = [dictionary objectForKey:@"Title"];
    cell.titleLabel.delegate = self;

    cell.dateLabel.text = [dictionary objectForKey:@"Date"];

    if (indexPath.row%2) {
        cell.backgroundImage.image = firstImage;
    }
    else {
        cell.backgroundImage.image = secondImage;
    }
    return cell;
}

Edit:

- (UIImage*)roundCorneredImage: (UIImage*)orig radius:(CGFloat) r {
    UIGraphicsBeginImageContextWithOptions(orig.size, NO, 0);
    [[UIBezierPath bezierPathWithRoundedRect:(CGRect){CGPointZero, orig.size} 
                                cornerRadius:r] addClip];
    [orig drawInRect:(CGRect){CGPointZero, orig.size}];
    UIImage* result = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return result;
}

Edit2: These are the lines that are causing the lag:

NSData *data = [dictionary objectForKey:@"OCRImage"];
cell.previewPicture.image = [self roundCorneredImage:[UIImage imageWithData:data] radius:60];

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

回忆追雨的时光 2024-12-31 17:42:00

正如 @Till 在评论中所说,您应该在 Instruments 中启动您的应用程序(Xcode 中的产品 -> 配置文件),然后选择 CPU -> 。时间分析仪。

然后,在该位置上滚动几秒钟,然后点击乐器中的“录制”工具栏图标以关闭您的应用程序。您将能够看到滚动部分,因为 CPU 使用率可能会固定在 100%(除非由于网络活动问题而速度缓慢)。

单击时间线中高 CPU 活动区域开始之后,然后单击“开始检查范围”工具栏按钮,然后单击高 CPU 活动区域结束之前,然后单击“停止检查范围”工具栏按钮。

现在,您可以深入查看窗口底部的调用树视图,准确了解所有 CPU 使用情况。根据我的经验,如果关闭左侧的“反转调用树”选项,通常更容易找到问题。

性能错误可能很难发现,有时一行明显很慢的代码实际上根本不会引起任何问题。解决性能问题而不浪费时间的唯一方法是使用 Instruments。

As @Till said in a comment, you should launch your app in Instruments (Product -> Profile in Xcode), and select the CPU -> Time Profiler instrument.

Then, scroll around over the place for a few seconds, then hit the Record toolbar icon in instruments to close your app. You will be able to see the scrolling section because CPU usage will probably be pinned at 100% (unless it's slow because of network activity problem).

Click on the timeline after the start of the high CPU activity area, and click the "start inspection range" toolbar button, then click before the end of the high CPU activity area and click the "stop inspection range" toolbar button.

You can now drill down into the call tree view at the bottom of the window to figure out exactly where all your CPU usage is. In my experience it's usually easier to find the problem if you turn off "invert call tree" option on the left.

Performance bugs can be very hard to find, and sometimes a line of code that is obviously slow actually isn't causing any problems at all. The only way to fix performance issues without wasting time is to use Instruments.

作死小能手 2024-12-31 17:42:00

确保您已将单元格的重用标识符设置为您在代码中指定的内容,即 @"Cell"。如果它们不匹配,那么您将无法正确地重用单元,并且可能会花费比必要的更多的时间来创建单元。

如果您正确地回收了单元格,那么您应该查看 if (cell == nil) {...} 块之后的代码。一旦表格创建了足够的单元格来填充屏幕(可能还有一两个以上),您将跳过整个块,因此滚动时此方法的大部分时间将归因于以下代码。了解 myArray 是什么,以及如果它实际上是一个数组,objectForKey: 方法的作用会很有趣。没有其他东西看起来应该需要很长时间,但找出周期的最佳方法是在 Instruments 中分析您的代码。

Make sure that you've set the reuse identifier for your cell to the same thing that you've specified in your code, i.e. @"Cell". If they don't match, then you won't be reusing cells properly, and probably spending a lot more time creating cells than necessary.

If you are properly recycling cells, then you should take a look at the code after the if (cell == nil) {...} block. You'll be skipping that entire block once the table has created enough cells to fill the screen (and maybe one or two more), so most of the time attributable to this method while scrolling will be due to the following code. It'd be interesting to know what myArray is, and if it's actually an array, what the objectForKey: method does. Nothing else there looks like it should take a long time, but the best way to find out where the cycles are going is to profile your code in Instruments.

你是暖光i 2024-12-31 17:42:00

查看您的代码后我的一些注释:

  1. Is roundCorneredImage:radius: 缓存结果吗?如果不是,为每个单元执行 CG 调用肯定会出现瓶颈。 更新:使用工具来确保,但将处理后的 UIImage 存储在集合中可能会更快(内存允许),以便下次可以再次将其拉出使用相同的参数调用该方法。

  2. 所有的 UIImage 都可以在其他地方声明,然后在此方法中呈现。您当前的代码为每个单元格实例化一个新的 UIImage ,这也会成为滚动的瓶颈。 更新:由于 Image1.pngImage2.png 基本上是静态的,您可以在界面中声明它们或将它们声明为静态 ivar,然后只需将它们分配给背景图像,而不是每次都实例化 UIImage

  3. 子类化 UITableViewCell 并实例化它可能比访问 UINib 更快。此外,您还可以将布局/数据逻辑与委托方法分开。 这是我在 UITableViewCell 子类中所做的要点。基本上,我将实体与单元一起存储,并且单元知道它的标签等。这使得单元格布局逻辑脱离了我的数据源代码。

  4. 您似乎正在使用 NSDictionary 作为数据源。如果该字典中有很多对象,那么使用 CoreData 和 NSFetchedResultsController 可能会快得多。 这是一篇关于此事的好文章更新:好的,这应该不是问题。

-

编辑

因此,如果您删除了所有这些:

NSDictionary *dictionary = [myArray objectForKey:@"OCRImage"];
cell.previewPicture.image = [self roundCorneredImage:[UIImage imageWithData:data] radius:60];

if (indexPath.row%2) {
    cell.backgroundImage.image = firstImage;
}
else {
    cell.backgroundImage.image = secondImage;
}

并且它仍然滞后,让我们看看您的构造函数......这些行是做什么的?

cell = [self CustomTableCell];
[self setCustomTableCell:nil];

另外,您没有在表格单元格中使用任何透明图像或任何内容,是吗?已知这些会导致绘图延迟...

-

编辑 #2

如果你精简到这一点,会发生什么?

CustomCell *cell = (CustomCell *)[aTableView dequeueReusableCellWithIdentifier:@"Cell"];
if (cell == nil) {
    if ([self labelCellNib]) {
        [[self labelCellNib] instantiateWithOwner:self options:nil];
    } else {
        [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
    }
    cell = [self CustomTableCell];
    [self setCustomTableCell:nil];
}

cell.titleLabel.text = [dictionary objectForKey:@"Title"];

Some of my notes after looking at your code:

  1. Is roundCorneredImage:radius: caching the result? If not, executing CG calls for every cell would surely present a bottleneck. Updated: Use instruments to be sure, but it might be faster (memory allowing) to store the processed UIImage in a collection so that you can pull it out again the next time that method is called with the same parameters.

  2. All of your UIImages could be declared elsewhere and then presented in this method. Your current code instantiates a new UIImage for each cell which can also bottleneck your scrolling. Updated: Since Image1.png and Image2.png are basically static, you could declare them in your interface or as a static ivar and then just assign them to the background image rather than instantiating UIImage each time.

  3. It may be faster to subclass UITableViewCell and instantiate that instead of reaching into UINib. Also, you'd then be able to separate your layout/data logic from the delegate method. Here's a gist of what I did in my UITableViewCell subclass. Basically, I store the entity with the cell and the cell knows about it's labels and such. This keeps the cell layout logic out of my data source code.

  4. It looks like you're using an NSDictionary as your data source. If you have a lot of objects in that dictionary, it may be considerable faster to use CoreData and an NSFetchedResultsController. Here's a good post on the matter. Updated: Ok, that shouldn't be an issue.

-

Edit

So if you removed all of this:

NSDictionary *dictionary = [myArray objectForKey:@"OCRImage"];
cell.previewPicture.image = [self roundCorneredImage:[UIImage imageWithData:data] radius:60];

if (indexPath.row%2) {
    cell.backgroundImage.image = firstImage;
}
else {
    cell.backgroundImage.image = secondImage;
}

and it still lags, let's look at your constructors...what do these lines do?

cell = [self CustomTableCell];
[self setCustomTableCell:nil];

Also, you're not using any transparent images or anything in your table cell are you? Those have been known to cause drawing lag...

-

Edit #2

If you strip down to this, what happens?

CustomCell *cell = (CustomCell *)[aTableView dequeueReusableCellWithIdentifier:@"Cell"];
if (cell == nil) {
    if ([self labelCellNib]) {
        [[self labelCellNib] instantiateWithOwner:self options:nil];
    } else {
        [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
    }
    cell = [self CustomTableCell];
    [self setCustomTableCell:nil];
}

cell.titleLabel.text = [dictionary objectForKey:@"Title"];
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文