cellforRowAtIndexPath 效率?
每当我滚动桌面视图时,它都非常滞后。我认为这与我加载细胞的方式有关。我尽可能使用 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
正如 @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.
确保您已将单元格的重用标识符设置为您在代码中指定的内容,即
@"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 whatmyArray
is, and if it's actually an array, what theobjectForKey:
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.查看您的代码后我的一些注释:
Is
roundCorneredImage:radius:
缓存结果吗?如果不是,为每个单元执行 CG 调用肯定会出现瓶颈。 更新:使用工具来确保,但将处理后的UIImage
存储在集合中可能会更快(内存允许),以便下次可以再次将其拉出使用相同的参数调用该方法。所有的
UIImage
都可以在其他地方声明,然后在此方法中呈现。您当前的代码为每个单元格实例化一个新的UIImage
,这也会成为滚动的瓶颈。 更新:由于Image1.png
和Image2.png
基本上是静态的,您可以在界面中声明它们或将它们声明为静态 ivar,然后只需将它们分配给背景图像,而不是每次都实例化UIImage
。子类化
UITableViewCell
并实例化它可能比访问UINib
更快。此外,您还可以将布局/数据逻辑与委托方法分开。 这是我在UITableViewCell
子类中所做的要点。基本上,我将实体与单元一起存储,并且单元知道它的标签等。这使得单元格布局逻辑脱离了我的数据源代码。子
您似乎正在使用
NSDictionary
作为数据源。如果该字典中有很多对象,那么使用 CoreData 和 NSFetchedResultsController 可能会快得多。 这是一篇关于此事的好文章。 更新:好的,这应该不是问题。-
编辑
因此,如果您删除了所有这些:
并且它仍然滞后,让我们看看您的构造函数......这些行是做什么的?
另外,您没有在表格单元格中使用任何透明图像或任何内容,是吗?已知这些会导致绘图延迟...
-
编辑 #2
如果你精简到这一点,会发生什么?
Some of my notes after looking at your code:
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 processedUIImage
in a collection so that you can pull it out again the next time that method is called with the same parameters.All of your
UIImage
s could be declared elsewhere and then presented in this method. Your current code instantiates a newUIImage
for each cell which can also bottleneck your scrolling. Updated: SinceImage1.png
andImage2.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 instantiatingUIImage
each time.It may be faster to subclass
UITableViewCell
and instantiate that instead of reaching intoUINib
. 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 myUITableViewCell
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.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 useCoreData
and anNSFetchedResultsController
. Here's a good post on the matter. Updated: Ok, that shouldn't be an issue.-
Edit
So if you removed all of this:
and it still lags, let's look at your constructors...what do these lines do?
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?