Skip to content

Fix build and two runtime crashes on Xcode 16.4 / Swift 6.1 - #66

Open
danilmezor wants to merge 2 commits into
scier:mainfrom
danilmezor:fix/xcode-16.4-build-and-crashes
Open

Fix build and two runtime crashes on Xcode 16.4 / Swift 6.1#66
danilmezor wants to merge 2 commits into
scier:mainfrom
danilmezor:fix/xcode-16.4-build-and-crashes

Conversation

@danilmezor

Copy link
Copy Markdown

Building the sample app with Xcode 16.4 (Swift 6.1.2) currently fails, and once it builds it crashes on the first rendered frame. Three related fixes, one per commit.

1. Build failure: sending 'self.device' risks causing data races

ProceduralSplatController's async init is nonisolated, so calling it from @MainActor code sends the non-Sendable MTLDevice across an isolation boundary.

Swift 6.2 makes nonisolated async functions run on the caller's actor (nonisolated(nonsending)), which is presumably why this builds for you — but Xcode 16.4 ships Swift 6.1. Adding an isolated (any Actor)? = #isolation parameter gets the same behaviour on 6.1, and keeps the non-isolated VisionSceneRenderer call site working.

2. Crash: actor-isolation trap in the command buffer completion handler

MetalKitSceneRenderer is @MainActor, and MTLCommandBufferHandler is not audited for Sendable in the SDK, so the completion closure is inferred @MainActor-isolated. Metal invokes it on com.Metal.CompletionQueueDispatch, so the Swift 6 runtime executor check fails:

_dispatch_assert_queue_fail
swift_task_isCurrentExecutorWithFlagsImpl
closure #1 in MetalKitSceneRenderer.draw(in:)
-[_MTLCommandBuffer didCompleteWithStartTime:endTime:error:]

This fires on the first rendered frame of any model, so Sample Box, Procedural Splat and a loaded scene all crash identically. Marking the closure @Sendable makes it nonisolated; it only signals a DispatchSemaphore, which is already Sendable.

3. Crash: force-unwrapped Bundle.main.bundleIdentifier

The Logger initialisers force-unwrap Bundle.main.bundleIdentifier, which is nil — the target never sets PRODUCT_BUNDLE_IDENTIFIER and Info.plist has no CFBundleIdentifier, so a macOS build has no identifier at all.

Any log call therefore traps. That includes the error path in draw(in:):

Self.log.error("Unable to render scene: \(error.localizedDescription)")

so a render failure crashed instead of being reported. This sets a bundle identifier and stops force-unwrapping in both renderers.

Testing

Builds clean for macOS and iOS Simulator on Xcode 16.4. Verified against a 9.2M-splat scene on an M1 Pro.

danilmezorand others added 2 commits August 21, 2026 19:19
ProceduralSplatController's async init is nonisolated, so calling it from a
@mainactor context sends the non-Sendable MTLDevice across an isolation
boundary: "sending 'self.device' risks causing data races".
Swift 6.2 makes nonisolated async functions run on the caller's actor
(nonisolated(nonsending)) so this compiles there, but Xcode 16.4 ships
Swift 6.1. An explicit `isolated` parameter defaulted to #isolation gets
the same behaviour on 6.1, and keeps the non-isolated visionOS call site
working too.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pkf6MUWwCwkz9jDjcQ6f4Q
1. Command buffer completion handler trapped on the first rendered frame.
MetalKitSceneRenderer is @mainactor and MTLCommandBufferHandler is not
audited for Sendable, so the closure was inferred @MainActor-isolated.
Metal invokes it on its own completion queue, so the Swift 6 runtime
executor check failed:
dispatch_assert_queue_fail
swift_task_isCurrentExecutorWithFlagsImpl
closure scier#1 in MetalKitSceneRenderer.draw(in:)
-[_MTLCommandBuffer didCompleteWithStartTime:endTime:error:]
Marking the closure @sendable makes it nonisolated. It only signals a
DispatchSemaphore, which is already Sendable.
2. Logger init force-unwrapped Bundle.main.bundleIdentifier, which is nil
because the target never set PRODUCT_BUNDLE_IDENTIFIER and Info.plist
has no CFBundleIdentifier. Any log call trapped -- including the
error path in draw(in:), so a render failure crashed instead of being
reported. Set a bundle identifier and stop force-unwrapping.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pkf6MUWwCwkz9jDjcQ6f4Q
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@danilmezor