我想在我的iOS应用上显示一个3.2.1倒计时(在拍照之前),但我没有找到一个优雅的解决方案。我不想用NSTimer制作一个倒计时应用程序。对我来说,重要的是将所有代码保持在相同的方法中,使用像块这样的系统。
self.infoLabel.text = [NSString stringWithFormat:@"3"];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.infoLabel.text = [NSString stringWithFormat:@"2"];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.infoLabel.text = [NSString stringWithFormat:@"1"];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.infoLabel.hidden = YES;
// DO WHAT I WANT AFTER 3 SECs
});
});
});
});你有更好的解决方案吗?T工作正常,但它并不像我以前那样优雅地连接到dispatch_after上。
发布于 2015-04-19 15:56:19
在任何类型的计时器中,每一个“滴答”都是以前的“滴答”的度量,其问题是,在软件中,这些“滴答”并不一定是精确的。这意味着,如果你的第一个滴答是十分之一秒,剩下的每一个滴答将以这个数量或更多。你的第二个滴答是根据你的第一个滴答排定的。这意味着通过的总时间的实际数量是准确的,而且你拥有的时间越多,你的总时间就越容易出错。
因此,首先,我想向您展示倒计时对象类可能是什么样子。那我来看看我们怎么用这个。
typedef void (^CRCountdownCompletion)(void);
@interface CRCountdown : NSObject
- (void)startCountdownWithInterval:(NSTimeInterval)interval
ticks:(NSUInteger)ticks
completion:(CRCountdownCompletion)completion;
@property (readonly) NSUInteger ticksRemaining;
@property (readonly) NSTimeInterval interval;
@end@interface CRCountdown()
@property NSTimer *timer;
@property (readwrite) NSTimeInterval interval;
@property (copy) CRCountdownCompletion completion;
@end
@implementation CRCountdown
- (void)startCountdownWithInterval:(NSTimeInterval)interval ticks:(NSUInteger)ticks completion:(CRCountdownCompletion)completion {
self.completion = completion;
self.interval = interval;
self.timer = [NSTimer scheduledTimerWithTimeInterval:(interval * ticks) target:self selector:@selector(countdownComplete:) userInfo:nil repeats:NO];
}
- (void)stopCountdown {
[self.timer invalidate];
}
- (NSUInteger)ticksRemaining {
if (self.timer.isValid) {
NSTimeInterval timeRemaining = [self.timer.fireDate timeIntervalSinceDate:[NSDate date]];
return timeRemaining / self.interval;
} else {
return 0;
}
}
- (void)countdownComplete:(NSTimer *)timer {
if (self.completion) {
self.completion();
}
}
@end现在,这将保证我们的完成事件发生在尽可能准确的时间。我们仍然不能保证它将精确地发生在特定的时刻,但是由于消除了为我们的每一个“更新滴答”增加错误的可能性,错误的范围被大大地减小了。
相反,我们设置了一个重复的NSTimer,负责调用一些代码来更新UI。这个UI更新代码可以查看ticksRemaining (如果有必要的话,将其乘以interval),以确定它应该更新UI来表示什么。
甚至不需要为completion参数传递任何内容,因为我们感兴趣的对象已经在轮询ticksRemaining,因此每当返回0时,我们都知道计时器是完整的(无论如何都是完整的)。
但是,我们可以在Countdown对象上更进一步,并提供一种方法来包含一个update块,如果我们愿意的话,这个块会在每一个滴答上触发。然而,对于这一点,我们想要两位NSTimer的S继续前进。
首先,在我们的标题中,让我们添加另一个块ty对联f:
typedef void (^CRCountdownUpdate)(NSUInteger);我们还需要更改我们的startCountdown...方法以接受这种类型的参数:
- (void)startCountdownWithInterval:(NSTimerInterval)interval
ticks:(NSUInteger)ticks
update:(CRCountdownUpdate)update
completion:(CRCountdownCompletion)completion;这意味着在.m中再添加两个属性,一个updateTimer (NSTimer *)和一个CRCountdownUpdate:
@property NSTimer *updateTimer;
@property (copy) CRCountdownUpdate update;我们需要修改我们的countdownComplete:方法,这样它就会使updateTimer失效(所以update永远不会在完成后触发):
- (void)countdownComplete:(NSTimer *)timer {
[self.updateTimer invalidate];
if (self.completion) {
self.completion();
}
}并添加一个更新方法来处理更新刻度:
- (void)countdownUpdate:(NSTimer *)timer {
if (self.update) {
self.update(self.ticksRemaining);
}
}最后一步是修改我们的startCountdown...方法,以匹配我们更新头部的方式,并负责设置update计时器:
- (void)startCountdownWithInterval:(NSTimeInterval)interval ticks:(NSUInteger)ticks completion:(CRCountdownCompletion)completion update:(CRCountdownUpdate)update {
self.completion = completion;
self.update = update;
self.interval = interval;
self.timer = [NSTimer scheduledTimerWithTimeInterval:(interval * ticks) target:self selector:@selector(countdownComplete:) userInfo:nil repeats:NO];
if (self.update) {
self.updateTimer = [NSTimer scheduledTimerWithTimeInterval:interval target:self selector:@selector(countdownUpdate:) userInfo:nil repeats:YES];
}
}现在,使用这个对象非常简单:
CRCountdownUpdate update = ^(NSUInteger ticks) {
self.infoLabel.text = [NSString stringWithFormat:@"%lu", (unsigned long)ticks];
};
CRCountdownCompletion completion = ^{
self.infoLabel.hidden = YES;
// do whatever else you want
};
CRCountdown *countdown = [[CRCountdown alloc] init];
[countdown startCountdownWithInterval:1.0
ticks:3
update:update
completion:completion];我建议的这个课程的最终版本如下所示:
typedef void (^CRCountdownCompletion)(void);
typedef void (^CRCountdownUpdate)(NSUInteger);
@interface CRCountdown : NSObject
- (void)startCountdownWithInterval:(NSTimeInterval)interval ticks:(NSUInteger)ticks completion:(CRCountdownCompletion)completion update:(CRCountdownUpdate)update;
@property (readonly) NSUInteger ticksRemaining;
@property (readonly) NSTimeInterval interval;
@end@interface CRCountdown()
@property NSTimer *timer;
@property NSTimer *updateTimer;
@property (readwrite) NSTimeInterval interval;
@property (copy) CRCountdownCompletion completion;
@property (copy) CRCountdownUpdate update;
@end
@implementation CRCountdown
- (void)startCountdownWithInterval:(NSTimeInterval)interval ticks:(NSUInteger)ticks completion:(CRCountdownCompletion)completion update:(CRCountdownUpdate)update {
self.completion = completion;
self.update = update;
self.interval = interval;
self.timer = [NSTimer scheduledTimerWithTimeInterval:(interval * ticks) target:self selector:@selector(countdownComplete:) userInfo:nil repeats:NO];
if (self.update) {
self.updateTimer = [NSTimer scheduledTimerWithTimeInterval:interval target:self selector:@selector(countdownUpdate:) userInfo:nil repeats:YES];
}
}
- (void)stopCountdown {
[self.updateTimer invalidate];
[self.timer invalidate];
}
- (NSUInteger)ticksRemaining {
if (self.timer.isValid) {
NSTimeInterval timeRemaining = [self.timer.fireDate timeIntervalSinceDate:[NSDate date]];
return timeRemaining / self.interval;
} else {
return 0;
}
}
- (void)countdownUpdate:(NSTimer *)timer {
if (self.update) {
self.update(self.ticksRemaining);
NSString *s = [NSString stringWithFormat:@"%lu", (unsigned long)self.ticksRemaining];
}
}
- (void)countdownComplete:(NSTimer *)timer {
[self.updateTimer invalidate];
if (self.completion) {
self.completion();
}
self.update = nil;
self.completion = nil;
}
@end当然,也可以通过授权而不是阻止来做到这一点,这可能是一种适当的做法。
我已经用基于块和基于委托的方法创建了一个github回购。可以找到这里。
发布于 2015-06-04 13:07:36
self.infoLabel.text = [NSString stringWithFormat:@"3"];
[self performSelector:@selector(countDownMethod) withObject:nil afterDelay:1.0];的方法中执行和更改文本
-(void)countDownMethod{
if([self.infoLabel.text isEqualToString:@"3"]){
self.infoLabel.text = [NSString stringWithFormat:@"2"];
[self performSelector:@selector(countDownMethod) withObject:nil afterDelay:1.0];
}else if([self.infoLabel.text isEqualToString:@"2"]){
self.infoLabel.text = [NSString stringWithFormat:@"1"];
[self performSelector:@selector(countDownMethod) withObject:nil afterDelay:1.0];
}else{
self.infoLabel.hidden = YES;
}
}https://codereview.stackexchange.com/questions/87169
复制相似问题