Skip to content
Development
Command

/swift6-fix

**Project context:** Values in angle brackets below (e.g. `<scheme>`, `<JIRA_KEY>`, `<flag-key-enum>`) are resolved at runtime — detect them from the project (`xcodebuild -list -json` for the scheme, `git`/`gh` for repo & owner, the branch name for the Jira key, a codebase

From plugin
ios-workflow-claude
722 skills3 agents22 commands
Install
$ npx -y skills add carloshpdoc/ios-workflow-claude --agent claude-code

How it fires

How this command gets triggered: by you, by Claude, or both.

  • Fires itselfClaude auto-loads it when your prompt matches the work.
  • You can call itInvoke it directly when you want it.
  • Slash command/swift6-fix

Context preview

What this command does when you run it.

**Project context:** Values in angle brackets below (e.g. `<scheme>`, `<JIRA_KEY>`, `<flag-key-enum>`) are resolved at runtime — detect them from the project (`xcodebuild -list -json` for the scheme, `git`/`gh` for repo & owner, the branch name for the Jira key, a codebase

Command definition

swift6-fix.md

Swift 6 Fix: $ARGUMENTS

> **Project context:** Values in angle brackets below (e.g. `<scheme>`, `<JIRA_KEY>`, `<flag-key-enum>`) are resolved at runtime — detect them from the project (`xcodebuild -list -json` for the scheme, `git`/`gh` for repo & owner, the branch name for the Jira key, a codebase search for flag/font files), or ask if they cannot be inferred. This plugin ships no per-project config.

Apply Swift 6 strict concurrency fixes for the specified category.

**Valid categories:** `config`, `mainactor`, `singletons`, `dispatch-queue`, `completion-handlers`, `sendable`, `delegates`

If `$ARGUMENTS` is empty, show usage and recommend next category based on `docs/swift6-migration-status.md`.

Prerequisites

1. Read `docs/swift6-migration-status.md` to understand current progress 2. Run `/swift6-check $ARGUMENTS` mentally — verify that the category has remaining items 3. If the category shows 0 remaining, inform the user and suggest the next category

Category: `config`

Foundation changes — run this FIRST before any other category.

Steps

1. Update `Project.swift`: change `"SWIFT_VERSION": "5.3"` → `"SWIFT_VERSION": "6.0"` (all occurrences) 2. Update all `Modules/*/Package.swift`: change `swiftLanguageMode(.v5)` → `swiftLanguageMode(.v6)` 3. Add `SWIFT_STRICT_CONCURRENCY` build setting:

  • If first time: set to `targeted`
  • If `targeted` already done: set to `complete`

4. Lock any dependency versions still pinned to `master` / a moving branch (Swift 6 will break on unexpected upstream changes) 5. Run `tuist generate --no-open` 6. Build: `xcodebuild -scheme <scheme> -destination 'platform=iOS Simulator,name=iPhone 11,OS=latest' -quiet build` 7. If build fails, fix errors iteratively (max 10 iterations) 8. Update `docs/swift6-migration-status.md` config checklist 9. Commit with message: `[CHORE] Swift 6 migration: update Swift version and concurrency settings`

Category: `mainactor`

Add `@MainActor` to ViewModels that are `ObservableObject` subclasses.

Rules

  • Add `@MainActor` annotation to the class declaration
  • Do NOT change any method signatures or property types
  • If a method is explicitly `nonisolated`, leave it as-is
  • If a class already has `@MainActor`, skip it
  • Work in batches of 20-30 files per session to keep PRs reviewable

Steps

1. Find all unannotated ViewModels:

   grep -rl "class.*ViewModel.*ObservableObject" <scheme>/ --include="*.swift" | while read f; do
     grep -L "@MainActor" "$f"
   done

2. For each file, add `@MainActor` before the class declaration:

   // BEFORE
   final class SomeViewModel: ObservableObject {

   // AFTER
   @MainActor
   final class SomeViewModel: ObservableObject {

3. Build after every 10 files. If errors appear:

  • `@MainActor`-isolated property accessed from non-isolated context → add `@MainActor` to the caller or mark the access as `MainActor.assumeIsolated`
  • Protocol conformance issues → add `@MainActor` to the protocol if it's internal
  • Test files referencing the ViewModel → add `@MainActor` to the test class or use `await`

4. Run tests for affected modules 5. Update `docs/swift6-migration-status.md`:

  • Increment "Done" count
  • Decrement "Remaining" count
  • Add entry to Execution Log

6. Format changed files with `swiftformat` 7. Commit with message: `[CHORE] Swift 6 migration: add @MainActor to ViewModels (batch N)`

Category: `singletons`

Protect mutable singletons with actor isolation or `@MainActor`.

Rules

  • `static let shared` with mutable properties → add `@MainActor` to the class
  • `static var shared` (mutable reference) → change to `static let shared` + add `@MainActor`
  • If the singleton is accessed from background threads intentionally, wrap in an actor instead
  • The session/user singleton typically gets special treatment — it's usually the most critical one

Critical Singletons (priority order)

1. Session/user managers — many mutable properties, accessed everywhere 2. Any `static var shared` (mutable reference!) — convert first 3. Analytics/tracking singletons with mutable internal state 4. Shared ViewModels exposed as `static var` 5. All remaining `static let shared` with mutable internal state

Steps

1. List all singletons:

   grep -rn "static let shared\|static var shared" <scheme>/ --include="*.swift"

2. For each singleton: a. Read the file to understand thread access patterns b. If mainly UI-bound: add `@MainActor` to the class c. If accessed from background threads: convert to actor or use `nonisolated(unsafe)` as escape hatch d. Change `static var shared` → `static let shared` where possible 3. Build after every 5 changes 4. Fix cascading errors (callers may need `await` or `@MainActor`) 5. Run tests 6. Update `docs/swift6-migration-status.md` 7. Commit with message: `[CHORE] Swift 6 migration: protect singletons with actor isolation`

Category: `dispatch-queue`

Replace `DispatchQueue.main.async` with structured concurrency.

Rules

  • `DispatchQueue.main.async { ... }` in a `@MainActor` context → remove the dispatch, code already runs on main
  • `DispatchQueue.main.async { ... }` in a non-MainActor context → use `Task { @MainActor in ... }` or `await MainActor.run { ... }`
  • `DispatchQueue.main.sync` → evaluate carefully, may indicate a design issue
  • `DispatchQueue.global().async` → use `Task.detached` or `Task { ... }` with appropriate priority
  • Work in batches of 30-50 replacements per session

Steps

1. Find all occurrences:

   grep -rn "DispatchQueue\.main\.async" <scheme>/ --include="*.swift"

2. Group by file and context:

  • In ViewModels (already `@MainActor` after mainactor phase) → remove dispatch wrapper
  • In Services/Repositories → use `Task { @MainActor in ... }`
  • In UIKit delegates/callbacks → use `Task { @MainActor in ... }`

3. Apply changes per file 4. Build after every 15 files 5. Run tests 6. Update `docs/swift6-migration-status.

Read more
Ships withios-workflow-claude

Reusable Claude Code slash-commands, skills, and workflows extracted from real iOS / backend projects. Packaged as three installable plugins - register the marketplace and /plugin install what you need.

Get the whole plugin, auto-invoked
Stats
7
Stars
0
Views
1
Forks
Maintained
Maintenance
Shell
Language
Apache-2.0
License
2mo ago
Last commit
2mo ago
Created

Repo: carloshpdoc/ios-workflow-claude

Other commands on ios-workflow-claude.