Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS CoreMotion.MotionThread EXC_BAD_ACCESS is thrown after stopDeviceMotionUpdates() is called

I have a view controller that uses CoreMotion to monitor the device's Attitude.

Here is the handler that is used in the call to startDeviceMotionUpdates():

/**
     * Receives device motion updates from Core Motion and uses the attitude of the device to update
     * the position of the attitude tracker inside the bubble level view.
     */
    private func handleAttitude(deviceMotion: CMDeviceMotion?, error: Error?) {
        guard let attitude = deviceMotion?.attitude else {
            GLog.Error(message: "Could not get device attitude.")
            return
        }
        
        // Calculate the current attitude vector
        let roll = attitude.roll
        let pitch = attitude.pitch - optimalAngle
        let magnitude = sqrt(roll * roll + pitch * pitch)
        
        // Drawing can only happen on the main thread
        DispatchQueue.main.async {
            [weak self] in
            
            guard let weakSelf = self else {
                GLog.Log("could not get weak self")
                return
            }
            // Move the bubble in the attitude tracker to match the current attitude
            weakSelf.bubblePosX.constant = CGFloat(roll * weakSelf.attitudeScalar)
            weakSelf.bubblePosY.constant = CGFloat(pitch * weakSelf.attitudeScalar)
            
            // Set the border color based on the current attitude.
            if magnitude < weakSelf.yellowThreshold {
                weakSelf.attitudeView.layer.borderColor = weakSelf.green.cgColor
            } else if magnitude < weakSelf.redThreshold {
                weakSelf.attitudeView.layer.borderColor = weakSelf.yellow.cgColor
            } else {
                weakSelf.attitudeView.layer.borderColor = weakSelf.red.cgColor
            }
            
            // Do the actual drawing
            weakSelf.view.layoutIfNeeded()
        }
    }

I added [weak self] to see if it would fix things, but it has not. This crash is not easy to reproduce.

When I am done the with VC that uses CoreMotion, I call stopDeviceMotionUpdates() in the VC's viewWillDisappear() method. This VC is the only class in the app that imports CoreMotion.

However, when I arrive in the next VC, occasionally I see EXC_BAD_ACCESS getting thrown on a co m.apple.CoreMotion.MotionThread.

MotionThread backtrace

Anybody know why CoreMotion would spawn a thread after the VC that used it has been dismissed? I've verified that the VC is no longer in memory when the crash happens. And yes, the two VCs I'm dealing with are presented modally.

I've examined the memory graph, and when the crash happens, these CoreMotion objects are being reported:

enter image description here

And:

enter image description here

I don't know if those objects should still be in memory after the instance of the CoreMotionManager has been deallocated or not. According to the memory graph, there is no instance of CoreMotionManager in memory.

The VC that imports CoreMotion also imports ARKit. Not sure if some crazy interaction between CoreMotion and ARKit is the problem.

There does seem to be something going on between the main thread and the MotionThread(14):

expanded stack trace

I'm not sure what to make of the main thread stack trace.

Sometimes when the CoreMotion VC is dismissed, I've noticed that there is a lag in the memory it uses getting released. The release always happens eventually.

Thanks to anybody who can help!

like image 261
Budge Avatar asked Aug 30 '25 17:08

Budge


1 Answers

We have a ARSCNView member. We were not calling sceneView.session.pause() when we dismissed the VC that used the sceneView member. One line of code. That was it.

like image 199
Budge Avatar answered Sep 02 '25 07:09

Budge