如何为循环添加延迟?
Posted
技术标签:
【中文标题】如何为循环添加延迟?【英文标题】:How to add a delay to a loop? 【发布时间】:2013-07-18 19:03:35 【问题描述】:我正在尝试使用此代码将图像视图添加到 UIView:
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];
这可行,但问题是我希望在添加每个图像之前有 5 秒的延迟,而不是同时添加它们。有人可以帮我吗?谢谢。
例子:
5 seconds = one image on screen
10 seconds = two images on screen
15 seconds = three images on screen
【问题讨论】:
Displaying images in sequence with a loop, Displaying multiple images serially within a loop的可能重复 【参考方案1】:使用NSTimer 会更有效。
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:numberOfSeconds
target:self
selector:@selector(methodToAddImages:)
userInfo:nil
repeats:YES];
这实际上会以指定的时间间隔重复调用methodToAddImages
。要停止调用此方法,请调用[NSTimer invalidate]
(请记住,无效的计时器无法重复使用,您需要创建一个新的计时器对象以防重复此过程)。
在methodToAddImages
中,您应该有代码来遍历数组并添加图像。
您可以使用计数器变量来跟踪索引。
另一种选择(我的建议)是拥有此数组的可变副本并将lastObject
添加为子视图,然后将其从数组的可变副本中删除。
您可以先按相反的顺序创建一个 mutableCopy,如下所示:
NSMutableArray* reversedImages = [[[images reverseObjectEnumerator] allObjects] mutableCopy];
你的 methodToAddImages 看起来像:
- (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]];
我不知道您使用的是 ARC 还是 Manual Retain Release,但此答案是假设 ARC 编写的(基于您问题中的代码)。
【讨论】:
【参考方案2】:您可以使用dispatch_after 调度一个块,异步执行以添加图像。示例:
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];
);
【讨论】:
试过了,我认为它会工作,但它只是在延迟后同时添加所有图像。有什么想法吗? @SarabyteStudios 你说得对,我忘了任何视图都应该只在主线程上更新。所以我编辑了块中的最后一行代码,以确保添加子视图的方法在主线程上执行。【参考方案3】:将您的代码分成一个函数,并通过NSTimer
调用。
for (int i = 0; numberOfImages; i++)
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5
target:self
selector:@selector(showImage)
userInfo:[NSNumber numberWithInt:i]
repeats:NO];
然后是你的函数:
-(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
是一种将参数传递给您需要调用的函数的便捷方式(但它们必须是对象)。此外,通过使用repeats:NO
,您不必担心会使计时器失效,也不会有让计时器在内存中运行的风险。
【讨论】:
由于您使用的是 showImage: 并递增 intValue,因此这里的初始循环似乎是多余的。没有它,这项技术也可以工作。 另外“selector:@selector(showImage)”实际上应该是“selector:@selector(showImage:)”【参考方案4】:这也是最好的选择。试试这个
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:5.0]];
【讨论】:
您能否准确解释一下为什么最好按照您的方式实施时间延迟? @XLE_22 SRunLoop 更好,因为它允许NSRunLoop
在您等待时响应事件。【参考方案5】:
我觉得你最好用动画
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];
不完全符合您的要求,因为所有视图都会立即添加,然后淡入,但我觉得您实际上正在尝试实现这一点,就像某种图像堆叠,对吧?
其实,如果你打算移除之前的图片,你可以在完成块中进行,像这样:
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;
【讨论】:
虽然这不会创建 5 秒的时间间隔 @Rakesh 实际上,我将延迟写为可变的 (5.0*i
)。
哎呀.. 我读它为 0.2*i。没关系。为“不明显”的解决方案 +1 :)
我想我实际上是在您评论时编辑问题,在此之前我添加了 0.2 以在我的模拟器上进行测试。
哦。好的。我实际上在想我如何看待它。 :)以上是关于如何为循环添加延迟?的主要内容,如果未能解决你的问题,请参考以下文章