Reputation: 579
#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
This my whole implementation of the view controller
I try to make a stopwatch, but when I try to make this in objective-C updating UI in miliseconds slows down after 3 seconds and frozes simulator and computer after 6 seconds. Is there any solution? In swift it works very smoothly but when it comes to obj-c I have problem.
Upvotes: 0
Views: 147
Reputation: 3018
I created a new default iOS project in the latest Xcode and copied and pasted and slightly fixed your code - see below. I just wired it up to the default view controller that Xcode creates as part of the project.
I am running this on the oldest mac mini known to man and working on another project while running this one and it gave no trouble at all. See the screenshot. Even after 5m it was still running along just fine. I continued work elsewhere no problem, nothing slowed down. I am sure it must be some other funny issue?
#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
This is some other issue I am sure ... I assume your ActivityViewController
just derives straight from a normal UIViewController
and that your clockView
is not doing anything funny.
Anyhow, see if this helps but I think the issue is elsewhere.
Upvotes: 1
Reputation: 3018
Several things ... you dispatch on the main queue but you are already on the main queue so you are swamping the main queue. Also, you dispatch async so the queue gets clogged pretty soon I think. Still I would think the hardware should be able to handle it actually so I am not entirely sure why it freezes, but I think you need to do it a bit better.
Also, importantly, if you build a stopwatch you should not count yourself. Sure, use a timer to regularly update the stopwatch, but in stead of counting yourself you should use the wall clock for the time. The way you do it now will be very inaccurate and the inaccuracies will accumulate over time.
At present you fire every 10 millis. Maybe fire every 100 and then update your stopwatch but read from the device's internal clock. This in itself is problematic, see How can I get the Correct Current Time in iOS? for some ideas on how to do that.
When the stopwatch starts note the time e.g.
NSDate * start = NSDate.now;
and when the timer fires calculate the difference from this start time using the current time, again with something like
NSDate * now = NSDate.now;
and update your stopwatch with the difference between the two. This will be both easier and more accurate BUT see that link as it is also needs some improvement and is just a starting point for now.
Upvotes: 1