简体   繁体   中英

Write method that takes completion block

I just started experimenting with blocks and I am interesting in creating my own methods that take completion blocks. Until now I read a tutorial from appCoda and a this post from stackoverflow: Custom Completion Block For My Own Method

And here is my attempt to implement it an example:

#import "MainViewController.h"

@interface MainViewController ()
{
    UIImageView *animationView;
}
typedef void(^myCompletion)(BOOL);
@end

@implementation MainViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    //Set the backgroun image
    UIImageView *backgroundImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 20.0f, [[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height - 20.f)];
    [backgroundImage setImage:[UIImage imageNamed:@"chalk_board_texture_by_blueamnesiac-d4h76qm.png"]];
    [self.view addSubview:backgroundImage];


    [self myMethod:^(BOOL finished) {
        if(finished){
            [animationView setImage:[UIImage imageNamed:@"Animation60.png"]];
        }
    }];
}

-(void) myMethod:(myCompletion) compblock{
    //do stuff
    //Get the imges name into array
    NSArray *imageNames = @[@"Animation1.png", @"Animation2.png", @"Animation3.png", @"Animation4.png",
                            @"Animation5.png", @"Animation6.png", @"Animation7.png", @"Animation8.png",
                            @"Animation9.png", @"Animation10.png", @"Animation11.png", @"Animation12.png",
                            @"Animation13.png", @"Animation14.png", @"Animation15.png", @"Animation16.png",
                            @"Animation17.png", @"Animation18.png", @"Animation19.png", @"Animation20.png",
                            @"Animation21.png", @"Animation22.png", @"Animation23.png", @"Animation24.png",
                            @"Animation25.png", @"Animation26.png", @"Animation27.png", @"Animation28.png",
                            @"Animation29.png", @"Animation30.png", @"Animation31.png", @"Animation32.png",
                            @"Animation33.png", @"Animation34.png", @"Animation35.png", @"Animation36.png",
                            @"Animation37.png", @"Animation38.png", @"Animation39.png", @"Animation40.png",
                            @"Animation41.png", @"Animation42.png", @"Animation43.png", @"Animation44.png",
                            @"Animation45.png", @"Animation46.png", @"Animation47.png", @"Animation48.png",
                            @"Animation49.png", @"Animation50.png", @"Animation51.png", @"Animation52.png",
                            @"Animation53.png", @"Animation54.png", @"Animation55.png", @"Animation56.png",
                            @"Animation57.png", @"Animation58.png", @"Animation59.png", @"Animation60.png",];

    //move image objects by name to mutable array
    NSMutableArray *images = [[NSMutableArray alloc] init];
    for (int i = 0; i < imageNames.count; i++) {
        [images addObject:[UIImage imageNamed:[imageNames objectAtIndex:i]]];
    }

    //Create the image horlder for the animation using the window size
    int animationViewWidth = [[UIScreen mainScreen] bounds].size.width - 20.0f;
    int animationViewHeight = animationViewWidth * 1.38;
    animationView = [[UIImageView alloc]initWithFrame:CGRectMake(10.0f, 20.0f, animationViewWidth, animationViewHeight)];
    animationView.animationImages = images;
    animationView.animationDuration = 0.5;
    animationView.animationRepeatCount = 1;
    [self.view addSubview:animationView];
    [animationView startAnimating];

    //completion finished set bool to yes
    compblock(YES);
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end

The bug in the completion handler is that it doesn't set the background image after the animation finishes. Thank in advance!

Until now I found two great answer to the issue: the one from @Rob: - Set the image view's image property to be the 60th image before startAnimating.

and another one from @ian-macdonald that redirects to a great tutorial that we found at the same time: - How to Animate Images in a UIImageView with Completion Handler

But the question remains why can't a block be implemented as listener and when the animation finishes the block triggers the background image change?

I think you don't need the finished block at all. Just call
[animationView setImage:[UIImage imageNamed:@"Animation60.png"]];
BEFORE triggering the animation and it will show the image after the animation finished. Not sure though if there will be a short time where the last image is shown before the animation is started (But I think there's none if you start the animation right away).

You're calling compblock immediately after telling the animation to start. The animation hasn't had time to complete.

You could listen for animation completion, or you could just assume that it takes the exact amount of time you request.

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  compblock(YES);
});

You may experience some misaligned frames with this method because the animation may take less or more time, but it'll probably just be a few milliseconds and entirely unnoticeable.


You may be interested in the first hit on Google for uiimageview animation images completion . Relevant code block:

NSMutableArray *images = [[NSMutableArray alloc] init];
NSInteger animationImageCount = 38;
for (NSInteger i = 0; i < animationImageCount; i++) {
    // Images are numbered IndexedImagesInMyAnimation0, 1, 2, etc...
    [images addObject:(id)[UIImage imageNamed:[NSString stringWithFormat:@"IndexedImagesInMyAnimation%d", i]].CGImage];
}

CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"contents"];
animation.calculationMode = kCAAnimationDiscrete;
animation.duration = animationImageCount / 24.0; // 24 frames per second
animation.values = images;
animation.repeatCount = 1;
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
[self.animationImageView.layer addAnimation:animation forKey:@"animation"];

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM