Animations Array Loads Slowly. How can I speed the

2020-07-27 02:07发布

问题:

we're loading about 30 full 320 x 480 images into an animations array. These images are very small in size at about 5 - 7Kb per images. The problem is when we run the loop to populate an array for the images, it seems to pause the entire app while this array get's populated. Is there perhaps a way to load this mutable array with the images in a separate thread or something to allow the array to populate without hurting performance? Thanks

    NSMutableArray *totalAnimationImages  = [[NSMutableArray alloc] initWithCapacity:numOfImages];

for(int i = 1; i < numOfImages; i++) {
    [totalAnimationImages addObject:[UIImage imageNamed:
                                     [NSString stringWithFormat:@"%@%d.png", image, i]]];
}

annImage.animationImages = totalAnimationImages;
annImage.animationDuration = speed; //.4 second
annImage.animationRepeatCount = 1; //infinite loop

[annImage startAnimating]; //start the animation

[totalAnimationImages release];

In working with this issue, and using the threading suggestion provided by shabzco, I've come up with the below code to process a loop, changing the image in an image view, with what seem to be absolutely no performance hit. This only holds one image at a time instead of 30 in an NSMutableArray. Just as Richard J. Ross III said, as soon as the animation would start it would be processing all of the images "into a in-memory bitmap format". This is where the long wait / lag came from. In the below code this is only happening once per image update instead of 30 just to start the animation. I use the while loop with timer in the suggested dispatch thread to keep this timer from effecting the main thread thus potentially creating jerky performance during animations. Please provide feedback on this solution! Thanks

UPDATE: Shabzco suggested that I replace the "ImageNamed" with "imageWithContentsOfFile" to avoid strange memory leaks due to ImageNamed potentially caching images in memory. This was discovered after running xcode profiler and watching the "Real Memory" counter. It became evident that every time an animation ran, the real memory would increase more and more until ultimately the app would crash. After replacing "ImageNamed" with "imageWithContentsOfFile" the issue went away. I've updated the below code.

annImage.image = [UIImage imageNamed:@""];
[annImage setAlpha:1.0];
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{ 
    NSTimeInterval timeout = 1.00 / speed;   // Number of seconds before giving up
    NSTimeInterval idle = 1.00 / 8;     // Number of seconds to pause within loop
    BOOL timedOut = NO;
    NSDate *timeoutDate;
    for(int i = 1; i < numOfImages; i++) {
        timeoutDate = [[NSDate alloc] initWithTimeIntervalSinceNow:timeout];
        timedOut = NO;
        while (!timedOut)
        {
            NSDate *tick = [[NSDate alloc] initWithTimeIntervalSinceNow:idle];
            [[NSRunLoop currentRunLoop] runUntilDate:tick];
            timedOut = ([tick compare:timeoutDate] == NSOrderedDescending);
            [tick release];
        }
        dispatch_async(dispatch_get_main_queue(), ^{
            //annImage.image = [UIImage imageNamed:
            //                      [NSString stringWithFormat:@"%@%d.png", image, i]];
            NSString *filePath = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@%d", image, i] ofType:@"png"];
            annImage.image = [UIImage imageWithContentsOfFile:filePath];
        });   
    }

    dispatch_async(dispatch_get_main_queue(), ^{
        [UIView beginAnimations:nil context:nil];
        [UIView setAnimationDuration: 0.3];
        [annImage setAlpha:0.0];
        [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
        [UIView commitAnimations];

    });
});

回答1:

This will make your for loop happen in a different thread and will start animating once everything has been loaded.

@autoreleasepool {
        NSMutableArray *totalAnimationImages  = [[NSMutableArray alloc] initWithCapacity:numOfImages];
        dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        dispatch_async(concurrentQueue, ^{   
            for(int i = 1; i < numOfImages; i++) {
                [totalAnimationImages addObject:[UIImage imageNamed:
                                                 [NSString stringWithFormat:@"%@%d.png", image, i]]];
            }
            annImage.animationImages = totalAnimationImages;
            annImage.animationDuration = speed; //.4 second
            annImage.animationRepeatCount = 1; //infinite loop
            [annImage startAnimating]; //start the animation
            dispatch_async(dispatch_get_main_queue(), ^{

                [totalAnimationImages release];

            });
        });
}