From a3807faf2da9dec6ec2c09fe1ba2d73bc6b83a1e Mon Sep 17 00:00:00 2001 From: Trey t Date: Mon, 13 Apr 2026 16:19:03 -0500 Subject: [PATCH] Fix speech authorization crash on device from dispatch queue assertion Request authorization off main queue and marshal callback result back via DispatchQueue.main.async. Check current status first to avoid unnecessary system prompt if already authorized or denied. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../Services/PronunciationService.swift | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/Conjuga/Conjuga/Services/PronunciationService.swift b/Conjuga/Conjuga/Services/PronunciationService.swift index 1c42b3e..3b81039 100644 --- a/Conjuga/Conjuga/Services/PronunciationService.swift +++ b/Conjuga/Conjuga/Services/PronunciationService.swift @@ -16,19 +16,29 @@ final class PronunciationService { private var recognizerResolved = false func requestAuthorization() { - // SFSpeechRecognizer.requestAuthorization crashes on simulators - // without speech services. Check availability first. - guard SFSpeechRecognizer.self != nil else { return } - #if targetEnvironment(simulator) print("[PronunciationService] skipping speech auth on simulator") - isAuthorized = false + return #else - print("[PronunciationService] requesting speech authorization...") - SFSpeechRecognizer.requestAuthorization { [weak self] status in - print("[PronunciationService] authorization status: \(status.rawValue)") - Task { @MainActor in - self?.isAuthorized = (status == .authorized) + // Check current status first to avoid unnecessary prompt + let currentStatus = SFSpeechRecognizer.authorizationStatus() + if currentStatus == .authorized { + isAuthorized = true + return + } + if currentStatus == .denied || currentStatus == .restricted { + isAuthorized = false + return + } + + // Only request if not determined yet — do it on a background queue + // to avoid blocking main thread, then update state on main + DispatchQueue.global(qos: .userInitiated).async { + SFSpeechRecognizer.requestAuthorization { status in + DispatchQueue.main.async { [weak self] in + self?.isAuthorized = (status == .authorized) + print("[PronunciationService] authorization status: \(status.rawValue)") + } } } #endif