@mmerterden/multi-agent-pipeline 20.7.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 +9 -0
- package/LICENSE +0 -10
- package/docs/facts.json +1 -1
- package/manifest.json +266 -267
- package/package.json +2 -2
- package/pipeline/scripts/_notices.mjs +1 -1
- package/pipeline/skills/.skill-manifest.json +68 -68
- package/pipeline/skills/shared/README.md +70 -70
- 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/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/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/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/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/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/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/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/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-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-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-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/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/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/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/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/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/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/tipkit/SKILL.md +220 -335
- package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
- 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/weatherkit/SKILL.md +152 -310
- package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
- 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,423 +1,334 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: core-motion
|
|
3
|
-
description: "
|
|
3
|
+
description: "Core Motion on iOS and watchOS: accelerometer, gyroscope, magnetometer, fused device motion and reference frames, CMPedometer steps, distance and floors, activity recognition, barometric and absolute altitude, AirPods head tracking, batched high-rate workout capture, watchOS water submersion and depth. Use when building tilt controls, step counters, activity-aware features, altitude tracking or other motion interactions."
|
|
4
4
|
metadata:
|
|
5
|
-
source:
|
|
5
|
+
source: multi-agent-pipeline
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
#
|
|
8
|
+
# Core Motion
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
Core Motion turns the accelerometer, gyroscope, magnetometer and barometer into
|
|
11
|
+
data an app can act on. It fuses the raw sensors into a single device-motion
|
|
12
|
+
stream and also ships higher-level services: a pedometer, an activity
|
|
13
|
+
classifier and an altimeter. Fitness, navigation, games and accessibility
|
|
14
|
+
features all build on it. Examples assume Swift 6.3 and iOS 26 or later.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Longer SwiftUI services, batched sensors, head tracking, a step dashboard,
|
|
17
|
+
activity-driven modes and dive support live in the
|
|
18
|
+
[motion patterns reference](references/motion-patterns.md).
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
- [CMPedometer: Step and Distance Data](#cmpedometer-step-and-distance-data)
|
|
22
|
-
- [CMMotionActivityManager: Activity Recognition](#cmmotionactivitymanager-activity-recognition)
|
|
23
|
-
- [CMAltimeter: Altitude Data](#cmaltimeter-altitude-data)
|
|
24
|
-
- [Update Intervals and Battery](#update-intervals-and-battery)
|
|
25
|
-
- [Common Mistakes](#common-mistakes)
|
|
26
|
-
- [Review Checklist](#review-checklist)
|
|
27
|
-
- [References](#references)
|
|
20
|
+
Covers: activity recognition (walking, running, driving, cycling) and
|
|
21
|
+
distance and floor counts from `CMPedometer`. Not for HealthKit workout
|
|
22
|
+
sessions or SensorKit research data.
|
|
28
23
|
|
|
29
24
|
## Setup
|
|
30
25
|
|
|
31
|
-
###
|
|
26
|
+
### Usage string
|
|
32
27
|
|
|
33
|
-
|
|
34
|
-
why
|
|
35
|
-
|
|
36
|
-
```xml
|
|
37
|
-
<key>NSMotionUsageDescription</key>
|
|
38
|
-
<string>This app uses motion data to track your activity.</string>
|
|
39
|
-
```
|
|
28
|
+
Info.plist must carry `NSMotionUsageDescription`, a sentence telling the user
|
|
29
|
+
why the app reads motion. If the key is absent, the process is terminated the first
|
|
30
|
+
time it touches a protected motion API.
|
|
40
31
|
|
|
41
32
|
### Authorization
|
|
42
33
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
`
|
|
46
|
-
`CMMotionManager`
|
|
47
|
-
|
|
48
|
-
|
|
34
|
+
Several managers expose an authorization status: `CMPedometer`,
|
|
35
|
+
`CMMotionActivityManager`, `CMAltimeter`, `CMHeadphoneMotionManager`,
|
|
36
|
+
`CMBatchedSensorManager` and `CMWaterSubmersionManager`. Read it before you
|
|
37
|
+
start updates. The raw `CMMotionManager` streams (accelerometer, gyroscope,
|
|
38
|
+
device motion) have no request call at all; ship the usage string anyway and
|
|
39
|
+
treat errors delivered to the handler as the failure signal.
|
|
49
40
|
|
|
50
41
|
```swift
|
|
51
42
|
import CoreMotion
|
|
52
43
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
case .notDetermined:
|
|
56
|
-
// Will prompt on first use
|
|
57
|
-
break
|
|
58
|
-
case .authorized:
|
|
59
|
-
break
|
|
60
|
-
case .restricted, .denied:
|
|
61
|
-
// Direct user to Settings
|
|
62
|
-
break
|
|
63
|
-
@unknown default:
|
|
64
|
-
break
|
|
44
|
+
enum MotionAccess {
|
|
45
|
+
case ready, willPrompt, blocked
|
|
65
46
|
}
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
## CMMotionManager: Sensor Data
|
|
69
|
-
|
|
70
|
-
Create exactly **one** `CMMotionManager` per app. Multiple instances degrade
|
|
71
|
-
sensor update rates.
|
|
72
47
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
48
|
+
func pedometerAccess() -> MotionAccess {
|
|
49
|
+
switch CMPedometer.authorizationStatus() {
|
|
50
|
+
case .authorized: return .ready
|
|
51
|
+
case .notDetermined: return .willPrompt // system asks on first query
|
|
52
|
+
case .denied, .restricted: return .blocked // point the user at Settings
|
|
53
|
+
@unknown default: return .blocked
|
|
54
|
+
}
|
|
55
|
+
}
|
|
77
56
|
```
|
|
78
57
|
|
|
79
|
-
|
|
58
|
+
## CMMotionManager: raw sensors
|
|
80
59
|
|
|
81
|
-
|
|
82
|
-
|
|
60
|
+
Create one `CMMotionManager` for the whole app. Extra instances compete for
|
|
61
|
+
the same hardware and every one of them receives updates at a lower rate.
|
|
83
62
|
|
|
84
|
-
|
|
63
|
+
### Accelerometer
|
|
85
64
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
65
|
+
```swift
|
|
66
|
+
@MainActor let sensors = CMMotionManager()
|
|
67
|
+
|
|
68
|
+
@MainActor func beginShakeDetection(onShake: @escaping () -> Void) {
|
|
69
|
+
guard sensors.isAccelerometerAvailable else { return }
|
|
70
|
+
sensors.accelerometerUpdateInterval = 1.0 / 60.0
|
|
71
|
+
sensors.startAccelerometerUpdates(to: .main) { sample, error in
|
|
72
|
+
guard let a = sample?.acceleration, error == nil else { return }
|
|
73
|
+
let magnitude = (a.x * a.x + a.y * a.y + a.z * a.z).squareRoot()
|
|
74
|
+
if magnitude > 2.5 { onShake() }
|
|
75
|
+
}
|
|
89
76
|
}
|
|
90
77
|
|
|
91
|
-
|
|
92
|
-
motionManager.stopAccelerometerUpdates()
|
|
78
|
+
@MainActor func endShakeDetection() { sensors.stopAccelerometerUpdates() }
|
|
93
79
|
```
|
|
94
80
|
|
|
95
|
-
|
|
81
|
+
`CMMotionManager` is not `Sendable`, so Swift 6 rejects a plain global `let` of
|
|
82
|
+
it ("not concurrency-safe"). The shared instance is therefore `@MainActor`, and
|
|
83
|
+
so is every function that touches it; the same goes for the pedometer,
|
|
84
|
+
activity and altimeter globals below. Handlers queued on `.main` run on the
|
|
85
|
+
main thread either way.
|
|
96
86
|
|
|
97
|
-
|
|
98
|
-
guard motionManager.isGyroAvailable else { return }
|
|
99
|
-
|
|
100
|
-
motionManager.gyroUpdateInterval = 1.0 / 60.0
|
|
87
|
+
### Gyroscope
|
|
101
88
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
89
|
+
```swift
|
|
90
|
+
@MainActor func beginSpinTracking() {
|
|
91
|
+
guard sensors.isGyroAvailable else { return }
|
|
92
|
+
sensors.gyroUpdateInterval = 1.0 / 30.0
|
|
93
|
+
sensors.startGyroUpdates(to: .main) { sample, error in
|
|
94
|
+
guard let spin = sample?.rotationRate, error == nil else { return }
|
|
95
|
+
_ = spin.z // radians per second around each axis
|
|
96
|
+
}
|
|
105
97
|
}
|
|
106
98
|
|
|
107
|
-
|
|
99
|
+
@MainActor func endSpinTracking() { sensors.stopGyroUpdates() }
|
|
108
100
|
```
|
|
109
101
|
|
|
110
|
-
### Polling
|
|
102
|
+
### Polling from a game loop
|
|
111
103
|
|
|
112
|
-
|
|
104
|
+
A game that already runs a per-frame loop can skip the handler. Call the
|
|
105
|
+
start method with no arguments and read the latest value when drawing.
|
|
113
106
|
|
|
114
107
|
```swift
|
|
115
|
-
|
|
108
|
+
sensors.startAccelerometerUpdates()
|
|
116
109
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
// Move player based on tilt
|
|
110
|
+
@MainActor func tick() { // called from a display link or render loop
|
|
111
|
+
guard let latest = sensors.accelerometerData else { return }
|
|
112
|
+
applyTilt(x: latest.acceleration.x)
|
|
121
113
|
}
|
|
122
114
|
```
|
|
123
115
|
|
|
124
|
-
##
|
|
116
|
+
## Device motion
|
|
125
117
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
118
|
+
`CMDeviceMotion` blends accelerometer, gyroscope and magnetometer readings.
|
|
119
|
+
Each sample carries `attitude`, `userAcceleration` (gravity already removed),
|
|
120
|
+
`gravity`, `rotationRate`, a calibrated `magneticField` and `heading`, which is
|
|
121
|
+
reported in degrees relative to the active reference frame.
|
|
129
122
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
123
|
+
Never hard-code a reference frame. Ask
|
|
124
|
+
`CMMotionManager.availableAttitudeReferenceFrames()` at runtime and fall back
|
|
125
|
+
to `.xArbitraryZVertical`.
|
|
133
126
|
|
|
134
127
|
```swift
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
let
|
|
138
|
-
let frame: CMAttitudeReferenceFrame =
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
let gravity = motion.gravity
|
|
153
|
-
let heading = motion.heading // degrees relative to the current frame
|
|
154
|
-
|
|
155
|
-
print("Pitch: \(attitude.pitch), Roll: \(attitude.roll)")
|
|
128
|
+
@MainActor func beginOrientationTracking() {
|
|
129
|
+
guard sensors.isDeviceMotionAvailable else { return }
|
|
130
|
+
let offered = CMMotionManager.availableAttitudeReferenceFrames()
|
|
131
|
+
let frame: CMAttitudeReferenceFrame =
|
|
132
|
+
offered.contains(.xArbitraryCorrectedZVertical)
|
|
133
|
+
? .xArbitraryCorrectedZVertical
|
|
134
|
+
: .xArbitraryZVertical
|
|
135
|
+
|
|
136
|
+
sensors.deviceMotionUpdateInterval = 1.0 / 30.0
|
|
137
|
+
sensors.startDeviceMotionUpdates(using: frame, to: .main) { reading, failure in
|
|
138
|
+
guard let reading, failure == nil else { return }
|
|
139
|
+
let tilt = reading.attitude // roll, pitch, yaw in radians
|
|
140
|
+
let push = reading.userAcceleration // in g, gravity removed
|
|
141
|
+
let down = reading.gravity
|
|
142
|
+
let degrees = reading.heading
|
|
143
|
+
_ = (tilt.roll, push.z, down.y, degrees)
|
|
144
|
+
}
|
|
156
145
|
}
|
|
157
146
|
|
|
158
|
-
|
|
147
|
+
@MainActor func endOrientationTracking() { sensors.stopDeviceMotionUpdates() }
|
|
159
148
|
```
|
|
160
149
|
|
|
161
|
-
###
|
|
150
|
+
### Reference frames
|
|
162
151
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
`
|
|
167
|
-
|
|
152
|
+
| Frame | X axis | Needs | Good for |
|
|
153
|
+
|---|---|---|---|
|
|
154
|
+
| `.xArbitraryZVertical` | wherever the device pointed at start; the default | nothing extra | most games, tilt |
|
|
155
|
+
| `.xArbitraryCorrectedZVertical` | same, with gyro drift corrected over time | nothing extra | longer tilt sessions |
|
|
156
|
+
| `.xMagneticNorthZVertical` | magnetic north | magnetometer | compass-like UI |
|
|
157
|
+
| `.xTrueNorthZVertical` | true north | magnetometer and location | geographic alignment |
|
|
168
158
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
| `.xArbitraryCorrectedZVertical` | Same as above, corrected for gyro drift over time. |
|
|
173
|
-
| `.xMagneticNorthZVertical` | X points to magnetic north. Requires magnetometer. |
|
|
174
|
-
| `.xTrueNorthZVertical` | X points to true north. Requires magnetometer + location. |
|
|
159
|
+
For plain tilt, pick one of the two arbitrary frames: they do not depend on the
|
|
160
|
+
magnetometer or on location. Before asking for a north frame, confirm
|
|
161
|
+
`availableAttitudeReferenceFrames().contains(...)` includes it.
|
|
175
162
|
|
|
176
|
-
|
|
163
|
+
## CMPedometer
|
|
177
164
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
if available.contains(.xTrueNorthZVertical) {
|
|
181
|
-
// Safe to use true north
|
|
182
|
-
}
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
## CMPedometer: Step and Distance Data
|
|
186
|
-
|
|
187
|
-
`CMPedometer` provides step counts, distance, pace, cadence, and floor counts.
|
|
165
|
+
The pedometer reports step count, distance, pace, cadence and floors climbed
|
|
166
|
+
or descended.
|
|
188
167
|
|
|
189
168
|
```swift
|
|
190
|
-
let
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
print("Floors up: \(data.floorsAscended?.intValue ?? 0)")
|
|
169
|
+
@MainActor let stepCounter = CMPedometer()
|
|
170
|
+
|
|
171
|
+
@MainActor func loadTodaysWalk() {
|
|
172
|
+
guard CMPedometer.isStepCountingAvailable() else { return }
|
|
173
|
+
let midnight = Calendar.current.startOfDay(for: .now)
|
|
174
|
+
stepCounter.queryPedometerData(from: midnight, to: .now) { summary, error in
|
|
175
|
+
guard let summary, error == nil else { return }
|
|
176
|
+
let steps = summary.numberOfSteps.intValue
|
|
177
|
+
let meters = summary.distance?.doubleValue ?? 0
|
|
178
|
+
let climbed = summary.floorsAscended?.intValue ?? 0
|
|
179
|
+
_ = (steps, meters, climbed)
|
|
180
|
+
}
|
|
203
181
|
}
|
|
204
182
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
183
|
+
@MainActor func followLiveSteps(since start: Date) {
|
|
184
|
+
stepCounter.startUpdates(from: start) { summary, _ in
|
|
185
|
+
_ = summary?.numberOfSteps
|
|
186
|
+
}
|
|
209
187
|
}
|
|
210
188
|
|
|
211
|
-
|
|
212
|
-
pedometer.stopUpdates()
|
|
189
|
+
@MainActor func stopLiveSteps() { stepCounter.stopUpdates() }
|
|
213
190
|
```
|
|
214
191
|
|
|
215
|
-
|
|
192
|
+
Each metric has its own capability check:
|
|
216
193
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
| `isPaceAvailable()` | Pace data |
|
|
223
|
-
| `isCadenceAvailable()` | Cadence data |
|
|
194
|
+
- `isStepCountingAvailable()` - step hardware present
|
|
195
|
+
- `isDistanceAvailable()` - distance estimates
|
|
196
|
+
- `isFloorCountingAvailable()` - floors, which need a barometer
|
|
197
|
+
- `isPaceAvailable()` - pace
|
|
198
|
+
- `isCadenceAvailable()` - cadence
|
|
224
199
|
|
|
225
|
-
## CMMotionActivityManager
|
|
200
|
+
## CMMotionActivityManager
|
|
226
201
|
|
|
227
|
-
|
|
202
|
+
The classifier reports stationary, walking, running, cycling and automotive
|
|
203
|
+
states.
|
|
228
204
|
|
|
229
205
|
```swift
|
|
230
|
-
let
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
} else if activity.running {
|
|
241
|
-
print("Running")
|
|
242
|
-
} else if activity.automotive {
|
|
243
|
-
print("In vehicle")
|
|
244
|
-
} else if activity.cycling {
|
|
245
|
-
print("Cycling")
|
|
246
|
-
} else if activity.stationary {
|
|
247
|
-
print("Stationary")
|
|
206
|
+
@MainActor let classifier = CMMotionActivityManager()
|
|
207
|
+
|
|
208
|
+
@MainActor func watchMovement() {
|
|
209
|
+
guard CMMotionActivityManager.isActivityAvailable() else { return }
|
|
210
|
+
classifier.startActivityUpdates(to: .main) { activity in
|
|
211
|
+
guard let activity else { return }
|
|
212
|
+
let flags = (activity.walking, activity.running, activity.cycling,
|
|
213
|
+
activity.automotive, activity.stationary)
|
|
214
|
+
let certainty = activity.confidence.rawValue // 0 low, 1 medium, 2 high
|
|
215
|
+
_ = (flags, certainty)
|
|
248
216
|
}
|
|
249
217
|
}
|
|
250
218
|
|
|
251
|
-
|
|
219
|
+
@MainActor func stopWatchingMovement() { classifier.stopActivityUpdates() }
|
|
252
220
|
```
|
|
253
221
|
|
|
254
|
-
###
|
|
222
|
+
### Looking back
|
|
255
223
|
|
|
256
224
|
```swift
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
from:
|
|
261
|
-
|
|
262
|
-
to: .main
|
|
263
|
-
) { activities, error in
|
|
264
|
-
guard let activities else { return }
|
|
265
|
-
for activity in activities {
|
|
266
|
-
print("\(activity.startDate): walking=\(activity.walking)")
|
|
225
|
+
@MainActor func lastDayOfActivity() {
|
|
226
|
+
let end = Date.now
|
|
227
|
+
let start = end.addingTimeInterval(-24 * 60 * 60)
|
|
228
|
+
classifier.queryActivityStarting(from: start, to: end, to: .main) { entries, _ in
|
|
229
|
+
for entry in entries ?? [] { _ = entry.startDate }
|
|
267
230
|
}
|
|
268
231
|
}
|
|
269
232
|
```
|
|
270
233
|
|
|
271
|
-
## CMAltimeter
|
|
272
|
-
|
|
273
|
-
Altimeter access is covered by `NSMotionUsageDescription`; handle denied motion
|
|
274
|
-
access through unavailable data and update-handler errors.
|
|
234
|
+
## CMAltimeter
|
|
275
235
|
|
|
276
|
-
|
|
277
|
-
|
|
236
|
+
The same `NSMotionUsageDescription` covers the altimeter. When the user denies
|
|
237
|
+
motion access, altitude simply stops being available and the handlers receive
|
|
238
|
+
errors.
|
|
278
239
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
altimeter.startRelativeAltitudeUpdates(to: .main) { data, error in
|
|
282
|
-
guard let data else { return }
|
|
283
|
-
print("Relative altitude: \(data.relativeAltitude) meters")
|
|
284
|
-
print("Pressure: \(data.pressure) kPa")
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
altimeter.stopRelativeAltitudeUpdates()
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
Absolute altitude is altitude relative to sea level, not GPS-based altitude.
|
|
291
|
-
First check availability. Absolute altitude is available only on supported
|
|
292
|
-
hardware such as iPhone 12 or later and Apple Watch Series 6, Apple Watch SE, or
|
|
293
|
-
later.
|
|
240
|
+
### Relative altitude
|
|
294
241
|
|
|
295
242
|
```swift
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
guard
|
|
300
|
-
|
|
243
|
+
@MainActor let barometer = CMAltimeter()
|
|
244
|
+
|
|
245
|
+
@MainActor func trackClimb() {
|
|
246
|
+
guard CMAltimeter.isRelativeAltitudeAvailable() else { return }
|
|
247
|
+
barometer.startRelativeAltitudeUpdates(to: .main) { reading, error in
|
|
248
|
+
guard let reading, error == nil else { return }
|
|
249
|
+
let gainedMeters = reading.relativeAltitude.doubleValue
|
|
250
|
+
let kilopascals = reading.pressure.doubleValue
|
|
251
|
+
_ = (gainedMeters, kilopascals)
|
|
252
|
+
}
|
|
301
253
|
}
|
|
302
254
|
|
|
303
|
-
|
|
255
|
+
@MainActor func stopClimb() { barometer.stopRelativeAltitudeUpdates() }
|
|
304
256
|
```
|
|
305
257
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
| Interval | Hz | Use Case | Battery Impact |
|
|
309
|
-
|---|---|---|---|
|
|
310
|
-
| `1.0 / 10.0` | 10 | UI orientation | Low |
|
|
311
|
-
| `1.0 / 30.0` | 30 | Casual games | Moderate |
|
|
312
|
-
| `1.0 / 60.0` | 60 | Action games | High |
|
|
313
|
-
| `1.0 / 100.0` | 100 | Max rate (iPhone) | Very High |
|
|
314
|
-
|
|
315
|
-
Use the lowest frequency that meets your needs. Do not assume a fixed maximum
|
|
316
|
-
sample rate across devices. For high-frequency workout motion, use
|
|
317
|
-
`CMBatchedSensorManager` where supported and read its reported
|
|
318
|
-
`accelerometerDataFrequency` or `deviceMotionDataFrequency` instead of assigning
|
|
319
|
-
those read-only properties.
|
|
258
|
+
### Absolute altitude
|
|
320
259
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
```swift
|
|
326
|
-
// WRONG -- degrades update rates for all instances
|
|
327
|
-
class ViewA { let motion = CMMotionManager() }
|
|
328
|
-
class ViewB { let motion = CMMotionManager() }
|
|
329
|
-
|
|
330
|
-
// CORRECT -- single instance, shared across the app
|
|
331
|
-
@Observable
|
|
332
|
-
final class MotionService {
|
|
333
|
-
static let shared = MotionService()
|
|
334
|
-
let manager = CMMotionManager()
|
|
335
|
-
}
|
|
336
|
-
```
|
|
337
|
-
|
|
338
|
-
### DON'T: Skip sensor availability checks
|
|
260
|
+
Absolute altitude is height above sea level estimated by the system, not a GPS
|
|
261
|
+
fix. Supported hardware starts at iPhone 12 on the phone side; on the wrist it
|
|
262
|
+
starts at Apple Watch Series 6 and Apple Watch SE. Always gate on `isAbsoluteAltitudeAvailable()`.
|
|
339
263
|
|
|
340
264
|
```swift
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
showUnsupportedMessage()
|
|
347
|
-
return
|
|
348
|
-
}
|
|
349
|
-
motionManager.startGyroUpdates(to: .main) { data, _ in }
|
|
350
|
-
```
|
|
351
|
-
|
|
352
|
-
### DON'T: Forget to stop updates
|
|
353
|
-
|
|
354
|
-
```swift
|
|
355
|
-
// WRONG -- updates keep running, draining battery
|
|
356
|
-
class MotionVC: UIViewController {
|
|
357
|
-
override func viewDidAppear(_ animated: Bool) {
|
|
358
|
-
super.viewDidAppear(animated)
|
|
359
|
-
motionManager.startAccelerometerUpdates(to: .main) { _, _ in }
|
|
265
|
+
@MainActor func trackElevation() {
|
|
266
|
+
guard CMAltimeter.isAbsoluteAltitudeAvailable() else { return }
|
|
267
|
+
barometer.startAbsoluteAltitudeUpdates(to: .main) { reading, error in
|
|
268
|
+
guard let reading, error == nil else { return }
|
|
269
|
+
_ = (reading.altitude, reading.accuracy) // both in meters
|
|
360
270
|
}
|
|
361
|
-
// Missing viewDidDisappear stop!
|
|
362
271
|
}
|
|
363
272
|
|
|
364
|
-
|
|
365
|
-
override func viewDidDisappear(_ animated: Bool) {
|
|
366
|
-
super.viewDidDisappear(animated)
|
|
367
|
-
motionManager.stopAccelerometerUpdates()
|
|
368
|
-
}
|
|
369
|
-
```
|
|
370
|
-
|
|
371
|
-
### DON'T: Use unnecessarily high update rates
|
|
372
|
-
|
|
373
|
-
```swift
|
|
374
|
-
// WRONG -- 100 Hz for a compass display
|
|
375
|
-
motionManager.deviceMotionUpdateInterval = 1.0 / 100.0
|
|
376
|
-
|
|
377
|
-
// CORRECT -- 10 Hz is more than enough for a compass
|
|
378
|
-
motionManager.deviceMotionUpdateInterval = 1.0 / 10.0
|
|
379
|
-
```
|
|
380
|
-
|
|
381
|
-
### DON'T: Assume all CMMotionActivity properties are mutually exclusive
|
|
382
|
-
|
|
383
|
-
```swift
|
|
384
|
-
// WRONG -- checking only one property
|
|
385
|
-
if activity.walking { handleWalking() }
|
|
386
|
-
|
|
387
|
-
// CORRECT -- multiple can be true simultaneously; check confidence
|
|
388
|
-
if activity.walking && activity.confidence == .high {
|
|
389
|
-
handleWalking()
|
|
390
|
-
} else if activity.automotive && activity.confidence != .low {
|
|
391
|
-
handleDriving()
|
|
392
|
-
}
|
|
273
|
+
@MainActor func stopElevation() { barometer.stopAbsoluteAltitudeUpdates() }
|
|
393
274
|
```
|
|
394
275
|
|
|
395
|
-
##
|
|
276
|
+
## Update rates and battery
|
|
396
277
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
278
|
+
| Use case | Frequency | Energy impact | Interval to set |
|
|
279
|
+
|---|---|---|---|
|
|
280
|
+
| UI that follows orientation | 10 Hz | low | `1.0 / 10.0` |
|
|
281
|
+
| Casual game | 30 Hz | moderate | `1.0 / 30.0` |
|
|
282
|
+
| Fast action game | 60 Hz | high | `1.0 / 60.0` |
|
|
283
|
+
| Fastest iPhone sampling | 100 Hz | very high | `1.0 / 100.0` |
|
|
284
|
+
|
|
285
|
+
Pick the slowest rate the feature tolerates. The ceiling differs from one
|
|
286
|
+
device model to the next, so no code path should rely on a fixed maximum. For high-frequency workout
|
|
287
|
+
analysis, prefer `CMBatchedSensorManager` where it is supported, and read its
|
|
288
|
+
`accelerometerDataFrequency` or `deviceMotionDataFrequency`. Those two
|
|
289
|
+
properties are read-only; there is nothing to assign.
|
|
290
|
+
|
|
291
|
+
## Common mistakes
|
|
292
|
+
|
|
293
|
+
- **Several `CMMotionManager` objects.** Rates drop for all of them. Wrap one
|
|
294
|
+
manager in a shared `@Observable` service exposed as `static let shared`.
|
|
295
|
+
- **No availability guard.** Starting gyroscope updates without checking
|
|
296
|
+
`isGyroAvailable` can crash on hardware that lacks one. Guard first and tell
|
|
297
|
+
the user the feature is unsupported.
|
|
298
|
+
- **Never stopping.** Sensors keep running and drain the battery. Pair every
|
|
299
|
+
start with a stop in the matching lifecycle callback, for example
|
|
300
|
+
`viewDidAppear` with `viewDidDisappear`.
|
|
301
|
+
- **Oversampling.** A compass needle does not need 100 Hz; 10 Hz is plenty.
|
|
302
|
+
- **Treating activity flags as exclusive.** Several can be true together.
|
|
303
|
+
Combine them with `confidence`, for example act on `walking` only at `.high`,
|
|
304
|
+
and on `automotive` only when confidence is not `.low`.
|
|
305
|
+
|
|
306
|
+
## Review checklist
|
|
307
|
+
|
|
308
|
+
- [ ] Info.plist has a clear `NSMotionUsageDescription`
|
|
309
|
+
- [ ] The app owns exactly one shared `CMMotionManager`
|
|
310
|
+
- [ ] Availability (`isAccelerometerAvailable` and friends) is checked before any start call
|
|
311
|
+
- [ ] Authorization is read before pedometer and activity APIs are used
|
|
312
|
+
- [ ] The update interval is the lowest that still works
|
|
313
|
+
- [ ] Every `start*Updates` has a `stop*Updates` in the opposite lifecycle event
|
|
314
|
+
- [ ] Handlers run on a suitable queue and heavy processing stays off the main thread
|
|
315
|
+
- [ ] `CMMotionActivity.confidence` is checked before the app reacts
|
|
316
|
+
- [ ] Handler `error` parameters are inspected
|
|
317
|
+
- [ ] Device-motion code calls `availableAttitudeReferenceFrames()` before choosing a frame
|
|
318
|
+
- [ ] The frame matches the need; true north is never the default
|
|
408
319
|
|
|
409
320
|
## References
|
|
410
321
|
|
|
411
|
-
-
|
|
412
|
-
- [
|
|
413
|
-
- [CMMotionManager](https://
|
|
414
|
-
- [CMPedometer](https://
|
|
415
|
-
- [CMMotionActivityManager](https://
|
|
416
|
-
- [CMDeviceMotion](https://
|
|
417
|
-
- [CMAltimeter](https://
|
|
418
|
-
- [CMAbsoluteAltitudeData](https://
|
|
419
|
-
- [CMBatchedSensorManager](https://
|
|
420
|
-
- [CMHeadphoneMotionManager](https://
|
|
421
|
-
- [CMWaterSubmersionManager](https://
|
|
422
|
-
- [Accessing submersion data](https://
|
|
423
|
-
- [Getting processed device-motion data](https://
|
|
322
|
+
- [Motion patterns](references/motion-patterns.md) - SwiftUI services, batched sensors, headphone motion, pedometer dashboard, activity modes, water submersion
|
|
323
|
+
- [Core Motion](https://developer.apple.com/documentation/coremotion)
|
|
324
|
+
- [CMMotionManager](https://developer.apple.com/documentation/coremotion/cmmotionmanager)
|
|
325
|
+
- [CMPedometer](https://developer.apple.com/documentation/coremotion/cmpedometer)
|
|
326
|
+
- [CMMotionActivityManager](https://developer.apple.com/documentation/coremotion/cmmotionactivitymanager)
|
|
327
|
+
- [CMDeviceMotion](https://developer.apple.com/documentation/coremotion/cmdevicemotion)
|
|
328
|
+
- [CMAltimeter](https://developer.apple.com/documentation/coremotion/cmaltimeter)
|
|
329
|
+
- [CMAbsoluteAltitudeData](https://developer.apple.com/documentation/coremotion/cmabsolutealtitudedata)
|
|
330
|
+
- [CMBatchedSensorManager](https://developer.apple.com/documentation/coremotion/cmbatchedsensormanager)
|
|
331
|
+
- [CMHeadphoneMotionManager](https://developer.apple.com/documentation/coremotion/cmheadphonemotionmanager)
|
|
332
|
+
- [CMWaterSubmersionManager](https://developer.apple.com/documentation/coremotion/cmwatersubmersionmanager)
|
|
333
|
+
- [Accessing submersion data](https://developer.apple.com/documentation/coremotion/accessing-submersion-data)
|
|
334
|
+
- [Getting processed device-motion data](https://developer.apple.com/documentation/coremotion/getting-processed-device-motion-data)
|