Expert Swift decisions Claude doesn't instinctively make: struct vs class trade-offs, @MainActor placement, async/await vs Combine selection, memory management pitfalls, and iOS-specific anti-patterns. Use when writing Swift code for iOS/tvOS apps, reviewing Swift architecture decisions, or debugging memory/concurrency issues. Trigger keywords: Swift, iOS, tvOS, actor, async, Sendable, retain cycle, memory leak, struct, class, protocol, generic
View on GitHubKaakati/rails-enterprise-dev
reactree-ios-dev
January 25, 2026
Select agents to install to:
npx add-skill https://github.com/Kaakati/rails-enterprise-dev/blob/main/plugins/reactree-ios-dev/skills/swift-conventions/SKILL.md -a claude-code --skill swift-conventionsInstallation paths:
.claude/skills/swift-conventions/# Swift Conventions — Expert Decisions
Expert decision frameworks for Swift choices that require experience. Claude knows Swift syntax — this skill provides the judgment calls.
---
## Decision Trees
### Struct vs Class
```
Need shared mutable state across app?
├─ YES → Class (singleton pattern, session managers)
└─ NO
└─ Need inheritance hierarchy?
├─ YES → Class (UIKit subclasses, NSObject interop)
└─ NO
└─ Data model or value type?
├─ YES → Struct (User, Configuration, Point)
└─ NO → Consider what identity means
├─ Same instance matters → Class
└─ Same values matters → Struct
```
**The non-obvious trade-off**: Structs with reference-type properties (arrays, classes inside) lose copy-on-write benefits. A `struct` containing `[UIImage]` copies the array reference, not images — mutations affect all "copies."
### async/await vs Combine vs Callbacks
```
Is this a one-shot operation? (fetch user, save file)
├─ YES → async/await (cleaner, better stack traces)
└─ NO → Is it a stream of values over time?
├─ YES
│ └─ Need transformations/combining?
│ ├─ Heavy transforms → Combine (map, filter, merge)
│ └─ Simple iteration → AsyncStream
└─ NO → Must support iOS 14?
├─ YES → Combine or callbacks
└─ NO → async/await with continuation
```
**When Combine still wins**: Multiple publishers needing `combineLatest`, `merge`, or `debounce`. Converting this to pure async/await requires manual coordination that Combine handles elegantly.
### @MainActor Placement
```
Is every public method UI-related?
├─ YES → @MainActor on class/struct
└─ NO
└─ Does it manage UI state? (@Published, bindings)
├─ YES → @MainActor on class, nonisolated for non-UI methods
└─ NO
└─ Only some methods touch UI?
├─ YES → @MainActor on specific methods
└─ NO → No @MainActor needed
```
**Critical**: `@Published` properties MUST be updated on