@mmerterden/multi-agent-pipeline 20.6.0 → 20.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (326) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/LICENSE +0 -10
  3. package/docs/facts.json +1 -1
  4. package/manifest.json +328 -329
  5. package/package.json +2 -2
  6. package/pipeline/multi-agent-refs/features/design-conformance.md +62 -64
  7. package/pipeline/scripts/_notices.mjs +12 -1
  8. package/pipeline/scripts/gen-skills-index.mjs +1 -1
  9. package/pipeline/skills/.skill-manifest.json +106 -106
  10. package/pipeline/skills/shared/README.md +71 -71
  11. package/pipeline/skills/shared/external/agent-introspection-debugging/SKILL.md +1 -0
  12. package/pipeline/skills/shared/external/alarmkit/SKILL.md +373 -381
  13. package/pipeline/skills/shared/external/alarmkit/evals/evals.json +23 -18
  14. package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +328 -378
  15. package/pipeline/skills/shared/external/android-architecture/SKILL.md +2 -0
  16. package/pipeline/skills/shared/external/android-performance/SKILL.md +2 -0
  17. package/pipeline/skills/shared/external/android-security/SKILL.md +2 -0
  18. package/pipeline/skills/shared/external/app-clips/SKILL.md +260 -160
  19. package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
  20. package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
  21. package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
  22. package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
  23. package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
  24. package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
  25. package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
  26. package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +339 -277
  27. package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
  28. package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +105 -122
  29. package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +143 -166
  30. package/pipeline/skills/shared/external/app-store-review/SKILL.md +307 -326
  31. package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
  32. package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
  33. package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
  34. package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +333 -360
  35. package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
  36. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
  37. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
  38. package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
  39. package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
  40. package/pipeline/skills/shared/external/authentication/SKILL.md +265 -381
  41. package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
  42. package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +133 -178
  43. package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
  44. package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
  45. package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
  46. package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
  47. package/pipeline/skills/shared/external/background-processing/SKILL.md +270 -382
  48. package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
  49. package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +169 -317
  50. package/pipeline/skills/shared/external/backlog/BACKLOG.md +1 -1
  51. package/pipeline/skills/shared/external/backlog/SKILL.md +56 -33
  52. package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
  53. package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
  54. package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
  55. package/pipeline/skills/shared/external/ci-cd-pipelines/SKILL.md +1 -0
  56. package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
  57. package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
  58. package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
  59. package/pipeline/skills/shared/external/compose-components/SKILL.md +2 -0
  60. package/pipeline/skills/shared/external/compose-navigation/SKILL.md +3 -2
  61. package/pipeline/skills/shared/external/compose-testing/SKILL.md +2 -0
  62. package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
  63. package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
  64. package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
  65. package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +226 -376
  66. package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
  67. package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
  68. package/pipeline/skills/shared/external/core-data/SKILL.md +292 -368
  69. package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
  70. package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
  71. package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
  72. package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
  73. package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
  74. package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
  75. package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
  76. package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
  77. package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
  78. package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
  79. package/pipeline/skills/shared/external/council/SKILL.md +1 -0
  80. package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
  81. package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
  82. package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
  83. package/pipeline/skills/shared/external/css-modern/SKILL.md +1 -0
  84. package/pipeline/skills/shared/external/database-patterns/SKILL.md +1 -0
  85. package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
  86. package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
  87. package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
  88. package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
  89. package/pipeline/skills/shared/external/device-integrity/SKILL.md +230 -353
  90. package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
  91. package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
  92. package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
  93. package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
  94. package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
  95. package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
  96. package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
  97. package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
  98. package/pipeline/skills/shared/external/evidence-github/SKILL.md +2 -0
  99. package/pipeline/skills/shared/external/evidence-registry/SKILL.md +2 -0
  100. package/pipeline/skills/shared/external/gradle-kotlin-dsl/SKILL.md +2 -0
  101. package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
  102. package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
  103. package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
  104. package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
  105. package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
  106. package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
  107. package/pipeline/skills/shared/external/html-semantic/SKILL.md +1 -0
  108. package/pipeline/skills/shared/external/humanizer/SKILL.md +1 -0
  109. package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
  110. package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
  111. package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
  112. package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
  113. package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
  114. package/pipeline/skills/shared/external/ios-coding-standard/SKILL.md +1 -0
  115. package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
  116. package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
  117. package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
  118. package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
  119. package/pipeline/skills/shared/external/ios-module-structure/SKILL.md +1 -0
  120. package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
  121. package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
  122. package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
  123. package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
  124. package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
  125. package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
  126. package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
  127. package/pipeline/skills/shared/external/ios-security/SKILL.md +2 -0
  128. package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
  129. package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
  130. package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
  131. package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
  132. package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
  133. package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
  134. package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +91 -283
  135. package/pipeline/skills/shared/external/localization-reuse-map/reference/format-and-output.md +119 -151
  136. package/pipeline/skills/shared/external/localization-reuse-map/reference/publish-and-snapshot.md +60 -90
  137. package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +119 -156
  138. package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-artifact.py +726 -787
  139. package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-spreadsheet.py +253 -288
  140. package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-annotations.py +243 -304
  141. package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-legacy-labels.py +88 -104
  142. package/pipeline/skills/shared/external/localization-reuse-map/scripts/publish-confluence.py +181 -235
  143. package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-key-shots.py +198 -263
  144. package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-overlay.py +461 -466
  145. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-legacy-values.py +145 -151
  146. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +123 -141
  147. package/pipeline/skills/shared/external/localization-reuse-map/scripts/scan-screen-keys.py +146 -157
  148. package/pipeline/skills/shared/external/localization-reuse-map/scripts/snapshot-resources.sh +22 -19
  149. package/pipeline/skills/shared/external/localization-reuse-map/scripts/verify-map.py +156 -140
  150. package/pipeline/skills/shared/external/mapkit-location/SKILL.md +295 -267
  151. package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
  152. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
  153. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
  154. package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
  155. package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
  156. package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
  157. package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
  158. package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
  159. package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
  160. package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
  161. package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
  162. package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
  163. package/pipeline/skills/shared/external/nextjs-app-router/SKILL.md +1 -0
  164. package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
  165. package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
  166. package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
  167. package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
  168. package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
  169. package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
  170. package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
  171. package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
  172. package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
  173. package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
  174. package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
  175. package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
  176. package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
  177. package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
  178. package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
  179. package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
  180. package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
  181. package/pipeline/skills/shared/external/play-store-review/SKILL.md +2 -0
  182. package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
  183. package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
  184. package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
  185. package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
  186. package/pipeline/skills/shared/external/python-patterns/SKILL.md +1 -0
  187. package/pipeline/skills/shared/external/react-best-practices/SKILL.md +1 -0
  188. package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
  189. package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
  190. package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
  191. package/pipeline/skills/shared/external/rest-api-design/SKILL.md +1 -0
  192. package/pipeline/skills/shared/external/retrofit-networking/SKILL.md +2 -0
  193. package/pipeline/skills/shared/external/room-database/SKILL.md +2 -0
  194. package/pipeline/skills/shared/external/search-first/SKILL.md +1 -0
  195. package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
  196. package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
  197. package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
  198. package/pipeline/skills/shared/external/signal-community/SKILL.md +2 -0
  199. package/pipeline/skills/shared/external/skill-creator/SKILL.md +80 -41
  200. package/pipeline/skills/shared/external/skill-creator/audit.md +63 -59
  201. package/pipeline/skills/shared/external/skill-creator/checklist.md +28 -20
  202. package/pipeline/skills/shared/external/skill-creator/examples.md +40 -40
  203. package/pipeline/skills/shared/external/skill-creator/label-check.md +48 -36
  204. package/pipeline/skills/shared/external/skill-creator/scripts/audit-panel.js +91 -100
  205. package/pipeline/skills/shared/external/skill-creator/template.md +51 -39
  206. package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
  207. package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
  208. package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
  209. package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
  210. package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
  211. package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
  212. package/pipeline/skills/shared/external/storekit/references/core-patterns.md +298 -242
  213. package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
  214. package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
  215. package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
  216. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
  217. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
  218. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
  219. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
  220. package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
  221. package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
  222. package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
  223. package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
  224. package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
  225. package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
  226. package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
  227. package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +303 -351
  228. package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
  229. package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
  230. package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
  231. package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
  232. package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
  233. package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
  234. package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
  235. package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
  236. package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
  237. package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
  238. package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
  239. package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
  240. package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
  241. package/pipeline/skills/shared/external/swift-security/SKILL.md +180 -161
  242. package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
  243. package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
  244. package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +408 -476
  245. package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
  246. package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
  247. package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
  248. package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
  249. package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
  250. package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
  251. package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +352 -472
  252. package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
  253. package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
  254. package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
  255. package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +396 -457
  256. package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
  257. package/pipeline/skills/shared/external/swift-testing/SKILL.md +188 -175
  258. package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
  259. package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +80 -84
  260. package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
  261. package/pipeline/skills/shared/external/swiftdata/SKILL.md +392 -256
  262. package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
  263. package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
  264. package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
  265. package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
  266. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
  267. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
  268. package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
  269. package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
  270. package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
  271. package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
  272. package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
  273. package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
  274. package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
  275. package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
  276. package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
  277. package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
  278. package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
  279. package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
  280. package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
  281. package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
  282. package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
  283. package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
  284. package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
  285. package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
  286. package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +193 -168
  287. package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
  288. package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +132 -133
  289. package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
  290. package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +106 -140
  291. package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
  292. package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
  293. package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
  294. package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
  295. package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
  296. package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
  297. package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
  298. package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
  299. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
  300. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
  301. package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
  302. package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
  303. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
  304. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
  305. package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
  306. package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
  307. package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
  308. package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
  309. package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
  310. package/pipeline/skills/shared/external/tailwind-css/SKILL.md +1 -0
  311. package/pipeline/skills/shared/external/testing-backend/SKILL.md +1 -0
  312. package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
  313. package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
  314. package/pipeline/skills/shared/external/typescript-patterns/SKILL.md +1 -0
  315. package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
  316. package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
  317. package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
  318. package/pipeline/skills/shared/external/vue-composition/SKILL.md +1 -0
  319. package/pipeline/skills/shared/external/weatherkit/SKILL.md +152 -310
  320. package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
  321. package/pipeline/skills/shared/external/web-accessibility/SKILL.md +1 -0
  322. package/pipeline/skills/shared/external/web-performance/SKILL.md +1 -0
  323. package/pipeline/skills/shared/external/web-testing/SKILL.md +1 -0
  324. package/pipeline/skills/shared/external/widgetkit/SKILL.md +216 -288
  325. package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +414 -719
  326. package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +0 -39
@@ -1,430 +1,438 @@
1
1
  ---
2
2
  name: swiftui-uikit-interop
3
- description: "Bridges UIKit and SwiftUI by wrapping UIKit views and view controllers in SwiftUI with UIViewRepresentable and UIViewControllerRepresentable, embedding SwiftUI in UIKit with UIHostingController, and coordinating delegate callbacks. Use when integrating camera previews, map views, mail compose, document scanners, PDF renderers, text views with attributed text, or other UIKit-only or third-party UIKit SDK surfaces into a SwiftUI app, or when migrating a UIKit app to SwiftUI incrementally."
3
+ description: "UIKit and SwiftUI interop: UIViewRepresentable, UIViewControllerRepresentable, UIHostingController, UIHostingConfiguration, Coordinator delegate bridging. Use when SwiftUI needs a camera preview, map view, mail compose, document scanner, PDF renderer, attributed text view or another UIKit-only or third-party UIKit SDK surface, or when migrating a UIKit app to SwiftUI step by step. Not for web content (swiftui-webkit)."
4
4
  metadata:
5
- source: "dpearson2699/swift-ios-skills (PolyForm Perimeter 1.0.0)"
5
+ source: multi-agent-pipeline
6
6
  ---
7
7
 
8
- # SwiftUI-UIKit Interop
8
+ # SwiftUI and UIKit Interop
9
9
 
10
- Bridge UIKit and SwiftUI in both directions. Wrap UIKit views and view controllers for use in SwiftUI, embed SwiftUI views inside UIKit screens, and synchronize state across the boundary. Targets iOS 26+ with Swift 6.3 patterns; notes backward-compatible to iOS 16 unless stated otherwise.
10
+ SwiftUI and UIKit meet at three seams: a UIKit view or controller shown inside
11
+ SwiftUI (the representable protocols), SwiftUI shown inside UIKit (the hosting
12
+ controller and the hosting cell configuration), and the object that carries
13
+ UIKit callbacks back into SwiftUI state (the Coordinator). This skill covers all
14
+ three. Patterns target iOS 26 and Swift 6.3 and stay usable back to iOS 16
15
+ unless a section says otherwise.
11
16
 
12
- See [references/representable-recipes.md](references/representable-recipes.md) for complete wrapping recipes and [references/hosting-migration.md](references/hosting-migration.md) for UIKit-to-SwiftUI migration patterns.
17
+ Detailed material lives in two references:
13
18
 
14
- ## Contents
15
-
16
- - [UIViewRepresentable Protocol](#uiviewrepresentable-protocol)
17
- - [UIViewControllerRepresentable Protocol](#uiviewcontrollerrepresentable-protocol)
18
- - [The Coordinator Pattern](#the-coordinator-pattern)
19
- - [UIHostingController](#uihostingcontroller)
20
- - [Sizing and Layout](#sizing-and-layout)
21
- - [State Synchronization Patterns](#state-synchronization-patterns)
22
- - [Sendable Considerations](#sendable-considerations)
23
- - [Common Mistakes](#common-mistakes)
24
- - [Review Checklist](#review-checklist)
25
- - [References](#references)
19
+ - [wrapper recipes](references/representable-recipes.md):
20
+ nine complete wrappers (map, attributed text view, camera preview, photo
21
+ picker, mail, share sheet, search bar, PDF view, SMS) with usage and pitfalls.
22
+ - [migration guide](references/hosting-migration.md): moving a
23
+ UIKit app to SwiftUI one piece at a time, including navigation, shared data
24
+ and environment bridging.
26
25
 
27
- ## UIViewRepresentable Protocol
26
+ Embedded web content is out of scope: on iOS 26 use the native SwiftUI WebKit
27
+ types and the `swiftui-webkit` skill.
28
28
 
29
- Use `UIViewRepresentable` to wrap any `UIView` subclass for use in SwiftUI.
29
+ ## Contents
30
30
 
31
- ### Required Methods
31
+ 1. [Wrapping a view](#1-uiviewrepresentable)
32
+ 2. [Wrapping a controller](#2-uiviewcontrollerrepresentable)
33
+ 3. [Coordinators](#3-the-coordinator-pattern)
34
+ 4. [Hosting SwiftUI in a controller](#4-uihostingcontroller)
35
+ 5. [Hosting SwiftUI in cells](#5-uihostingconfiguration-ios-16)
36
+ 6. [Sizing](#6-sizing-and-layout)
37
+ 7. [Keeping state in sync](#7-state-synchronization)
38
+ 8. [Concurrency](#8-swift-concurrency-and-sendable)
39
+ 9. [Mistakes](#9-common-mistakes)
40
+ 10. [Checklist](#10-review-checklist)
41
+
42
+ ## 1. UIViewRepresentable
43
+
44
+ `UIViewRepresentable` lets SwiftUI display any `UIView` subclass. Two methods
45
+ are required:
46
+
47
+ - `makeUIView(context:)` builds and returns the UIKit view. SwiftUI calls it a
48
+ single time, when the representable is inserted. Put one-time setup here:
49
+ delegate assignment, fonts, static configuration.
50
+ - `updateUIView(_:context:)` pushes SwiftUI state into the view. It runs again
51
+ for every relevant state change, so compare before you assign. Writing a value
52
+ the view already holds can trigger a delegate callback that writes the binding
53
+ that calls update again.
32
54
 
33
55
  ```swift
34
- struct WrappedTextView: UIViewRepresentable {
35
- @Binding var text: String
56
+ import UIKit
57
+ import SwiftUI
58
+
59
+ struct PlainTextEditor: UIViewRepresentable {
60
+ @Binding var draft: String
61
+
62
+ func makeCoordinator() -> Coordinator { Coordinator(parent: self) }
36
63
 
37
64
  func makeUIView(context: Context) -> UITextView {
38
- // Called ONCE when SwiftUI inserts this view into the hierarchy.
39
- // Create and return the UIKit view. One-time setup goes here.
40
- let textView = UITextView()
41
- textView.delegate = context.coordinator
42
- textView.font = .preferredFont(forTextStyle: .body)
43
- return textView
65
+ let editor = UITextView(frame: .zero)
66
+ editor.delegate = context.coordinator
67
+ editor.font = .preferredFont(forTextStyle: .body)
68
+ return editor
44
69
  }
45
70
 
46
- func updateUIView(_ uiView: UITextView, context: Context) {
47
- // Called on EVERY SwiftUI state change that affects this view.
48
- // Synchronize SwiftUI state into the UIKit view.
49
- // Guard against redundant updates to avoid loops.
50
- if uiView.text != text {
51
- uiView.text = text
71
+ func updateUIView(_ editor: UITextView, context: Context) {
72
+ context.coordinator.parent = self
73
+ guard editor.text != draft else { return }
74
+ editor.text = draft
75
+ }
76
+
77
+ @MainActor
78
+ final class Coordinator: NSObject, UITextViewDelegate {
79
+ init(parent: PlainTextEditor) { self.parent = parent }
80
+ var parent: PlainTextEditor
81
+
82
+ func textViewDidChange(_ editor: UITextView) {
83
+ parent.draft = editor.text
52
84
  }
53
85
  }
54
86
  }
55
87
  ```
56
88
 
57
- ### Lifecycle Timing
89
+ ### Lifecycle order
58
90
 
59
- | Method | When Called | Purpose |
60
- |--------|-----------|---------|
61
- | `makeCoordinator()` | Before `makeUIView`. Once per representable lifetime. | Create the delegate/datasource reference type. |
62
- | `makeUIView(context:)` | Once, when the representable enters the view tree. | Allocate and configure the UIKit view. |
63
- | `updateUIView(_:context:)` | Immediately after `makeUIView`, then on every relevant state change. | Push SwiftUI state into the UIKit view. |
64
- | `dismantleUIView(_:coordinator:)` | When the representable is removed from the view tree. | Clean up observers, timers, subscriptions. |
65
- | `sizeThatFits(_:uiView:context:)` | During layout, when SwiftUI needs the view's ideal size. iOS 16+. | Return a custom size proposal. |
91
+ | Step | Method | When it runs | Job |
92
+ |------|--------|--------------|-----|
93
+ | 1 | `makeCoordinator()` | Before `makeUIView`, once for the representable's lifetime | Create the reference object that acts as delegate or data source |
94
+ | 2 | `makeUIView(context:)` | Once, when the view joins the tree | Build the UIKit object and set it up |
95
+ | 3 | `updateUIView(_:context:)` | Immediately after make, then on each relevant change | Copy SwiftUI state into UIKit |
96
+ | 4 | `dismantleUIView(_:coordinator:)` | When the view leaves the tree | Tear down: observers removed, timers invalidated, subscriptions cancelled |
97
+ | - | `sizeThatFits(_:uiView:context:)` | While laying out, if SwiftUI wants an ideal size (iOS 16+) | Report a custom size |
66
98
 
67
- **Why `updateUIView` is the most important method:** SwiftUI calls it every time any `@Binding`, `@State`, `@Environment`, or `@Observable` property read by the representable changes. All state synchronization from SwiftUI to UIKit happens here. If you skip a property, the UIKit view will fall out of sync.
99
+ SwiftUI calls `updateUIView` whenever anything the representable reads changes:
100
+ a `@Binding`, `@State`, `@Environment` value or a property of an `@Observable`
101
+ model. A property you forget to apply in `updateUIView` silently goes stale.
68
102
 
69
103
  ### Optional: dismantleUIView
70
104
 
105
+ `dismantleUIView` is a `static` function. SwiftUI hands it both the UIKit view
106
+ and the Coordinator, so anything the coordinator stores can be released there.
107
+
108
+ For a coordinator that keeps a list of cancellable observation tokens:
109
+
71
110
  ```swift
72
- static func dismantleUIView(_ uiView: UITextView, coordinator: Coordinator) {
73
- // Remove observers, invalidate timers, cancel subscriptions.
74
- // The coordinator is passed in so you can access state stored on it.
75
- coordinator.cancellables.removeAll()
111
+ static func dismantleUIView(_ editor: UITextView, coordinator: Coordinator) {
112
+ coordinator.observationTokens.forEach { $0.cancel() }
113
+ coordinator.observationTokens.removeAll()
76
114
  }
77
115
  ```
78
116
 
79
117
  ### Optional: sizeThatFits (iOS 16+)
80
118
 
119
+ A `nil` result means SwiftUI falls back to the view's `intrinsicContentSize`. Return a
120
+ `CGSize` and SwiftUI uses that size instead of its own choice.
121
+
81
122
  ```swift
82
123
  @available(iOS 16.0, *)
83
- func sizeThatFits(
84
- _ proposal: ProposedViewSize,
85
- uiView: UITextView,
86
- context: Context
87
- ) -> CGSize? {
88
- // Return nil to fall back to UIKit's intrinsicContentSize.
89
- // Return a CGSize to override SwiftUI's sizing for this view.
90
- let width = proposal.width ?? UIView.layoutFittingExpandedSize.width
91
- let size = uiView.sizeThatFits(CGSize(width: width, height: .greatestFiniteMagnitude))
92
- return size
124
+ func sizeThatFits(_ proposal: ProposedViewSize,
125
+ uiView editor: UITextView,
126
+ context: Context) -> CGSize? {
127
+ let targetWidth = proposal.width ?? UIView.layoutFittingExpandedSize.width
128
+ return editor.sizeThatFits(
129
+ CGSize(width: targetWidth, height: .greatestFiniteMagnitude)
130
+ )
93
131
  }
94
132
  ```
95
133
 
96
- ## UIViewControllerRepresentable Protocol
134
+ ## 2. UIViewControllerRepresentable
97
135
 
98
- Use `UIViewControllerRepresentable` to wrap a `UIViewController` subclass -- typically for system pickers, document scanners, mail compose, or any controller that presents modally.
136
+ Wrap a `UIViewController` subclass with `UIViewControllerRepresentable`. It is
137
+ the right choice for pickers the system provides, a scanner for documents, the
138
+ mail composer, and other controllers that are normally presented modally.
139
+ The methods mirror the view version: `makeUIViewController(context:)`, `updateUIViewController(_:context:)`
140
+ and `makeCoordinator()`. For a modal controller the update method usually
141
+ has nothing to push after presentation; it only refreshes the coordinator's
142
+ `parent`.
99
143
 
100
144
  ```swift
101
- struct DocumentScannerView: UIViewControllerRepresentable {
102
- @Binding var scannedImages: [UIImage]
103
- @Environment(\.dismiss) private var dismiss
145
+ import VisionKit
146
+ import SwiftUI
147
+
148
+ struct PageScannerView: UIViewControllerRepresentable {
149
+ @Environment(\.dismiss) var close
150
+ @Binding var pages: [UIImage]
151
+
152
+ func makeCoordinator() -> Coordinator { Coordinator(parent: self) }
104
153
 
105
154
  func makeUIViewController(context: Context) -> VNDocumentCameraViewController {
106
- let scanner = VNDocumentCameraViewController()
107
- scanner.delegate = context.coordinator
108
- return scanner
155
+ let camera = VNDocumentCameraViewController()
156
+ camera.delegate = context.coordinator
157
+ return camera
109
158
  }
110
159
 
111
- func updateUIViewController(_ uiViewController: VNDocumentCameraViewController, context: Context) {
112
- // Usually empty for modal controllers -- nothing to push from SwiftUI.
160
+ func updateUIViewController(_ camera: VNDocumentCameraViewController,
161
+ context: Context) {
162
+ context.coordinator.parent = self
113
163
  }
114
-
115
- func makeCoordinator() -> Coordinator { Coordinator(self) }
116
164
  }
117
165
  ```
118
166
 
119
- ### Handling Results from Presented Controllers
167
+ ### Returning results from a presented controller
120
168
 
121
- The coordinator captures delegate callbacks and routes results back to SwiftUI through the parent's `@Binding` or closures:
169
+ Delegate callbacks land in the Coordinator, which passes results on by writing
170
+ a `@Binding` or calling a closure stored on `parent`. Every exit path, success, cancel
171
+ and failure, ends by dismissing.
122
172
 
123
173
  ```swift
124
- extension DocumentScannerView {
125
- final class Coordinator: NSObject, VNDocumentCameraViewControllerDelegate {
126
- let parent: DocumentScannerView
127
-
128
- init(_ parent: DocumentScannerView) { self.parent = parent }
129
-
130
- func documentCameraViewController(
131
- _ controller: VNDocumentCameraViewController,
132
- didFinishWith scan: VNDocumentCameraScan
133
- ) {
134
- parent.scannedImages = (0..<scan.pageCount).map { scan.imageOfPage(at: $0) }
135
- parent.dismiss()
174
+ extension PageScannerView {
175
+ @MainActor
176
+ final class Coordinator: NSObject, @preconcurrency VNDocumentCameraViewControllerDelegate {
177
+ init(parent: PageScannerView) { self.parent = parent }
178
+ var parent: PageScannerView
179
+
180
+ func documentCameraViewController(_ camera: VNDocumentCameraViewController,
181
+ didFinishWith result: VNDocumentCameraScan) {
182
+ parent.pages = (0..<result.pageCount).map { index in result.imageOfPage(at: index) }
183
+ parent.close()
136
184
  }
137
185
 
138
- func documentCameraViewControllerDidCancel(_ controller: VNDocumentCameraViewController) {
139
- parent.dismiss()
186
+ func documentCameraViewControllerDidCancel(_ camera: VNDocumentCameraViewController) {
187
+ parent.close()
140
188
  }
141
189
 
142
- func documentCameraViewController(
143
- _ controller: VNDocumentCameraViewController,
144
- didFailWithError error: Error
145
- ) {
146
- parent.dismiss()
190
+ func documentCameraViewController(_ camera: VNDocumentCameraViewController,
191
+ didFailWithError failure: Error) {
192
+ parent.close()
147
193
  }
148
194
  }
149
195
  }
150
196
  ```
151
197
 
152
- ## The Coordinator Pattern
198
+ The coordinator is a `final class` that subclasses `NSObject`, adopts the
199
+ delegate protocol, stores `parent`, and is built from `makeCoordinator()` by
200
+ passing `self`.
201
+
202
+ ## 3. The Coordinator Pattern
153
203
 
154
- ### Why Coordinators Exist
204
+ ### Why it exists
155
205
 
156
- UIKit delegates, data sources, and target-action patterns require a reference type (`class`). SwiftUI representable structs are value types and cannot serve as delegates. The Coordinator is a `class` instance that SwiftUI creates and manages for you -- it lives as long as the representable view.
206
+ Delegates, data sources and target-action receivers in UIKit have to be class
207
+ instances. A representable is a struct, so it cannot play that role. The
208
+ Coordinator is the class that does. SwiftUI creates it, owns it, and keeps it
209
+ alive exactly as long as the representable.
157
210
 
158
- ### Structure
211
+ ### Shape
159
212
 
160
- Always nest the Coordinator inside the representable or in an extension. Store a reference to `parent` (the representable struct) so the coordinator can write back to `@Binding` properties.
213
+ Declare the Coordinator as a nested type of the representable, directly or
214
+ through an extension. Give it a `parent` property holding the representable
215
+ struct; that is how it writes to `@Binding` properties and calls closures.
161
216
 
162
217
  ```swift
163
- struct SearchBarView: UIViewRepresentable {
164
- @Binding var text: String
165
- var onSearch: (String) -> Void
218
+ struct LegacySearchField: UIViewRepresentable {
219
+ @Binding var query: String
220
+ var onSubmit: (String) -> Void
166
221
 
167
- func makeCoordinator() -> Coordinator { Coordinator(self) }
222
+ func makeCoordinator() -> Coordinator { .init(parent: self) }
168
223
 
169
224
  func makeUIView(context: Context) -> UISearchBar {
170
- let bar = UISearchBar()
171
- bar.delegate = context.coordinator // Set delegate HERE, not in updateUIView
225
+ let bar = UISearchBar(frame: .zero)
226
+ bar.delegate = context.coordinator
172
227
  return bar
173
228
  }
174
229
 
175
- func updateUIView(_ uiView: UISearchBar, context: Context) {
176
- if uiView.text != text {
177
- uiView.text = text
178
- }
230
+ func updateUIView(_ bar: UISearchBar, context: Context) {
231
+ context.coordinator.parent = self
232
+ if bar.text != query { bar.text = query }
179
233
  }
180
234
 
235
+ @MainActor
181
236
  final class Coordinator: NSObject, UISearchBarDelegate {
182
- var parent: SearchBarView
183
-
184
- init(_ parent: SearchBarView) { self.parent = parent }
237
+ init(parent: LegacySearchField) { self.parent = parent }
238
+ var parent: LegacySearchField
185
239
 
186
- func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
187
- parent.text = searchText
240
+ func searchBar(_ bar: UISearchBar, textDidChange newText: String) {
241
+ parent.query = newText
188
242
  }
189
243
 
190
- func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
191
- parent.onSearch(parent.text)
192
- searchBar.resignFirstResponder()
244
+ func searchBarSearchButtonClicked(_ bar: UISearchBar) {
245
+ parent.onSubmit(parent.query)
246
+ bar.resignFirstResponder()
193
247
  }
194
248
  }
195
249
  }
196
250
  ```
197
251
 
198
- ### Key Rules
252
+ ### Rules
199
253
 
200
- 1. **Set the delegate in `makeUIView`/`makeUIViewController`, never in `updateUIView`.** The update method runs on every state change -- setting the delegate there causes redundant assignment and can trigger unexpected side effects.
254
+ - Assign the coordinator as delegate in `makeUIView` or
255
+ `makeUIViewController`. Doing it in the update method repeats the assignment
256
+ on every state change and can cause side effects inside the UIKit object.
257
+ - SwiftUI does not refresh `coordinator.parent` for you. The coordinator is
258
+ created once with the first struct value, while SwiftUI builds a new struct
259
+ on every update. Start `updateUIView` (or `updateUIViewController`) with
260
+ `context.coordinator.parent = self`, so the coordinator always reads the
261
+ current bindings and closures before the next delegate callback arrives.
262
+ - When a UIKit object stores a closure that refers to the coordinator, capture
263
+ it as `[weak coordinator]` to avoid a retain cycle.
201
264
 
202
- 2. **The coordinator's `parent` property is updated automatically.** SwiftUI updates the coordinator's reference to the latest representable struct value before each call to `updateUIView`. This means the coordinator always sees current `@Binding` values through `parent`.
265
+ ## 4. UIHostingController
203
266
 
204
- 3. **Use `[weak coordinator]` in closures** to avoid retain cycles between the coordinator and UIKit objects that capture it.
267
+ ### Basic embedding
205
268
 
206
- ## UIHostingController
207
-
208
- Embed SwiftUI views inside UIKit view controllers using `UIHostingController`.
209
-
210
- ### Basic Embedding
269
+ `UIHostingController(rootView:)` puts a SwiftUI view inside a UIKit
270
+ controller. Containment has three steps and the order is fixed:
211
271
 
212
272
  ```swift
213
- final class ProfileViewController: UIViewController {
214
- private let hostingController = UIHostingController(rootView: ProfileView())
273
+ final class ProfileScreenController: UIViewController {
274
+ let summaryHost = UIHostingController(rootView: ProfileSummary(profile: .empty))
215
275
 
216
276
  override func viewDidLoad() {
217
277
  super.viewDidLoad()
278
+ addChild(summaryHost) // 1
218
279
 
219
- // 1. Add as child
220
- addChild(hostingController)
221
-
222
- // 2. Add and constrain the view
223
- hostingController.view.translatesAutoresizingMaskIntoConstraints = false
224
- view.addSubview(hostingController.view)
280
+ let hosted: UIView = summaryHost.view
281
+ hosted.translatesAutoresizingMaskIntoConstraints = false // 2
282
+ view.addSubview(hosted)
225
283
  NSLayoutConstraint.activate([
226
- hostingController.view.topAnchor.constraint(equalTo: view.topAnchor),
227
- hostingController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
228
- hostingController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
229
- hostingController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
284
+ hosted.topAnchor.constraint(equalTo: view.topAnchor),
285
+ hosted.bottomAnchor.constraint(equalTo: view.bottomAnchor),
286
+ hosted.leadingAnchor.constraint(equalTo: view.leadingAnchor),
287
+ hosted.trailingAnchor.constraint(equalTo: view.trailingAnchor)
230
288
  ])
231
289
 
232
- // 3. Notify the child
233
- hostingController.didMove(toParent: self)
290
+ summaryHost.didMove(toParent: self) // 3
234
291
  }
235
292
  }
236
293
  ```
237
294
 
238
- The three-step sequence (addChild, add view, didMove) is mandatory. Skipping any step causes containment callbacks to misfire, which breaks appearance transitions and trait propagation.
295
+ Leave out any step and containment callbacks, appearance transitions and trait
296
+ propagation stop working correctly.
239
297
 
240
- ### Sizing Options (iOS 16+)
298
+ ### Sizing options (iOS 16+)
241
299
 
242
- ```swift
243
- @available(iOS 16.0, *)
244
- hostingController.sizingOptions = [.intrinsicContentSize]
245
- ```
300
+ `sizingOptions` is an option set on the hosting controller:
246
301
 
247
- | Option | Effect |
248
- |--------|--------|
249
- | `.intrinsicContentSize` | The hosting controller's view reports its SwiftUI content size as `intrinsicContentSize`. Use in Auto Layout when the hosted view should size itself. |
250
- | `.preferredContentSize` | Updates `preferredContentSize` to match SwiftUI content. Use when presenting as a popover or form sheet. |
302
+ | Option | Effect | Use for |
303
+ |--------|--------|---------|
304
+ | `.intrinsicContentSize` | The hosting view reports the SwiftUI content size as its `intrinsicContentSize` | Self-sizing under Auto Layout |
305
+ | `.preferredContentSize` | `preferredContentSize` follows the SwiftUI content size | Popovers and form sheets |
251
306
 
252
- ### Updating the Root View
307
+ ### Updating the root view
253
308
 
254
- When data changes in UIKit, push new state into the hosted SwiftUI view:
309
+ To push new data from UIKit, assign a new value: `summaryHost.rootView =
310
+ ProfileSummary(profile: updated)`. If the SwiftUI view instead receives an
311
+ `@Observable` model, SwiftUI tracks its changes and no reassignment is needed.
255
312
 
256
- ```swift
257
- func updateProfile(_ profile: Profile) {
258
- hostingController.rootView = ProfileView(profile: profile)
259
- }
260
- ```
313
+ ## 5. UIHostingConfiguration (iOS 16+)
261
314
 
262
- For observable models, pass an `@Observable` object and SwiftUI tracks changes automatically -- no need to reassign `rootView`.
263
-
264
- ### UIHostingConfiguration (iOS 16+)
265
-
266
- Render SwiftUI content directly inside `UICollectionViewCell` or `UITableViewCell` without managing a child hosting controller:
315
+ For cells, set `contentConfiguration` to a `UIHostingConfiguration`. SwiftUI
316
+ content renders directly in a `UICollectionViewCell` or `UITableViewCell`
317
+ without creating a child hosting controller yourself.
267
318
 
268
319
  ```swift
269
- @available(iOS 16.0, *)
270
- func collectionView(
271
- _ collectionView: UICollectionView,
272
- cellForItemAt indexPath: IndexPath
273
- ) -> UICollectionViewCell {
274
- let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
320
+ func collectionView(_ grid: UICollectionView,
321
+ cellForItemAt position: IndexPath) -> UICollectionViewCell {
322
+ let contact = contacts[position.item]
323
+ let cell = grid.dequeueReusableCell(withReuseIdentifier: "contact", for: position)
275
324
  cell.contentConfiguration = UIHostingConfiguration {
276
- ItemRow(item: items[indexPath.item])
325
+ ContactRow(contact: contact)
277
326
  }
278
327
  return cell
279
328
  }
280
329
  ```
281
330
 
282
- ## Sizing and Layout
283
-
284
- ### intrinsicContentSize Bridging
331
+ Margins, backgrounds, self-sizing and reuse rules are in
332
+ [the migration guide, pattern 5](references/hosting-migration.md#5-uihostingconfiguration-ios-16).
285
333
 
286
- UIKit views wrapped in `UIViewRepresentable` communicate their natural size to SwiftUI through `intrinsicContentSize`. SwiftUI respects this during layout unless overridden by `frame()` or `fixedSize()`.
334
+ ## 6. Sizing and Layout
287
335
 
288
- ### fixedSize() and frame() Interactions
336
+ A wrapped UIKit view tells SwiftUI its natural size through
337
+ `intrinsicContentSize`. SwiftUI respects it unless `frame()` or `fixedSize()`
338
+ says otherwise.
289
339
 
290
- | SwiftUI Modifier | Effect on Representable |
291
- |-----------------|------------------------|
292
- | No modifier | SwiftUI uses `intrinsicContentSize` as ideal size; the view is flexible. |
293
- | `.fixedSize()` | Forces the representable to its ideal (intrinsic) size in both axes. |
294
- | `.fixedSize(horizontal: true, vertical: false)` | Fixes width to intrinsic; height remains flexible. |
295
- | `.frame(width:height:)` | Overrides the proposed size; UIKit view receives this size. |
340
+ | Modifier on the representable | Result |
341
+ |-------------------------------|--------|
342
+ | none | Intrinsic size is the ideal size; the view can still grow or shrink |
343
+ | `.frame(width:height:)` | Replaces the proposed size; the UIKit view gets exactly that size |
344
+ | `.fixedSize()` | Locked to the intrinsic size in width and height |
345
+ | `.fixedSize(horizontal: true, vertical: false)` | Width locked to intrinsic, height flexible |
296
346
 
297
- ### Auto Layout with UIHostingController
347
+ When SwiftUI is the child inside UIKit, pin the hosting view with constraints
348
+ and set `sizingOptions = [.intrinsicContentSize]`; that is how Auto Layout
349
+ learns the natural size. Self-sizing cells and sections of variable height
350
+ depend on this.
298
351
 
299
- When embedding `UIHostingController` as a child, pin its view with constraints. Use `.sizingOptions = [.intrinsicContentSize]` so Auto Layout can query the SwiftUI content's natural size for self-sizing cells or variable-height sections.
352
+ ## 7. State Synchronization
300
353
 
301
- ## State Synchronization Patterns
354
+ **Two-way with `@Binding`.** The coordinator writes `parent.value` from a
355
+ delegate method; `updateUIView` reads the binding and applies it to the view.
356
+ The `PlainTextEditor` above does both halves (`textViewDidChange(_:)` writes,
357
+ the update method applies).
302
358
 
303
- ### `@Binding`: Two-Way Sync (SwiftUI <-> UIKit)
304
-
305
- Use `@Binding` when both sides read and write the same value. The coordinator writes to `parent.bindingProperty` in delegate callbacks; `updateUIView` reads the binding and pushes it into the UIKit view.
359
+ **One-way with closures.** For events that flow only from UIKit to SwiftUI
360
+ (tap, submit, scan finished), give the representable an optional closure
361
+ property such as `var onScanComplete: ((String) -> Void)?`. The coordinator
362
+ calls `parent.onScanComplete?(code)` when UIKit reports the event, and SwiftUI
363
+ supplies the closure at the call site:
306
364
 
307
365
  ```swift
308
- // SwiftUI -> UIKit: in updateUIView
309
- if uiView.text != text { uiView.text = text }
310
-
311
- // UIKit -> SwiftUI: in Coordinator delegate method
312
- func textViewDidChange(_ textView: UITextView) {
313
- parent.text = textView.text
314
- }
366
+ TicketBarcodeView(onScanComplete: { code in checkIn.validate(code) })
315
367
  ```
316
368
 
317
- ### Closures: One-Way Events (UIKit -> SwiftUI)
318
-
319
- For fire-and-forget events (button tapped, search submitted, scan completed), pass a closure instead of a binding:
369
+ **Environment.** Inside the representable methods read SwiftUI environment
370
+ values from `context.environment`:
320
371
 
321
372
  ```swift
322
- struct WebViewWrapper: UIViewRepresentable {
323
- let url: URL
324
- var onNavigationFinished: ((URL) -> Void)?
373
+ func updateUIView(_ editor: UITextView, context: Context) {
374
+ context.coordinator.parent = self
375
+ let environment = context.environment
376
+ editor.isEditable = environment.isEnabled
377
+ editor.backgroundColor = environment.colorScheme == .dark
378
+ ? .secondarySystemBackground : .systemBackground
325
379
  }
326
380
  ```
327
381
 
328
- ### Environment Values
329
-
330
- Access SwiftUI environment values inside representable methods via `context.environment`:
331
-
332
- ```swift
333
- func updateUIView(_ uiView: UITextView, context: Context) {
334
- let isEnabled = context.environment.isEnabled
335
- uiView.isEditable = isEnabled
336
-
337
- // Respond to color scheme changes
338
- let colorScheme = context.environment.colorScheme
339
- uiView.backgroundColor = colorScheme == .dark ? .systemGray6 : .white
340
- }
341
- ```
342
-
343
- ### Avoiding Update Loops
344
-
345
- `updateUIView` is called whenever SwiftUI state changes -- including changes triggered by the coordinator writing to a `@Binding`. Guard against redundant updates to prevent infinite loops:
346
-
347
- ```swift
348
- func updateUIView(_ uiView: UITextView, context: Context) {
349
- // GUARD: Only update if values actually differ
350
- if uiView.text != text {
351
- uiView.text = text
352
- }
353
- }
354
- ```
355
-
356
- Without the guard, setting `uiView.text` may trigger the delegate's `textViewDidChange`, which writes to `parent.text`, which triggers `updateUIView` again.
357
-
358
- ## Sendable Considerations
359
-
360
- UIKit delegate protocols are not `Sendable`. When the coordinator conforms to a UIKit delegate, it inherits main-actor isolation from UIKit. Mark coordinators `@MainActor` or use `nonisolated` only for methods that truly do not touch UIKit state. In Swift 6 strict concurrency:
361
-
362
- ```swift
363
- @MainActor
364
- final class Coordinator: NSObject, UISearchBarDelegate {
365
- var parent: SearchBarView
366
- init(_ parent: SearchBarView) { self.parent = parent }
367
- // Delegate methods are main-actor-isolated -- safe to access UIKit and @Binding.
368
- }
369
- ```
370
-
371
- If passing closures across isolation boundaries, ensure they are `@Sendable` or captured on the correct actor.
372
-
373
- ## Common Mistakes
374
-
375
- ### DO / DON'T
376
-
377
- **DON'T:** Create the UIKit view in `updateUIView`.
378
- **DO:** Create the view once in `makeUIView`; only configure/update it in `updateUIView`.
379
- *Why:* `updateUIView` runs on every state change. Creating a new view each time destroys all UIKit state (selection, scroll position, first responder) and leaks memory.
380
-
381
- **DON'T:** Set delegates in `updateUIView`.
382
- **DO:** Set delegates in `makeUIView`/`makeUIViewController` only.
383
- *Why:* Redundant delegate assignment on every update can reset internal delegate state in UIKit views like `WKWebView` or `MKMapView`.
384
-
385
- **DON'T:** Hold strong references to the Coordinator from closures.
386
- **DO:** Use `[weak coordinator]` in closures.
387
- *Why:* UIKit objects often store closures (completion handlers, action blocks). A strong reference to the coordinator that holds a reference to the UIKit view creates a retain cycle.
388
-
389
- **DON'T:** Forget to call `parent.dismiss()` or completion handlers.
390
- **DO:** Use the coordinator to track dismissal and invoke `parent.dismiss()` in all delegate exit paths.
391
- *Why:* Modal controllers presented by SwiftUI (via `.sheet`) need their dismiss binding toggled, or the sheet state becomes inconsistent.
392
-
393
- **DON'T:** Ignore `dismantleUIView` for views that hold observers or timers.
394
- **DO:** Clean up `NotificationCenter` observers, `Combine` subscriptions, and `Timer` instances in `dismantleUIView`.
395
- *Why:* Without cleanup, observers and timers continue firing after the view is removed, causing crashes or stale state updates.
396
-
397
- **DON'T:** Force `UIHostingController`'s view to fill the parent without proper constraints.
398
- **DO:** Use Auto Layout constraints or `sizingOptions` for proper embedding.
399
- *Why:* Setting `frame` manually breaks adaptive layout, trait propagation, and safe area handling.
400
-
401
- **DON'T:** Try to use `@State` in the Coordinator -- it is not a `View`.
402
- **DO:** Use regular stored properties on the Coordinator and communicate to SwiftUI via `parent`'s `@Binding` properties.
403
- *Why:* `@State` only works inside `View` conformances. Using it on a class has no effect.
404
-
405
- **DON'T:** Skip the `addChild`/`didMove(toParent:)` dance when embedding `UIHostingController`.
406
- **DO:** Always call `addChild(_:)`, add the view to the hierarchy, then call `didMove(toParent:)`.
407
- *Why:* Skipping containment causes viewWillAppear/viewDidAppear to never fire, breaks trait collection propagation, and causes visual glitches.
408
-
409
- ## Review Checklist
410
-
411
- - [ ] View/controller created in `make*`, not `update*`
412
- - [ ] Coordinator set as delegate in `make*`, not `update*`
413
- - [ ] `@Binding` used for two-way state sync
414
- - [ ] `updateUIView` handles all SwiftUI state changes with redundancy guards
415
- - [ ] `dismantleUIView` cleans up observers/timers if needed
416
- - [ ] No retain cycles between coordinator and closures (`[weak coordinator]`)
417
- - [ ] `UIHostingController` properly added as child (`addChild` + `didMove(toParent:)`)
418
- - [ ] Sizing strategy chosen (`intrinsicContentSize` vs fixed `frame` vs `sizeThatFits`)
419
- - [ ] Environment values read in `updateUIView` via `context.environment` where needed
420
- - [ ] Coordinator marked `@MainActor` for strict concurrency
421
- - [ ] Modal controllers dismiss in all delegate exit paths (success, cancel, error)
422
- - [ ] `UIHostingConfiguration` used for collection/table view cells instead of manual hosting (iOS 16+)
382
+ **Why the equality guard matters.** Assigning to the UIKit view may fire its
383
+ delegate, the delegate writes the binding, the binding change calls
384
+ `updateUIView`, which assigns again. Checking for a difference before assigning
385
+ is what ends that cycle.
386
+
387
+ ## 8. Swift Concurrency and Sendable
388
+
389
+ - Delegate protocols in UIKit are main-actor protocols, not `Sendable` ones. A
390
+ coordinator adopting one is isolated to the main actor through that
391
+ conformance.
392
+ - Some framework delegates carry no isolation at all, for example
393
+ `VNDocumentCameraViewControllerDelegate`, `MFMailComposeViewControllerDelegate`
394
+ and `MFMessageComposeViewControllerDelegate`. A `@MainActor` coordinator that
395
+ adopts one plainly fails in Swift 6 with "conformance ... crosses into main
396
+ actor-isolated code". Write `@preconcurrency` before the protocol name: the
397
+ conformance compiles, and the callbacks are checked at run time to arrive on
398
+ the main thread, which is where these controllers deliver them.
399
+ - Mark coordinators `@MainActor`. Use `nonisolated` only on methods that never
400
+ touch UIKit state.
401
+ - A closure that crosses an isolation boundary must be `@Sendable` or captured
402
+ on the actor it runs on.
403
+
404
+ ## 9. Common Mistakes
405
+
406
+ | Mistake | Consequence | Fix |
407
+ |---------|-------------|-----|
408
+ | Creating the UIKit view inside `updateUIView` | Selection, scroll offset and first responder are lost, and memory leaks | Create once in `makeUIView` |
409
+ | Setting delegates inside `updateUIView` | Objects such as `WKWebView` or `MKMapView` may reset their own delegate bookkeeping | Assign in `make*` |
410
+ | Strong capture of the coordinator in a closure a UIKit object keeps | Retain cycle coordinator to view and back | `[weak coordinator]` |
411
+ | Forgetting `parent.dismiss()` or the completion on one delegate path | A `.sheet` presenting the controller is left in an inconsistent state | Dismiss on every exit path |
412
+ | Leaving `NotificationCenter` observers, Combine subscriptions or `Timer`s alive | They keep firing after removal: crashes and stale updates | Tear down in `dismantleUIView` |
413
+ | Sizing the hosting view by setting `frame` by hand | Safe areas, trait propagation and adaptive layout stop working | Constraints or `sizingOptions` |
414
+ | Using `@State` in a Coordinator | Does nothing, the coordinator is not a `View` | Plain stored properties, talk to SwiftUI through `parent` bindings |
415
+ | Skipping `addChild` or `didMove(toParent:)` | `viewWillAppear` and `viewDidAppear` never run, traits do not propagate, visual glitches | Full containment sequence |
416
+
417
+ ## 10. Review Checklist
418
+
419
+ - [ ] View or controller created in `make*`, never in `update*`
420
+ - [ ] Delegate assignment to the coordinator happens in `make*`, never in `update*`
421
+ - [ ] `@Binding` used where data flows both ways
422
+ - [ ] `updateUIView` applies every piece of state it depends on, each behind a difference check
423
+ - [ ] `dismantleUIView` removes observers and timers where any exist
424
+ - [ ] No retain cycle between coordinator and stored closures (`[weak coordinator]`)
425
+ - [ ] Hosting controller added as a child with `addChild` and `didMove(toParent:)`
426
+ - [ ] Sizing chosen deliberately: `intrinsicContentSize`, fixed `frame`, or `sizeThatFits`
427
+ - [ ] Environment values read from `context.environment` in `updateUIView` where relevant
428
+ - [ ] Coordinators carry `@MainActor` so strict concurrency checking passes
429
+ - [ ] Modal controllers dismiss on success, cancel and error
430
+ - [ ] Cells use `UIHostingConfiguration` rather than hand-managed hosting controllers (iOS 16+)
423
431
 
424
432
  ## References
425
433
 
426
- - Wrapping recipes: [references/representable-recipes.md](references/representable-recipes.md)
427
- - Migration patterns: [references/hosting-migration.md](references/hosting-migration.md)
428
- - Apple docs: [UIViewRepresentable](https://sosumi.ai/documentation/swiftui/UIViewRepresentable)
429
- - Apple docs: [UIViewControllerRepresentable](https://sosumi.ai/documentation/swiftui/UIViewControllerRepresentable)
430
- - Apple docs: [UIHostingController](https://sosumi.ai/documentation/swiftui/UIHostingController)
434
+ - [wrapper recipes](references/representable-recipes.md): complete wrapper recipes
435
+ - [migration guide](references/hosting-migration.md): incremental UIKit to SwiftUI migration
436
+ - Apple: [UIViewRepresentable](https://developer.apple.com/documentation/swiftui/uiviewrepresentable),
437
+ [UIViewControllerRepresentable](https://developer.apple.com/documentation/swiftui/uiviewcontrollerrepresentable),
438
+ [UIHostingController](https://developer.apple.com/documentation/swiftui/uihostingcontroller)