Objective-c NSTimer,使用 timeInterval 0.01 更新 UILabel 导致应用冻结
Objective-c NSTimer, updating UILabel with timeInterval 0.01 causes app froze
#import "ActivityViewController.h"
@interface ActivityViewController ()
@property (weak, nonatomic) IBOutlet UIView *clockView;
@property (weak , nonatomic) NSTimer *timer;
@property (weak, nonatomic) IBOutlet UILabel *hoursLabel;
@property (weak, nonatomic) IBOutlet UILabel *minutesLabel;
@property (weak, nonatomic) IBOutlet UILabel *secondsLabel;
@property (weak, nonatomic) IBOutlet UILabel *miliLabel;
@end
@implementation ActivityViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
NSDate *start;
- (IBAction)pause:(UIButton *)sender {
[self.timer invalidate];
}
-(void)startTimer {
start = [[NSDate alloc] init];
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(count) userInfo:nil repeats:true];
}
- (IBAction)startCounting:(UIButton *)sender {
[self startTimer];
}
-(void)count {
NSDate *now = [[NSDate alloc] init];
NSTimeInterval interval = [now timeIntervalSinceDate:start];
self.hoursLabel.text = [NSString stringWithFormat:@"%@", [self hourString:interval]];
self.minutesLabel.text = [NSString stringWithFormat:@"%@", [self minuteString:interval]];
self.secondsLabel.text = [NSString stringWithFormat:@"%@", [self secondString:interval]];
self.miliLabel.text = [NSString stringWithFormat:@"%@", [self miliString:interval]];
}
-(NSString *)hourString:(NSTimeInterval)timeInterval {
NSInteger interval = timeInterval;
long hours = (interval / 3600);
return [NSString stringWithFormat:@"%0.2ld", hours];
}
-(NSString *)minuteString:(NSTimeInterval)timeInterval {
NSInteger interval = timeInterval;
long minutes = (interval / 60) % 60;
return [NSString stringWithFormat:@"%0.2ld", minutes];
}
-(NSString *)secondString:(NSTimeInterval)timeInterval {
NSInteger interval = timeInterval;
long seconds = interval % 60;
return [NSString stringWithFormat:@"%0.2ld", seconds];
}
-(NSString *)miliString:(NSTimeInterval)timeInterval {
NSInteger ms = (fmod(timeInterval, 1) * 100);
return [NSString stringWithFormat:@"%0.2ld", ms];
}
@end
这是我对视图控制器的整个实现
我尝试制作秒表,但是当我尝试在 objective-C 中制作时,更新 UI 以毫秒为单位在 3 秒后变慢,并在 6 秒后冻结模拟器和计算机。有什么解决办法吗?在 swift 中,它工作得非常顺利,但是当涉及到 obj-c 时,我遇到了问题。
有几件事……你在主队列上分派,但你已经在主队列上了,所以你淹没了主队列。另外,你分派异步,所以我认为队列很快就会被阻塞。我仍然认为硬件应该能够实际处理它,所以我不完全确定它为什么会冻结,但我认为你需要做得更好。
此外,重要的是,如果您制作秒表,您不应该计算自己。当然,可以使用计时器定期更新秒表,但与其自己数,不如使用挂钟计时。你现在做的方式会很不准确,而且随着时间的推移,不准确度会累积。
目前你每 10 毫秒发射一次。也许每 100 次触发一次,然后更新您的秒表,但从设备的内部时钟读取。这本身就是有问题的,请参阅 How can I get the Correct Current Time in iOS? 了解如何做到这一点的一些想法。
秒表启动时记下时间,例如
NSDate * start = NSDate.now;
当计时器触发时,使用当前时间计算与此开始时间的差异,再次使用类似
的方法
NSDate * now = NSDate.now;
并用两者之间的差异更新您的秒表。这将更容易和更准确,但请注意 link 因为它还需要一些改进并且现在只是一个起点。
我在最新的 Xcode 中创建了一个新的默认 iOS 项目并复制并粘贴并稍微修复了您的代码 - 见下文。我只是将它连接到 Xcode 作为项目的一部分创建的默认视图控制器。
我 运行 这个是人类已知的最古老的 mac mini,我正在做另一个项目,而 运行 这个是,它一点也不麻烦。请参阅屏幕截图。即使在 5 米之后,它仍然 运行 很好。我继续在其他地方工作没问题,没有放慢速度。我确定这一定是其他有趣的问题?
#import "ViewController.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIView * clockView;
@property (weak, nonatomic) IBOutlet UILabel * hoursLabel;
@property (weak, nonatomic) IBOutlet UILabel * minutesLabel;
@property (weak, nonatomic) IBOutlet UILabel * secondsLabel;
@property (weak, nonatomic) IBOutlet UILabel * miliLabel;
@property (strong, nonatomic) NSTimer * timer;
@property (strong, nonatomic) NSDate * start;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (IBAction)pause:(UIButton *)sender
{
self.timer.invalidate;
}
-(void)startTimer
{
self.start = [[NSDate alloc] init];
self.timer.invalidate;
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.01
target:self
selector:@selector(count:)
userInfo:nil
repeats:true];
}
- (IBAction)startCounting:(UIButton *)sender
{
[self startTimer];
}
- ( void ) count:( NSTimer * ) timer
{
NSDate *now = [[NSDate alloc] init];
NSTimeInterval interval = [now timeIntervalSinceDate:self.start];
self.hoursLabel.text = [NSString stringWithFormat:@"%@", [self hourString:interval]];
self.minutesLabel.text = [NSString stringWithFormat:@"%@", [self minuteString:interval]];
self.secondsLabel.text = [NSString stringWithFormat:@"%@", [self secondString:interval]];
self.miliLabel.text = [NSString stringWithFormat:@"%@", [self miliString:interval]];
}
-(NSString *)hourString:(NSTimeInterval)timeInterval {
NSInteger interval = timeInterval;
long hours = (interval / 3600);
return [NSString stringWithFormat:@"%0.2ld", hours];
}
-(NSString *)minuteString:(NSTimeInterval)timeInterval {
NSInteger interval = timeInterval;
long minutes = (interval / 60) % 60;
return [NSString stringWithFormat:@"%0.2ld", minutes];
}
-(NSString *)secondString:(NSTimeInterval)timeInterval {
NSInteger interval = timeInterval;
long seconds = interval % 60;
return [NSString stringWithFormat:@"%0.2ld", seconds];
}
-(NSString *)miliString:(NSTimeInterval)timeInterval {
NSInteger ms = (fmod(timeInterval, 1) * 100);
return [NSString stringWithFormat:@"%0.2ld", ms];
}
@end
我确定这是其他问题...我假设您的 ActivityViewController
只是直接从正常的 UIViewController
派生而来,并且您的 clockView
没有做任何有趣的事情。
无论如何,看看这是否有帮助,但我认为问题出在其他地方。
#import "ActivityViewController.h"
@interface ActivityViewController ()
@property (weak, nonatomic) IBOutlet UIView *clockView;
@property (weak , nonatomic) NSTimer *timer;
@property (weak, nonatomic) IBOutlet UILabel *hoursLabel;
@property (weak, nonatomic) IBOutlet UILabel *minutesLabel;
@property (weak, nonatomic) IBOutlet UILabel *secondsLabel;
@property (weak, nonatomic) IBOutlet UILabel *miliLabel;
@end
@implementation ActivityViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
NSDate *start;
- (IBAction)pause:(UIButton *)sender {
[self.timer invalidate];
}
-(void)startTimer {
start = [[NSDate alloc] init];
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(count) userInfo:nil repeats:true];
}
- (IBAction)startCounting:(UIButton *)sender {
[self startTimer];
}
-(void)count {
NSDate *now = [[NSDate alloc] init];
NSTimeInterval interval = [now timeIntervalSinceDate:start];
self.hoursLabel.text = [NSString stringWithFormat:@"%@", [self hourString:interval]];
self.minutesLabel.text = [NSString stringWithFormat:@"%@", [self minuteString:interval]];
self.secondsLabel.text = [NSString stringWithFormat:@"%@", [self secondString:interval]];
self.miliLabel.text = [NSString stringWithFormat:@"%@", [self miliString:interval]];
}
-(NSString *)hourString:(NSTimeInterval)timeInterval {
NSInteger interval = timeInterval;
long hours = (interval / 3600);
return [NSString stringWithFormat:@"%0.2ld", hours];
}
-(NSString *)minuteString:(NSTimeInterval)timeInterval {
NSInteger interval = timeInterval;
long minutes = (interval / 60) % 60;
return [NSString stringWithFormat:@"%0.2ld", minutes];
}
-(NSString *)secondString:(NSTimeInterval)timeInterval {
NSInteger interval = timeInterval;
long seconds = interval % 60;
return [NSString stringWithFormat:@"%0.2ld", seconds];
}
-(NSString *)miliString:(NSTimeInterval)timeInterval {
NSInteger ms = (fmod(timeInterval, 1) * 100);
return [NSString stringWithFormat:@"%0.2ld", ms];
}
@end
这是我对视图控制器的整个实现
我尝试制作秒表,但是当我尝试在 objective-C 中制作时,更新 UI 以毫秒为单位在 3 秒后变慢,并在 6 秒后冻结模拟器和计算机。有什么解决办法吗?在 swift 中,它工作得非常顺利,但是当涉及到 obj-c 时,我遇到了问题。
有几件事……你在主队列上分派,但你已经在主队列上了,所以你淹没了主队列。另外,你分派异步,所以我认为队列很快就会被阻塞。我仍然认为硬件应该能够实际处理它,所以我不完全确定它为什么会冻结,但我认为你需要做得更好。
此外,重要的是,如果您制作秒表,您不应该计算自己。当然,可以使用计时器定期更新秒表,但与其自己数,不如使用挂钟计时。你现在做的方式会很不准确,而且随着时间的推移,不准确度会累积。
目前你每 10 毫秒发射一次。也许每 100 次触发一次,然后更新您的秒表,但从设备的内部时钟读取。这本身就是有问题的,请参阅 How can I get the Correct Current Time in iOS? 了解如何做到这一点的一些想法。
秒表启动时记下时间,例如
NSDate * start = NSDate.now;
当计时器触发时,使用当前时间计算与此开始时间的差异,再次使用类似
的方法NSDate * now = NSDate.now;
并用两者之间的差异更新您的秒表。这将更容易和更准确,但请注意 link 因为它还需要一些改进并且现在只是一个起点。
我在最新的 Xcode 中创建了一个新的默认 iOS 项目并复制并粘贴并稍微修复了您的代码 - 见下文。我只是将它连接到 Xcode 作为项目的一部分创建的默认视图控制器。
我 运行 这个是人类已知的最古老的 mac mini,我正在做另一个项目,而 运行 这个是,它一点也不麻烦。请参阅屏幕截图。即使在 5 米之后,它仍然 运行 很好。我继续在其他地方工作没问题,没有放慢速度。我确定这一定是其他有趣的问题?
#import "ViewController.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIView * clockView;
@property (weak, nonatomic) IBOutlet UILabel * hoursLabel;
@property (weak, nonatomic) IBOutlet UILabel * minutesLabel;
@property (weak, nonatomic) IBOutlet UILabel * secondsLabel;
@property (weak, nonatomic) IBOutlet UILabel * miliLabel;
@property (strong, nonatomic) NSTimer * timer;
@property (strong, nonatomic) NSDate * start;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (IBAction)pause:(UIButton *)sender
{
self.timer.invalidate;
}
-(void)startTimer
{
self.start = [[NSDate alloc] init];
self.timer.invalidate;
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.01
target:self
selector:@selector(count:)
userInfo:nil
repeats:true];
}
- (IBAction)startCounting:(UIButton *)sender
{
[self startTimer];
}
- ( void ) count:( NSTimer * ) timer
{
NSDate *now = [[NSDate alloc] init];
NSTimeInterval interval = [now timeIntervalSinceDate:self.start];
self.hoursLabel.text = [NSString stringWithFormat:@"%@", [self hourString:interval]];
self.minutesLabel.text = [NSString stringWithFormat:@"%@", [self minuteString:interval]];
self.secondsLabel.text = [NSString stringWithFormat:@"%@", [self secondString:interval]];
self.miliLabel.text = [NSString stringWithFormat:@"%@", [self miliString:interval]];
}
-(NSString *)hourString:(NSTimeInterval)timeInterval {
NSInteger interval = timeInterval;
long hours = (interval / 3600);
return [NSString stringWithFormat:@"%0.2ld", hours];
}
-(NSString *)minuteString:(NSTimeInterval)timeInterval {
NSInteger interval = timeInterval;
long minutes = (interval / 60) % 60;
return [NSString stringWithFormat:@"%0.2ld", minutes];
}
-(NSString *)secondString:(NSTimeInterval)timeInterval {
NSInteger interval = timeInterval;
long seconds = interval % 60;
return [NSString stringWithFormat:@"%0.2ld", seconds];
}
-(NSString *)miliString:(NSTimeInterval)timeInterval {
NSInteger ms = (fmod(timeInterval, 1) * 100);
return [NSString stringWithFormat:@"%0.2ld", ms];
}
@end
我确定这是其他问题...我假设您的 ActivityViewController
只是直接从正常的 UIViewController
派生而来,并且您的 clockView
没有做任何有趣的事情。
无论如何,看看这是否有帮助,但我认为问题出在其他地方。