Fix memory leak

This commit is contained in:
ronaldheft 2022-09-03 16:34:31 -04:00
parent 836ffddd4f
commit fb8e6408bb
2 changed files with 30 additions and 23 deletions

View file

@ -100,20 +100,21 @@ class AudioPlayer: NSObject {
NSLog("Audioplayer ready") NSLog("Audioplayer ready")
} }
deinit { deinit {
self.stopPausedTimer() self.stopPausedTimer()
self.removeSleepTimer() self.removeSleepTimer()
self.removeTimeObserver() self.removeTimeObserver()
self.queueObserver?.invalidate() self.queueObserver?.invalidate()
self.queueItemStatusObserver?.invalidate() self.queueItemStatusObserver?.invalidate()
destroy()
} }
public func destroy() { public func destroy() {
// Pause is not synchronous causing this error on below lines: // Pause is not synchronous causing this error on below lines:
// AVAudioSession_iOS.mm:1206 Deactivating an audio session that has running I/O. All I/O should be stopped or paused prior to deactivating the audio session // AVAudioSession_iOS.mm:1206 Deactivating an audio session that has running I/O. All I/O should be stopped or paused prior to deactivating the audio session
// It is related to L79 `AVAudioSession.sharedInstance().setActive(false)` // It is related to L79 `AVAudioSession.sharedInstance().setActive(false)`
pause() self.pause()
audioPlayer.replaceCurrentItem(with: nil) self.audioPlayer.replaceCurrentItem(with: nil)
do { do {
try AVAudioSession.sharedInstance().setActive(false) try AVAudioSession.sharedInstance().setActive(false)
@ -125,6 +126,11 @@ class AudioPlayer: NSObject {
DispatchQueue.runOnMainQueue { DispatchQueue.runOnMainQueue {
UIApplication.shared.endReceivingRemoteControlEvents() UIApplication.shared.endReceivingRemoteControlEvents()
} }
// Remove observers
self.audioPlayer.removeObserver(self, forKeyPath: #keyPath(AVPlayer.rate), context: &playerContext)
self.audioPlayer.removeObserver(self, forKeyPath: #keyPath(AVPlayer.currentItem), context: &playerContext)
NotificationCenter.default.post(name: NSNotification.Name(PlayerEvents.closed.rawValue), object: nil) NotificationCenter.default.post(name: NSNotification.Name(PlayerEvents.closed.rawValue), object: nil)
} }
@ -185,7 +191,8 @@ class AudioPlayer: NSObject {
} }
private func setupQueueObserver() { private func setupQueueObserver() {
self.queueObserver = self.audioPlayer.observe(\.currentItem, options: [.new]) {_,_ in self.queueObserver = self.audioPlayer.observe(\.currentItem, options: [.new]) { [weak self] _,_ in
guard let self = self else { return }
let prevTrackIndex = self.currentTrackIndex let prevTrackIndex = self.currentTrackIndex
self.audioPlayer.currentItem.map { item in self.audioPlayer.currentItem.map { item in
self.currentTrackIndex = self.allPlayerItems.firstIndex(of:item) ?? 0 self.currentTrackIndex = self.allPlayerItems.firstIndex(of:item) ?? 0
@ -201,8 +208,8 @@ class AudioPlayer: NSObject {
// Listen for player item updates // Listen for player item updates
self.queueItemStatusObserver?.invalidate() self.queueItemStatusObserver?.invalidate()
self.queueItemStatusObserver = self.audioPlayer.currentItem?.observe(\.status, options: [.new, .old], changeHandler: { playerItem, change in self.queueItemStatusObserver = self.audioPlayer.currentItem?.observe(\.status, options: [.new, .old], changeHandler: { [weak self] playerItem, change in
self.handleQueueItemStatus(playerItem: playerItem) self?.handleQueueItemStatus(playerItem: playerItem)
}) })
// Ensure we didn't miss a player item update during initialization // Ensure we didn't miss a player item update during initialization
@ -486,59 +493,59 @@ class AudioPlayer: NSObject {
let deviceSettings = Database.shared.getDeviceSettings() let deviceSettings = Database.shared.getDeviceSettings()
commandCenter.playCommand.isEnabled = true commandCenter.playCommand.isEnabled = true
commandCenter.playCommand.addTarget { [unowned self] event in commandCenter.playCommand.addTarget { [weak self] event in
play(allowSeekBack: true) self?.play(allowSeekBack: true)
return .success return .success
} }
commandCenter.pauseCommand.isEnabled = true commandCenter.pauseCommand.isEnabled = true
commandCenter.pauseCommand.addTarget { [unowned self] event in commandCenter.pauseCommand.addTarget { [weak self] event in
pause() self?.pause()
return .success return .success
} }
commandCenter.skipForwardCommand.isEnabled = true commandCenter.skipForwardCommand.isEnabled = true
commandCenter.skipForwardCommand.preferredIntervals = [NSNumber(value: deviceSettings.jumpForwardTime)] commandCenter.skipForwardCommand.preferredIntervals = [NSNumber(value: deviceSettings.jumpForwardTime)]
commandCenter.skipForwardCommand.addTarget { [unowned self] event in commandCenter.skipForwardCommand.addTarget { [weak self] event in
guard let command = event.command as? MPSkipIntervalCommand else { guard let command = event.command as? MPSkipIntervalCommand else {
return .noSuchContent return .noSuchContent
} }
guard let currentTime = self.getCurrentTime() else { guard let currentTime = self?.getCurrentTime() else {
return .commandFailed return .commandFailed
} }
seek(currentTime + command.preferredIntervals[0].doubleValue, from: "remote") self?.seek(currentTime + command.preferredIntervals[0].doubleValue, from: "remote")
return .success return .success
} }
commandCenter.skipBackwardCommand.isEnabled = true commandCenter.skipBackwardCommand.isEnabled = true
commandCenter.skipBackwardCommand.preferredIntervals = [NSNumber(value: deviceSettings.jumpBackwardsTime)] commandCenter.skipBackwardCommand.preferredIntervals = [NSNumber(value: deviceSettings.jumpBackwardsTime)]
commandCenter.skipBackwardCommand.addTarget { [unowned self] event in commandCenter.skipBackwardCommand.addTarget { [weak self] event in
guard let command = event.command as? MPSkipIntervalCommand else { guard let command = event.command as? MPSkipIntervalCommand else {
return .noSuchContent return .noSuchContent
} }
guard let currentTime = self.getCurrentTime() else { guard let currentTime = self?.getCurrentTime() else {
return .commandFailed return .commandFailed
} }
seek(currentTime - command.preferredIntervals[0].doubleValue, from: "remote") self?.seek(currentTime - command.preferredIntervals[0].doubleValue, from: "remote")
return .success return .success
} }
commandCenter.changePlaybackPositionCommand.isEnabled = true commandCenter.changePlaybackPositionCommand.isEnabled = true
commandCenter.changePlaybackPositionCommand.addTarget { event in commandCenter.changePlaybackPositionCommand.addTarget { [weak self] event in
guard let event = event as? MPChangePlaybackPositionCommandEvent else { guard let event = event as? MPChangePlaybackPositionCommandEvent else {
return .noSuchContent return .noSuchContent
} }
self.seek(event.positionTime, from: "remote") self?.seek(event.positionTime, from: "remote")
return .success return .success
} }
commandCenter.changePlaybackRateCommand.isEnabled = true commandCenter.changePlaybackRateCommand.isEnabled = true
commandCenter.changePlaybackRateCommand.supportedPlaybackRates = [0.5, 0.75, 1.0, 1.25, 1.5, 2] commandCenter.changePlaybackRateCommand.supportedPlaybackRates = [0.5, 0.75, 1.0, 1.25, 1.5, 2]
commandCenter.changePlaybackRateCommand.addTarget { event in commandCenter.changePlaybackRateCommand.addTarget { [weak self] event in
guard let event = event as? MPChangePlaybackRateCommandEvent else { guard let event = event as? MPChangePlaybackRateCommandEvent else {
return .noSuchContent return .noSuchContent
} }
self.setPlaybackRate(event.playbackRate) self?.setPlaybackRate(event.playbackRate)
return .success return .success
} }
} }

View file

@ -42,9 +42,9 @@ extension AudioPlayer {
self.sleepTimeRemaining = secondsUntilSleep self.sleepTimeRemaining = secondsUntilSleep
DispatchQueue.runOnMainQueue { DispatchQueue.runOnMainQueue {
self.sleepTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in self.sleepTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
if self.isPlaying() { if self?.isPlaying() ?? false {
self.decrementSleepTimerIfRunning() self?.decrementSleepTimerIfRunning()
} }
} }
} }