Potential memory leak in code

前端 未结 2 614
旧巷少年郎
旧巷少年郎 2021-01-14 13:33

In an app I\'m working on, there is a requirement to periodically poll for device\'s data like acceleration, gyro and motion. I wrote the following class to handle all the r

相关标签:
2条回答
  • 2021-01-14 14:04

    You directly access self in blocks, that may cause retain cycle. Try to use weak self like:

    motionDetector?.motionTypeChangedBlock = { [weak self] motionType in
        if motionType == MotionTypeNotMoving {
            self?.isMoving = false
        } else {
            self?.isMoving = true
        }
    }
    

    So does others blocks.

    0 讨论(0)
  • 2021-01-14 14:07

    You have retain cycles on self. You are capturing self strongly inside your blocks but self is retaining those blocks and variables..

    Example:

    class MotionManager: NSObject {
       override init() {
            super.init()
    
            motionManager = CMMotionManager() //retains motionManager..
        }
    
        func usage() {
            motionManager.execute({ foo in
                self.blah(foo);  //capturing self strongly in motionManager block.. motionManager is retained by self.. retain cycle..
            })
        }
    }
    

    You need to use weak self or unowned self in the block's capture frame.

    class MotionManager: NSObject {
       override init() {
            super.init()
    
            motionManager = CMMotionManager() //retains motionManager..
        }
    
        func usage() {
            motionManager.execute({ [weak self] (foo) in
                self?.blah(foo);  //Doesn't retain self. Fixed :D
            })
        }
    }
    

    Do something like:

    class MotionManager: NSObject {
    
        weak var delegate: MotionManagerDelegate?
    
        fileprivate let motionDetector = SOMotionDetector.sharedInstance()
        fileprivate let accelerationCaptureInterval: TimeInterval = 0.02
        fileprivate let gyroCaptureInterval: TimeInterval = 1
        fileprivate var lastAcceleration: (x: Double, y: Double, z: Double) = (x: 0.0, y: 0.0, z: 0.0)
        fileprivate var isMoving: Bool = false
    
        fileprivate var motionManager: CMMotionManager!
    
    
        override init() {
            super.init()
    
            motionManager = CMMotionManager()
            motionManager.gyroUpdateInterval = gyroCaptureInterval
            motionManager.accelerometerUpdateInterval = accelerationCaptureInterval
            motionManager.deviceMotionUpdateInterval = gyroCaptureInterval
    
            motionDetector?.useM7IfAvailable = true
        }
    
        func startCapturing() throws {
            motionManager.startGyroUpdates(to: OperationQueue()) { [weak self] (gyroData, error) in
                if let rotation = gyroData?.rotationRate {
                    let gyro = (x: rotation.x, y: rotation.y, z: rotation.z)
                    self?.delegate?.didReceiveGyro(gyro)
                } else {
                    let gyro = (x: 0.0, y: 0.0, z: 0.0)
                    self?.delegate?.didReceiveGyro(gyro)
                }
            }
    
            motionDetector?.motionTypeChangedBlock = { [weak self] (motionType) in
                if motionType == MotionTypeNotMoving {
                    self?.isMoving = false
                } else {
                    self?.isMoving = true
                }
            }
    
            motionDetector?.startDetection()
    
            motionManager.startAccelerometerUpdates(to: OperationQueue()) { [weak self] (accelerometerData, error) in
                var x = 0.0
                var y = 0.0
                var z = 0.0
                if let acceleration = accelerometerData?.acceleration {
                    x = acceleration.x
                    y = acceleration.y
                    z = acceleration.z
                }
    
                if (self?.isMoving)! {
                    if let delegate = self?.delegate {
                        delegate.didReceiveAcceleration((x: x, y: y, z: z))
                    }
                }
            }
    
            motionManager.startDeviceMotionUpdates(to: OperationQueue()) { [weak self] (motionData, error) in
                if let quaternion = motionData?.attitude.quaternion {
                    let motion = (x: quaternion.x, y: quaternion.y, z: quaternion.z, w: quaternion.w)
                    self?.delegate?.didReceiveMotion(motion)
                }
            }
        }
    
        func stopCapturing() {
            motionManager.stopGyroUpdates()
            motionManager.stopAccelerometerUpdates()
            motionManager.stopDeviceMotionUpdates()
            motionDetector?.stopDetection()
        }
    }
    
    0 讨论(0)
提交回复
热议问题