Performance iOS/Core动画:性能调整

Performance iOS/Core动画:性能调整,performance,ios,optimization,core-animation,Performance,Ios,Optimization,Core Animation,我的应用程序在iPad上运行。但它的表现非常糟糕——我的速度低于15帧/秒。有人能帮我优化吗 它基本上是一个轮子(源自UIView),包含12个按钮(源自UIControl)。 当用户旋转按钮时,按钮会动态展开和收缩(例如,位于12点钟位置的按钮应始终最大) 因此,我的方向盘包含一个: - (void) displayLinkIsCallingBack: (CADisplayLink *) dispLink { : // using CATransaction like th

我的应用程序在iPad上运行。但它的表现非常糟糕——我的速度低于15帧/秒。有人能帮我优化吗

它基本上是一个轮子(源自UIView),包含12个按钮(源自UIControl)。

当用户旋转按钮时,按钮会动态展开和收缩(例如,位于12点钟位置的按钮应始终最大)

因此,我的方向盘包含一个:

- (void) displayLinkIsCallingBack: (CADisplayLink *) dispLink 
{
    :
    // using CATransaction like this goes from 14fps to 19fps
    [CATransaction begin];
    [CATransaction setDisableActions: YES];
    
    // NEG, as coord system is flipped/fucked
    self.transform = CGAffineTransformMakeRotation(-thetaWheel);
    
    [CATransaction commit];

    if (BLA)
        [self rotateNotch: direction];  
}
…根据最近的触摸输入计算车轮的新旋转。这里已经有一个性能问题,我正在另一个线程中研究:

此例程还检查控制盘是否已完成另一个1/12旋转,如果已完成,则指示所有12个按钮调整大小:

// Wheel.m
- (void) rotateNotch: (int) direction
{
    for (int i=0; i < [self buttonCount] ; i++)
    {
            CustomButton * b = (CustomButton *) [self.buttons objectAtIndex: i];

    // Note that b.btnSize is a dynamic property which will calculate
    // the desired button size based on the button index and the wheels rotation.
            [b resize: b.btnSize];
    }
}
我想知道这个问题是否与排队的多个transform.scale操作的开销有关——每个按钮调整大小都需要整整一秒钟的时间才能完成,如果我快速旋转轮子,可能每秒旋转几圈;这意味着每个按钮每秒调整24次大小

**创建按钮的图层**

我想最后一个谜题是看看按钮的内容杀手。但是我试过了

contentsLayer.setRasterize = YES;
应该有效地将其存储为位图。因此,通过设置,代码实际上是动态调整12个位图的大小

我不敢相信这会让设备负担过重。然而,核心动画工具告诉我另一种情况;当我旋转方向盘时(通过在圆圈中拖动我的手指),它报告的速度约为15fps

这是不好的:我最终需要在每个按钮中放置一个文本层,这将进一步降低性能(…除非我使用上面的.setRasterize设置,在这种情况下,它应该是相同的)

一定是我做错了什么!但是什么呢

编辑:以下是负责生成按钮内容层(即带阴影的形状)的代码:

正如你所看到的,我正在尝试每一种可能的方法,我正在尝试两种制作形状的方法,并且分别切换。应该光栅化吗

**牺牲UI设计以获得可容忍的帧速率**


编辑:现在我已尝试禁用动态调整大小行为,直到控制盘固定到新位置,并设置wheel.setRasterize=YES。因此,它实际上是在手指下旋转一个预渲染的UIView(无可否认,它占据了大部分屏幕)(它很乐意以@~60fps的速度旋转),直到轮子停止转动,在这一点上它执行这个大尺寸的动画(@你也许应该在OpenGL中重新做这件事

我没有开发iPad应用程序的经验,但我确实有一些优化视频游戏的经验。因此,我不能给出确切的答案,但我想给出一些优化方面的提示

不要猜测。对其进行分析。

您似乎试图在不分析代码的情况下进行更改。更改一些可疑代码并交叉手指并不能真正起作用。您应该通过检查每个任务的
时间长度
以及它们需要运行的
频率
来分析代码。尝试分解您的任务并使用分析代码来衡量
时间
频率
。如果您可以测量每个任务使用了多少
内存
,或者有多少其他系统资源,那就更好了。根据证据找到瓶颈,而不是感觉

对于您的特定问题,您认为当您调整大小的工作开始时,程序会变得非常慢。但是,您确定吗?可能是其他原因。在获得实际的分析数据之前,我们无法确定

在进行更改之前,尽量减少问题区域并测量实际性能。

分析后,您的瓶颈有一个候选项。如果您仍然可以将原因拆分为几个小任务,请执行此操作并对其进行分析,直到无法再拆分。然后,尝试通过重复运行数千次来测量其精确性能。这一点很重要,因为您需要了解性能(速度和空间)进行任何更改之前,以便您可以将其与将来的更改进行比较

对于您的特定问题,如果确实存在调整大小的问题,请尝试检查它的执行情况。执行一次调整大小调用需要多长时间?您需要多久执行一次调整大小工作才能完成工作

改进它。如何改进?视情况而定。

现在,您有了有问题的代码块及其当前性能。您现在必须改进它。如何改进?这实际上取决于问题是什么。您可以搜索
更好的算法
,您可以执行
延迟获取
,如果您可以延迟计算直到真正需要执行,或者您可以执行
过多的计算如果您过于频繁地执行相同的操作,则可以通过缓存某些数据来进行恢复。您越了解原因,就越容易改进


对于您的特定问题,这可能只是操作系统ui功能的限制。通常,“调整大小”按钮不仅仅是调整按钮本身的大小,它还会使整个区域或其父窗口小部件失效,以便正确呈现每个ui内容。调整按钮的大小可能会很昂贵,如果是这样,您可以通过sim卡解决问题ply使用基于图像的方法,而不是基于操作系统ui的系统。如果操作系统API中的图像操作不够,您可以尝试使用OpenGL。但是,同样,在我们实际尝试它们和
profile
这些备选方案之前,我们不知道。祝您好运!:)

在没有阴影的情况下尝试一下,看看这是否会提高性能。我想这会大大提高性能。然后我会研究使用CALayer的阴影路径渲染阴影。这将大大提高阴影渲染性能

苹果去年WWDC的核心动画视频中有很多关于提高核心动画性能的重要信息

顺便说一下,我是阿尼玛
contentsLayer.setRasterize = YES;
- (CALayer *) makeContentsLayer
{
    CAShapeLayer * shapeOutline = [CAShapeLayer layer];
    shapeOutline.path = self.pOutline;
    
    CALayer * contents = [CALayer layer];
    
    // get the smallest rectangle centred on (0,0) that completely contains the button
    CGRect R = CGRectIntegral(CGPathGetPathBoundingBox(self.pOutline)); 
    float xMax = MAX(abs(R.origin.x), abs(R.origin.x+R.size.width));
    float yMax = MAX(abs(R.origin.y), abs(R.origin.y+R.size.height));
    CGRect S = CGRectMake(-xMax, -yMax, 2*xMax, 2*yMax);
    contents.bounds = S; 
    
    contents.shouldRasterize = YES; // try NO also
    
    switch (technique)
    {
        case kMethodMask:
            // clip contents layer by outline (outline centered on (0, 0))
            contents.backgroundColor = self.clr; 
            contents.mask = shapeOutline;
            break;
            
        case kMethodComposite:
            shapeOutline.fillColor = self.clr;
            [contents addSublayer: shapeOutline];
            self.shapeLayer = shapeOutline;
            break;
            
        default:
            break;
    }
    
    if (NO)
        [self markPosition: CGPointZero
                   onLayer: contents ];
    
    //[self refreshTextLayer];
    
    //[contents addSublayer: self.shapeLayerForText];
        
    return contents;
}