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 没有做任何有趣的事情。

无论如何,看看这是否有帮助,但我认为问题出在其他地方。