我有一个UILabel,我想显示当前时间(HH:mm)(与状态栏中的时间相同)。
如何更新标签以更改为新时间?如果我安排一个间隔为60秒的NSTimer,那么如果计时器在系统时间分钟改变之前触发,那么标签可能会超时一分钟吗?
将计时器的间隔设置为1秒是否可以,或者是否会使用超过必要的资源?或者是否有另一种方法可以确保标签与状态栏时钟保持同步(最好是完全正确,但1秒背风方式可以)?
答案 0 :(得分:5)
派遣是你的朋友:
void runBlockEveryMinute(dispatch_block_t block)
{
block(); // initial block call
// get the current time
struct timespec startPopTime;
gettimeofday((struct timeval *) &startPopTime, NULL);
// trim the time
startPopTime.tv_sec -= (startPopTime.tv_sec % 60);
startPopTime.tv_sec += 60;
dispatch_time_t time = dispatch_walltime(&startPopTime, 0);
__block dispatch_block_t afterBlock = ^(void) {
block();
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 60), dispatch_get_main_queue(), afterBlock);
};
dispatch_after(time, dispatch_get_main_queue(), afterBlock); // start the 'timer' going
}
这将同步到纳秒,并且只在分钟改变时调用。我相信这是适合您情况的最佳解决方案。
答案 1 :(得分:1)
将定时器的间隔设置为1秒是否可以,或者将其设置为1秒 使用超过必要的资源?
取决于您正在做什么。如果您正在计算pi的前一百万个数字,或者渲染数百个3-D对象,那么您需要每个处理器周期都可以节省。如果CPU大部分时间处于空闲状态,您也可以使用这些周期使界面看起来不错。
答案 2 :(得分:1)
//Create a timer...
timer = [NSTimer scheduledTimerWithTimeInterval:0.25
target:self
selector:@selector(tick:)
userInfo:NULL
repeats:YES];
//Function to update time
- (void)tick:(NSTimer*)t
{
NSDate *now = [NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"HH:mm:ss"];
NSString *timeString = [dateFormatter stringFromDate:now];
[uilabel setText:timeString];
}
您的计时器将始终“延迟”一段时间,因为没有“委托”功能可以调用来制作此类功能。
我会坚持使用计时器,但是提到的Richard J. Ross III也是有效的。
答案 3 :(得分:0)
我想我会在后台线程中运行NSTimer,延迟时间为1秒,让它运行的方法检查当前时间(HH:mm)到标签中显示的当前时间。如果它匹配扔掉它,如果是新的,请更新标签。
如果您担心性能问题,在第一次返回后,找出距离下一分钟的秒数,并让它运行计时器运行那么长时间。然后在第一次更新后,计时器以60秒的间隔运行。
答案 4 :(得分:0)
一秒钟是正确的答案。
答案 5 :(得分:0)
也许你可以设置两个计时器。第一个(触发一次)用于使第二个计时器与60s的间隔同步,这使得它在系统时间到达HH:00时被触发;
答案 6 :(得分:0)
没有gettimeofday或块的第二次精度同步更新。
弱指针和dispatch_async
会阻止保留周期。
- (void)updateTimeLabel
{
if (!timeFormatter) {
timeFormatter = [NSDateFormatter new];
timeFormatter.dateStyle = NSDateFormatterNoStyle;
timeFormatter.timeStyle = NSDateFormatterShortStyle;
}
NSDate *currentTime = [NSDate date];
NSTimeInterval delay = [[currentTime nextMinute] timeIntervalSinceDate:currentTime];
timeLabel.text = [timeFormatter stringFromDate:currentTime];
__weak id weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf performSelector:@selector(updateTimeLabel) withObject:nil afterDelay:delay];
});
}
下一分钟0秒。
@implementation NSDate (Utils)
- (NSDate *)nextMinute {
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *comps = [calendar components:(NSCalendarUnit) NSUIntegerMax fromDate:self];
comps.minute += 1;
comps.second = 0;
return [calendar dateFromComponents:comps];
}
@end
我认为在理查德的答案中存在一个带阻塞的保留周期(可以用__weak + dispatch_async修复)