@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,499 +1,459 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: swift-language
|
|
3
|
-
description: "
|
|
3
|
+
description: "Core Swift 6.3 outside concurrency and SwiftUI: if and switch expressions, typed throws, result builders, property wrappers, some vs any, guard, Never, Regex builders, collection APIs, string interpolation, @c interop, module selectors, performance attributes. Use when writing or reviewing plain Swift with generics, protocols, enums, closures or newer language features. Not for deep Codable, formatting, API naming, concurrency or SwiftUI."
|
|
4
4
|
metadata:
|
|
5
|
-
source:
|
|
5
|
+
source: multi-agent-pipeline
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
# Swift Language
|
|
8
|
+
# Swift Language (Swift 6.3)
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
This skill owns the language itself: expressions, the type system, error
|
|
11
|
+
typing, DSL-building features, pattern matching and the standard library
|
|
12
|
+
surface that everyday code touches. It also carries the basics of Codable,
|
|
13
|
+
string and collection APIs, simple formatting, C interop through `@c`, module
|
|
14
|
+
disambiguation with `ModuleName::symbol`, and the performance attributes
|
|
15
|
+
`@specialized` and `@inline(always)`. The attribute details live in
|
|
16
|
+
[references/swift-attributes-interop.md](references/swift-attributes-interop.md).
|
|
12
17
|
|
|
13
|
-
|
|
18
|
+
When a reviewer asks for a `@c` fix, list the Swift-only types that cannot
|
|
19
|
+
appear in the signature: `String`, `Array`, `UnsafeBufferPointer`, closures and
|
|
20
|
+
generic placeholders. Saying "use C types" is not enough.
|
|
14
21
|
|
|
15
|
-
-
|
|
16
|
-
- [Typed Throws](#typed-throws)
|
|
17
|
-
- [Result Builders](#result-builders)
|
|
18
|
-
- [Property Wrappers](#property-wrappers)
|
|
19
|
-
- [Opaque and Existential Types](#opaque-and-existential-types)
|
|
20
|
-
- [Guard Patterns](#guard-patterns)
|
|
21
|
-
- [Never Type](#never-type)
|
|
22
|
-
- [Regex Builders](#regex-builders)
|
|
23
|
-
- [Codable Best Practices](#codable-best-practices)
|
|
24
|
-
- [Modern Collection APIs](#modern-collection-apis)
|
|
25
|
-
- [FormatStyle](#formatstyle)
|
|
26
|
-
- [String Interpolation](#string-interpolation)
|
|
27
|
-
- [Common Mistakes](#common-mistakes)
|
|
28
|
-
- [Review Checklist](#review-checklist)
|
|
29
|
-
- [References](#references)
|
|
22
|
+
Hand-offs:
|
|
30
23
|
|
|
31
|
-
|
|
24
|
+
| Topic | Skill |
|
|
25
|
+
|---|---|
|
|
26
|
+
| Codable models, key strategies, date decoding, API payloads | `swift-codable` |
|
|
27
|
+
| Format styles, locale behaviour, localized display | `swift-formatstyle` (with `ios-localization` for market QA) |
|
|
28
|
+
| Naming and argument labels | `swift-api-design-guidelines` |
|
|
29
|
+
| Actors, tasks, isolation, Sendable | `swift-concurrency` |
|
|
30
|
+
| SwiftUI state and view structure | `swiftui-patterns` |
|
|
31
|
+
|
|
32
|
+
## if and switch as expressions
|
|
32
33
|
|
|
33
|
-
Swift 5.9
|
|
34
|
-
|
|
34
|
+
Since Swift 5.9, `if` and `switch` can produce a value directly for an
|
|
35
|
+
assignment, a `return` or an initializer.
|
|
35
36
|
|
|
36
37
|
```swift
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
let
|
|
42
|
-
case .
|
|
43
|
-
case .
|
|
44
|
-
case .
|
|
38
|
+
enum Tier { case free, plus, pro }
|
|
39
|
+
|
|
40
|
+
func badge(for tier: Tier, trial: Bool) -> String {
|
|
41
|
+
let base = if trial { "Trial" } else { "Member" }
|
|
42
|
+
let suffix = switch tier {
|
|
43
|
+
case .free: ""
|
|
44
|
+
case .plus: " +"
|
|
45
|
+
case .pro: " Pro"
|
|
46
|
+
}
|
|
47
|
+
return base + suffix
|
|
45
48
|
}
|
|
46
49
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
case .
|
|
51
|
-
case .
|
|
52
|
-
case .low: .green
|
|
50
|
+
func seatLimit(_ tier: Tier) -> Int {
|
|
51
|
+
switch tier {
|
|
52
|
+
case .free: 1
|
|
53
|
+
case .plus: 5
|
|
54
|
+
case .pro: 50
|
|
53
55
|
}
|
|
54
56
|
}
|
|
55
57
|
```
|
|
56
58
|
|
|
57
|
-
|
|
58
|
-
- Every branch must produce a value of the same type.
|
|
59
|
-
- Multi-statement branches are not allowed -- each branch is a single expression.
|
|
60
|
-
- Wrap in parentheses when used as a function argument to avoid ambiguity.
|
|
59
|
+
Rules to remember:
|
|
61
60
|
|
|
62
|
-
|
|
61
|
+
- All branches produce one common type.
|
|
62
|
+
- A branch holds exactly one expression. Several statements in a branch are not
|
|
63
|
+
allowed; fall back to a statement form.
|
|
64
|
+
- Wrap the expression in parentheses when it is passed as a function argument,
|
|
65
|
+
so the parser does not misread it.
|
|
63
66
|
|
|
64
|
-
|
|
67
|
+
## Typed throws
|
|
65
68
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
69
|
+
Swift 6 lets a function name its error type: `throws(ParseFailure)`. Inside,
|
|
70
|
+
`throw .emptyInput` works as shorthand, and a `catch` block at the call site
|
|
71
|
+
gets `error` already typed as `ParseFailure`, so a `switch` over it can be
|
|
72
|
+
exhaustive with no `as?` cast.
|
|
70
73
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
```swift
|
|
75
|
+
enum ParseFailure: Error { case emptyInput, badDigit(Character) }
|
|
76
|
+
|
|
77
|
+
func parseCode(_ text: String) throws(ParseFailure) -> Int {
|
|
78
|
+
guard !text.isEmpty else { throw .emptyInput }
|
|
79
|
+
var value = 0
|
|
80
|
+
for ch in text {
|
|
81
|
+
guard let d = ch.wholeNumberValue else { throw .badDigit(ch) }
|
|
82
|
+
value = value * 10 + d
|
|
83
|
+
}
|
|
84
|
+
return value
|
|
75
85
|
}
|
|
76
86
|
|
|
77
|
-
|
|
78
|
-
do {
|
|
79
|
-
|
|
80
|
-
} catch {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
case .alreadyTaken: print("Taken")
|
|
87
|
+
func show(_ text: String) -> String {
|
|
88
|
+
do {
|
|
89
|
+
return String(try parseCode(text))
|
|
90
|
+
} catch {
|
|
91
|
+
switch error {
|
|
92
|
+
case .emptyInput: return "missing"
|
|
93
|
+
case .badDigit(let c): return "bad \(c)"
|
|
94
|
+
}
|
|
86
95
|
}
|
|
87
96
|
}
|
|
88
97
|
```
|
|
89
98
|
|
|
90
|
-
|
|
91
|
-
- Use `throws(SomeError)` only when callers benefit from exhaustive error
|
|
92
|
-
handling. For mixed error sources, use untyped `throws`.
|
|
93
|
-
- `throws(Never)` marks a function that syntactically throws but never actually
|
|
94
|
-
does -- useful in generic contexts.
|
|
95
|
-
- Typed throws propagate: a function calling `throws(A)` and `throws(B)` must
|
|
96
|
-
itself throw a type that covers both (or use untyped `throws`).
|
|
99
|
+
Guidance:
|
|
97
100
|
|
|
98
|
-
|
|
101
|
+
- Reach for `throws(E)` when there is one clear error type and callers gain
|
|
102
|
+
from handling every case. Code that forwards errors from several unrelated
|
|
103
|
+
sources stays with plain `throws`.
|
|
104
|
+
- `throws(Never)` spells a function that is declared throwing but cannot
|
|
105
|
+
throw; it matters mostly in generic code that is parameterised over the
|
|
106
|
+
error type.
|
|
107
|
+
- Calling a `throws(A)` function and a `throws(B)` function from one body means
|
|
108
|
+
the outer function must throw a type that covers both, or be untyped.
|
|
99
109
|
|
|
100
|
-
|
|
101
|
-
|
|
110
|
+
## Result builders
|
|
111
|
+
|
|
112
|
+
`@resultBuilder` turns a closure of plain statements into a built value.
|
|
113
|
+
`@ViewBuilder` is the one most people meet first.
|
|
102
114
|
|
|
103
115
|
```swift
|
|
104
116
|
@resultBuilder
|
|
105
|
-
|
|
106
|
-
static func
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
static func
|
|
110
|
-
static func
|
|
111
|
-
static func
|
|
112
|
-
static func buildEither(second component: [Element]) -> [Element] { component }
|
|
113
|
-
static func buildArray(_ components: [[Element]]) -> [Element] { components.flatMap { $0 } }
|
|
117
|
+
enum LinesBuilder {
|
|
118
|
+
static func buildExpression(_ line: String) -> [String] { [line] }
|
|
119
|
+
static func buildBlock(_ parts: [String]...) -> [String] { parts.flatMap { $0 } }
|
|
120
|
+
static func buildOptional(_ part: [String]?) -> [String] { part ?? [] }
|
|
121
|
+
static func buildEither(first part: [String]) -> [String] { part }
|
|
122
|
+
static func buildEither(second part: [String]) -> [String] { part }
|
|
123
|
+
static func buildArray(_ parts: [[String]]) -> [String] { parts.flatMap { $0 } }
|
|
114
124
|
}
|
|
115
125
|
|
|
116
|
-
func
|
|
126
|
+
func receipt(@LinesBuilder _ body: () -> [String]) -> String {
|
|
127
|
+
body().joined(separator: "\n")
|
|
128
|
+
}
|
|
117
129
|
|
|
118
|
-
let items =
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
for
|
|
130
|
+
let items = ["tea", "scone"]
|
|
131
|
+
let printed = receipt {
|
|
132
|
+
"Corner Cafe"
|
|
133
|
+
for item in items { "- \(item)" }
|
|
134
|
+
if items.count > 1 { "multi-item order" } else { "single item" }
|
|
122
135
|
}
|
|
123
136
|
```
|
|
124
137
|
|
|
125
|
-
|
|
138
|
+
What each hook handles:
|
|
139
|
+
|
|
140
|
+
| Method | Called for |
|
|
141
|
+
|---|---|
|
|
142
|
+
| `buildBlock` | combining the statements of a block |
|
|
143
|
+
| `buildExpression` | lifting one expression into the component type |
|
|
144
|
+
| `buildOptional` | `if` with no `else` |
|
|
145
|
+
| `buildEither(first:)` / `buildEither(second:)` | the two arms of `if`/`else` (and `switch`) |
|
|
146
|
+
| `buildArray` | `for ... in` loops |
|
|
147
|
+
| `buildFinalResult` | optional last step that converts the result |
|
|
126
148
|
|
|
127
|
-
|
|
149
|
+
More builders: [references/swift-patterns-extended.md](references/swift-patterns-extended.md#result-builders).
|
|
128
150
|
|
|
129
|
-
|
|
151
|
+
## Property wrappers
|
|
130
152
|
|
|
131
153
|
```swift
|
|
132
154
|
@propertyWrapper
|
|
133
|
-
struct
|
|
134
|
-
private var
|
|
135
|
-
let
|
|
155
|
+
struct Bounded<Value: Comparable> {
|
|
156
|
+
private var stored: Value
|
|
157
|
+
let limits: ClosedRange<Value>
|
|
136
158
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
159
|
+
init(wrappedValue: Value, _ limits: ClosedRange<Value>) {
|
|
160
|
+
self.limits = limits
|
|
161
|
+
stored = min(max(wrappedValue, limits.lowerBound), limits.upperBound)
|
|
140
162
|
}
|
|
141
163
|
|
|
142
|
-
var
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
self.range = range
|
|
146
|
-
self.value = min(max(wrappedValue, range.lowerBound), range.upperBound)
|
|
164
|
+
var wrappedValue: Value {
|
|
165
|
+
get { stored }
|
|
166
|
+
set { stored = min(max(newValue, limits.lowerBound), limits.upperBound) }
|
|
147
167
|
}
|
|
148
|
-
}
|
|
149
168
|
|
|
150
|
-
|
|
151
|
-
struct Volume {
|
|
152
|
-
@Clamped(0...100) var level: Int = 50
|
|
169
|
+
var projectedValue: ClosedRange<Value> { limits }
|
|
153
170
|
}
|
|
154
171
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
print(v.$level) // projected value: 0...100
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
**Design rules:**
|
|
161
|
-
- `wrappedValue` is the primary getter/setter.
|
|
162
|
-
- `projectedValue` (accessed via `$property`) provides metadata or bindings.
|
|
163
|
-
- Property wrappers can be composed: `@A @B var x` applies outer wrapper first.
|
|
164
|
-
- Do not use property wrappers when a simple computed property suffices.
|
|
165
|
-
|
|
166
|
-
## Opaque and Existential Types
|
|
167
|
-
|
|
168
|
-
### `some Protocol` (Opaque Type)
|
|
169
|
-
|
|
170
|
-
The caller does not know the concrete type, but the compiler does. The
|
|
171
|
-
underlying type is fixed for a given scope.
|
|
172
|
-
|
|
173
|
-
```swift
|
|
174
|
-
func makeCollection() -> some Collection<Int> {
|
|
175
|
-
[1, 2, 3] // Always returns Array<Int> -- compiler knows the concrete type
|
|
172
|
+
struct Thermostat {
|
|
173
|
+
@Bounded(10...30) var target: Double = 21
|
|
176
174
|
}
|
|
177
|
-
```
|
|
178
175
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
### `any Protocol` (Existential Type)
|
|
185
|
-
|
|
186
|
-
An existential box that can hold any conforming type at runtime. It uses dynamic
|
|
187
|
-
dispatch and may allocate when the value does not fit in the inline buffer.
|
|
188
|
-
|
|
189
|
-
```swift
|
|
190
|
-
func process(items: [any StringProtocol]) {
|
|
191
|
-
for item in items {
|
|
192
|
-
print(item.uppercased())
|
|
193
|
-
}
|
|
194
|
-
}
|
|
176
|
+
var unit = Thermostat()
|
|
177
|
+
unit.target = 45
|
|
178
|
+
let clamped = unit.target
|
|
179
|
+
let window = unit.$target
|
|
195
180
|
```
|
|
196
181
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
182
|
+
- `wrappedValue` is the getter and setter the property exposes.
|
|
183
|
+
- `projectedValue` is what `$name` returns: metadata, a binding, a validity
|
|
184
|
+
flag.
|
|
185
|
+
- Wrappers stack. With `@Outer @Inner var x`, the outer one wraps the inner
|
|
186
|
+
one and is applied first.
|
|
187
|
+
- If a computed property would do the job, write the computed property. A
|
|
188
|
+
wrapper earns its place through reuse or a useful projection.
|
|
189
|
+
|
|
190
|
+
## some and any
|
|
191
|
+
|
|
192
|
+
- `some Shape` is an opaque type: the compiler knows the concrete type, the
|
|
193
|
+
caller does not, and the type stays the same for every return from that
|
|
194
|
+
scope. `func evens() -> some Collection<Int> { [2, 4, 6] }` hides the array.
|
|
195
|
+
- In parameter position (Swift 5.7+), `some Shape` is shorthand for an
|
|
196
|
+
anonymous generic parameter `<T: Shape>`.
|
|
197
|
+
- `any Shape` is an existential box. It can hold any conforming value at
|
|
198
|
+
runtime, calls go through dynamic dispatch, and a value too large for the
|
|
199
|
+
box's inline storage is heap allocated.
|
|
200
|
+
|
|
201
|
+
| Pick `some` for | Pick `any` for |
|
|
200
202
|
|---|---|
|
|
201
|
-
|
|
|
202
|
-
|
|
|
203
|
-
|
|
|
203
|
+
| hiding a return type | mixed-type collections such as `[any Shape]` |
|
|
204
|
+
| simple generic parameters | erasing a type chosen at runtime |
|
|
205
|
+
| static dispatch and speed | working past `Self` or associated-type constraints |
|
|
204
206
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
+
Start from `some`. Move to `any` only when values of different concrete types
|
|
208
|
+
really have to share one container or the type is decided at runtime.
|
|
207
209
|
|
|
208
|
-
##
|
|
210
|
+
## guard
|
|
209
211
|
|
|
210
|
-
`guard`
|
|
211
|
-
|
|
212
|
+
`guard` states a precondition and leaves early when it fails, so the main path
|
|
213
|
+
stays at the left margin.
|
|
212
214
|
|
|
213
215
|
```swift
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
guard
|
|
220
|
-
guard
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
// Pattern matching
|
|
226
|
-
guard case .confirmed(let date) = order.status else {
|
|
227
|
-
throw OrderError.notConfirmed
|
|
216
|
+
enum Shipment { case pending, dispatched(on: Date), lost }
|
|
217
|
+
struct Parcel { var weight: Double; var status: Shipment }
|
|
218
|
+
enum ParcelError: Error { case none, tooHeavy, notDispatched }
|
|
219
|
+
|
|
220
|
+
func dispatchDate(_ parcel: Parcel?, express: Bool) throws -> Date {
|
|
221
|
+
guard let parcel else { throw ParcelError.none }
|
|
222
|
+
guard parcel.weight <= 30 else { throw ParcelError.tooHeavy }
|
|
223
|
+
guard express else { return .distantFuture }
|
|
224
|
+
guard case .dispatched(let date) = parcel.status else {
|
|
225
|
+
throw ParcelError.notDispatched
|
|
228
226
|
}
|
|
229
|
-
|
|
230
|
-
return Receipt(order: order, confirmedAt: date)
|
|
227
|
+
return date
|
|
231
228
|
}
|
|
232
229
|
```
|
|
233
230
|
|
|
234
|
-
|
|
235
|
-
-
|
|
236
|
-
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
- Use shorthand unwrap: `guard let value else { ... }` (Swift 5.7+).
|
|
231
|
+
- `guard` for preconditions, `if` for genuine branches.
|
|
232
|
+
- Several bindings fit one statement: `guard let host, let port else { return }`.
|
|
233
|
+
- The `else` body has to leave the scope: `return`, `throw`, `continue`,
|
|
234
|
+
`break`, or a `Never` call such as `fatalError()`.
|
|
235
|
+
- The shorthand `guard let value else` needs Swift 5.7 or later.
|
|
240
236
|
|
|
241
|
-
## Never
|
|
237
|
+
## Never
|
|
242
238
|
|
|
243
|
-
`Never`
|
|
244
|
-
|
|
245
|
-
conform to arbitrary protocols or satisfy a generic `T: SomeProtocol`
|
|
246
|
-
constraint. When recommending `Result<T, Never>` or `throws(Never)`, explicitly
|
|
247
|
-
state all three points: uninhabited, bottom-like, and no universal protocol
|
|
248
|
-
conformance.
|
|
239
|
+
When `Never` comes up, say all three things, because each changes what code
|
|
240
|
+
compiles:
|
|
249
241
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
242
|
+
1. It is uninhabited: no value of type `Never` can exist.
|
|
243
|
+
2. It behaves like a bottom type in expressions: a call returning `Never` can
|
|
244
|
+
stand where any type is expected.
|
|
245
|
+
3. It does not conform to arbitrary protocols, so it does not satisfy an
|
|
246
|
+
arbitrary `T: SomeProtocol` constraint on its own.
|
|
247
|
+
|
|
248
|
+
This applies whenever you recommend `Result<T, Never>` or `throws(Never)`.
|
|
257
249
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
250
|
+
```swift
|
|
251
|
+
func halt(_ reason: String, context: [String: String]) -> Never {
|
|
252
|
+
let summary = context.map { "\($0.key)=\($0.value)" }.sorted().joined(separator: " ")
|
|
253
|
+
print("fatal: \(reason) \(summary)")
|
|
254
|
+
fatalError(reason)
|
|
261
255
|
}
|
|
262
|
-
// Result<String, Never> -- a result that can never fail
|
|
263
256
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
case .success(let value): print(value)
|
|
268
|
-
// No .failure case needed -- compiler knows it's impossible
|
|
269
|
-
}
|
|
257
|
+
let greeting: Result<String, Never> = .success("hello")
|
|
258
|
+
switch greeting {
|
|
259
|
+
case .success(let text): print(text)
|
|
270
260
|
}
|
|
271
261
|
```
|
|
272
262
|
|
|
273
|
-
|
|
263
|
+
A function returning `Never` does not come back. A `Result` whose failure type
|
|
264
|
+
is `Never` cannot fail, so the `switch` needs only `.success` and no `default`.
|
|
265
|
+
|
|
266
|
+
## Regex builders
|
|
274
267
|
|
|
275
|
-
Swift 5.7
|
|
268
|
+
`RegexBuilder` (Swift 5.7+, imported next to Foundation) writes patterns as
|
|
269
|
+
readable, compiler-checked Swift with typed captures.
|
|
276
270
|
|
|
277
271
|
```swift
|
|
278
272
|
import Foundation
|
|
279
273
|
import RegexBuilder
|
|
280
274
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
275
|
+
let clock = Regex {
|
|
276
|
+
Capture { /\d{2}/ }
|
|
277
|
+
":"
|
|
278
|
+
Capture { /\d{2}/ }
|
|
284
279
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
_ = (year, month, day)
|
|
280
|
+
if let hit = "Doors open 19:45".firstMatch(of: clock) {
|
|
281
|
+
let (_, hour, minute) = hit.output
|
|
282
|
+
print(hour, minute)
|
|
289
283
|
}
|
|
290
284
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
285
|
+
let price = Regex {
|
|
286
|
+
"EUR "
|
|
287
|
+
TryCapture {
|
|
288
|
+
OneOrMore(.digit)
|
|
289
|
+
"."
|
|
290
|
+
Repeat(.digit, count: 2)
|
|
291
|
+
} transform: { Decimal(string: String($0)) }
|
|
296
292
|
}
|
|
297
293
|
```
|
|
298
294
|
|
|
299
|
-
|
|
300
|
-
-
|
|
301
|
-
|
|
302
|
-
-
|
|
303
|
-
|
|
304
|
-
## Codable Best Practices
|
|
295
|
+
Use the builder when a pattern is long, reused, or needs typed captures. A
|
|
296
|
+
short one-off pattern reads better as a literal such as `/\d+/`, and literals
|
|
297
|
+
can be dropped into a builder where that helps. More in
|
|
298
|
+
[references/swift-patterns-extended.md](references/swift-patterns-extended.md#advanced-regex).
|
|
305
299
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
Rename keys without writing a custom decoder:
|
|
300
|
+
## Codable basics
|
|
309
301
|
|
|
310
302
|
```swift
|
|
311
|
-
struct
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
303
|
+
struct Venue: Codable {
|
|
304
|
+
var venueName: String
|
|
305
|
+
var seatCount: Int
|
|
306
|
+
var isOutdoor: Bool
|
|
307
|
+
var city: String
|
|
315
308
|
|
|
316
309
|
enum CodingKeys: String, CodingKey {
|
|
317
|
-
case
|
|
318
|
-
case displayName = "display_name"
|
|
319
|
-
case avatarURL = "avatar_url"
|
|
310
|
+
case venueName = "venue_name", seatCount = "seat_count", isOutdoor = "is_outdoor", location
|
|
320
311
|
}
|
|
321
|
-
}
|
|
322
|
-
```
|
|
323
|
-
|
|
324
|
-
### Custom Decoding
|
|
325
|
-
|
|
326
|
-
Handle mismatched types, defaults, and transformations:
|
|
327
|
-
|
|
328
|
-
```swift
|
|
329
|
-
struct Item: Decodable {
|
|
330
|
-
let name: String
|
|
331
|
-
let quantity: Int
|
|
332
|
-
let isActive: Bool
|
|
312
|
+
enum LocationKeys: String, CodingKey { case city }
|
|
333
313
|
|
|
334
314
|
init(from decoder: Decoder) throws {
|
|
335
|
-
let
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
if let
|
|
339
|
-
|
|
315
|
+
let c = try decoder.container(keyedBy: CodingKeys.self)
|
|
316
|
+
venueName = try c.decode(String.self, forKey: .venueName)
|
|
317
|
+
seatCount = try c.decodeIfPresent(Int.self, forKey: .seatCount) ?? 0
|
|
318
|
+
if let flag = try? c.decode(Bool.self, forKey: .isOutdoor) {
|
|
319
|
+
isOutdoor = flag
|
|
340
320
|
} else {
|
|
341
|
-
|
|
321
|
+
isOutdoor = (try c.decodeIfPresent(String.self, forKey: .isOutdoor)) == "true"
|
|
342
322
|
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
}
|
|
346
|
-
```
|
|
347
|
-
|
|
348
|
-
### Nested Containers
|
|
349
|
-
|
|
350
|
-
Flatten nested JSON into a flat Swift struct:
|
|
351
|
-
|
|
352
|
-
```swift
|
|
353
|
-
// JSON: { "id": 1, "metadata": { "created_at": "...", "tags": [...] } }
|
|
354
|
-
struct Record: Decodable {
|
|
355
|
-
let id: Int
|
|
356
|
-
let createdAt: String
|
|
357
|
-
let tags: [String]
|
|
358
|
-
|
|
359
|
-
enum CodingKeys: String, CodingKey {
|
|
360
|
-
case id, metadata
|
|
323
|
+
let place = try c.nestedContainer(keyedBy: LocationKeys.self, forKey: .location)
|
|
324
|
+
city = try place.decode(String.self, forKey: .city)
|
|
361
325
|
}
|
|
362
326
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
id = try container.decode(Int.self, forKey: .id)
|
|
371
|
-
let metadata = try container.nestedContainer(
|
|
372
|
-
keyedBy: MetadataKeys.self, forKey: .metadata)
|
|
373
|
-
createdAt = try metadata.decode(String.self, forKey: .createdAt)
|
|
374
|
-
tags = try metadata.decode([String].self, forKey: .tags)
|
|
327
|
+
func encode(to encoder: Encoder) throws {
|
|
328
|
+
var c = encoder.container(keyedBy: CodingKeys.self)
|
|
329
|
+
try c.encode(venueName, forKey: .venueName)
|
|
330
|
+
try c.encode(seatCount, forKey: .seatCount)
|
|
331
|
+
try c.encode(isOutdoor, forKey: .isOutdoor)
|
|
332
|
+
var place = c.nestedContainer(keyedBy: LocationKeys.self, forKey: .location)
|
|
333
|
+
try place.encode(city, forKey: .city)
|
|
375
334
|
}
|
|
376
335
|
}
|
|
377
336
|
```
|
|
378
337
|
|
|
379
|
-
|
|
380
|
-
|
|
338
|
+
- A `CodingKeys: String, CodingKey` enum renames snake_case keys without a
|
|
339
|
+
custom decoder.
|
|
340
|
+
- A custom `init(from:)` covers defaults (`decodeIfPresent(...) ?? value`) and
|
|
341
|
+
type mismatches, here a flag that sometimes arrives as the string `"true"`.
|
|
342
|
+
- `nestedContainer(keyedBy:forKey:)` flattens a nested JSON object into flat
|
|
343
|
+
properties using a second key enum.
|
|
381
344
|
|
|
382
|
-
|
|
345
|
+
Enums with associated values, date strategies and unkeyed containers are in
|
|
346
|
+
[references/swift-patterns-extended.md](references/swift-patterns-extended.md#codable).
|
|
347
|
+
Anything beyond this goes to `swift-codable`.
|
|
383
348
|
|
|
384
|
-
|
|
349
|
+
## Collection APIs
|
|
385
350
|
|
|
386
351
|
```swift
|
|
387
|
-
let
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
let
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
let
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
let
|
|
400
|
-
let
|
|
401
|
-
|
|
402
|
-
// compactMap -- unwrap optionals from a transform
|
|
403
|
-
let ids = strings.compactMap { Int($0) }
|
|
404
|
-
|
|
405
|
-
// flatMap -- flatten nested collections
|
|
406
|
-
let allTags = articles.flatMap(\.tags)
|
|
407
|
-
|
|
408
|
-
// Dictionary(grouping:by:)
|
|
409
|
-
let byCategory = Dictionary(grouping: items, by: \.category)
|
|
410
|
-
|
|
411
|
-
// reduce(into:) -- efficient accumulation
|
|
412
|
-
let freq = words.reduce(into: [:]) { counts, word in
|
|
413
|
-
counts[word, default: 0] += 1
|
|
414
|
-
}
|
|
352
|
+
let scores = [72, 95, 40, 88]
|
|
353
|
+
let passed = scores.count(where: { $0 >= 50 })
|
|
354
|
+
let hasPerfect = scores.contains(where: { $0 == 100 })
|
|
355
|
+
let firstFail = scores.first(where: { $0 < 50 })
|
|
356
|
+
let lastHigh = scores.last(where: { $0 > 80 })
|
|
357
|
+
|
|
358
|
+
let slug = "Summer Sale 2026".replacing(" ", with: "-")
|
|
359
|
+
let digitsHidden = "PIN 4821".replacing(/\d/, with: "*")
|
|
360
|
+
|
|
361
|
+
struct Post { var tags: [String]; var author: String? }
|
|
362
|
+
let posts = [Post(tags: ["swift"], author: "ana"), Post(tags: ["ios", "swift"], author: nil)]
|
|
363
|
+
let authors = posts.compactMap(\.author)
|
|
364
|
+
let allTags = posts.flatMap(\.tags)
|
|
365
|
+
let byFirstTag = Dictionary(grouping: posts, by: { $0.tags.first ?? "" })
|
|
366
|
+
let tagCounts = allTags.reduce(into: [:]) { tally, tag in tally[tag, default: 0] += 1 }
|
|
415
367
|
```
|
|
416
368
|
|
|
417
|
-
|
|
369
|
+
- `count(where:)` replaces `filter { }.count` without building an array.
|
|
370
|
+
- `contains(where:)` stops at the first match.
|
|
371
|
+
- `String.replacing(_:with:)` (Swift 5.7+) returns a new string and takes a
|
|
372
|
+
string or a regex.
|
|
373
|
+
- `compactMap` drops `nil`; `flatMap(\.tags)` flattens nested arrays.
|
|
374
|
+
- `Dictionary(grouping:by:)` buckets values by a key.
|
|
375
|
+
- `reduce(into:)` mutates one accumulator instead of copying on every step.
|
|
418
376
|
|
|
419
|
-
|
|
420
|
-
type-safe, localized, and concise.
|
|
377
|
+
## Formatting basics
|
|
421
378
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
let now = Date.now
|
|
425
|
-
now.formatted() // "3/15/2024, 2:30 PM"
|
|
426
|
-
now.formatted(date: .abbreviated, time: .shortened) // "Mar 15, 2024, 2:30 PM"
|
|
427
|
-
now.formatted(.dateTime.year().month().day()) // "Mar 15, 2024"
|
|
428
|
-
now.formatted(.relative(presentation: .named)) // "yesterday"
|
|
429
|
-
|
|
430
|
-
// Numbers
|
|
431
|
-
let price = 42.5
|
|
432
|
-
price.formatted(.currency(code: "USD")) // "$42.50"
|
|
433
|
-
price.formatted(.percent) // "4,250%"
|
|
434
|
-
(1_000_000).formatted(.number.notation(.compactName)) // "1M"
|
|
435
|
-
|
|
436
|
-
// Measurements
|
|
437
|
-
let distance = Measurement(value: 5, unit: UnitLength.kilometers)
|
|
438
|
-
distance.formatted(.measurement(width: .abbreviated)) // "5 km"
|
|
439
|
-
|
|
440
|
-
// Duration (Swift 5.7+)
|
|
441
|
-
let duration = Duration.seconds(3661)
|
|
442
|
-
duration.formatted(.time(pattern: .hourMinuteSecond)) // "1:01:01"
|
|
443
|
-
|
|
444
|
-
// Byte counts
|
|
445
|
-
Int64(1_500_000).formatted(.byteCount(style: .file)) // "1.5 MB"
|
|
446
|
-
|
|
447
|
-
// Lists
|
|
448
|
-
["Alice", "Bob", "Carol"].formatted(.list(type: .and)) // "Alice, Bob, and Carol"
|
|
449
|
-
```
|
|
379
|
+
Prefer `.formatted()` to `DateFormatter` and `NumberFormatter`: it is typed,
|
|
380
|
+
localized and short.
|
|
450
381
|
|
|
451
|
-
**Parsing:** `FormatStyle` also supports parsing:
|
|
452
382
|
```swift
|
|
453
|
-
|
|
454
|
-
|
|
383
|
+
import Foundation
|
|
384
|
+
|
|
385
|
+
let now = Date()
|
|
386
|
+
now.formatted()
|
|
387
|
+
now.formatted(date: .abbreviated, time: .shortened)
|
|
388
|
+
now.formatted(.dateTime.year().month().day())
|
|
389
|
+
now.addingTimeInterval(-3600).formatted(.relative(presentation: .named))
|
|
390
|
+
|
|
391
|
+
19.99.formatted(.currency(code: "EUR"))
|
|
392
|
+
0.425.formatted(.percent)
|
|
393
|
+
42.5.formatted(.percent)
|
|
394
|
+
2_400_000.formatted(.number.notation(.compactName))
|
|
395
|
+
Measurement(value: 12, unit: UnitLength.kilometers).formatted(.measurement(width: .abbreviated))
|
|
396
|
+
Duration.seconds(4000).formatted(.time(pattern: .hourMinuteSecond))
|
|
397
|
+
Int64(5_300_000).formatted(.byteCount(style: .file))
|
|
398
|
+
["oat", "rye", "spelt"].formatted(.list(type: .and))
|
|
399
|
+
|
|
400
|
+
let cost = try Decimal("EUR 42.50", format: .currency(code: "EUR"))
|
|
401
|
+
let day = try Date("Mar 4, 2026", strategy: .dateTime.month().day().year())
|
|
455
402
|
```
|
|
456
403
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
404
|
+
`.percent` multiplies by 100, so `42.5` prints as `4,250%`; pass `0.425` for
|
|
405
|
+
42.5%. `.compactName` turns 2,400,000 into `2.4M`. `Duration.formatted` needs
|
|
406
|
+
Swift 5.7+. Everything past these basics, including locale behaviour and
|
|
407
|
+
custom styles in depth, belongs to `swift-formatstyle`.
|
|
408
|
+
|
|
409
|
+
## String interpolation
|
|
410
|
+
|
|
411
|
+
Extending `DefaultStringInterpolation` gives domain-specific `\(...)` forms;
|
|
412
|
+
see [references/swift-patterns-extended.md](references/swift-patterns-extended.md#string-interpolation).
|
|
413
|
+
In a `"""` multi-line string, indentation is measured from the closing
|
|
414
|
+
delimiter, so align the closing quotes with the text you want flush left.
|
|
415
|
+
|
|
416
|
+
## Common mistakes
|
|
417
|
+
|
|
418
|
+
1. `any` where `some` would do: adds boxing and dynamic dispatch and throws
|
|
419
|
+
away type information.
|
|
420
|
+
2. Hand-written loops where `count(where:)`, `contains(where:)`, `compactMap`
|
|
421
|
+
or `flatMap` say it directly.
|
|
422
|
+
3. New `DateFormatter` code instead of format styles.
|
|
423
|
+
4. Force-unwrapping decoded values; use `decodeIfPresent` with a default.
|
|
424
|
+
5. Nested `if let` pyramids; use `guard let`.
|
|
425
|
+
6. Accepting an invalid `@c` signature. Name the C-compatible types that are
|
|
426
|
+
allowed and reject `String`, `Array`, `UnsafeBufferPointer`, closures and
|
|
427
|
+
generic placeholders.
|
|
428
|
+
7. Plain `throws` when a single error type exists and callers would switch on
|
|
429
|
+
it.
|
|
430
|
+
8. A property wrapper with no reuse and no projection.
|
|
431
|
+
9. Describing `Never` loosely; state uninhabited, bottom-like and no universal
|
|
432
|
+
conformance.
|
|
433
|
+
10. Taking over deep formatting or localization work that belongs to
|
|
434
|
+
`swift-formatstyle` and `ios-localization`.
|
|
435
|
+
|
|
436
|
+
## Review checklist
|
|
437
|
+
|
|
438
|
+
- [ ] `some` used for opaque returns and as parameter shorthand
|
|
487
439
|
- [ ] `guard` for preconditions; collection APIs instead of manual loops
|
|
488
|
-
- [ ] `.formatted()`
|
|
489
|
-
- [ ]
|
|
490
|
-
- [ ] if
|
|
491
|
-
|
|
492
|
-
- [ ]
|
|
493
|
-
- [ ]
|
|
494
|
-
- [ ] `
|
|
495
|
-
- [ ]
|
|
440
|
+
- [ ] `.formatted()` instead of formatter objects
|
|
441
|
+
- [ ] `CodingKeys` for renames; `decodeIfPresent` with defaults
|
|
442
|
+
- [ ] `if`/`switch` expressions for conditional assignment; wrappers justified
|
|
443
|
+
by reuse
|
|
444
|
+
- [ ] Regex builder for complex patterns, literals for simple ones
|
|
445
|
+
- [ ] typed throws where exhaustive handling helps callers
|
|
446
|
+
- [ ] `@c` corrections list the rejected Swift-only types
|
|
447
|
+
- [ ] `Never` guidance states all three properties
|
|
448
|
+
- [ ] deep Codable, formatting and localization, naming, concurrency and
|
|
449
|
+
SwiftUI work sent to the sibling skills
|
|
450
|
+
|
|
496
451
|
## References
|
|
497
452
|
|
|
498
|
-
-
|
|
499
|
-
|
|
453
|
+
- [references/swift-patterns-extended.md](references/swift-patterns-extended.md):
|
|
454
|
+
Codable edge cases, builders, wrappers, advanced Regex, custom format
|
|
455
|
+
styles, Swift Algorithms, complex `guard`, typed throws in protocols, custom
|
|
456
|
+
interpolation, advanced `Never`.
|
|
457
|
+
- [references/swift-attributes-interop.md](references/swift-attributes-interop.md):
|
|
458
|
+
`@c`, module selectors, `@specialized`, `@inline(always)`, `@export`,
|
|
459
|
+
`@section` and `@used`.
|