Search code examples
iosswifttimermapkitheap-corruption

iOS Timer function heap corruption


So I am new to iOS and am using trying to have a view controller with a timer that periodically updates the UI. The issue that I am seeing is that I am getting heap corruption, more specifically EXC_BAD_ACCESS KERN_INVALID_ADDRESS error that is caused by objc_retain call.

This error is happening in several places but all within my Timer function and higher on the call stack __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION is being called in each case.

I must be missing a reference or not releasing something properly, here is the code

func scheduleTimer() {
    timer = Timer.scheduledTimer(timeInterval: timeInterval, target: self, selector: #selector(self.timerFunc), userInfo: nil, repeats: true)
}

func timerFunc() {
    if let gps = sdlService?.getLatestLocation() {
        let clCoor = CLLocationCoordinate2D(locStruct: gps)
        self.updateLatestDriverIcon(gps: gps, coor: clCoor)
        if isRecording {
            self.addNextPathPoint(coor: clCoor)
        }
        latestCoor = clCoor
    }
}

func updateLatestDriverIcon(gps: LocationStruct, coor: CLLocationCoordinate2D) {
    if latestCoor == nil {
        car = MarkerAnnotation(coordinate: coor, title: carMarker)
        mapView.addAnnotation(car!)
        latestCoor = coor
        mapView.centerOnLatestGPS(animated: false)
        markerView.rotation = MathUtils.wrap(gps.bearing, min: 0, max: 360)
    } else if coor.isDifferent(to: latestCoor!) {
        if isMapFollowingCar {
            mapView.centerOnLatestGPS(animated: false)
        }
        car!.coordinate = coor
        markerView.rotation = MathUtils.wrap(gps.bearing, min: 0, max: 360)
    }
}

Now this timer function is referencing properties of my view controller, as well as a nested function (updateLatestDriverIcon). I have seen crashes on the mapView.centerOnLatestGPS() func, and multiple places within the markerView.rotation call stack all with the same error codes listed above. What am I missing here?

EDIT: Here is a stack trace from crashlytics. I am using events triggered over an external accessory so I can be attached to the debugger: Stack Trace


Solution

  • So after several weeks of tracking this thing down, we found it was due to an animation on a UIView. Not exactly sure why it was throwing errors where it did, if anyone knows why that would be very helpful! Here is some more info on the architecture:

    We had a screen updating a UI at about 10HZ and was driven by a timer using the above code. The animation was done on a UIView subclass that was done off of the main thread which was being rendered into a bitmap context. This was being done at ~30Hz.

    The animation code:

    UIView.animate(
            withDuration: self.animationDuration,
            animations: { self.currentGearValue = actualGearValue },
            completion: { (isComplete) in  /* not sure we need this yet */ })
    

    I haven't tested it but it might be because the animation is overlapped if the previous one isn't finished by the time the next animation gets started.