swift-code-reviewer-skill 1.2.0 → 1.3.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 (95) hide show
  1. package/CHANGELOG.md +43 -169
  2. package/README.md +43 -2
  3. package/SKILL.md +194 -711
  4. package/bin/install.js +1 -1
  5. package/package.json +2 -1
  6. package/references/agent-loop-feedback.md +148 -0
  7. package/references/companion-skills.md +70 -0
  8. package/references/spec-adherence.md +157 -0
  9. package/skills/README.md +43 -0
  10. package/skills/swift-concurrency/NOTICE.md +18 -0
  11. package/skills/swift-concurrency/SKILL.md +235 -0
  12. package/skills/swift-concurrency/references/actors.md +640 -0
  13. package/skills/swift-concurrency/references/async-await-basics.md +249 -0
  14. package/skills/swift-concurrency/references/async-sequences.md +635 -0
  15. package/skills/swift-concurrency/references/core-data.md +533 -0
  16. package/skills/swift-concurrency/references/glossary.md +96 -0
  17. package/skills/swift-concurrency/references/linting.md +38 -0
  18. package/skills/swift-concurrency/references/memory-management.md +542 -0
  19. package/skills/swift-concurrency/references/migration.md +721 -0
  20. package/skills/swift-concurrency/references/performance.md +574 -0
  21. package/skills/swift-concurrency/references/sendable.md +578 -0
  22. package/skills/swift-concurrency/references/tasks.md +604 -0
  23. package/skills/swift-concurrency/references/testing.md +565 -0
  24. package/skills/swift-concurrency/references/threading.md +452 -0
  25. package/skills/swift-expert/NOTICE.md +18 -0
  26. package/skills/swift-expert/SKILL.md +226 -0
  27. package/skills/swift-expert/references/async-concurrency.md +363 -0
  28. package/skills/swift-expert/references/memory-performance.md +380 -0
  29. package/skills/swift-expert/references/protocol-oriented.md +357 -0
  30. package/skills/swift-expert/references/swiftui-patterns.md +294 -0
  31. package/skills/swift-expert/references/testing-patterns.md +402 -0
  32. package/skills/swift-testing/NOTICE.md +18 -0
  33. package/skills/swift-testing/SKILL.md +295 -0
  34. package/skills/swift-testing/references/async-testing.md +245 -0
  35. package/skills/swift-testing/references/dump-snapshot-testing.md +265 -0
  36. package/skills/swift-testing/references/fixtures.md +193 -0
  37. package/skills/swift-testing/references/integration-testing.md +189 -0
  38. package/skills/swift-testing/references/migration-xctest.md +301 -0
  39. package/skills/swift-testing/references/parameterized-tests.md +171 -0
  40. package/skills/swift-testing/references/snapshot-testing.md +201 -0
  41. package/skills/swift-testing/references/test-doubles.md +243 -0
  42. package/skills/swift-testing/references/test-organization.md +231 -0
  43. package/skills/swiftui-expert-skill/NOTICE.md +18 -0
  44. package/skills/swiftui-expert-skill/SKILL.md +281 -0
  45. package/skills/swiftui-expert-skill/references/accessibility-patterns.md +151 -0
  46. package/skills/swiftui-expert-skill/references/animation-advanced.md +403 -0
  47. package/skills/swiftui-expert-skill/references/animation-basics.md +284 -0
  48. package/skills/swiftui-expert-skill/references/animation-transitions.md +326 -0
  49. package/skills/swiftui-expert-skill/references/charts-accessibility.md +135 -0
  50. package/skills/swiftui-expert-skill/references/charts.md +602 -0
  51. package/skills/swiftui-expert-skill/references/image-optimization.md +203 -0
  52. package/skills/swiftui-expert-skill/references/latest-apis.md +464 -0
  53. package/skills/swiftui-expert-skill/references/layout-best-practices.md +266 -0
  54. package/skills/swiftui-expert-skill/references/liquid-glass.md +414 -0
  55. package/skills/swiftui-expert-skill/references/list-patterns.md +394 -0
  56. package/skills/swiftui-expert-skill/references/macos-scenes.md +318 -0
  57. package/skills/swiftui-expert-skill/references/macos-views.md +357 -0
  58. package/skills/swiftui-expert-skill/references/macos-window-styling.md +303 -0
  59. package/skills/swiftui-expert-skill/references/performance-patterns.md +403 -0
  60. package/skills/swiftui-expert-skill/references/scroll-patterns.md +293 -0
  61. package/skills/swiftui-expert-skill/references/sheet-navigation-patterns.md +363 -0
  62. package/skills/swiftui-expert-skill/references/state-management.md +417 -0
  63. package/skills/swiftui-expert-skill/references/view-structure.md +389 -0
  64. package/skills/swiftui-ui-patterns/NOTICE.md +18 -0
  65. package/skills/swiftui-ui-patterns/SKILL.md +95 -0
  66. package/skills/swiftui-ui-patterns/references/app-wiring.md +201 -0
  67. package/skills/swiftui-ui-patterns/references/async-state.md +96 -0
  68. package/skills/swiftui-ui-patterns/references/components-index.md +50 -0
  69. package/skills/swiftui-ui-patterns/references/controls.md +57 -0
  70. package/skills/swiftui-ui-patterns/references/deeplinks.md +66 -0
  71. package/skills/swiftui-ui-patterns/references/focus.md +90 -0
  72. package/skills/swiftui-ui-patterns/references/form.md +97 -0
  73. package/skills/swiftui-ui-patterns/references/grids.md +71 -0
  74. package/skills/swiftui-ui-patterns/references/haptics.md +71 -0
  75. package/skills/swiftui-ui-patterns/references/input-toolbar.md +51 -0
  76. package/skills/swiftui-ui-patterns/references/lightweight-clients.md +93 -0
  77. package/skills/swiftui-ui-patterns/references/list.md +86 -0
  78. package/skills/swiftui-ui-patterns/references/loading-placeholders.md +38 -0
  79. package/skills/swiftui-ui-patterns/references/macos-settings.md +71 -0
  80. package/skills/swiftui-ui-patterns/references/matched-transitions.md +59 -0
  81. package/skills/swiftui-ui-patterns/references/media.md +73 -0
  82. package/skills/swiftui-ui-patterns/references/menu-bar.md +101 -0
  83. package/skills/swiftui-ui-patterns/references/navigationstack.md +159 -0
  84. package/skills/swiftui-ui-patterns/references/overlay.md +45 -0
  85. package/skills/swiftui-ui-patterns/references/performance.md +62 -0
  86. package/skills/swiftui-ui-patterns/references/previews.md +48 -0
  87. package/skills/swiftui-ui-patterns/references/scroll-reveal.md +133 -0
  88. package/skills/swiftui-ui-patterns/references/scrollview.md +87 -0
  89. package/skills/swiftui-ui-patterns/references/searchable.md +71 -0
  90. package/skills/swiftui-ui-patterns/references/sheets.md +155 -0
  91. package/skills/swiftui-ui-patterns/references/split-views.md +72 -0
  92. package/skills/swiftui-ui-patterns/references/tabview.md +114 -0
  93. package/skills/swiftui-ui-patterns/references/theming.md +71 -0
  94. package/skills/swiftui-ui-patterns/references/title-menus.md +93 -0
  95. package/skills/swiftui-ui-patterns/references/top-bar.md +49 -0
@@ -0,0 +1,721 @@
1
+ # Migration to Swift 6 and Strict Concurrency
2
+
3
+ A practical guide to migrating existing Swift codebases to Swift 6's strict concurrency model, including strategies, habits, tooling, and common patterns.
4
+
5
+ ---
6
+
7
+ ## Why Migrate to Swift 6?
8
+
9
+ Swift 6 doesn't fundamentally change how Swift Concurrency works—it **enforces existing rules more strictly**:
10
+
11
+ - **Compile-time safety**: Catches data races and threading issues at compile time instead of runtime
12
+ - **Warnings become errors**: Many Swift 5 warnings become hard errors in Swift 6 language mode
13
+ - **Future-proofing**: New concurrency features will build on this stricter foundation
14
+ - **Better maintainability**: Code becomes safer and easier to reason about
15
+
16
+ > **Important**: You can adopt strict concurrency checking gradually while still compiling under Swift 5. You don't need to flip the Swift 6 switch immediately.
17
+
18
+ > **Course Deep Dive**: This topic is covered in detail in [Lesson 12.2: The impact of Swift 6 on Swift Concurrency](https://www.swiftconcurrencycourse.com?utm_source=github&utm_medium=agent-skill&utm_campaign=lesson-reference)
19
+
20
+ ---
21
+
22
+ ## Project Settings That Change Concurrency Behavior
23
+
24
+ Before interpreting diagnostics or choosing a fix, confirm the target/module settings. These settings can materially change how code executes and what the compiler enforces.
25
+
26
+ ### Quick matrix
27
+
28
+ | Setting / feature | Where to check | Why it matters |
29
+ |---|---|---|
30
+ | Swift language mode (Swift 5.x vs Swift 6) | Xcode build settings (`SWIFT_VERSION`) / SwiftPM `// swift-tools-version:` | Swift 6 turns many warnings into errors and enables stricter defaults. |
31
+ | Strict concurrency checking | Xcode: Strict Concurrency Checking (`SWIFT_STRICT_CONCURRENCY`) / SwiftPM: strict concurrency flags | Controls how aggressively Sendable + isolation rules are enforced. |
32
+ | Default actor isolation | Xcode: Default Actor Isolation (`SWIFT_DEFAULT_ACTOR_ISOLATION`) / SwiftPM: `.defaultIsolation(MainActor.self)` | Changes the default isolation of declarations; can reduce migration noise but changes behavior and requirements. |
33
+ | `NonisolatedNonsendingByDefault` | Xcode upcoming feature / SwiftPM `.enableUpcomingFeature("NonisolatedNonsendingByDefault")` | Changes how nonisolated async functions execute (can inherit the caller’s actor unless explicitly marked `@concurrent`). |
34
+ | Approachable Concurrency | Xcode build setting / SwiftPM enables the underlying upcoming features | Bundles multiple upcoming features; recommended to migrate feature-by-feature first. |
35
+
36
+ ## The Concurrency Rabbit Hole
37
+
38
+ A common migration experience:
39
+
40
+ 1. Enable strict concurrency checking
41
+ 2. See 50+ errors and warnings
42
+ 3. Fix a bunch of them
43
+ 4. Rebuild and see 80+ new errors appear
44
+
45
+ **Why this happens**: Fixing isolation in one place often exposes issues elsewhere. This is normal and manageable with the right strategy.
46
+
47
+ > **Course Deep Dive**: This topic is covered in detail in [Lesson 12.1: Challenges in migrating to Swift Concurrency](https://www.swiftconcurrencycourse.com?utm_source=github&utm_medium=agent-skill&utm_campaign=lesson-reference)
48
+
49
+ ---
50
+
51
+ ## Six Migration Habits for Success
52
+
53
+ ### 1. Don't Panic—It's All About Iterations
54
+
55
+ Break migration into small, manageable chunks:
56
+
57
+ ```swift
58
+ // Day 1: Enable strict concurrency, fix a few warnings
59
+ // Build Settings → Strict Concurrency Checking = Complete
60
+
61
+ // Day 2: Fix more warnings
62
+
63
+ // Day 3: Revert to minimal checking if needed
64
+ // Build Settings → Strict Concurrency Checking = Minimal
65
+ ```
66
+
67
+ Allow yourself 30 minutes per day to migrate gradually. Don't expect completion in a few days for large projects.
68
+
69
+ ### 2. Sendable by Default for New Code
70
+
71
+ When writing new types, make them `Sendable` from the start:
72
+
73
+ ```swift
74
+ // ✅ Good: New code prepared for Swift 6
75
+ struct UserProfile: Sendable {
76
+ let id: UUID
77
+ let name: String
78
+ }
79
+
80
+ // ❌ Avoid: Creating technical debt
81
+ class UserProfile { // Will need migration later
82
+ var id: UUID
83
+ var name: String
84
+ }
85
+ ```
86
+
87
+ It's easier to design for concurrency upfront than to retrofit it later.
88
+
89
+ ### 3. Use Swift 6 for New Projects and Packages
90
+
91
+ For new projects, packages, or files:
92
+ - Enable Swift 6 language mode from the start
93
+ - Use Swift Concurrency features (async/await, actors)
94
+ - Reduce technical debt before it accumulates
95
+
96
+ You can enable Swift 6 for individual files in a Swift 5 project to prevent scope creep.
97
+
98
+ ### 4. Resist the Urge to Refactor
99
+
100
+ **Focus solely on concurrency changes**. Don't combine migration with:
101
+ - Architecture refactors
102
+ - API modernization
103
+ - Code style improvements
104
+
105
+ Create separate tickets for non-concurrency refactors and address them later.
106
+
107
+ ### 5. Focus on Minimal Changes
108
+
109
+ - Make small, focused pull requests
110
+ - Migrate one class or module at a time
111
+ - Get changes merged quickly to create checkpoints
112
+ - Avoid large PRs that are hard to review
113
+
114
+ ### 6. Don't Just @MainActor All the Things
115
+
116
+ Don't blindly add `@MainActor` to fix warnings. Consider:
117
+ - Should this actually run on the main actor?
118
+ - Would a custom actor be more appropriate?
119
+ - Is `nonisolated` the right choice?
120
+
121
+ **Exception**: For app projects (not frameworks), consider enabling **Default Actor Isolation** to `@MainActor`, since most app code needs main thread access.
122
+
123
+ > **Course Deep Dive**: This topic is covered in detail in [Lesson 12.3: The six migration habits for a successful migration](https://www.swiftconcurrencycourse.com?utm_source=github&utm_medium=agent-skill&utm_campaign=lesson-reference)
124
+
125
+ ---
126
+
127
+ ## Step-by-Step Migration Process
128
+
129
+ ### 1. Find an Isolated Piece of Code
130
+
131
+ Start with:
132
+ - Standalone packages with minimal dependencies
133
+ - Individual Swift files within a package
134
+ - Code that's not heavily used throughout the project
135
+
136
+ **Why**: Fewer dependencies = less risk of falling into the concurrency rabbit hole.
137
+
138
+ ### 2. Update Related Dependencies
139
+
140
+ Before enabling strict concurrency:
141
+
142
+ ```swift
143
+ // Update third-party packages to latest versions
144
+ // Example: Vapor, Alamofire, etc.
145
+ ```
146
+
147
+ Apply these updates in a separate PR before proceeding with concurrency changes.
148
+
149
+ ### 3. Add Async Alternatives
150
+
151
+ Provide async/await wrappers for existing closure-based APIs:
152
+
153
+ ```swift
154
+ // Original closure-based API
155
+ @available(*, deprecated, renamed: "fetchImage(urlRequest:)",
156
+ message: "Consider using the async/await alternative.")
157
+ func fetchImage(urlRequest: URLRequest,
158
+ completion: @escaping @Sendable (Result<UIImage, Error>) -> Void) {
159
+ // ... existing implementation
160
+ }
161
+
162
+ // New async wrapper
163
+ func fetchImage(urlRequest: URLRequest) async throws -> UIImage {
164
+ return try await withCheckedThrowingContinuation { continuation in
165
+ fetchImage(urlRequest: urlRequest) { result in
166
+ continuation.resume(with: result)
167
+ }
168
+ }
169
+ }
170
+ ```
171
+
172
+ **Benefits**:
173
+ - Colleagues can start using async/await immediately
174
+ - You can migrate callers before rewriting implementation
175
+ - Tests can be updated to async/await first
176
+
177
+ **Tip**: Use Xcode's **Refactor → Add Async Wrapper** to generate these automatically.
178
+
179
+ ### 4. Change Default Actor Isolation (Swift 6.2+)
180
+
181
+ For app projects, set default isolation to `@MainActor`:
182
+
183
+ **Xcode Build Settings**:
184
+ ```
185
+ Swift Concurrency → Default Actor Isolation = MainActor
186
+ ```
187
+
188
+ **Swift Package Manager**:
189
+ ```swift
190
+ .target(
191
+ name: "MyTarget",
192
+ swiftSettings: [
193
+ .defaultIsolation(MainActor.self)
194
+ ]
195
+ )
196
+ ```
197
+
198
+ This drastically reduces warnings in app code where most types need main thread access.
199
+
200
+ ### 5. Enable Strict Concurrency Checking
201
+
202
+ **Xcode Build Settings**: Search for "Strict Concurrency Checking"
203
+
204
+ Three levels available:
205
+
206
+ - **Minimal**: Only checks code that explicitly adopts concurrency (`@Sendable`, `@MainActor`)
207
+ - **Targeted**: Checks all code that adopts concurrency, including `Sendable` conformances
208
+ - **Complete**: Checks entire codebase (matches Swift 6 behavior)
209
+
210
+ **Swift Package Manager**:
211
+ ```swift
212
+ .target(
213
+ name: "MyTarget",
214
+ swiftSettings: [
215
+ .enableExperimentalFeature("StrictConcurrency=targeted")
216
+ ]
217
+ )
218
+ ```
219
+
220
+ **Strategy**: Start with Minimal → Targeted → Complete, fixing errors at each level.
221
+
222
+ ### 6. Add Sendable Conformances
223
+
224
+ Even if the compiler doesn't complain, add `Sendable` to types that will cross isolation domains:
225
+
226
+ ```swift
227
+ // ✅ Prepare for future use
228
+ struct Configuration: Sendable {
229
+ let apiKey: String
230
+ let timeout: TimeInterval
231
+ }
232
+ ```
233
+
234
+ This prevents warnings when the type is used in concurrent contexts later.
235
+
236
+ ### 7. Enable Approachable Concurrency (Swift 6.2+)
237
+
238
+ **Xcode Build Settings**: Search for "Approachable Concurrency"
239
+
240
+ Enables multiple upcoming features at once:
241
+ - `DisableOutwardActorInference`
242
+ - `GlobalActorIsolatedTypesUsability`
243
+ - `InferIsolatedConformances`
244
+ - `InferSendableFromCaptures`
245
+ - `NonisolatedNonsendingByDefault`
246
+
247
+ **⚠️ Warning**: Don't just flip this switch for existing projects. Use migration tooling (see below) to migrate to each feature individually first.
248
+
249
+ > **Course Deep Dive**: This topic is covered in detail in [Lesson 12.5: The Approachable Concurrency build setting (Updated for Swift 6.2)](https://www.swiftconcurrencycourse.com?utm_source=github&utm_medium=agent-skill&utm_campaign=lesson-reference)
250
+
251
+ ### 8. Enable Upcoming Features
252
+
253
+ **Xcode Build Settings**: Search for "Upcoming Feature"
254
+
255
+ Enable features individually:
256
+
257
+ **Swift Package Manager**:
258
+ ```swift
259
+ .target(
260
+ name: "MyTarget",
261
+ swiftSettings: [
262
+ .enableUpcomingFeature("ExistentialAny"),
263
+ .enableUpcomingFeature("InferIsolatedConformances")
264
+ ]
265
+ )
266
+ ```
267
+
268
+ Find feature keys in Swift Evolution proposals (e.g., SE-335 for `ExistentialAny`).
269
+
270
+ ### 9. Change to Swift 6 Language Mode
271
+
272
+ **Xcode Build Settings**:
273
+ ```
274
+ Swift Language Version = Swift 6
275
+ ```
276
+
277
+ **Swift Package Manager**:
278
+ ```swift
279
+ // swift-tools-version: 6.0
280
+ ```
281
+
282
+ If you've completed all previous steps, you should have minimal new errors.
283
+
284
+ > **Course Deep Dive**: This topic is covered in detail in [Lesson 12.4: Steps to migrate existing code to Swift 6 and Strict Concurrency Checking](https://www.swiftconcurrencycourse.com?utm_source=github&utm_medium=agent-skill&utm_campaign=lesson-reference)
285
+
286
+ ---
287
+
288
+ ## Migration Tooling for Upcoming Features
289
+
290
+ Swift 6.2+ includes **semi-automatic migration** for upcoming features.
291
+
292
+ ### Xcode Migration
293
+
294
+ 1. Go to Build Settings → Find the upcoming feature (e.g., "Require Existential any")
295
+ 2. Set to **Migrate** (temporary setting)
296
+ 3. Build the project
297
+ 4. Warnings appear with **Apply** buttons
298
+ 5. Click Apply for each warning
299
+
300
+ **Example warning**:
301
+ ```swift
302
+ // ⚠️ Use of protocol 'Error' as a type must be written 'any Error'
303
+ func fetchData() throws -> Data // Before
304
+ func fetchData() throws -> any Data // After applying fix
305
+ ```
306
+
307
+ ### Package Migration
308
+
309
+ Use the `swift package migrate` command:
310
+
311
+ ```bash
312
+ # Migrate all targets
313
+ swift package migrate --to-feature ExistentialAny
314
+
315
+ # Migrate specific target
316
+ swift package migrate --target MyTarget --to-feature ExistentialAny
317
+ ```
318
+
319
+ **Output**:
320
+ ```
321
+ > Applied 24 fix-its in 11 files (0.016s)
322
+ > Updating manifest
323
+ ```
324
+
325
+ The tool automatically:
326
+ - Applies all fix-its
327
+ - Updates `Package.swift` to enable the feature
328
+
329
+ **Available migrations** (as of Swift 6.2):
330
+ - `ExistentialAny` (SE-335)
331
+ - `InferIsolatedConformances` (SE-470)
332
+ - More features will add migration support over time
333
+
334
+ > **Course Deep Dive**: This topic is covered in detail in [Lesson 12.6: Migration tooling for upcoming Swift features](https://www.swiftconcurrencycourse.com?utm_source=github&utm_medium=agent-skill&utm_campaign=lesson-reference)
335
+
336
+ **Additional resource**: [Migration Tooling Video](https://youtu.be/FK9XFxSWZPg?si=2z_ybn1t1YCJow5k)
337
+
338
+ ---
339
+
340
+ ## Rewriting Closures to Async/Await
341
+
342
+ ### Using Xcode Refactoring
343
+
344
+ Three refactoring options available:
345
+
346
+ 1. **Add Async Wrapper**: Wraps existing closure-based method (recommended first step)
347
+ 2. **Add Async Alternative**: Rewrites method as async, keeps original
348
+ 3. **Convert Function to Async**: Replaces method entirely
349
+
350
+ **⚠️ Known Issue**: Refactoring can be unstable in Xcode. If you get "Connection interrupted" errors:
351
+ - Clean build folder
352
+ - Clear derived data
353
+ - Restart Xcode
354
+ - Simplify complex methods (shorthand if statements can cause failures)
355
+
356
+ ### Manual Rewriting Example
357
+
358
+ **Before** (closure-based):
359
+ ```swift
360
+ func fetchImage(urlRequest: URLRequest,
361
+ completion: @escaping @Sendable (Result<UIImage, Error>) -> Void) {
362
+ URLSession.shared.dataTask(with: urlRequest) { data, _, error in
363
+ do {
364
+ if let error = error { throw error }
365
+ guard let data = data, let image = UIImage(data: data) else {
366
+ throw ImageError.conversionFailed
367
+ }
368
+ completion(.success(image))
369
+ } catch {
370
+ completion(.failure(error))
371
+ }
372
+ }.resume()
373
+ }
374
+ ```
375
+
376
+ **After** (async/await):
377
+ ```swift
378
+ func fetchImage(urlRequest: URLRequest) async throws -> UIImage {
379
+ let (data, _) = try await URLSession.shared.data(for: urlRequest)
380
+ guard let image = UIImage(data: data) else {
381
+ throw ImageError.conversionFailed
382
+ }
383
+ return image
384
+ }
385
+ ```
386
+
387
+ **Benefits**:
388
+ - Less code to maintain
389
+ - Easier to reason about
390
+ - No nested closures
391
+ - Automatic error propagation
392
+
393
+ > **Course Deep Dive**: This topic is covered in detail in [Lesson 12.7: Techniques for rewriting closures to async/await syntax](https://www.swiftconcurrencycourse.com?utm_source=github&utm_medium=agent-skill&utm_campaign=lesson-reference)
394
+
395
+ ---
396
+
397
+ ## Using @preconcurrency
398
+
399
+ Suppresses `Sendable` warnings from modules you don't control.
400
+
401
+ ### When to Use
402
+
403
+ ```swift
404
+ // ⚠️ Third-party library doesn't support Swift Concurrency yet
405
+ @preconcurrency import SomeThirdPartyLibrary
406
+
407
+ actor DataProcessor {
408
+ func process(_ data: LibraryType) { // No Sendable warning
409
+ // ...
410
+ }
411
+ }
412
+ ```
413
+
414
+ ### Risks
415
+
416
+ - **No compile-time safety**: You're responsible for ensuring thread safety
417
+ - **Hides real issues**: Library might not be thread-safe at all
418
+ - **Technical debt**: Easy to forget to revisit later
419
+
420
+ ### Best Practices
421
+
422
+ 1. **Don't use by default**: Only add when compiler suggests it
423
+ 2. **Check for updates first**: Library might have a newer version with concurrency support
424
+ 3. **Document why**: Add a comment explaining why it's needed
425
+ 4. **Revisit regularly**: Set reminders to check if library has been updated
426
+
427
+ ```swift
428
+ // TODO: Remove @preconcurrency when SomeLibrary adds Sendable support
429
+ // Last checked: 2026-01-07 (version 2.3.0)
430
+ @preconcurrency import SomeLibrary
431
+ ```
432
+
433
+ The compiler will warn if `@preconcurrency` is unused:
434
+ ```
435
+ '@preconcurrency' attribute on module 'SomeModule' is unused
436
+ ```
437
+
438
+ > **Course Deep Dive**: This topic is covered in detail in [Lesson 12.8: How and when to use @preconcurrency](https://www.swiftconcurrencycourse.com?utm_source=github&utm_medium=agent-skill&utm_campaign=lesson-reference)
439
+
440
+ ---
441
+
442
+ ## Migrating from Combine/RxSwift
443
+
444
+ ### Observation Alternative
445
+
446
+ Swift 6 will include **Transactional Observation** (SE-475):
447
+
448
+ ```swift
449
+ // Future API (not yet implemented)
450
+ let names = Observations { person.name }
451
+
452
+ Task.detached {
453
+ for await name in names {
454
+ print("Name updated to: \(name)")
455
+ }
456
+ }
457
+ ```
458
+
459
+ **Current alternatives**:
460
+ - Use `@Observable` macro for SwiftUI
461
+ - Use `AsyncStream` for custom observation
462
+ - Consider [AsyncExtensions](https://github.com/sideeffect-io/AsyncExtensions) package
463
+
464
+ ### Debouncing Example
465
+
466
+ **Combine**:
467
+ ```swift
468
+ $searchQuery
469
+ .debounce(for: .milliseconds(500), scheduler: DispatchQueue.main)
470
+ .sink { [weak self] query in
471
+ self?.performSearch(query)
472
+ }
473
+ .store(in: &cancellables)
474
+ ```
475
+
476
+ **Swift Concurrency**:
477
+ ```swift
478
+ func search(_ query: String) {
479
+ currentSearchTask?.cancel()
480
+
481
+ currentSearchTask = Task {
482
+ do {
483
+ try await Task.sleep(for: .milliseconds(500))
484
+ performSearch(query)
485
+ } catch {
486
+ // Search was cancelled
487
+ }
488
+ }
489
+ }
490
+ ```
491
+
492
+ **SwiftUI Integration**:
493
+ ```swift
494
+ struct SearchView: View {
495
+ @State private var searchQuery = ""
496
+ @State private var searcher = ArticleSearcher()
497
+
498
+ var body: some View {
499
+ List(searcher.results) { result in
500
+ Text(result.title)
501
+ }
502
+ .searchable(text: $searchQuery)
503
+ .onChange(of: searchQuery) { _, newValue in
504
+ searcher.search(newValue)
505
+ }
506
+ }
507
+ }
508
+ ```
509
+
510
+ ### Mindset Shift
511
+
512
+ **Don't think in Combine pipelines**. Many problems are simpler without FRP:
513
+
514
+ ```swift
515
+ // ❌ Looking for AsyncSequence equivalent of complex Combine pipeline
516
+ somePublisher
517
+ .debounce(for: .seconds(0.5))
518
+ .removeDuplicates()
519
+ .flatMap { ... }
520
+ .sink { ... }
521
+
522
+ // ✅ Rethink the problem with Swift Concurrency
523
+ Task {
524
+ var lastValue: String?
525
+ for await value in stream {
526
+ guard value != lastValue else { continue }
527
+ lastValue = value
528
+ try await Task.sleep(for: .seconds(0.5))
529
+ await process(value)
530
+ }
531
+ }
532
+ ```
533
+
534
+ **For complex operators**: Check [Swift Async Algorithms](https://github.com/apple/swift-async-algorithms) package.
535
+
536
+ ### ⚠️ Critical: Actor Isolation with Combine
537
+
538
+ **Problem**: `sink` closures don't respect actor isolation at compile time.
539
+
540
+ ```swift
541
+ @MainActor
542
+ final class NotificationObserver {
543
+ private var cancellables: [AnyCancellable] = []
544
+
545
+ init() {
546
+ NotificationCenter.default.publisher(for: .someNotification)
547
+ .sink { [weak self] _ in
548
+ self?.handleNotification() // ⚠️ May crash if posted from background
549
+ }
550
+ .store(in: &cancellables)
551
+ }
552
+
553
+ private func handleNotification() {
554
+ // Expects to run on main actor
555
+ }
556
+ }
557
+ ```
558
+
559
+ **Why it crashes**: Notification observers run on the same thread as the poster. If posted from a background thread, the `@MainActor` method is called off the main actor.
560
+
561
+ **Solutions**:
562
+
563
+ 1. **Migrate to Swift Concurrency** (recommended):
564
+ ```swift
565
+ Task { [weak self] in
566
+ for await _ in NotificationCenter.default.notifications(named: .someNotification) {
567
+ await self?.handleNotification() // ✅ Compile-time safe
568
+ }
569
+ }
570
+ ```
571
+
572
+ 2. **Use Task wrapper** (temporary):
573
+ ```swift
574
+ .sink { [weak self] _ in
575
+ Task { @MainActor in
576
+ self?.handleNotification()
577
+ }
578
+ }
579
+ ```
580
+
581
+ > **Course Deep Dive**: This topic is covered in detail in [Lesson 12.9: Migrating away from Functional Reactive Programming like RxSwift or Combine](https://www.swiftconcurrencycourse.com?utm_source=github&utm_medium=agent-skill&utm_campaign=lesson-reference)
582
+
583
+ ---
584
+
585
+ ## Concurrency-Safe Notifications (iOS 26+)
586
+
587
+ Swift 6.2 introduces **typed, thread-safe notifications**.
588
+
589
+ ### MainActorMessage
590
+
591
+ For notifications that should be delivered on the main actor:
592
+
593
+ ```swift
594
+ // Old way
595
+ NotificationCenter.default.addObserver(
596
+ forName: UIApplication.didBecomeActiveNotification,
597
+ object: nil,
598
+ queue: .main
599
+ ) { [weak self] _ in
600
+ self?.handleDidBecomeActive() // ⚠️ Concurrency warning
601
+ }
602
+
603
+ // New way (iOS 26+)
604
+ token = NotificationCenter.default.addObserver(
605
+ of: UIApplication.self,
606
+ for: .didBecomeActive
607
+ ) { [weak self] message in
608
+ self?.handleDidBecomeActive() // ✅ No warning, guaranteed main actor
609
+ }
610
+ ```
611
+
612
+ **Key difference**: Observer closure is guaranteed to run on `@MainActor`.
613
+
614
+ ### AsyncMessage
615
+
616
+ For notifications delivered asynchronously on arbitrary isolation:
617
+
618
+ ```swift
619
+ struct RecentBuildsChangedMessage: NotificationCenter.AsyncMessage {
620
+ typealias Subject = [RecentBuild]
621
+ let recentBuilds: Subject
622
+ }
623
+
624
+ // Enable static member lookup
625
+ extension NotificationCenter.MessageIdentifier
626
+ where Self == NotificationCenter.BaseMessageIdentifier<RecentBuildsChangedMessage> {
627
+ static var recentBuildsChanged: NotificationCenter.BaseMessageIdentifier<RecentBuildsChangedMessage> {
628
+ .init()
629
+ }
630
+ }
631
+ ```
632
+
633
+ **Posting**:
634
+ ```swift
635
+ let builds = [RecentBuild(appName: "Stock Analyzer")]
636
+ let message = RecentBuildsChangedMessage(recentBuilds: builds)
637
+ NotificationCenter.default.post(message)
638
+ ```
639
+
640
+ **Observing**:
641
+ ```swift
642
+ // Old way: Unsafe casting
643
+ NotificationCenter.default.addObserver(forName: .recentBuildsChanged, object: nil, queue: nil) { notification in
644
+ guard let builds = notification.object as? [RecentBuild] else { return }
645
+ handleBuilds(builds)
646
+ }
647
+
648
+ // New way: Strongly typed, thread-safe
649
+ token = NotificationCenter.default.addObserver(
650
+ of: [RecentBuild].self,
651
+ for: .recentBuildsChanged
652
+ ) { message in
653
+ handleBuilds(message.recentBuilds) // ✅ Direct access, no casting
654
+ }
655
+ ```
656
+
657
+ **Benefits**:
658
+ - Strongly typed (no `Any` casting)
659
+ - Compile-time thread safety
660
+ - Clear isolation guarantees
661
+
662
+ > **Course Deep Dive**: This topic is covered in detail in [Lesson 12.10: Migrating to concurrency-safe notifications](https://www.swiftconcurrencycourse.com?utm_source=github&utm_medium=agent-skill&utm_campaign=lesson-reference)
663
+
664
+ ---
665
+
666
+ ## Common Challenges
667
+
668
+ ### "It's Too Much Work"
669
+
670
+ Break it down:
671
+ - Migrate one package at a time
672
+ - Use 30-minute daily sessions
673
+ - Create checkpoints with small PRs
674
+ - Celebrate incremental progress
675
+
676
+ ### "My Team Isn't Ready"
677
+
678
+ Start small:
679
+ - Enable Swift 6 for new files only
680
+ - Make new types `Sendable` by default
681
+ - Share learnings in team meetings
682
+ - Pair program on tricky migrations
683
+
684
+ ### "Dependencies Aren't Ready"
685
+
686
+ Options:
687
+ - Update to latest versions first
688
+ - Use `@preconcurrency` temporarily
689
+ - Contribute fixes to open-source dependencies
690
+ - Wrap third-party APIs in your own concurrency-safe layer
691
+
692
+ ### "I Keep Going in Circles"
693
+
694
+ This is the "concurrency rabbit hole":
695
+ - Take breaks and revisit later
696
+ - Temporarily disable strict checking to make progress elsewhere
697
+ - Focus on one module at a time
698
+ - Don't try to fix everything at once
699
+
700
+ > **Course Deep Dive**: This topic is covered in detail in [Lesson 12.11: Frequently Asked Questions (FAQ) around Swift 6 Migrations](https://www.swiftconcurrencycourse.com?utm_source=github&utm_medium=agent-skill&utm_campaign=lesson-reference)
701
+
702
+ ---
703
+
704
+ ## Summary
705
+
706
+ Migration to Swift 6 is a journey, not a sprint:
707
+
708
+ 1. **Start small**: Find isolated code with minimal dependencies
709
+ 2. **Be incremental**: Use the three strict concurrency levels (Minimal → Targeted → Complete)
710
+ 3. **Use tooling**: Leverage Xcode refactoring and `swift package migrate`
711
+ 4. **Create checkpoints**: Small, focused PRs that can be merged quickly
712
+ 5. **Stay positive**: The concurrency rabbit hole is real, but manageable with the right habits
713
+ 6. **Think differently**: Let go of the threading mindset; trust the compiler
714
+
715
+ The result is **compile-time thread safety**, more maintainable code, and a future-proof codebase.
716
+
717
+ **Additional resources**:
718
+ - [Approachable Concurrency Video](https://youtu.be/y_Qc8cT-O_g?si=y4C1XQDGtyIOLW81)
719
+ - [Migration Tooling Video](https://youtu.be/FK9XFxSWZPg?si=2z_ybn1t1YCJow5k)
720
+ - [Swift Concurrency Course](https://www.swiftconcurrencycourse.com) for in-depth migration strategies
721
+