Repository: Automattic/pocket-casts-ios
File: podcasts/WatchManager.swift (Swift)

Code before:
    @objc private func upNextChanged() {
        sendStateToWatchInBackground()
    }

    @objc private func playbackStateChanged() {
        sendStateToWatchInBackground()
    }

    @objc private func episodeStarredChanged(_ notification: Notification) {
        guard let uuid = notification.object as? String, PlaybackManager.shared.queue.contains(episodeUuid: uuid) else { return }

        // currently the watch only needs to know if the starred status of something in Up Next changes
        sendStateToWatchInBackground()
    }

    @objc private func autoDownloadChanged() {
        sendStateToWatchInBackground()
    }

    private func sendStateToWatchInBackground() {
        guard Thread.isMainThread else {
            sendStateToWatch()
            return
        }
        DispatchQueue.global(qos: .background).async { [weak self] in
            self?.sendStateToWatch()
            if FeatureFlag.refreshAndSaveWatchLogsOnSend.enabled {
                FileLog.shared.addMessage("WatchManager: Start log request on send")
                WatchManager.shared.requestLogFile(completion: { _ in
                    // We don't do anything with the log, requesting it will cache and save the contents
                    FileLog.shared.addMessage("WatchManager: Completed log request on send")
                })
            }
        }
    }

    private func sendStateToWatch() {
        guard WCSession.isSupported() else { return }

        let session = WCSession.default

        // only send data when we have a valid connection
        guard session.activationState == .activated,
              session.isPaired,
              session.isWatchAppInstalled
        else {
            return
        }

        var applicationDict = [String: Any]()
        applicationDict[WatchConstants.Keys.messageVersion] = WatchConstants.Values.messageVersion

Review comment (bug):
This was the main cause of the crash. `sendStateToWatch` was already effectively checking the optional value but the lower value was not and I think this caused a crash while `WatchManager` is being deallocated.

Code after:
    @objc private func upNextChanged() {
        sendStateToWatchInBackground()
    }

    @objc private func playbackStateChanged() {
        sendStateToWatchInBackground()
    }

    @objc private func episodeStarredChanged(_ notification: Notification) {
        guard let uuid = notification.object as? String, PlaybackManager.shared.queue.contains(episodeUuid: uuid) else { return }

        // currently the watch only needs to know if the starred status of something in Up Next changes
        sendStateToWatchInBackground()
    }

    @objc private func autoDownloadChanged() {
        sendStateToWatchInBackground()
    }

    private func sendStateToWatchInBackground() {
        guard Thread.isMainThread else {
            sendStateToWatch()
            return
        }
        DispatchQueue.global(qos: .background).async { [weak self] in
            guard let self else { return }
            sendStateToWatch()
            if FeatureFlag.refreshAndSaveWatchLogsOnSend.enabled {
                FileLog.shared.addMessage("WatchManager: Start log request on send")
                requestLogFile(completion: { _ in
                    // We don't do anything with the log, requesting it will cache and save the contents
                    FileLog.shared.addMessage("WatchManager: Completed log request on send")
                })
            }
        }
    }

    private func sendStateToWatch() {
        guard WCSession.isSupported() else { return }

        let session = WCSession.default

        // only send data when we have a valid connection
        guard session.activationState == .activated,
              session.isPaired,
              session.isWatchAppInstalled
        else {
            return
        }

        var applicationDict = [String: Any]()