perf(ios): cache ISO-8601 parsers instead of allocating per call#3457
Conversation
caveParseISO() allocated up to two ISO8601DateFormatter instances on every call, and it's invoked per item inside sort/filter/map across the tasks, calendar, reminders and thread lists. ISO8601DateFormatter is comparatively expensive to construct, so this added avoidable churn while scrolling and re-sorting those lists. Hoist the two formatters (fractional + plain) to shared, lazily-initialized instances and reuse them. ISO8601DateFormatter is thread-safe for reads, and behaviour is identical (try fractional, then plain). Verified: xcodebuild build (scheme CovenCave, iOS Simulator) succeeds.
There was a problem hiding this comment.
Pull request overview
This PR improves iOS list scrolling/sorting performance by avoiding repeated ISO8601DateFormatter allocations during ISO-8601 parsing, which is used heavily in per-item sort/filter/map paths across multiple list views.
Changes:
- Hoists two
ISO8601DateFormatterinstances (fractional + plain) into shared cached instances. - Updates
caveParseISO(_:)to reuse the cached formatters instead of allocating new ones per call.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Verification completeReviewed the exact head Validation:
The local WSL worktree does not provide Xcode; the PR author's recorded iOS Simulator |
Summary
Fourth PR in the iOS performance pass. Cuts avoidable allocations in list scrolling/sorting.
Root cause
caveParseISO()allocated up to twoISO8601DateFormatterinstances on every call, and it's called per item insidesorted/filter/mapacross the tasks, calendar, reminders, and thread lists (e.g.FamiliarThreadsViewsort comparator,CalendarViewgrouping).ISO8601DateFormatteris comparatively expensive to construct, so this was avoidable churn during scroll and re-sort.Fix
Hoist the two formatters (fractional + plain) to shared, lazily-initialized module-level instances and reuse them.
ISO8601DateFormatteris thread-safe for reads; parsing behavior is identical (try fractional, then plain).Verification
xcodebuild build(schemeCovenCave, iOS Simulator) → BUILD SUCCEEDED.Blast radius
Tiny — 1 file, pure internal caching. Same inputs/outputs.
Notes
Part of the perf series (#3454 chat render, #3455 stream coalescing, #3456 persist debounce). CI does not build the Swift app; local
xcodebuildis the iOS gate.