Skip to content

Fix CALayerInvalidGeometry crash when reparenting views on iPadOS 27 - #25

Merged
antonsoderdahl merged 1 commit into
masterfrom
fix/coordinate-conversion-nan-crash
Oct 9, 2026
Merged

antonsoderdahl merged 1 commit into
masterfrom
fix/coordinate-conversion-nan-crash

Conversation

@Jacobfredrikssonbonnier

Copy link
Copy Markdown
Contributor

Problem

Crashlytics shows CALayerInvalidGeometry in LayoutArrangement.makeSubviews → UITextView.setFrame: on iPads running iPadOS 27 only.

LayoutArrangement.addSubview(_:maintainCoordinates:) converts the reparented view's frame to and from UIScreen.main.fixedCoordinateSpace. On iPadOS 27 a window that is not full screen (resized at runtime, or launched inside a Stage Manager window) gets a window scene whose screen is not UIScreen.main. Converting between the two unrelated screens returns (inf, inf, 0, 0), and assigning that as a frame throws.

Measured with a probe app on the iPadOS 27 simulator: the state persists for the whole process lifetime (survives taps and background/foreground), and with Stage Manager on it is present from launch, which matches the same device crashing twice within 100 s in Crashlytics. convert(_, to: nil) returns the correct rect in the same state.

Fix

  • UIKitSupport.swift: convert via the window (to: nil / from: nil) instead of UIScreen.main, which has also been deprecated since iOS 16. Views reparented by an arrangement always share a window.
  • LayoutArrangement.swift: skip the frame assignment when the converted rect has non-finite components. The arrangement's real frame is applied by Animation.apply() right after anyway.

Verification

  • Package builds for the iOS simulator; Expressen builds against this branch via a local package override on iPad Air 13-inch (iOS 27.0).
  • Probe app on the iPadOS 27 simulator: window-relative conversion stays finite in every window state where the screen-based one returned infinity.

Release

Tag 10.0.11 after merge, then bump exactVersion and Package.resolved in iphoneshell.

🤖 Generated with Claude Code

`LayoutArrangement.addSubview(_:maintainCoordinates:)` converted the reparented
view's frame to and from `UIScreen.main.fixedCoordinateSpace`. On iPadOS 27 a
window that is not full screen (resized at runtime, or launched inside a Stage
Manager window) gets a window scene whose `screen` is not `UIScreen.main`, and
converting between the two unrelated screens returns `(inf, inf, 0, 0)`.
Assigning that frame throws `CALayerInvalidGeometry`, which Crashlytics shows
on iPad / iPadOS 27 only.

Convert via the window instead (`convert(_, to: nil)`); views reparented by an
arrangement always share a window. Also skip the frame assignment when the
converted rect has non-finite components, so the arrangement's real frame from
`Animation.apply()` wins instead of crashing.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@antonsoderdahl antonsoderdahl left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you say so. Känns inte som jag har så starka åsikter om kodkvalitén på layoutkit här så funkar det så kör. ;)

@antonsoderdahl
antonsoderdahl merged commit bc1c5e7 into master Oct 9, 2026
3 of 4 checks passed
Sign up for free to 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.

2 participants