While testing LetPiano's archive build on Mac, it popped "LetPiano quit unexpectedly." The crash log shows a SIGABRT: SwiftUI changed constraints in the middle of the window's layout pass, AppKit refused, and threw an exception. A simple record of what happened.
SIGABRTSwiftUIAppKit · macOSlog 解讀Log Analysis
📌 一句話結論
這是 Mac 版的本機測試 build(從 Xcode archive 跑的,不是 App Store 上架版)的閃退。log 指向一個 SwiftUI + AppKit 的視窗布局問題:當視窗「正在排版(layout)」的當下,畫面又觸發了一次會去改約束(constraints)的更新,AppKit 不允許這種「邊排版邊改」,於是丟出例外(NSException)、呼叫 abort() 強制結束。這是程式層的 bug,不是 Mac 壞掉;送審的 iOS(iPhone / iPad)版本不受這個影響。
📌 TL;DR
This was a crash in the local Mac test build (run from an Xcode archive, not the App Store version). The log points to a SwiftUI + AppKit window-layout problem: while the window was in the middle of its layout pass, the UI triggered another update that changed constraints. AppKit doesn't allow "changing layout while laying out," so it threw an exception (NSException) and called abort(). It's an app-level bug, not a broken Mac — and the iOS (iPhone / iPad) build under review is unaffected.
I was on a Mac (Mac13,1 / macOS 26.5.1) running LetPiano's archive build 1.0.20260619 for pre-submission testing. About 15 minutes into the session (the log shows launch at 23:15, crash at 23:30), the window suddenly closed and macOS showed the "LetPiano quit unexpectedly" dialog.
Exception Type: EXC_CRASH (SIGABRT), abort() called, on the main thread. SIGABRT usually means "the program deliberately stopped itself" — most often an uncaught exception or a tripped system safety check.
② The key call chain
Read bottom-up, the backtrace tells a clear story:
NSHostingView.windowDidLayout() (SwiftUI hears "the window just finished layout") → invalidateProperties (SwiftUI decides to update some properties) → NSView setNeedsUpdateConstraints (marks "constraints need recomputing") → _postWindowNeedsUpdateConstraints → throws NSException → abort()
③ In plain terms
In the very beat where the window was laying out, SwiftUI turned around and asked to recompute constraints. To AppKit that's re-entrancy during layout — like changing the blueprint mid-construction. It won't accept it, so it throws and aborts.
For reference: the path is …/Xcode/Archives/…/LetPiano.app, so this is a local archive test build, not the App Store download. app.rexcode.letpiano shares one SwiftUI codebase across platforms; this crash surfaced in macOS's NSHostingView (the bridge that hosts SwiftUI inside an AppKit window).
This class of crash is common when SwiftUI runs inside a macOS window. A typical trigger: some state change (a window resize, onAppear, a safe-area/size change) mutates something layout-affecting while layout is still running, creating a "lay out → trigger update → lay out again" loop or re-entrancy.
This single log can't pinpoint the exact line, but the direction is clear: move layout-mutating work out of the layout pass (e.g. defer it to the next runloop, and don't invalidate constraints while the view body is being computed).
3. iOS 送審版照常:這是 Mac target 的偶發布局 crash,iPhone / iPad 版(已送審)走的是 iOS 的 hosting 路徑,不受這條 macOS 專屬的呼叫鏈影響。修好 Mac 後再隨更新一起出。
🛠️ What To Do
✅ Three directions
1. Treat it as a Mac-side layout bug: it happens in the NSHostingView window-layout bridge. Deferring the layout-mutating state change (e.g. wrapping it in DispatchQueue.main.async, or using a more stable layout approach) usually resolves it.
2. Narrow it down: from the backtrace, find recently changed views tied to window size / safe area / animation, and check whether state is mutated synchronously in onAppear or on size changes.
3. The iOS submission is fine: this is an intermittent layout crash on the Mac target. The iPhone / iPad build (already submitted) uses the iOS hosting path and isn't affected by this macOS-specific call chain. Fix the Mac side and ship it in a later update.
Below is the key section (header + exception backtrace). For privacy, Crash Reporter Key and Incident Identifier are redacted. The full thread / image list that follows is unrelated to the cause and omitted.
Method: read from the crash report's Exception Type and Last Exception Backtrace. This is an intermittent layout crash in a macOS archive test build — not a hardware fault, and it doesn't affect the iOS build already submitted.