Search code examples
iphonexcodeuicolor

Optimizing UIColor Animation


I'm trying like hell to make this GIF I have to show on an iPhone app I'm building. I'm at the point now where I'm profiling the app, and I realized that I was continuously allocated a UIColor and it was using virtually all of the phone's CPU.

I've been trying like hell all morning to optimize this function that I use to create and run the animation. If anyone has some insight, I'd greatly appreciate it.

I'm just trying to pull that UIColor out of the for statement, but maybe someone out there will see that I can do this a better way.

- (void)doBackgroundColorAnimation
{
     static NSInteger i = 0;
     int count = 34;
     NSMutableArray *colors = [[NSMutableArray alloc] initWithCapacity:count];
     for (int i=1; i<=34; i++) {
     NSString *strImgName = [NSString stringWithFormat: @"layer%d.png", i];
     UIColor *image = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:strImgName]];
     if (image) {
     [colors addObject:image];
     }
     }

     if (i >= [colors count]) {
     i = 1;
     }
     [UIView animateWithDuration:0.05f
     animations:^{
     self.animationView.backgroundColor = [colors objectAtIndex:i];
     } completion:^(BOOL finished) {
     ++i;
     [self doBackgroundColorAnimation];
     }];
}

EDIT: Request to post code

NSMutableArray *colors = [[NSMutableArray alloc] initWithCapacity:count];
static NSString *strImgName;
UIColor *image = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:strImgName]];
for (int i=1; i<=34; i++) {
strImgName = [NSString stringWithFormat: @"layer%d.png", i];
if (image) {
[colors addObject:image];
}
}

That returns -[__NSArrayM objectAtIndex:]: index 1 beyond bounds for empty array


Solution

  • This is a more explicit explanation of H2CO3's comments:

    Define some class properties:

    @property (nonatomic, retain) NSMutableArray* colors;
    @property (nonatomic, assign) currentColorIndex;
    

    Then have a single color initialization routine:

    - (void)calledDuringInit
    {
        self.colors = [NSMutableArray array];
    
        for (int i=1; i<=34; i++) 
        {
            NSString *strImgName = [NSString stringWithFormat: @"layer%d.png", i];
            UIColor *image = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:strImgName]];
            if (image)
            {
                 [self.colors addObject:image];
            }
        }
    }
    

    At this point the doBackgroundColorAnimation has no need to keep creating the color array:

    - (void)doBackgroundColorAnimation
    {
         if (self.currentColorCount >= [self.colors count]) 
         {
             self.currentColorCount = 1;
         }
    
         [UIView animateWithDuration:0.05f
         animations:^{
             self.animationView.backgroundColor = [self.colors objectAtIndex:self.currentColorCount];
         } completion:^(BOOL finished) {
             ++self.currentColorCount;
             [self doBackgroundColorAnimation];
         }];
    }