@mmerterden/multi-agent-pipeline 20.6.0 → 20.8.0
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/CHANGELOG.md +27 -0
- package/LICENSE +0 -10
- package/docs/facts.json +1 -1
- package/manifest.json +328 -329
- package/package.json +2 -2
- package/pipeline/multi-agent-refs/features/design-conformance.md +62 -64
- package/pipeline/scripts/_notices.mjs +12 -1
- package/pipeline/scripts/gen-skills-index.mjs +1 -1
- package/pipeline/skills/.skill-manifest.json +106 -106
- package/pipeline/skills/shared/README.md +71 -71
- package/pipeline/skills/shared/external/agent-introspection-debugging/SKILL.md +1 -0
- package/pipeline/skills/shared/external/alarmkit/SKILL.md +373 -381
- package/pipeline/skills/shared/external/alarmkit/evals/evals.json +23 -18
- package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +328 -378
- package/pipeline/skills/shared/external/android-architecture/SKILL.md +2 -0
- package/pipeline/skills/shared/external/android-performance/SKILL.md +2 -0
- package/pipeline/skills/shared/external/android-security/SKILL.md +2 -0
- package/pipeline/skills/shared/external/app-clips/SKILL.md +260 -160
- package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
- package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
- package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
- package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
- package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
- package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
- package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +339 -277
- package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
- package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +105 -122
- package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +143 -166
- package/pipeline/skills/shared/external/app-store-review/SKILL.md +307 -326
- package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
- package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
- package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +333 -360
- package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
- package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
- package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
- package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
- package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
- package/pipeline/skills/shared/external/authentication/SKILL.md +265 -381
- package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
- package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +133 -178
- package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
- package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
- package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
- package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
- package/pipeline/skills/shared/external/background-processing/SKILL.md +270 -382
- package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
- package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +169 -317
- package/pipeline/skills/shared/external/backlog/BACKLOG.md +1 -1
- package/pipeline/skills/shared/external/backlog/SKILL.md +56 -33
- package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
- package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
- package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
- package/pipeline/skills/shared/external/ci-cd-pipelines/SKILL.md +1 -0
- package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
- package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
- package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
- package/pipeline/skills/shared/external/compose-components/SKILL.md +2 -0
- package/pipeline/skills/shared/external/compose-navigation/SKILL.md +3 -2
- package/pipeline/skills/shared/external/compose-testing/SKILL.md +2 -0
- package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
- package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
- package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
- package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +226 -376
- package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
- package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
- package/pipeline/skills/shared/external/core-data/SKILL.md +292 -368
- package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
- package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
- package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
- package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
- package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
- package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
- package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
- package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
- package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
- package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
- package/pipeline/skills/shared/external/council/SKILL.md +1 -0
- package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
- package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
- package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
- package/pipeline/skills/shared/external/css-modern/SKILL.md +1 -0
- package/pipeline/skills/shared/external/database-patterns/SKILL.md +1 -0
- package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
- package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
- package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
- package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
- package/pipeline/skills/shared/external/device-integrity/SKILL.md +230 -353
- package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
- package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
- package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
- package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
- package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
- package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
- package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
- package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
- package/pipeline/skills/shared/external/evidence-github/SKILL.md +2 -0
- package/pipeline/skills/shared/external/evidence-registry/SKILL.md +2 -0
- package/pipeline/skills/shared/external/gradle-kotlin-dsl/SKILL.md +2 -0
- package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
- package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
- package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
- package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
- package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
- package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
- package/pipeline/skills/shared/external/html-semantic/SKILL.md +1 -0
- package/pipeline/skills/shared/external/humanizer/SKILL.md +1 -0
- package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
- package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
- package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
- package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
- package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
- package/pipeline/skills/shared/external/ios-coding-standard/SKILL.md +1 -0
- package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
- package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
- package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
- package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
- package/pipeline/skills/shared/external/ios-module-structure/SKILL.md +1 -0
- package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
- package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
- package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
- package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
- package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
- package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
- package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
- package/pipeline/skills/shared/external/ios-security/SKILL.md +2 -0
- package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
- package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
- package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
- package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
- package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +91 -283
- package/pipeline/skills/shared/external/localization-reuse-map/reference/format-and-output.md +119 -151
- package/pipeline/skills/shared/external/localization-reuse-map/reference/publish-and-snapshot.md +60 -90
- package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +119 -156
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-artifact.py +726 -787
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-spreadsheet.py +253 -288
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-annotations.py +243 -304
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-legacy-labels.py +88 -104
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/publish-confluence.py +181 -235
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-key-shots.py +198 -263
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-overlay.py +461 -466
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-legacy-values.py +145 -151
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +123 -141
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/scan-screen-keys.py +146 -157
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/snapshot-resources.sh +22 -19
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/verify-map.py +156 -140
- package/pipeline/skills/shared/external/mapkit-location/SKILL.md +295 -267
- package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
- package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
- package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
- package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
- package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
- package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
- package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
- package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
- package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
- package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
- package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
- package/pipeline/skills/shared/external/nextjs-app-router/SKILL.md +1 -0
- package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
- package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
- package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
- package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
- package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
- package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
- package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
- package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
- package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
- package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
- package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
- package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
- package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
- package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
- package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
- package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
- package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
- package/pipeline/skills/shared/external/play-store-review/SKILL.md +2 -0
- package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
- package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
- package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
- package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
- package/pipeline/skills/shared/external/python-patterns/SKILL.md +1 -0
- package/pipeline/skills/shared/external/react-best-practices/SKILL.md +1 -0
- package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
- package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
- package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
- package/pipeline/skills/shared/external/rest-api-design/SKILL.md +1 -0
- package/pipeline/skills/shared/external/retrofit-networking/SKILL.md +2 -0
- package/pipeline/skills/shared/external/room-database/SKILL.md +2 -0
- package/pipeline/skills/shared/external/search-first/SKILL.md +1 -0
- package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
- package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
- package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
- package/pipeline/skills/shared/external/signal-community/SKILL.md +2 -0
- package/pipeline/skills/shared/external/skill-creator/SKILL.md +80 -41
- package/pipeline/skills/shared/external/skill-creator/audit.md +63 -59
- package/pipeline/skills/shared/external/skill-creator/checklist.md +28 -20
- package/pipeline/skills/shared/external/skill-creator/examples.md +40 -40
- package/pipeline/skills/shared/external/skill-creator/label-check.md +48 -36
- package/pipeline/skills/shared/external/skill-creator/scripts/audit-panel.js +91 -100
- package/pipeline/skills/shared/external/skill-creator/template.md +51 -39
- package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
- package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
- package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
- package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
- package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
- package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
- package/pipeline/skills/shared/external/storekit/references/core-patterns.md +298 -242
- package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
- package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
- package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
- package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
- package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
- package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
- package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
- package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
- package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
- package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
- package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +303 -351
- package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
- package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
- package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
- package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
- package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
- package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
- package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
- package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
- package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
- package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
- package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
- package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
- package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
- package/pipeline/skills/shared/external/swift-security/SKILL.md +180 -161
- package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
- package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
- package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +408 -476
- package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
- package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
- package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
- package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
- package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
- package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
- package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +352 -472
- package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
- package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
- package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
- package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +396 -457
- package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
- package/pipeline/skills/shared/external/swift-testing/SKILL.md +188 -175
- package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
- package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +80 -84
- package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
- package/pipeline/skills/shared/external/swiftdata/SKILL.md +392 -256
- package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
- package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
- package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
- package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
- package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
- package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
- package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
- package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
- package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
- package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
- package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
- package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
- package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
- package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
- package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
- package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
- package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
- package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
- package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
- package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
- package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
- package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
- package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
- package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
- package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +193 -168
- package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
- package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +132 -133
- package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
- package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +106 -140
- package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
- package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
- package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
- package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
- package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
- package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
- package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
- package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
- package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
- package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
- package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
- package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
- package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
- package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
- package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
- package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
- package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
- package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
- package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
- package/pipeline/skills/shared/external/tailwind-css/SKILL.md +1 -0
- package/pipeline/skills/shared/external/testing-backend/SKILL.md +1 -0
- package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
- package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
- package/pipeline/skills/shared/external/typescript-patterns/SKILL.md +1 -0
- package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
- package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
- package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
- package/pipeline/skills/shared/external/vue-composition/SKILL.md +1 -0
- package/pipeline/skills/shared/external/weatherkit/SKILL.md +152 -310
- package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
- package/pipeline/skills/shared/external/web-accessibility/SKILL.md +1 -0
- package/pipeline/skills/shared/external/web-performance/SKILL.md +1 -0
- package/pipeline/skills/shared/external/web-testing/SKILL.md +1 -0
- package/pipeline/skills/shared/external/widgetkit/SKILL.md +216 -288
- package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +414 -719
- package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +0 -39
|
@@ -1,220 +1,131 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Mental Model: Dependencies, Identity and Lifecycle
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
Notes drawn from the WWDC23 session "Demystify SwiftUI performance". Use them
|
|
4
|
+
to explain why a SwiftUI screen does more work than it should.
|
|
5
5
|
|
|
6
|
-
##
|
|
7
|
-
- Core mental model
|
|
8
|
-
- Dependencies and invalidation
|
|
9
|
-
- Expensive body work
|
|
10
|
-
- Identity rules for lists and tables
|
|
11
|
-
- Initialization and lifecycle pitfalls
|
|
12
|
-
- Debugging tools
|
|
13
|
-
- Fix patterns
|
|
14
|
-
- What to verify after a change
|
|
6
|
+
## The Model
|
|
15
7
|
|
|
16
|
-
|
|
8
|
+
- For each frame, SwiftUI should do only the work the current state requires.
|
|
9
|
+
- A slow screen almost always has one of three problems: each update does too
|
|
10
|
+
much, updates happen too often, or identity is unstable and work gets thrown
|
|
11
|
+
away and redone.
|
|
12
|
+
- Work in a loop: measure, find the cause, change one thing, measure again.
|
|
13
|
+
Always measure again; gains are hard to judge by eye.
|
|
17
14
|
|
|
18
|
-
|
|
19
|
-
current state should happen for the current frame.
|
|
15
|
+
## Dependencies Decide What Updates
|
|
20
16
|
|
|
21
|
-
A
|
|
17
|
+
A view is re-evaluated when something it depends on changes. Dependencies come
|
|
18
|
+
from:
|
|
22
19
|
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
20
|
+
- `@State` and `@Binding`
|
|
21
|
+
- `@Observable` models and `@ObservedObject`
|
|
22
|
+
- `@Environment` values
|
|
23
|
+
- identity supplied by containers such as `ForEach`, `List` and `Table`
|
|
26
24
|
|
|
27
|
-
|
|
25
|
+
Aim for dependencies that are exact, not just few:
|
|
28
26
|
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
|
|
32
|
-
-
|
|
27
|
+
- A row that shows one element should not depend on the whole collection.
|
|
28
|
+
- Values that change quickly (scroll offsets, timers, playback position) should
|
|
29
|
+
not travel through the environment, where they reach many views.
|
|
30
|
+
- Extract subviews so each one reads a smaller part of the state.
|
|
33
31
|
|
|
34
|
-
|
|
32
|
+
`Self._printChanges()` tells you which property changed, whether a parent
|
|
33
|
+
re-rendered the view, and whether the view reacts to state it does not
|
|
34
|
+
display. It is a debugging aid; do not ship it and do not treat it as a
|
|
35
|
+
profiler.
|
|
35
36
|
|
|
36
|
-
##
|
|
37
|
+
## Work That Does Not Belong in `body`
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
- `@State`
|
|
43
|
-
- `@Binding`
|
|
44
|
-
- `@Observable` / `@ObservedObject`
|
|
45
|
-
- `@Environment`
|
|
46
|
-
- container-derived identity (`ForEach`, `List`, `Table`)
|
|
47
|
-
|
|
48
|
-
The performance goal is not "fewer dependencies" in the abstract. The goal is
|
|
49
|
-
**precise dependencies** so only the view that needs to update actually updates.
|
|
50
|
-
|
|
51
|
-
### Practical implications
|
|
52
|
-
|
|
53
|
-
- Avoid a row depending on a whole collection if it only needs one element.
|
|
54
|
-
- Avoid broad environment-driven updates for fast-changing values.
|
|
55
|
-
- Extract subviews when a smaller view can read a smaller state surface.
|
|
56
|
-
|
|
57
|
-
### Debug-only dependency inspection
|
|
58
|
-
|
|
59
|
-
`Self._printChanges()` is useful in debug builds when you are not sure why a
|
|
60
|
-
view keeps updating.
|
|
61
|
-
|
|
62
|
-
Use it to answer:
|
|
63
|
-
|
|
64
|
-
- which property changed?
|
|
65
|
-
- which parent view re-rendered?
|
|
66
|
-
- is the view reacting to state it should not care about?
|
|
67
|
-
|
|
68
|
-
Do not treat `_printChanges()` output as a shipping-time profiling tool.
|
|
69
|
-
|
|
70
|
-
## Expensive body work
|
|
71
|
-
|
|
72
|
-
View bodies need to stay cheap.
|
|
73
|
-
|
|
74
|
-
Typical mistakes:
|
|
75
|
-
|
|
76
|
-
- string formatting in `body`
|
|
77
|
-
- array filtering and sorting in `body`
|
|
78
|
-
- expensive image work in `body`
|
|
79
|
-
- constructing large attributed strings during render
|
|
80
|
-
- initializing heavy models in-line with view creation
|
|
39
|
+
Frequent offenders: formatting strings, filtering and sorting, image
|
|
40
|
+
processing, building large attributed strings, and constructing heavy model
|
|
41
|
+
objects inline.
|
|
81
42
|
|
|
82
43
|
```swift
|
|
83
|
-
//
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
Text(numberFormatter.string(from: item.value as NSNumber) ?? "")
|
|
87
|
-
}
|
|
44
|
+
// Every evaluation filters, sorts and formats each row again.
|
|
45
|
+
List(orders.filter { $0.isOpen }.sorted { $0.date > $1.date }) { order in
|
|
46
|
+
Text(order.amount.formatted(.currency(code: "EUR")))
|
|
88
47
|
}
|
|
89
48
|
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
Text(item.formattedValue)
|
|
94
|
-
}
|
|
49
|
+
// The model prepares rows once, when its inputs change.
|
|
50
|
+
List(board.openRows) { row in
|
|
51
|
+
Text(row.amountText)
|
|
95
52
|
}
|
|
96
53
|
```
|
|
97
54
|
|
|
98
|
-
|
|
99
|
-
`body`.
|
|
100
|
-
|
|
101
|
-
## Identity rules for lists and tables
|
|
102
|
-
|
|
103
|
-
Identity is one of the biggest hidden performance levers in SwiftUI.
|
|
55
|
+
Do this preparation where data enters the model, not in the view.
|
|
104
56
|
|
|
105
|
-
|
|
57
|
+
## Identity for Lists and Tables
|
|
106
58
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
Inside `ForEach`, SwiftUI expects a predictable mapping between data elements and
|
|
113
|
-
rendered views.
|
|
114
|
-
|
|
115
|
-
Avoid patterns like:
|
|
59
|
+
- Ids must survive a refresh and a re-sort. When they churn, SwiftUI cannot
|
|
60
|
+
reuse rows, keep animations or diff efficiently.
|
|
61
|
+
- `ForEach` expects each element to map to a predictable view. Do not wrap rows
|
|
62
|
+
in `if item.isVisible { ... }`; iterate a collection that is already filtered
|
|
63
|
+
so every element yields exactly one row.
|
|
116
64
|
|
|
117
65
|
```swift
|
|
118
|
-
ForEach(
|
|
119
|
-
|
|
120
|
-
Row(item: item)
|
|
121
|
-
}
|
|
66
|
+
ForEach(shelf.visibleBooks) { book in
|
|
67
|
+
BookRow(book: book)
|
|
122
68
|
}
|
|
123
69
|
```
|
|
124
70
|
|
|
125
|
-
|
|
71
|
+
- Keep `AnyView` out of list rows that are rendered often.
|
|
72
|
+
- A `TableRow` resolves to exactly one row. Keep row structure predictable and
|
|
73
|
+
prefer the simpler `Table` initialisers when they fit.
|
|
126
74
|
|
|
127
|
-
|
|
128
|
-
ForEach(visibleItems) { item in
|
|
129
|
-
Row(item: item)
|
|
130
|
-
}
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
### Avoid `AnyView` in hot list rows
|
|
134
|
-
|
|
135
|
-
Type erasure can hide useful structural information and increase work in large
|
|
136
|
-
lists or tables.
|
|
137
|
-
|
|
138
|
-
### Table-specific note
|
|
139
|
-
|
|
140
|
-
`TableRow` resolves to a single row. Keep row structure predictable and use the
|
|
141
|
-
streamlined `Table` APIs when possible.
|
|
75
|
+
## Initialisation and Lifecycle
|
|
142
76
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
### Heavy model creation in view init/body
|
|
146
|
-
|
|
147
|
-
Keep view initialization lightweight. Start async work with `.task` or from a
|
|
148
|
-
model object.
|
|
77
|
+
Keep `init` cheap; SwiftUI can create view values many times. Start expensive
|
|
78
|
+
or asynchronous work from `.task` or from a model:
|
|
149
79
|
|
|
150
80
|
```swift
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// DO
|
|
157
|
-
struct DetailView: View {
|
|
158
|
-
@State private var model: DetailModel?
|
|
81
|
+
struct InvoiceDetail: View {
|
|
82
|
+
let invoiceID: Invoice.ID
|
|
83
|
+
@State private var loader: InvoiceLoader?
|
|
159
84
|
|
|
160
85
|
var body: some View {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
86
|
+
Group {
|
|
87
|
+
if let loader {
|
|
88
|
+
InvoiceSummary(loader: loader)
|
|
89
|
+
} else {
|
|
90
|
+
ProgressView()
|
|
164
91
|
}
|
|
92
|
+
}
|
|
93
|
+
.task(id: invoiceID) {
|
|
94
|
+
loader = await InvoiceLoader.prepare(for: invoiceID)
|
|
95
|
+
}
|
|
165
96
|
}
|
|
166
97
|
}
|
|
167
98
|
```
|
|
168
99
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
A computed property can still be body work if it runs during render. If it is
|
|
172
|
-
expensive, treat it like body work and precompute it.
|
|
173
|
-
|
|
174
|
-
## Debugging tools
|
|
175
|
-
|
|
176
|
-
### Instruments
|
|
177
|
-
|
|
178
|
-
Use Instruments for hangs, hitches, update counts, and expensive frames.
|
|
179
|
-
|
|
180
|
-
### `_printChanges()`
|
|
181
|
-
|
|
182
|
-
Use it in debug to inspect dependency behavior.
|
|
183
|
-
|
|
184
|
-
### Release-build validation
|
|
185
|
-
|
|
186
|
-
A debug build can make SwiftUI performance look worse or different than a
|
|
187
|
-
shipping build. Validate important performance changes in Release on device.
|
|
188
|
-
|
|
189
|
-
## Fix patterns
|
|
190
|
-
|
|
191
|
-
### Split views by dependency boundary
|
|
192
|
-
|
|
193
|
-
If one small piece of state changes frequently, isolate the subview that reads
|
|
194
|
-
it.
|
|
195
|
-
|
|
196
|
-
### Pre-filter and cache collections
|
|
100
|
+
The version to avoid stores `let loader = InvoiceLoader(id:)` as a property, so
|
|
101
|
+
the loader is rebuilt every time the parent creates the view.
|
|
197
102
|
|
|
198
|
-
|
|
103
|
+
An expensive computed property read during rendering counts as body work too.
|
|
104
|
+
Compute it ahead of time.
|
|
199
105
|
|
|
200
|
-
|
|
106
|
+
## Tools
|
|
201
107
|
|
|
202
|
-
|
|
203
|
-
|
|
108
|
+
Instruments shows hangs, hitches, update counts and expensive frames. Confirm
|
|
109
|
+
findings in a Release build on a device; a Debug build can look worse, or just
|
|
110
|
+
different.
|
|
204
111
|
|
|
205
|
-
|
|
112
|
+
## Fix Patterns
|
|
206
113
|
|
|
207
|
-
|
|
114
|
+
- Split views along dependency boundaries.
|
|
115
|
+
- Filter, map, sort and group before rendering.
|
|
116
|
+
- Keep reads of broad environment values out of hot paths; keep values that
|
|
117
|
+
change quickly local.
|
|
118
|
+
- Move formatters, bundle lookups and derived strings out of code that runs on
|
|
119
|
+
every update.
|
|
208
120
|
|
|
209
|
-
##
|
|
121
|
+
## Checking a Fix
|
|
210
122
|
|
|
211
|
-
After
|
|
123
|
+
After a change, check that:
|
|
212
124
|
|
|
213
|
-
- the
|
|
214
|
-
- update counts
|
|
215
|
-
- row identity
|
|
216
|
-
-
|
|
217
|
-
-
|
|
125
|
+
- the interaction is visibly smoother,
|
|
126
|
+
- update counts went down,
|
|
127
|
+
- row identity stays the same across reloads,
|
|
128
|
+
- animations still do what was intended,
|
|
129
|
+
- caching or splitting did not introduce a correctness bug.
|
|
218
130
|
|
|
219
|
-
A
|
|
220
|
-
real fix.
|
|
131
|
+
A change that breaks state ownership or animation is not a fix.
|
|
@@ -1,234 +1,128 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Profiling with the SwiftUI Instrument
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
Based on the WWDC25 session "Optimize SwiftUI performance with Instruments".
|
|
4
|
+
The SwiftUI Instrument described here ships with Instruments 26.
|
|
5
5
|
|
|
6
|
-
##
|
|
7
|
-
- When to use the SwiftUI Instrument
|
|
8
|
-
- Recommended capture setup
|
|
9
|
-
- Reading the SwiftUI timeline
|
|
10
|
-
- Workflow for long view body updates
|
|
11
|
-
- Workflow for frequent updates
|
|
12
|
-
- Cause and Effect Graph usage
|
|
13
|
-
- Common hotspots
|
|
14
|
-
- Fix patterns
|
|
15
|
-
- Re-measure checklist
|
|
6
|
+
## When It Is the Right Tool
|
|
16
7
|
|
|
17
|
-
|
|
8
|
+
Reach for it when the symptom points at view updates, layout, rendering or
|
|
9
|
+
state spreading too far:
|
|
18
10
|
|
|
19
|
-
|
|
20
|
-
|
|
11
|
+
- scrolling stutters,
|
|
12
|
+
- a push to a new screen pauses first,
|
|
13
|
+
- an animation is uneven although nothing obviously blocks the main thread,
|
|
14
|
+
- a timer or observable model triggers far more updates than expected.
|
|
21
15
|
|
|
22
|
-
|
|
16
|
+
When the whole app freezes and nothing points at the UI, start with Hangs or
|
|
17
|
+
Time Profiler and come to the SwiftUI lanes afterwards.
|
|
23
18
|
|
|
24
|
-
|
|
25
|
-
- pushing a destination causes a pause during view construction
|
|
26
|
-
- an animation feels inconsistent even without obvious main-thread blocking
|
|
27
|
-
- a timer or observable object causes too many updates
|
|
19
|
+
## Capture Setup
|
|
28
20
|
|
|
29
|
-
|
|
30
|
-
|
|
21
|
+
- Release build on a real device.
|
|
22
|
+
- A sequence you can repeat exactly.
|
|
23
|
+
- As little debug logging as possible.
|
|
24
|
+
- Enough repetitions that a pattern shows.
|
|
31
25
|
|
|
32
|
-
|
|
26
|
+
A good default set: the SwiftUI Instrument plus Time Profiler, and Hangs or
|
|
27
|
+
Animation Hitches when the symptom calls for it.
|
|
33
28
|
|
|
34
|
-
|
|
29
|
+
## The SwiftUI Lanes
|
|
35
30
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
31
|
+
| Lane | What it tells you |
|
|
32
|
+
|------|-------------------|
|
|
33
|
+
| Update Groups | Coarse buckets of work. Shows bursts even when no single update is slow. |
|
|
34
|
+
| Long View Body Updates | `body` evaluations that took too long. Orange is worth a look, red is clearly too slow. |
|
|
35
|
+
| Long Platform View Updates | Time in hosted UIKit or AppKit views: `UIViewRepresentable`, `UIViewControllerRepresentable`, heavy list or table bridging, embedded media or web views. |
|
|
36
|
+
| Other Long Updates | Text layout, geometry, list diffing and update coordination. |
|
|
41
37
|
|
|
42
|
-
|
|
38
|
+
## Workflow: One Update Is Too Slow
|
|
43
39
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
### Update Groups
|
|
53
|
-
|
|
54
|
-
High-level buckets of SwiftUI work over time. Useful for spotting bursts of
|
|
55
|
-
activity even when no single update is individually slow.
|
|
56
|
-
|
|
57
|
-
### Long View Body Updates
|
|
58
|
-
|
|
59
|
-
Use this lane when a view `body` itself is expensive.
|
|
60
|
-
|
|
61
|
-
Interpretation:
|
|
62
|
-
|
|
63
|
-
- orange indicates notable cost
|
|
64
|
-
- red indicates clearly too-slow view updates
|
|
65
|
-
|
|
66
|
-
### Long Platform View Updates
|
|
67
|
-
|
|
68
|
-
This usually points to UIKit/AppKit work hosted inside SwiftUI, including:
|
|
69
|
-
|
|
70
|
-
- `UIViewRepresentable`
|
|
71
|
-
- `UIViewControllerRepresentable`
|
|
72
|
-
- heavy `List`/table bridging
|
|
73
|
-
- embedded media or web views
|
|
74
|
-
|
|
75
|
-
### Other Long Updates
|
|
76
|
-
|
|
77
|
-
Catches expensive work outside pure body computation, such as:
|
|
78
|
-
|
|
79
|
-
- text layout
|
|
80
|
-
- geometry
|
|
81
|
-
- list diffing
|
|
82
|
-
- update coordination
|
|
83
|
-
|
|
84
|
-
## Workflow for long view body updates
|
|
85
|
-
|
|
86
|
-
### 1. Find a red or orange update
|
|
87
|
-
|
|
88
|
-
Start with one obviously expensive update rather than a long trace window.
|
|
89
|
-
|
|
90
|
-
### 2. Set inspection range
|
|
91
|
-
|
|
92
|
-
Select the update window so Time Profiler aligns with the same time slice.
|
|
93
|
-
|
|
94
|
-
### 3. Inspect the call tree or flame graph
|
|
95
|
-
|
|
96
|
-
Look for work that should not be happening during body evaluation.
|
|
97
|
-
|
|
98
|
-
Common surprises:
|
|
99
|
-
|
|
100
|
-
- formatter allocation
|
|
101
|
-
- sorting or filtering collections
|
|
102
|
-
- image decoding
|
|
103
|
-
- string building
|
|
104
|
-
- model initialization
|
|
105
|
-
- synchronous persistence reads
|
|
106
|
-
|
|
107
|
-
### 4. Move heavy work out of `body`
|
|
40
|
+
1. Pick a single red or orange update, not a long stretch of timeline.
|
|
41
|
+
2. Set the inspection range to that update so Time Profiler shows the same
|
|
42
|
+
interval.
|
|
43
|
+
3. Read the call tree or flame graph. Typical findings: a formatter being
|
|
44
|
+
created, sorting or filtering, image decoding, string building, model
|
|
45
|
+
construction, a synchronous read from storage.
|
|
46
|
+
4. Move that work out of `body`:
|
|
108
47
|
|
|
109
48
|
```swift
|
|
110
|
-
//
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
49
|
+
// Before: runs on every evaluation.
|
|
50
|
+
Text(playlist.tracks.sorted { $0.position < $1.position }
|
|
51
|
+
.map(\.title).joined(separator: ", "))
|
|
114
52
|
|
|
115
|
-
//
|
|
116
|
-
|
|
117
|
-
Text(viewModel.joinedTitles)
|
|
118
|
-
}
|
|
53
|
+
// After: the model keeps the joined string current.
|
|
54
|
+
Text(playlist.trackSummary)
|
|
119
55
|
```
|
|
120
56
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
If the trace still shows long view body updates, the expensive work likely just
|
|
124
|
-
moved into a child view or another dependency path.
|
|
57
|
+
5. Record again. If long updates remain, the work probably moved into a child
|
|
58
|
+
view or reaches the view through another dependency.
|
|
125
59
|
|
|
126
|
-
## Workflow
|
|
60
|
+
## Workflow: Too Many Updates
|
|
127
61
|
|
|
128
|
-
|
|
129
|
-
update is
|
|
62
|
+
A screen can feel slow because it updates constantly, even if every single
|
|
63
|
+
update is cheap.
|
|
130
64
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
Look
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
A screen doing cheap work 200 times can still feel worse than one doing one
|
|
138
|
-
moderately expensive update.
|
|
139
|
-
|
|
140
|
-
### 3. Open Cause and Effect Graph
|
|
141
|
-
|
|
142
|
-
This is often the fastest way to answer:
|
|
143
|
-
|
|
144
|
-
- what changed?
|
|
145
|
-
- which dependency triggered the update?
|
|
146
|
-
- why did that change fan out to unrelated views?
|
|
147
|
-
|
|
148
|
-
### 4. Narrow the dependency scope
|
|
65
|
+
- Start with Update Groups: look for long active stretches full of updates with
|
|
66
|
+
no red spikes.
|
|
67
|
+
- Look at counts, not only durations. Cheap work done 200 times can feel worse
|
|
68
|
+
than one moderately expensive update.
|
|
69
|
+
- Open the Cause and Effect Graph to see what changed, which dependency fired
|
|
70
|
+
and why the update spread.
|
|
149
71
|
|
|
150
72
|
Typical fixes:
|
|
73
|
+
- extract subviews that read only the state they show,
|
|
74
|
+
- replace a broad shared model with narrower derived state,
|
|
75
|
+
- stop passing fast-changing data through the environment,
|
|
76
|
+
- split a large `@Observable` model whose unrelated properties change together.
|
|
151
77
|
|
|
152
|
-
|
|
153
|
-
- replace broad shared models with narrower derived state
|
|
154
|
-
- avoid environment values for fast-changing data
|
|
155
|
-
- split large `@Observable` models if unrelated properties change together
|
|
156
|
-
|
|
157
|
-
## Cause and Effect Graph usage
|
|
158
|
-
|
|
159
|
-
Use it when backtraces are misleading.
|
|
160
|
-
|
|
161
|
-
SwiftUI is declarative, so the expensive work may not appear near the code that
|
|
162
|
-
caused the update chain.
|
|
163
|
-
|
|
164
|
-
Good uses:
|
|
165
|
-
|
|
166
|
-
- a selection change updates an unrelated sidebar
|
|
167
|
-
- a timer invalidates a full list
|
|
168
|
-
- geometry updates ripple through many subviews
|
|
169
|
-
- a global favorites model causes every row to re-evaluate
|
|
170
|
-
|
|
171
|
-
## Common hotspots
|
|
78
|
+
## Cause and Effect Graph
|
|
172
79
|
|
|
173
|
-
|
|
80
|
+
Use it when backtraces point in the wrong direction; in a declarative UI the
|
|
81
|
+
code that did the work is often far from the code that caused it. Good uses:
|
|
174
82
|
|
|
175
|
-
|
|
176
|
-
|
|
83
|
+
- changing the selection also updates an unrelated sidebar,
|
|
84
|
+
- a timer invalidates an entire list,
|
|
85
|
+
- a geometry change ripples through many subviews,
|
|
86
|
+
- a global favourites model makes every row re-evaluate.
|
|
177
87
|
|
|
178
|
-
|
|
88
|
+
## Hot Spots and How to Fix Them
|
|
179
89
|
|
|
180
|
-
|
|
90
|
+
- Never build `DateFormatter`, `NumberFormatter` or `MeasurementFormatter` in
|
|
91
|
+
`body` or per row.
|
|
92
|
+
- Filter collections before rendering; do not route raw geometry through a
|
|
93
|
+
broadly observed model.
|
|
94
|
+
- Unstable identity and a row count that changes between passes make lists
|
|
95
|
+
and tables expensive.
|
|
96
|
+
- Check representables for configuration repeated on every
|
|
97
|
+
`updateUIView` or `updateUIViewController` call.
|
|
181
98
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
Avoid feeding raw geometry values through broad observable state.
|
|
185
|
-
|
|
186
|
-
### Identity instability
|
|
187
|
-
|
|
188
|
-
Lists and tables get expensive when identity changes or row counts vary in ways
|
|
189
|
-
SwiftUI cannot efficiently diff.
|
|
190
|
-
|
|
191
|
-
### Platform view bridging
|
|
192
|
-
|
|
193
|
-
Audit representables for repeated configuration work in `updateUIView` or
|
|
194
|
-
`updateUIViewController`.
|
|
195
|
-
|
|
196
|
-
## Fix patterns
|
|
197
|
-
|
|
198
|
-
### Cache presentation data
|
|
99
|
+
Cache presentation values in a model:
|
|
199
100
|
|
|
200
101
|
```swift
|
|
201
102
|
@Observable
|
|
202
|
-
final class
|
|
203
|
-
var
|
|
103
|
+
final class RunSummary {
|
|
104
|
+
private(set) var distanceText = ""
|
|
204
105
|
|
|
205
|
-
func update(
|
|
206
|
-
|
|
106
|
+
func update(metres: Double, using formatter: MeasurementFormatter) {
|
|
107
|
+
let distance = Measurement<UnitLength>(value: metres, unit: .meters)
|
|
108
|
+
distanceText = formatter.string(from: distance)
|
|
207
109
|
}
|
|
208
110
|
}
|
|
209
111
|
```
|
|
210
112
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
Only mutate the hosted platform view when input values actually changed.
|
|
218
|
-
|
|
219
|
-
### Gate noisy signals
|
|
220
|
-
|
|
221
|
-
A geometry or timer signal may need thresholding, debouncing, or coalescing.
|
|
222
|
-
|
|
223
|
-
## Re-measure checklist
|
|
113
|
+
- Scope observable dependencies so a row reads only its own state.
|
|
114
|
+
- Make representable updates idempotent: touch the hosted view only when an
|
|
115
|
+
input actually changed.
|
|
116
|
+
- Tame noisy geometry or timer signals with a threshold, debouncing or
|
|
117
|
+
coalescing.
|
|
224
118
|
|
|
225
|
-
|
|
119
|
+
## Measuring Again
|
|
226
120
|
|
|
227
|
-
-
|
|
228
|
-
-
|
|
229
|
-
-
|
|
230
|
-
-
|
|
231
|
-
-
|
|
121
|
+
- Record the same flow again.
|
|
122
|
+
- Compare how many updates happen, not only how long they take.
|
|
123
|
+
- Confirm there are fewer hitches.
|
|
124
|
+
- Confirm no new Long Platform View Updates appeared.
|
|
125
|
+
- Check in Release on a device.
|
|
232
126
|
|
|
233
|
-
If
|
|
234
|
-
|
|
127
|
+
If one screen gets faster while updates rise somewhere else, keep following the
|
|
128
|
+
dependency graph until the fan-out really goes down.
|