0

約30〜35分間使用した後、OS全体の速度が低下するアプリがあります。ラグは緩やかで、同じ操作を何度も繰り返すと、時間の経過とともにラグが大きくなることがわかります。これは音楽アプリであり、約15〜20トラックをストリーミングした後、ラグは耐えられません。

UIScrollViewでアイテムをスクロールしている間、フレームレートは10を下回ります。多くのフレームがスキップされ、UIがほとんどロックされます。アプリをバックグラウンドで実行すると、SpringBoardのOSと基本的にどこでもこの遅れが見られます。SpringBoardでアプリアイコンをスクロールすると途切れがちになります。ロックを解除するスライドが途切れるなど。

この問題を解決するにはどうすればよいですか?おそらく何が原因である可能性があります。コードベースはかなり複雑なので、コードを切り詰めて再現可能な最小限の例を作成することはできません。OSがほとんどロックする原因を理解するのに助けが必要です。UIはまだ応答するため、デッドロックではありませんが、非常に長い時間がかかります。

この問題の原因に光を当てるのに役立つプロファイリングツールは何ですか?メモリリークが原因の可能性があると思われますが、驚くべきことに、OSがアプリにメモリ警告を送信していないため、それについても完全にはわかりません。

どんな助けでも大歓迎です。

4

2 に答える 2

2

問題は、アニメーションの蓄積にありました。アクティビティモニターは、この問題のデバッグに最も役立ちました。SpringboardのCPU使用率は、100%に達するまで上昇し続けました。そのため、時間は明らかに私のアプリケーションではなく、Springboardにあるレンダリングサーバーに費やされていました。

繰り返し実行回数が非常に多い2つのアニメーションを作成して、永久に実行できるようにしました。次に、各アニメーションを別々のレイヤーに追加しました。アニメーションを作成するために、レイジーチェックを使用し、指定されたキーを使用して既存のアニメーションをレイヤーに要求しました。レイヤーが何も返さない場合は、アニメーションを作成しました。問題は、レイヤーが常に何も返さないことでした。そのため、私はこれらの永遠に繰り返されるアニメーションを作成し続けました。

これは問題のあるコードでした。

// 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:コールバックまたはメソッドの2つのポイントでこれを行うことができ、どちらも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);
}

しかし、私がまだ興味を持っていることが1つあります。特定のキーに対してアクティブなアニメーションは1つしかないため、同じキーで新しいアニメーションを追加しようとしたときに、Core Animationによって既存のアニメーションが削除されるべきではありませんか?そして、なぜまったくanimationForKey:戻ってこなかったのか。nil

于 2012-11-25T21:29:48.660 に答える
1

Instrumentsを使用して、何が起こっているかを調べます。スレッドの暴走スポーン?メモリリーク?https://developer.apple.com/library/ios/#documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/Introduction/Introduction.htmlを参照してください

于 2012-11-21T20:11:06.537 に答える