How to add a delay to a loop?

2019-01-29 02:25发布

Im attempting add image views to a UIView using this code:

for (int i = 0; i <numberOfImages; i++) {
    UIImageView *image = [UIImageView alloc]initWithFrame:CGRectMake(40, 40, 40, 40)];
    image.image = [images objectAtIndex:i];
    [self.view addSubview:image];
}

This works but the problem is I would like to have a 5 second delay before it adds each image, instead it adds them all at the same time. Can anybody help me out? Thanks.

Example:

5 seconds = one image on screen
10 seconds = two images on screen
15 seconds = three images on screen

5条回答
在下西门庆
2楼-- · 2019-01-29 02:38

I think you'd be better off with an animation

for (int i = 0; i < numberOfImages; i++)
{
    // Retrieve the image
    UIImageView *image = [[UIImageView alloc] initWithFrame:CGRectMake(40, 40, 40, 40)];
    image.image = [images objectAtIndex:i];

    // Add with alpha 0
    image.alpha = 0.0;
    [self.view addSubview:image];

    [UIView animateWithDuration:0.5 delay:5.0*i options:UIViewAnimationOptionAllowUserInteraction animations:^{
        // Fade in with delay
        image.alpha = 1.0;
    } completion:nil];
}

Not exactly what you asked for, since all the views will be added immediately, and then faded-in, but I feel that you're actually trying to achieve that, like some sort of stacking of images, right?

In fact, if you plan on removing the previous image, you can do it in the completion block, like this:

UIImageView *imagePrevious = nil;

for (int i = 0; i < numberOfImages; i++)
{
    // Retrieve the image
    UIImageView *image = [[UIImageView alloc] initWithFrame:CGRectMake(40, 40, 40, 40)];
    image.image = [images objectAtIndex:i];

    // Add with alpha 0
    image.alpha = 0.0;

    [UIView animateWithDuration:0.5 delay:5.0*i options:UIViewAnimationOptionAllowUserInteraction animations:^{
        // Add and fade in with delay
        [self.view addSubview:image];
        image.alpha = 1.0;
    } completion:^(BOOL finished)
    {
        if (finished && imagePrevious)
        {
            [imagePrevious removeFromSuperview];
        }
    }];

    imagePrevious = image;
}
查看更多
Explosion°爆炸
3楼-- · 2019-01-29 02:54

also this is best option. Try this

 [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:5.0]];
查看更多
Deceive 欺骗
4楼-- · 2019-01-29 02:55

Separate your code into a function, and call via NSTimer.

for (int i = 0; numberOfImages; i++) {
    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5
                                                      target:self
                                                    selector:@selector(showImage)
                                                    userInfo:[NSNumber numberWithInt:i] 
                                                     repeats:NO];

And then your function:

-(void) showImage:(NSTimer*)timer {
      //do your action, using
      NSNumber *i = timer.userInfo;

      //Insert relevant code here

      if (!done)
          NSTimer *newTimer = [NSTimer scheduledTimerWithTimeInterval:5 
                                                      target:self
                                                    selector:@selector(showImage)
                                                    userInfo:[NSNumber numberWithInt: i.intValue+1]
                                                     repeats:NO];
  }
}

userInfo is a convenient way of passing parameters to functions that you need to call (but they do have to be Objects). Also, by using repeats:NO, you don't have to worry about invalidating the timer, and there's no risk of leaving timer running in memory.

查看更多
5楼-- · 2019-01-29 02:59

You can use dispatch_after to dispatch a block, executed asynchronously that adds the image. Example:

for(int i = 0; numberOfImages; i++)
{
    double delayInSeconds = 5.0;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
    dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void)
    {
        UIImageView *image = [UIImageView alloc]initWithFrame:CGRectMake(40, 40, 40, 40)];
        image.image = [images objectAtIndex:i];
        // Update the view on the main thread:
        [self.view performSelectorOnMainThread: @selector(addSubview:) withObject: image waitUntilDone: NO];
    });
}
查看更多
Lonely孤独者°
6楼-- · 2019-01-29 03:03

It will be more efficient to use an NSTimer.

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:numberOfSeconds
                                                      target:self 
                                                    selector:@selector(methodToAddImages:) 
                                                    userInfo:nil 
                                                     repeats:YES];

This will essentially call methodToAddImages repeatedly with the specified time interval. To stop this method from being called, call [NSTimer invalidate] (bear in mind that an invalidated timer cannot be reused, and you will need to create a new timer object in case you want to repeat this process).

Inside methodToAddImages you should have code to go over the array and add the images. You can use a counter variable to track the index.

Another option (my recommendation) is to have a mutable copy of this array and add lastObject as a subview and then remove it from the mutable copy of your array.

You can do this by first making a mutableCopy in reversed order as shown:

NSMutableArray* reversedImages = [[[images reverseObjectEnumerator] allObjects] mutableCopy];

Your methodToAddImages looks like:

- (void)methodToAddImages
{
    if([reversedImages lastObject] == nil)
    {
        [timer invalidate];
        return;
    }

    UIImageView *imageView = [[UIImageView alloc] initWithFrame:(CGRectMake(40, 40, 40, 40))];
    imageView.image = [reversedImages lastObject];
    [self.view addSubview:imageView];
    [reversedImages removeObject:[reversedImages lastObject]];
}

I don't know if you're using ARC or Manual Retain Release, but this answer is written assuming ARC (based on the code in your question).

查看更多
登录 后发表回答