Fix a crash on macOS when using QuickLook. (#5790)

Introduced by the default @MainActor isolation and macOS being weird with threads.
This commit is contained in:
Doug
2026-06-24 18:34:45 +01:00
committed by GitHub
parent 3c5c1c62e3
commit 605ccc6be7
4 changed files with 29 additions and 15 deletions
@@ -153,11 +153,11 @@ private struct MediaPreviewViewController: UIViewControllerRepresentable {
class MediaPreviewItem: NSObject, QLPreviewItem { class MediaPreviewItem: NSObject, QLPreviewItem {
let file: MediaFileHandleProxy let file: MediaFileHandleProxy
var previewItemURL: URL? { nonisolated var previewItemURL: URL? { // nonisolated as QuickLook can call from any thread (macOS 26).
file.url file.url
} }
let previewItemTitle: String? nonisolated let previewItemTitle: String? // nonisolated as QuickLook can call from any thread (macOS 26).
init(file: MediaFileHandleProxy, title: String?) { init(file: MediaFileHandleProxy, title: String?) {
self.file = file self.file = file
@@ -9,6 +9,7 @@
import Combine import Combine
import Foundation import Foundation
import QuickLook import QuickLook
import Synchronization
/// A dedicated data source for QLPreviewController to support timeline updates. This was added to /// A dedicated data source for QLPreviewController to support timeline updates. This was added to
/// workaround the fact that calling `reloadData` on the controller **always** reloads the current /// workaround the fact that calling `reloadData` on the controller **always** reloads the current
@@ -147,8 +148,14 @@ enum TimelineMediaPreviewItem: Equatable {
/// Wraps a media file and title to be previewed with QuickLook. /// Wraps a media file and title to be previewed with QuickLook.
@Observable class Media: NSObject, QLPreviewItem, Identifiable { @Observable class Media: NSObject, QLPreviewItem, Identifiable {
fileprivate(set) var timelineItem: EventBasedMessageTimelineItemProtocol fileprivate(set) var timelineItem: EventBasedMessageTimelineItemProtocol {
var fileHandle: MediaFileHandleProxy? didSet { updatePreviewItemValues() }
}
var fileHandle: MediaFileHandleProxy? {
didSet { updatePreviewItemValues() }
}
var downloadError: Error? var downloadError: Error?
init(timelineItem: EventBasedMessageTimelineItemProtocol) { init(timelineItem: EventBasedMessageTimelineItemProtocol) {
@@ -184,15 +191,22 @@ enum TimelineMediaPreviewItem: Equatable {
// MARK: QLPreviewItem // MARK: QLPreviewItem
var previewItemURL: URL? { private let _previewItemURL = Mutex<URL?>(nil)
fileHandle?.url nonisolated var previewItemURL: URL? { // nonisolated as QuickLook can call from any thread (macOS 26).
_previewItemURL.withLock { $0 }
} }
var previewItemTitle: String? { private let _previewItemTitle = Mutex<String?>(" ")
switch fileHandle?.url { nonisolated var previewItemTitle: String? { // nonisolated as QuickLook can call from any thread (macOS 26).
case .some: filename _previewItemTitle.withLock { $0 }
case .none: " " // Don't show any background text when the preview is still loading. }
}
private func updatePreviewItemValues() {
let url = fileHandle?.url
_previewItemURL.withLock { $0 = url }
// Don't show any background text (" ") while the preview is still loading.
_previewItemTitle.withLock { $0 = url == nil ? " " : filename }
} }
// MARK: Event details // MARK: Event details
@@ -63,8 +63,8 @@ private struct PreviewView: UIViewControllerRepresentable {
} }
private class PreviewItem: NSObject, QLPreviewItem { private class PreviewItem: NSObject, QLPreviewItem {
var previewItemURL: URL? nonisolated let previewItemURL: URL? // nonisolated as QuickLook can call from any thread (macOS 26).
var previewItemTitle: String? nonisolated let previewItemTitle: String? // nonisolated as QuickLook can call from any thread (macOS 26).
init(previewItemURL: URL?, previewItemTitle: String?) { init(previewItemURL: URL?, previewItemTitle: String?) {
self.previewItemURL = previewItemURL self.previewItemURL = previewItemURL
@@ -289,8 +289,8 @@ private struct PreviewView: UIViewControllerRepresentable {
} }
private class PreviewItem: NSObject, QLPreviewItem { private class PreviewItem: NSObject, QLPreviewItem {
var previewItemURL: URL? nonisolated let previewItemURL: URL? // nonisolated as QuickLook can call from any thread (macOS 26).
var previewItemTitle: String? nonisolated let previewItemTitle: String? // nonisolated as QuickLook can call from any thread (macOS 26).
init(previewItemURL: URL?, previewItemTitle: String?) { init(previewItemURL: URL?, previewItemTitle: String?) {
self.previewItemURL = previewItemURL self.previewItemURL = previewItemURL