claudecode-omc 5.6.6 → 5.6.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.local/skills/THIRD_PARTY_LICENSES/AvdLee-SwiftUI-Agent-Skill.LICENSE +21 -0
- package/.local/skills/THIRD_PARTY_LICENSES/Dimillian-Skills.LICENSE +21 -0
- package/.local/skills/THIRD_PARTY_LICENSES/README.md +36 -0
- package/.local/skills/THIRD_PARTY_LICENSES/twostraws-swiftui-agent-skill.LICENSE +21 -0
- package/.local/skills/h5-to-swiftui/SKILL.md +201 -0
- package/.local/skills/h5-to-swiftui/assets/calibration/README.md +176 -0
- package/.local/skills/h5-to-swiftui/assets/calibration/h5-twin/index.html +52 -0
- package/.local/skills/h5-to-swiftui/assets/calibration/h5-twin/style.css +133 -0
- package/.local/skills/h5-to-swiftui/assets/calibration/swiftui-twin/Package.swift +26 -0
- package/.local/skills/h5-to-swiftui/assets/calibration/swiftui-twin/Sources/CalibrationScreen/CalibrationScreen.swift +142 -0
- package/.local/skills/h5-to-swiftui/assets/calibration/swiftui-twin-divergent/Package.swift +32 -0
- package/.local/skills/h5-to-swiftui/assets/calibration/swiftui-twin-divergent/Sources/CalibrationScreenDivergent/CalibrationScreenDivergent.swift +122 -0
- package/.local/skills/h5-to-swiftui/assets/calibration/tokens.json +42 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/index.html +14 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/package.json +20 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/public/api/articles/001.json +96 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/public/api/articles/index.json +89 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/App.jsx +22 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/App.module.css +11 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/ArticleCard.jsx +53 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/ArticleCard.module.css +139 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/NavBar.jsx +37 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/NavBar.module.css +72 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/TagCloud.jsx +30 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/TagCloud.module.css +50 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/TrendChart.jsx +159 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/TrendChart.module.css +21 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/main.jsx +12 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/screens/ArticleScreen.jsx +182 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/screens/ArticleScreen.module.css +294 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/screens/FeedScreen.jsx +147 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/screens/FeedScreen.module.css +161 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/styles/global.css +50 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/styles/tokens.css +103 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-react/vite.config.js +6 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/data/tasks.js +67 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/index.html +26 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/router.js +73 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/screens/detail.js +164 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/screens/home.js +53 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/screens/list.js +87 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/styles/app.css +342 -0
- package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/styles/tokens.css +68 -0
- package/.local/skills/h5-to-swiftui/references/css-to-swiftui-map.md +205 -0
- package/.local/skills/h5-to-swiftui/references/design-token-extraction.md +209 -0
- package/.local/skills/h5-to-swiftui/references/high-risk-triage.md +209 -0
- package/.local/skills/h5-to-swiftui/references/render-equivalence-calibration.md +193 -0
- package/.local/skills/h5-to-swiftui/references/stack-detection.md +160 -0
- package/.local/skills/h5-to-swiftui/references/visual-diff-loop-protocol.md +365 -0
- package/.local/skills/h5-to-swiftui/scripts/_calib-consts.mjs +150 -0
- package/.local/skills/h5-to-swiftui/scripts/_imglib.mjs +547 -0
- package/.local/skills/h5-to-swiftui/scripts/_provenance.mjs +123 -0
- package/.local/skills/h5-to-swiftui/scripts/calibrate-render.mjs +625 -0
- package/.local/skills/h5-to-swiftui/scripts/capture-reference.mjs +386 -0
- package/.local/skills/h5-to-swiftui/scripts/detect-stack.mjs +305 -0
- package/.local/skills/h5-to-swiftui/scripts/evaluate-convergence.mjs +1093 -0
- package/.local/skills/h5-to-swiftui/scripts/extract-tokens.mjs +600 -0
- package/.local/skills/h5-to-swiftui/scripts/mark-overlay.mjs +379 -0
- package/.local/skills/h5-to-swiftui/scripts/pixel-diff.mjs +530 -0
- package/.local/skills/h5-to-swiftui/scripts/sim-screenshot.sh +544 -0
- package/.local/skills/ios-debugger-agent/SKILL.md +51 -0
- package/.local/skills/ios-debugger-agent/agents/openai.yaml +4 -0
- package/.local/skills/swift-concurrency-expert/SKILL.md +105 -0
- package/.local/skills/swift-concurrency-expert/agents/openai.yaml +4 -0
- package/.local/skills/swift-concurrency-expert/references/approachable-concurrency.md +63 -0
- package/.local/skills/swift-concurrency-expert/references/swift-6-2-concurrency.md +272 -0
- package/.local/skills/swift-concurrency-expert/references/swiftui-concurrency-tour-wwdc.md +33 -0
- package/.local/skills/swiftui-expert-skill/SKILL.md +162 -0
- package/.local/skills/swiftui-expert-skill/references/accessibility-patterns.md +215 -0
- package/.local/skills/swiftui-expert-skill/references/animation-advanced.md +403 -0
- package/.local/skills/swiftui-expert-skill/references/animation-basics.md +284 -0
- package/.local/skills/swiftui-expert-skill/references/animation-transitions.md +326 -0
- package/.local/skills/swiftui-expert-skill/references/charts-accessibility.md +135 -0
- package/.local/skills/swiftui-expert-skill/references/charts.md +602 -0
- package/.local/skills/swiftui-expert-skill/references/focus-patterns.md +299 -0
- package/.local/skills/swiftui-expert-skill/references/image-optimization.md +203 -0
- package/.local/skills/swiftui-expert-skill/references/latest-apis.md +488 -0
- package/.local/skills/swiftui-expert-skill/references/layout-best-practices.md +266 -0
- package/.local/skills/swiftui-expert-skill/references/liquid-glass.md +423 -0
- package/.local/skills/swiftui-expert-skill/references/list-patterns.md +446 -0
- package/.local/skills/swiftui-expert-skill/references/macos-scenes.md +318 -0
- package/.local/skills/swiftui-expert-skill/references/macos-views.md +357 -0
- package/.local/skills/swiftui-expert-skill/references/macos-window-styling.md +303 -0
- package/.local/skills/swiftui-expert-skill/references/performance-patterns.md +403 -0
- package/.local/skills/swiftui-expert-skill/references/scroll-patterns.md +293 -0
- package/.local/skills/swiftui-expert-skill/references/sheet-navigation-patterns.md +363 -0
- package/.local/skills/swiftui-expert-skill/references/state-management.md +388 -0
- package/.local/skills/swiftui-expert-skill/references/text-patterns.md +32 -0
- package/.local/skills/swiftui-expert-skill/references/trace-analysis.md +295 -0
- package/.local/skills/swiftui-expert-skill/references/trace-recording.md +134 -0
- package/.local/skills/swiftui-expert-skill/references/view-structure.md +780 -0
- package/.local/skills/swiftui-expert-skill/scripts/__pycache__/analyze_trace.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/__pycache__/record_trace.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/analyze_trace.py +301 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__init__.py +1 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/__init__.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/causes.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/correlate.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/events.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/hangs.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/hitches.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/summary.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/swiftui.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/time_profiler.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/xctrace.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/xml_utils.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/causes.py +187 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/correlate.py +179 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/events.py +291 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/hangs.py +108 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/hitches.py +145 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/summary.py +243 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/swiftui.py +195 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/time_profiler.py +135 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/xctrace.py +117 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/xml_utils.py +224 -0
- package/.local/skills/swiftui-expert-skill/scripts/record_trace.py +252 -0
- package/.local/skills/swiftui-liquid-glass/SKILL.md +90 -0
- package/.local/skills/swiftui-liquid-glass/agents/openai.yaml +4 -0
- package/.local/skills/swiftui-liquid-glass/references/liquid-glass.md +280 -0
- package/.local/skills/swiftui-performance-audit/SKILL.md +106 -0
- package/.local/skills/swiftui-performance-audit/agents/openai.yaml +4 -0
- package/.local/skills/swiftui-performance-audit/references/code-smells.md +150 -0
- package/.local/skills/swiftui-performance-audit/references/demystify-swiftui-performance-wwdc23.md +46 -0
- package/.local/skills/swiftui-performance-audit/references/optimizing-swiftui-performance-instruments.md +29 -0
- package/.local/skills/swiftui-performance-audit/references/profiling-intake.md +44 -0
- package/.local/skills/swiftui-performance-audit/references/report-template.md +47 -0
- package/.local/skills/swiftui-performance-audit/references/understanding-hangs-in-your-app.md +33 -0
- package/.local/skills/swiftui-performance-audit/references/understanding-improving-swiftui-performance.md +52 -0
- package/.local/skills/swiftui-pro/SKILL.md +108 -0
- package/.local/skills/swiftui-pro/agents/openai.yaml +10 -0
- package/.local/skills/swiftui-pro/assets/swiftui-pro-icon.png +0 -0
- package/.local/skills/swiftui-pro/assets/swiftui-pro-icon.svg +29 -0
- package/.local/skills/swiftui-pro/references/accessibility.md +13 -0
- package/.local/skills/swiftui-pro/references/api.md +39 -0
- package/.local/skills/swiftui-pro/references/data.md +43 -0
- package/.local/skills/swiftui-pro/references/design.md +32 -0
- package/.local/skills/swiftui-pro/references/hygiene.md +9 -0
- package/.local/skills/swiftui-pro/references/navigation.md +14 -0
- package/.local/skills/swiftui-pro/references/performance.md +46 -0
- package/.local/skills/swiftui-pro/references/swift.md +56 -0
- package/.local/skills/swiftui-pro/references/views.md +36 -0
- package/.local/skills/swiftui-ui-patterns/SKILL.md +95 -0
- package/.local/skills/swiftui-ui-patterns/agents/openai.yaml +4 -0
- package/.local/skills/swiftui-ui-patterns/references/app-wiring.md +201 -0
- package/.local/skills/swiftui-ui-patterns/references/async-state.md +96 -0
- package/.local/skills/swiftui-ui-patterns/references/components-index.md +50 -0
- package/.local/skills/swiftui-ui-patterns/references/controls.md +57 -0
- package/.local/skills/swiftui-ui-patterns/references/deeplinks.md +66 -0
- package/.local/skills/swiftui-ui-patterns/references/focus.md +90 -0
- package/.local/skills/swiftui-ui-patterns/references/form.md +97 -0
- package/.local/skills/swiftui-ui-patterns/references/grids.md +71 -0
- package/.local/skills/swiftui-ui-patterns/references/haptics.md +71 -0
- package/.local/skills/swiftui-ui-patterns/references/input-toolbar.md +51 -0
- package/.local/skills/swiftui-ui-patterns/references/lightweight-clients.md +93 -0
- package/.local/skills/swiftui-ui-patterns/references/list.md +86 -0
- package/.local/skills/swiftui-ui-patterns/references/loading-placeholders.md +38 -0
- package/.local/skills/swiftui-ui-patterns/references/macos-settings.md +71 -0
- package/.local/skills/swiftui-ui-patterns/references/matched-transitions.md +59 -0
- package/.local/skills/swiftui-ui-patterns/references/media.md +73 -0
- package/.local/skills/swiftui-ui-patterns/references/menu-bar.md +101 -0
- package/.local/skills/swiftui-ui-patterns/references/navigationstack.md +159 -0
- package/.local/skills/swiftui-ui-patterns/references/overlay.md +45 -0
- package/.local/skills/swiftui-ui-patterns/references/performance.md +62 -0
- package/.local/skills/swiftui-ui-patterns/references/previews.md +48 -0
- package/.local/skills/swiftui-ui-patterns/references/scroll-reveal.md +133 -0
- package/.local/skills/swiftui-ui-patterns/references/scrollview.md +87 -0
- package/.local/skills/swiftui-ui-patterns/references/searchable.md +71 -0
- package/.local/skills/swiftui-ui-patterns/references/sheets.md +155 -0
- package/.local/skills/swiftui-ui-patterns/references/split-views.md +72 -0
- package/.local/skills/swiftui-ui-patterns/references/tabview.md +114 -0
- package/.local/skills/swiftui-ui-patterns/references/theming.md +71 -0
- package/.local/skills/swiftui-ui-patterns/references/title-menus.md +93 -0
- package/.local/skills/swiftui-ui-patterns/references/top-bar.md +49 -0
- package/.local/skills/swiftui-view-refactor/SKILL.md +202 -0
- package/.local/skills/swiftui-view-refactor/agents/openai.yaml +4 -0
- package/.local/skills/swiftui-view-refactor/references/mv-patterns.md +161 -0
- package/bundled/manifest.json +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: swift-concurrency-expert
|
|
3
|
+
description: Swift Concurrency review and remediation for Swift 6.2+. Use when asked to review Swift Concurrency usage, improve concurrency compliance, or fix Swift concurrency compiler errors in a feature or file. Concrete actions include adding Sendable conformance, applying @MainActor annotations, resolving actor isolation warnings, fixing data race diagnostics, and migrating completion handlers to async/await.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Swift Concurrency Expert
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Review and fix Swift Concurrency issues in Swift 6.2+ codebases by applying actor isolation, Sendable safety, and modern concurrency patterns with minimal behavior changes.
|
|
11
|
+
|
|
12
|
+
## Workflow
|
|
13
|
+
|
|
14
|
+
### 1. Triage the issue
|
|
15
|
+
|
|
16
|
+
- Capture the exact compiler diagnostics and the offending symbol(s).
|
|
17
|
+
- Check project concurrency settings: Swift language version (6.2+), strict concurrency level, and whether approachable concurrency (default actor isolation / main-actor-by-default) is enabled.
|
|
18
|
+
- Identify the current actor context (`@MainActor`, `actor`, `nonisolated`) and whether a default actor isolation mode is enabled.
|
|
19
|
+
- Confirm whether the code is UI-bound or intended to run off the main actor.
|
|
20
|
+
|
|
21
|
+
### 2. Apply the smallest safe fix
|
|
22
|
+
|
|
23
|
+
Prefer edits that preserve existing behavior while satisfying data-race safety.
|
|
24
|
+
|
|
25
|
+
Common fixes:
|
|
26
|
+
- **UI-bound types**: annotate the type or relevant members with `@MainActor`.
|
|
27
|
+
- **Protocol conformance on main actor types**: make the conformance isolated (e.g., `extension Foo: @MainActor SomeProtocol`).
|
|
28
|
+
- **Global/static state**: protect with `@MainActor` or move into an actor.
|
|
29
|
+
- **Background work**: move expensive work into a `@concurrent` async function on a `nonisolated` type or use an `actor` to guard mutable state.
|
|
30
|
+
- **Sendable errors**: prefer immutable/value types; add `Sendable` conformance only when correct; avoid `@unchecked Sendable` unless you can prove thread safety.
|
|
31
|
+
|
|
32
|
+
### 3. Verify the fix
|
|
33
|
+
|
|
34
|
+
- Rebuild and confirm all concurrency diagnostics are resolved with no new warnings introduced.
|
|
35
|
+
- Run the test suite to check for regressions — concurrency changes can introduce subtle runtime issues even when the build is clean.
|
|
36
|
+
- If the fix surfaces new warnings, treat each one as a fresh triage (return to step 1) and resolve iteratively until the build is clean and tests pass.
|
|
37
|
+
|
|
38
|
+
### Examples
|
|
39
|
+
|
|
40
|
+
**UI-bound type — adding `@MainActor`**
|
|
41
|
+
|
|
42
|
+
```swift
|
|
43
|
+
// Before: data-race warning because ViewModel is accessed from the main thread
|
|
44
|
+
// but has no actor isolation
|
|
45
|
+
class ViewModel: ObservableObject {
|
|
46
|
+
@Published var title: String = ""
|
|
47
|
+
func load() { title = "Loaded" }
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// After: annotate the whole type so all stored state and methods are
|
|
51
|
+
// automatically isolated to the main actor
|
|
52
|
+
@MainActor
|
|
53
|
+
class ViewModel: ObservableObject {
|
|
54
|
+
@Published var title: String = ""
|
|
55
|
+
func load() { title = "Loaded" }
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Protocol conformance isolation**
|
|
60
|
+
|
|
61
|
+
```swift
|
|
62
|
+
// Before: compiler error — SomeProtocol method is nonisolated but the
|
|
63
|
+
// conforming type is @MainActor
|
|
64
|
+
@MainActor
|
|
65
|
+
class Foo: SomeProtocol {
|
|
66
|
+
func protocolMethod() { /* accesses main-actor state */ }
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// After: scope the conformance to @MainActor so the requirement is
|
|
70
|
+
// satisfied inside the correct isolation context
|
|
71
|
+
@MainActor
|
|
72
|
+
extension Foo: SomeProtocol {
|
|
73
|
+
func protocolMethod() { /* safely accesses main-actor state */ }
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Background work with `@concurrent`**
|
|
78
|
+
|
|
79
|
+
```swift
|
|
80
|
+
// Before: expensive computation blocks the main actor
|
|
81
|
+
@MainActor
|
|
82
|
+
func processData(_ input: [Int]) -> [Int] {
|
|
83
|
+
input.map { heavyTransform($0) } // runs on main thread
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// After: hop off the main actor for the heavy work, then return the result
|
|
87
|
+
// The caller awaits the result and stays on its own actor
|
|
88
|
+
nonisolated func processData(_ input: [Int]) async -> [Int] {
|
|
89
|
+
await Task.detached(priority: .userInitiated) {
|
|
90
|
+
input.map { heavyTransform($0) }
|
|
91
|
+
}.value
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Or, using a @concurrent async function (Swift 6.2+):
|
|
95
|
+
@concurrent
|
|
96
|
+
func processData(_ input: [Int]) async -> [Int] {
|
|
97
|
+
input.map { heavyTransform($0) }
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Reference material
|
|
102
|
+
|
|
103
|
+
- See `references/swift-6-2-concurrency.md` for Swift 6.2 changes, patterns, and examples.
|
|
104
|
+
- See `references/approachable-concurrency.md` when the project is opted into approachable concurrency mode.
|
|
105
|
+
- See `references/swiftui-concurrency-tour-wwdc.md` for SwiftUI-specific concurrency guidance.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
## Approachable Concurrency (Swift 6.2) - project mode quick guide
|
|
2
|
+
|
|
3
|
+
Use this reference when the project has opted into the Swift 6.2 approachable
|
|
4
|
+
concurrency settings (default actor isolation / main-actor-by-default).
|
|
5
|
+
|
|
6
|
+
## Detect the mode
|
|
7
|
+
|
|
8
|
+
Check Xcode build settings under "Swift Compiler - Concurrency":
|
|
9
|
+
- Swift language version (must be 6.2+).
|
|
10
|
+
- Default actor isolation / Main Actor by default.
|
|
11
|
+
- Strict concurrency checking level (Complete/Targeted/Minimal).
|
|
12
|
+
|
|
13
|
+
For SwiftPM, inspect Package.swift swiftSettings for the same flags.
|
|
14
|
+
|
|
15
|
+
## Behavior changes to expect
|
|
16
|
+
|
|
17
|
+
- Async functions stay on the caller's actor by default; they don't hop to a
|
|
18
|
+
global concurrent executor unless the implementation chooses to.
|
|
19
|
+
- Main-actor-by-default reduces data race errors for UI-bound code and global
|
|
20
|
+
state, because mutable state is implicitly protected.
|
|
21
|
+
- Protocol conformances can be isolated (e.g., `extension Foo: @MainActor Bar`).
|
|
22
|
+
|
|
23
|
+
## How to apply fixes in this mode
|
|
24
|
+
|
|
25
|
+
- Prefer minimal annotations; let main-actor-by-default do the work when the
|
|
26
|
+
code is UI-bound.
|
|
27
|
+
- Use isolated conformances instead of forcing `nonisolated` workarounds.
|
|
28
|
+
- Keep global or shared mutable state on the main actor unless there is a clear
|
|
29
|
+
performance need to offload it.
|
|
30
|
+
|
|
31
|
+
## When to opt out or offload work
|
|
32
|
+
|
|
33
|
+
- Use `@concurrent` on async functions that must run on the concurrent pool.
|
|
34
|
+
- Make types or members `nonisolated` only when they are truly thread-safe and
|
|
35
|
+
used off the main actor.
|
|
36
|
+
- Continue to respect Sendable boundaries when values cross actors or tasks.
|
|
37
|
+
|
|
38
|
+
## Common pitfalls
|
|
39
|
+
|
|
40
|
+
- `Task.detached` ignores inherited actor context; avoid it unless you truly
|
|
41
|
+
need to break isolation.
|
|
42
|
+
- Main-actor-by-default can hide performance issues if CPU-heavy work stays on
|
|
43
|
+
the main actor; move that work into `@concurrent` async functions.
|
|
44
|
+
|
|
45
|
+
## Keywords (from source cheat sheet)
|
|
46
|
+
|
|
47
|
+
| Keyword | What it does |
|
|
48
|
+
| --- | --- |
|
|
49
|
+
| `async` | Function can pause |
|
|
50
|
+
| `await` | Pause here until done |
|
|
51
|
+
| `Task { }` | Start async work, inherits context |
|
|
52
|
+
| `Task.detached { }` | Start async work, no inherited context |
|
|
53
|
+
| `@MainActor` | Runs on main thread |
|
|
54
|
+
| `actor` | Type with isolated mutable state |
|
|
55
|
+
| `nonisolated` | Opts out of actor isolation |
|
|
56
|
+
| `Sendable` | Safe to pass between isolation domains |
|
|
57
|
+
| `@concurrent` | Always run on background (Swift 6.2+) |
|
|
58
|
+
| `async let` | Start parallel work |
|
|
59
|
+
| `TaskGroup` | Dynamic parallel work |
|
|
60
|
+
|
|
61
|
+
## Source
|
|
62
|
+
|
|
63
|
+
https://fuckingapproachableswiftconcurrency.com/en/
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
## Concurrent programming updates in Swift 6.2
|
|
2
|
+
|
|
3
|
+
Concurrent programming is hard because sharing memory between multiple tasks is prone to mistakes that lead to unpredictable behavior.
|
|
4
|
+
|
|
5
|
+
## Data-race safety
|
|
6
|
+
|
|
7
|
+
Data-race safety in Swift 6 prevents these mistakes at compile time, so you can write concurrent code without fear of introducing hard-to-debug runtime bugs. But in many cases, the most natural code to write is prone to data races, leading to compiler errors that you have to address. A class with mutable state, like this `PhotoProcessor` class, is safe as long as you don’t access it concurrently.
|
|
8
|
+
|
|
9
|
+
```swift
|
|
10
|
+
class PhotoProcessor {
|
|
11
|
+
func extractSticker(data: Data, with id: String?) async -> Sticker? { }
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@MainActor
|
|
15
|
+
final class StickerModel {
|
|
16
|
+
let photoProcessor = PhotoProcessor()
|
|
17
|
+
|
|
18
|
+
func extractSticker(_ item: PhotosPickerItem) async throws -> Sticker? {
|
|
19
|
+
guard let data = try await item.loadTransferable(type: Data.self) else {
|
|
20
|
+
return nil
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Error: Sending 'self.photoProcessor' risks causing data races
|
|
24
|
+
// Sending main actor-isolated 'self.photoProcessor' to nonisolated instance method 'extractSticker(data:with:)'
|
|
25
|
+
// risks causing data races between nonisolated and main actor-isolated uses
|
|
26
|
+
return await photoProcessor.extractSticker(data: data, with: item.itemIdentifier)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
It has an async method to extract a `Sticker` by computing the subject of the given image data. But if you try to call `extractSticker` from UI code on the main actor, you’ll get an error that the call risks causing data races. This is because there are several places in the language that offload work to the background implicitly, even if you never needed code to run in parallel.
|
|
32
|
+
|
|
33
|
+
Swift 6.2 changes this philosophy to stay single threaded by default until you choose to introduce concurrency.
|
|
34
|
+
|
|
35
|
+
```swift
|
|
36
|
+
class PhotoProcessor {
|
|
37
|
+
func extractSticker(data: Data, with id: String?) async -> Sticker? { }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
@MainActor
|
|
41
|
+
final class StickerModel {
|
|
42
|
+
let photoProcessor = PhotoProcessor()
|
|
43
|
+
|
|
44
|
+
func extractSticker(_ item: PhotosPickerItem) async throws -> Sticker? {
|
|
45
|
+
guard let data = try await item.loadTransferable(type: Data.self) else {
|
|
46
|
+
return nil
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// No longer a data race error in Swift 6.2 because of Approachable Concurrency and default actor isolation
|
|
50
|
+
return await photoProcessor.extractSticker(data: data, with: item.itemIdentifier)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The language changes in Swift 6.2 make the most natural code to write data race free by default. This provides a more approachable path to introducing concurrency in a project.
|
|
56
|
+
|
|
57
|
+
When you choose to introduce concurrency because you want to run code in parallel, data-race safety will protect you.
|
|
58
|
+
|
|
59
|
+
First, we've made it easier to call async functions on types with mutable state. Instead of eagerly offloading async functions that aren't tied to a specific actor, the function will continue to run on the actor it was called from. This eliminates data races because the values passed into the async function are never sent outside the actor. Async functions can still offload work in their implementation, but clients don’t have to worry about their mutable state.
|
|
60
|
+
|
|
61
|
+
Next, we’ve made it easier to implement conformances on main actor types. Here I have a protocol called `Exportable`, and I’m trying to implement a conformance for my main actor `StickerModel` class. The export requirement doesn’t have actor isolation, so the language assumed that it could be called from off the main actor, and prevented `StickerModel` from using main actor state in its implementation.
|
|
62
|
+
|
|
63
|
+
```swift
|
|
64
|
+
protocol Exportable {
|
|
65
|
+
func export()
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
extension StickerModel: Exportable { // error: Conformance of 'StickerModel' to protocol 'Exportable' crosses into main actor-isolated code and can cause data races
|
|
69
|
+
func export() {
|
|
70
|
+
photoProcessor.exportAsPNG()
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Swift 6.2 supports these conformances. A conformance that needs main actor state is called an *isolated* conformance. This is safe because the compiler ensures a main actor conformance is only used on the main actor.
|
|
76
|
+
|
|
77
|
+
```swift
|
|
78
|
+
// Isolated conformances
|
|
79
|
+
|
|
80
|
+
protocol Exportable {
|
|
81
|
+
func export()
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
extension StickerModel: @MainActor Exportable {
|
|
85
|
+
func export() {
|
|
86
|
+
photoProcessor.exportAsPNG()
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
I can create an `ImageExporter` type that adds a `StickerModel` to an array of any `Exportable` items as long as it stays on the main actor.
|
|
92
|
+
|
|
93
|
+
```swift
|
|
94
|
+
// Isolated conformances
|
|
95
|
+
|
|
96
|
+
@MainActor
|
|
97
|
+
struct ImageExporter {
|
|
98
|
+
var items: [any Exportable]
|
|
99
|
+
|
|
100
|
+
mutating func add(_ item: StickerModel) {
|
|
101
|
+
items.append(item)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
func exportAll() {
|
|
105
|
+
for item in items {
|
|
106
|
+
item.export()
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
But if I allow `ImageExporter` to be used from anywhere, the compiler prevents adding `StickerModel` to the array because it isn’t safe to call export on `StickerModel` from outside the main actor.
|
|
113
|
+
|
|
114
|
+
```swift
|
|
115
|
+
// Isolated conformances
|
|
116
|
+
|
|
117
|
+
nonisolated
|
|
118
|
+
struct ImageExporter {
|
|
119
|
+
var items: [any Exportable]
|
|
120
|
+
|
|
121
|
+
mutating func add(_ item: StickerModel) {
|
|
122
|
+
items.append(item) // error: Main actor-isolated conformance of 'StickerModel' to 'Exportable' cannot be used in nonisolated context
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
func exportAll() {
|
|
126
|
+
for item in items {
|
|
127
|
+
item.export()
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
With isolated conformances, you only have to solve data race safety issues when the code indicates that it uses the conformance concurrently.
|
|
134
|
+
|
|
135
|
+
## Global State
|
|
136
|
+
|
|
137
|
+
Global and static variables are prone to data races because they allow mutable state to be accessed from anywhere.
|
|
138
|
+
|
|
139
|
+
```swift
|
|
140
|
+
final class StickerLibrary {
|
|
141
|
+
static let shared: StickerLibrary = .init() // error: Static property 'shared' is not concurrency-safe because non-'Sendable' type 'StickerLibrary' may have shared mutable state
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
The most common way to protect global state is with the main actor.
|
|
146
|
+
|
|
147
|
+
```swift
|
|
148
|
+
final class StickerLibrary {
|
|
149
|
+
@MainActor
|
|
150
|
+
static let shared: StickerLibrary = .init()
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
And it’s common to annotate an entire class with the main actor to protect all of its mutable state, especially in a project that doesn’t have a lot of concurrent tasks.
|
|
155
|
+
|
|
156
|
+
```swift
|
|
157
|
+
@MainActor
|
|
158
|
+
final class StickerLibrary {
|
|
159
|
+
static let shared: StickerLibrary = .init()
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
You can model a program that's entirely single-threaded by writing `@MainActor` on everything in your project.
|
|
164
|
+
|
|
165
|
+
```swift
|
|
166
|
+
@MainActor
|
|
167
|
+
final class StickerLibrary {
|
|
168
|
+
static let shared: StickerLibrary = .init()
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
@MainActor
|
|
172
|
+
final class StickerModel {
|
|
173
|
+
let photoProcessor: PhotoProcessor
|
|
174
|
+
|
|
175
|
+
var selection: [PhotosPickerItem]
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
extension StickerModel: @MainActor Exportable {
|
|
179
|
+
func export() {
|
|
180
|
+
photoProcessor.exportAsPNG()
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
To make it easier to model single-threaded code, we’ve introduced a mode to infer main actor by default.
|
|
186
|
+
|
|
187
|
+
```swift
|
|
188
|
+
// Mode to infer main actor by default in Swift 6.2
|
|
189
|
+
|
|
190
|
+
final class StickerLibrary {
|
|
191
|
+
static let shared: StickerLibrary = .init()
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
final class StickerModel {
|
|
195
|
+
let photoProcessor: PhotoProcessor
|
|
196
|
+
|
|
197
|
+
var selection: [PhotosPickerItem]
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
extension StickerModel: Exportable {
|
|
201
|
+
func export() {
|
|
202
|
+
photoProcessor.exportAsPNG()
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
This eliminates data-race safety errors about unsafe global and static variables, calls to other main actor functions like ones from the SDK, and more, because the main actor protects all mutable state by default. It also reduces concurrency annotations in code that’s mostly single-threaded. This mode is great for projects that do most of the work on the main actor, and concurrent code is encapsulated within specific types or files. It’s opt-in and it’s recommended for apps, scripts, and other executable targets.
|
|
208
|
+
|
|
209
|
+
## Offloading work to the background
|
|
210
|
+
|
|
211
|
+
Offloading work to the background is still important for performance, such as keeping apps responsive when performing CPU-intensive tasks.
|
|
212
|
+
|
|
213
|
+
Let’s look at the implementation of the `extractSticker` method on `PhotoProcessor`.
|
|
214
|
+
|
|
215
|
+
```swift
|
|
216
|
+
// Explicitly offloading async work
|
|
217
|
+
|
|
218
|
+
class PhotoProcessor {
|
|
219
|
+
var cachedStickers: [String: Sticker]
|
|
220
|
+
|
|
221
|
+
func extractSticker(data: Data, with id: String) async -> Sticker {
|
|
222
|
+
if let sticker = cachedStickers[id] {
|
|
223
|
+
return sticker
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
let sticker = await Self.extractSubject(from: data)
|
|
227
|
+
cachedStickers[id] = sticker
|
|
228
|
+
return sticker
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Offload expensive image processing using the @concurrent attribute.
|
|
232
|
+
@concurrent
|
|
233
|
+
static func extractSubject(from data: Data) async -> Sticker { }
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
It first checks whether it already extracted a sticker for an image, so it can return the cached sticker immediately. If the sticker hasn’t been cached, it extracts the subject from the image data and creates a new sticker. The `extractSubject` method performs expensive image processing that I don’t want to block the main actor or any other actor.
|
|
238
|
+
|
|
239
|
+
I can offload this work using the `@concurrent` attribute. `@concurrent` ensures that a function always runs on the concurrent thread pool, freeing up the actor to run other tasks at the same time.
|
|
240
|
+
|
|
241
|
+
### An example
|
|
242
|
+
|
|
243
|
+
Say you have a function called `process` that you would like to run on a background thread. To call that function on a background thread you need to:
|
|
244
|
+
|
|
245
|
+
- make sure the structure or class is `nonisolated`
|
|
246
|
+
- add the `@concurrent` attribute to the function you want to run in the background
|
|
247
|
+
- add the keyword `async` to the function if it is not already asynchronous
|
|
248
|
+
- and then add the keyword `await` to any callers
|
|
249
|
+
|
|
250
|
+
Like this:
|
|
251
|
+
|
|
252
|
+
```swift
|
|
253
|
+
nonisolated struct PhotoProcessor {
|
|
254
|
+
|
|
255
|
+
@concurrent
|
|
256
|
+
func process(data: Data) async -> ProcessedPhoto? { ... }
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Callers with the added await
|
|
260
|
+
processedPhotos[item.id] = await PhotoProcessor().process(data: data)
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
## Summary
|
|
265
|
+
|
|
266
|
+
These language changes work together to make concurrency more approachable.
|
|
267
|
+
|
|
268
|
+
You start by writing code that runs on the main actor by default, where there’s no risk of data races. When you start to use async functions, those functions run wherever they’re called from. There’s still no risk of data races because all of your code still runs on the main actor. When you’re ready to embrace concurrency to improve performance, it’s easy to offload specific code to the background to run in parallel.
|
|
269
|
+
|
|
270
|
+
Some of these language changes are opt-in because they require changes in your project to adopt. You can find and enable all of the approachable concurrency language changes under the Swift Compiler - Concurrency section of Xcode build settings. You can also enable these features in a Swift package manifest file using the SwiftSettings API.
|
|
271
|
+
|
|
272
|
+
Swift 6.2 includes migration tooling to help you make the necessary code changes automatically. You can learn more about migration tooling at swift.org/migration.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# SwiftUI Concurrency Tour (Summary)
|
|
2
|
+
|
|
3
|
+
Context: SwiftUI-focused concurrency overview covering actor isolation, Sendable closures, and how SwiftUI runs work off the main thread.
|
|
4
|
+
|
|
5
|
+
## Main-actor default in SwiftUI
|
|
6
|
+
|
|
7
|
+
- `View` is `@MainActor` isolated by default; members and `body` inherit isolation.
|
|
8
|
+
- Swift 6.2 can infer `@MainActor` for all types in a module (new language mode).
|
|
9
|
+
- This default simplifies UI code and aligns with UIKit/AppKit `@MainActor` APIs.
|
|
10
|
+
|
|
11
|
+
## Where SwiftUI runs code off the main thread
|
|
12
|
+
|
|
13
|
+
- SwiftUI may evaluate some view logic on background threads for performance.
|
|
14
|
+
- Examples: `Shape` path generation, `Layout` methods, `visualEffect` closures, and `onGeometryChange` closures.
|
|
15
|
+
- These APIs often require `Sendable` closures to reflect their runtime semantics.
|
|
16
|
+
|
|
17
|
+
## Sendable closures and data-race safety
|
|
18
|
+
|
|
19
|
+
- Accessing `@MainActor` state from a `Sendable` closure is unsafe and flagged by the compiler.
|
|
20
|
+
- Prefer capturing value copies in the closure capture list (e.g., copy a `Bool`).
|
|
21
|
+
- Avoid sending `self` into a sendable closure just to read a single property.
|
|
22
|
+
|
|
23
|
+
## Structuring async work with SwiftUI
|
|
24
|
+
|
|
25
|
+
- SwiftUI action callbacks are synchronous so UI updates (like loading states) can be immediate.
|
|
26
|
+
- Use `Task` to bridge into async contexts; keep async bodies minimal.
|
|
27
|
+
- Use state as the boundary: async work updates model/state; UI reacts synchronously.
|
|
28
|
+
|
|
29
|
+
## Performance-driven concurrency
|
|
30
|
+
|
|
31
|
+
- Offload expensive work from the main actor to avoid hitches.
|
|
32
|
+
- Keep time-sensitive UI logic (animations, gesture responses) synchronous.
|
|
33
|
+
- Separate UI code from long-running async work to improve responsiveness and testability.
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: swiftui-expert-skill
|
|
3
|
+
description: Use when writing, reviewing, or refactoring SwiftUI code for iOS or macOS, including state management, view composition, performance, Liquid Glass adoption, or Instruments `.trace` capture/analysis for hangs, hitches, CPU hotspots, or
|
|
4
|
+
excessive view updates.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# SwiftUI Expert Skill
|
|
8
|
+
|
|
9
|
+
## Operating Rules
|
|
10
|
+
|
|
11
|
+
- Consult `references/latest-apis.md` at the start of every task to avoid deprecated APIs
|
|
12
|
+
- Prefer native SwiftUI APIs over UIKit/AppKit bridging unless bridging is necessary
|
|
13
|
+
- Focus on correctness and performance; do not enforce specific architectures (MVVM, VIPER, etc.)
|
|
14
|
+
- Encourage separating business logic from views for testability without mandating how
|
|
15
|
+
- Follow Apple's Human Interface Guidelines and API design patterns
|
|
16
|
+
- Only adopt Liquid Glass when explicitly requested by the user (see `references/liquid-glass.md`)
|
|
17
|
+
- Present performance optimizations as suggestions, not requirements
|
|
18
|
+
- Use `#available` gating with sensible fallbacks for version-specific APIs
|
|
19
|
+
|
|
20
|
+
## Task Workflow
|
|
21
|
+
|
|
22
|
+
### Review existing SwiftUI code
|
|
23
|
+
- Read the code under review and identify which topics apply
|
|
24
|
+
- Flag deprecated APIs (compare against `references/latest-apis.md`)
|
|
25
|
+
- Run the Topic Router below for each relevant topic
|
|
26
|
+
- Validate `#available` gating and fallback paths for iOS 26+ features
|
|
27
|
+
|
|
28
|
+
### Improve existing SwiftUI code
|
|
29
|
+
- Audit current implementation against the Topic Router topics
|
|
30
|
+
- Replace deprecated APIs with modern equivalents from `references/latest-apis.md`
|
|
31
|
+
- Refactor hot paths to reduce unnecessary state updates
|
|
32
|
+
- Extract complex view bodies into separate subviews
|
|
33
|
+
- Suggest image downsampling when `UIImage(data:)` is encountered (optional optimization, see `references/image-optimization.md`)
|
|
34
|
+
|
|
35
|
+
### Implement new SwiftUI feature
|
|
36
|
+
- Design data flow first: identify owned vs injected state
|
|
37
|
+
- Structure views for optimal diffing (extract subviews early)
|
|
38
|
+
- Apply correct animation patterns (implicit vs explicit, transitions)
|
|
39
|
+
- Use `Button` for all tappable elements; add accessibility grouping and labels
|
|
40
|
+
- Gate version-specific APIs with `#available` and provide fallbacks
|
|
41
|
+
|
|
42
|
+
### Record a new Instruments trace
|
|
43
|
+
Trigger when the user asks to "record a trace", "profile the app", "capture a session", etc. Full reference: `references/trace-recording.md`.
|
|
44
|
+
|
|
45
|
+
1. **Confirm target** — attach to a running app, launch an app, or record all processes? If the user didn't say, ask. List connected devices when useful:
|
|
46
|
+
```bash
|
|
47
|
+
python3 "${SKILL_DIR}/scripts/record_trace.py" --list-devices
|
|
48
|
+
```
|
|
49
|
+
2. **Pick a template based on target kind** — the `SwiftUI` template populates the SwiftUI lane on any **real device**: a physical iOS/iPadOS device **or the host Mac**. The only exception is the **iOS Simulator**, where the SwiftUI lane comes back empty — switch to `--template "Time Profiler"` in that case (still gives Time Profiler + Hangs + Animation Hitches). Always check `--list-devices`: `simulators` kind → `Time Profiler`; `devices` kind (real devices and the host Mac) → default `SwiftUI`. Full decision table in `references/trace-recording.md`.
|
|
50
|
+
3. **Start the recording**. For agent-driven sessions where the user says "I'll tell you when I'm done", start in the background and use a stop-file:
|
|
51
|
+
```bash
|
|
52
|
+
python3 "${SKILL_DIR}/scripts/record_trace.py" \
|
|
53
|
+
--device "<name|udid>" --attach "<AppName>" \
|
|
54
|
+
--stop-file /tmp/stop-trace --output ~/Desktop/session.trace
|
|
55
|
+
```
|
|
56
|
+
For interactive sessions, just tell the user to press Ctrl+C when done.
|
|
57
|
+
4. **Signal stop** — when the user says they've finished exercising the app, `touch /tmp/stop-trace`. The script cleanly SIGINTs xctrace and waits up to 60s for finalisation.
|
|
58
|
+
5. **Analyse** the resulting trace (flow into the "Trace-driven improvement" workflow below).
|
|
59
|
+
|
|
60
|
+
### Trace-driven improvement (Instruments `.trace` provided)
|
|
61
|
+
Trigger whenever the user's request references a `.trace` file. A target SwiftUI source file is **optional** — if given, cite specific lines; if not, recommend where to look based on view names and symbols the trace already reveals.
|
|
62
|
+
|
|
63
|
+
Full reference: `references/trace-analysis.md`. Summary of the composition pattern:
|
|
64
|
+
|
|
65
|
+
1. **Scope the analysis.** Ask yourself: does the user want the whole trace, or a slice?
|
|
66
|
+
- "focus on X / after X / between X and Y / during X" → **resolve to a window first** (see step 2).
|
|
67
|
+
- No scoping cue → analyse the whole trace.
|
|
68
|
+
2. **Resolve a window (only if the user scoped).** The parser exposes two discovery modes:
|
|
69
|
+
```bash
|
|
70
|
+
# Find a log that marks the start/end of the region of interest:
|
|
71
|
+
python3 "${SKILL_DIR}/scripts/analyze_trace.py" --trace <path> \
|
|
72
|
+
--list-logs --log-message-contains "loaded feed" --log-limit 5
|
|
73
|
+
# Or list os_signpost intervals (paired begin/end), filterable by name:
|
|
74
|
+
python3 "${SKILL_DIR}/scripts/analyze_trace.py" --trace <path> \
|
|
75
|
+
--list-signposts --signpost-name-contains "ImageDecode"
|
|
76
|
+
```
|
|
77
|
+
Both modes accept `--window START_MS:END_MS` to scope discovery. Pick the `time_ms` (for logs) or `start_ms`/`end_ms` (for signposts) that match the user's description. Build a window like `--window 10400:11700`.
|
|
78
|
+
3. **Run the main analysis** (with or without `--window`):
|
|
79
|
+
```bash
|
|
80
|
+
python3 "${SKILL_DIR}/scripts/analyze_trace.py" --trace <path> \
|
|
81
|
+
--json-only --top 10 [--window START_MS:END_MS]
|
|
82
|
+
```
|
|
83
|
+
4. **Interpret with `references/trace-analysis.md`** — key diagnostics:
|
|
84
|
+
- `main_running_coverage_pct` inside each correlation (<25% = blocked; ≥75% = CPU-bound).
|
|
85
|
+
- `swiftui-causes.top_sources` reveals *why* updates keep happening — high-edge-count sources like `UserDefaultObserver.send()` or wide `EnvironmentWriter` entries are structural invalidation bugs. Fixing one often collapses many downstream hot views.
|
|
86
|
+
5. **When a specific view shows as expensive, ask who's invalidating it.** Use `--fanin-for "<view name>"` to get the ranked list of source nodes driving the updates.
|
|
87
|
+
6. **Optionally ground in source.** If the user pointed at a file, read it and match view names / user-code symbols against identifiers there. If not, recommend which files to open based on the view names SwiftUI reported.
|
|
88
|
+
7. **Return a prioritised plan.** Cite evidence (coverage %, hot symbol, overlapping view, log timestamp, cause-graph edges) and route each recommendation to a Topic Router reference.
|
|
89
|
+
8. Only edit code if the user asked for edits.
|
|
90
|
+
|
|
91
|
+
### Topic Router
|
|
92
|
+
|
|
93
|
+
Consult the reference file for each topic relevant to the current task:
|
|
94
|
+
|
|
95
|
+
| Topic | Reference |
|
|
96
|
+
|-------|-----------|
|
|
97
|
+
| State management | `references/state-management.md` |
|
|
98
|
+
| View composition | `references/view-structure.md` |
|
|
99
|
+
| Performance | `references/performance-patterns.md` |
|
|
100
|
+
| Lists and ForEach | `references/list-patterns.md` |
|
|
101
|
+
| Layout | `references/layout-best-practices.md` |
|
|
102
|
+
| Sheets and navigation | `references/sheet-navigation-patterns.md` |
|
|
103
|
+
| ScrollView | `references/scroll-patterns.md` |
|
|
104
|
+
| Focus management | `references/focus-patterns.md` |
|
|
105
|
+
| Animations (basics) | `references/animation-basics.md` |
|
|
106
|
+
| Animations (transitions) | `references/animation-transitions.md` |
|
|
107
|
+
| Animations (advanced) | `references/animation-advanced.md` |
|
|
108
|
+
| Accessibility | `references/accessibility-patterns.md` |
|
|
109
|
+
| Swift Charts | `references/charts.md` |
|
|
110
|
+
| Charts accessibility | `references/charts-accessibility.md` |
|
|
111
|
+
| Image optimization | `references/image-optimization.md` |
|
|
112
|
+
| Liquid Glass (iOS 26+) | `references/liquid-glass.md` |
|
|
113
|
+
| macOS scenes | `references/macos-scenes.md` |
|
|
114
|
+
| macOS window styling | `references/macos-window-styling.md` |
|
|
115
|
+
| macOS views | `references/macos-views.md` |
|
|
116
|
+
| Text patterns | `references/text-patterns.md` |
|
|
117
|
+
| Deprecated API lookup | `references/latest-apis.md` |
|
|
118
|
+
| Instruments trace analysis | `references/trace-analysis.md` |
|
|
119
|
+
| Instruments trace recording | `references/trace-recording.md` |
|
|
120
|
+
|
|
121
|
+
## Correctness Checklist
|
|
122
|
+
|
|
123
|
+
These are hard rules -- violations are always bugs:
|
|
124
|
+
|
|
125
|
+
- [ ] `@State` properties are `private`
|
|
126
|
+
- [ ] `@Binding` only where a child modifies parent state
|
|
127
|
+
- [ ] Passed values never declared as `@State` or `@StateObject` (they ignore updates)
|
|
128
|
+
- [ ] `@StateObject` for view-owned objects; `@ObservedObject` for injected
|
|
129
|
+
- [ ] iOS 17+: `@State` with `@Observable`; `@Bindable` for injected observables needing bindings
|
|
130
|
+
- [ ] `ForEach` uses stable identity (never `.indices` for dynamic content)
|
|
131
|
+
- [ ] Constant number of views per `ForEach` element
|
|
132
|
+
- [ ] `.animation(_:value:)` always includes the `value` parameter
|
|
133
|
+
- [ ] `@FocusState` properties are `private`
|
|
134
|
+
- [ ] No redundant `@FocusState` writes inside tap gesture handlers on `.focusable()` views
|
|
135
|
+
- [ ] iOS 26+ APIs gated with `#available` and fallback provided
|
|
136
|
+
- [ ] `import Charts` present in files using chart types
|
|
137
|
+
|
|
138
|
+
## References
|
|
139
|
+
|
|
140
|
+
- `references/latest-apis.md` -- **Read first for every task.** Deprecated-to-modern API transitions (iOS 15+ through iOS 26+)
|
|
141
|
+
- `references/state-management.md` -- Property wrappers, data flow, `@Observable` migration
|
|
142
|
+
- `references/view-structure.md` -- View extraction, container patterns, `@ViewBuilder`
|
|
143
|
+
- `references/performance-patterns.md` -- Hot-path optimization, update control, `_logChanges()`
|
|
144
|
+
- `references/list-patterns.md` -- ForEach identity, Table (iOS 16+), inline filtering pitfalls
|
|
145
|
+
- `references/layout-best-practices.md` -- Layout patterns, GeometryReader alternatives
|
|
146
|
+
- `references/accessibility-patterns.md` -- VoiceOver, Dynamic Type, grouping, traits
|
|
147
|
+
- `references/animation-basics.md` -- Implicit/explicit animations, timing, performance
|
|
148
|
+
- `references/animation-transitions.md` -- View transitions, `matchedGeometryEffect`, `Animatable`
|
|
149
|
+
- `references/animation-advanced.md` -- Phase/keyframe animations (iOS 17+), `@Animatable` macro (iOS 26+)
|
|
150
|
+
- `references/charts.md` -- Swift Charts marks, axes, selection, styling, Chart3D (iOS 26+)
|
|
151
|
+
- `references/charts-accessibility.md` -- Charts VoiceOver, Audio Graph, fallback strategies
|
|
152
|
+
- `references/sheet-navigation-patterns.md` -- Sheets, NavigationSplitView, Inspector
|
|
153
|
+
- `references/scroll-patterns.md` -- ScrollViewReader, programmatic scrolling
|
|
154
|
+
- `references/focus-patterns.md` -- Focus state, focusable views, focused values, default focus, common pitfalls
|
|
155
|
+
- `references/image-optimization.md` -- AsyncImage, downsampling, caching
|
|
156
|
+
- `references/liquid-glass.md` -- iOS 26+ Liquid Glass effects and fallback patterns
|
|
157
|
+
- `references/macos-scenes.md` -- Settings, MenuBarExtra, WindowGroup, multi-window
|
|
158
|
+
- `references/macos-window-styling.md` -- Toolbar styles, window sizing, Commands
|
|
159
|
+
- `references/macos-views.md` -- HSplitView, Table, PasteButton, AppKit interop
|
|
160
|
+
- `references/text-patterns.md` -- Text initializer selection, verbatim vs localized
|
|
161
|
+
- `references/trace-analysis.md` -- Parse Instruments `.trace` files via `scripts/analyze_trace.py`; interpret main-thread coverage, high-severity SwiftUI updates, hitch narratives, and map findings back to source files
|
|
162
|
+
- `references/trace-recording.md` -- Record a new trace via `scripts/record_trace.py`: attach to a running app, launch one fresh, or capture a manually-stopped session; supports stop-file for agent-driven flows
|