NSTimer crashes with bad access

2019-08-17 10:04发布

问题:

I have the following method to update a label which show a simple time up

-(void)updateTimeLabel:(NSTimer *)timer{
    NSInteger secondsSinceStart = (NSInteger)[[NSDate date] timeIntervalSinceDate:_startTime];

    NSInteger seconds = secondsSinceStart % 60;
    NSInteger minutes = (secondsSinceStart / 60) % 60;
    NSInteger hours = secondsSinceStart / (60 * 60);
    NSString *result = nil;
    if (hours > 0) {
        result = [NSString stringWithFormat:@"%02d:%02d:%02d", hours, minutes, seconds];
    }
    else {
    result = [NSString stringWithFormat:@"%02d:%02d", minutes, seconds];
    }

    _totalTime = result;
    _totalTimeLabel.text = result;
}

I then call this as the action to a button:

-(IBAction) startTimer{
    _startTime = [NSDate date];
    _walkRouteTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateTimeLabel:) userInfo:nil repeats:YES];
    [_walkRouteTimer fire];
}

But when I run the app I get a bad access error and the app crashes, can anyone help me with this?

Thanks in advance

回答1:

Are you using ARC? If not, _startTime = [NSDate date]; this line will cause your problem. [NSDate date] returned an autorelease object and _startTime will not hold it if you are not using ARC(or using ARC but declared _startTime as weak).

If so, try to add a retain to it

-(IBAction) startTimer{
    //_startTime = [NSDate date]
    _startTime = [[NSDate date] retain];
    _walkRouteTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateTimeLabel:) userInfo:nil repeats:YES];
    [_walkRouteTimer fire];
}

And when you finished your timer, after calling of [_walkRouteTimer invalidate], call [_startTime release].

Or even simpler, if you use property for startTime and declared it as retain. Just use dot notation:

-(IBAction) startTimer{
    //_startTime = [NSDate date]
    self.startTime = [NSDate date];
    _walkRouteTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateTimeLabel:) userInfo:nil repeats:YES];
    [_walkRouteTimer fire];
}
...
//After [_walkRouteTimer invalidate]
self.startTime = nil;


回答2:

Try adding an exception breakpoint to see which line is crashing:

1) Click on the breakpoint tab (second from the right)... kinda looks like a right pointing arrow or "next" button

2) Click on the "+" in the bottom left corner of the tab menu

3) Select "Add Exception Breakpoint"

4) (Optional) Select "Exception" drop down and change to "Objective-C"

5) Select "Done"

6) Run your code again and try to generate the crash... when you do, it will hopefully be caught by this breakpoint, and you'll see which line is crashing and be able to fix it

Good luck