我有一个应用程序,在使用它约30-35分钟后,整个操作系统的速度变慢。滞后是渐进的,我可以看到它随着时间的推移逐渐积累,因为我一遍又一遍地重复相同的操作。它是一个音乐应用程序,在流媒体播放约15-20首曲目后,滞后是无法忍受的。
在UIScrollView中滚动项目时,帧速率降至10以下。很多帧被跳过,UI几乎锁定。如果我对应用程序进行后台处理,我会在SpringBoard的操作系统中看到这种滞后,基本上无处不在。在SpringBoard中滚动应用程序图标会变得不稳定。解锁的幻灯片变得不稳定等等。
我将如何解决这个问题?可能是什么原因造成的。我不能减少代码来创建一个最小的可重现的例子,因为代码库相当复杂。我需要帮助来理解可能导致操作系统几乎锁定的原因。这不是一个僵局,因为用户界面仍然会响应但只需要很长时间。
哪些分析工具可以帮助阐明此问题的原因?我怀疑它可能是因为内存泄漏,但令人惊讶的是操作系统没有向应用程序发送内存警告,所以我也不完全确定。
非常感谢任何帮助。
答案 0 :(得分:2)
问题在于动画的积累。 Activity Monitor在调试此问题时最有用。 Springboard的CPU使用率持续上升,直到达到100%。因此,显然没有花时间在我的应用程序中,而是在Springboard中的渲染服务器中。
我创建了两个具有巨大重复次数的动画,让它们永远运行。然后我将每个动画添加到一个单独的图层。为了创建动画,我使用了一个惰性检查,并向图层询问了具有给定键的任何现有动画。如果图层没有返回任何内容,我创建了动画。问题是图层总是没有返回,所以我不断创建这些永远重复的动画。
这是有问题的代码。
// This call always returned nil.
CABasicAnimation *innerRotationAnimation = (CABasicAnimation *)[self.spinnerViewInner.layer animationForKey:@"rotationAnimation"];
// So I kept on creating animations and piling them up.
if (innerRotationAnimation == nil)
{
CATransform3D innerRotationTransform = CATransform3DMakeRotation(0.25f * M_PI * -1, 0, 0, 1.0);
innerRotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
innerRotationAnimation.toValue = [NSValue valueWithCATransform3D:innerRotationTransform];
innerRotationAnimation.duration = 0.25f;
innerRotationAnimation.cumulative = YES;
innerRotationAnimation.repeatCount = HUGE_VALF;
[self.spinnerViewInner.layer addAnimation:innerRotationAnimation forKey:@"rotationAnimation"];
}
要解决此问题,我开始删除现有动画。我可以在animationDidStop:finished:
回调或我的setAnimating:
方法中的两个点完成此操作,两者都运行良好。以下是setAnimating:
方法的更改。
- (void)setAnimating:(BOOL)animating
{
if (animating == NO) {
// Remove all existing animations now.
[self.layer removeAllAnimations];
}
else {
CABasicAnimation *animation = // Create animation;
[self.layer addAnimation:animation forKey:@"rotationAnimation"];
}
}
如果有人感兴趣的话,这是原始的 BROKEN 代码。
- (void)setAnimating:(BOOL)animating
{
if (self.isAnimating == animating)
{
return;
}
_animating = animating;
if (self.isAnimating == YES)
{
CABasicAnimation *innerRotationAnimation = (CABasicAnimation *)[self.spinnerViewInner.layer animationForKey:@"rotationAnimation"];
CABasicAnimation *outerRotationAnimation = (CABasicAnimation *)[self.spinnerViewOuter.layer animationForKey:@"rotationAnimation"];
if (innerRotationAnimation == nil)
{
CATransform3D innerRotationTransform = CATransform3DMakeRotation(0.25f * M_PI * -1, 0, 0, 1.0);
innerRotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
innerRotationAnimation.toValue = [NSValue valueWithCATransform3D:innerRotationTransform];
innerRotationAnimation.duration = 0.25f;
innerRotationAnimation.cumulative = YES;
innerRotationAnimation.repeatCount = HUGE_VALF;
[self.spinnerViewInner.layer addAnimation:innerRotationAnimation forKey:@"rotationAnimation"];
}
if (outerRotationAnimation == nil)
{
CATransform3D outerRotationTransform = CATransform3DMakeRotation(0.25f * M_PI * -1, 0, 0, -1.0);
outerRotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
outerRotationAnimation.toValue = [NSValue valueWithCATransform3D:outerRotationTransform];
outerRotationAnimation.duration = 0.25f;
outerRotationAnimation.cumulative = YES;
outerRotationAnimation.repeatCount = HUGE_VALF;
[self.spinnerViewOuter.layer addAnimation:outerRotationAnimation forKey:@"rotationAnimation"];
}
}
}
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag
{
self.spinnerViewInner.layer.opacity = (self.isAnimating ? 1.0 : 0.0);
self.spinnerViewOuter.layer.opacity = (self.isAnimating ? 1.0 : 0.0);
}
但有一件事我仍然很好奇。由于给定键只能有一个活动动画,当我尝试添加一个具有相同键的新动画时,Core Animation是否应该删除我现有的动画?为什么animationForKey:
会返回nil
。
答案 1 :(得分:1)
使用Instruments查看正在发生的事情。线程的失控产卵?内存泄漏?见https://developer.apple.com/library/ios/#documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/Introduction/Introduction.html