代码中潜在的内存泄漏
在我正在开发的应用程序中,需要定期轮询设备的数据,如加速度,陀螺仪和运动。 我编写了以下类来处理所有相关任务(我还使用第三方库SOMotionDetector来检测设备是否正在移动。如果只有这样,我调用didReceiveAcceleration
委托方法)。
import CoreMotion import Foundation import SOMotionDetector protocol MotionManagerDelegate: class { func didReceiveAcceleration(_ acceleration: (x: Double, y: Double, z: Double)) func didReceiveGyro(_ gyro: (x: Double, y: Double, z: Double)) func didReceiveMotion(_ motion: (x: Double, y: Double, z: Double, w: Double)) } 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()) { 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 = { motionType in if motionType == MotionTypeNotMoving { self.isMoving = false } else { self.isMoving = true } } motionDetector?.startDetection() motionManager.startAccelerometerUpdates(to: OperationQueue()) { 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()) { 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() } }
这很好用。 但我得到随机崩溃报告,说代码中存在内存泄漏/堆损坏。 由于我无法连接调试器并随着手机上运行的应用程序移动,我无法确定这种情况发生的位置。
我非常感谢任何帮助,找出问题代码可能是什么。 我的上述代码是否容易出现保留周期等问题?
你有self
保留周期。 你在你的积木中强烈地捕捉self
但是self
保留了那些积木和变量。
例:
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.. }) } }
你需要在块的捕获帧中使用weak self
或unowned self
。
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 }) } }
做类似的事情:
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() } }
您可以直接访问块中的self
,这可能会导致保留周期。 尝试使用弱自我:
motionDetector?.motionTypeChangedBlock = { [weak self] motionType in if motionType == MotionTypeNotMoving { self?.isMoving = false } else { self?.isMoving = true } }
其他人阻止了。