@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
package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md
CHANGED
|
@@ -1,347 +1,283 @@
|
|
|
1
1
|
# Synchronization Primitives
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
to use from multiple threads.
|
|
6
|
-
|
|
7
|
-
## Contents
|
|
8
|
-
|
|
9
|
-
- [Mutex](#mutex)
|
|
10
|
-
- [OSAllocatedUnfairLock](#osallocatedunfairlock)
|
|
11
|
-
- [Atomic](#atomic)
|
|
12
|
-
- [Locks vs Actors: When to Use Each](#locks-vs-actors-when-to-use-each)
|
|
3
|
+
When an actor is the wrong shape for some shared mutable state, these types
|
|
4
|
+
protect it instead. Each one is `Sendable` and safe to use from any thread.
|
|
13
5
|
|
|
14
6
|
## Mutex
|
|
15
7
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
ensuring only one execution context accesses the protected value at a time.
|
|
21
|
-
|
|
22
|
-
**Documentation:**
|
|
23
|
-
[sosumi.ai/documentation/synchronization/mutex](https://sosumi.ai/documentation/synchronization/mutex)
|
|
24
|
-
|
|
25
|
-
### Basic Usage
|
|
8
|
+
`Mutex<Value>` lives in the `Synchronization` module and needs iOS 18.0 or
|
|
9
|
+
later. It guarantees mutual exclusion: a thread that asks for a lock someone
|
|
10
|
+
else holds waits until it is released. Documentation:
|
|
11
|
+
https://developer.apple.com/documentation/synchronization/mutex
|
|
26
12
|
|
|
27
13
|
```swift
|
|
28
14
|
import Synchronization
|
|
15
|
+
import UIKit
|
|
29
16
|
|
|
30
|
-
class
|
|
31
|
-
let
|
|
17
|
+
final class AvatarCache: Sendable {
|
|
18
|
+
private let images = Mutex<[String: UIImage]>([:])
|
|
32
19
|
|
|
33
|
-
func image(
|
|
34
|
-
|
|
20
|
+
func image(for handle: String) -> UIImage? {
|
|
21
|
+
images.withLock { $0[handle] }
|
|
35
22
|
}
|
|
36
23
|
|
|
37
|
-
func store(_ image: UIImage,
|
|
38
|
-
|
|
24
|
+
func store(_ image: UIImage, for handle: String) {
|
|
25
|
+
images.withLock { $0[handle] = image }
|
|
39
26
|
}
|
|
40
27
|
|
|
41
|
-
func
|
|
42
|
-
|
|
28
|
+
func purge() {
|
|
29
|
+
images.withLock { $0.removeAll() }
|
|
43
30
|
}
|
|
44
31
|
}
|
|
45
32
|
```
|
|
46
33
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
Use `withLockIfAvailable` to attempt acquisition without blocking. Returns
|
|
50
|
-
`nil` if the lock is already held.
|
|
34
|
+
`withLockIfAvailable` tries once and returns `nil` instead of waiting when the
|
|
35
|
+
lock is taken:
|
|
51
36
|
|
|
52
37
|
```swift
|
|
53
|
-
let
|
|
38
|
+
let pendingFlushes = Mutex<Int>(0)
|
|
54
39
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
print("Current count: \(value)")
|
|
40
|
+
if let count = pendingFlushes.withLockIfAvailable({ $0 }) {
|
|
41
|
+
metrics.report(pendingFlushes: count)
|
|
58
42
|
} else {
|
|
59
|
-
|
|
43
|
+
// contended: skip this sample
|
|
60
44
|
}
|
|
61
45
|
```
|
|
62
46
|
|
|
63
|
-
|
|
47
|
+
Properties worth remembering:
|
|
64
48
|
|
|
65
|
-
-
|
|
66
|
-
|
|
67
|
-
-
|
|
68
|
-
|
|
69
|
-
-
|
|
70
|
-
|
|
71
|
-
-
|
|
72
|
-
|
|
73
|
-
|
|
49
|
+
- It is generic over the protected value and stores that value itself, so it
|
|
50
|
+
is always clear what the lock guards.
|
|
51
|
+
- It is `Sendable`, so it can sit in a `Sendable` class, in global state, or
|
|
52
|
+
(rarely) next to an actor.
|
|
53
|
+
- It is not recursive. Locking it again on the thread that holds it is
|
|
54
|
+
undefined behavior.
|
|
55
|
+
- It is synchronous. The lock is held for the entire `withLock` closure, so
|
|
56
|
+
never `await` inside it; suspending while holding a lock can deadlock or
|
|
57
|
+
starve the thread pool.
|
|
74
58
|
|
|
75
59
|
## OSAllocatedUnfairLock
|
|
76
60
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
61
|
+
`OSAllocatedUnfairLock<State>` comes from the `os` module and needs iOS 16.0.
|
|
62
|
+
It wraps `os_unfair_lock` in a safe API. Because it allocates the lock on the
|
|
63
|
+
heap, it avoids the problem that makes a raw `os_unfair_lock` unsound in Swift:
|
|
64
|
+
Swift gives no stable address for a stored struct. Documentation:
|
|
65
|
+
https://developer.apple.com/documentation/os/osallocatedunfairlock
|
|
82
66
|
|
|
83
|
-
|
|
84
|
-
[sosumi.ai/documentation/os/osallocatedunfairlock](https://sosumi.ai/documentation/os/osallocatedunfairlock)
|
|
85
|
-
|
|
86
|
-
### State-Protecting Lock
|
|
67
|
+
Guarding state:
|
|
87
68
|
|
|
88
69
|
```swift
|
|
89
70
|
import os
|
|
90
71
|
|
|
91
|
-
enum
|
|
92
|
-
case
|
|
93
|
-
case
|
|
94
|
-
case
|
|
95
|
-
case failed(Error)
|
|
72
|
+
enum UploadPhase: Sendable {
|
|
73
|
+
case waiting
|
|
74
|
+
case sending(progress: Double)
|
|
75
|
+
case done(receipt: String)
|
|
76
|
+
case failed(any Error)
|
|
96
77
|
}
|
|
97
78
|
|
|
98
|
-
final class
|
|
99
|
-
let
|
|
100
|
-
|
|
101
|
-
func beginLoading() {
|
|
102
|
-
state.withLock { $0 = .loading }
|
|
103
|
-
}
|
|
79
|
+
final class UploadTracker: Sendable {
|
|
80
|
+
private let phase = OSAllocatedUnfairLock(initialState: UploadPhase.waiting)
|
|
104
81
|
|
|
105
|
-
func
|
|
106
|
-
|
|
82
|
+
func update(_ newPhase: UploadPhase) {
|
|
83
|
+
phase.withLock { $0 = newPhase }
|
|
107
84
|
}
|
|
108
85
|
|
|
109
|
-
var
|
|
110
|
-
|
|
86
|
+
var current: UploadPhase {
|
|
87
|
+
phase.withLock { $0 }
|
|
111
88
|
}
|
|
112
89
|
}
|
|
113
90
|
```
|
|
114
91
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
When protecting external state or a code section rather than a specific value:
|
|
92
|
+
Guarding a critical section with no state inside the lock:
|
|
118
93
|
|
|
119
94
|
```swift
|
|
120
|
-
let
|
|
95
|
+
let journalLock = OSAllocatedUnfairLock()
|
|
121
96
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
97
|
+
func appendToJournal(_ line: String) {
|
|
98
|
+
journalLock.withLock {
|
|
99
|
+
writeLine(line, toFileAt: journalURL)
|
|
100
|
+
}
|
|
125
101
|
}
|
|
126
102
|
```
|
|
127
103
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
**Never** use across `await` suspension points.
|
|
104
|
+
`lock()` and `unlock()` also exist but are discouraged. If you use them, unlock
|
|
105
|
+
on the same thread that locked, never span an `await`, and pair them with
|
|
106
|
+
`defer`:
|
|
132
107
|
|
|
133
108
|
```swift
|
|
134
|
-
|
|
135
|
-
defer {
|
|
136
|
-
|
|
109
|
+
journalLock.lock()
|
|
110
|
+
defer { journalLock.unlock() }
|
|
111
|
+
writeLine("checkpoint", toFileAt: journalURL)
|
|
137
112
|
```
|
|
138
113
|
|
|
139
|
-
|
|
114
|
+
## Mutex or OSAllocatedUnfairLock
|
|
140
115
|
|
|
141
|
-
| | `Mutex
|
|
116
|
+
| | `Mutex` | `OSAllocatedUnfairLock` |
|
|
142
117
|
|---|---|---|
|
|
143
|
-
|
|
|
144
|
-
|
|
|
145
|
-
|
|
|
146
|
-
|
|
|
147
|
-
|
|
|
148
|
-
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
iOS 16 through current
|
|
153
|
-
`OSAllocatedUnfairLock
|
|
154
|
-
`Mutex`
|
|
155
|
-
|
|
118
|
+
| Minimum OS | iOS 18 | iOS 16 |
|
|
119
|
+
| Module | `Synchronization` | `os` |
|
|
120
|
+
| State | Always stores a generic `Value` | Optional, via `initialState:` |
|
|
121
|
+
| Non-blocking attempt | `withLockIfAvailable` | `withLockIfAvailable` |
|
|
122
|
+
| Ownership checks | None | `precondition(.owner)`, `precondition(.notOwner)` |
|
|
123
|
+
| Manual `lock()` / `unlock()` | No | Yes |
|
|
124
|
+
|
|
125
|
+
- Targeting iOS 18 or later: use `Mutex`.
|
|
126
|
+
- Targeting iOS 16 or 17: use `OSAllocatedUnfairLock`.
|
|
127
|
+
- Supporting iOS 16 through the current release: build the shared abstraction
|
|
128
|
+
on `OSAllocatedUnfairLock`, or branch with `#available(iOS 18, *)` and use
|
|
129
|
+
`Mutex` where it exists.
|
|
130
|
+
- Want to assert lock ownership while debugging: `OSAllocatedUnfairLock`.
|
|
156
131
|
|
|
157
132
|
## Atomic
|
|
158
133
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
compare-and-swap patterns where a full lock would be overkill.
|
|
164
|
-
|
|
165
|
-
**Documentation:**
|
|
166
|
-
[sosumi.ai/documentation/synchronization/atomic](https://sosumi.ai/documentation/synchronization/atomic)
|
|
167
|
-
|
|
168
|
-
### Counter Example
|
|
134
|
+
`Atomic<Value>` is in `Synchronization` and needs iOS 18.0. It performs
|
|
135
|
+
lock-free operations on types conforming to `AtomicRepresentable` and suits
|
|
136
|
+
counters, flags and compare-and-exchange where a lock would be overkill.
|
|
137
|
+
Documentation: https://developer.apple.com/documentation/synchronization/atomic
|
|
169
138
|
|
|
170
139
|
```swift
|
|
171
140
|
import Synchronization
|
|
172
141
|
|
|
173
|
-
final class
|
|
174
|
-
let
|
|
175
|
-
|
|
176
|
-
func beginRequest() {
|
|
177
|
-
activeRequests.wrappingAdd(1, ordering: .relaxed)
|
|
178
|
-
}
|
|
142
|
+
final class ActiveStreams: Sendable {
|
|
143
|
+
private let count = Atomic<Int>(0)
|
|
179
144
|
|
|
180
|
-
func
|
|
181
|
-
|
|
182
|
-
}
|
|
145
|
+
func opened() { count.wrappingAdd(1, ordering: .relaxed) }
|
|
146
|
+
func closed() { count.wrappingSubtract(1, ordering: .relaxed) }
|
|
147
|
+
var value: Int { count.load(ordering: .relaxed) }
|
|
148
|
+
}
|
|
183
149
|
|
|
184
|
-
|
|
185
|
-
|
|
150
|
+
final class Teardown: Sendable {
|
|
151
|
+
private let finished = Atomic<Bool>(false)
|
|
152
|
+
|
|
153
|
+
func runOnce() {
|
|
154
|
+
let (won, _) = finished.compareExchange(
|
|
155
|
+
expected: false,
|
|
156
|
+
desired: true,
|
|
157
|
+
ordering: .acquiringAndReleasing
|
|
158
|
+
)
|
|
159
|
+
guard won else { return }
|
|
160
|
+
closeSockets()
|
|
186
161
|
}
|
|
187
162
|
}
|
|
188
163
|
```
|
|
189
164
|
|
|
190
|
-
###
|
|
165
|
+
### Memory ordering
|
|
191
166
|
|
|
192
|
-
|
|
193
|
-
let isShutdown = Atomic<Bool>(false)
|
|
194
|
-
|
|
195
|
-
func shutdown() {
|
|
196
|
-
let (exchanged, _) = isShutdown.compareExchange(
|
|
197
|
-
expected: false,
|
|
198
|
-
desired: true,
|
|
199
|
-
ordering: .acquiringAndReleasing
|
|
200
|
-
)
|
|
201
|
-
guard exchanged else { return } // Already shut down
|
|
202
|
-
performCleanup()
|
|
203
|
-
}
|
|
204
|
-
```
|
|
167
|
+
Every atomic call names an ordering.
|
|
205
168
|
|
|
206
|
-
|
|
169
|
+
| Ordering | Use |
|
|
170
|
+
|---|---|
|
|
171
|
+
| `.relaxed` | Counters and statistics; no ordering relative to other memory |
|
|
172
|
+
| `.acquiring` | A load that must see everything written before the matching release |
|
|
173
|
+
| `.releasing` | A store whose earlier writes must be visible to the matching acquire |
|
|
174
|
+
| `.acquiringAndReleasing` | Compare-and-exchange and other read-modify-write operations |
|
|
175
|
+
| `.sequentiallyConsistent` | Strongest and slowest; rarely required, use only with a proven need |
|
|
207
176
|
|
|
208
|
-
|
|
177
|
+
Rule of thumb: `.relaxed` for plain counters, `.acquiringAndReleasing` for
|
|
178
|
+
compare-and-exchange.
|
|
209
179
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
-
|
|
226
|
-
|
|
227
|
-
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
## Locks vs Actors: When to Use Each
|
|
231
|
-
|
|
232
|
-
### Use Actors When:
|
|
233
|
-
|
|
234
|
-
- **Async isolation is natural.** The protected state is accessed from async
|
|
235
|
-
contexts and you can afford the hop.
|
|
236
|
-
- **Callers can suspend.** Actor-isolated APIs are `async` from outside the
|
|
237
|
-
actor, so they fit task-based code but not synchronous C callbacks, real-time
|
|
238
|
-
hooks, or other no-suspension call sites.
|
|
239
|
-
- **Structured concurrency.** You want the compiler to enforce isolation
|
|
240
|
-
boundaries and prevent data races statically.
|
|
241
|
-
- **Most Swift code.** Actors are the default recommendation for shared mutable
|
|
242
|
-
state in Swift concurrency.
|
|
243
|
-
- **Complex state with multiple methods.** Actor isolation protects all
|
|
244
|
-
properties and methods automatically.
|
|
180
|
+
### Atomic or Mutex
|
|
181
|
+
|
|
182
|
+
- **Atomic:** a single scalar such as `Int`, `Bool` or `UInt64`, updated one
|
|
183
|
+
field at a time: counters, flags. Lock-free and very fast.
|
|
184
|
+
- **Mutex:** compound state such as dictionaries or structs with several
|
|
185
|
+
fields, and any sequence of steps that must happen as one unit.
|
|
186
|
+
|
|
187
|
+
## Locks or actors
|
|
188
|
+
|
|
189
|
+
### Choose an actor when
|
|
190
|
+
|
|
191
|
+
- the state is reached from async code and the cost of hopping is acceptable;
|
|
192
|
+
- callers can suspend. From outside, an actor's API is `async`, which rules it
|
|
193
|
+
out for synchronous C callbacks, real-time audio hooks and similar call sites;
|
|
194
|
+
- you want the compiler to enforce the isolation boundary;
|
|
195
|
+
- there is no special constraint: actors are the default for shared mutable
|
|
196
|
+
state in most Swift code;
|
|
197
|
+
- the state is rich and has many operations, since isolation covers all of
|
|
198
|
+
them at once.
|
|
245
199
|
|
|
246
200
|
```swift
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
private var cache: [URL: UIImage] = [:]
|
|
201
|
+
actor ArtworkLoader {
|
|
202
|
+
private var loaded: [URL: UIImage] = [:]
|
|
250
203
|
|
|
251
|
-
func
|
|
252
|
-
if let
|
|
204
|
+
func artwork(at url: URL) async throws -> UIImage? {
|
|
205
|
+
if let image = loaded[url] { return image }
|
|
253
206
|
let (data, _) = try await URLSession.shared.data(from: url)
|
|
254
|
-
let image = UIImage(data: data)
|
|
255
|
-
|
|
207
|
+
let image = UIImage(data: data)
|
|
208
|
+
loaded[url] = image
|
|
256
209
|
return image
|
|
257
210
|
}
|
|
258
211
|
}
|
|
259
212
|
```
|
|
260
213
|
|
|
261
|
-
###
|
|
214
|
+
### Choose a lock when
|
|
262
215
|
|
|
263
|
-
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
-
|
|
270
|
-
|
|
271
|
-
- **Simple counters or flags.** `Atomic<Int>` or `Atomic<Bool>` is cheaper and
|
|
272
|
-
simpler than creating an actor for a single value.
|
|
216
|
+
- callers must stay synchronous; calling an actor from sync code requires a
|
|
217
|
+
`Task` and makes the operation asynchronous;
|
|
218
|
+
- the path is hot: taking an uncontended lock costs nanoseconds while an actor
|
|
219
|
+
hop involves scheduling, so tight loops can be far faster with a lock;
|
|
220
|
+
- C or Objective-C callbacks, delegates or APIs that cannot become async touch
|
|
221
|
+
the state;
|
|
222
|
+
- the state is one counter or flag, where `Atomic<Int>` or `Atomic<Bool>` is
|
|
223
|
+
both cheaper and simpler than an actor.
|
|
273
224
|
|
|
274
225
|
```swift
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
let metrics = Mutex<[String: Int]>([:])
|
|
226
|
+
final class EventTally: Sendable {
|
|
227
|
+
private let counts = Mutex<[String: Int]>([:])
|
|
278
228
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
metrics.withLock { $0[key, default: 0] += 1 }
|
|
229
|
+
func record(_ name: String) {
|
|
230
|
+
counts.withLock { $0[name, default: 0] += 1 }
|
|
282
231
|
}
|
|
283
232
|
|
|
284
233
|
func snapshot() -> [String: Int] {
|
|
285
|
-
|
|
234
|
+
counts.withLock { $0 }
|
|
286
235
|
}
|
|
287
236
|
}
|
|
288
237
|
```
|
|
289
238
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
├── Performance-critical (nanosecond-level)?
|
|
300
|
-
│ └── Use Mutex or Atomic
|
|
301
|
-
└── Bridging C/ObjC callbacks?
|
|
302
|
-
└── Use Mutex or OSAllocatedUnfairLock
|
|
303
|
-
```
|
|
239
|
+
## Decision guide
|
|
240
|
+
|
|
241
|
+
| Situation | Use |
|
|
242
|
+
|---|---|
|
|
243
|
+
| Every access can be async | An actor |
|
|
244
|
+
| Some access must be synchronous | `Mutex`, or `OSAllocatedUnfairLock` below iOS 18 |
|
|
245
|
+
| One counter or flag | `Atomic<Value>` |
|
|
246
|
+
| Nanosecond-sensitive path | `Mutex` or `Atomic` |
|
|
247
|
+
| C or Objective-C callbacks | `Mutex` or `OSAllocatedUnfairLock` |
|
|
304
248
|
|
|
305
|
-
|
|
249
|
+
## Anti-patterns
|
|
306
250
|
|
|
307
|
-
**
|
|
308
|
-
a
|
|
251
|
+
**A lock inside an actor.** The actor already serializes access; the lock adds
|
|
252
|
+
a second layer and a way to deadlock.
|
|
309
253
|
|
|
310
254
|
```swift
|
|
311
|
-
//
|
|
312
|
-
actor
|
|
313
|
-
let
|
|
314
|
-
// The actor already protects its state
|
|
255
|
+
// Wrong
|
|
256
|
+
actor PrefetchQueueWrong {
|
|
257
|
+
private let pending = Mutex<[URL]>([])
|
|
315
258
|
}
|
|
316
259
|
|
|
317
|
-
//
|
|
318
|
-
actor
|
|
319
|
-
var
|
|
320
|
-
|
|
321
|
-
func store(_ data: Data, key: String) {
|
|
322
|
-
cache[key] = data
|
|
323
|
-
}
|
|
260
|
+
// Right
|
|
261
|
+
actor PrefetchQueue {
|
|
262
|
+
private var pending: [URL] = []
|
|
263
|
+
func enqueue(_ url: URL) { pending.append(url) }
|
|
324
264
|
}
|
|
325
265
|
```
|
|
326
266
|
|
|
327
|
-
**
|
|
328
|
-
`NSLock` is `Sendable`,
|
|
329
|
-
(iOS
|
|
330
|
-
|
|
331
|
-
|
|
267
|
+
**Old primitives by reflex.** `DispatchSemaphore` and `NSLock` should not be the
|
|
268
|
+
first tool in modern Swift. `NSLock` is `Sendable`, so it is legal, but `Mutex`
|
|
269
|
+
(iOS 18) and `OSAllocatedUnfairLock` (iOS 16) tie the lock to the state it
|
|
270
|
+
protects and make ownership clearer. Keep `NSLock` for compatibility or where an
|
|
271
|
+
existing API expects it.
|
|
332
272
|
|
|
333
|
-
**
|
|
334
|
-
the cooperative
|
|
273
|
+
**A lock held across `await`.** The thread stays blocked while the task is
|
|
274
|
+
suspended, which can exhaust or deadlock the cooperative pool.
|
|
335
275
|
|
|
336
276
|
```swift
|
|
337
|
-
//
|
|
338
|
-
|
|
339
|
-
value = await fetchData() // DEADLOCK RISK
|
|
340
|
-
}
|
|
277
|
+
// Wrong: suspends while holding the lock
|
|
278
|
+
// latest.withLock { $0 = await feed.fetch() }
|
|
341
279
|
|
|
342
|
-
//
|
|
343
|
-
let
|
|
344
|
-
|
|
345
|
-
value = data
|
|
346
|
-
}
|
|
280
|
+
// Right: await first, lock only to publish the result
|
|
281
|
+
let fresh = await feed.fetch()
|
|
282
|
+
latest.withLock { $0 = fresh }
|
|
347
283
|
```
|