fix: Swift 6 strict-concurrency build errors on newer Xcode toolchains#80
fix: Swift 6 strict-concurrency build errors on newer Xcode toolchains#80iOSDevSK wants to merge 1 commit into
Conversation
main does not compile with recent Xcode releases (stricter Swift 6 sendability checking). Minimal fixes, no behavior changes: - nonisolated(unsafe) for the shared CIContext statics in AnnotationDrawing and RedactionImageProcessor - @preconcurrency import ScreenCaptureKit / AVFoundation where non-Sendable SDK results cross isolation boundaries - @sendable download-delegate callbacks in AppUpdater - nonisolated HistoryStore URL/thumbnail accessors (called from detached thumbnail-loading tasks) - @mainactor on the text-view Coordinator in AnnotationItemView - main-actor Task instead of Task.detached for menu bar actions (sending 'screen' data-race errors) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Someone is attempting to deploy a commit to the knox projects Team on Vercel. A member of the Team first needs to authorize it. |
| enum AnnotationDrawing { | ||
|
|
||
| private static let ciContext = CIContext(options: [.cacheIntermediates: false]) | ||
| nonisolated(unsafe) private static let ciContext = CIContext(options: [.cacheIntermediates: false]) |
There was a problem hiding this comment.
Worth adding a one-liner here so future readers know why the unsafe is intentional.
| nonisolated(unsafe) private static let ciContext = CIContext(options: [.cacheIntermediates: false]) | |
| // CIContext is documented as thread-safe; this shared instance is safe to use across tasks. | |
| nonisolated(unsafe) private static let ciContext = CIContext(options: [.cacheIntermediates: false]) |
| return cache | ||
| }() | ||
| private static let ciContext = CIContext(options: [.cacheIntermediates: false]) | ||
| nonisolated(unsafe) private static let ciContext = CIContext(options: [.cacheIntermediates: false]) |
There was a problem hiding this comment.
Same idea here: a short comment helps justify the unsafe and avoids it looking like an arbitrary suppression.
| nonisolated(unsafe) private static let ciContext = CIContext(options: [.cacheIntermediates: false]) | |
| // CIContext is documented as thread-safe; this shared instance is safe to use across tasks. | |
| nonisolated(unsafe) private static let ciContext = CIContext(options: [.cacheIntermediates: false]) |
| } | ||
|
|
||
| func thumbnail(for record: CaptureRecord, maxSize: CGFloat = 120) -> NSImage? { | ||
| nonisolated func thumbnail(for record: CaptureRecord, maxSize: CGFloat = 120) -> NSImage? { |
There was a problem hiding this comment.
urlForRecord / displayURLForRecord being nonisolated makes sense, but I’d be a bit cautious about making the thumbnail generation nonisolated since it constructs NSImage (AppKit).
If you don’t specifically need to do AppKit work off-main, keeping this @MainActor and doing the background work at the call site tends to be safer.
| nonisolated func thumbnail(for record: CaptureRecord, maxSize: CGFloat = 120) -> NSImage? { | |
| func thumbnail(for record: CaptureRecord, maxSize: CGFloat = 120) -> NSImage? { |
| let screen = originScreen | ||
| dismissPopover() | ||
| Task.detached { | ||
| Task { |
There was a problem hiding this comment.
Minor, but making the actor hop explicit here helps keep sendability checking predictable if this action ever stops being main-actor-bound.
| Task { | |
| Task { @MainActor in |
| let onProgress: (Double) -> Void | ||
| var completion: ((Result<URL, Error>) -> Void)? | ||
| let onProgress: @Sendable (Double) -> Void | ||
| nonisolated(unsafe) var completion: (@Sendable (Result<URL, Error>) -> Void)? |
There was a problem hiding this comment.
Since this is now nonisolated(unsafe), it’d help to document the threading assumption (set before resume(), invoked at most once from delegate callbacks). That makes it easier to audit for races later.
| nonisolated(unsafe) var completion: (@Sendable (Result<URL, Error>) -> Void)? | |
| // Set before `resume()` and invoked at most once from URLSession delegate callbacks. | |
| nonisolated(unsafe) var completion: (@Sendable (Result<URL, Error>) -> Void)? |
Problem
maincurrently fails to build with recent Xcode releases — stricter Swift 6 sendability checking turns several patterns into hard errors (12 errors across 8 files), e.g.:Fix
Minimal, mechanical fixes with no behavior changes:
nonisolated(unsafe)for the sharedCIContextstatics inAnnotationDrawingandRedactionImageProcessor(CIContext is documented thread-safe)@preconcurrency importfor ScreenCaptureKit / AVFoundation where non-Sendable SDK results cross isolation boundaries@Sendabledownload-delegate callbacks inAppUpdaternonisolatedHistoryStore URL/thumbnail accessors (called from detached thumbnail-loading tasks)@MainActoron the text-viewCoordinatorinAnnotationItemViewTaskinstead ofTask.detachedfor menu bar actions (the 200 ms delayed capture/recording start doesn't need a background thread)Testing
make releasebuilds clean (Release, Xcode 26 toolchain)🤖 Generated with Claude Code