@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.
Files changed (264) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/LICENSE +0 -10
  3. package/docs/facts.json +1 -1
  4. package/manifest.json +266 -267
  5. package/package.json +2 -2
  6. package/pipeline/scripts/_notices.mjs +1 -1
  7. package/pipeline/skills/.skill-manifest.json +68 -68
  8. package/pipeline/skills/shared/README.md +70 -70
  9. package/pipeline/skills/shared/external/alarmkit/SKILL.md +373 -381
  10. package/pipeline/skills/shared/external/alarmkit/evals/evals.json +23 -18
  11. package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +328 -378
  12. package/pipeline/skills/shared/external/app-clips/SKILL.md +260 -160
  13. package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
  14. package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
  15. package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
  16. package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
  17. package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
  18. package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
  19. package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
  20. package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +339 -277
  21. package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
  22. package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +105 -122
  23. package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +143 -166
  24. package/pipeline/skills/shared/external/app-store-review/SKILL.md +307 -326
  25. package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
  26. package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
  27. package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
  28. package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +333 -360
  29. package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
  30. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
  31. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
  32. package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
  33. package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
  34. package/pipeline/skills/shared/external/authentication/SKILL.md +265 -381
  35. package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
  36. package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +133 -178
  37. package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
  38. package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
  39. package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
  40. package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
  41. package/pipeline/skills/shared/external/background-processing/SKILL.md +270 -382
  42. package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
  43. package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +169 -317
  44. package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
  45. package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
  46. package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
  47. package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
  48. package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
  49. package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
  50. package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
  51. package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
  52. package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
  53. package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +226 -376
  54. package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
  55. package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
  56. package/pipeline/skills/shared/external/core-data/SKILL.md +292 -368
  57. package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
  58. package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
  59. package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
  60. package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
  61. package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
  62. package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
  63. package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
  64. package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
  65. package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
  66. package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
  67. package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
  68. package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
  69. package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
  70. package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
  71. package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
  72. package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
  73. package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
  74. package/pipeline/skills/shared/external/device-integrity/SKILL.md +230 -353
  75. package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
  76. package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
  77. package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
  78. package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
  79. package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
  80. package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
  81. package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
  82. package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
  83. package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
  84. package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
  85. package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
  86. package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
  87. package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
  88. package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
  89. package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
  90. package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
  91. package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
  92. package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
  93. package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
  94. package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
  95. package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
  96. package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
  97. package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
  98. package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
  99. package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
  100. package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
  101. package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
  102. package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
  103. package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
  104. package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
  105. package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
  106. package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
  107. package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
  108. package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
  109. package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
  110. package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
  111. package/pipeline/skills/shared/external/mapkit-location/SKILL.md +295 -267
  112. package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
  113. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
  114. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
  115. package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
  116. package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
  117. package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
  118. package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
  119. package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
  120. package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
  121. package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
  122. package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
  123. package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
  124. package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
  125. package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
  126. package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
  127. package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
  128. package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
  129. package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
  130. package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
  131. package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
  132. package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
  133. package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
  134. package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
  135. package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
  136. package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
  137. package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
  138. package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
  139. package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
  140. package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
  141. package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
  142. package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
  143. package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
  144. package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
  145. package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
  146. package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
  147. package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
  148. package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
  149. package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
  150. package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
  151. package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
  152. package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
  153. package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
  154. package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
  155. package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
  156. package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
  157. package/pipeline/skills/shared/external/storekit/references/core-patterns.md +298 -242
  158. package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
  159. package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
  160. package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
  161. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
  162. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
  163. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
  164. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
  165. package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
  166. package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
  167. package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
  168. package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
  169. package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
  170. package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
  171. package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
  172. package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +303 -351
  173. package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
  174. package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
  175. package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
  176. package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
  177. package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
  178. package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
  179. package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
  180. package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
  181. package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
  182. package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
  183. package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
  184. package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
  185. package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
  186. package/pipeline/skills/shared/external/swift-security/SKILL.md +180 -161
  187. package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
  188. package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
  189. package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +408 -476
  190. package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
  191. package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
  192. package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
  193. package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
  194. package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
  195. package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
  196. package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +352 -472
  197. package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
  198. package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
  199. package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
  200. package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +396 -457
  201. package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
  202. package/pipeline/skills/shared/external/swift-testing/SKILL.md +188 -175
  203. package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
  204. package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +80 -84
  205. package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
  206. package/pipeline/skills/shared/external/swiftdata/SKILL.md +392 -256
  207. package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
  208. package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
  209. package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
  210. package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
  211. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
  212. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
  213. package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
  214. package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
  215. package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
  216. package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
  217. package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
  218. package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
  219. package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
  220. package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
  221. package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
  222. package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
  223. package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
  224. package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
  225. package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
  226. package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
  227. package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
  228. package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
  229. package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
  230. package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
  231. package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +193 -168
  232. package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
  233. package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +132 -133
  234. package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
  235. package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +106 -140
  236. package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
  237. package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
  238. package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
  239. package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
  240. package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
  241. package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
  242. package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
  243. package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
  244. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
  245. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
  246. package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
  247. package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
  248. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
  249. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
  250. package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
  251. package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
  252. package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
  253. package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
  254. package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
  255. package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
  256. package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
  257. package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
  258. package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
  259. package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
  260. package/pipeline/skills/shared/external/weatherkit/SKILL.md +152 -310
  261. package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
  262. package/pipeline/skills/shared/external/widgetkit/SKILL.md +216 -288
  263. package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +414 -719
  264. package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +0 -39
@@ -1,463 +1,310 @@
1
- # UIKit-to-SwiftUI Migration Patterns
1
+ # Hosting and Incremental Migration
2
2
 
3
- Patterns for incrementally migrating a UIKit app to SwiftUI. Each pattern is self-contained with rationale, implementation, and gotchas.
4
-
5
- ---
3
+ A UIKit app does not have to switch to SwiftUI in one release. These six
4
+ patterns move it over piece by piece while both frameworks share the same
5
+ navigation stack, the same models and the same traits.
6
6
 
7
7
  ## Contents
8
8
 
9
- - [1. Screen-by-Screen Migration](#1-screen-by-screen-migration)
10
- - [2. UIHostingController as Child](#2-uihostingcontroller-as-child)
11
- - [3. Navigation Bridging](#3-navigation-bridging)
12
- - [4. Data Sharing Between UIKit and SwiftUI](#4-data-sharing-between-uikit-and-swiftui)
13
- - [5. UIHostingConfiguration (iOS 16+)](#5-uihostingconfiguration-ios-16)
14
- - [6. Environment Bridging](#6-environment-bridging)
9
+ 1. [Replace whole screens](#1-screen-by-screen-migration)
10
+ 2. [Embed a SwiftUI region](#2-uihostingcontroller-as-child)
11
+ 3. [Share one navigation stack](#3-navigation-bridging)
12
+ 4. [Share models](#4-data-sharing-between-uikit-and-swiftui)
13
+ 5. [SwiftUI cells](#5-uihostingconfiguration-ios-16)
14
+ 6. [Pass environment and traits](#6-environment-bridging)
15
15
 
16
16
  ## 1. Screen-by-Screen Migration
17
17
 
18
- Replace one `UIViewController` at a time with a `UIHostingController` wrapping a SwiftUI view. This is the safest migration path -- each screen is an isolated unit.
19
-
20
- ### Strategy
21
-
22
- 1. Pick a leaf screen (one that does not contain child view controllers).
23
- 2. Rewrite its UI in SwiftUI.
24
- 3. Replace the UIKit view controller with `UIHostingController` wherever it was instantiated.
25
- 4. Wire navigation from the parent UIKit code into the hosting controller.
26
-
27
- ### Implementation
28
-
29
- ```swift
30
- // BEFORE: UIKit screen pushed onto a navigation stack
31
- let detailVC = ItemDetailViewController(item: item)
32
- navigationController?.pushViewController(detailVC, animated: true)
33
-
34
- // AFTER: SwiftUI screen wrapped in UIHostingController
35
- let detailView = ItemDetailView(item: item)
36
- let hostingVC = UIHostingController(rootView: detailView)
37
- navigationController?.pushViewController(hostingVC, animated: true)
38
- ```
18
+ The lowest-risk route is to replace whole view controllers, one at a time, with
19
+ a `UIHostingController` that wraps the new SwiftUI screen.
39
20
 
40
- ### Passing Dismiss/Navigation Callbacks
21
+ Order of work:
41
22
 
42
- When the SwiftUI screen needs to pop itself or trigger navigation in the UIKit stack:
23
+ 1. Choose a leaf screen, one that embeds no child view controllers.
24
+ 2. Rebuild it in SwiftUI.
25
+ 3. Replace the old controller wherever it was instantiated.
26
+ 4. Connect the surrounding UIKit navigation to the hosting controller.
43
27
 
44
28
  ```swift
45
- struct ItemDetailView: View {
46
- let item: Item
47
- var onDelete: (() -> Void)?
48
-
49
- @Environment(\.dismiss) private var dismiss
50
-
51
- var body: some View {
52
- VStack {
53
- Text(item.title)
54
- Button("Delete", role: .destructive) {
55
- onDelete?()
56
- dismiss()
57
- }
58
- }
59
- }
60
- }
61
-
62
- // In UIKit:
63
- let detailView = ItemDetailView(item: item) {
64
- self.dataSource.delete(item)
65
- self.navigationController?.popViewController(animated: true)
66
- }
67
- let hostingVC = UIHostingController(rootView: detailView)
29
+ // Before: navigationController?.pushViewController(InvoiceDetailViewController(invoice: invoice), animated: true)
30
+ let detail = InvoiceDetailView(invoice: invoice, onVoid: { [weak self] in
31
+ self?.ledger.void(invoice)
32
+ self?.navigationController?.popViewController(animated: true)
33
+ })
34
+ let host = UIHostingController(rootView: detail)
35
+ navigationController?.pushViewController(host, animated: true)
68
36
  ```
69
37
 
70
- ### Gotchas
38
+ The SwiftUI view takes a callback such as `onVoid`; the UIKit side supplies the
39
+ closure that changes data and pops the screen.
71
40
 
72
- - **Navigation bar.** `UIHostingController` inherits navigation bar visibility from its parent `UINavigationController`. Use `.navigationTitle()` and `.toolbar()` in the SwiftUI view -- they propagate to the UIKit navigation bar automatically.
73
- - **Large titles.** Set `hostingVC.navigationItem.largeTitleDisplayMode` in UIKit code if the SwiftUI `.navigationBarTitleDisplayMode()` modifier does not apply correctly.
74
- - **Tab bar insets.** `UIHostingController` respects `additionalSafeAreaInsets`. If the content overlaps the tab bar, verify safe area propagation.
41
+ Navigation bar behaviour:
75
42
 
76
- ---
43
+ - `.navigationTitle()` and `.toolbar()` inside the hosted view show up in the
44
+ UIKit navigation bar. Whether the bar is visible is decided by the parent
45
+ `UINavigationController`.
46
+ - If `.navigationBarTitleDisplayMode()` does not take effect, set
47
+ `host.navigationItem.largeTitleDisplayMode` from UIKit instead.
48
+ - `UIHostingController` respects `additionalSafeAreaInsets`. If content slides
49
+ under the tab bar, check how the safe area reaches the hosted view.
77
50
 
78
51
  ## 2. UIHostingController as Child
79
52
 
80
- Embed SwiftUI sections within an existing UIKit screen. Use when migrating part of a screen (a header, a card, a section) before rewriting the entire controller.
81
-
82
- ### Implementation
53
+ Use a child hosting controller to migrate a region of a screen, such as a
54
+ header, a card or a section, before rewriting the rest.
83
55
 
84
56
  ```swift
85
- final class DashboardViewController: UIViewController {
86
- private var statsHostingController: UIHostingController<StatsCardView>?
57
+ final class AccountViewController: UIViewController {
58
+ private var balanceHost: UIHostingController<BalanceCard>?
59
+ private let cardContainer = UIView()
87
60
 
88
61
  override func viewDidLoad() {
89
62
  super.viewDidLoad()
90
-
91
- let statsView = StatsCardView(stats: currentStats)
92
- let hostingVC = UIHostingController(rootView: statsView)
93
-
94
- // Enable intrinsic sizing so Auto Layout can size the hosted view
63
+ let host = UIHostingController(rootView: BalanceCard(amount: 0))
95
64
  if #available(iOS 16.0, *) {
96
- hostingVC.sizingOptions = [.intrinsicContentSize]
65
+ host.sizingOptions = [.intrinsicContentSize]
97
66
  }
67
+ host.view.backgroundColor = .clear
98
68
 
99
- addChild(hostingVC)
100
- hostingVC.view.translatesAutoresizingMaskIntoConstraints = false
101
- containerView.addSubview(hostingVC.view)
102
-
69
+ addChild(host)
70
+ host.view.translatesAutoresizingMaskIntoConstraints = false
71
+ cardContainer.addSubview(host.view)
103
72
  NSLayoutConstraint.activate([
104
- hostingVC.view.topAnchor.constraint(equalTo: containerView.topAnchor),
105
- hostingVC.view.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
106
- hostingVC.view.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
107
- hostingVC.view.bottomAnchor.constraint(equalTo: containerView.bottomAnchor),
73
+ host.view.topAnchor.constraint(equalTo: cardContainer.topAnchor),
74
+ host.view.bottomAnchor.constraint(equalTo: cardContainer.bottomAnchor),
75
+ host.view.leadingAnchor.constraint(equalTo: cardContainer.leadingAnchor),
76
+ host.view.trailingAnchor.constraint(equalTo: cardContainer.trailingAnchor)
108
77
  ])
109
-
110
- hostingVC.didMove(toParent: self)
111
- statsHostingController = hostingVC
78
+ host.didMove(toParent: self)
79
+ balanceHost = host
112
80
  }
113
81
 
114
- func updateStats(_ stats: Stats) {
115
- statsHostingController?.rootView = StatsCardView(stats: stats)
116
- }
117
- }
118
- ```
119
-
120
- ### With `@Observable` Model
121
-
122
- Pass an `@Observable` model to avoid reassigning `rootView` manually. SwiftUI tracks changes automatically:
123
-
124
- ```swift
125
- @Observable
126
- final class DashboardModel {
127
- var stats: Stats = .empty
128
- var isLoading = false
129
- }
130
-
131
- struct StatsCardView: View {
132
- let model: DashboardModel
133
-
134
- var body: some View {
135
- // Automatically re-renders when model.stats changes
136
- if model.isLoading {
137
- ProgressView()
138
- } else {
139
- StatsGrid(stats: model.stats)
140
- }
82
+ func show(amount: Decimal) {
83
+ balanceHost?.rootView = BalanceCard(amount: amount)
141
84
  }
142
85
  }
143
-
144
- // In UIKit:
145
- let model = DashboardModel()
146
- let hostingVC = UIHostingController(rootView: StatsCardView(model: model))
147
-
148
- // Later -- just mutate the model, no rootView reassignment needed
149
- model.stats = newStats
150
86
  ```
151
87
 
152
- ### Gotchas
88
+ With an `@Observable` model passed into the card instead, mutate the model and
89
+ leave `rootView` alone; SwiftUI picks up the change.
153
90
 
154
- - **Background color.** `UIHostingController`'s view has an opaque system background by default. Set `hostingVC.view.backgroundColor = .clear` if embedding over existing content.
155
- - **sizingOptions on iOS 16+.** Without `.intrinsicContentSize`, the hosted view may report zero size in Auto Layout, causing the container to collapse.
156
- - **Memory.** Store the hosting controller in a property. If it is only held as a child, removing it from the parent deallocates it and the SwiftUI view disappears.
91
+ Pitfalls:
157
92
 
158
- ---
93
+ - By default the hosting view paints the opaque system background. Set
94
+ `view.backgroundColor = .clear` when it sits over existing UIKit content.
95
+ - Without `.intrinsicContentSize` the hosted view can report a zero size and
96
+ the container collapses.
97
+ - Keep a stored reference to the hosting controller. Removing the child would
98
+ otherwise free it and the view vanishes.
159
99
 
160
100
  ## 3. Navigation Bridging
161
101
 
162
- Mix UIKit and SwiftUI screens in the same `UINavigationController` stack.
102
+ UIKit screens and SwiftUI screens can live on the same `UINavigationController`
103
+ stack.
163
104
 
164
- ### UIKit Pushing SwiftUI
105
+ **UIKit pushes SwiftUI.** Wrap the view, give the host a `title`, push it:
165
106
 
166
107
  ```swift
167
- // From a UIKit view controller, push a SwiftUI screen
168
- func showProfile(for user: User) {
169
- let profileView = ProfileView(user: user)
170
- let hostingVC = UIHostingController(rootView: profileView)
171
- hostingVC.title = user.name
172
- navigationController?.pushViewController(hostingVC, animated: true)
173
- }
108
+ let host = UIHostingController(rootView: ReceiptsView())
109
+ host.title = "Receipts"
110
+ navigationController?.pushViewController(host, animated: true)
174
111
  ```
175
112
 
176
- ### SwiftUI Pushing UIKit
177
-
178
- Use a coordinator or `UIViewControllerRepresentable` bridge:
113
+ **SwiftUI presents UIKit.** Present a representable from `.sheet` that returns
114
+ a `UINavigationController(rootViewController:)` around the legacy controller:
179
115
 
180
116
  ```swift
181
- struct ProfileView: View {
182
- let user: User
183
- @State private var showLegacyEditor = false
184
-
185
- var body: some View {
186
- List {
187
- // ... profile content
188
- Button("Edit (Legacy)") { showLegacyEditor = true }
189
- }
190
- .sheet(isPresented: $showLegacyEditor) {
191
- LegacyEditorWrapper(user: user)
192
- }
193
- }
194
- }
195
-
196
- struct LegacyEditorWrapper: UIViewControllerRepresentable {
197
- let user: User
198
-
117
+ struct LegacyExportFlow: UIViewControllerRepresentable {
199
118
  func makeUIViewController(context: Context) -> UINavigationController {
200
- let editor = ProfileEditorViewController(user: user)
201
- return UINavigationController(rootViewController: editor)
119
+ UINavigationController(rootViewController: ExportOptionsViewController())
202
120
  }
203
-
204
- func updateUIViewController(_ uiViewController: UINavigationController, context: Context) {}
121
+ func updateUIViewController(_ nav: UINavigationController, context: Context) {}
205
122
  }
206
- ```
207
123
 
208
- ### Passing NavigationController Reference
124
+ // .sheet(isPresented: $exporting) { LegacyExportFlow() }
125
+ ```
209
126
 
210
- For deep integration where SwiftUI needs to push onto the UIKit navigation stack:
127
+ **Deep integration.** Give SwiftUI views a small bridge to the UIKit stack
128
+ through the environment:
211
129
 
212
130
  ```swift
213
- struct NavigationBridge {
131
+ struct UIKitNavigator {
214
132
  weak var navigationController: UINavigationController?
215
133
 
216
- func push(_ viewController: UIViewController, animated: Bool = true) {
217
- navigationController?.pushViewController(viewController, animated: animated)
134
+ @MainActor
135
+ func push(_ controller: UIViewController, animated: Bool = true) {
136
+ navigationController?.pushViewController(controller, animated: animated)
218
137
  }
219
138
 
220
- func push<V: View>(_ view: V, title: String? = nil, animated: Bool = true) {
221
- let hostingVC = UIHostingController(rootView: view)
222
- hostingVC.title = title
223
- navigationController?.pushViewController(hostingVC, animated: animated)
139
+ @MainActor
140
+ func push<Content: View>(_ view: Content, title: String, animated: Bool = true) {
141
+ let host = UIHostingController(rootView: view)
142
+ host.title = title
143
+ navigationController?.pushViewController(host, animated: animated)
224
144
  }
225
145
  }
226
146
 
227
- // Inject via environment
228
- private struct NavigationBridgeKey: EnvironmentKey {
229
- static let defaultValue = NavigationBridge()
147
+ private struct UIKitNavigatorKey: EnvironmentKey {
148
+ static var defaultValue: UIKitNavigator { UIKitNavigator() }
230
149
  }
231
150
 
232
151
  extension EnvironmentValues {
233
- var navigationBridge: NavigationBridge {
234
- get { self[NavigationBridgeKey.self] }
235
- set { self[NavigationBridgeKey.self] = newValue }
152
+ var uikitNavigator: UIKitNavigator {
153
+ get { self[UIKitNavigatorKey.self] }
154
+ set { self[UIKitNavigatorKey.self] = newValue }
236
155
  }
237
156
  }
238
157
  ```
239
158
 
240
- ### Gotchas
159
+ Set it on the root view before creating the host:
160
+ `ReceiptsView().environment(\.uikitNavigator, UIKitNavigator(navigationController: navigationController))`.
241
161
 
242
- - **Back button.** When pushing `UIHostingController` onto a `UINavigationController`, the back button works automatically. Do not add a manual back button in the SwiftUI view.
243
- - **Double navigation bars.** If the SwiftUI view uses `NavigationStack`, it creates its own navigation bar inside the UIKit one. Remove `NavigationStack` from SwiftUI views presented inside `UINavigationController`.
244
- - **Toolbar items.** SwiftUI `.toolbar` items propagate to the UIKit navigation bar when hosted in `UIHostingController`. This works reliably on iOS 16+.
162
+ Notes:
245
163
 
246
- ---
164
+ - A pushed hosting controller gets the standard back button automatically. Do
165
+ not add your own.
166
+ - Do not put a `NavigationStack` inside a hosting controller that is already on
167
+ a `UINavigationController`; you get two navigation bars. Remove the
168
+ `NavigationStack`.
169
+ - On iOS 16 and later, SwiftUI `.toolbar` items reliably appear in the UIKit
170
+ navigation bar.
247
171
 
248
172
  ## 4. Data Sharing Between UIKit and SwiftUI
249
173
 
250
- ### Using `@Observable` (iOS 17+)
251
-
252
- The cleanest approach. Create an `@Observable` model, pass it to both UIKit and SwiftUI code:
174
+ **Preferred (iOS 17+): one `@Observable` model for both sides.** SwiftUI tracks
175
+ it automatically; UIKit reads its properties directly.
253
176
 
254
177
  ```swift
255
178
  @Observable
256
- final class AppState {
257
- var currentUser: User?
258
- var unreadCount: Int = 0
259
- var theme: AppTheme = .system
260
- }
261
-
262
- // UIKit side -- read properties directly
263
- let state = AppState()
264
- func viewDidLoad() {
265
- titleLabel.text = state.currentUser?.name
266
- }
267
-
268
- // SwiftUI side -- observation is automatic
269
- struct HeaderView: View {
270
- let state: AppState
271
-
272
- var body: some View {
273
- HStack {
274
- Text(state.currentUser?.name ?? "Guest")
275
- if state.unreadCount > 0 {
276
- Badge(count: state.unreadCount)
277
- }
278
- }
279
- }
179
+ @MainActor
180
+ final class CartModel {
181
+ var itemCount = 0
280
182
  }
281
183
  ```
282
184
 
283
- ### Reactive Updates in UIKit with Combine
284
-
285
- If UIKit code needs to react to `@Observable` changes, bridge with a `withObservationTracking` loop or use `Combine`:
185
+ `@Observable` does not push changes into UIKit by itself. A UIKit controller
186
+ has to observe explicitly, for example with `withObservationTracking` inside a
187
+ long-lived task:
286
188
 
287
189
  ```swift
288
- import Combine
289
- import Observation
190
+ final class CartBadgeViewController: UIViewController {
191
+ private let cart: CartModel
192
+ private var observation: Task<Void, Never>?
290
193
 
291
- final class DashboardViewController: UIViewController {
292
- let state: AppState
293
- private var observationTask: Task<Void, Never>?
194
+ init(cart: CartModel) {
195
+ self.cart = cart
196
+ super.init(nibName: nil, bundle: .main)
197
+ }
198
+ required init?(coder: NSCoder) { fatalError("init(coder:) is not supported") }
294
199
 
295
200
  override func viewDidLoad() {
296
201
  super.viewDidLoad()
297
- startObserving()
298
- }
299
-
300
- private func startObserving() {
301
- observationTask = Task { @MainActor [weak self] in
202
+ observation = Task { @MainActor [weak self, cart] in
302
203
  while !Task.isCancelled {
303
- guard let self else { return }
304
- withObservationTracking {
305
- self.updateUI(unreadCount: self.state.unreadCount)
306
- } onChange: {
307
- // Triggers next iteration
204
+ await withCheckedContinuation { continuation in
205
+ withObservationTracking {
206
+ self?.title = "\(cart.itemCount) items"
207
+ } onChange: {
208
+ continuation.resume()
209
+ }
308
210
  }
309
- try? await Task.sleep(for: .zero) // Yield to allow onChange to fire
310
211
  }
311
212
  }
312
213
  }
313
214
 
314
- private func updateUI(unreadCount: Int) {
315
- badgeLabel.text = "\(unreadCount)"
316
- }
317
-
318
- deinit { observationTask?.cancel() }
215
+ deinit { observation?.cancel() }
319
216
  }
320
217
  ```
321
218
 
322
- ### Legacy: ObservableObject with Combine
219
+ Each pass applies the current value, registers tracking, and suspends until
220
+ the next change. A variant that loops and yields with `Task.sleep(for: .zero)`
221
+ also works, but it wakes constantly; waiting on the `onChange` signal does not.
222
+ The task holds `self` weakly, and `deinit` cancels it; a cancelled task leaves the loop at the next change.
323
223
 
324
- For iOS 15-16 or existing `ObservableObject` models, subscribe to `objectWillChange`:
224
+ **Legacy (iOS 15 and 16, or an `ObservableObject`).** Subscribe to
225
+ `objectWillChange` with Combine and keep the cancellable:
325
226
 
326
227
  ```swift
327
- final class SettingsViewController: UIViewController {
328
- let settings: SettingsModel // ObservableObject
329
- private var cancellable: AnyCancellable?
330
-
331
- override func viewDidLoad() {
332
- super.viewDidLoad()
333
- cancellable = settings.objectWillChange
334
- .receive(on: RunLoop.main)
335
- .sink { [weak self] _ in
336
- self?.updateUI()
337
- }
228
+ cancellable = store.objectWillChange
229
+ .receive(on: RunLoop.main)
230
+ .sink { [weak self] _ in
231
+ self?.refreshBadge()
338
232
  }
339
- }
340
233
  ```
341
234
 
342
- ### Gotchas
343
-
344
- - **`@Observable` does not trigger UIKit updates automatically.** Unlike SwiftUI views, UIKit code must manually observe changes via `withObservationTracking` or `Combine`.
345
- - **Thread safety.** Mutate `@Observable` properties on `@MainActor` when they drive UI in both UIKit and SwiftUI.
346
- - **Retain cycles.** Use `[weak self]` in Combine sinks and task closures. Store cancellables and tasks, then cancel in `deinit`.
235
+ Rules:
347
236
 
348
- ---
237
+ - Change UI-driving properties of an `@Observable` model on the `@MainActor`.
238
+ - Capture `[weak self]` in sinks and task closures. Keep cancellables and tasks
239
+ in stored properties and cancel them in `deinit`.
349
240
 
350
241
  ## 5. UIHostingConfiguration (iOS 16+)
351
242
 
352
- Render SwiftUI content inside `UICollectionViewCell` and `UITableViewCell` without managing a child `UIHostingController`. This is the preferred approach for cells in a UIKit collection or table view.
353
-
354
- ### UICollectionView with SwiftUI Cells
243
+ This is the preferred way to put SwiftUI content into UIKit collection and
244
+ table view cells.
355
245
 
356
246
  ```swift
357
- @available(iOS 16.0, *)
358
- func collectionView(
359
- _ collectionView: UICollectionView,
360
- cellForItemAt indexPath: IndexPath
361
- ) -> UICollectionViewCell {
362
- let cell = collectionView.dequeueReusableCell(
363
- withReuseIdentifier: "cell",
364
- for: indexPath
365
- )
366
- let item = dataSource[indexPath.item]
367
-
368
- cell.contentConfiguration = UIHostingConfiguration {
369
- HStack {
370
- AsyncImage(url: item.imageURL) { image in
371
- image.resizable().scaledToFill()
372
- } placeholder: {
373
- ProgressView()
374
- }
375
- .frame(width: 60, height: 60)
376
- .clipShape(.rect(cornerRadius: 8))
377
-
378
- VStack(alignment: .leading) {
379
- Text(item.title).font(.headline)
380
- Text(item.subtitle).font(.subheadline).foregroundStyle(.secondary)
381
- }
247
+ cell.contentConfiguration = UIHostingConfiguration {
248
+ HStack(spacing: 12) {
249
+ AsyncImage(url: product.thumbnailURL) { image in
250
+ image.resizable().scaledToFill()
251
+ } placeholder: {
252
+ ProgressView()
382
253
  }
254
+ .frame(width: 56, height: 56)
255
+ .clipShape(.rect(cornerRadius: 8))
256
+ Text(product.name)
383
257
  }
384
- .margins(.all, 12)
385
-
386
- return cell
387
258
  }
259
+ .margins(.all, 12)
388
260
  ```
389
261
 
390
- ### UITableView with SwiftUI Cells
391
-
392
- ```swift
393
- @available(iOS 16.0, *)
394
- func tableView(
395
- _ tableView: UITableView,
396
- cellForRowAt indexPath: IndexPath
397
- ) -> UITableViewCell {
398
- let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
399
- let item = items[indexPath.row]
400
-
401
- cell.contentConfiguration = UIHostingConfiguration {
402
- ItemRowView(item: item)
403
- }
404
-
405
- return cell
406
- }
407
- ```
408
-
409
- ### Self-Sizing
410
-
411
- `UIHostingConfiguration` cells self-size automatically. Ensure:
412
- - The table/collection view uses `UICollectionViewCompositionalLayout` with estimated dimensions, or `tableView.rowHeight = UITableView.automaticDimension`.
413
- - The SwiftUI content has defined height (via content or explicit `.frame`).
414
-
415
- ### Background Customization
262
+ Table views work the same way inside `tableView(_:cellForRowAt:)`:
416
263
 
417
264
  ```swift
265
+ let cell = tableView.dequeueReusableCell(withIdentifier: "order", for: indexPath)
418
266
  cell.contentConfiguration = UIHostingConfiguration {
419
- ItemRowView(item: item)
267
+ OrderRowView(order: orders[indexPath.row])
420
268
  }
421
- .background {
422
- RoundedRectangle(cornerRadius: 12)
423
- .fill(.background)
424
- }
425
- .margins(.horizontal, 16)
426
- .minSize(height: 60)
269
+ return cell
427
270
  ```
428
271
 
429
- ### Gotchas
272
+ Configuration modifiers include `.background { }`, `.margins(.horizontal, 16)`
273
+ and `.minSize(height: 60)`.
430
274
 
431
- - **Performance.** Each `UIHostingConfiguration` creates a lightweight hosting controller. For very large lists (10,000+ items), profile with Instruments to ensure smooth scrolling.
432
- - **State management.** The SwiftUI content inside `UIHostingConfiguration` is recreated on each cell reuse. Do not store `@State` that needs to persist across reuse -- use the data model instead.
433
- - **Swipe actions.** Configure swipe actions in UIKit (`leadingSwipeActionsConfigurationForRowAt`), not inside the SwiftUI content.
434
- - **No `@Environment` propagation by default.** Environment values from the UIKit context are not automatically available. Inject them explicitly in the `UIHostingConfiguration` closure.
275
+ Notes:
435
276
 
436
- ---
277
+ - Self-sizing needs a `UICollectionViewCompositionalLayout` with estimated
278
+ dimensions (for tables, `rowHeight` set to `UITableView.automaticDimension`), plus
279
+ SwiftUI content that has a definite height.
280
+ - Behind every configuration sits a small hosting controller. For huge
281
+ lists (10,000 items and up) measure with Instruments.
282
+ - The content is rebuilt when a cell is reused. `@State` inside it does not
283
+ survive reuse; keep such state in the data model.
284
+ - Swipe actions belong to UIKit (`leadingSwipeActionsConfigurationForRowAt`),
285
+ not to the SwiftUI content.
286
+ - Environment values from the surrounding UIKit context are not passed in
287
+ automatically. Inject what you need inside the configuration closure.
437
288
 
438
289
  ## 6. Environment Bridging
439
290
 
440
- Pass SwiftUI environment values into hosted SwiftUI views from UIKit, and access UIKit traits from SwiftUI.
441
-
442
- ### Injecting Environment into UIHostingController
291
+ Environment has to be attached before the hosting controller exists. Apply
292
+ `.environment(model)` (iOS 17, for an `@Observable` model),
293
+ `.environment(\.locale, ...)` and similar modifiers to the root view, then
294
+ create the host. Adding environment afterwards means
295
+ assigning a new `rootView`.
443
296
 
444
297
  ```swift
445
- let model = AppState()
446
- let settingsView = SettingsView()
447
- .environment(model)
448
- .environment(\.locale, Locale(identifier: "en_US"))
449
-
450
- let hostingVC = UIHostingController(rootView: settingsView)
298
+ let root = SettingsView()
299
+ .environment(session)
300
+ .environment(\.locale, Locale(identifier: "fr_FR"))
301
+ let host = UIHostingController(rootView: root)
451
302
  ```
452
303
 
453
- Apply environment modifiers to the root view before passing it to the hosting controller. The hosting controller does not support adding environment values after creation (you would need to reassign `rootView`).
304
+ Traits that bridge on their own:
454
305
 
455
- ### Trait Collection to SwiftUI Environment
456
-
457
- `UIHostingController` automatically bridges these UIKit trait collections to SwiftUI environment values:
458
-
459
- | UIKit Trait | SwiftUI Environment |
460
- |------------|-------------------|
306
+ | UIKit trait | SwiftUI environment |
307
+ |-------------|---------------------|
461
308
  | `userInterfaceStyle` | `\.colorScheme` |
462
309
  | `horizontalSizeClass` | `\.horizontalSizeClass` |
463
310
  | `verticalSizeClass` | `\.verticalSizeClass` |
@@ -465,70 +312,40 @@ Apply environment modifiers to the root view before passing it to the hosting co
465
312
  | `layoutDirection` | `\.layoutDirection` |
466
313
  | `legibilityWeight` | `\.legibilityWeight` |
467
314
 
468
- These update automatically when the UIKit trait environment changes (device rotation, split view resize, accessibility settings change).
315
+ These stay current as the device rotates, a split view resizes, or an
316
+ accessibility setting changes. `host.overrideUserInterfaceStyle` forces light
317
+ or dark and flows through to `\.colorScheme`.
469
318
 
470
- ### Custom Environment Values Across the Bridge
319
+ **Custom values.** Declare an `EnvironmentKey` with a `defaultValue`, extend
320
+ `EnvironmentValues`, set it from UIKit with `.environment(\.yourKey, value)`
321
+ and read it in SwiftUI with `@Environment(\.yourKey)`. The navigator in pattern
322
+ 3 is an example.
471
323
 
472
- Define a custom environment key and set it from UIKit:
324
+ **Changing environment after creation (iOS 17+).** Wrap the content in a
325
+ container view that reads an `@Observable` state object and applies the environment. Mutating
326
+ that object then updates the environment without touching `rootView`.
473
327
 
474
328
  ```swift
475
- private struct UserRoleKey: EnvironmentKey {
476
- static let defaultValue: UserRole = .guest
477
- }
478
-
479
- extension EnvironmentValues {
480
- var userRole: UserRole {
481
- get { self[UserRoleKey.self] }
482
- set { self[UserRoleKey.self] = newValue }
483
- }
484
- }
485
-
486
- // UIKit side:
487
- let role = authManager.currentRole
488
- let profileView = ProfileView().environment(\.userRole, role)
489
- let hostingVC = UIHostingController(rootView: profileView)
490
-
491
- // SwiftUI side:
492
- struct ProfileView: View {
493
- @Environment(\.userRole) private var role
494
-
495
- var body: some View {
496
- if role == .admin {
497
- AdminDashboard()
498
- } else {
499
- UserDashboard()
500
- }
501
- }
329
+ @Observable
330
+ @MainActor
331
+ final class HostedEnvironment {
332
+ var locale = Locale.current
502
333
  }
503
- ```
504
-
505
- ### Updating Environment After Creation
506
-
507
- To change environment values after the hosting controller is created, wrap the root view in a container that takes a binding or observable:
508
334
 
509
- ```swift
510
335
  struct EnvironmentBridge<Content: View>: View {
511
- let state: AppState // @Observable
512
- let content: Content
336
+ let state: HostedEnvironment
337
+ @ViewBuilder var content: Content
513
338
 
514
339
  var body: some View {
515
- content
516
- .environment(state)
517
- .environment(\.userRole, state.currentRole)
340
+ content.environment(\.locale, state.locale)
518
341
  }
519
342
  }
520
-
521
- // UIKit:
522
- let state = AppState()
523
- let bridge = EnvironmentBridge(state: state, content: SettingsView())
524
- let hostingVC = UIHostingController(rootView: bridge)
525
-
526
- // Later: mutating state.currentRole updates the environment automatically
527
- state.currentRole = .admin
528
343
  ```
529
344
 
530
- ### Gotchas
345
+ Pitfalls:
531
346
 
532
- - **`@Environment(\.dismiss)` in hosted views.** This works when the `UIHostingController` is presented modally (via `present(_:animated:)`). It does NOT work when the hosting controller is pushed onto a `UINavigationController` -- use the navigation controller's `popViewController` instead.
533
- - **Missing environment.** If a SwiftUI view expects an `@Environment` object and it is not provided, the app crashes at runtime. Always set required environment values before creating the hosting controller.
534
- - **Overriding traits.** Use `hostingVC.overrideUserInterfaceStyle` to force light/dark mode for a hosted SwiftUI view. This propagates to `\.colorScheme` automatically.
347
+ - `@Environment(\.dismiss)` inside a hosted view works when the host was shown
348
+ with `present(_:animated:)`. It does nothing when the host was pushed onto a
349
+ `UINavigationController`; call `popViewController(animated:)` there instead.
350
+ - A required environment object that is missing crashes at runtime. Set every
351
+ one before creating the hosting controller.